#การทดสอบ API ด้วย Playwright

เมื่อพูดถึง Playwright หลายคนมักนึกถึงการทดสอบเว็บแบบ End-to-End หรือการควบคุม Browser อัตโนมัติ แต่ Playwright สามารถใช้สำหรับ API Testing ได้โดยตรงเช่นกัน

Playwright Test มี request fixture ซึ่งเป็น APIRequestContext สำหรับส่ง HTTP Request ไปยัง REST API โดยไม่ต้องเปิด Browser ทำให้เราสามารถเขียน Automated API Test ด้วย TypeScript/JavaScript และใช้ Test Runner, Assertions, Fixtures, Reporting และ CI/CD ชุดเดียวกับ UI Test ได้

Playwright เหมาะอย่างยิ่งกับโครงการที่ต้องการรวม

API Testing
     +
UI / E2E Testing
     +
CI/CD
     =
Automated Quality Pipeline

#API Testing คืออะไร

API Testing คือการตรวจสอบการทำงานของ API โดยส่ง HTTP Request ไปยัง Endpoint และตรวจสอบ HTTP Response ที่ได้รับกลับมา

ตัวอย่างเช่น

Test
 |
 | GET /api/users/1
 v
REST API
 |
 | 200 OK
 | application/json
 v
Assertions

สิ่งที่ควรตรวจสอบในการทดสอบ API ได้แก่

  • HTTP Status Code
  • Response Body
  • Response Headers
  • Data Type
  • Business Rules
  • Authentication
  • Authorization
  • Error Handling
  • API Contract
  • Response Time

#ทำไมจึงใช้ Playwright สำหรับ API Testing

Playwright มี APIRequestContext ซึ่งสามารถส่ง HTTP(S) Request ได้โดยตรง

Playwright Test ยังมี request fixture ที่สร้าง API Request Context แบบแยกสำหรับแต่ละ Test และสามารถใช้ค่าจาก playwright.config.ts เช่น baseURL และ extraHTTPHeaders ได้ทันที

จุดเด่นของการใช้ Playwright คือ

  1. ทดสอบ API และ UI ด้วย Framework เดียวกัน
  2. ใช้ TypeScript/JavaScript ได้โดยตรง
  3. มี Test Runner และ Assertions ในตัว
  4. รองรับ Fixtures และ Hooks
  5. รองรับ Parallel Testing
  6. มี HTML Report
  7. เชื่อมต่อ CI/CD ได้ง่าย
  8. ใช้ API เตรียมข้อมูลก่อน UI Test ได้
  9. ใช้ API ตรวจสอบ Backend State หลังทำงานผ่าน UI ได้

#1. สร้างโครงการ Playwright

ต้องติดตั้ง Node.js ก่อน

สร้างโครงการใหม่ด้วยคำสั่ง

mkdir playwright-api-testing
cd playwright-api-testing

npm init playwright@latest

หรือถ้ามีโครงการ Node.js อยู่แล้ว สามารถติดตั้ง Playwright Test ได้ด้วย

npm install -D @playwright/test@latest

ตรวจสอบเวอร์ชัน

npx playwright --version

จากนั้นรัน Test ด้วย

npx playwright test

#2. โครงสร้างโครงการ

ตัวอย่างโครงสร้างสำหรับแยก API Test ออกจาก UI Test

playwright-api-testing/
├── tests/
│   ├── api/
│   │   ├── users.spec.ts
│   │   └── posts.spec.ts
│   └── e2e/
├── utils/
│   └── api-client.ts
├── playwright.config.ts
├── package.json
└── .env

แนวทางนี้ช่วยให้สามารถรันเฉพาะ API Test ได้ง่าย เช่น

npx playwright test tests/api

#3. ตั้งค่า Base URL

กำหนด baseURL ใน playwright.config.ts

import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests',

  use: {
    baseURL: 'https://jsonplaceholder.typicode.com',
  },

  reporter: 'html',
});

เมื่อกำหนด Base URL แล้ว จากเดิมที่ต้องเขียน

await request.get(
  'https://jsonplaceholder.typicode.com/users/1'
);

สามารถเขียนเพียง

await request.get('/users/1');

ทำให้ Test อ่านง่ายและเปลี่ยน Environment ได้สะดวกขึ้น


#4. ทดสอบ GET Request

