สมอง BC

คลังความรู้ / ระบบงานในชุด BC

#systems#tests#uat#playwright#postgres

บอท 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)

ที่มาในโค้ด