browser tests run only by hand: the suites that launch Chrome / Chromium move to tests/browser/*.browser.ts (bun test, ci, ci:quick and the Forgejo workflows never pick them up; bun run test:browser runs them); the desktop boot check leaves bun run ci (it stays in desktop-release.ts mac at release time); CI=full is gone: Forgejo's ci runs the Rust steps when the push changed a Rust input (STOREBOUND_CI_BASE=HEAD~1), no Playwright install; CONTRIBUTING

This commit is contained in:
CRTkafa 2026-10-15 01:25:17 +08:00
parent 4c7ff89950
commit cd1e13c1e2
20 changed files with 116 additions and 133 deletions

View file

@ -13,9 +13,9 @@ export const TIMINGS = join(ROOT, 'node_modules/.cache/storebound-ci/test-timing
* never next to the light tests, and those shards start first: eight browsers at once (one per shard) on a machine
* other sessions already load to 100+ made the walks time out. */
export const HEAVY = [
'tests/console-fill.test.ts', 'tests/site-overflow.test.ts', 'tests/local-fonts.test.ts', 'tests/glyphs.test.ts',
'tests/capture-web.test.ts', 'tests/console-session.test.ts', 'tests/console-persist.test.ts', 'tests/console-flow.test.ts',
'tests/glyph-ligatures.test.ts', 'tests/feature-fit.test.ts',
'tests/browser/console-fill.browser.ts', 'tests/browser/site-overflow.browser.ts', 'tests/browser/local-fonts.browser.ts', 'tests/browser/glyphs.browser.ts',
'tests/browser/capture-web.browser.ts', 'tests/browser/console-session.browser.ts', 'tests/browser/console-persist.browser.ts', 'tests/browser/console-flow.browser.ts',
'tests/browser/glyph-ligatures.browser.ts', 'tests/browser/feature-fit.browser.ts',
];
/** Browser tests of one file at the same time (bun test --max-concurrency for the browser shards; the tests opt in
@ -31,7 +31,7 @@ export function browserShardCount(env = process.env): number {
/**
* The local pre-push gate on a busy shared machine: with the 1-minute load average above 2x the cores, the browser
* suites (HEAVY) and the desktop boot check (real Chrome) are deferred to the Forgejo CI on the VDS, which always runs
* them (CI=full; a red Forgejo CI on main stops releases). CI=full forces them locally.
* them. Kept for the record: CI has no browser suites any more (tests/browser/, `bun run test:browser`).
*/
export function deferBrowser(env = process.env, load1 = loadavg()[0] ?? 0, cores = cpus().length): boolean {
return env.CI !== 'full' && load1 > 2 * cores;

View file

@ -15,14 +15,14 @@
// no-hand-written-SVG guard; the desktop boot check (tools/desktop-boot-check.ts: the built window in headless
// Chromium, needs playwright's browser or Google Chrome) runs after the desktop build.
// The desktop Rust host (cargo test, clippy with warnings as errors) runs when cargo is installed and
// apps/desktop/src-tauri or the sidecar build changed against origin/main, or always with CI=full;
// apps/desktop/src-tauri or the sidecar build changed against origin/main (STOREBOUND_CI_BASE);
// STOREBOUND_CI_RUST=0 skips it on a machine without Rust.
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
import { cpus, homedir, loadavg, tmpdir } from 'node:os';
import { join } from 'node:path';
import { hostTarget, OUT_DIR, outName } from './build-sidecars';
import { loadFactor, loadNote, RETRY_MARK, scaled } from '../tests/helpers/load';
import { BROWSER_CONCURRENCY, changedFiles, deferBrowser, HEAVY, junitTimes, listTests, mergeTimings, planShards, readTimings, relatedTests, ROOT, rustNeeded, writeTimings } from './ci-plan';
import { BROWSER_CONCURRENCY, changedFiles, HEAVY, junitTimes, listTests, mergeTimings, planShards, readTimings, relatedTests, ROOT, rustNeeded, writeTimings } from './ci-plan';
interface Task { name: string; cmd: string[]; cwd?: string; env?: Record<string, string>; after?: string[]; junit?: string }
@ -30,10 +30,9 @@ const quick = process.argv.includes('--quick');
const tauri = join(ROOT, 'apps/desktop/src-tauri');
const cache = join(ROOT, 'node_modules/.cache/storebound-ci');
const changed = changedFiles();
const deferred = deferBrowser();
const allTests = listTests();
const tests = deferred ? allTests.filter(f => !HEAVY.includes(f)) : allTests;
if (deferred) console.log(`ci: browser suites deferred to Forgejo CI (load ${loadavg()[0]!.toFixed(0)} > 2 x ${cpus().length} cores): ${allTests.filter(f => HEAVY.includes(f)).join(' ')} and the desktop boot check. CI=full runs them here.`);
// no browser runs in CI: the browser suites live in tests/browser/*.browser.ts and run only with `bun run test:browser`;
// the one browser step left is the desktop boot check inside `tools/desktop-release.ts mac` (release time)
const tests = listTests();
const touches = (re: RegExp) => changed === null || changed.some(f => re.test(f));
const tasks: Task[] = [];
const add = (t: Task) => tasks.push(t);
@ -100,11 +99,8 @@ if (quick) {
add({ name: 'desktop build', cmd: ['bunx', 'vite', 'build', '--logLevel', 'warn'], cwd: join(ROOT, 'apps/desktop') });
// the release bundle must not carry the dev fixture mode
add({ name: 'desktop bundle check', cmd: ['bun', 'test', './apps/desktop/tests/webview.test.ts'], after: ['desktop build'] });
// the built window boots (release CSP, Tauri's frozen Object.prototype, mocked host + real sidecar) on an empty, a
// D1 (folders gone) and a full D3 saved state, through every screen: no uncaught error, never an empty window
if (!deferred) add({ name: 'desktop boot check', cmd: ['bun', 'tools/desktop-boot-check.ts'], after: ['desktop build'] });
// the CLI compiled into the desktop sidecar (bun build --compile, scanned for this machine's paths): rebuilt when
// its inputs changed, with CI=full, or when missing; tauri's build script needs it for cargo test / clippy
// its inputs changed or when missing; tauri's build script needs it for cargo test / clippy
const hostBin = join(OUT_DIR, outName(hostTarget()));
const sidecarBuild = process.env.CI === 'full' || !existsSync(hostBin) || touches(/^(cli\/|tools\/build-sidecars\.ts$|package\.json$|bun\.lock$)/);
if (sidecarBuild) add({ name: 'desktop sidecar (host)', cmd: ['bun', 'tools/build-sidecars.ts', '--host'] });
@ -116,14 +112,6 @@ if (quick) {
}
}
// The browser suites fall back to Google Chrome without playwright's own headless Chromium; Chrome's shutdown takes
// seconds to half a minute per browser, which makes those shards several times slower.
if (tasks.some(t => t.name === 'desktop boot check' || t.cmd.some(a => HEAVY.some(h => a.endsWith(h))))) try {
const { registry } = await import('playwright-core/lib/server/registry/index' as string);
const exe = registry.findExecutable('chromium-headless-shell')?.executablePath('javascript') as string | undefined;
if (exe && !existsSync(exe)) console.log(`ci: playwright's headless Chromium is not installed (${exe.replace(homedir(), '~')}): the browser tests use Google Chrome, which is much slower to close. Install it once: bunx playwright install chromium-headless-shell`);
} catch { /* playwright internals moved: no hint */ }
// ---- runner ----
interface Run { task: Task; start: number; end?: number; code?: number; proc?: ReturnType<typeof Bun.spawn> }
@ -199,6 +187,5 @@ for (const r of [...runs.values()].sort((a, b) => a.start - b.start)) {
}
for (const t of pending) console.log(` ${t.name.padEnd(width)} - not started`);
if (retried.length) console.log(`\nretried under load (${retried.length}; each timed out once while load ÷ cores was above 2, then ran again):\n${retried.map(r => ` ${r}`).join('\n')}`);
if (deferred) console.log(`\nci: browser suites deferred to Forgejo CI (load ${loadavg()[0]!.toFixed(0)}); check its run on main`);
if (failed) { console.error(`\nci: ${failed} failed`); process.exit(1); }
console.log(`\n${quick ? 'ci:quick' : 'ci'}: all green`);