01บทนำ · About This Guide
Test scope · deliverables · references
เอกสารนี้เป็น Test Documentation สำหรับหน้าจอ Workflow Lifecycle v5.0 ครอบคลุม:
- Test Scenarios · 14 areas — Template list · Create/Edit · Steps · Transitions · SVG diagram · NCR loop
- Test Cases · 70 cases — Positive / Negative / Boundary / UI / Integration / A11y
- Playwright Automation Guide — POM · sample scripts · state machine testing
- NCR Sub-Loop coverage — 3 NCR states + Sub Contractor role + 5 NCR transitions
📌
Reference file:
ConstructQ_WorkflowLifecycle_v5.0.html · React SPA · 3 templates seeded · 10 states (7 base + 3 NCR) · 6 triggers · SVG state diagram with cubic bezier arrows · TH/EN toggle02Screen Overview
Template list · designer · state diagram · 3 templates
🗺️ Screen Map
| View | State | Function |
|---|---|---|
| Template List | view=list | 3 workflow template cards · Standard · Simple · NCR-Loop |
| Template Picker | modal | Pick starting template for new workflow |
| Create/Edit Form | view=designer | Steps table + Transitions table + SVG State Diagram (live preview) |
| Save Confirm Modal | modal | Summary before publish |
| Delete Confirm | modal | Warning + Cancel/Confirm |
🎨 10 States (7 base + 3 NCR sub-loop)
| State | Color | Terminal | Main Row | Purpose |
|---|---|---|---|---|
| created | Blue | No | ✅ Yes | Task created · awaiting assign |
| assigned | Purple | No | ✅ Yes | Assigned to inspector |
| in_progress | Gold | No | ✅ Yes | Inspection in progress |
| review | Teal | No | ✅ Yes | Reviewer approving result |
| done | Green | ✅ Yes | ✅ Yes | Task closed |
| blocked | Coral | No | No (below) | Paused on blocker |
| rejected | Pink | No | No (below) | Result rejected · returns to assigned |
| ncr_open | Red | No | NCR row | Defect found · NCR raised · awaiting Sub |
| ncr_fixing | Orange | No | NCR row | Sub is fixing the NCR |
| ncr_verify | Gold-brown | No | NCR row | Awaiting QC Inspector verify |
⚡ 6 Triggers
| Trigger | Style | Meaning |
|---|---|---|
| auto | solid indigo | System auto-transitions (no user action) |
| pass | solid green | Inspector/reviewer marks result as passed |
| fail | dashed red | Inspector/reviewer marks result as failed |
| block | solid orange | User raises blocker (waiting on external) |
| unblock | solid teal | Blocker resolved · resume progress |
| cancel | solid pink | User cancels task |
📋 3 Seeded Templates
| # | Icon | Name TH | Steps | Transitions | NCR Loop? |
|---|---|---|---|---|---|
| 1 | ⭐ | Workflow มาตรฐาน QC ก่อสร้าง | 7 | 8 | No |
| 2 | 🪶 | ตรวจสอบอย่างง่าย (3 ขั้นตอน) | 3 | 2 | No |
| 3 | 🔧 | Workflow มาตรฐาน + รอบแก้ NCR | 10 | 13 | ✅ Yes |
🔄 NCR Sub-Loop Transitions (v5.0 new)
| From | → | To | Trigger | Note |
|---|---|---|---|---|
| in_progress | → | ncr_open | fail | พบ defect · dashed line going down |
| ncr_open | → | ncr_fixing | auto | Sub รับ NCR · solid purple right |
| ncr_fixing | → | ncr_verify | pass | Sub ส่งการแก้ · solid green right |
| ncr_verify | → | ncr_fixing | fail | Inspector ไม่ผ่าน · curved back |
| ncr_verify | → | in_progress | pass | Inspector อนุมัติ · NCR ปิดอัตโนมัติ · up+left |
03Test Strategy
Test types · priority · environments
🎯 Test Types
| Type | Objective | Coverage |
|---|---|---|
| Positive | Create/Edit/Save/Delete workflows | ~35% |
| Negative | Missing state · invalid trigger · orphan transition | ~20% |
| Boundary | 0 steps · 100+ steps · single state · loop cycles | ~10% |
| UI/UX | SVG diagram render · color/style · arrows · animation | ~15% |
| Integration | State machine consistency · task lifecycle enforcement | ~10% |
| Accessibility | Keyboard · ARIA · contrast · SVG semantics | ~10% |
⚡ Priority
- P1 — Critical · save · state machine integrity · NCR sub-loop
- P2 — High · UI accuracy · role assignment · validation
- P3 — Medium · language toggle · edge cases · polish
🌐 Environments
- Local: localStorage-backed · 3 seeded templates as fixtures
- Staging: Backend + DB · workflow templates table · seed script
- UAT: Real users test NCR loop end-to-end with actual QC + Sub Contractor
04Test Scenarios + Test Cases
14 areas · 70 detailed test cases
4.1 · 📚 Landing + Template List
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-01 | เข้าหน้า Workflow Lifecycle | 1. Login (admin_org) 2. Navigate to Master Data → Workflow |
AppShell · breadcrumb · title "🔄 Workflow Lifecycle" · 3 template cards | P1 | Pos |
| TC-02 | 3 seeded template cards render | 1. View list | 3 cards: ⭐ มาตรฐาน · 🪶 อย่างง่าย · 🔧 มาตรฐาน+NCR · แต่ละใบมี name TH+EN · desc · version chip | P1 | Pos |
| TC-03 | Status badge "published" visible | 1. View card | All 3 templates show published badge | P2 | UI |
| TC-04 | Click card → open designer | 1. Click ⭐ template | Designer view opens with template pre-filled | P1 | Pos |
| TC-05 | "➕ สร้าง Workflow ใหม่" button | 1. Click Create button | Template picker modal opens | P1 | Pos |
4.2 · 🎯 Template Picker
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-06 | Picker shows 3 templates + blank | 1. Open picker | 4 options: Blank · Standard · Simple · NCR-Loop | P1 | Pos |
| TC-07 | Select Standard · Continue | 1. Click ⭐ Standard 2. Confirm |
Designer opens with 7 steps + 8 transitions pre-loaded | P1 | Pos |
| TC-08 | Select NCR-Loop · Continue | 1. Click 🔧 NCR-Loop | Designer opens with 10 steps + 13 transitions incl. NCR sub-loop | P1 | Pos |
| TC-09 | Blank · empty designer | 1. Click "เริ่มจากเปล่า" | Designer opens · 0 steps · 0 transitions · empty diagram | P2 | Pos |
| TC-10 | Cancel picker | 1. Click Cancel/backdrop | Picker closes · stays on list view | P2 | Pos |
4.3 · ➕ Create Template
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-11 | Fill name + description | 1. Enter name TH/EN + desc | Fields accept input · saved to draft | P1 | Pos |
| TC-12 | Version default v1.0 | 1. Leave version empty · Save | Defaults to "v1.0" | P2 | Bnd |
| TC-13 | Required · name TH empty | 1. Skip name · Save | Error · block save | P1 | Neg |
| TC-14 | Icon selection | 1. Choose emoji icon | Icon saved with template | P3 | UI |
| TC-15 | Circular back icon (v2.0+) | 1. View designer header | Circular ◀ button before title | P3 | UI |
4.4 · ✏️ Edit Existing Template
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-16 | Open existing · pre-filled | 1. Click ⭐ template | Steps + transitions + diagram all pre-loaded | P1 | Pos |
| TC-17 | Save updates · same ID | 1. Edit name · Save | Same ID · updated name in list | P1 | Pos |
| TC-18 | Unsaved changes warning | 1. Edit · click ◀ back | Warning "มีการแก้ไข · ออกจริงไหม?" | P2 | Neg |
4.5 · 📋 Steps Editor
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-19 | Add step row | 1. Click "+ Step" | New empty row · auto-id "s-XXXXXX" | P1 | Pos |
| TC-20 | State dropdown · 10 options | 1. Click state dropdown | 10 states: created, assigned, in_progress, review, done, blocked, rejected, ncr_open, ncr_fixing, ncr_verify | P1 | Pos |
| TC-21 | Role field · text input | 1. Type "QC Inspector" | Role saved · role suggestions (QCM, PM, QC Inspector, Sub Contractor) | P2 | Pos |
| TC-22 | SLA hours · numeric only | 1. Type "abc" | Reject non-numeric | P2 | Neg |
| TC-23 | Note TH + EN bilingual | 1. Enter noteTh + noteEn | Both saved · shown per language toggle | P2 | Pos |
| TC-24 | Delete step | 1. Click delete on row | Row removed · related transitions warning if any | P1 | Pos |
| TC-25 | Reorder steps · drag/drop | 1. Drag s-2 above s-1 | Order updates · diagram updates | P2 | Pos |
| TC-26 | Duplicate state · warning | 1. Add 2 steps with state=created | Warning "state ซ้ำ" · but allow (business rule) | P3 | Bnd |
4.6 · 🔀 Transitions Editor
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-27 | Add transition row | 1. Click "+ Transition" | New empty row · auto-id "t-XXXXXX" | P1 | Pos |
| TC-28 | From/To dropdown · only defined states | 1. Open From dropdown | Options limited to states defined in Steps table | P1 | Pos |
| TC-29 | Trigger dropdown · 6 options | 1. Open trigger dropdown | auto · pass · fail · block · unblock · cancel | P1 | Pos |
| TC-30 | Duplicate transition · same from+to+trigger | 1. Add 2 identical transitions | Warning "transition ซ้ำ" · block or override | P2 | Neg |
| TC-31 | Orphan transition · reference undefined state | 1. Add transition with from="foo" (no state) | Warning icon · block save | P1 | Neg |
| TC-32 | Label TH/EN bilingual | 1. Enter labelTh + labelEn | Both saved · shown on arrows per language | P2 | Pos |
| TC-33 | Delete transition · arrow removed | 1. Delete t-1 | Row + arrow both removed from diagram | P1 | Pos |
4.7 · 🎨 SVG State Diagram
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-34 | Diagram renders 7 main states in row | 1. Open Standard template | 7 state boxes: created→assigned→in_progress→review→done (main row) + blocked+rejected (below) | P1 | UI |
| TC-35 | State box color matches WF_STATES | 1. Inspect each box | created=blue · assigned=purple · done=green · rejected=pink · etc. | P2 | UI |
| TC-36 | Arrows · forward (right) | 1. Verify created→assigned | Solid line · left-to-right · marker at end | P1 | UI |
| TC-37 | Arrows · backward (curved) | 1. Verify rejected→assigned | Curved bezier · goes back | P2 | UI |
| TC-38 | Arrows · downward (main → below) | 1. Verify in_progress→blocked | Arrow goes down | P2 | UI |
| TC-39 | Arrow style per trigger | 1. Compare pass vs fail arrows | pass=solid green · fail=dashed red · auto=solid indigo | P2 | UI |
| TC-40 | Arrow label bilingual | 1. Toggle TH/EN | Labels update (e.g. "อนุมัติ" → "Approve") | P2 | Pos |
| TC-41 | Live update · edit step → diagram refreshes | 1. Delete a step 2. Verify diagram |
State box disappears · related arrows removed | P1 | Int |
| TC-42 | Empty state · no steps | 1. Blank template | Empty diagram placeholder message | P3 | UI |
4.8 · 🔄 NCR Sub-Loop Workflow (v5.0)
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-43 | NCR template loads · 10 states | 1. Open 🔧 NCR-Loop template | Steps table has 10 rows including 3 NCR states | P1 | Pos |
| TC-44 | NCR states render below main row | 1. View diagram | NCR row (y=224) below main row · ncr_open, ncr_fixing, ncr_verify visible | P1 | UI |
| TC-45 | in_progress → ncr_open (fail down) | 1. Verify transition | Dashed red arrow going down from in_progress | P1 | UI |
| TC-46 | ncr_open → ncr_fixing (auto right) | 1. Verify transition | Solid purple arrow to the right | P1 | UI |
| TC-47 | ncr_fixing → ncr_verify (pass right) | 1. Verify transition | Solid green arrow right | P1 | UI |
| TC-48 | ncr_verify → ncr_fixing (fail curve) | 1. Verify transition | Dashed red curved arrow back | P1 | UI |
| TC-49 | ncr_verify → in_progress (pass up+left) | 1. Verify NCR close transition | Solid green arrow · goes up + left · closes NCR loop | P1 | UI |
| TC-50 | Sub Contractor role · assigned to ncr_fixing | 1. View step s-5 | Role = "Sub Contractor" | P1 | Pos |
| TC-51 | NCR SLA hours · Sub 48h | 1. View SLA for ncr_fixing | slaHours = 48 | P2 | Pos |
4.9 · 👥 Role Assignment
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-52 | Role suggestions dropdown | 1. Click role field | Suggestions: QCM · PM · QC Inspector · Sub Contractor · CEO | P2 | Pos |
| TC-53 | Terminal state role = "—" | 1. View "done" step | Role field = "—" (no role needed after close) | P3 | UI |
| TC-54 | Sub Contractor · only in NCR templates | 1. Compare Standard vs NCR-Loop | Standard has no Sub · NCR-Loop uses Sub Contractor for ncr_fixing | P2 | Pos |
4.10 · 💾 Save + Validation
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-55 | Save valid workflow · success | 1. Complete fields · Save | Toast success · redirect to list · new/updated card | P1 | Pos |
| TC-56 | Save with 0 steps · blocked | 1. Empty steps · Save | Error "ต้องมี Step อย่างน้อย 1 รายการ" | P1 | Neg |
| TC-57 | Save with no terminal state · warning | 1. Remove "done" step · Save | Warning "ไม่มี terminal state · task ปิดไม่ได้" | P1 | Neg |
| TC-58 | Save with unreachable state · warning | 1. Add step no incoming transition · Save | Warning "state ไม่มี path เข้าถึง" | P2 | Neg |
| TC-59 | Save confirm popup | 1. Click Save button | Popup summary: name, version, #steps, #transitions | P1 | Pos |
4.11 · 🗑️ Delete + Publish Status
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-60 | Delete confirm dialog | 1. Delete workflow | Modal warning "ลบ workflow? · Task ที่ใช้จะถูกกระทบ" | P1 | Pos |
| TC-61 | Confirm delete · removed | 1. Confirm | Workflow หายจาก list · toast success | P1 | Pos |
| TC-62 | Publish · status = published | 1. Click "เผยแพร่" | Status changes to "published" · badge updates | P1 | Pos |
| TC-63 | Draft mode · not selectable in Task Mgmt | 1. Create draft · check Task Mgmt | Only published workflows available | P2 | Int |
4.12 · 🌐 Language Toggle TH/EN (v3.0)
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-64 | Toggle TH → EN · React page updates | 1. Click EN flag | State names · labels · steps · transitions text switch to EN | P1 | Pos |
| TC-65 | Data preserved on toggle | 1. Fill · toggle · toggle back | Data intact | P1 | Pos |
4.13 · 💾 Data Persistence
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-66 | Refresh · 3 seed persist | 1. F5 | 3 seeded templates still present | P1 | Int |
| TC-67 | Custom workflow persists | 1. Create custom · reload | Custom still in list | P1 | Int |
| TC-68 | Clear localStorage · fallback to 3 seed | 1. Clear storage · reload | Reverts to 3 seed templates | P3 | Int |
4.14 · ♿ Accessibility
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-69 | Keyboard nav · full designer | 1. Tab through steps → transitions → save | Focus visible · logical order | P2 | A11y |
| TC-70 | SVG diagram · ARIA + contrast | 1. Screen reader on SVG · axe scan | State names announced · arrows have title · contrast ≥ 4.5:1 | P2 | A11y |
📊
Test Case Summary: รวม 70 test cases · P1 = 32 · P2 = 28 · P3 = 10 · Positive 27 · Negative 8 · Boundary 3 · Integration 5 · UI 21 · A11y 2
05Playwright Automation Guide + Sample Scripts
Setup · POM · sample tests for state machine · NCR loop
🚀 Setup
- Install:
npm init playwright@latest - Fixture reset: Seed 3 templates before each test
- SVG testing: Query SVG elements via
page.locator('svg [data-state="ncr_open"]') - State machine assertions: Verify counts + relationships + arrow styles
📁 Project Structure
treetests/workflow/ ├── list.spec.ts # TC-01 to TC-05 ├── template-picker.spec.ts # TC-06 to TC-10 ├── create.spec.ts # TC-11 to TC-15 ├── edit.spec.ts # TC-16 to TC-18 ├── steps-editor.spec.ts # TC-19 to TC-26 ├── transitions.spec.ts # TC-27 to TC-33 ├── svg-diagram.spec.ts # TC-34 to TC-42 ├── ncr-loop.spec.ts # TC-43 to TC-51 (CRITICAL) ├── role-assign.spec.ts # TC-52 to TC-54 ├── save-validation.spec.ts # TC-55 to TC-59 ├── delete-publish.spec.ts # TC-60 to TC-63 ├── language.spec.ts # TC-64, TC-65 ├── persistence.spec.ts # TC-66 to TC-68 ├── a11y.spec.ts # TC-69, TC-70 └── e2e-full-flow.spec.ts # Composite smoke pages/ ├── WorkflowListPage.ts ├── WorkflowDesignerPage.ts ├── StepsEditor.ts ├── TransitionsEditor.ts └── SVGDiagram.ts fixtures/ └── seed-workflows.json playwright.config.ts
🎯 Page Object Model · WorkflowDesignerPage
TypeScriptimport { Page, Locator, expect } from '@playwright/test'; export type StateId = 'created' | 'assigned' | 'in_progress' | 'review' | 'done' | 'blocked' | 'rejected' | 'ncr_open' | 'ncr_fixing' | 'ncr_verify'; export type Trigger = 'auto' | 'pass' | 'fail' | 'block' | 'unblock' | 'cancel'; export class WorkflowDesignerPage { readonly page: Page; readonly nameTh: Locator; readonly nameEn: Locator; readonly version: Locator; readonly btnAddStep: Locator; readonly btnAddTransition: Locator; readonly btnSave: Locator; readonly stepRows: Locator; readonly transitionRows: Locator; readonly svgDiagram: Locator; constructor(page: Page) { this.page = page; this.nameTh = page.locator('#wfNameTh'); this.nameEn = page.locator('#wfNameEn'); this.version = page.locator('#wfVersion'); this.btnAddStep = page.getByRole('button', { name: /\+ Step/ }); this.btnAddTransition = page.getByRole('button', { name: /\+ Transition/ }); this.btnSave = page.getByRole('button', { name: /บันทึก|Save/ }); this.stepRows = page.locator('.wf-step-row'); this.transitionRows = page.locator('.wf-trans-row'); this.svgDiagram = page.locator('svg.wf-diagram'); } async addStep(state: StateId, role: string, slaHours: number = 4, note?: string) { await this.btnAddStep.click(); const last = this.stepRows.last(); await last.locator('.wf-state-select').selectOption(state); await last.locator('.wf-role-input').fill(role); await last.locator('.wf-sla-input').fill(String(slaHours)); if (note) await last.locator('.wf-note-input').fill(note); } async addTransition(from: StateId, to: StateId, trigger: Trigger, label?: string) { await this.btnAddTransition.click(); const last = this.transitionRows.last(); await last.locator('.wf-from-select').selectOption(from); await last.locator('.wf-to-select').selectOption(to); await last.locator('.wf-trigger-select').selectOption(trigger); if (label) await last.locator('.wf-label-input').fill(label); } async save() { await this.btnSave.click(); await this.page.getByRole('dialog').waitFor({ state: 'visible' }); await this.page.getByRole('button', { name: /ยืนยัน|Confirm/ }).click(); } // SVG diagram helpers async stateBox(state: StateId): Promise<Locator> { return this.svgDiagram.locator(`[data-state="${state}"]`); } async arrowExists(from: StateId, to: StateId, trigger: Trigger): Promise<boolean> { const arrow = this.svgDiagram.locator( `[data-from="${from}"][data-to="${to}"][data-trigger="${trigger}"]` ); return (await arrow.count()) > 0; } }
✅ Sample Test 1 · Standard Template Creation
TypeScriptimport { test, expect } from '@playwright/test'; import { WorkflowDesignerPage } from '../pages/WorkflowDesignerPage'; test.describe('Workflow · Standard Template', () => { test.beforeEach(async ({ page }) => { await page.goto('/master-data/workflow'); }); test('TC-02 · 3 seeded templates render', async ({ page }) => { const cards = page.locator('.wf-card'); await expect(cards).toHaveCount(3); await expect(page.getByText('Workflow มาตรฐาน QC')).toBeVisible(); await expect(page.getByText('ตรวจสอบอย่างง่าย')).toBeVisible(); await expect(page.getByText('Workflow มาตรฐาน + รอบแก้ NCR')).toBeVisible(); }); test('TC-07 · Create Standard workflow from scratch', async ({ page }) => { await page.getByRole('button', { name: /สร้าง Workflow ใหม่/ }).click(); await page.getByText('⭐ Standard').click(); await page.getByRole('button', { name: /เริ่มต้น|Continue/ }).click(); const designer = new WorkflowDesignerPage(page); await expect(designer.stepRows).toHaveCount(7); // 7 base states await expect(designer.transitionRows).toHaveCount(8); // 8 base transitions }); });
✅ Sample Test 2 · NCR Sub-Loop (CRITICAL v5.0)
TypeScripttest.describe('Workflow · NCR Sub-Loop v5.0', () => { test('TC-43 · NCR template loads · 10 states', async ({ page }) => { await page.goto('/master-data/workflow'); await page.getByText('Workflow มาตรฐาน + รอบแก้ NCR').click(); const designer = new WorkflowDesignerPage(page); await expect(designer.stepRows).toHaveCount(10); // Verify all 3 NCR states present for (const state of ['ncr_open', 'ncr_fixing', 'ncr_verify'] as const) { const box = await designer.stateBox(state); await expect(box).toBeVisible(); } }); test('TC-45 → TC-49 · All 5 NCR transitions render correctly', async ({ page }) => { await page.goto('/master-data/workflow'); await page.getByText('Workflow มาตรฐาน + รอบแก้ NCR').click(); const designer = new WorkflowDesignerPage(page); // 1. in_progress → ncr_open (fail down) expect(await designer.arrowExists('in_progress', 'ncr_open', 'fail')).toBe(true); // 2. ncr_open → ncr_fixing (auto right) expect(await designer.arrowExists('ncr_open', 'ncr_fixing', 'auto')).toBe(true); // 3. ncr_fixing → ncr_verify (pass right) expect(await designer.arrowExists('ncr_fixing', 'ncr_verify', 'pass')).toBe(true); // 4. ncr_verify → ncr_fixing (fail curve back) expect(await designer.arrowExists('ncr_verify', 'ncr_fixing', 'fail')).toBe(true); // 5. ncr_verify → in_progress (pass up+left · NCR close) expect(await designer.arrowExists('ncr_verify', 'in_progress', 'pass')).toBe(true); }); test('TC-50 · Sub Contractor role assigned to ncr_fixing', async ({ page }) => { await page.goto('/master-data/workflow'); await page.getByText('Workflow มาตรฐาน + รอบแก้ NCR').click(); const ncrFixingRow = page.locator('.wf-step-row[data-state="ncr_fixing"]'); const roleInput = ncrFixingRow.locator('.wf-role-input'); await expect(roleInput).toHaveValue('Sub Contractor'); const slaInput = ncrFixingRow.locator('.wf-sla-input'); await expect(slaInput).toHaveValue('48'); }); });
✅ Sample Test 3 · Build Custom Workflow End-to-End
TypeScripttest('TC-E2E-01 · Build custom NCR workflow from scratch', async ({ page }) => { const designer = new WorkflowDesignerPage(page); // Open blank designer await page.goto('/master-data/workflow'); await page.getByRole('button', { name: /สร้าง Workflow ใหม่/ }).click(); await page.getByText('เริ่มจากเปล่า').click(); // Fill basic info await designer.nameTh.fill('Workflow ทดสอบ NCR'); await designer.nameEn.fill('Test NCR Workflow'); await designer.version.fill('v1.0'); // Add 5 main states + 3 NCR states await designer.addStep('created', 'QCM', 4); await designer.addStep('assigned', 'QCM', 8); await designer.addStep('in_progress', 'QC Inspector', 24); await designer.addStep('ncr_open', 'QC Inspector', 2); await designer.addStep('ncr_fixing', 'Sub Contractor', 48); await designer.addStep('ncr_verify', 'QC Inspector', 4); await designer.addStep('done', '—', 0); // Add all NCR transitions await designer.addTransition('created', 'assigned', 'auto'); await designer.addTransition('assigned', 'in_progress', 'auto'); await designer.addTransition('in_progress', 'ncr_open', 'fail'); // NCR trigger await designer.addTransition('ncr_open', 'ncr_fixing', 'auto'); await designer.addTransition('ncr_fixing', 'ncr_verify', 'pass'); await designer.addTransition('ncr_verify', 'ncr_fixing', 'fail'); // re-fix await designer.addTransition('ncr_verify', 'in_progress', 'pass'); // NCR close await designer.addTransition('in_progress', 'done', 'pass'); // Save with confirm popup await designer.save(); // Verify list shows 4 templates now (3 seed + 1 new) await expect(page.locator('.wf-card')).toHaveCount(4); await expect(page.getByText('Workflow ทดสอบ NCR')).toBeVisible(); });
✅ Sample Test 4 · SVG Diagram Arrow Style Verification
TypeScripttest('TC-39 · Arrow style per trigger', async ({ page }) => { await page.goto('/master-data/workflow'); await page.getByText('Workflow มาตรฐาน QC').click(); // Verify pass arrow · solid green const passArrow = page.locator('svg [data-from="review"][data-to="done"][data-trigger="pass"]'); await expect(passArrow).toHaveAttribute('stroke', '#27AE60'); await expect(passArrow).not.toHaveAttribute('stroke-dasharray', /.+/); // no dash // Verify fail arrow · dashed red const failArrow = page.locator('svg [data-from="review"][data-to="rejected"][data-trigger="fail"]'); await expect(failArrow).toHaveAttribute('stroke', /#DC2626|#FF5A7A/); await expect(failArrow).toHaveAttribute('stroke-dasharray', /.+/); // has dash // Verify auto arrow · solid indigo const autoArrow = page.locator('svg [data-trigger="auto"]').first(); await expect(autoArrow).not.toHaveAttribute('stroke-dasharray', /.+/); });
✅ Sample Test 5 · Language Toggle (v3.0)
TypeScripttest('TC-64 · Language TH → EN updates React page content', async ({ page }) => { await page.goto('/master-data/workflow'); // Default TH · check Thai text await expect(page.getByText('Workflow มาตรฐาน QC ก่อสร้าง')).toBeVisible(); // Toggle to EN await page.locator('[data-lang="en"]').click(); // Verify EN content await expect(page.getByText('Standard Construction QC Workflow')).toBeVisible(); // Open template · verify state labels also switch await page.getByText('Standard Construction QC Workflow').click(); await expect(page.getByText('Assigned')).toBeVisible(); // state name EN await expect(page.getByText('In Progress')).toBeVisible(); });
🎭 Fixture · Reset localStorage Before Each Test
TypeScript// tests/setup.ts import seed from '../fixtures/seed-workflows.json'; test.beforeEach(async ({ page }) => { await page.addInitScript((data) => { localStorage.setItem('wf_templates', JSON.stringify(data)); }, seed); });
💡
Best Practices: Use
data-state · data-from · data-to · data-trigger attributes on SVG for reliable selectors · verify state machine consistency via counts (7 states → 8 transitions typical) · always test NCR loop via all 5 transitions · confirm popup as checkpoint06Appendix
📌 Version History
- ConstructQ_WorkflowLifecycle_v5.0.html · source · NCR sub-loop diagram drawing complete
- เอกสารนี้ v1.0 · 13 ก.ค. 2569 · 70 test cases · Playwright + sample scripts
🔗 References
- Playwright Docs:
https://playwright.dev - State machine testing:
https://xstate.js.org/docs/ - Related file:
ConstructQ_WorkflowLifecycle_ER_v2.0.html·Tables_v2.0.xlsx - Excel companion:
ConstructQ_Workflow_TestScenario_v1.0.xlsx
🌳 3 Seeded Templates Reference
| ID | Icon | Steps | Transitions | NCR Loop |
|---|---|---|---|---|
wf-tpl-qc-standard | ⭐ | 7 | 8 | No |
wf-tpl-simple | 🪶 | 3 | 2 | No |
wf-tpl-ncr-loop | 🔧 | 10 | 13 | ✅ Yes |