สร้างไฟล์

tests/api/users.spec.ts

ตัวอย่าง

import { test, expect } from '@playwright/test';

test('GET /users/1 should return user', async ({ request }) => {
  const response = await request.get('/users/1');

  expect(response.status()).toBe(200);

  const body = await response.json();

  expect(body.id).toBe(1);
  expect(body.name).toBeTruthy();
  expect(body.email).toContain('@');
});

ตัวอย่างนี้ประกอบด้วย 3 ขั้นตอนหลัก

Arrange
  |
Act
  |
Assert

ในกรณีนี้เราไม่มีข้อมูลที่ต้องเตรียมมาก จึงเริ่มจากส่ง GET Request แล้วตรวจสอบ Response ได้ทันที


#5. ตรวจสอบ Response ด้วย toBeOK()

Playwright มี API Response Assertion สำหรับตรวจสอบว่า Status Code อยู่ในช่วง 200-299

await expect(response).toBeOK();

ตัวอย่าง

test('API should return success', async ({ request }) => {
  const response = await request.get('/users/1');

  await expect(response).toBeOK();
});

หาก Test ต้องการ Status Code ที่เจาะจง เช่น 201 Created ควรตรวจสอบโดยตรง

expect(response.status()).toBe(201);

#6. ตรวจสอบ JSON Response

สมมติ API คืนข้อมูล

{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "Sincere@april.biz"
}

สามารถตรวจสอบบาง Field ด้วย toMatchObject()

const body = await response.json();

expect(body).toMatchObject({
  id: 1,
  username: 'Bret',
});

ตรวจสอบชนิดข้อมูลได้ด้วย

expect(body.id).toEqual(expect.any(Number));
expect(body.name).toEqual(expect.any(String));
expect(body.email).toEqual(expect.any(String));

#7. ทดสอบ API ที่คืน Array

ตัวอย่าง

test('GET /users should return array', async ({ request }) => {
  const response = await request.get('/users');

  expect(response.status()).toBe(200);

  const users = await response.json();

  expect(Array.isArray(users)).toBe(true);
  expect(users.length).toBeGreaterThan(0);

  expect(users[0]).toEqual(
    expect.objectContaining({
      id: expect.any(Number),
      name: expect.any(String),
      email: expect.any(String),
    })
  );
});

การตรวจสอบลักษณะนี้มีประโยชน์มากกว่าเช็กเพียง Status Code เพราะช่วยยืนยันว่าโครงสร้างข้อมูลยังตรงกับสิ่งที่ Application คาดหวัง


#8. ส่ง Query Parameters

สามารถใช้ params เพื่อสร้าง Query String ได้

const response = await request.get('/posts', {
  params: {
    userId: 1,
  },
});

ตัวอย่าง Test

test('GET posts by userId', async ({ request }) => {
  const response = await request.get('/posts', {
    params: {
      userId: 1,
    },
  });

  expect(response.status()).toBe(200);

  const posts = await response.json();

  expect(posts.length).toBeGreaterThan(0);

  for (const post of posts) {
    expect(post.userId).toBe(1);
  }
});

#9. ทดสอบ POST Request

POST มักใช้สำหรับสร้าง Resource ใหม่

test('POST /posts should create post', async ({ request }) => {
  const payload = {
    title: 'Playwright API Testing',
    body: 'Learning API testing with Playwright',
    userId: 1,
  };

  const response = await request.post('/posts', {
    data: payload,
  });

  expect(response.status()).toBe(201);

  const body = await response.json();

  expect(body).toMatchObject(payload);
  expect(body.id).toBeDefined();
});

เมื่อส่ง Object ผ่าน data Playwright สามารถ serialize เป็น JSON Request Body ให้ได้


#10. ทดสอบ PUT Request

PUT มักใช้สำหรับ Update Resource ทั้งชุด

test('PUT /posts/1 should update post', async ({ request }) => {
  const payload = {
    id: 1,
    title: 'Updated title',
    body: 'Updated body',
    userId: 1,
  };

  const response = await request.put('/posts/1', {
    data: payload,
  });

  expect(response.status()).toBe(200);

  const body = await response.json();

  expect(body.title).toBe('Updated title');
  expect(body.body).toBe('Updated body');
});

#11. ทดสอบ PATCH Request

