SumoSunday

ซีรีส์ QA ใช้ AI ทำงาน · ตอนที่ 7 จาก 7

ให้ AI เขียน Automated Test ครั้งแรก แล้วแยกให้ออกว่าไม่ผ่านเพราะบั๊ก หรือเพราะหาปุ่มไม่เจอ

17 ต.ค. 2569 · อ่าน 9 นาที

เราให้ AI เขียน Test ด้วย Playwright ที่กดหน้าเว็บร้านค้าจำลองจริง รอบแรก Test ไม่ผ่านทั้ง 3 ข้อ แต่ไม่ใช่เพราะบั๊ก เป็นเพราะหาปุ่มไม่เจอ เมื่อส่งรายงานของ Playwright กลับไปให้แก้ รอบนี้ไม่ผ่าน 2 ข้อตรงกับบั๊กจริง ตอนสุดท้ายของซีรีส์ QA ใช้ AI ทำงาน เล่าทุกขั้น พร้อมกติกา 4 ข้อของ Test ที่เชื่อถือได้ และคำสั่งสำเร็จรูป

ตอนที่ 7 ซึ่งเป็นตอนสุดท้ายของซีรีส์ "QA ใช้ AI ทำงาน" ตลอดซีรีส์เราใช้ AI ช่วยคิด ช่วยร่าง และช่วยสรุป ตอนนี้ไปอีกขั้น คือให้ AI เขียน Automated Test ที่เปิดเบราว์เซอร์ กดหน้าเว็บ และตรวจผลเอง

เครื่องมือที่ใช้คือ Playwright ซึ่งสั่งงานเบราว์เซอร์ได้ด้วยโค้ด

ข้อมูล ณ ตุลาคม 2569 เราลองกับ Claude ครั้งละ 1 รอบ แล้วรัน Test จริงด้วย Playwright 1.63 บน Chromium กับร้านกาแฟตัวอย่าง (ร้านสมมติ) ที่เราสร้างไว้ทดสอบ

Test ที่เราอยากได้: ต้องไม่ผ่านกับร้านที่มีบั๊ก

Test ข้อแรกตรวจกรณีที่เรารู้จากตอนก่อนๆ ว่าร้านทำผิด คือ ยอดสินค้า 500 บาทพอดี ใส่ SAVE10 แล้วต้องใช้ได้ เพราะ Requirement บอกว่าขั้นต่ำคือ 500 บาท แล้วให้ AI เลือกอีก 2 กรณีเอง

Test ที่ดีต้องไม่ผ่าน (แดง) กับร้านนี้ เพราะร้านมีบั๊ก ถ้า Test ผ่าน (เขียว) แปลว่า Test ไม่ได้ตรวจเรื่องที่เราต้องการ

เราบอก Claude 2 อย่าง คือ Requirement ส่วนคูปองและค่าส่ง และหน้าตาเว็บแบบที่ QA เห็นในเบราว์เซอร์ เช่น "แต่ละแถวมีชื่อสินค้า ราคา และปุ่ม ใส่ตะกร้า"

รอบที่ 1: ไม่ผ่านทั้ง 3 ข้อ แต่ไม่ใช่เพราะบั๊ก

Claude ให้ Test มา 3 ข้อ อีก 2 ข้อที่ Claude เลือกเองดีมาก คือยอด 1,050 บาทใช้ SAVE10 แล้วต้องกลับมาเสียค่าส่ง และยอดสินค้า 450 บาทบวกค่าส่ง 50 บาท ต้องใช้โค้ดไม่ได้ เพราะขั้นต่ำไม่รวมค่าส่ง Claude ไม่ใช้การรอแบบกำหนดวินาที และตรวจผลด้วย expect ที่รอให้หน้าเว็บอัปเดตเอง

แต่เมื่อรันจริง Test ไม่ผ่านทั้ง 3 ข้อ ที่บรรทัดเดียวกัน คือหาปุ่ม "ใส่ตะกร้า" ไม่เจอ จนรอหมดเวลา Playwright รายงานว่ากำลังรอสิ่งนี้อยู่

prompt
waiting for locator('*').filter({ hasText: 'เมล็ดกาแฟคั่วกลาง 250 กรัม' })
  .filter({ has: getByRole('button', { name: 'ใส่ตะกร้า', exact: true }) })

สาเหตุคือบนจอ ปุ่มเขียนว่า "ใส่ตะกร้า" แต่ชื่อที่โปรแกรมอ่านหน้าจอและ Playwright เห็นคือ "ใส่ตะกร้า เมล็ดกาแฟคั่วกลาง 250 กรัม" Claude เขียน Test จากคำบรรยายของเรา จึงไม่มีทางรู้เรื่องนี้

นี่คือกับดักแรก Test ไม่ผ่านไม่ได้แปลว่าเจอบั๊กเสมอไป ต้องอ่านว่าไม่ผ่านเพราะอะไร

