diff --git a/test/e2e/batch13-billing-drive.mjs b/test/e2e/batch13-billing-drive.mjs new file mode 100644 index 0000000..b947d40 --- /dev/null +++ b/test/e2e/batch13-billing-drive.mjs @@ -0,0 +1,160 @@ +// batch13-billing-drive.mjs — the billing batch's Drive list. +// +// Every check here is invisible on a hold owner's account: GetSubscriptionInfo +// short-circuits for a captain and returns a synthetic "Captain" tier before any +// Stripe lookup, and GetWebhookLimits / HasAIAdvisor / GetSupporterBadge bypass +// on the same first line. Run this as a NON-CAPTAIN. +// +// PHASE=managed node test/e2e/batch13-billing-drive.mjs +// PHASE=selfhosted node test/e2e/batch13-billing-drive.mjs +// +// The two phases are the same account either side of one config change: whether +// its default hold appears in server.managed_holds. +import { open, reporter, APPVIEW } from './lib.mjs'; + +const PHASE = process.env.PHASE ?? 'managed'; +const { record, summarize } = reporter(); + +const ctx = await open(); +const page = ctx.pages()[0] ?? (await ctx.newPage()); +const text = () => page.evaluate(() => document.body.innerText); +const atLogin = (u) => /\/login|\/auth\/oauth|\/oauth\/authorize|jarrett\.app|bsky\./.test(u); + +await page.goto(`${APPVIEW}/settings`, { waitUntil: 'domcontentloaded' }); +await page.waitForTimeout(2500); + +// Wait for a human to finish OAuth. Deliberately does NOT navigate: reloading +// would wipe out a half-typed password form. +if (atLogin(page.url())) { + console.log('\n >>> Sign in as the NON-CAPTAIN account in the open browser window.\n'); + const deadline = Date.now() + 10 * 60 * 1000; + while (Date.now() < deadline && atLogin(page.url())) await page.waitForTimeout(2000); + if (atLogin(page.url())) { console.error('Timed out.'); await ctx.close(); process.exit(2); } + console.log('Signed in.\n'); +} + +// --- who, and on what hold ------------------------------------------------- +await page.goto(`${APPVIEW}/settings/storage`, { waitUntil: 'domcontentloaded' }); +await page.waitForTimeout(1500); +const storage = await text(); +const handle = (storage.match(/@([\w.-]+)/) ?? [])[1] ?? '(unknown)'; +const activeHold = (storage.match(/Active Hold:\s*\n?\s*([^\n]+)/) ?? [])[1] ?? '(unknown)'; +console.log(`account: @${handle}\nactive hold (scraped): ${activeHold}\n`); +console.log('--- /settings/storage ---\n' + storage + '\n--- end ---\n'); +// Read the hold selector from the DOM. innerText cannot distinguish the +// selected