Skip to main content

E2E Test Plan

E2E Test Plan: Drop — Fintech Payment AppPlan

Project: Drop — Remittance + QR Payments{{PROJECT_NAME}} Version: 1.0{{VERSION}} Date: 2026-02-23{{DATE}} Author: John (AI Director){{AUTHOR}} Status: Draft | In Review | Approved Reviewers: Alem Bašić (CEO){{REVIEWERS}}

Document History

Version Date Author Changes
0.1 2026-02-23{{DATE}} John{{AUTHOR}} Initial E2E plan — 3 Playwright projects (user-flows, full-flows, input-chaos)draft

1. E2E Testing Objectives

Objectives:

  1. Validate that the 5{{COUNT}} most critical Drop user journeys work end-to-end onin staginga production-like environment
  2. Catch integration failures between Next.js frontend, API routes, SQLite DB,backend, and mockthird-party BaaSservices that unit/integration tests cannot detect
  3. Provide confidence before every production deployment via post-staging deploy gate
  4. Serve as living documentation of critical user flows for CEO UAT

What E2E tests are NOT for:

  • Complete feature coverage (handledthat's byfor unit/integration tests — 40+ Vitest tests)
  • Testing every error state (too expensive to maintain; covered by input-chaos.spec.ts for validation)maintain)
  • Performance benchmarking (handleduse byperformance api-benchmarks.test.ts)tests)
  • Visual pixel-perfection (Figmause sourcevisual ofregression truth:tests mockups/figma-make-export/)separately)

2. Critical User Journeys

Journey 1: User Registration — 3-Step Onboarding{{JOURNEY_1_NAME}}

Field Value
Priority Critical
Business Impact Core{{IMPACT}} user acquisition — no registration = no users
Frequency Every{{FREQUENCY}} new user (one-time)
Test File src/drop-app/__tests__/e2e/user-flows.spec.ts{{TEST_PATH}}

Steps:

  1. Navigate{{STEP_1}} to https://drop-staging.fly.dev/
  2. Click{{STEP_2}} "Registrer deg" — registration form opens
  3. Enter{{STEP_3}} valid data: name (with Unicode: Amir Hasić), email, password ≥ 8 chars, Norwegian phone (+47), DOB ≥ 18 years
  4. Submit{{STEP_4}} form — OTP sent to phone, OTP input shown
  5. Enter{{STEP_5}} correct 6-digit OTP
  6. Enter{{STEP_6}} and confirm 4-digit PIN
  7. Redirect to dashboard — account activated

Assertions:

  • 201{{ASSERTION_1}} Created on registration (no password hash in response)
  • JWT{{ASSERTION_2}} httpOnly cookie set after PIN setup
  • Dashboard{{ASSERTION_3}} visible with user's name
  • Audit log entry created

Journey 2: User Login + Dashboard Access{{JOURNEY_2_NAME}}

Field Value
Priority Critical
Business Impact Core returning user flow — no login = no revenue{{IMPACT}}
Frequency Every user, every session{{FREQUENCY}}
Test File src/drop-app/__tests__/e2e/user-flows.spec.ts{{TEST_PATH}}

Steps:

  1. Navigate to /login{{STEP_1}}
  2. Enter valid email and password{{STEP_2}}
  3. Submit
  4. Redirected to dashboard
  5. Bank balance shown (from mock AISP)
  6. Recent transactions visible{{STEP_3}}

Assertions:

  • 200 on login; JWT cookie set; SameSite=Strict; httpOnly
  • GET /api/auth/me returns user object (no password hash)
  • Balance shown is from mock BaaS (not stored in Drop DB)

Journey 3: Remittance — NOK to RSD

FieldValue
PriorityCritical
Business ImpactCore revenue — 0.5% fee per transaction
FrequencyMultiple times per month per user
Test Filesrc/drop-app/__tests__/e2e/full-flows.spec.ts

Steps:

  1. Log in as KYC-approved consumer
  2. Navigate to "Send penger" (Send Money)
  3. Select recipient; enter amount = 1,000 NOK; select currency = RSD
  4. Review: fee shown as 5 NOK (0.5%); exchange rate shown
  5. Confirm and submit
  6. Transaction created with status = completed
  7. Navigate to Transaction History — transaction visible

Assertions:

  • 201 Created; transaction in DB with fee = 5 NOK
  • Transaction history shows amount, fee, currency, status
  • No balance change in Drop DB (pass-through — balance read from mock AISP)

