Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions examples/pages-router-complex/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,11 @@ PLAYWRIGHT_PROJECT=pages-router-complex pnpm run test:e2e
degrades under it, so the `@atlas/*` alias is wired into both bundlers
explicitly (webpack hook + Vite `resolve.alias`); tsconfig `paths` (without
the removed `baseUrl`) stays authoritative for the type checker.
- **vinext dev (Cloudflare plugin): 59/73 specs pass; the 14 known gaps are
- **vinext dev (Cloudflare plugin): 62/73 specs pass; the 11 known gaps are
marked `test.fixme` so the passing surface runs in CI.** Known gaps:
`generateBuildId` is invoked at dev startup (Next.js only calls it at build
time — the e2e server exports `RELEASE_TAG` to compensate), shallow routing
+ `router.events` (including a hydration knock-on that breaks page
interactivity), the `next/image` custom-loader/`fill` path, raw
time — the e2e server exports `RELEASE_TAG` to compensate), the `next/image`
custom-loader/`fill` path, raw
`/_next/data` interception and the `/_next/image` 403 middleware branches,
the `history.replaceState`-beside-the-router hybrid, the gallery scrub
redirect, cacheable-404 surrogate headers, the `afterFiles` type-ahead
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export type GalleryWallProps = PageLiftedProps & {

export type GalleryWallComponentProps = Omit<
GalleryWallProps,
"lifted" | "graphSnapshot" | "edgeProbeData"
"graphSnapshot" | "edgeProbeData"
>;

const SORT_ORDERS = ["featured", "newest", "alpha"] as const;
Expand All @@ -62,7 +62,7 @@ const orderAssets = (assets: AssetCard[], sort: SortOrder): AssetCard[] => {
}
};

const GalleryWall = ({ wallPath, startPage }: GalleryWallComponentProps) => {
const GalleryWall = ({ wallPath, startPage, lifted }: GalleryWallComponentProps) => {
const router = useRouter();
const leaf = wallPath.split("/").filter(Boolean)[1] ?? "";
const node = useGraphOp<TopicNode>("nodeByTrail", { trail: leaf });
Expand Down Expand Up @@ -109,6 +109,7 @@ const GalleryWall = ({ wallPath, startPage }: GalleryWallComponentProps) => {
data-start-page={startPage}
data-sort={sort}
data-from-snapshot={node.fromSnapshot}
data-rendered-at-ms={lifted.renderedAtMs}
>
<h1>Wall: {node.data?.name ?? "…"}</h1>
<label>
Expand Down
28 changes: 24 additions & 4 deletions tests/e2e/pages-router-complex/client-routing.spec.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
import { test, expect } from "@playwright/test";
import { test, expect, type Page } from "@playwright/test";

type BeaconWindow = Window & {
__ATLAS_BEACONS__?: { name: string; attributes: Record<string, unknown> }[];
__ATLAS_TRIALS_ACTIVE__?: string[];
__nav_marker__?: boolean;
};

const waitForHydration = (page: Page) =>
expect(page.locator('[data-testid="helper-dock"]')).toBeVisible();

/**
* Client-side routing behaviours: shallow router.push with the internal
* dynamic-route pattern, router.events subscriptions, and the trial-mark
* reset hook built on next/compat/router.
*
* Next.js parity references:
* https://github.com/vercel/next.js/blob/canary/test/e2e/middleware-rewrites/test/index.test.ts
* https://github.com/vercel/next.js/blob/canary/test/e2e/basepath/router-events.test.ts
*/
test.describe("shallow routing and router events", () => {
test.fixme("changing sort shallow-navigates without re-running gSSP", async ({ page }) => {
test("changing sort shallow-navigates without re-running gSSP", async ({ page }) => {
await page.goto("/gallery/skies/clips");
await expect(page.locator('[data-testid="gallery-wall"]')).toHaveAttribute(
"data-sort",
"featured",
);
await waitForHydration(page);
const renderedAtMs = await page
.locator('[data-testid="gallery-wall"]')
.getAttribute("data-rendered-at-ms");
if (!renderedAtMs) {
throw new Error("gallery wall did not expose its gSSP render timestamp");
}

// Plant a marker: a shallow transition must NOT be a full document load.
await page.evaluate(() => {
Expand All @@ -31,6 +45,10 @@ test.describe("shallow routing and router events", () => {
"data-sort",
"alpha",
);
await expect(page.locator('[data-testid="gallery-wall"]')).toHaveAttribute(
"data-rendered-at-ms",
renderedAtMs,
);

const marker = await page.evaluate(() => (window as BeaconWindow).__nav_marker__);
expect(marker).toBe(true);
Expand All @@ -40,10 +58,11 @@ test.describe("shallow routing and router events", () => {
expect(titles).toEqual([...titles].sort((a, b) => a.localeCompare(b)));
});

test.fixme("shallow transitions fire router events observed by the progress frame", async ({
test("shallow transitions fire router events observed by the progress frame", async ({
page,
}) => {
await page.goto("/gallery/skies/clips");
await waitForHydration(page);
await expect(page.locator('[data-testid="route-progress"]')).toBeVisible();

await page.locator('[data-testid="wall-sort"]').selectOption("newest");
Expand All @@ -60,8 +79,9 @@ test.describe("shallow routing and router events", () => {
expect(phases.indexOf("start")).toBeLessThan(phases.indexOf("complete"));
});

test.fixme("route changes reset the per-page trial marks", async ({ page }) => {
test("route changes reset the per-page trial marks", async ({ page }) => {
await page.goto("/gallery/skies/clips");
await waitForHydration(page);
await page.evaluate(() => {
(window as BeaconWindow).__ATLAS_TRIALS_ACTIVE__ = ["stale-flag"];
});
Expand Down
Loading