PATCH เหมาะสำหรับแก้ไขข้อมูลเพียงบางส่วน

test('PATCH /posts/1 should update title', async ({ request }) => {
  const response = await request.patch('/posts/1', {
    data: {
      title: 'New title',
    },
  });

  expect(response.status()).toBe(200);

  const body = await response.json();

  expect(body.title).toBe('New title');
});

#12. ทดสอบ DELETE Request

test('DELETE /posts/1', async ({ request }) => {
  const response = await request.delete('/posts/1');

  expect(response.status()).toBe(200);
});

ในระบบจริง ไม่ควรตรวจเพียงว่า DELETE สำเร็จ แต่ควรตรวจ Post-condition ต่อด้วย เช่น

DELETE /api/users/10
        |
        v
GET /api/users/10
        |
        v
404 Not Found

#13. ตรวจสอบ Response Headers

สามารถอ่าน Header จาก Response ได้

test('response should be JSON', async ({ request }) => {
  const response = await request.get('/users/1');

  const headers = response.headers();

  expect(headers['content-type']).toContain('application/json');
});

Header ที่มักใช้ตรวจสอบ เช่น

Content-Type
Cache-Control
Authorization
Location
ETag
Retry-After

#14. HTTP Status Code ที่ควรรู้

Status Code ความหมาย
200 OK
201 Created
204 No Content
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
409 Conflict
422 Unprocessable Content
500 Internal Server Error

ตัวอย่าง

expect(response.status()).toBe(201);

ควรตรวจ Status Code ให้ตรงกับ API Contract ของระบบ ไม่ควรสมมติว่า Request ที่สำเร็จต้องเป็น 200 เสมอ


#15. Negative Testing

API Test ที่ดีไม่ควรมีเฉพาะ Happy Path

ควรทดสอบกรณีผิดพลาด เช่น

Invalid ID
Missing Required Field
Invalid Data Type
Invalid Format
Invalid Token
Expired Token
Unauthorized User
Forbidden Resource
Duplicate Data
Resource Not Found

ตัวอย่าง

test('should reject invalid payload', async ({ request }) => {
  const response = await request.post('/api/users', {
    data: {
      email: 'invalid-email',
    },
  });

  expect([400, 422]).toContain(response.status());
});

ในระบบจริงควรระบุ Status Code ตาม Contract ที่ชัดเจน เช่น

expect(response.status()).toBe(422);

แทนการยอมรับหลายค่าโดยไม่จำเป็น


#16. Authentication ด้วย Bearer Token

API จำนวนมากใช้ JWT หรือ Bearer Token

test('authenticated API', async ({ request }) => {
  const response = await request.get('/api/profile', {
    headers: {
      Authorization: `Bearer ${process.env.API_TOKEN}`,
    },
  });

  expect(response.status()).toBe(200);
});

ไม่ควร Hard-code Token ใน Source Code

หลีกเลี่ยง

Authorization: 'Bearer eyJhbGciOi...'

ควรเก็บ Secret ไว้ใน Environment Variable หรือ Secret Manager ของ CI/CD


#17. กำหนด Header ส่วนกลาง

ถ้าทุก Request ใช้ Header เดียวกัน สามารถกำหนด extraHTTPHeaders ใน Config

import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    baseURL: process.env.API_URL,

    extraHTTPHeaders: {
      Accept: 'application/json',
      Authorization: `Bearer ${process.env.API_TOKEN}`,
    },
  },
});

จากนั้น Test จะสั้นลง

test('get profile', async ({ request }) => {
  const response = await request.get('/api/profile');

  expect(response.status()).toBe(200);
});

#18. ใช้ไฟล์ .env

ติดตั้ง dotenv

npm install dotenv

สร้างไฟล์ .env

API_URL=https://api.example.com
API_TOKEN=your-token

เพิ่ม .env ลงใน .gitignore

.env

แก้ playwright.config.ts

import { defineConfig } from '@playwright/test';
import dotenv from 'dotenv';

dotenv.config();

export default defineConfig({
  use: {
    baseURL: process.env.API_URL,

    extraHTTPHeaders: {
      Authorization: `Bearer ${process.env.API_TOKEN}`,
    },
  },
});

#19. แยก Environment

โครงการจริงมักมีหลาย Environment เช่น

Development
Testing
Staging
Production

