Files
nur-falah-prevention/e2e-auth-helper.cjs
T
wmj 22ad077dab feat: add Support tab — donations + co-branding/white-label contact
New tab under the Giving hub, alongside Zakat/Sadaqah/Khairat. Two parts:

Donations: amount presets + custom amount, four frequencies (One-Time,
Monthly, Quarterly, Yearly), each mapped to its own live Polar.sh
checkout link (merchant of record — this app never touches payment
details, same 'log intent, don't move money' principle used everywhere
else). Design/copy modeled on the sibling moslem03.falahos.my app's
existing Support tab, per direct reference.

No donation product existed on the Polar account yet, so created one
via the Polar API with the user's explicit go-ahead: 'Support Nur
Falah' as 4 pay-what-you-want products (one-time + monthly/quarterly/
yearly recurring, quarterly via recurring_interval=month with count=3
since Polar has no native quarterly interval), plus a hosted checkout
link for each. Verified all four resolve to genuinely distinct, live
Stripe-backed checkout sessions before shipping — moslem03's own
checkout.polar.sh URL pattern turned out to be stale/non-resolving;
the current correct domain is buy.polar.sh via the /v1/checkout-links
API, discovered from Polar's live OpenAPI spec rather than guessed.

Partnership section: co-branding and white-label pitch with the VP
Sales contact info given directly — info@falahos.my and WhatsApp
+60132250691 — reachable via a 'View Partnership Opportunities' link
from the donation card, matching moslem03's UX pattern of surfacing
partnership discovery from the support flow.

Covered by e2e-support.cjs (14/14) — including opening all four
checkout links live and confirming each is a genuinely distinct,
resolving Stripe checkout session, not a dead or placeholder link.
Full regression: all suites pass (one confirmed transient flake on
rerun, unrelated to this change).
2026-08-14 16:24:42 +08:00

59 lines
2.9 KiB
JavaScript

// Shared sign-in prelude for the pre-auth-gate E2E suites. Each suite creates
// its own fresh family per run (unique name) so accumulated data from a
// previous run's assets/hibah/etc. can never bleed into another run's
// percentage/coverage assertions — same isolation the old per-context
// localStorage gave for free, now done explicitly since data is shared and
// persistent in Supabase instead of wiped with the browser context.
const OWNER_EMAIL = 'nurfalah.e2etest.owner@gmail.com';
const OWNER_PASSWORD = 'TestPassword123!';
async function signInFreshFamily(page, BASE, familyLabel) {
await page.goto(BASE, { waitUntil: 'networkidle' });
await page.locator('.field:has-text("Email") input').fill(OWNER_EMAIL);
await page.locator('.field:has-text("Password") input').fill(OWNER_PASSWORD);
await page.locator('button.btn-primary', { hasText: 'Sign in' }).click();
await page.waitForTimeout(1500);
const familyName = `${familyLabel || 'E2E'} ${Date.now()}-${Math.floor(Math.random() * 1e6)}`;
await page.locator('.field:has-text("Family name") input').fill(familyName);
await page.locator('button.btn-primary', { hasText: 'Create family' }).click();
await page.waitForTimeout(1200);
return familyName;
}
// Hub map mirroring App.svelte's HUBS config — the nav went from a single
// flat 22-item strip to 5 bottom-nav hubs, each revealing its own sub-nav.
// Reaching any given tab is now a two-step click (hub, then sub-tab)
// instead of one, so every test goes through this helper rather than
// hardcoding the old single-click selector.
const HUB_OF_TAB = {
'Coverage': 'Home',
'Assets': 'Estate', 'Faraid': 'Estate', 'Insurance': 'Estate', 'Wassiyah': 'Estate',
'Hibah': 'Estate', 'Family Waqf': 'Estate', 'Nominate': 'Estate', 'Claims (H2)': 'Estate',
'Zakat': 'Giving', 'Sadaqah': 'Giving', 'Khairat': 'Giving', 'Support': 'Giving',
'Tree': 'Family', 'Trigger': 'Family', 'Mutawalli': 'Family', 'Manage': 'Family', 'Neighbourhood': 'Family',
'Prayer Times': 'Daily', 'Qibla': 'Daily', 'Quran': 'Daily', 'Locate': 'Daily'
};
/** Navigates to a tab by its old flat label — clicks the owning hub first (if not already active), then the sub-tab. 'Settings' is a special case (a header icon, not a hub). */
async function gotoTab(page, label) {
if (label === 'Settings') {
await page.locator('button[aria-label="Settings"]').click();
return;
}
const hub = HUB_OF_TAB[label];
if (!hub) throw new Error(`gotoTab: unknown tab label "${label}"`);
const hubBtn = page.locator(`.hub-tab[aria-label="${hub}"]`);
const alreadyActive = await hubBtn.evaluate(el => el.classList.contains('active')).catch(() => false);
if (!alreadyActive) {
await hubBtn.click();
await page.waitForTimeout(200);
}
if (hub !== 'Home') {
await page.locator(`.subnav .tab[aria-label="${label}"]`).click();
}
}
module.exports = { signInFreshFamily, OWNER_EMAIL, OWNER_PASSWORD, gotoTab };