154 lines
4.6 KiB
TypeScript
154 lines
4.6 KiB
TypeScript
import { expect, test, type Page } from "@playwright/test";
|
|
|
|
import { mockCoreApis } from "@e2e/fixtures/api-mocks";
|
|
import { apiEnvelope } from "@e2e/fixtures/data/common";
|
|
import { e2eEmailUser } from "@e2e/fixtures/data/user";
|
|
import {
|
|
clearBrowserState,
|
|
seedEmailSession,
|
|
} from "@e2e/fixtures/test-helpers";
|
|
|
|
const phpPlans = {
|
|
plans: [
|
|
{
|
|
planId: "dol_1000",
|
|
planName: "1,000 Credits",
|
|
orderType: "dol",
|
|
amountCents: 49_990,
|
|
originalAmountCents: 74_990,
|
|
dailyPriceCents: null,
|
|
currency: "PHP",
|
|
vipDays: null,
|
|
dolAmount: 1_000,
|
|
creditBalance: 1_000,
|
|
},
|
|
],
|
|
};
|
|
|
|
async function registerPhilippinesPaymentMocks(
|
|
page: Page,
|
|
response: "hosted" | "qr",
|
|
) {
|
|
let createOrderCount = 0;
|
|
|
|
await page.route("**/api/user/profile", async (route) => {
|
|
await route.fulfill({
|
|
json: apiEnvelope({ ...e2eEmailUser, countryCode: "PH" }),
|
|
});
|
|
});
|
|
await page.route("**/api/payment/plans**", async (route) => {
|
|
await route.fulfill({ json: apiEnvelope(phpPlans) });
|
|
});
|
|
await page.route("**/api/payment/create-order", async (route) => {
|
|
createOrderCount += 1;
|
|
await route.fulfill({
|
|
json: apiEnvelope({
|
|
orderId: `order_gcash_${response}`,
|
|
payParams: {
|
|
provider: "ezpay",
|
|
countryCode: "PH",
|
|
channelCode: "PH_QRPH_DYNAMIC",
|
|
channelType: "QR",
|
|
payData: "000201010212ph-qr-payload",
|
|
...(response === "hosted"
|
|
? { cashierUrl: "https://pay.example/gcash-hosted" }
|
|
: {}),
|
|
firstChargeAmountCents: 49_990,
|
|
currency: "PHP",
|
|
},
|
|
}),
|
|
});
|
|
});
|
|
await page.route("**/api/payment/order-status**", async (route) => {
|
|
await route.fulfill({
|
|
json: apiEnvelope({
|
|
orderId: `order_gcash_${response}`,
|
|
status: "pending",
|
|
orderType: "dol",
|
|
planId: "dol_1000",
|
|
creditsAdded: 0,
|
|
}),
|
|
});
|
|
});
|
|
|
|
return {
|
|
getCreateOrderCount: () => createOrderCount,
|
|
};
|
|
}
|
|
|
|
async function preparePhilippinesUser(page: Page) {
|
|
await seedEmailSession(page);
|
|
await page.evaluate(() => {
|
|
const rawUser = localStorage.getItem("cozsweet:user");
|
|
const user = rawUser ? JSON.parse(rawUser) : {};
|
|
localStorage.setItem(
|
|
"cozsweet:user",
|
|
JSON.stringify({ ...user, countryCode: "PH" }),
|
|
);
|
|
});
|
|
}
|
|
|
|
test.beforeEach(async ({ baseURL, context, page }) => {
|
|
await clearBrowserState(context, page, baseURL);
|
|
await mockCoreApis(page);
|
|
});
|
|
|
|
test("Philippines checkout prefers the hosted GCash URL even for a QR response", async ({
|
|
page,
|
|
}) => {
|
|
const payment = await registerPhilippinesPaymentMocks(page, "hosted");
|
|
await preparePhilippinesUser(page);
|
|
await page.goto("/subscription?type=topup&character=elio");
|
|
|
|
await expect(page.getByRole("button", { name: "GCash" })).toHaveAttribute(
|
|
"aria-pressed",
|
|
"true",
|
|
);
|
|
await page.getByRole("button", { name: "Pay and Top Up" }).click();
|
|
|
|
await expect(
|
|
page.getByRole("alertdialog", { name: "Continue to payment?" }),
|
|
).toBeVisible();
|
|
await expect(
|
|
page.getByRole("dialog", { name: "Pay with GCash / QR Ph" }),
|
|
).toHaveCount(0);
|
|
await expect(
|
|
page.getByRole("dialog", { name: "Scan to pay with QRIS" }),
|
|
).toHaveCount(0);
|
|
expect(payment.getCreateOrderCount()).toBe(1);
|
|
|
|
await page.getByRole("button", { name: "Cancel" }).click();
|
|
await expect(page.getByRole("button", { name: "Stripe" })).toBeEnabled();
|
|
expect(payment.getCreateOrderCount()).toBe(1);
|
|
});
|
|
|
|
test("Philippines QR-only fallback is labeled GCash / QR Ph and can switch to Stripe", async ({
|
|
page,
|
|
}) => {
|
|
await page.setViewportSize({ width: 390, height: 844 });
|
|
const payment = await registerPhilippinesPaymentMocks(page, "qr");
|
|
await preparePhilippinesUser(page);
|
|
await page.goto("/subscription?type=topup&character=elio");
|
|
|
|
await page.getByRole("button", { name: "Pay and Top Up" }).click();
|
|
const dialog = page.getByRole("dialog", {
|
|
name: "Pay with GCash / QR Ph",
|
|
});
|
|
await expect(dialog).toBeVisible();
|
|
await expect(dialog).toContainText(/₱\s*499\.90/);
|
|
await expect(dialog).not.toContainText("QRIS");
|
|
await expect(
|
|
dialog.getByRole("img", { name: "GCash / QR Ph payment QR code" }),
|
|
).toBeVisible();
|
|
|
|
await dialog.getByRole("button", { name: "Close" }).click();
|
|
await expect(dialog).toBeHidden();
|
|
await expect(page.getByRole("button", { name: "Stripe" })).toBeEnabled();
|
|
await page.getByRole("button", { name: "Stripe" }).click();
|
|
await expect(page.getByRole("button", { name: "Stripe" })).toHaveAttribute(
|
|
"aria-pressed",
|
|
"true",
|
|
);
|
|
expect(payment.getCreateOrderCount()).toBe(1);
|
|
});
|