สามารถส่ง Base URL จาก Environment Variable

Linux/macOS:

API_URL=https://staging-api.example.com npx playwright test

Windows PowerShell:

$env:API_URL="https://staging-api.example.com"
npx playwright test

แนวทางนี้ดีกว่าการแก้ URL ใน Source Code ทุกครั้ง


#20. สร้าง APIRequestContext เอง

นอกจาก request fixture แล้ว ยังสามารถสร้าง Context เองเพื่อควบคุม Configuration ได้ละเอียดขึ้น

import {
  test,
  expect,
  APIRequestContext,
} from '@playwright/test';

let apiContext: APIRequestContext;

test.beforeAll(async ({ playwright }) => {
  apiContext = await playwright.request.newContext({
    baseURL: 'https://jsonplaceholder.typicode.com',

    extraHTTPHeaders: {
      Accept: 'application/json',
    },
  });
});

test.afterAll(async () => {
  await apiContext.dispose();
});

test('GET user', async () => {
  const response = await apiContext.get('/users/1');

  expect(response.status()).toBe(200);
});

เหมาะกับกรณี

  • ต้องเรียก API หลาย Service
  • ต้องใช้ Authentication ต่างกัน
  • ต้องแยก Cookie Storage
  • ต้องสร้าง API Client สำหรับแต่ละ Role
  • ต้องใช้ Configuration เฉพาะชุด Test

#21. API Context และ Cookie

Playwright มี API Request Context สองลักษณะสำคัญ

BrowserContext
   |
   +-- context.request
   |
   +-- page.request

context.request และ page.request ใช้ Cookie Storage ร่วมกับ Browser Context

จึงเหมาะกับ Flow เช่น

Login ผ่าน UI
      |
      v
Browser Session
      |
      v
page.request
      |
      v
Authenticated API

หากต้องการ Context ที่ไม่แชร์ Cookie กับ Browser ให้สร้างด้วย

playwright.request.newContext()

#22. ใช้ API เตรียมข้อมูลก่อน UI Test

หนึ่งในแนวทางที่มีประสิทธิภาพมากคือใช้ API สำหรับ Setup Test Data

แทนที่จะเปิด Browser แล้วกรอก Form หลายขั้นตอน สามารถสร้างข้อมูลผ่าน API ก่อน

test('user can view created post', async ({ request, page }) => {
  const response = await request.post('/posts', {
    data: {
      title: 'Playwright',
      body: 'API + UI',
      userId: 1,
    },
  });

  expect(response.status()).toBe(201);

  const post = await response.json();

  await page.goto(`/posts/${post.id}`);
});

Workflow

API
 |
 | Create Test Data
 v
Backend
 |
 v
UI Test

ข้อดีคือ Setup Test ได้เร็วกว่าใช้ UI ทุกขั้นตอน


#23. ใช้ API ตรวจสอบผลหลัง UI Test

อีก Pattern คือให้ User ทำงานผ่าน UI แล้วตรวจสอบข้อมูล Backend ผ่าน API

Browser
 |
 | Create Order
 v
Web Application
 |
 v
Backend
 |
 | GET /api/orders/{id}
 v
API Assertion

ตัวอย่าง

test('created order should exist in backend', async ({
  page,
  request,
}) => {
  await page.goto('/orders/new');

  // ทำรายการผ่าน UI
  // ...

  const response = await request.get('/api/orders/1001');

  expect(response.status()).toBe(200);

  const order = await response.json();

  expect(order.status).toBe('pending');
});

รูปแบบนี้ทำให้ Test ครอบคลุมทั้ง UI และ Backend State


#24. สร้าง Reusable API Client

เมื่อ Test Suite มีขนาดใหญ่ ไม่ควรเขียน Endpoint เดิมซ้ำในทุกไฟล์

สร้าง

utils/users-api.ts
import { APIRequestContext } from '@playwright/test';

export class UsersApi {
  constructor(
    private request: APIRequestContext
  ) {}

  async getUser(id: number) {
    return this.request.get(`/users/${id}`);
  }

  async getUsers() {
    return this.request.get('/users');
  }

  async createUser(data: object) {
    return this.request.post('/users', {
      data,
    });
  }
}

ใช้งาน

import { test, expect } from '@playwright/test';
import { UsersApi } from '../../utils/users-api';

