บทที่ 5 · Part 1 — Foundations
Setup and First Test
ติดตั้ง Playwright Test, วาง config และเขียน test แรกที่รันซ้ำได้บน Chromium, Firefox และ WebKit
Setup and First Test
test แรกที่ผ่านบนเครื่องคนเขียนอาจ fail บน CI เพราะ browser binary คนละรุ่น, base URL ต่างกัน หรือ dev server ยังไม่พร้อม Setup ที่ดีจึงต้องทำ version, environment และ run command ให้ reproducible ตั้งแต่วันแรก ไม่รอแก้เมื่อ suite โตแล้ว
จบบทนี้คุณจะ
สร้าง Playwright Test project ด้วย TypeScript ตั้งค่า browsers, baseURL, webServer, reports
และเขียน test แรกที่ใช้ semantic locator กับ web-first assertion
Version Baseline และ Installation
ตัวอย่างคอร์สนี้อ้างอิง @playwright/test 1.62.1 ซึ่งเผยแพร่ 30 กรกฎาคม 2026 และเป็น stable ล่าสุด
ที่ตรวจสอบ ณ วันที่ 10 สิงหาคม 2026 ให้ project จริง pin
version ผ่าน lockfile และ upgrade package กับ browser binaries พร้อมกัน เริ่ม project ใหม่ตาม
installation guide:
npm init playwright@latest
npx playwright install --with-deps
คำสั่งแรกสร้าง config, example test และ workflow ตามตัวเลือก ส่วน install --with-deps ติดตั้ง browser
binaries กับ OS dependencies ที่ต้องใช้ บน laptop ที่มี dependencies แล้วใช้ npx playwright install
ได้ แต่ CI image ใหม่ควรติดตั้งตาม official guidance ของ platform นั้น
ไฟล์หลักขั้นต่ำ:
playwright.config.ts
tests/
ui/
api/
src/
fixtures/
pom/
test-data/
ยังไม่ต้องสร้าง abstraction ทุก folder ตั้งแต่แรก ให้เพิ่มเมื่อมี behavior จริง แต่แยก UI/API ตั้งแต่ต้น ช่วยให้ projects, timeout และ suite selection ชัด
Config ที่อธิบายเหตุผลได้
import { defineConfig, devices } from '@playwright/test'
const appURL = process.env.APP_BASE_URL ?? 'http://127.0.0.1:4173'
new URL(appURL) // fail fast ถ้าค่าไม่ใช่ URL
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: Boolean(process.env.CI),
retries: process.env.CI ? 2 : 0,
reporter: process.env.CI
? [['line'], ['html', { open: 'never' }], ['blob']]
: [['list'], ['html', { open: 'never' }]],
use: {
baseURL: appURL,
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
],
webServer: process.env.CI
? undefined
: {
command: 'npm run dev',
url: appURL,
reuseExistingServer: true,
},
})
ค่า retry ไม่ใช่ universal best value: เริ่มจาก zero ใน local เพื่อเห็น failure ทันที ใช้ CI retry เพื่อเก็บหลักฐานว่า intermittent หรือไม่ แล้วติดตาม flaky classification อย่ากำหนด timeout 60 วินาทีทั้ง suite เพราะ endpoint เดียวช้า ให้ใช้ timeout เฉพาะ assertion/operation ที่มี latency budget ต่างจริง
webServer เหมาะกับ local application ที่ runner เปิดเอง ถ้า CI deploy preview environment ก่อนรันอยู่แล้ว
ให้ส่ง APP_BASE_URL และไม่เปิด server ซ้ำ ตรวจ health/readiness ของ environment ก่อน test เสมอ
Test แรก: ค้นหา Workshop
import { expect, test } from '@playwright/test'
test('SEARCH-001 - shows workshops matching the learner query', async ({ page }) => {
await page.goto('/workshops')
await page.getByRole('searchbox', { name: 'Search workshops' }).fill('Playwright')
const results = page.getByRole('region', { name: 'Search results' })
await expect(results.getByRole('article')).toHaveCount(1)
await expect(
results.getByRole('heading', { name: 'Reliable Browser Tests' }),
).toBeVisible()
})
test นี้ไม่เก็บ ElementHandle, ไม่รอด้วย sleep และไม่ select .result-card มันค้นหา control ผ่าน
accessible role/name แล้วใช้ assertion ที่ retry จน UI เข้า state ที่คาดภายใน timeout
Projects ไม่ใช่แค่ Browser List
Project เป็น configuration group ใช้แยก browser, mobile viewport, locale, logged-in state หรือ API suite ได้ เช่น API tests ไม่ต้องเปิด browser:
projects: [
{
name: 'api',
testMatch: 'tests/api/**/*.spec.ts',
use: { baseURL: process.env.API_BASE_URL },
},
{
name: 'desktop-chromium',
testMatch: 'tests/ui/**/*.spec.ts',
use: { ...devices['Desktop Chrome'] },
},
]
หลีกเลี่ยง project matrix ที่ทุก role × browser × locale รันทุก test หาก claim ไม่ต้องการ เช่น contract API ไม่ต้องรัน 3 browser ส่วน critical keyboard interaction อาจต้องรันทุก browser ที่ support
Scripts และคำสั่งที่ทีมใช้ร่วมกัน
{
"scripts": {
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
"test:e2e:api": "playwright test --project=api",
"test:e2e:smoke": "playwright test --grep @smoke",
"report:e2e": "playwright show-report"
}
}
คำสั่งใช้งานประจำวันที่ควรรู้:
npx playwright test
npx playwright test tests/ui/workshops/search.spec.ts
npx playwright test --project=firefox
npx playwright test --grep @smoke
npx playwright test --headed
npx playwright test --debug
npx playwright test --ui
อย่าให้แต่ละคนจำ long command ต่างกัน Scripts เป็น public interface ของ repository และ CI ควรใช้ command เดียวกับ local เท่าที่เป็นไปได้
Environment และ Secrets
config ควร fail fast เมื่อ required variable หายหรือ malformed แต่ห้าม log secret เพื่อ debug ใช้ test account สิทธิ์ต่ำ แยก environment และเก็บ credential ใน secret manager ของ CI
const required = (name: string): string => {
const value = process.env[name]
if (!value) throw new Error(`Missing required environment variable: ${name}`)
return value
}
export const env = {
apiBaseURL: new URL(required('API_BASE_URL')).toString(),
learnerEmail: required('E2E_LEARNER_EMAIL'),
learnerPassword: required('E2E_LEARNER_PASSWORD'),
}
Error บอกชื่อ key ที่ขาดได้แต่ไม่พิมพ์ value .env, auth state, trace และ reports ต้องอยู่ใน
.gitignore ซึ่งจะลงลึกในบท Authentication and Authorization
รายการตรวจสอบ
- Package และ browser binaries มาจาก Playwright version เดียวกัน
- Config มีเหตุผลสำหรับ projects, retries, timeouts และ reporters
-
forbidOnlyเปิดบน CI - Base URL validate ก่อนเริ่ม suite
- Test แรกใช้ role/name locator และ assertion ที่ retry ได้
- Artifact กับ environment files ไม่ถูก commit
สรุปบทนี้
Setup ที่ดีทำให้ laptop และ CI รัน contract เดียวกัน Version, browser, environment และ command ต้อง reproducible ก่อนเพิ่ม abstraction หรือ test cases จำนวนมาก