DEV Community

Cover image for ตรวจสอบ API ด้วย Playwright: วิธีการเช็ค Response อย่างละเอียด
Thanawat Wongchai
Thanawat Wongchai

Posted on • Originally published at apidog.com

ตรวจสอบ API ด้วย Playwright: วิธีการเช็ค Response อย่างละเอียด

การทดสอบ Playwright ของคุณผ่านหมด: ปุ่มล็อกอินคลิกได้ แดชบอร์ดแสดงผล ชาร์ตขึ้นครบ แต่ลูกค้ากลับเจอว่าตัวเลขในชาร์ตผิด เพราะ API คืน 200 OK พร้อม payload ที่ผิด schema และ E2E test ตรวจแค่ว่ามี UI แสดงบนจอ นี่คือช่องว่างของ browser test ล้วน ๆ การแก้คือเพิ่มการยืนยัน API ให้เข้มเท่ากับ UI flow โดยใช้ OpenAPI เป็นสัญญาหลัก แล้วรัน Playwright คู่กับ Apidog ใน CI เพื่อจับทั้ง UI regression และ API contract drift

ลองใช้ Apidog วันนี้

TL;DR

แนวทางที่ใช้งานได้จริงคือ:

  1. ใช้ openapi.yaml เป็น source of truth
  2. ใช้ Playwright request fixture สำหรับ API smoke checks ใกล้กับ user flow
  3. ใช้ page.route เพื่อ mock network response จาก fixture เดียวกัน
  4. ใช้ Apidog scenarios เพื่อตรวจ schema, chained API workflow, error paths และ business rules
  5. รันทั้ง 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 ทั่วไปมักทำประมาณนี้:

  1. เปิดหน้าเว็บ
  2. ล็อกอิน
  3. คลิกปุ่ม
  4. รอข้อมูลแสดง
  5. assert ว่า element มีอยู่

สิ่งนี้ยืนยันว่า user flow ทำงานได้ แต่ไม่ได้ยืนยันว่า API ถูกต้อง

ตัวอย่าง bug ที่มักหลุด:

1. Payload shape เปลี่ยน แต่ UI ยังผ่าน

API เดิมคืน:

{
  "total_count": 120
}
Enter fullscreen mode Exit fullscreen mode

แต่ backend เปลี่ยนเป็น:

{
  "totalCount": 120
}
Enter fullscreen mode Exit fullscreen mode

ถ้า 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
Enter fullscreen mode Exit fullscreen mode

หลักการคือ:

  • 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 };
Enter fullscreen mode Exit fullscreen mode

จากนั้นใน 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);
});
Enter fullscreen mode Exit fullscreen mode

Playwright test นี้ไม่ได้แทนที่ API test ทั้งหมด แต่ทำหน้าที่เป็น smoke check และ business assertion ที่อยู่ใกล้ user journey

ใช้ Apidog ตรวจ Schema และ Scenario Chain

ฝั่ง Apidog ให้ทำตามนี้:

  1. เปิด Apidog project
  2. กด Import
  3. เลือก openapi.yaml
  4. ตรวจว่า endpoints, parameters, request bodies และ response schemas ถูกสร้างครบ
  5. สร้าง scenario เช่น checkout flow:
    • POST /auth/token
    • POST /orders
    • GET /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);
});
Enter fullscreen mode Exit fullscreen mode

ข้อสำคัญ: 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 }}
Enter fullscreen mode Exit fullscreen mode

ถ้า job ใด fail ให้ block PR

ใช้ GitHub Actions docs สำหรับ matrix builds, caching และ artifacts

สำหรับทีมที่ต้องแบ่ง ownership ระหว่าง frontend, backend และ QA อ่านเพิ่มได้ที่ เครื่องมือทดสอบ API สำหรับวิศวกร QA

เพิ่ม Schema Drift Detection

เป้าหมายคือจับ bug ประเภท “API ยังคืน 200 แต่ payload ผิด”

แนวทางที่แนะนำ:

  1. เก็บ openapi.yaml เวอร์ชันล่าสุดไว้ใน repo
  2. ให้ CI validate ทุก PR ที่แก้ API contract
  3. ให้ Apidog scenario fail เมื่อ response ไม่ตรง schema
  4. เพิ่ม scheduled job รายวันเพื่อเทียบ production spec กับ spec ใน repo
  5. ถ้า 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',
  },
});
Enter fullscreen mode Exit fullscreen mode

เมื่อ 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,
});
Enter fullscreen mode Exit fullscreen mode

ถ้า 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 }) => {
  // ...
});
Enter fullscreen mode Exit fullscreen mode

รันเฉพาะ smoke:

npx playwright test --grep @smoke
Enter fullscreen mode Exit fullscreen mode

สำหรับ Apidog ให้แยก scenarios ตาม criticality เช่น:

apidog/scenarios/
├── smoke/
├── regression/
└── nightly/
Enter fullscreen mode Exit fullscreen mode

ข้อผิดพลาดที่ควรหลีกเลี่ยง

  • เช็คแค่ 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:

  1. นำเข้า openapi.yaml เข้า Apidog
  2. สร้าง Playwright fixture
  3. สร้าง Apidog scenario ที่ตรงกัน
  4. ใช้ fixture เดียวกัน
  5. รันทั้งสองใน CI
  6. ขยาย 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);
}
Enter fullscreen mode Exit fullscreen mode

ใน 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,
});
Enter fullscreen mode Exit fullscreen mode

และแยก Apidog scenarios เป็นกลุ่ม smoke/regression/nightly เพื่อไม่ต้องรันทุกอย่างทุกครั้ง

ต้องใช้ Apidog แบบเสียเงินเพื่อรัน CI ไหม?

ตรวจสอบหน้าราคาและเงื่อนไขปัจจุบันของ Apidog ก่อนใช้งานในองค์กร แต่โดย workflow แล้ว Apidog CLI สามารถใช้รัน scenarios ใน local และ CI ได้ เหมาะสำหรับทำ API validation แบบอัตโนมัติใน pipeline

Top comments (0)