test('get user', async ({ request }) => {
  const usersApi = new UsersApi(request);

  const response = await usersApi.getUser(1);

  expect(response.status()).toBe(200);
});

ข้อดีคือหาก Endpoint เปลี่ยน สามารถแก้ไขได้จาก API Client จุดเดียว


#25. เขียน Test แบบ Arrange–Act–Assert

รูปแบบ AAA ช่วยให้ Test อ่านง่าย

test('create post', async ({ request }) => {
  // Arrange
  const payload = {
    title: 'Playwright',
    body: 'API Testing',
    userId: 1,
  };

  // Act
  const response = await request.post('/posts', {
    data: payload,
  });

  // Assert
  expect(response.status()).toBe(201);

  const body = await response.json();

  expect(body.title).toBe(payload.title);
});

โครงสร้างคือ

Arrange
   |
   v
Act
   |
   v
Assert

#26. ตรวจสอบหลายเงื่อนไขใน Response

test('validate user response', async ({ request }) => {
  const response = await request.get('/users/1');

  expect(response.status()).toBe(200);

  const body = await response.json();

  expect(body).toMatchObject({
    id: expect.any(Number),
    name: expect.any(String),
    username: expect.any(String),
    email: expect.any(String),
  });

  expect(body.address).toBeDefined();
  expect(body.company).toBeDefined();
});

ควรเลือก Assert เฉพาะข้อมูลที่เป็น Requirement สำคัญ ไม่ควร Assert ทุก Field โดยไม่มีเหตุผล เพราะอาจทำให้ Test เปราะเกินไป


#27. ตรวจสอบ Response Time เบื้องต้น

สามารถวัดเวลาของ Request ได้

test('response time should be acceptable', async ({ request }) => {
  const start = Date.now();

  const response = await request.get('/users');

  const duration = Date.now() - start;

  expect(response.status()).toBe(200);
  expect(duration).toBeLessThan(1000);
});

อย่างไรก็ตาม วิธีนี้เหมาะกับ Threshold เบื้องต้นเท่านั้น

หากต้องการทำ

Load Testing
Stress Testing
Spike Testing
Soak Testing

ควรใช้เครื่องมือเฉพาะทาง เช่น

  • k6
  • JMeter
  • Gatling

#28. Polling สำหรับ Asynchronous API

บางระบบไม่ได้ประมวลผลเสร็จทันที เช่น

Create Job
   |
   v
queued
   |
   v
processing
   |
   v
completed

สามารถใช้ expect.poll() เพื่อรอผล

await expect.poll(async () => {
  const response = await request.get('/api/jobs/100');

  const body = await response.json();

  return body.status;
}, {
  timeout: 30_000,
}).toBe('completed');

เหมาะกับระบบประเภท

  • Background Job
  • Queue
  • Report Generation
  • File Processing
  • AI Job
  • Payment Processing

#29. ใช้ Test Hooks

Playwright รองรับ Hooks เช่น

test.beforeAll()
test.beforeEach()
test.afterEach()
test.afterAll()

ตัวอย่าง

test.beforeEach(async ({ request }) => {
  await request.post('/api/test/reset');
});

เหมาะกับงาน เช่น

Reset Database
Seed Test Data
Login
Create Resource
Cleanup Resource

#30. Group Test ด้วย test.describe()

test.describe('Users API', () => {
  test('GET user', async ({ request }) => {
    // ...
  });

  test('CREATE user', async ({ request }) => {
    // ...
  });

  test('UPDATE user', async ({ request }) => {
    // ...
  });

  test('DELETE user', async ({ request }) => {
    // ...
  });
});

ช่วยจัด Test Suite ให้อ่านง่ายและแบ่งตาม Resource หรือ Feature


#31. Tag API Tests

สามารถใส่ Tag ให้ Test

test(
  'GET users',
  {
    tag: '@api',
  },
  async ({ request }) => {
    const response = await request.get('/users');

    expect(response.status()).toBe(200);
  }
);

รันเฉพาะ Test ที่มี Tag

npx playwright test --grep @api

ตัวอย่าง Tag ที่เหมาะกับโครงการจริง

@api
@smoke
@regression
@critical
@auth
@negative

#32. รัน Test และดู Report

รัน Test ทั้งหมด

npx playwright test

รันเฉพาะ API Test

