120 lines
4.0 KiB
TypeScript
120 lines
4.0 KiB
TypeScript
import { expect, test, type Page } from "@playwright/test";
|
|
|
|
import { stripePaymentDialogStyles } from "@/app/_components/payment/stripe-payment-dialog.styles";
|
|
import { mockCoreApis } from "@e2e/fixtures/api-mocks";
|
|
|
|
const viewports = [
|
|
{ width: 390, height: 844 },
|
|
{ width: 405, height: 797 },
|
|
{ width: 540, height: 900 },
|
|
] as const;
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
await mockCoreApis(page);
|
|
});
|
|
|
|
for (const viewport of viewports) {
|
|
test(`payment portal stays viewport-bound at ${viewport.width}x${viewport.height}`, async ({
|
|
page,
|
|
}) => {
|
|
await page.setViewportSize(viewport);
|
|
await page.goto("/subscription?type=topup", {
|
|
waitUntil: "domcontentloaded",
|
|
});
|
|
|
|
await mountPaymentPanel(page, 180);
|
|
await expectViewportScrim(page, viewport);
|
|
await expectCenteredShortPanel(page, viewport);
|
|
|
|
await mountPaymentPanel(page, 1_200);
|
|
await expectViewportScrim(page, viewport);
|
|
await expectScrollableTallPanel(page, viewport);
|
|
});
|
|
}
|
|
|
|
async function mountPaymentPanel(page: Page, contentHeight: number) {
|
|
await page.evaluate(
|
|
({ dialogClassName, overlayClassName, requestedContentHeight }) => {
|
|
document.querySelector('[data-testid="payment-layout-overlay"]')?.remove();
|
|
document.querySelector('[data-testid="transformed-checkout-host"]')?.remove();
|
|
|
|
const transformedCheckoutHost = document.createElement("div");
|
|
transformedCheckoutHost.dataset.testid = "transformed-checkout-host";
|
|
transformedCheckoutHost.style.transform = "translateX(50%)";
|
|
document.body.appendChild(transformedCheckoutHost);
|
|
|
|
const overlay = document.createElement("div");
|
|
overlay.dataset.testid = "payment-layout-overlay";
|
|
overlay.className = overlayClassName;
|
|
|
|
const panel = document.createElement("div");
|
|
panel.dataset.testid = "payment-layout-panel";
|
|
panel.className = dialogClassName;
|
|
|
|
const content = document.createElement("div");
|
|
content.style.height = `${requestedContentHeight}px`;
|
|
content.textContent = "Complete payment";
|
|
panel.appendChild(content);
|
|
overlay.appendChild(panel);
|
|
|
|
// Mirrors ModalPortal: the overlay must be a body child, never a child of
|
|
// the transformed checkout host that triggered it.
|
|
document.body.appendChild(overlay);
|
|
},
|
|
{
|
|
dialogClassName: stripePaymentDialogStyles.dialog,
|
|
overlayClassName: stripePaymentDialogStyles.overlay,
|
|
requestedContentHeight: contentHeight,
|
|
},
|
|
);
|
|
}
|
|
|
|
async function expectViewportScrim(
|
|
page: Page,
|
|
viewport: { width: number; height: number },
|
|
) {
|
|
const overlay = page.getByTestId("payment-layout-overlay");
|
|
await expect(overlay).toBeVisible();
|
|
const box = await overlay.boundingBox();
|
|
|
|
expect(box).not.toBeNull();
|
|
expect(box?.x).toBeCloseTo(0, 0);
|
|
expect(box?.y).toBeCloseTo(0, 0);
|
|
expect(box?.width).toBeCloseTo(viewport.width, 0);
|
|
expect(box?.height).toBeCloseTo(viewport.height, 0);
|
|
await expect(overlay.evaluate((node) => node.parentElement === document.body))
|
|
.resolves.toBe(true);
|
|
}
|
|
|
|
async function expectCenteredShortPanel(
|
|
page: Page,
|
|
viewport: { width: number; height: number },
|
|
) {
|
|
const panel = page.getByTestId("payment-layout-panel");
|
|
const box = await panel.boundingBox();
|
|
|
|
expect(box).not.toBeNull();
|
|
expect(box?.y ?? 0).toBeGreaterThan(100);
|
|
expect(Math.abs((box?.y ?? 0) * 2 + (box?.height ?? 0) - viewport.height))
|
|
.toBeLessThanOrEqual(2);
|
|
}
|
|
|
|
async function expectScrollableTallPanel(
|
|
page: Page,
|
|
viewport: { width: number; height: number },
|
|
) {
|
|
const panel = page.getByTestId("payment-layout-panel");
|
|
const box = await panel.boundingBox();
|
|
const scrollMetrics = await panel.evaluate((node) => ({
|
|
clientHeight: node.clientHeight,
|
|
scrollHeight: node.scrollHeight,
|
|
}));
|
|
|
|
expect(box).not.toBeNull();
|
|
expect(box?.y ?? 0).toBeGreaterThanOrEqual(15);
|
|
expect(box?.y ?? 100).toBeLessThanOrEqual(25);
|
|
expect((box?.y ?? 0) + (box?.height ?? 0))
|
|
.toBeLessThanOrEqual(viewport.height - 15);
|
|
expect(scrollMetrics.scrollHeight).toBeGreaterThan(scrollMetrics.clientHeight);
|
|
}
|