fix(ci): keep routing and desktop suites isolated

The routing regression must run before dependency installation, and desktop Vitest must not collect Playwright-owned specs.
This commit is contained in:
Mohamed Boudra
2026-07-28 18:50:36 +02:00
parent 61409dfe9c
commit 1c2cb89a42
4 changed files with 17 additions and 6 deletions

1
package-lock.json generated
View File

@@ -35,7 +35,6 @@
"oxlint": "1.61.0",
"oxlint-tsgolint": "^0.22.1",
"patch-package": "^8.0.1",
"picomatch": "4.0.5",
"playwright": "^1.56.1",
"typescript": "^5.9.3",
"ws": "^8.20.0"

View File

@@ -127,7 +127,6 @@
"oxlint": "1.61.0",
"oxlint-tsgolint": "^0.22.1",
"patch-package": "^8.0.1",
"picomatch": "4.0.5",
"playwright": "^1.56.1",
"typescript": "^5.9.3",
"ws": "^8.20.0"

View File

@@ -23,7 +23,7 @@
"test:e2e:renderer": "cross-env E2E_DESKTOP_RUNTIME=1 playwright test --config=playwright.config.ts --project=desktop",
"test:e2e:browser-tabs": "npm run build:main && node ./e2e/browser-tabs.e2e.mjs",
"verify:electron-cdp": "node ./scripts/verify-electron-cdp.mjs",
"test": "vitest run",
"test": "vitest run --exclude \"e2e/**\"",
"typecheck": "tsgo --noEmit -p tsconfig.json"
},
"dependencies": {

View File

@@ -1,8 +1,7 @@
import assert from "node:assert/strict";
import { readFileSync, readdirSync } from "node:fs";
import { relative as relativePath } from "node:path";
import { matchesGlob, relative as relativePath } from "node:path";
import test from "node:test";
import picomatch from "picomatch";
const repoRoot = new URL("../", import.meta.url);
const ciWorkflowPath = new URL(".github/workflows/ci.yml", repoRoot);
@@ -10,6 +9,7 @@ const dockerWorkflowPath = new URL(".github/workflows/docker.yml", repoRoot);
const nixWorkflowPath = new URL(".github/workflows/nix.yml", repoRoot);
const filtersPath = new URL(".github/ci-paths.yml", repoRoot);
const serverTsconfigPath = new URL("packages/server/tsconfig.server.json", repoRoot);
const desktopPackagePath = new URL("packages/desktop/package.json", repoRoot);
const gatedCiJobs = new Map([
["format", { name: "format", contract: "format" }],
@@ -65,7 +65,17 @@ function loadFilters(path) {
}
function matchesFilter(filters, filterName, changedPath) {
return filters[filterName].some((pattern) => picomatch(pattern, { dot: true })(changedPath));
const visiblePath = exposeDotSegments(changedPath);
return filters[filterName].some((pattern) =>
matchesGlob(visiblePath, exposeDotSegments(pattern)),
);
}
// dorny/paths-filter uses picomatch with `dot: true`. Node's dependency-free
// matcher hides dot-prefixed path segments by default, so make those segments
// ordinary in both operands before matching.
function exposeDotSegments(value) {
return value.replace(/(^|\/)\./g, "$1__dot__");
}
function filesUnder(relativeDirectory, predicate) {
@@ -245,6 +255,9 @@ test("browser and desktop tests have exclusive, directory-owned suites", () => {
assert.ok(desktopSpecs.every((path) => path.startsWith("packages/desktop/e2e/")));
assert.ok(electronModules.every((path) => path.startsWith("packages/app/src/desktop/")));
const desktopPackage = JSON.parse(readFileSync(desktopPackagePath, "utf8"));
assert.match(desktopPackage.scripts.test, /--exclude ["']e2e\/\*\*["']/);
for (const path of browserSpecs) {
assert.equal(matchesFilter(filters, "browser", path), true, path);
assert.equal(matchesFilter(filters, "desktop", path), false, path);