ลอง Playwright เทสแอพ React + Vite แบบง่ายๆ
หลังจากวันก่อน ได้ลองใช้งาน Playwright ไป วันนี้ก็เลยลองเอาตัว Playwright มาลองทำ testing ง่ายๆ ด้วยการจำลองเว็บ โดยใช้ default เว็บ ของ React + Vite (เว็บที่เป็น counter)

สร้างโปรเจ็คไว้เทส
เริ่มแรก ผมสร้างเว็บ เพื่อจะเอาไว้เทสก่อน ซึ่งใช้ starter ของ React + Vite เลย
npm create vite@latest my-react-app -- --template react-ts
จากนั้น ก็ install
cd my-react-app
npm install
ผมมีการเพิ่ม Input นิดหน่อย เพื่อให้เวลา Input และกด Set Title ให้มันไปเปลี่ยนค่า React + Vite เป็นค่าที่เราใส่ ไฟล์ src/App.tsx
ผมปรับแต่งนิดหน่อย แบบนี้
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
function App() {
const [count, setCount] = useState(0)
const [title, setTitle] = useState('Vite + React')
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
const formData = new FormData(e.currentTarget)
setTitle(formData.get('title') as string)
}
return (
<div className="App">
<div>
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://reactjs.org" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>{title}</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<form onSubmit={handleSubmit}>
<input type="text" name="title" className="input-title" />
<button type="submit">Set Title</button>
</form>
</div>
)
}
export default App
เมื่อลองรัน dev server จะเป็น url http://localhost:5173 และหน้าตาก็ประมาณนี้

ซึ่งถ้าเราดูตัวเว็บ React สิ่งที่มีคือ
- มี document title ชื่อ Vite + React + TS
- มีปุ่ม count ( count is 0 เริ่มต้น) เมื่อเรากด ค่ามันก็จะเพิ่มทีละ 1
- มี input เพื่อ set ค่า title (
h1
)
ทีนี้ ส่วนของเทส ผมก็จะตั้งเทสเคส ไว้ 3 ตัว คร่าวๆ คือ
- เทสว่า เว็บมี document title หรือไม่
- เทสว่า เมื่อกด count ค่าจะเพิ่มตามจำนวนคลิ๊กมั้ย
- เทสว่า เมื่อพิมพ์ input และกด Set Title ค่า heading 1 จะเปลี่ยนมั้ย
สร้างโปรเจ็ค Playwright
npm init playwright@latest
เช็ค document title
import { test, expect } from '@playwright/test'
const BASE_URL = 'http://localhost:5173/'
test('has document title', async ({ page }) => {
await page.goto(BASE_URL)
await expect(page).toHaveTitle('Vite + React + TS')
await page.screenshot({ path: `screenshots/example-has-title.png` })
})
เทสนี้ไม่มีอะไรมาก
- สั่งให้เปิดเว็บด้วย
page.goto()
- เช็คว่า
page
มี document title มั้ย ด้วย.toHaveTitle()
- ลอง screenshot ถ่ายรูปไว้ด้วย ด้วยคำสั่ง
page.screenshot
เทส click count button
test('click count button', async ({ page }) => {
await page.goto(BASE_URL)
const counter = page.locator('.card button')
counter.click()
await expect(counter).toHaveText('count is 1')
})
- ก็เปิดเว็บ React ด้วย
goto()
เหมือนเดิม - จากนั้น ใช้
page.locator
เพื่อหา element ด้วย selector.card button
แบบเดียวกับ css / js - เมื่อได้ element ก็ทำการกด click 1 ที
element.click()
- สุดท้าย expect ว่า element ต้องมี text เป็น count is 1
เรื่องของ locator เราสามารถใช้ ได้หลายวิธีเช่น หา button ในเพจนี้
page.locator('.card button')
page.getByRole('button')
- มีโอกาสได้ หลาย elementspage.getByText('count is 0')
- ใช้ได้เฉพาะเริ่มต้นครั้งแรก
ส่วนตัวผมชอบใช้ selector มากกว่า เพราะถ้าเคสนี้ใช้ getByRole()
หรือ getByText()
เวลา expect ก็จะหา element นั้นไม่เจอ เพราะค่า มันเปลี่ยนแล้ว
const counter = await page.getByRole('button', { name: 'count is 0' })
counter.click()
// ✅
await expect(page.locator('.card button')).toHaveText('count is 1')
// ❌
await expect(counter).toHaveText('count is 1')
เทส set heading title
test('set heading title', async ({ page }) => {
await page.goto(BASE_URL)
const input = page.locator('input')
await input.fill('Hello World')
const button = page.locator('button[type=submit]')
button.click()
await expect(page.locator('h1')).toHaveText('Hello World')
await page.screenshot({ path: `screenshots/example-set-title.png` })
})
เทสสุดท้าย เริ่มจาก
page.goto
เพื่อเปิดเว็บ- หา element ด้วย
page.locator
เนื่องจากเว็บมี input ที่เดียว - ทำการกรอกค่าด้วย
input.fill()
- หา element
button
ที่เป็นtype=submit
จากนั้นกด click - expect หา
h1
ต้องมีค่าHello World
- สุดท้าย screenshots ไว้ซักหน่อย
ลองรันเทส playwright ดูผลลัพธ์
npx playwright test
Running 9 tests using 5 workers
9 passed (4.7s)
To open last HTML report run:
npx playwright show-report
สุดท้าย ไฟล์ test ของผม react-vite.spec.ts
เผื่ออยากลองเอาไปรัน
import { test, expect } from '@playwright/test'
const BASE_URL = 'http://localhost:5173/'
test.describe('React Vite', () => {
test('has document title', async ({ page }) => {
await page.goto(BASE_URL)
await expect(page).toHaveTitle('Vite + React + TS')
await page.screenshot({ path: `screenshots/example-has-title.png` })
})
test('click count button', async ({ page }) => {
await page.goto(BASE_URL)
// const counter = page.locator('.card button')
const counter = await page.getByText('count is 0')
counter.click()
await expect(page.locator('.card button')).toHaveText('count is 1')
})
test('set heading title', async ({ page }) => {
await page.goto(BASE_URL)
const input = page.locator('input')
await input.fill('Hello World')
const button = page.locator('button[type=submit]')
button.click()
await expect(page.locator('h1')).toHaveText('Hello World')
await page.screenshot({ path: `screenshots/example-set-title.png` })
})
})
สรุป
วันนี้ก็ลองเทส Playwright ด้วยการใช้ Selector ง่ายๆ มีการ fill input และก็ take screenshot ไป หวังว่าบทความนี้ะเป็นไอเดีย และแนวทางให้ใครหลายๆ คนที่ลองใช้ Playwright ลองไปเล่นกันดูนะครับ
Happy Coding ❤️