CupCode.cc
Section 04 · Module 07 · Lesson 02 · ~15–20 นาที

Test Organization Patterns

เวลาเรียน: 15–20 นาที ต้องรู้มาก่อน: Lesson 01 (POM) รูปแบบ: อ่าน + Code Lab + แบบฝึก

จบบทนี้แล้วคุณจะ...

  • จัดกลุ่ม test ด้วย test.describe แบบ nesting
  • เลือกระหว่าง grouping by feature กับ by page
  • ใช้ test tagging (@smoke, @regression) เพื่อ filter test
  • ตั้งค่า parallel execution groups
1 · ทำไม Test Organization สำคัญ?

เมื่อ test suite โตจาก 10 เป็น 200+ tests:

  • หา test ที่ต้องการไม่เจอ
  • ไม่รู้ว่า test ไหนต้องรันก่อน deploy
  • CI ช้าเพราะรันทุก test ทุกครั้ง
  • test ที่ fail ไม่รู้ว่าเกี่ยวกับ feature ไหน

การจัดระเบียบดี = ทีมทำงานเร็วขึ้น

2 · test.describe — จัดกลุ่มอย่างเป็นระบบ
test.describe('Authentication', () => {

  test.describe('Login', () => {
    test('successful login with valid credentials', async ({ page }) => {
      // ...
    });

    test('shows error with invalid password', async ({ page }) => {
      // ...
    });

    test('redirects to dashboard after login', async ({ page }) => {
      // ...
    });
  });

  test.describe('Logout', () => {
    test('clears session on logout', async ({ page }) => {
      // ...
    });

    test('redirects to login page', async ({ page }) => {
      // ...
    });
  });

});

ผลลัพธ์ใน report:

Authentication > Login > successful login with valid credentials
Authentication > Login > shows error with invalid password
Authentication > Logout > clears session on logout
3 · Grouping: By Feature vs By Page

By Feature (แนะนำ)

tests/
├── auth/
│   ├── login.spec.ts
│   ├── logout.spec.ts
│   └── forgot-password.spec.ts
├── products/
│   ├── product-list.spec.ts
│   ├── product-detail.spec.ts
│   └── product-search.spec.ts
├── cart/
│   ├── add-to-cart.spec.ts
│   ├── update-quantity.spec.ts
│   └── checkout.spec.ts
└── admin/
    ├── user-management.spec.ts
    └── reports.spec.ts

By Page

tests/
├── login-page.spec.ts
├── dashboard-page.spec.ts
├── products-page.spec.ts
├── cart-page.spec.ts
└── admin-page.spec.ts
By Feature By Page
ข้อดี ตรงกับ user journey, หา test ง่าย เรียบง่าย, 1 page = 1 file
ข้อเสีย file อาจเยอะ test ไม่สะท้อน business flow
เหมาะกับ ทีมใหญ่, feature หลายตัว โปรเจกต์เล็ก, หน้าไม่เยอะ
4 · Shared Setup ด้วย beforeEach
test.describe('Dashboard - Authenticated User', () => {

  test.beforeEach(async ({ page }) => {
    // login ก่อนทุก test
    await page.goto('/login');
    await page.locator('#email').fill('[email protected]');
    await page.locator('#password').fill('secret123');
    await page.locator('button[type="submit"]').click();
    await page.waitForURL('/dashboard');
  });

  test('displays welcome message', async ({ page }) => {
    await expect(page.locator('.welcome')).toBeVisible();
  });

  test('shows recent orders', async ({ page }) => {
    await expect(page.locator('.recent-orders')).toBeVisible();
  });

});
5 · Test Tagging — @smoke, @regression

Playwright ใช้ tag ใน test title หรือ test.describe.configure:

// วิธีที่ 1: ใส่ tag ใน title
test('login with valid credentials @smoke', async ({ page }) => {
  // ...
});

test('login with expired token @regression', async ({ page }) => {
  // ...
});

// วิธีที่ 2: ใช้ tag option (Playwright 1.42+)
test('checkout flow', { tag: ['@smoke', '@critical'] }, async ({ page }) => {
  // ...
});

รัน test ตาม tag:

# รันเฉพาะ @smoke
npx playwright test --grep @smoke

# รันทุกอย่างยกเว้น @slow
npx playwright test --grep-invert @slow

# รัน @smoke และ @critical
npx playwright test --grep "@smoke|@critical"

แนะนำ tags:

  • @smoke — test หลักที่ต้องผ่านก่อน deploy (5-10 ตัว)
  • @regression — ครอบคลุมกว้าง รันรอบคืน
  • @critical — business-critical flow เช่น payment
  • @slow — test ที่ใช้เวลานาน ไม่ต้องรันทุก PR
6 · Parallel Execution
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  fullyParallel: true,     // ทุก test รัน parallel
  workers: 4,               // ใช้ 4 workers

  projects: [
    {
      name: 'smoke',
      grep: /@smoke/,
      fullyParallel: true,
    },
    {
      name: 'regression',
      grep: /@regression/,
      fullyParallel: false,  // sequential สำหรับ tests ที่มี dependencies
    }
  ]
});

ข้อควรระวัง parallel:

  • test แต่ละตัวต้อง independent — ไม่พึ่ง state ของ test อื่น
  • ใช้ test.describe.serial() สำหรับ test ที่ต้องรันตามลำดับ
test.describe.serial('Order Flow', () => {
  test('step 1: add to cart', async ({ page }) => { /* ... */ });
  test('step 2: checkout', async ({ page }) => { /* ... */ });
  test('step 3: confirm payment', async ({ page }) => { /* ... */ });
});
แบบฝึกหัด: จัดระเบียบ Test Files

โจทย์: คุณได้รับ test files ที่วางระเรียงอย่างไม่มีระบบ:

tests/
├── test1.spec.ts    (login tests)
├── test2.spec.ts    (product search + product detail)
├── test3.spec.ts    (add to cart + checkout + payment)
├── test4.spec.ts    (admin user management)
├── test5.spec.ts    (forgot password + reset password)

ให้ทำ:

  1. เสนอโครงสร้าง folder ใหม่แบบ by feature
  2. กำหนด tags ที่เหมาะสม
  3. ระบุว่า tests ไหนควรเป็น @smoke
ดูคำตอบแนะนำ
tests/
├── auth/
│   ├── login.spec.ts            @smoke (login success)
│   ├── forgot-password.spec.ts
│   └── reset-password.spec.ts
├── products/
│   ├── product-search.spec.ts   @smoke (search works)
│   └── product-detail.spec.ts
├── cart/
│   ├── add-to-cart.spec.ts      @smoke (add item works)
│   └── checkout.spec.ts         @smoke @critical (payment flow)
└── admin/
    └── user-management.spec.ts  @regression

@smoke tests (รันทุก PR):

  • login success — เพราะทุก feature ต้องใช้ login
  • product search — เพราะเป็น primary user journey
  • add to cart — เพราะเกี่ยวกับ revenue
  • checkout/payment — เพราะเป็น business-critical

สิ่งที่ต้องจำ

  • test.describe จัดกลุ่ม test ให้อ่านง่ายและ report ชัดเจน
  • Group by feature เหมาะกับทีมใหญ่ — ตรงกับ business flow
  • Tags (@smoke, @regression) ช่วย filter test ตาม context — ไม่ต้องรันทุกตัวทุกครั้ง
  • fullyParallel เร็วขึ้น แต่ test ต้อง independent
  • ใช้ test.describe.serial() สำหรับ tests ที่ต้องรันตามลำดับเท่านั้น