Files
cfw-autumn/server/tests/utils/browserPool/playwright/setupPayment.ts

121 lines
4.0 KiB
TypeScript

import type { Page } from "playwright-core";
/**
* Self-contained Playwright function for completing a Stripe setup payment checkout.
* NO external imports — this function must be serializable via fn.toString()
* for Kernel Playwright Execution. (type imports are fine — Bun strips them)
*
* Handles setup mode checkout (mode: "setup") for adding payment methods.
* Uses checkout.stripe.com direct DOM selectors, CVC is "100",
* and unchecks the Stripe Link "Save my info" checkbox if present.
*/
export const setupPayment = async ({
page,
url,
}: {
page: Page;
url: string;
}) => {
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 60000 });
console.log("[setupPayment] Page loaded");
// Wait for the checkout page to render
await page.waitForTimeout(3000);
// Select the Card payment method. The hidden radio input is covered by an
// AccordionButton overlay (expandedClickArea). Target that button via
// data-testid and use a JS click since it has no visible text content.
try {
const cardBtn = page.locator('[data-testid="card-accordion-item-button"]');
if ((await cardBtn.count()) > 0) {
await cardBtn.evaluate((el) => (el as HTMLElement).click());
console.log("[setupPayment] Card selected via accordion button JS click");
await page.waitForTimeout(1000);
} else {
// Fallback: try the accordion ID directly via JS
await page.evaluate(() => {
const radio = document.getElementById(
"payment-method-accordion-item-title-card",
);
if (radio) radio.click();
});
console.log("[setupPayment] Card selected via radio JS click fallback");
await page.waitForTimeout(1000);
}
} catch {
// Card might already be selected
}
const cardNumber = page.locator("#cardNumber");
await cardNumber.waitFor({ timeout: 10000 });
await cardNumber.pressSequentially("4242424242424242");
console.log("[setupPayment] Card number filled");
const cardExpiry = page.locator("#cardExpiry");
await cardExpiry.waitFor({ timeout: 5000 });
await cardExpiry.pressSequentially("1228");
console.log("[setupPayment] Expiry filled");
const cardCvc = page.locator("#cardCvc");
await cardCvc.waitFor({ timeout: 5000 });
await cardCvc.pressSequentially("100");
console.log("[setupPayment] CVC filled");
const billingName = page.locator("#billingName");
await billingName.waitFor({ timeout: 5000 });
await billingName.pressSequentially("Test Customer");
console.log("[setupPayment] Billing name filled");
// Uncheck "Save my information for faster checkout" (Stripe Link) if checked.
// This must be unchecked or the submit button stays greyed out.
// The checkbox input is hidden behind custom styling, so use JS click directly.
try {
const wasChecked = await page.evaluate(() => {
const cb = document.getElementById("enableStripePass") as HTMLInputElement | null;
if (cb && cb.checked) {
cb.click();
return true;
}
return false;
});
if (wasChecked) {
console.log("[setupPayment] Stripe Link checkbox unchecked");
await page.waitForTimeout(500);
}
} catch {
// Stripe Link checkbox not present
}
// Force country to US so a postal code input is always shown
try {
const countrySelect = page.locator("#billingCountry");
if ((await countrySelect.count()) > 0) {
await countrySelect.selectOption("US");
console.log("[setupPayment] Country set to US");
await page.waitForTimeout(500);
}
} catch {
// Country selector not present
}
try {
const postalCode = page.locator("#billingPostalCode");
if ((await postalCode.count()) > 0) {
await postalCode.pressSequentially("10001");
console.log("[setupPayment] Postal code filled");
}
} catch {
// Postal code field not present
}
const submitBtn = page.locator(".SubmitButton-TextContainer").first();
if ((await submitBtn.count()) > 0) {
await submitBtn.evaluate((el) => (el as HTMLElement).click());
console.log("[setupPayment] Submit clicked");
}
// Wait for form submission to complete
await page.waitForTimeout(7000);
console.log("[setupPayment] Setup payment complete");
};