npx playwright test tests/api

รันไฟล์เดียว

npx playwright test tests/api/users.spec.ts

ดู HTML Report

npx playwright show-report

#33. ตัวอย่าง CRUD Test Suite

import { test, expect } from '@playwright/test';

test.describe('Posts API', () => {

  test('GET posts', async ({ request }) => {
    const response = await request.get('/posts');

    expect(response.status()).toBe(200);

    const posts = await response.json();

    expect(Array.isArray(posts)).toBe(true);
  });

  test('CREATE post', async ({ request }) => {
    const response = await request.post('/posts', {
      data: {
        title: 'Playwright',
        body: 'API Testing',
        userId: 1,
      },
    });

    expect(response.status()).toBe(201);

    const body = await response.json();

    expect(body.title).toBe('Playwright');
  });

  test('UPDATE post', async ({ request }) => {
    const response = await request.put('/posts/1', {
      data: {
        id: 1,
        title: 'Updated',
        body: 'Updated body',
        userId: 1,
      },
    });

    expect(response.status()).toBe(200);
  });

  test('DELETE post', async ({ request }) => {
    const response = await request.delete('/posts/1');

    expect(response.status()).toBe(200);
  });

});

#34. รัน API Test บน GitHub Actions

สร้างไฟล์

.github/workflows/playwright-api.yml

ตัวอย่าง

name: Playwright API Tests

on:
  push:
  pull_request:

jobs:
  api-test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Install dependencies
        run: npm ci

      - name: Run API tests
        run: npx playwright test tests/api
        env:
          API_URL: ${{ secrets.API_URL }}
          API_TOKEN: ${{ secrets.API_TOKEN }}

      - name: Upload Playwright report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/

สำหรับ Test Suite ที่ทดสอบ API อย่างเดียว ไม่จำเป็นต้องเปิด Browser ใน Test

ถ้า Repository เดียวกันมี UI Test ด้วย ควรติดตั้ง Browser Dependencies ตาม Workflow ของ Playwright เช่น

npx playwright install --with-deps

#35. Test Cases ที่ควรมี

กลุ่ม ตัวอย่าง Test
Happy Path Request ถูกต้องและสำเร็จ
Validation Required Field
Validation Invalid Type
Validation Invalid Format
Authentication ไม่มี Token
Authentication Token ผิด
Authentication Token หมดอายุ
Authorization Role ไม่มี Permission
Resource Resource ไม่มีอยู่
Duplicate ข้อมูลซ้ำ
Business Rule ผิดเงื่อนไขธุรกิจ
Header Content-Type
Contract Field และ Data Type
Performance Response Time
Security Sensitive Data ไม่ถูกส่งกลับ

#36. แนวทางจัด API Test Suite

tests/api/
│
├── smoke/
│   └── critical-api.spec.ts
│
├── users/
│   ├── get-users.spec.ts
│   ├── create-user.spec.ts
│   ├── update-user.spec.ts
│   └── delete-user.spec.ts
│
├── auth/
│   ├── login.spec.ts
│   └── authorization.spec.ts
│
├── validation/
│   └── user-validation.spec.ts
│
└── regression/
    └── business-rules.spec.ts

การจัด Folder ควรเลือกตามขนาดของโครงการ ไม่จำเป็นต้องแบ่งละเอียดเกินไปในโครงการเล็ก


#37. Best Practices

#ใช้ baseURL

ช่วยลด URL ซ้ำและเปลี่ยน Environment ได้ง่าย

#อย่า Hard-code Secret

ใช้

Environment Variables
GitHub Secrets
CI/CD Secret Store
Vault

#ตรวจสอบทั้ง Status และ Body

ไม่ควรตรวจเพียง

expect(response.status()).toBe(200);

ควรตรวจข้อมูลหรือ Business Rule ที่สำคัญด้วย

#มีทั้ง Positive และ Negative Test

Happy Path อย่างเดียวไม่เพียงพอสำหรับ Regression Test

#แยก Test Data จาก Production

ไม่ควรใช้ Production Data เป็นข้อมูลหลักของ Automated Test

#Cleanup Test Data

โดยเฉพาะ Test ที่สร้าง แก้ไข หรือลบข้อมูล

#ทำ Test ให้ Independent

หลีกเลี่ยง Test ที่ต้องพึ่งผลจาก Test ก่อนหน้า