Journey 4: QR Payment — Scan + Pay

FieldValue
PriorityCritical
Business ImpactCore QR revenue — 1% merchant fee
FrequencyMultiple times per week per merchant
Test Filesrc/drop-app/__tests__/e2e/full-flows.spec.ts

Steps:

  1. Log in as KYC-approved consumer
  2. Navigate to "Scan QR"
  3. Enter valid merchantId (pre-seeded merchant)
  4. Enter amount = 200 NOK
  5. Review: merchant_fee = 2 NOK (1%)
  6. Confirm payment
  7. Transaction created; visible in history

Assertions:

  • 201 Created; merchant_fee = 2 NOK; amount = 200 NOK
  • Transaction visible in consumer history
  • Mock PISP payment recorded

Journey 5: Merchant Registration + QR Generation

FieldValue
PriorityHigh
Business ImpactMerchant onboarding — enables QR revenue
FrequencyOne-time per merchant
Test Filesrc/drop-app/__tests__/e2e/full-flows.spec.ts

Steps:

  1. Log in as user (not yet a merchant)
  2. Navigate to "Bli Merchant" (Become Merchant)
  3. Enter business_name and bank_account
  4. Submit — merchant created with unique QR code value
  5. Navigate to merchant dashboard — QR code visible

Assertions:

  • 201 Created; merchant has unique qr_code_value
  • GET /api/merchants/me returns merchant details + QR code
  • QR code is unique (no two merchants share a code)

All Journeys Summary

Journey Priority Est. Duration Automated PlaywrightLast ProjectPass
User Registration (3-step){{JOURNEY_1_NAME}} Critical ~30s{{DURATION}}s Yes user-flows{{DATE}}
{{JOURNEY_2_NAME}}Critical{{DURATION}}sYes{{DATE}}
User Loginregistration + Dashboardemail verification Critical ~15s60s Yes user-flows
RemittancePassword NOK→RSDreset flow CriticalHigh ~45sYes
Account settings updateMedium30s Yes full-flows
QR PaymentCritical~25sYesfull-flows
Merchant RegistrationHigh~20sYesfull-flows
Input Chaos (20+ edge cases)High~60sYesinput-chaos

3. Browser & Device Matrix

Desktop Browsers

inPlaywrightCI requiredforNorwegianonMac
Browser Version OS Priority Notes
Chrome Latest stable macOS,Windows, Linux (CI)macOS Critical PrimaryHighest testmarket browsershare
FirefoxLatest stableWindows, macOSHigh
Safari Latest stable macOS High WebKit engine
Edge Latest usersstable Windows MediumChromium-based

Mobile Browsers

Browser Platform Version Priority Notes
Safari iOS Latest Critical PrimaryHighest Dropmobile platform — iPhone SE to iPhone Pro Maxshare
Chrome Android Latest HighCritical Secondary mobile platform

Screen Resolutions (configured in playwright.config.ts)

primarytargetdevice
Category Resolution Test Priority Notes
MobileDesktop S (iPhone SE)HD 375×6671920×1080 Critical
DropDesktop 1366×768 High
Laptop1280×800Medium
Tablet (landscape)1024×768High
Mobile L (iPhone 14 Pro) 428×926 Critical Drop primary target device
TabletMobile M 768×1024375×667 MediumSecondary
Desktop1280×800MediumFallback / admin useCritical

Matrix in CI: ChromiumRun +Critical WebKitpriority (mobilebrowser/resolution viewports 375px and 428px)combinations on every deployment. Full matrix on nightly schedule.


4. Test Data Setup & Teardown

Setup Strategy

Data Type Method Scope
ConsumerTest accountuser (KYC approved)accounts Pre-seeded inbefore beforeAlltest via APIrun Test suite
Merchant account{{DATA_TYPE}} Pre-seeded in beforeAllCreated via APITest suite
Test recipients (for remittance)Pre-seeded in beforeAll Test suite
Isolated freshtest user (for registration tests)data Created via API in beforeEach with unique email Individual test

Seed command: npmbash runscripts/e2e-seed.sh db:seed{{ENVIRONMENT}} (populatesSeed stagingverification: SQLitebash withscripts/verify-seed.sh synthetic test data){{ENVIRONMENT}}

Teardown Strategy

