123 lines
4.1 KiB
TypeScript
123 lines
4.1 KiB
TypeScript
import { notNullish } from "@autumn/shared";
|
|
import { timeout } from "../genUtils.js";
|
|
import { browserPool } from "./browserPool.js";
|
|
|
|
/**
|
|
* Complete a Stripe Checkout form using the shared browser pool.
|
|
* Opens a new tab, fills the form, and closes the tab (browser stays open).
|
|
*/
|
|
export const completeStripeCheckoutForm = async ({
|
|
url,
|
|
overrideQuantity,
|
|
promoCode,
|
|
}: {
|
|
url: string;
|
|
overrideQuantity?: number;
|
|
promoCode?: string;
|
|
}): Promise<void> => {
|
|
let step = "creating new page";
|
|
const page = await browserPool.newPage();
|
|
|
|
try {
|
|
step = "navigating to checkout URL";
|
|
await page.goto(url, { waitUntil: "networkidle2", timeout: 60000 });
|
|
|
|
// Try to click accordion if it exists (wait up to 2 seconds)
|
|
try {
|
|
await page.waitForSelector("#payment-method-accordion-item-title-card", {
|
|
timeout: 2000,
|
|
});
|
|
await page.click("#payment-method-accordion-item-title-card");
|
|
await timeout(500);
|
|
} catch (_e) {
|
|
// Accordion doesn't exist or didn't appear, continue without clicking
|
|
}
|
|
|
|
step = "waiting for #cardNumber";
|
|
await page.waitForSelector("#cardNumber", { timeout: 120000 });
|
|
await page.type("#cardNumber", "4242424242424242");
|
|
|
|
step = "filling card expiry";
|
|
await page.waitForSelector("#cardExpiry", { timeout: 60000 });
|
|
await page.type("#cardExpiry", "1234");
|
|
|
|
step = "filling card CVC";
|
|
await page.waitForSelector("#cardCvc", { timeout: 60000 });
|
|
await page.type("#cardCvc", "123");
|
|
|
|
step = "filling billing name";
|
|
await page.waitForSelector("#billingName", { timeout: 60000 });
|
|
await page.type("#billingName", "Test Customer");
|
|
|
|
// Email field may be present if customer has no email set
|
|
try {
|
|
await page.waitForSelector("#email", { timeout: 2000 });
|
|
await page.type("#email", "test@example.com");
|
|
} catch (_e) {
|
|
// Email field doesn't exist (customer already has email), continue without it
|
|
}
|
|
|
|
// Postal code may not be present for all countries (e.g., UK)
|
|
try {
|
|
await page.waitForSelector("#billingPostalCode", { timeout: 2000 });
|
|
await page.type("#billingPostalCode", "123456");
|
|
} catch (_e) {
|
|
// Postal code field doesn't exist, continue without it
|
|
}
|
|
|
|
if (notNullish(overrideQuantity)) {
|
|
step = `finding .AdjustableQuantitySelector for quantity=${overrideQuantity}`;
|
|
const quantityBtn = await page.$(".AdjustableQuantitySelector");
|
|
if (!quantityBtn) {
|
|
throw new Error(
|
|
`.AdjustableQuantitySelector not found - did you pass adjustable_quantity: true in attach params?`,
|
|
);
|
|
}
|
|
await quantityBtn.evaluate((b: any) => (b as HTMLElement).click());
|
|
|
|
step = "waiting for #adjustQuantity input";
|
|
await page.waitForSelector("#adjustQuantity", { timeout: 60000 });
|
|
await page.click("#adjustQuantity", { clickCount: 3 }); // Select all text
|
|
await page.keyboard.press("Backspace"); // Delete selected text
|
|
await page.type("#adjustQuantity", overrideQuantity.toString());
|
|
|
|
step = "clicking quantity update button";
|
|
const updateBtn = await page.$(".AdjustQuantityFooter-btn");
|
|
if (!updateBtn) {
|
|
throw new Error(`.AdjustQuantityFooter-btn not found`);
|
|
}
|
|
await updateBtn.evaluate((b: any) => (b as HTMLElement).click());
|
|
|
|
await timeout(1000);
|
|
}
|
|
|
|
if (promoCode) {
|
|
step = "applying promo code";
|
|
await page.waitForSelector("#promotionCode", { timeout: 60000 });
|
|
await page.click("#promotionCode");
|
|
await page.type("#promotionCode", promoCode);
|
|
await page.keyboard.press("Enter");
|
|
await timeout(5000);
|
|
}
|
|
|
|
step = "clicking submit button";
|
|
const submitButton = await page.$(".SubmitButton-TextContainer");
|
|
if (!submitButton) {
|
|
throw new Error(`.SubmitButton-TextContainer not found`);
|
|
}
|
|
await submitButton.evaluate((b: any) => (b as HTMLElement).click());
|
|
|
|
step = "waiting for checkout to process";
|
|
|
|
const testConcurrency = Number(process.env.TEST_FILE_CONCURRENCY || "0");
|
|
const timeoutMs = testConcurrency > 1 ? 30000 : 10000;
|
|
await timeout(timeoutMs);
|
|
} catch (error: any) {
|
|
const msg = error?.message || String(error);
|
|
throw new Error(`[completeStripeCheckoutForm] Failed at "${step}": ${msg}`);
|
|
} finally {
|
|
// Close the page (tab), but keep browser open for reuse
|
|
await page.close();
|
|
}
|
|
};
|