#ใช้ API สำหรับ Setup UI Test

ลดเวลาในการเตรียมข้อมูลผ่านหน้าเว็บ

#ใช้ API ตรวจสอบ Backend State

ช่วยเพิ่มความมั่นใจว่า Operation ที่ทำผ่าน UI ส่งผลถึง Backend จริง

#รันบน CI/CD

อย่างน้อยควรรัน Smoke Test หรือ Critical API Tests ทุก Pull Request


#38. Playwright API Testing Workflow

Developer
    |
    v
Write API Test
    |
    v
Playwright Test
    |
    +-------------------------+
    |                         |
    v                         v
HTTP Request              Assertions
    |                         |
    v                         |
REST API                     |
    |                         |
    v                         |
HTTP Response ---------------+
    |
    v
Pass / Fail
    |
    v
HTML Report
    |
    v
CI/CD

#39. Playwright หรือ Postman/Newman

Playwright และ Postman/Newman ไม่จำเป็นต้องแทนกันทั้งหมด

ประเด็น Playwright Postman / Newman
REST API Testing ดีมาก ดีมาก
UI Testing ดีมาก ไม่ใช่งานหลัก
API Exploration พอใช้ เด่น
Automated Regression เด่น เด่น
UI + API ใน Test เดียว เด่นมาก จำกัด
TypeScript Project เหมาะมาก ใช้งานได้
CI/CD ดีมาก ดีมาก
Shared Test Fixtures เด่น Workflow ต่างกัน

ถ้าโครงการใช้ Playwright ทำ E2E Test อยู่แล้ว การเพิ่ม API Test เข้าใน Repository เดียวกันช่วยลดจำนวนเครื่องมือและทำให้ Test Infrastructure เป็นชุดเดียวกัน


#40. Playwright หรือ k6/JMeter

ควรแยกวัตถุประสงค์ให้ชัดเจน

Playwright
   |
   +-- Functional API Testing
   +-- Integration Testing
   +-- E2E Testing
   +-- UI + API Testing

k6 / JMeter
   |
   +-- Load Testing
   +-- Stress Testing
   +-- Spike Testing
   +-- Soak Testing

Playwright สามารถวัด Response Time เบื้องต้นได้ แต่ไม่ได้ถูกออกแบบเป็น Load Testing Tool สำหรับสร้าง Concurrent Users จำนวนมาก


#สรุป

Playwright เป็น Framework ที่สามารถใช้ทดสอบได้มากกว่า UI Automation เพราะ APIRequestContext และ request fixture ช่วยให้สามารถส่ง HTTP Request และตรวจสอบ API Response ได้โดยตรง

ความสามารถที่สำคัญประกอบด้วย

GET
POST
PUT
PATCH
DELETE
Query Parameters
Headers
Authentication
Assertions
Fixtures
Hooks
Polling
API + UI Testing
HTML Report
CI/CD

ถ้าทีมใช้ Playwright สำหรับ End-to-End Testing อยู่แล้ว การเพิ่ม API Testing เข้าไปใน Playwright Test ช่วยให้ใช้ Configuration, Assertions, Test Runner, Fixtures, Reporting และ CI Pipeline ร่วมกันได้

แนวทางที่เหมาะกับโครงการจริงคือ

API Smoke Test
      +
API Regression Test
      +
UI / E2E Test
      +
CI/CD
      =
Continuous Quality

#เอกสารอ้างอิง

  1. Playwright — API testing
    https://playwright.dev/docs/api-testing

  2. Playwright — APIRequestContext
    https://playwright.dev/docs/api/class-apirequestcontext

  3. Playwright — APIResponseAssertions
    https://playwright.dev/docs/api/class-apiresponseassertions

  4. Playwright — Fixtures
    https://playwright.dev/docs/api/class-fixtures

  5. Playwright — Test Assertions
    https://playwright.dev/docs/test-assertions

  6. Playwright — Configuration
    https://playwright.dev/docs/test-use-options


หมายเหตุ: ตัวอย่างบางส่วนในบทความใช้ JSONPlaceholder เพื่ออธิบายแนวคิด สำหรับระบบจริงควรปรับ Endpoint, Authentication, Status Code, Validation และ Business Rules ให้ตรงกับ API Contract ของระบบ