fix(payment): portal checkout dialogs to viewport
(cherry picked from commit 67f292353e)
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user