การทดสอบ Playwright ของคุณผ่านหมด: ปุ่มล็อกอินคลิกได้ แดชบอร์ดแสดงผล ชาร์ตขึ้นครบ แต่ลูกค้ากลับเจอว่าตัวเลขในชาร์ตผิด เพราะ API คืน 200 OK พร้อม payload ที่ผิด schema และ E2E test ตรวจแค่ว่ามี UI แสดงบนจอ นี่คือช่องว่างของ browser test ล้วน ๆ การแก้คือเพิ่มการยืนยัน API ให้เข้มเท่ากับ UI flow โดยใช้ OpenAPI เป็นสัญญาหลัก แล้วรัน Playwright คู่กับ Apidog ใน CI เพื่อจับทั้ง UI regression และ API contract drift
TL;DR
แนวทางที่ใช้งานได้จริงคือ:
- ใช้
openapi.yamlเป็น source of truth - ใช้ Playwright
requestfixture สำหรับ API smoke checks ใกล้กับ user flow - ใช้
page.routeเพื่อ mock network response จาก fixture เดียวกัน - ใช้ Apidog scenarios เพื่อตรวจ schema, chained API workflow, error paths และ business rules
- รันทั้ง Playwright และ Apidog CLI ใน CI job เดียวกันหรือ parallel jobs
ผลลัพธ์คือเมื่อ API เปลี่ยน field, type, enum หรือ business behavior ผิดไป build จะ fail ก่อนขึ้น production
บทนำ
Playwright เหมาะมากสำหรับ browser automation และ เอกสาร API testing ของ Playwright ก็ทำให้เริ่มต้นง่าย เช่น request.get() แล้ว expect(response.status()).toBe(200)
แต่เมื่อระบบใหญ่ขึ้น ปัญหาจะเริ่มชัด:
- มี test หลายร้อยตัวที่เช็คแค่ status code
- payload shape ไม่ถูก validate จริง
- browser test กับ API test ใช้ fixture คนละชุด
- mock API แบบ offline ทำได้ไม่เป็นระบบ
- error path เช่น
401,409,429,500แทบไม่ถูกทดสอบ
วิธีแก้คือทำ workflow แบบ contract-first:
- ให้
openapi.yamlเป็นสัญญาหลัก - ให้ Playwright ใช้ fixture และ payload จากแหล่งเดียวกัน
- ให้ Apidog import spec เดียวกันเพื่อสร้าง scenarios และ schema assertions
- ให้ CI รันทั้งสองชุดทุกครั้งที่มี PR
ถ้าต้องติดตั้งก่อน ให้ ดาวน์โหลด Apidog แล้วนำเข้า OpenAPI spec ของโปรเจกต์คุณ จากนั้นทำตามขั้นตอนด้านล่าง
อ่านเพิ่มเติมเรื่องแนวทาง API-first/design-first ได้ที่ เครื่องมือการพัฒนา API แบบ design-first
ช่องว่างระหว่าง Playwright Test และ API Validation
Playwright test ทั่วไปมักทำประมาณนี้:
- เปิดหน้าเว็บ
- ล็อกอิน
- คลิกปุ่ม
- รอข้อมูลแสดง
- assert ว่า element มีอยู่
สิ่งนี้ยืนยันว่า user flow ทำงานได้ แต่ไม่ได้ยืนยันว่า API ถูกต้อง
ตัวอย่าง bug ที่มักหลุด:
1. Payload shape เปลี่ยน แต่ UI ยังผ่าน
API เดิมคืน:
{
"total_count": 120
}
แต่ backend เปลี่ยนเป็น:
{
"totalCount": 120
}
ถ้า UI fallback เป็น 0 หรือแสดงค่า default test อาจยังผ่าน เพราะ element ยังแสดงอยู่
2. Business logic ผิด แต่หน้าจอยัง render ได้
เช่น endpoint ส่วนลดควรคืน discount_pct: 15 แต่คืน 10
Playwright อาจตรวจแค่ว่ามีข้อความ “ส่วนลด” แสดงอยู่ แต่ไม่ได้ตรวจว่าคำนวณถูกต้อง
3. Error path ไม่ถูกครอบคลุม
API จริงมี branch จำนวนมาก:
- token หมดอายุ
- rate limit
- partial failure
- idempotency conflict
- validation error
- webhook retry
แต่ browser E2E test ส่วนใหญ่วิ่งเฉพาะ happy path
การแบ่งหน้าที่ที่เหมาะสมคือ:
- Playwright: ทดสอบ UI flow, browser behavior, network interception, API smoke checks ใกล้ user action
- Apidog: ทดสอบ schema, contract, chained API scenarios, error paths, mock server และ business assertions ระดับ API
ทั้งสองควรใช้ OpenAPI spec และ fixture ชุดเดียวกัน
โครงสร้างโปรเจกต์ที่แนะนำ
เริ่มจากจัดไฟล์ให้ชัด:
.
├── openapi.yaml
├── fixtures/
│ ├── order.json
│ └── user.json
├── tests/
│ ├── fixtures/
│ │ └── api.ts
│ ├── orders.spec.ts
│ └── dashboard.spec.ts
├── apidog/
│ └── scenarios/
│ └── checkout.json
├── playwright.config.ts
└── package.json
หลักการคือ:
-
openapi.yamlคือ contract หลัก -
fixtures/*.jsonคือ test data ที่ใช้ซ้ำ - Playwright import fixture จาก
tests/fixtures/api.ts - Apidog import
openapi.yamlและใช้ payload จาก fixture หรือ dataset เดียวกัน - CI รันทั้ง
npx playwright testและapidog-cli run
สร้าง Playwright API Fixture
สร้างไฟล์ tests/fixtures/api.ts
// tests/fixtures/api.ts
import { test as base, APIRequestContext, expect } from '@playwright/test';
import { readFileSync } from 'fs';
import path from 'path';
type ApiFixtures = {
apiRequest: APIRequestContext;
authToken: string;
sampleOrder: Record<string, unknown>;
};
export const test = base.extend<ApiFixtures>({
apiRequest: async ({ playwright }, use) => {
const ctx = await playwright.request.newContext({
baseURL: process.env.API_BASE_URL ?? 'https://api.staging.example.com',
extraHTTPHeaders: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
});
await use(ctx);
await ctx.dispose();
},
authToken: async ({ apiRequest }, use) => {
const res = await apiRequest.post('/auth/token', {
data: {
email: 'qa@example.com',
password: process.env.QA_PASSWORD,
},
});
expect(res.status()).toBe(200);
const body = await res.json();
await use(body.access_token);
},
sampleOrder: async ({}, use) => {
const raw = readFileSync(
path.join(__dirname, '..', '..', 'fixtures', 'order.json'),
'utf8',
);
await use(JSON.parse(raw));
},
});
export { expect };
จากนั้นใน test spec ให้ import จาก fixture นี้แทน @playwright/test
// tests/orders.spec.ts
import { test, expect } from './fixtures/api';
test('POST /orders returns valid order with 15 percent discount', async ({
apiRequest,
authToken,
sampleOrder,
}) => {
const res = await apiRequest.post('/orders', {
headers: {
Authorization: `Bearer ${authToken}`,
},
data: {
...sampleOrder,
coupon: 'SAVE15',
},
});
expect(res.status()).toBe(201);
const body = await res.json();
expect(body).toMatchObject({
id: expect.any(String),
status: 'pending',
discount_pct: 15,
total_cents: expect.any(Number),
});
expect(body.total_cents).toBeLessThan(sampleOrder.subtotal_cents);
});
Playwright test นี้ไม่ได้แทนที่ API test ทั้งหมด แต่ทำหน้าที่เป็น smoke check และ business assertion ที่อยู่ใกล้ user journey
ใช้ Apidog ตรวจ Schema และ Scenario Chain
ฝั่ง Apidog ให้ทำตามนี้:
- เปิด Apidog project
- กด Import
- เลือก
openapi.yaml - ตรวจว่า endpoints, parameters, request bodies และ response schemas ถูกสร้างครบ
- สร้าง scenario เช่น checkout flow:
POST /auth/tokenPOST /ordersGET /orders/{id}POST /orders/{id}/cancel- ตรวจ refund webhook หรือ status หลัง cancel
Apidog จะช่วยตรวจ:
- required fields
- field types
- enum values
- response schema
- chained variables ระหว่าง request
- environment variables
- pre-request scripts
- post-response assertions
ตัวอย่างการแบ่งหน้าที่:
| Layer | ตรวจอะไร |
|---|---|
| Playwright | UI flow, browser state, visible text, user action, smoke API assertions |
| Apidog | OpenAPI schema, chained API workflow, contract drift, error paths, mocks |
ถ้าใช้ Postman อยู่และกำลังประเมินทางเลือก อ่านเพิ่มเติมได้ที่ ทางเลือก Postman ที่โฮสต์เอง
Mock API ใน Playwright ด้วย page.route
เมื่อ UI ต้อง render โดยไม่เรียก backend จริง ให้ stub response จาก fixture เดียวกัน
// tests/dashboard.spec.ts
import { test, expect } from './fixtures/api';
test('dashboard renders cached order list when offline', async ({
page,
sampleOrder,
}) => {
await page.route('**/api/orders', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
orders: [sampleOrder],
}),
});
});
await page.goto('/dashboard');
await expect(page.getByTestId('order-row')).toHaveCount(1);
});
ข้อสำคัญ: page.route มีไว้เพื่อ isolation และ offline UI testing ไม่ใช่ใช้แทน API contract test
ให้ Apidog scenario รันกับ backend จริงหรือ mock server เพื่อยืนยันว่า response shape ยังตรงกับ openapi.yaml
ตั้งค่า Workflow ใน CI
ตัวอย่าง GitHub Actions:
name: tests
on:
push:
pull_request:
jobs:
playwright:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
env:
API_BASE_URL: ${{ secrets.API_BASE_URL }}
QA_PASSWORD: ${{ secrets.QA_PASSWORD }}
apidog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm i -g apidog-cli
- run: apidog-cli run ./apidog/scenarios/checkout.json --reporters cli,junit
env:
API_BASE_URL: ${{ secrets.API_BASE_URL }}
QA_PASSWORD: ${{ secrets.QA_PASSWORD }}
ถ้า job ใด fail ให้ block PR
ใช้ GitHub Actions docs สำหรับ matrix builds, caching และ artifacts
สำหรับทีมที่ต้องแบ่ง ownership ระหว่าง frontend, backend และ QA อ่านเพิ่มได้ที่ เครื่องมือทดสอบ API สำหรับวิศวกร QA
เพิ่ม Schema Drift Detection
เป้าหมายคือจับ bug ประเภท “API ยังคืน 200 แต่ payload ผิด”
แนวทางที่แนะนำ:
- เก็บ
openapi.yamlเวอร์ชันล่าสุดไว้ใน repo - ให้ CI validate ทุก PR ที่แก้ API contract
- ให้ Apidog scenario fail เมื่อ response ไม่ตรง schema
- เพิ่ม scheduled job รายวันเพื่อเทียบ production spec กับ spec ใน repo
- ถ้า field type, required field หรือ enum เปลี่ยน ให้ build fail ทันที
ตัวอย่าง rule ที่ควร fail:
-
total_centsจากnumberกลายเป็นstring - field
discount_pctหายไป - enum
statusมีค่าที่ไม่ได้ประกาศ - response body ไม่ตรง component schema ใน OpenAPI
เทคนิคขั้นสูง
เปิด Playwright Trace
ใน playwright.config.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
retries: 2,
use: {
trace: 'on-first-retry',
},
});
เมื่อ test fail ใน CI คุณจะเห็น:
- network calls
- DOM snapshots
- console logs
- screenshots
- timing ของแต่ละ action
จับคู่กับ Apidog report เพื่อดูว่า UI fail ก่อน หรือ API contract เปลี่ยนก่อน
ใช้ Apidog Mock Server
Apidog สามารถสร้าง mock server จาก OpenAPI spec ได้ เหมาะเมื่อ:
- backend staging ล่ม
- database กำลัง reset
- frontend ต้องพัฒนาก่อน backend เสร็จ
- ต้องการ deterministic response สำหรับ UI test
Pattern ที่แนะนำ:
- Playwright local/dev ชี้ไปที่ mock server
- Apidog scenario รันกับ mock เพื่อ validate contract
- Nightly หรือ PR-to-main รันกับ backend จริง
อ่านเพิ่มเรื่อง mock และ test generation ได้ที่ การสร้างการทดสอบ API ด้วย AI
จำกัด Retry
อย่าซ่อน flaky test ด้วย retry เยอะเกินไป
export default defineConfig({
retries: 2,
});
ถ้า test ต้อง retry 3-5 ครั้งถึงผ่าน ให้แก้ root cause เช่น race condition, unstable data หรือ backend latency
ฝั่ง Apidog scenario ก็ควรจำกัด retry ต่อ request เช่น retry: 1
แท็ก Test ตาม Priority
ตัวอย่าง:
-
@smokeรันทุก push -
@regressionรันทุก PR เข้า main -
@nightlyรันชุดใหญ่ตอนกลางคืน
ใน Playwright:
test('checkout flow @smoke', async ({ page }) => {
// ...
});
รันเฉพาะ smoke:
npx playwright test --grep @smoke
สำหรับ Apidog ให้แยก scenarios ตาม criticality เช่น:
apidog/scenarios/
├── smoke/
├── regression/
└── nightly/
ข้อผิดพลาดที่ควรหลีกเลี่ยง
- เช็คแค่
status === 200 - ไม่ validate body เลย
- hardcode bearer token ใน test
- ใช้ fixture คนละชุดระหว่าง Playwright และ Apidog
- ใช้
page.routeแทน API contract test จริง - ไม่รัน Apidog CLI ใน CI
- ปล่อย schema mismatch เป็น warning แทนที่จะ fail build
- ไม่ version OpenAPI spec
- ไม่ทดสอบ error paths เช่น
401,403,409,429
สำหรับระบบที่มี AI agents หรือ API behavior ที่ไม่ deterministic อ่านเพิ่มได้ที่ วิธีทดสอบ API ของ AI agents
ทางเลือกและการเปรียบเทียบเครื่องมือ
| สแตก | จุดแข็ง | จุดอ่อน | เหมาะกับ |
|---|---|---|---|
| Playwright อย่างเดียว | เครื่องมือเดียว, setup ง่าย, เร็ว | schema validation ตื้น, chained scenarios จำกัด | ทีมเล็ก, API ไม่ซับซ้อน |
| Playwright + Postman | ecosystem ใหญ่, มี Newman CLI | collection อาจ drift จาก OpenAPI, ต้องดูแลสองแหล่งข้อมูล | ทีมที่ใช้ Postman อยู่แล้ว |
| Playwright + Apidog | OpenAPI เป็น source เดียว, schema validation, mocks, CLI, design-first workflow | ต้องเรียนรู้สองเครื่องมือ | ทีมที่ต้องการ contract-driven testing |
| Cypress + cy-api plugin | เหมาะกับทีมที่ใช้ Cypress อยู่แล้ว | API testing จำกัดกว่า | legacy Cypress codebase |
| Pact | consumer-driven contract แข็งแรง | learning curve สูง, ต้องมี broker | microservices ขนาดใหญ่ |
หากกำลังย้ายจากเครื่องมือยุค SOAP ดูเพิ่มได้ที่ ทางเลือกสคริปต์ Groovy ของ SoapUI และ ทางเลือก ReadyAPI
ถ้าต้องการ workflow แบบ local-first อ่าน ส่วนเสริม VSCode สำหรับ REST client
กรณีใช้งานจริง
E-commerce Checkout
Playwright ตรวจ flow ตั้งแต่ cart → payment → confirmation
Apidog ตรวจ API chain:
- payment intent
- fraud check
- inventory deduction
- refund webhook
ถ้า payment gateway เปลี่ยน error_code เป็น errorCode Apidog จะจับ schema drift ได้เร็วกว่า browser test ที่อาจเห็นแค่หน้า error ทั่วไป
SaaS Dashboard
Playwright ตรวจว่า chart render ได้
Apidog ตรวจว่า endpoints ส่ง:
- totals
- percentiles
- time-series buckets
- aggregation result
ถ้า p99 latency endpoint ตัด outlier ผิด chart อาจยังดูปกติ แต่ API assertion จะ fail
Webhook Workflow
Playwright ตรวจ portal ที่ user ใช้งาน
Apidog ตรวจ:
- webhook delivery
- retry logic
- idempotency
- signature validation
- eventual consistency window
เหมาะกับ fintech, billing และ event-driven systems
สรุป
Playwright เหมาะกับ browser flow แต่ไม่พอสำหรับ API validation เชิงลึก
แนวทางที่แนะนำคือใช้ Playwright + Apidog แบบนี้:
- OpenAPI spec เดียวเป็น contract หลัก
- fixture ชุดเดียวใช้ทั้ง UI test และ API scenario
- Playwright ตรวจ user flow และ smoke API assertions
- Apidog ตรวจ schema, chained workflow และ error paths
- ใช้ mock server สำหรับ offline development
- ใช้ CI ให้ fail เมื่อ UI หรือ API regression เกิดขึ้น
เริ่มจาก journey สำคัญหนึ่งอัน เช่น signup หรือ checkout:
- นำเข้า
openapi.yamlเข้า Apidog - สร้าง Playwright fixture
- สร้าง Apidog scenario ที่ตรงกัน
- ใช้ fixture เดียวกัน
- รันทั้งสองใน CI
- ขยาย coverage ทีละ endpoint
คำถามที่พบบ่อย
ฉันตรวจ API ใน Playwright โดยไม่ใช้ Apidog ได้ไหม?
ได้ ใช้ request fixture แล้วเขียน expect เองได้ เหมาะกับ smoke checks และ endpoint จำนวนไม่มาก
แต่ถ้าต้องการ schema validation, chained scenarios, mocks, error-path coverage และ CI reports เครื่องมือเฉพาะอย่าง Apidog จะจัดการได้เป็นระบบกว่า
ดูภาพรวมเพิ่มเติมที่ เครื่องมือทดสอบ API สำหรับวิศวกร QA
จำเป็นต้องมี OpenAPI spec ไหม?
ควรมี ถ้าไม่มี คุณยังใช้ Playwright และ Apidog คู่กันได้ แต่จะเสีย source of truth กลาง และต้องดูแล payload examples หลายที่
ถ้า backend framework รองรับ OpenAPI generation เช่น FastAPI หรือ NestJS ให้เริ่มจาก generated spec แล้วปรับให้ถูกต้อง
จัดการ authentication อย่างไร?
ใช้ fixture หรือ setup step เพื่อขอโทเค็นใหม่ทุก test run
ใน Playwright:
authToken: async ({ apiRequest }, use) => {
const res = await apiRequest.post('/auth/token', {
data: {
email: 'qa@example.com',
password: process.env.QA_PASSWORD,
},
});
const body = await res.json();
await use(body.access_token);
}
ใน Apidog ให้เก็บ token เป็น environment variable แล้วส่งต่อใน requests ถัดไป
Apidog แทน Playwright ได้ไหม?
ไม่ได้ Apidog ทดสอบ API workflow ได้ดี แต่ไม่ได้ render browser
คุณยังต้องใช้ Playwright สำหรับ:
- visible text
- layout
- click flow
- browser state
- accessibility checks
- cross-browser behavior
ถ้า staging backend ไม่เสถียรควรทำอย่างไร?
ใช้ Apidog mock server จาก OpenAPI spec แล้วให้ local Playwright ชี้ไปที่ mock ก่อน
จากนั้นรันชุดเต็มกับ backend จริงใน PR-to-main หรือ nightly build
ทำให้ CI เร็วได้อย่างไร?
ใช้ test selection:
- push ทุกครั้ง:
@smoke - PR เข้า main: regression สำคัญ
- nightly: full Playwright + full Apidog scenarios
เพิ่ม parallelism:
export default defineConfig({
workers: 4,
});
และแยก Apidog scenarios เป็นกลุ่ม smoke/regression/nightly เพื่อไม่ต้องรันทุกอย่างทุกครั้ง
ต้องใช้ Apidog แบบเสียเงินเพื่อรัน CI ไหม?
ตรวจสอบหน้าราคาและเงื่อนไขปัจจุบันของ Apidog ก่อนใช้งานในองค์กร แต่โดย workflow แล้ว Apidog CLI สามารถใช้รัน scenarios ใน local และ CI ได้ เหมาะสำหรับทำ API validation แบบอัตโนมัติใน pipeline
Top comments (0)