suiteend
Cleanup Item Method Trigger
FreshTest-specific users created per testrecords DELETE via API afterEach
Test session data Clear browser storage afterEach
TransactionsEmails created duringin test inbox ArchiveAPI (not delete — audit trail)clear TestafterAll
Payment test dataStripe test mode auto-cleanupDaily job

Rule: Tests must not leave state that affects other tests. EachTests testmust createsbe itsexecutable ownin isolatedany data.order.

Test Accounts

Account Email Role Purpose
ConsumerStandard (Amir)user e2e-[email protected]user@test.{{DOMAIN}} Consumer, KYC approvedUser Standard journeys: login, remittance, QRjourneys
MerchantAdmin (Ahmet)user e2e-[email protected]admin@test.{{DOMAIN}} MerchantAdmin MerchantAdmin dashboard,panel QR generationjourneys
Fresh{{ROLE}} user e2e-fresh-{timestamp}{ROLE}}@test.alai.no{{DOMAIN}} None{{ROLE}} Registration flow tests{{PURPOSE}}

Credentials stored in: Vaultwarden{{CREDENTIAL_STORE}} (vault.basicconsulting.no)never hardcoded "Dropin E2E Test Accounts"tests)


5. Authentication Handling in Tests

Strategy: API-based{{AUTH_STRATEGY}} auth

// tests/fixtures/auth.ts
// Authenticate via POST /api/auth/login in beforeAll,API, save storage state,state
reuse// forReuse allstate across tests in the suite.same suite
// Only use UI login when testing the login flow itself.

// playwright.config.ts approach:
// 1. beforeAll: POST /api/auth/login → save JWT cookie to storage state
// 2. Each test that needs auth: restore storage state (< 1ms overhead)
// 3. Tests for login UI: always fresh (no saved state)itself

Session reuse:

  • Session state saved per role (consumer, merchant) after first auth
  • Reused for all tests requiring that role
  • JWTInvalidated expiresand inrefreshed 7if days — within test run durationexpired

6. Test Environment Requirements

Requirement Specification
Environment Staging (https://drop-staging.fly.dev/{{DOMAIN}})
Database StagingDedicated SQLiteE2E withdatabase, syntheticseeded seedbefore data onlyrun
External services MockSandbox BaaS/ test mode (NEXT_PUBLIC_SERVICE_MODE=mock);Stripe mocktest, Sumsubemail sandbox)
Stability No active deployments during E2E run (Fly.io deployment check)
Data persistence Isolated from— not shared with manual testing during E2E run
Response times < 5,000ms{{TIMEOUT}}s for all endpoints (PlaywrightE2E defaultassertions timeout)time out at 2× this)

Critical:Environment locking: CI acquires a lock before E2E tests must NOT run againstto aprevent productionconcurrent environment.deployments DropLock handlesmechanism: financial data — all E2E tests use mock BaaS exclusively.{{LOCK_MECHANISM}}


7. Flaky Test Management Strategy

Definition: A test that fails inconsistently for the same code.code

