Skip to content

Commit cf24f03

Browse files
committed
Add a test that the deeplink allowlist matches the environment routes
The allowlist is maintained by hand, so it can fall behind when a page is added. The test derives the expected set from the environment layout's route filenames and names any segment that drifts.
1 parent a1fa385 commit cf24f03

1 file changed

Lines changed: 61 additions & 0 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { readdirSync } from "node:fs";
2+
import { join } from "node:path";
3+
import { describe, expect, it } from "vitest";
4+
import { ENV_PAGE_SEGMENTS } from "./deeplinkPages";
5+
6+
// Flat-route prefix for every page that renders inside an environment. The trailing dot matters:
7+
// it excludes the layout route itself (`…env.$envParam`), which has no segment of its own.
8+
const ENV_ROUTE_PREFIX = "_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.";
9+
10+
/**
11+
* Segments that are route files but not deeplink targets:
12+
* - `_index` is the environment root, which is already where an unrecognised deeplink lands.
13+
* - `queues_` is Remix's "opt out of the parent layout" spelling of `queues`, not a distinct URL.
14+
*/
15+
const NOT_DEEPLINKABLE = new Set(["_index", "queues_"]);
16+
17+
/** The first path segment of every environment page, read off the route filenames. */
18+
function envRouteSegments(): Set<string> {
19+
const entries = readdirSync(join(__dirname, "../routes"));
20+
const segments = new Set<string>();
21+
22+
for (const entry of entries) {
23+
if (!entry.startsWith(ENV_ROUTE_PREFIX)) continue;
24+
// `metrics.$dashboardKey.ts` -> `metrics`, `agents` -> `agents`, `errors._index` -> `errors`
25+
const segment = entry.slice(ENV_ROUTE_PREFIX.length).split(/[./]/)[0];
26+
// Guards against a future `…env.$envParam.tsx` contributing its extension as a segment.
27+
if (!segment || segment === "ts" || segment === "tsx") continue;
28+
if (NOT_DEEPLINKABLE.has(segment)) continue;
29+
segments.add(segment);
30+
}
31+
32+
return segments;
33+
}
34+
35+
describe("deeplink allowlist", () => {
36+
it("matches the environment layout's route segments", () => {
37+
// Sorted arrays rather than sets so a mismatch names the segment that drifted.
38+
expect([...ENV_PAGE_SEGMENTS].sort()).toEqual([...envRouteSegments()].sort());
39+
});
40+
41+
it("found the routes directory", () => {
42+
// Guards the test itself: an empty derived set would make the assertion above vacuous
43+
// if the allowlist were ever emptied too.
44+
expect(envRouteSegments().size).toBeGreaterThan(20);
45+
});
46+
47+
it("excludes the environment root and the layout-opt-out spelling", () => {
48+
expect(ENV_PAGE_SEGMENTS.has("_index")).toBe(false);
49+
expect(ENV_PAGE_SEGMENTS.has("queues_")).toBe(false);
50+
// `queues` itself is still reachable — it is the real URL segment.
51+
expect(ENV_PAGE_SEGMENTS.has("queues")).toBe(true);
52+
});
53+
54+
it("includes the pages that ENV_PAGE_META omits", () => {
55+
// These have no entry in ENV_PAGE_META (their icon/label is special-cased when resolving
56+
// page metadata), which is why the allowlist is derived from routes and not from that map.
57+
for (const segment of ["tasks", "agents", "settings"]) {
58+
expect(ENV_PAGE_SEGMENTS.has(segment)).toBe(true);
59+
}
60+
});
61+
});

0 commit comments

Comments
 (0)