106 lines
3.7 KiB
TypeScript
106 lines
3.7 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
import { mockCoreApis } from "@e2e/fixtures/api-mocks";
|
|
import { apiEnvelope } from "@e2e/fixtures/data/common";
|
|
import {
|
|
clearBrowserState,
|
|
seedEmailSession,
|
|
} from "@e2e/fixtures/test-helpers";
|
|
|
|
const facebookAndroidUserAgent =
|
|
"Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 " +
|
|
"(KHTML, like Gecko) Version/4.0 Chrome/126.0.0.0 Mobile Safari/537.36 " +
|
|
"[FB_IAB/FB4A;FBAV/566.0.0.48.73;]";
|
|
const handoffToken = "checkout-handoff-token-that-is-at-least-32-characters";
|
|
|
|
test.use({
|
|
userAgent: facebookAndroidUserAgent,
|
|
viewport: { width: 390, height: 844 },
|
|
});
|
|
|
|
test.beforeEach(async ({ baseURL, context, page }) => {
|
|
await clearBrowserState(context, page, baseURL);
|
|
});
|
|
|
|
test("consumes the handoff, removes its token, and does not create an order", async ({
|
|
page,
|
|
}) => {
|
|
await mockCoreApis(page, { checkoutHandoffFlow: true });
|
|
let createOrderRequests = 0;
|
|
page.on("request", (request) => {
|
|
if (request.url().includes("/api/payment/create-order")) {
|
|
createOrderRequests += 1;
|
|
}
|
|
});
|
|
const consumeRequest = page.waitForRequest(
|
|
"**/api/auth/handoff/checkout/consume",
|
|
);
|
|
|
|
await page.goto(
|
|
`/external-entry?target=checkout&character=nayeli&handoffToken=${encodeURIComponent(handoffToken)}`,
|
|
);
|
|
|
|
expect((await consumeRequest).postDataJSON()).toEqual({ handoffToken });
|
|
await expect(page).toHaveURL(
|
|
/\/subscription\?planId=vip_monthly&autoRenew=1&character=nayeli&commercialOfferId=.*&payChannel=stripe/,
|
|
);
|
|
expect(page.url()).not.toContain("handoffToken");
|
|
await expect.poll(() => createOrderRequests).toBe(0);
|
|
await expect
|
|
.poll(() =>
|
|
page.evaluate(() => ({
|
|
loginProvider: localStorage.getItem("cozsweet:login_provider"),
|
|
loginToken: localStorage.getItem("cozsweet:login_token"),
|
|
})),
|
|
)
|
|
.toEqual({ loginProvider: "email", loginToken: "e2e-checkout-token" });
|
|
});
|
|
|
|
test("offers the Facebook external-browser path before creating a Stripe order", async ({
|
|
page,
|
|
}) => {
|
|
await mockCoreApis(page);
|
|
let createOrderRequests = 0;
|
|
page.on("request", (request) => {
|
|
if (request.url().includes("/api/payment/create-order")) {
|
|
createOrderRequests += 1;
|
|
}
|
|
});
|
|
await page.route("**/api/auth/handoff/checkout", async (route) => {
|
|
await route.fulfill({
|
|
json: apiEnvelope({
|
|
externalUrl:
|
|
"https://cozsweet.com/external-entry?target=checkout&handoffToken=opaque-token",
|
|
expiresAt: "2026-07-28T16:00:00+00:00",
|
|
}),
|
|
});
|
|
});
|
|
|
|
await seedEmailSession(page);
|
|
await page.goto("/subscription?type=vip&payChannel=stripe&character=maya");
|
|
await page.getByRole("button", { name: /Monthly,/i }).click();
|
|
const externalButton = page.getByRole("button", {
|
|
name: "Open in browser for more payment methods",
|
|
});
|
|
const paymentButton = page.getByRole("button", { name: "Pay and Top Up" });
|
|
await expect(externalButton).toBeVisible();
|
|
await expect(externalButton).toBeEnabled();
|
|
await expect(paymentButton).toBeVisible();
|
|
await expect(
|
|
page.getByRole("dialog", { name: "Automatic Renewal Confirmation" }),
|
|
).toHaveCount(0);
|
|
const externalBox = await externalButton.boundingBox();
|
|
const paymentBox = await paymentButton.boundingBox();
|
|
expect(externalBox).not.toBeNull();
|
|
expect(paymentBox).not.toBeNull();
|
|
expect(externalBox!.y).toBeLessThan(paymentBox!.y);
|
|
expect(paymentBox!.y + paymentBox!.height).toBeLessThanOrEqual(844);
|
|
const handoffRequest = page.waitForRequest("**/api/auth/handoff/checkout");
|
|
await externalButton.click();
|
|
expect((await handoffRequest).postDataJSON()).toMatchObject({
|
|
planId: "vip_monthly",
|
|
autoRenew: true,
|
|
});
|
|
expect(createOrderRequests).toBe(0);
|
|
});
|