Test Strategy

Per-phase test gates. No phase exits without these green.


Test pyramid (per repo)

LayerCurvaPasukuru BEPasukuru FE
UnitPest unit (Services, Builders)Jest unit (Services)Vitest unit (utils)
IntegrationPest feature (HTTP)Jest e2e (HTTP+DB)Playwright (cmp+API)
End-to-endCurva → Pasukuru via real HTTPSameCypress/Playwright LIFF (mock SDK)
ManualAdmin flows in browserPostman / curl scriptsLINE app on real device

Phase 0 test gates

TestLayerRequired forStatus
Migration up + downunit0.P-1
Identify endpoint mocked LINE responsejest e2e(Phase 1, but stub Phase 0)
Order event emit on status changejest unit0.P-4
Order builder per eventjest unit0.P-5
HMAC signing canonical stringjest unit0.P-7
HMAC verify rejects bad sigpest feature0.C-2
Webhook receiver persists logpest feature0.C-1
Replay nonce rejectedpest feature0.C-2
Smoke: pasukuru → curva order roundtripmanualPhase 0 exit

Phase 1 test gates

TestLayerRequired for
LIFF init mocked in jsdomvitest1.F-2
useLiff returns expected shapevitest1.F-3
Identify returns JWTjest e2e1.P-2
JWT shop_token resolves tenantjest e2e1.P-9
Auto-identify happens onceplaywright1.F-5
Stripe checkout works in LIFFmanual1.F-7
Smoke: LINE friend → LIFF → buymanualPhase 1 exit

Phase 2 test gates

TestLayer
Product cache event handlerspest unit
Sync command idempotentpest feature
Picker generates valid Flex JSONplaywright
RichMenu LIFF dropdown saves correct URIpest
Receipt Flex builds per event typepest unit
Abandoned cart trigger fires + cancelspest with time mock

Phase 3 test gates

TestLayer
LINE Pay sandbox confirmjest e2e
Agent QR scan → attributionmanual
Order history page renders past ordersplaywright
LIFF chrome polish on iOS+Androidmanual device

Continuous tests (every phase)

  • Lint clean (eslint, phpcs, eslint-fe)
  • Type-check clean (tsc, larastan)
  • Existing test suites pass (no regression)
  • Coverage doesn’t drop below current baseline

CI gates (HARD RULE — global policy)

All CI jobs MUST be green before merge. If even ONE job red → blocked.

Specifically:

  • Curva: PHP 8.2 unit + feature, larastan, php-cs-fixer, prettier (vue), eslint
  • Pasukuru BE: Jest, eslint, tsc
  • Pasukuru FE: Vitest, eslint, tsc, build

Per concepts/ci-cd-must-pass-before-merge.md.


Smoke test catalog

SMOKE-0 (Phase 0 exit)

“Order webhook reaches Curva from Pasukuru” Steps in 02-phase-0-foundation.md smoke test section.

SMOKE-1 (Phase 1 exit)

“User completes purchase inside LINE LIFF” Steps in 03-phase-1-liff-wrap.md.

SMOKE-2 (Phase 2 exit)

“Admin builds Flex Msg → user buys → receipt arrives” Steps in 04-phase-2-ux-glue.md.

SMOKE-3 (Phase 3 exit)

“Agent QR drives attributed purchase via LINE Pay” Steps in 05-phase-3-payment-agent.md.

SMOKE-PROD (Pre-launch)

All SMOKE-0 through SMOKE-3 against prod-staging tenant. Plus:

  • 1000-user load
  • Webhook DLQ < 5 across 1hr observation
  • No 5xx in nginx access log over 1hr

Test environment matrix

EnvPurposeAuto-deployed?
local (dev VPS)per-dev hackingmanual
stagingsmoke tests, integrationon dev branch merge
canaryfirst-touch tenantspromotion from staging
prodlivepromotion + manual approval

Test data fixtures

Maintained in vault pages/concepts/curva-pasukuru-test-fixtures.md:

  • 5 test products
  • 3 test members (one with LINE-linked, one without, one as agent)
  • 1 test PartnerConnection
  • Sample order in each status