Skip to content
Merged
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
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@
"test:all-runtimes": "deno task test:unit && deno task test:node && deno task test:bun",
"test:e2e": "deno task test:e2e:playwright",
"test:e2e:playwright": "deno run -A npm:playwright@1.60.0 test --config=tests/e2e/playwright.config.cjs",
"test:e2e:rsc-browser": "deno task generate && DENO_TESTING=1 VF_DISABLE_LRU_INTERVAL=1 SSR_TRANSFORM_PER_PROJECT_LIMIT=0 REVALIDATION_PER_PROJECT_LIMIT=0 NODE_ENV=production LOG_FORMAT=text deno test --no-check --allow-all tests/e2e/regressions/rsc-proxy-hydration.test.ts tests/e2e/regressions/2026-07-27-legacy-router-hydration.test.ts tests/e2e/regressions/2026-07-27-release-asset-page-island-hydration.test.ts tests/e2e/regressions/2026-08-14-server-layout-spa-fallback.test.ts --unstable-worker-options --unstable-net",
"test:e2e:rsc-browser": "deno task generate && DENO_TESTING=1 VF_DISABLE_LRU_INTERVAL=1 SSR_TRANSFORM_PER_PROJECT_LIMIT=0 REVALIDATION_PER_PROJECT_LIMIT=0 NODE_ENV=production LOG_FORMAT=text deno test --no-check --allow-all tests/e2e/regressions/rsc-proxy-hydration.test.ts tests/e2e/regressions/2026-07-27-legacy-router-hydration.test.ts tests/e2e/regressions/2026-07-27-release-asset-page-island-hydration.test.ts tests/e2e/regressions/2026-08-14-server-layout-spa-fallback.test.ts tests/e2e/regressions/dev-ui-browser-bundle.test.ts --unstable-worker-options --unstable-net",
"test:e2e:binary": "deno task generate && deno test --allow-all tests/integration/compiled-binary-e2e.test.ts",
"test:e2e:binary:fresh": "deno task generate && VERYFRONT_BINARY_FRESH=1 deno test --allow-all tests/integration/compiled-binary-e2e.test.ts",
"test:e2e:templates": "deno run --allow-all scripts/test/template-runtime-e2e.ts",
Expand Down
58 changes: 55 additions & 3 deletions scripts/test/run-suite.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
buildDenoSuiteCommandArgs,
parseDenoSuiteArgs,
} from "./run-deno-suite.ts";
import { LEAF_TEST_SUITES } from "./suites.ts";
import { classifyTestPath } from "./test-layout.ts";
import {
formatSuitePlan,
planSuiteFiles,
Expand Down Expand Up @@ -57,6 +59,21 @@ describe("suite planning parity", () => {
}
});

it("runs every root the unit suite claims to own", async () => {
// Regression guard. suites.ts, deno.json's test.include and
// suites.test.ts all place extensions/ and react/ in the unit suite, but
// UNIT_ROOTS omitted them, so 90 extension test files never executed while
// extensions/*/src/** still counted toward the 80% coverage gate.
const plan = await planSuiteFiles({ suite: "coverage:unit" });

for (const root of LEGACY_UNIT_ROOTS) {
assert(
plan.files.some((path) => path.startsWith(`${root}/`)),
`the unit suite owns ${root}/ but planned no test file from it`,
);
}
});

it("keeps runtime-guarded Deno references eligible for Node", async () => {
// `tests/test-file-utils.mjs` owns which sources count as Deno-dependent,
// and a file opting out with the runtime-guarded header runs on Node. A
Expand Down Expand Up @@ -284,11 +301,46 @@ describe("migration command surface", () => {
assert(match, "pre-push must invoke a named E2E task");
assert(config.tasks[match[1]], `${match[1]} must exist in deno.json`);
});

it("routes the Dev UI browser bundle test through the browser E2E lane", async () => {
const config = JSON.parse(
await Deno.readTextFile(new URL("../../deno.json", import.meta.url)),
);
const task = config.tasks["test:e2e:rsc-browser"] as string | undefined;
const browserBundleTest =
"tests/e2e/regressions/dev-ui-browser-bundle.test.ts";

assert(task, "browser E2E task must remain defined");
assert(
task.includes(browserBundleTest),
"the Chromium-backed Dev UI bundle test needs an explicit browser-capable runner",
);
assertEquals(classifyTestPath(browserBundleTest), {
kind: "canonical",
path: browserBundleTest,
level: "e2e",
suite: "e2e",
runner: "deno",
});
});
});

