แปลง Manual Test Steps เป็น Automation ด้วย AI
บทนี้พาคุณใช้ AI ลดเวลาแปลง manual test ที่มีอยู่แล้วเป็น automation script โดยรักษาความหมายของ test ไว้ ไม่ใช่แค่ port code ตามตัวอักษร
จบบทนี้แล้วคุณจะ...
- มี workflow ในการแปลง manual test case ให้เป็น automation script ด้วย AI
- รู้ว่าเมื่อไหร่ควร "แปลงตรง" และเมื่อไหร่ควร "เขียนใหม่"
- รักษา intent ของ manual test ไว้แม้ว่า script ที่ได้จะหน้าตาต่าง
- จัดการ test data, precondition และ cleanup ใน automation อย่างถูก
Manual test ไม่ได้ออกแบบให้ run อัตโนมัติ
Manual test step มักเขียนแบบ:
1. เปิดเว็บ
2. คลิกปุ่ม Login ที่มุมขวาบน
3. รอให้หน้า login โหลด
4. กรอก email
5. กรอก password
6. คลิก Submit
7. รอประมาณ 3 วินาที
8. เห็นหน้า dashboard
ถ้าแปลงตรงเป็น Playwright จะได้ script ที่:
- มี
waitForTimeout(3000)ที่ไม่จำเป็น - assertion ขั้นสุดท้ายแค่ "เห็นหน้า dashboard" — กว้างไป
- ไม่มี data setup, ใช้ user อะไรก็ได้
- ถ้า fail ไม่รู้ว่าพังขั้นไหน
ปัญหา: manual test เขียนเพื่อ "บอกให้คนทำตาม" ไม่ใช่ "บอก machine ให้ verify behavior" ความตั้งใจคือเหมือน แต่รูปแบบต้องเปลี่ยน
โครงที่ใช้ได้กับทุก test case
ขั้น 1: ดึง intent ของ test
อ่าน manual step แล้วถาม: "test นี้ตั้งใจ verify อะไร"
คำตอบควรเป็น 1 ประโยค:
- "user ที่มี account valid login แล้วเห็น dashboard ของตัวเอง"
- "user ที่ใส่ password ผิด 3 ครั้งจะถูก lock 15 นาที"
- "guest user เพิ่มสินค้าใส่ตะกร้าได้โดยไม่ต้อง login"
intent นี้คือสิ่งที่ test ใหม่ต้องรักษาไว้ ส่วนที่เหลือเปลี่ยนได้
ขั้น 2: ระบุ data + precondition + cleanup
manual test มักไม่ระบุชัด แต่ automation ต้องมี:
- Data: user ใช้ account ไหน? balance เท่าไหร่? state ของระบบ?
- Precondition: ต้องมี cart ว่าง? login มาก่อน?
- Cleanup: หลัง test เสร็จต้อง reset อะไร?
ถ้าไม่ระบุ test จะ flaky หรือ pollute test อื่น
ขั้น 3: prompt AI ให้แปลงโดยใส่ทั้ง intent และ data
Convert this manual test to a Playwright TypeScript test.
Manual test:
[PASTE]
Intent of this test (most important):
"User with valid credentials logs in and sees their personalized dashboard"
Data:
- Test user: [email protected] / Pass1234
- Expected dashboard greeting: "Welcome back, Test User"
Convention:
- Use getByRole and getByTestId
- No waitForTimeout
- Add explicit assertions for each milestone
Output: single test file.
AI จะ gen script ที่รักษา intent ไม่ใช่แค่ port step
ดูความต่างที่จับต้องได้
Manual test:
TC-LOGIN-001: User can login with valid credentials
1. เปิด https://app.example.com
2. คลิก "Login" มุมขวาบน
3. กรอก email "[email protected]"
4. กรอก password "Pass1234"
5. คลิก Submit
6. รอประมาณ 3 วินาที
7. ตรวจสอบว่าเห็นหน้า dashboard
แปลงตรง (แย่):
test('login', async ({ page }) => {
await page.goto('https://app.example.com');
await page.click('text=Login');
await page.fill('#email', '[email protected]');
await page.fill('#password', 'Pass1234');
await page.click('button:has-text("Submit")');
await page.waitForTimeout(3000);
await expect(page.locator('.dashboard')).toBeVisible();
});
แปลงโดยรักษา intent (ดี):
import { test, expect } from '@playwright/test';
test.describe('Login', () => {
test('user with valid credentials sees personalized dashboard', async ({ page }) => {
await page.goto('/');
await page.getByRole('link', { name: 'Login' }).click();
await expect(page).toHaveURL(/\/login/);
await page.getByLabel('Email').fill('[email protected]');
await page.getByLabel('Password').fill('Pass1234');
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL(/\/dashboard/);
await expect(
page.getByRole('heading', { name: /Welcome back, Test User/ })
).toBeVisible();
});
});
ความต่างที่สำคัญ:
- มี explicit assertion หลังคลิก Login (URL เปลี่ยนหรือยัง)
- ไม่มี hard wait
- assert content เฉพาะ ("Welcome back, Test User") ไม่ใช่แค่ element มี
- locator stable
บาง test ดีกว่าเขียนใหม่ตั้งแต่ต้น
ห้ามแปลง:
- Exploratory test: test ที่ตั้งใจให้คนใช้ judgment ระหว่างทำ — automation ทำแทนไม่ได้
- Visual perception test: "ตรวจว่า UI สวย" / "หา bug ที่ไม่คาด" — automation ไม่ทำแทนคน
- Test ที่เขียนไว้นานแล้ว irrelevant: feature เปลี่ยนไปแล้ว — เขียน test ใหม่ตาม feature ปัจจุบัน
- Test ที่ verify "feel": "user feels confident" / "system seems fast" — assertion วัดไม่ได้
ถ้าเจอ manual test แบบนี้ แทนที่จะแปลง ให้คุยกับทีมว่ายังจำเป็นไหม หรือต้องเขียนใหม่ในรูปแบบที่ automate ได้
เมื่อต้องแปลง 50+ test cases
ถ้ามี manual test เยอะที่จะแปลง อย่า prompt ทีละอัน:
- ระบุ data ที่ต้องใช้ทั้งหมดก่อน — gen test users / fixtures ครั้งเดียว
- group test ที่ใช้ flow คล้ายกัน — แปลงพร้อม shared Page Object
- แปลง happy path ก่อน, edge case ทีหลัง
- หลังแปลงครบ run ทั้งชุดดู flaky test ที่ต้องแก้ก่อน merge
วิธีนี้ลดเวลา review เพราะ pattern ของ test ทั้ง batch จะใกล้กัน
แบบฝึก: แปลง manual test เป็น Playwright
แปลง manual test ด้านล่างเป็น Playwright test ที่มี intent ชัดและไม่มี anti-pattern:
TC-CART-005: Guest user adds item to cart
1. เปิด /products
2. คลิกที่สินค้าชิ้นแรก
3. รอให้หน้า detail โหลด
4. คลิก "Add to cart"
5. รอ 2 วินาที
6. ตรวจสอบว่าตะกร้ามีสินค้า
ระบุ intent ก่อน แล้วเขียน script
ดูคำตอบแนะนำ
Intent: "Guest user (ไม่ login) สามารถเพิ่มสินค้าจาก product list ลงตะกร้าได้ และตะกร้าแสดงจำนวนถูกต้อง"
Data:
- ไม่มี user login
- product ใด ๆ ที่มี stock > 0
Script:
import { test, expect } from '@playwright/test';
test.describe('Cart', () => {
test('guest user can add a product to cart from product list', async ({ page }) => {
await page.goto('/products');
const firstProduct = page.getByTestId('product-card').first();
const productName = await firstProduct.getByRole('heading').textContent();
await firstProduct.click();
await expect(page.getByRole('heading', { name: productName ?? '' })).toBeVisible();
await page.getByRole('button', { name: 'Add to cart' }).click();
await expect(page.getByTestId('cart-count')).toHaveText('1');
await page.getByRole('link', { name: /cart/i }).click();
await expect(page.getByText(productName ?? '')).toBeVisible();
});
});
ตรวจ intent: assert ทั้งจำนวนใน cart icon + ตรวจว่าสินค้าที่เพิ่มเข้าไปคือสินค้าที่คลิก
สิ่งที่ต้องเอาติดตัวไปจากบทนี้
- แปลงตรง manual → automation มักได้ test ที่ flaky และ assert อ่อน
- ดึง intent ของ manual test ก่อน อย่า port step ตามตัวอักษร
- ระบุ data, precondition, cleanup ที่ manual test ละไว้
- บางประเภทของ manual test ไม่ควรแปลง (exploratory, visual)
- batch conversion ต้องวางแผน fixture และ shared object ก่อน