129 lines
3.2 KiB
TypeScript
129 lines
3.2 KiB
TypeScript
import "dotenv/config";
|
|
|
|
import puppeteer, { type Browser } from "puppeteer-core";
|
|
import { timeout } from "../genUtils.js";
|
|
|
|
// const client = new Hyperbrowser({
|
|
// apiKey: process.env.HYPERBROWSER_API_KEY,
|
|
// });
|
|
|
|
export const completeInvoiceConfirmation = async ({
|
|
url,
|
|
isLocal = false,
|
|
}: {
|
|
url: string;
|
|
isLocal?: boolean;
|
|
}) => {
|
|
let browser: Browser;
|
|
|
|
// if (process.env.NODE_ENV === "development" && !isLocal) {
|
|
// const session = await client.sessions.create();
|
|
// browser = await puppeteer.connect({
|
|
// browserWSEndpoint: session!.wsEndpoint,
|
|
// defaultViewport: null,
|
|
// });
|
|
// } else {
|
|
|
|
// }
|
|
browser = await puppeteer.launch({
|
|
headless: true,
|
|
executablePath: process.env.TESTS_CHROMIUM_PATH,
|
|
args: ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
});
|
|
|
|
try {
|
|
const page = await browser.newPage();
|
|
await page.setViewport({ width: 1280, height: 800 }); // Set standard desktop viewport size
|
|
await page.goto(url);
|
|
|
|
// Wait for the page to be ready
|
|
await page.waitForSelector("button", { timeout: 5000 });
|
|
|
|
// Find and click the "Confirm payment" button
|
|
const buttonClicked = await page.evaluate(() => {
|
|
const buttons = Array.from(document.querySelectorAll("button"));
|
|
const confirmBtn = buttons.find((b) =>
|
|
/confirm payment/i.test(b.textContent || ""),
|
|
);
|
|
if (confirmBtn) {
|
|
(confirmBtn as HTMLElement).click();
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
if (!buttonClicked) {
|
|
throw new Error("Could not find or click Confirm payment button");
|
|
}
|
|
|
|
// Wait for processing/navigation
|
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
|
|
// Wait for iframe with the three-ds-2-challenge URL
|
|
let threeDSFrame = null;
|
|
for (let i = 0; i < 15; i++) {
|
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
const frames = page.frames();
|
|
|
|
threeDSFrame = frames.find((f) =>
|
|
f.url().includes("three-ds-2-challenge"),
|
|
);
|
|
|
|
if (threeDSFrame) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!threeDSFrame) {
|
|
throw new Error("Could not find 3DS challenge frame");
|
|
}
|
|
|
|
// Wait for the 3DS frame content to load
|
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
|
|
// Check for nested iframes
|
|
const frameContent = await threeDSFrame.evaluate(() => {
|
|
return {
|
|
hasButton: !!document.querySelector("#test-source-authorize-3ds"),
|
|
iframes: document.querySelectorAll("iframe").length,
|
|
};
|
|
});
|
|
|
|
// If there's a nested iframe, find it
|
|
if (frameContent.iframes > 0) {
|
|
const childFrames = page.frames();
|
|
let challengeFrame = childFrames.find((f) =>
|
|
f.url().includes("3d_secure_2_test"),
|
|
);
|
|
|
|
if (!challengeFrame) {
|
|
challengeFrame = childFrames.find((f) => f.name() === "challengeFrame");
|
|
}
|
|
|
|
if (challengeFrame) {
|
|
threeDSFrame = challengeFrame;
|
|
}
|
|
}
|
|
|
|
// Wait for the button and click it
|
|
await threeDSFrame.waitForSelector("#test-source-authorize-3ds", {
|
|
timeout: 3000,
|
|
});
|
|
|
|
await threeDSFrame.evaluate(() => {
|
|
const button = document.querySelector(
|
|
"#test-source-authorize-3ds",
|
|
) as HTMLElement;
|
|
if (button) {
|
|
button.click();
|
|
}
|
|
});
|
|
|
|
// Wait for the 3DS authentication to complete
|
|
await timeout(10000);
|
|
} finally {
|
|
// always close browser
|
|
await browser.close();
|
|
}
|
|
};
|