// Read from the suite registry rather than restated here. A second hand-kept
// copy of the roots is what let ownership and execution drift in the first
// place: it would keep passing while a newly owned root went unplanned.
// scripts/ is excluded for the reason documented on UNPLANNABLE_UNIT_ROOTS in
// run-suite.ts -- deno.json's root `exclude` hides it from the main config.
const LEGACY_UNIT_ROOTS = (LEAF_TEST_SUITES
.find((suite) => suite.id === "unit")?.pathSelectors ?? [])
.filter((root) => root !== "scripts/")
.map((root) => root.replace(/\/$/, ""));

async function legacyUnitParallelFiles(): Promise<string[]> {
const files = await collectLegacyTestFiles(["src", "cli", "templates"]);
const excluded = new Set([...UNIT_CWD_FILES, ...UNIT_CWD_EXCLUSION_FILES]);
const files = await collectLegacyTestFiles(LEGACY_UNIT_ROOTS);
const excluded = new Set([
...UNIT_CWD_FILES,
...UNIT_CWD_EXCLUSION_FILES,
]);
return sorted(
files.filter((path) =>
!path.includes(".integration.test.ts") &&
Expand All @@ -308,7 +360,7 @@ async function legacyCliIntegrationFiles(): Promise<string[]> {

async function legacyUnitCoverageFiles(): Promise<string[]> {
return sorted(
(await collectLegacyTestFiles(["src", "cli", "templates"]))
(await collectLegacyTestFiles(LEGACY_UNIT_ROOTS))
.filter((path) => !/\.integration\.test\.tsx?$/.test(path))
.filter((path) => !path.startsWith("src/workflow/__tests__/")),
);
Expand Down
24 changes: 23 additions & 1 deletion scripts/test/run-suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from "../../tests/test-file-utils.mjs";
import { DENO_ONLY_TESTS } from "../../tests/deno-only-tests.mjs";
import { discoverTests } from "./test-layout.ts";
import { LEAF_TEST_SUITES } from "./suites.ts";

export type SuitePlanId =
| "unit:parallel"
Expand Down Expand Up @@ -42,7 +43,28 @@ export interface SuiteFilePlan {
readonly files: readonly string[];
}

const UNIT_ROOTS = ["src/", "cli/", "templates/"];
// deno.json's root `exclude` lists scripts/, so those files are undiscoverable
// under the main config -- `deno test` reports "No test modules found" for them.
// They run through the dedicated `test:scripts` task with scripts/test.deno.json
// instead, so the unit planner skips the root while the registry still owns it.
const UNPLANNABLE_UNIT_ROOTS = new Set(["scripts/"]);

/**
* Derived from the unit suite's own `pathSelectors` so ownership and execution
* cannot drift: a root added in suites.ts is planned here without a second
* edit. Hardcoding the list is what left extensions/ and react/ owned by the
* unit suite -- `resolveLeafSuiteOwners` said so and suites.test.ts asserted it
* -- while no runner selected them, so 90 extension test files never executed
* even though `--include=src/` still counted every extension package's own
* `src` directory toward the coverage gate.
*/
const UNIT_ROOTS = (() => {
const unit = LEAF_TEST_SUITES.find((suite) => suite.id === "unit");
if (!unit) {
throw new Error("The leaf suite registry no longer defines a unit suite.");
}
return unit.pathSelectors.filter((root) => !UNPLANNABLE_UNIT_ROOTS.has(root));
})();
const UNIT_CWD_FILES = [
"cli/router.test.ts",
"cli/app/operations/project-creation.test.ts",
Expand Down
Loading
Loading