รอบที่ 2: ส่งรายงานของ Playwright กลับไปให้ Claude แก้

เมื่อ Test ไม่ผ่าน Playwright จะสร้างไฟล์รายงานให้ ในไฟล์มี error และ Page snapshot ซึ่งคือโครงหน้าเว็บจริงพร้อมชื่อปุ่มทุกปุ่ม เราส่งไฟล์นี้ให้ Claude พร้อมสั่งว่า ห้ามเปลี่ยนสิ่งที่ Test แต่ละข้อตรวจ

Claude แก้ชื่อปุ่ม และยังเจออีกจุดที่จะพังต่อ คือบรรทัดยอดเงินที่ป้ายกับตัวเลขอยู่แยกกัน Claude บอกด้วยว่ายังไม่ได้รัน และเดาไว้ 3 อย่างเรื่องหน้าตาตะกร้า

เมื่อรันอีกรอบ ได้ผลดังนี้

Testผลเพราะ
ยอด 500 พอดี ใช้ SAVE10 ได้ไม่ผ่านร้านขึ้น "ใช้โค้ดไม่ได้" (บั๊ก)
ยอด 1,050 ใช้ SAVE10 ต้องเสียค่าส่งไม่ผ่านคาดว่าค่าส่ง 50 ร้านให้ 0 (บั๊ก)
ยอด 450 ใช้ SAVE10 ไม่ได้ผ่านร้านทำถูก

รอบนี้ Test ไม่ผ่านเพราะบั๊กจริง ทั้ง 2 ข้อ

ตรวจว่า Test ผ่านได้เมื่อร้านทำงานถูก

Test ที่ไม่ผ่านตลอดก็ใช้ไม่ได้เหมือนกัน เราจึงทำสำเนาร้านแล้วแก้บั๊ก 2 ตัวนั้น เมื่อรัน Test ชุดเดิม ผ่านทั้ง 3 ข้อ ตอนนี้เราเชื่อได้ว่า Test แดงเมื่อควรแดง และเขียวเมื่อควรเขียว

เราเขียน Test ใหม่ให้อ่านง่ายขึ้น

Test ของ Claude ใช้งานได้ แต่ยาวเกือบ 100 บรรทัด และมีตัวช่วยที่ใช้ regex กับ XPath ซึ่งคนในทีมอ่านยาก เราจึงเขียนใหม่ให้สั้นลง นี่คือข้อแรก

โค้ด TypeScript
import { test, expect } from '@playwright/test';

test('ยอดสินค้า 500 พอดี ใช้ SAVE10 ได้', async ({ page }) => {
  await page.goto('/');
  await page.getByRole('button', { name: 'ใส่ตะกร้า เมล็ดกาแฟคั่วกลาง 250 กรัม' }).click();
  await page.getByRole('button', { name: 'ใส่ตะกร้า ดริปแบ็ก 10 ซอง' }).click();
  await expect(page.locator('#subtotal')).toHaveText('500');

  await page.getByLabel('โค้ดส่วนลด').fill('SAVE10');
  await page.getByRole('button', { name: 'ใช้โค้ด' }).click();

  await expect(page.getByRole('status')).toHaveText('ใช้โค้ด SAVE10 แล้ว');
  await expect(page.locator('#discount')).toHaveText('-50');
  await expect(page.locator('#total')).toHaveText('500');
});

จุดที่เปลี่ยนสำคัญที่สุดคือ ตรวจข้อความในกล่องแสดงผลของโค้ดส่วนลดตรงๆ เมื่อ Test ไม่ผ่าน รายงานจะบอกเลยว่าร้านตอบอะไร เช่น

prompt
Expected: "ใช้โค้ด SAVE10 แล้ว"
Received: "ใช้โค้ดไม่ได้: ยอดสินค้าขั้นต่ำ 500 บาท"

ส่วน Test ของ Claude รายงานแค่ว่า "หาข้อความไม่เจอ" เราต้องเปิดดูเองว่าเกิดอะไรขึ้น

มีจุดหนึ่งที่เรายังไม่พอใจ ตัวเลขยอดเงินในหน้านี้ไม่มีชื่อที่ผู้ใช้เห็นผูกอยู่ เราจึงอ้างถึงด้วย id ของ element ซึ่งเอกสาร Playwright ไม่แนะนำ ทางที่ดีกว่าคือขอให้ Dev เพิ่ม test id ไว้ให้ Test ใช้โดยเฉพาะ

