CodeVetter · Repo Unpack · Testing signals
electron/electron
Tests are Mocha specs in spec/ (api-*-spec.ts per module plus feature specs like asar/fuses/esm/crash) executed inside the built Electron binary — spec/index.js is literally run as the app's main script by script/spec-runner.js. Assertions use chai with dirty-chai and chai-as-promised; CI shards by per-file weights and records timing artifacts. Coverage is strongest on the JS-facing API surface; C++ internals are exercised indirectly, and there are no unit tests for shell/ outside the in-binary specs.
- npm test → script/spec-runner.js, which installs spec node_modules when the spec hash changed, generates electron.d.ts if missing, then launches the built Electron binary with spec/ as the app.
- spec/index.js is the test app's main: it registers privileged test schemes ('app', 'zoom', 'sw', 'cors', 'stream', ...), appends js-flags=--expose_gc and enable-features switches, loads Mocha with forbidOnly+3 retries on CI, TAP reporter by default (MOCHA_REPORTER/MOCHA_MULTI_REPORTERS override), 30s default timeout (MOCHA_TIMEOUT).
- Spec discovery picks files matching /-spec\.[tj]s$/ under spec/ via get-files.ts; MOCHA_GREP/MOCHA_INVERT and --files allow sharding; npm_config_match filters by name.
- disabled-tests.json is a title-exact skip list enforced by a mocha beforeEach root hook; per-suite beforeAll kills orphaned Electron processes (pgrep/wmic/proc scan filtered by execPath and PID-descent) between spec files.
- On CI the runner writes spec/artifacts/spec-timings.json (per-file wall time keyed by platform/arch/mas/sanitizer) consumed by script/gen-spec-weights.js; script/spec-weights.json already holds per-file shard weights.
- spec/package.json pins the harness deps — mocha ^10, chai + chai-as-promised + dirty-chai, mocha-junit-reporter, ws, busboy — plus @electron-ci/* native-addon fixtures (dialog-helper, echo, is-valid-window, object-wrap, uv-dlopen, virtual-display) and @electron/fuses.
- ELECTRON_REQUIRE_TESTING_BINDINGS=1 makes the run fail early if testing bindings are unavailable, distinguishing testing builds from release binaries.
- electron.d.ts is generated from docs API markdown (create-api-json.mjs + @electron/typescript-definitions) and validated by a smoke test: spec/ts-smoke/runner.js compiles fixture TS against the definitions; the same generation runs as a docs lint step.
- Fixtures cover asar archives (test.asar, recursive-asar), crash-cases, devtools-extensions, native-addon builds, ESM variants and webview pages under spec/fixtures; helper modules live in spec/lib (http-server-helpers, codesign-helpers, window-helpers, ...).
- Linting is a first-class gate: npm run lint chains script/lint.js (oxlint for JS/TS, cpplint-style for C++/ObjC, python, gn), oxfmt format check, clang-format on shell/, and a docs pipeline that lints code blocks in markdown and validates api-history YAML blocks against docs/api-history.schema.json.
- CI splits work across pipeline workflows: pipeline-segment-electron-build.yml, pipeline-segment-electron-test.yml (plus a -64k variant), pipeline-electron-lint.yml, apply-patches.yml, and per-OS publish workflows (linux/macos/windows-publish.yml); audit workflows publish findings as an 'audit-results.md' artifact.
- default_app/ has no dedicated spec file — its CLI behaviors (REPL, --version, package loading) are only covered indirectly through specs that launch Electron with app paths; the argument parser itself is untested in isolation. (inferred)
- spec/CLAUDE.md documents real test-authoring hazards: expect() inside stream/event listeners becomes an uncaught exception that kills the runner silently, utilityProcess drops stdio listeners at 'exit', and children must be registered with deferKillUtilityProcess — evidence that flaky child-process specs have been a recurring problem.