Prevention:

  • Use explicit waits:waits (not waitForResponse('/api/...'sleep) — wait for elements/network, not page.waitForTimeout(1000)time
  • Isolate test data (no uniqueshared emailsstate perbetween test run (e2e-fresh-{Date.now()}@test.alai.no)tests)
  • Use data-testid selectors —retry-on-assertion, not CSSretry-on-run
  • classes
  • Avoid oranimation texttiming (can changeissues with Norwegian/English toggle)
  • Disable animationsprefers-reduced-motion in test env via prefers-reduced-motion

Detection:

  • Track flakiness rate per test in CI
  • Any test failing > 5%{{FLAKY_THRESHOLD}}% of runs without code changes = flaky
  • Playwright HTML report shows flaky tests in CI artifacts

Response:

  • TagImmediately tag flaky test with test.fixme()@flaky annotation in Playwright
  • Create Missionbug Control taskticket with P2priority prioritybased on journey criticality
  • Quarantine (run separately, don't block CI) while fixing
  • Fix within 3{{FLAKY_FIX_SLA}} days or remove the test
  • Monthly flaky test review during sprint retrospective

8. Visual Regression Testing

Approach:Tool: Playwright{{VIS_TOOL}} screenshot comparisons on critical screens. Baseline: Stored in src/drop-app/__tests__/e2e/snapshots/{{BASELINE_STORAGE}} (committedThreshold: Allow up to repo){{VIS_THRESHOLD}}% Sourcepixel ofdifference Truth:for Figmafont Make export: mockups/figma-make-export/src/components/rendering

Check Scope Trigger
DashboardFull screenshotpage screenshots DashboardCritical screenpages Post-stagingUI-touching deployPRs
SendComponent Money formsnapshots RemittanceUI formcomponents On UIComponent changes
QR Scan screenQR payment screenOn UI changes
Mobile 375pxResponsive layout AllMobile critical+ screensdesktop On responsiveLayout changes

Review process: ScreenshotVisual diffs requirein BuilderPR +requiring Validatorexplicit sign-offapproval before merge. Figma is the source of truth — any diff vs Figma is a regression.merge


9. Performance Assertions Within E2E

Assertion Metric Threshold Journey
Page load Time to Interactive < 3,000ms{{TTI}}ms Dashboard,All Sendcritical Moneypages
Core Web Vitals — LCP Largest Contentful Paint < 2,500ms{{LCP}}ms Homepage, Dashboardlanding pages
Core Web Vitals — CLSCumulative Layout Shift< {{CLS}}All pages
API response RemittanceTime endpointin test assertions < 1,000ms{{API_TIMEOUT}}ms JourneyAll 3
API responseLogin endpoint< 1,000msJourney 2
API responseExchange rates< 200msJourney 3 (rates call)calls

10. CI Integration

Trigger: Post-staging deployment (GitHub Actions workflow: .github/workflows/e2e.yml)

Parallelization:

  • 3Test Playwrightsharding: projects{{SHARD_COUNT}} run in parallel: user-flows, full-flows, input-chaosshards
  • 2Browser parallelism: {{BROWSER_WORKERS}} workers per project on CI (total: 6 parallel Playwright workers)shard
  • Estimated total time: < 10{{E2E_TOTAL_TIME}} minutes

CI configuration:

# .github/workflows/e2e.ymlReference: {{CI_CONFIG_PATH}}
# Key settings:
# - Projects:Shards: user-flows, full-flows, input-chaos{{SHARD_COUNT}}
# - Retries: 1{{RETRY_COUNT}} (for non-flaky detection;tests not masking failures)only)
# - Timeout per test: 30,000ms{{TEST_TIMEOUT}}ms
# - Timeout total: 600,000ms (10 min)
# - Base URL: https://drop-staging.fly.dev/{{SUITE_TIMEOUT}}min

On failure:

  • Collect screenshots, videos, Playwright traces as CI artifacts
  • Retain artifacts for 7{{ARTIFACT_RETENTION}} days
  • Alert Slack #drop-e2e-channel #e2e-failures on alai-talk.slack.com
  • Block production deployment until fixed

11. Test Report Format & Artifacts

Report format: Playwright{{REPORT_FORMAT}} HTML report + JUnit XML for CI Report location: GitHub{{REPORT_URL}} Actionsor CI artifacts (7-day retention)

Artifacts collected on failure:

Artifact Format When Collected
Screenshot PNG On step failure
Screen recording WebM video On test failure
Network trace HAR file On test failure
Browser console log JSON On test failure
Playwright trace .zip (Playwright trace viewer) On test failure

12. Maintenance Strategy

Page Object Pattern:

  • All page interactions wrapped in lightweight Page Object classes
  • Selectors centralized — change in tests/e2e/pages/one place
  • Location: src/drop-app/__tests__/tests/e2e/pages/

Selector strategy (Drop-specific):strategy:

  1. data-testid attributes (preferred preferredstable, (e.g., data-testid="remittance-amount")intent-clear)
  2. ARIA roles + accessible name (e.g.,good getByRole('button',for {accessibility name: 'Send penger' }))alignment)
  3. Text content (acceptable for stablestatic Norwegian/English texttext)
  4. CSS class names (avoid avoidcoupled (Tailwindto classes can change)styling)
  5. XPath (never neverfragile)

Review cadence:

  • E2ETest suite reviewed monthly for relevance
  • Remove tests updatedfor indeprecated samefeatures PRimmediately
  • as
  • Update tests before merging feature changes (tests are part of the PR)
  • Monthly review: remove tests for deprecated features
  • Figma-make-export checked after every UI change


Approval

Role Name Date Signature
Author John (AI Director) 2026-02-23 Approved (AI)
QA LeadReviewer Validator Agent 2026-02-23 Approved (AI)
AI Director (John)Approver John 2026-02-23Approved
CEO (Alem)Alem BašićTBD