กติกา 4 ข้อของ Test ที่เชื่อถือได้

  1. หาสิ่งต่างๆ บนหน้าเว็บแบบที่ผู้ใช้เห็น เอกสาร Playwright แนะนำให้ใช้ role เป็นหลัก เช่น ปุ่มชื่ออะไร ช่องที่มีป้ายอะไร และไม่แนะนำ CSS หรือ XPath เพราะโครงหน้าเว็บเปลี่ยนบ่อย ถ้าไม่แน่ใจชื่อจริง ให้ใช้ตัวสร้าง Test ของ Playwright ช่วยหา หรือดู Page snapshot
  2. ไม่รอแบบกำหนดวินาที ให้ใช้ expect ที่รอเอง เอกสารเขียนไว้ตรงๆ ว่า Test ที่รอตามเวลา "ไม่เสถียรโดยธรรมชาติ" ข้อนี้ Claude ทำถูกตั้งแต่แรก
  3. 1 Test ตรวจ 1 พฤติกรรม ชื่อ Test บอกได้ว่าตรวจอะไร เมื่อ Test ไม่ผ่านก็รู้ทันทีว่าเรื่องไหนพัง
  4. พิสูจน์ว่า Test แดงเมื่อควรแดง อ่านว่าไม่ผ่านเพราะบั๊กหรือเพราะหาของไม่เจอ แล้วลองกับระบบที่ถูก หรือแก้โค้ดให้ผิดสักจุด เหมือนที่เราทำในตอนที่ 6

คำสั่งสำเร็จรูป: ให้ AI แก้ Test ที่พังโดยไม่ลดสิ่งที่ตรวจ

คำสั่งนี้ดัดแปลงจากคำสั่งที่เราใช้ในรอบที่ 2 ให้ใช้กับงานทั่วไปได้

prompt
test ที่คุณเขียนให้ (ชื่อไฟล์ [ชื่อไฟล์]) รันแล้ว fail [กี่ข้อ]
ข้างล่างคือรายงานจาก Playwright มี error และ Page snapshot ของหน้าเว็บจริงตอนที่ fail

ช่วยบอกก่อนว่า fail เพราะ test หาของบนหน้าไม่เจอ หรือเพราะระบบทำงานไม่ตรงกับที่ test คาด
ถ้าเป็นเพราะหาของไม่เจอ ให้แก้วิธีหา โดยใช้ role และชื่อจาก Page snapshot
ห้ามเปลี่ยนผลที่คาดหวัง ห้ามลบ assertion และห้ามใช้การรอแบบกำหนดเวลา
ถ้าเป็นเพราะระบบทำงานไม่ตรง ห้ามแก้ test ให้ผ่าน ให้สรุปว่าน่าจะเป็นบั๊กอะไร

[วางเนื้อหาไฟล์ error-context.md ที่ Playwright สร้างให้]

ทำไมได้ผล: การถามก่อนว่าไม่ผ่านเพราะอะไร ช่วยแยก "Test พัง" ออกจาก "ระบบพัง" Page snapshot ทำให้ AI ไม่ต้องเดาชื่อปุ่ม และการห้ามเปลี่ยนผลลัพธ์ที่คาดหวัง (Expected Result) กับห้ามลบ Assertion ช่วยกันไม่ให้ AI ทำให้ Test ผ่านด้วยการตรวจน้อยลง

สรุปทั้งซีรีส์

AI เขียน Automated Test ได้เร็ว เลือกกรณีได้ดี และแก้ตามรายงานได้ แต่ AI เขียนจากสิ่งที่เราเล่า ถ้าเราเล่าไม่ครบ Test ก็พังด้วยเหตุผลที่ไม่เกี่ยวกับบั๊ก งานของ QA คืออ่านว่า Test ไม่ผ่านเพราะอะไร และพิสูจน์ว่า Test แดงเมื่อควรแดง

ตลอด 7 ตอน เราใช้ AI ช่วยอ่าน Requirement เขียน Test Case และรายงานบั๊ก คิดว่าควรลองอะไร ทำข้อมูลทดสอบ ตรวจ Test และเขียน Automated Test ทุกขั้น AI ช่วยได้จริง และทุกขั้นยังต้องมีคนรันกับของจริงและตัดสินใจ

สิ่งที่เจอจากทั้งซีรีส์ เรารวมไว้เป็นเช็กลิสต์ทดสอบร้านออนไลน์และหน้าชำระเงิน 41 ข้อ (ไฟล์ Excel) ดาวน์โหลดได้ที่หน้าเทมเพลต โดยต้องสมัครสมาชิกฟรีก่อนดาวน์โหลด อ่านซีรีส์ตั้งแต่ต้นได้ที่ตอนที่ 1

ใครอยากไปต่อเรื่อง Automated Test แบบจริงจัง เรากำลังทำคอร์ส "QA Automation ด้วย Claude Code" วางแผนจะใช้ร้านจำลองนี้ ตั้งแต่เขียน Test แรกจนวางเป็นระบบที่รันได้ทุกครั้งที่แก้โค้ด

อาทิตย์ละสกิล เดี๋ยวก็เก่ง