)
+
+ // Verify "Waiting for payment confirmation" banner appears
+ const hasWaiting = await isWaitingVisible();
+ console.log(`${LOG_PREFIX} 5.1.1: Waiting banner visible: ${hasWaiting}`);
+ expect(hasWaiting).toBe(true);
+
+ // Verify Upgrade buttons become disabled (text changes to "Waiting...")
+ const hasWaitingButton = await textExists('Waiting...');
+ console.log(`${LOG_PREFIX} 5.1.1: Waiting... button text visible: ${hasWaitingButton}`);
+
+ // Switch mock to BASIC so polling resolves and clears the state
+ setMockBehavior('plan', 'BASIC');
+ setMockBehavior('planActive', 'true');
+ setMockBehavior('planExpiry', new Date(Date.now() + 30 * 86400000).toISOString());
+
+ // Wait for polling to detect change and clear waiting state
+ const waitingGone = await waitForTextToDisappear('Waiting', 20_000);
+ expect(waitingGone).toBe(true);
+ console.log(`${LOG_PREFIX} 5.1.1: Waiting state cleared`);
+
+ console.log(`${LOG_PREFIX} 5.1.1 PASSED`);
+ });
+
+ it('5.1.2 — checkout session with annual billing interval', async () => {
+ // Reset to FREE plan and re-auth to clear purchasing state
+ resetMockBehavior();
+ await reAuthAndGoToBilling('e2e-annual-token');
+
+ // Click "Annual" billing interval toggle
+ await clickText('Annual', 10_000);
+ console.log(`${LOG_PREFIX} 5.1.2: Clicked Annual toggle`);
+ await browser.pause(1_000);
+
+ clearRequestLog();
+
+ // Click "Upgrade" on BASIC tier
+ await clickText('Upgrade', 10_000);
+ console.log(`${LOG_PREFIX} 5.1.2: Clicked Upgrade button`);
+ await browser.pause(3_000);
+
+ // Verify POST /payments/stripe/purchasePlan was called
+ const purchaseCall = await waitForRequest('POST', '/payments/stripe/purchasePlan', 10_000);
+ if (!purchaseCall) {
+ console.log(
+ `${LOG_PREFIX} 5.1.2: Purchase request log:`,
+ JSON.stringify(getRequestLog(), null, 2)
+ );
+ }
+ expect(purchaseCall).toBeDefined();
+
+ // Verify request body contains BASIC_YEARLY planId
+ if (purchaseCall?.body) {
+ const bodyStr = typeof purchaseCall.body === 'string' ? purchaseCall.body : '';
+ console.log(`${LOG_PREFIX} 5.1.2: Purchase request body:`, bodyStr);
+ expect(bodyStr).toContain('BASIC');
+ expect(bodyStr).toContain('YEARLY');
+ }
+
+ // Verify "Waiting" banner appears
+ const hasWaiting = await isWaitingVisible();
+ expect(hasWaiting).toBe(true);
+
+ // Resolve the polling so state clears
+ setMockBehavior('plan', 'BASIC');
+ setMockBehavior('planActive', 'true');
+ const waitingGone512 = await waitForTextToDisappear('Waiting', 20_000);
+ expect(waitingGone512).toBe(true);
+
+ console.log(`${LOG_PREFIX} 5.1.2 PASSED`);
+ });
+
+ it('5.1.3 — Coinbase crypto checkout creates charge', async () => {
+ // Reset to FREE plan and re-auth
+ resetMockBehavior();
+ await reAuthAndGoToBilling('e2e-crypto-token');
+
+ // Toggle "Pay with Crypto" switch ON.
+ // The label and toggle