test(ssr): Phase 7 parity gate — characterization spec for the Invoice Pay wizard
The Invoice Pay wizard is the first GENUINE multi-data-step wizard: choose-method (collects bank-account + method) -> payment-details (collects check-number / handwritten-date / amounts), merged only at submit. This gate characterizes that flow before migrating it onto the session-backed engine, so the merge can be proven behavior-preserving. - Seed: make the TEST client's check bank account visible (+ name "Test Checking") so the choose-method step renders a usable method card. The pay flow had no e2e coverage, so the bank account was never visible in tests before. - Spec drives the real 2-step flow against the unmodified wizard: choose-method renders the bank account + its methods (print-check/debit/handwrite-check, in the card tooltip); picking handwrite-check advances to payment-details (check-number + date + Pay); filling the check number and submitting shows the completion modal. The handwrite-check path is used because it transacts a pending check payment directly (no PDF/S3), making the success assertion stable. Notes for the migration: the method controls live in a <template x-ref="tooltip"> revealed by the card button; the footer Pay submit is x-ref="next"; both the grid filters and the modal carry a check-number input, so the modal selectors are scoped to #wizard-form. Verification: invoice-pay spec 3/3; full suite 58/58 (no regressions from the seed change). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
73
e2e/invoice-pay.spec.ts
Normal file
73
e2e/invoice-pay.spec.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
// Characterization spec for the Invoice Pay wizard (the first genuine multi-data-step
|
||||
// wizard: choose-method -> payment-details, merged at submit). Captures CURRENT
|
||||
// (pre-migration) behavior so the migration onto the session-backed engine can be proven
|
||||
// behavior-preserving. The seed's lone unpaid invoice (UNPAID-001, Test Vendor, $150,
|
||||
// client TEST) is payable; its client has one visible check bank account (Test Checking).
|
||||
test.beforeEach(async ({ request }) => { await request.post('/test-reset'); });
|
||||
|
||||
// Select the unpaid invoice on the grid and open the pay wizard (choose-method step).
|
||||
async function openPayWizard(page: any) {
|
||||
await page.setExtraHTTPHeaders({ 'x-clients': '"mine"' });
|
||||
await page.goto('/invoice');
|
||||
await page.waitForSelector('#entity-table tbody tr');
|
||||
await page.locator('#entity-table tbody input[type="checkbox"]').first().click();
|
||||
await page.waitForTimeout(300);
|
||||
// #pay-button's container hx-gets /invoice/pay on click; wait for the wizard to land.
|
||||
await page.locator('#pay-button').first().click();
|
||||
await page.waitForTimeout(900);
|
||||
}
|
||||
|
||||
// The bank-account card's method options (print-check / debit / handwrite-check) live in a
|
||||
// <template x-ref="tooltip"> revealed by clicking the card's tooltip button; open it.
|
||||
async function openMethodTooltip(page: any) {
|
||||
await page.locator('button[x-ref="button"]').first().click();
|
||||
await page.waitForTimeout(400);
|
||||
}
|
||||
|
||||
// Advance choose-method -> payment-details by picking a method (each is an hx-put to
|
||||
// .../pay/navigate?to=:payment-details carrying step-params[method]).
|
||||
async function pickMethod(page: any, method: string) {
|
||||
await openMethodTooltip(page);
|
||||
await page.locator(`[hx-vals*="${method}"]`).first().click();
|
||||
await page.waitForTimeout(900);
|
||||
}
|
||||
|
||||
test.describe.configure({ mode: 'serial' });
|
||||
|
||||
test.describe('Invoice Pay wizard (characterization)', () => {
|
||||
test('choose-method step renders the bank account and its payment methods', async ({ page }) => {
|
||||
await openPayWizard(page);
|
||||
const body = page.locator('body');
|
||||
await expect(body).toContainText('Payment method');
|
||||
await expect(body).toContainText('Test Checking');
|
||||
// a check account offers print-check / debit / handwrite-check (in the card's tooltip)
|
||||
await openMethodTooltip(page);
|
||||
expect(await page.locator('[hx-vals*="handwrite-check"]').count()).toBeGreaterThan(0);
|
||||
expect(await page.locator('[hx-vals*="print-check"]').count()).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('picking handwrite-check advances to the payment-details step', async ({ page }) => {
|
||||
await openPayWizard(page);
|
||||
await pickMethod(page, 'handwrite-check');
|
||||
const body = page.locator('body');
|
||||
await expect(body).toContainText('Check number'); // handwrite-check-only field
|
||||
await expect(body).toContainText('Date'); // check date
|
||||
await expect(body.locator('button:has-text("Pay"), a:has-text("Pay")').first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('completing a handwritten-check payment shows the success modal', async ({ page }) => {
|
||||
await openPayWizard(page);
|
||||
await pickMethod(page, 'handwrite-check');
|
||||
// step 2 collects the check number; method (step 1) + check-number (step 2) combine at submit
|
||||
// scope to the wizard form (the background grid filters also have a check-number input)
|
||||
await page.locator('#wizard-form input[name*="check-number"]').first().fill('10001');
|
||||
await page.waitForTimeout(150);
|
||||
// the footer submit button (x-ref="next"), not the background #pay-button
|
||||
await page.locator('[x-ref="next"]').first().click();
|
||||
await page.waitForTimeout(1500);
|
||||
// the submit transacts a pending check payment and swaps in the completion modal
|
||||
await expect(page.locator('body')).toContainText('payment is complete');
|
||||
});
|
||||
});
|
||||
@@ -69,7 +69,8 @@
|
||||
[(assoc (test-client :db/id "client-id"
|
||||
:client/code "TEST"
|
||||
:client/locations ["DT"])
|
||||
:client/bank-accounts [(test-bank-account :db/id "bank-account-id" :bank-account/code "TEST-CHK")])
|
||||
:client/bank-accounts [(test-bank-account :db/id "bank-account-id" :bank-account/code "TEST-CHK"
|
||||
:bank-account/visible true :bank-account/name "Test Checking")])
|
||||
(test-client :db/id "client-id-2"
|
||||
:client/code "TEST2"
|
||||
:client/locations ["NY"])
|
||||
|
||||
Reference in New Issue
Block a user