บอท UAT ในเครื่อง (tests/uat)
ชุดนี้คือสคริปต์ Node ที่ขับ Chrome ผ่าน Playwright เปิดหน้าจอจริงของ ERP แล้วตรวจย้อนไปถึง API และฐานข้อมูลทุกขั้น เขียนขึ้นเพื่อให้ "บอท" หลายตัว แต่ละตัวสวมบทผู้ใช้หนึ่งตำแหน่ง ไล่ทดสอบพร้อมกันได้ บอทมีหน้าที่ ทดสอบและรายงานเท่านั้น ห้ามแก้โค้ดแอป (tests/uat/BRIEF.md:3) ภาพรวมของชุดทดสอบทั้งโปรเจกต์อยู่ที่ ระบบทดสอบ ภาพรวม: บอท UAT, Stagehand, Playwright และ Go test (Tests Overview)
บอทแต่ละตัว
| ไฟล์ | บทบาทที่จำลอง | ขอบเขต |
|---|---|---|
bots/p00-pilot.mjs |
ต้นแบบ | พิสูจน์ว่า lib.mjs ครบวงจร (เปิดจอ + API + ฐานข้อมูล) ในหน้าจอกลุ่มผู้ใช้ ใช้เป็นแม่แบบของบอทอื่น |
b01.mjs |
แอดมินตั้งค่าระบบ | เมนูตั้งค่า menu_setup_* ทั้ง 8 กลุ่ม แยกเฟส smoke / master / special |
b02.mjs |
ผู้ดูแลฐานข้อมูลและสิทธิ์ | เมนูระบบในแอป (หน้า /login, /select-database, /admin/* ถูกปิดไว้ในโหมดเดโม) เฟส smoke, audit, tools, designers, xcheck, heavy หน้าจอสำรอง/คืนข้อมูล/ย่อฐาน/เปลี่ยนรหัสหลัก/นำเข้า/ซ่อมรายการ เปิดดูอย่างเดียว ไม่กดปุ่มรัน |
b03.mjs |
เจ้าหน้าที่ทะเบียนสินค้าและราคา | เฟส smoke, item, price, barcode |
b04.mjs |
เจ้าหน้าที่คลังสินค้า | เอกสารคลัง เลือกขั้นที่จะรันด้วย env UAT_STEPS (รายการ ib,if,rio,io,ir,rim,im,ia,is,co,cancel,inq) และเฟส smoke / flows / reports |
b05.mjs |
เจ้าหน้าที่จัดซื้อ | เมนู menu_po เฟส smoke / flows / reports เลือกขั้นด้วย env UAT_STAGES |
b06.mjs |
พนักงานขาย | เมนู menu_so เสนอราคา, อนุมัติ, จอง, ใบสั่งขาย, ใบกำกับ, ลดหนี้/เพิ่มหนี้, มัดจำ, ยกเลิก, รายงาน |
b07.mjs |
เจ้าหน้าที่เจ้าหนี้ | ทะเบียนเจ้าหนี้และเอกสารเจ้าหนี้ |
b08.mjs |
เจ้าหน้าที่ลูกหนี้ | ทะเบียนลูกหนี้, เอกสาร, ล้างข้อมูลทดสอบท้ายงาน (เฟส cleanup) |
b09.mjs |
เจ้าหน้าที่การเงิน/ธนาคาร | เฟส smoke / flows / reports |
b10.mjs |
นักบัญชี/ผู้ตรวจข้ามโมดูล | กระทบยอดทั้งบัญชีเป็นการอ่านอย่างเดียว (เฟส recon) และงานสมุดรายวัน/สินทรัพย์ของตัวเอง (เฟส flows) |
b11.mjs |
ผู้ดูแลระบบ/ผู้ทดสอบความปลอดภัยโซนแอดมิน | /login, /select-database, /admin/*, /api/admin/* เฟส guard, smoke, crud |
ตัวช่วยกลาง lib.mjs
ทุกบอท import จาก tests/uat/lib.mjs (บอทห้ามแก้ไฟล์นี้) ฟังก์ชันหลัก:
| ฟังก์ชัน | หน้าที่ |
|---|---|
menuLeaves(roots) (:33) |
อ่าน frontend/src/config/bcMenu.json แล้วคืนรายการเมนูใบที่ผู้ใช้เห็นจริงใต้เมนูแม่ที่ระบุ ใช้กฎการมองเห็นเดียวกับ bcMenu.ts (ข้ามเมนูที่ติดแท็ก &hide&) |
startBot(id) (:74) |
เปิด Chrome ขนาด 1600x900 locale ไทย สร้างโฟลเดอร์ผลลัพธ์ out/<runId>/<id>/ และเก็บ event ที่เป็น HTTP 400 ขึ้นไป, JS error, console error |
openMenu(bot, key) (:132) |
เปิดเมนูด้วย URL /home?open=<key> แล้วรอแท็บของเมนูนั้นสูงสุด 45 วินาที |
smoke(bot, leaf) (:187) |
ด่านตรวจหนึ่งเมนู (ดูหัวข้อถัดไป) |
bot.api(method, path, data) (:114) |
เรียก API ผ่าน Playwright โดยใช้คุกกี้ที่ล็อกอินอยู่ และเก็บคำขอ/คำตอบเป็นไฟล์ api-NNN.json เป็นหลักฐาน |
sql(query, vars, db) (:207) |
รัน psql โดยส่งค่าผ่านตัวแปร :'name' และส่ง SQL ทาง stdin (ภาษาไทยไม่เพี้ยน) อ่านการเชื่อมต่อจากไฟล์ตั้งค่า backend ชื่อ backend/configs/BCConfigbcdemo.json ตอนรัน และปฏิเสธถ้าโฮสต์ไม่ใช่เครื่องนี้ |
bot.finding({...}) (:108) |
เขียนปัญหาหนึ่งรายการต่อท้าย findings.jsonl |
bot.shot(name), bot.drain() |
ถ่ายภาพหน้าจอ และดึงเหตุการณ์ที่ค้างตั้งแต่การเรียกครั้งก่อน |
ตอนเปิดหน้าเว็บ lib.mjs ฉีดสคริปต์ดักจับ (:52-72): ล้างแท็บที่จำไว้ใน localStorage, บันทึก fetch ที่ล้มและ promise ที่ไม่ถูกจัดการ และแทนที่ confirm/alert ด้วยฟังก์ชันที่ตอบรับอัตโนมัติพร้อมจดข้อความไว้ ตัวแปร env ที่ใช้ได้: UAT_BASE_URL (ค่าเริ่มต้นคือเว็บเดโมในเครื่อง ตรวจให้เป็น localhost เท่านั้น), UAT_RUN_ID (ค่าเริ่มต้นคือวันที่วันนี้), UAT_HEADED=1 (เปิดหน้าต่างให้เห็น), UAT_DB_CONFIG, PSQL (ที่อยู่ psql)
smoke ตรวจอะไรในแต่ละเมนู
smokeOnce (lib.mjs:149-184) เปิดเมนู รอ 1.5 วินาที แล้วตรวจ:
| ระดับ | เงื่อนไข |
|---|---|
| S2 | เมนูไม่ขึ้นหน้าจอใน 45 วินาที, หน้าจอแสดงข้อความ error ของฐานข้อมูล (เช่น SQLSTATE, "column ... does not exist"), มี JS error, API ตอบ 5xx หรือ 404 ใต้ /api/ |
| S3 | มีข้อความ F1-F12 บนปุ่ม/ป้าย, ป้ายภาษาไทยมีชื่อฟิลด์ที่มีขีดล่างในวงเล็บ |
| S4 | หน้าจอไม่มีหัวเรื่อง h1 |
ปัญหาระดับ S2 จะถูกบันทึกก็ต่อเมื่อรันซ้ำรอบที่สองแล้วเจออีก เพื่อไม่ให้เสียงรบกวนจากจังหวะเวลา (lib.mjs:187-199) กฎ UI ที่ใช้ตรวจมาจาก AGENTS.md ของโปรเจกต์ (ข้อ 1, 4, 17, 18) ตามที่ BRIEF.md:21 ระบุ
ปัญหา (finding) และระดับความรุนแรง
แต่ละปัญหาเป็นหนึ่งบรรทัด JSON ใน out/<runId>/<id>/findings.jsonl มี id รูปแบบ <บอท>-NNN (นับต่อเนื่องแม้รันบอทเดิมซ้ำ), severity, layer (UI / API / DB), title, expected, actual, steps, หลักฐาน (ภาพ ไฟล์ API แถว SQL) และ suspectCode เฉพาะเมื่ออ่านโค้ดแล้วมั่นใจ (BRIEF.md:35-38)
| ระดับ | ความหมายตาม BRIEF |
|---|---|
| S1 | เงิน ภาษี สต็อก หรือบัญชีผิด ข้อมูลหาย ข้ามสิทธิ์ |
| S2 | ฟังก์ชันหลักพังหรือหน้าจอล่ม |
| S3 | ผิดกฎ UI มาตรฐานหรือมีทางเลี่ยง |
| S4 | ถ้อยคำหรือการจัดวาง |
ก่อนบันทึก S1/S2 ต้องทำซ้ำอีกครั้ง และห้ามบันทึกปัญหาของสคริปต์เองเป็นบั๊กของแอป
การรวมและเปรียบเทียบผล
node tests/uat/merge.mjs <runId>รวมfindings.jsonlของทุกบอทในรอบนั้น จัดกลุ่มตามสาเหตุ (layer+title) เขียนsummary.mdและsummary.jsonโดยกลุ่มจะใช้ระดับที่รุนแรงที่สุดของสมาชิก (merge.mjs:1-44)node tests/uat/compare.mjs <runId> [baselineRunId]เทียบรอบใหม่กับรอบฐาน แต่ละกลุ่มปัญหาเดิมได้ผล "ยังพบ" / "ไม่พบแล้ว" / "ไม่ได้ทดสอบ" และแสดงปัญหาใหม่ แล้วเขียนcompare.mdการเทียบชื่อปัญหาจะปิดตัวเลขและรหัสเอกสารก่อน เพราะเลขที่เอกสารเปลี่ยนทุกรอบ ชื่อที่ถูกเขียนใหม่จะออกเป็นคู่ "ไม่พบแล้ว" + "ใหม่" ให้คนตรวจต่อ (compare.mjs:1-23)
วิธีรัน
cd <ราก repo>
UAT_RUN_ID=<YYYYMMDD> UAT_PHASE=smoke node tests/uat/bots/b03.mjs
UAT_RUN_ID=<YYYYMMDD> node tests/uat/smoke-all.mjs
node tests/uat/merge.mjs <YYYYMMDD>
เว็บ (โหมดเดโม FORCE_BCDEMO=1), Go API และ PostgreSQL ต้องรันอยู่แล้ว บอทไม่สตาร์ทหรือหยุดบริการเอง และหยุดรายงานถ้าเว็บหรือ API ไม่ตอบ (BRIEF.md:5-9) ต้องติดตั้ง Playwright ในโฟลเดอร์ tests/playwright ก่อน เพราะ lib.mjs นำเข้าจากที่นั่น (lib.mjs:4-5) บอทที่ทำงานยาว (b04, b05 ฯลฯ) แบ่งเฟสด้วย env UAT_PHASE และเก็บเลขเอกสารที่สร้างไว้ใน out/<run>/<id>/state.json เพื่อรันต่อได้หลังล้ม
กติกาข้อมูลที่บอทต้องทำตาม
- ก่อนลบ ยกเลิก หรือแก้แล้วบันทึก ต้องอ่านรหัสบนหน้าจอและทำต่อเมื่อเป็นรหัสของบอทเอง (
UATB<NN>) เพราะบางหน้าจอเลือกแถวแรกเองเมื่อค้นหาช้า เคยทำให้ลบสินค้าเดโมผิดตัวมาแล้ว (BRIEF.md:29) - หน้าตั้งค่า (เช่น ตัวเลือกระบบ รูปแบบเลขที่เอกสาร) ให้อ่านค่าเดิมจากฐานข้อมูล เปลี่ยนช่องที่ไม่กระทบหนึ่งช่อง ตรวจ แล้วคืนค่าเดิมและตรวจซ้ำ ห้ามแตะประเภทปี อัตรา VAT วันที่งวด ข้อมูลบริษัท (
BRIEF.md:32) - เมนูปิดงวด ปิดปี ประมวลผลกำไรขาดทุน ยกเลิกผ่านรายการ เปลี่ยนรหัสหลัก และส่ง e-Tax เปิดดูเท่านั้น (
BRIEF.md:33) - เอกสารห้ามลบด้วย SQL ให้ยกเลิกผ่านหน้าจอ แล้วตรวจว่ารายการบัญชีและสต็อกกลับรายการ และเอกสารที่ยกเลิกแล้วยกเลิกซ้ำไม่ได้ (
BRIEF.md:51) - หลังบันทึกหรือยกเลิกทุกเอกสาร ตรวจด้วย SQL: หัวบิลกับรายการ,
gl_journal_detailของเอกสารนั้น เดบิตเท่าเครดิต, ผลกระทบสต็อก, ยอดค้างap_ar_trans, เลขที่เอกสารตรงรูปแบบในerp_doc_format, ตัวเลขบนจอตรงฐานข้อมูลถึงสตางค์ (BRIEF.md:52) - บอทชุดเอกสาร (b04-b09) รันพร้อมกันบนฐานเดียวกัน จึงแบ่งสินค้า ลูกค้า ผู้ขาย ตามลำดับ (offset) ไม่ให้ชนกัน (
BRIEF.md:48)
ลำดับรอบที่ใช้จริง
BRIEF แบ่งงานเป็น 4 รอบ: รอบ 1 บอทชุดแรก (BRIEF อ้างถึง b03 ว่าอยู่ในรอบนี้) รอบ 2 บอทเอกสาร b04-b09 รันพร้อมกัน รอบ 3 บอท b10 รันคนเดียวทีหลังสุดเพื่อกระทบยอดทั้งสมุดบัญชี (เดบิตเท่าเครดิตทุกเลขที่เอกสาร, งบทดลอง, รายงานภาษี ภ.พ.30 และ ภ.ง.ด., อายุลูกหนี้/เจ้าหนี้เทียบบัญชีคุม, สต็อก) และรอบ 3b บอท b11 ทดสอบโซนแอดมินบนเว็บอีกตัวที่ไม่เปิดโหมดเดโม ด้วยเซสชันที่สร้างและเซ็นในหน่วยความจำ (ค่าลับของเซสชันอ่านตอนรันจากไฟล์ตั้งค่าของ frontend ไม่พิมพ์และไม่เก็บ) ตรวจว่าไม่มีคุกกี้ คุกกี้สิทธิ์ต่ำ หรือเซสชันหมดอายุ ต้องถูกปฏิเสธ (BRIEF.md:43-80)
ที่มาในโค้ด
tests/uat/lib.mjs:14-18ค่าตั้งต้นและล็อกเฉพาะเครื่อง,:33-49menuLeaves,:52-72สคริปต์ดักจับ,:74-129startBot,:149-199smoke,:207-216sqltests/uat/BRIEF.md:3-9หลักการและเงื่อนไขการรัน,:28-33กติกาข้อมูล,:35-38finding,:43-55รอบ 2,:57-70รอบ 3,:72-81รอบ 3btests/uat/merge.mjs:1-44รวมผล,tests/uat/compare.mjs:1-59เทียบผล,tests/uat/smoke-all.mjs:1-29smoke ทุกเมนูtests/uat/bots/b01.mjs:1-3,b04.mjs:1-4,b10.mjs:1-3,b11.mjs:1-3ส่วนหัวของบอท (เฟส env และขอบเขต)- ดูเพิ่ม: ระบบทดสอบ ภาพรวม: บอท UAT, Stagehand, Playwright และ Go test (Tests Overview) · Stagehand, Playwright และ Go test: ทดสอบด้วย AI, สคริปต์ตรวจหน้าจอ และชุดทดสอบ backend · ระบบ UAT ภาพรวม: บอททดสอบอัตโนมัติและ Chaos Lab (UAT System Overview) · รูปแบบสคริปต์ทดสอบและตัวรัน (UAT Script Format and Runner)