Type-check the e2e specs and packages/shared strictly, and collect the suite before it gates a deploy - #625
Conversation
…ugh one helper
The e2e specs gate production: a failed production E2E rolls production back. A spec that uses a host that is null on the environment it runs against (hosts.app, hosts.admin and hosts.testmap are null on production, and one or another on staging and the dev server) throws at module scope while Playwright collects the file, since test.skip stops the tests but not the file's own top-level code. That crashes the whole run, not the one spec. tsconfig.base.json turns strictNullChecks off, and the only guard was a comment beside each cast.
e2e/tsconfig.json now extends a new root tsconfig.strict.json, which turns strict, noImplicitAny and strictNullChecks on by name (the base sets the last two to false outright, which strict alone does not override). The specs compiled clean under it already.
What changes in them is how they reach a nullable host. app-surface paired a test.skip with an `as string` cast, live-map built `${TESTMAP}/sim` at module scope, and dashboard used `ADMIN!` assertions. The exported `hosts` now carries only the roles every environment has (api, map, dash); app, admin and testmap are reached through hostOrSkip(role, reason) alone, so a spec that reads one any other way does not compile. hostOrSkip skips the file, group or test it is called in where the role is null and returns an unroutable .invalid stand-in there, so it is safe at module scope and a spec's skip and host cannot disagree. It has to be called from the spec itself, since a shared module runs once and only its first importer would skip; its docstring says so. The config also refuses an E2E_ENV it has no hosts for, by name, where the old cast left the table undefined to fail later as a TypeError.
tsconfig.strict.json lists strict-probe.ts in its files, so every workspace that extends it compiles the probe: one line per setting that has to stay a type error, which fails tsc as an unused @ts-expect-error the day that setting stops applying.
Checked: tsc is clean; switching off any of the three flags fails it, and so does a nullable role read off hosts; hostOrSkip at module scope, even parsed as a URL, and inside a describe collects cleanly on every environment; app-surface passes against staging, and it, live-map and the dashboard's admin group skip on prod.
ClickUp 3.2 (123zgec4my9).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eploy A spec that throws at module scope while Playwright collects it takes the whole E2E run down, and the production E2E rolls production back when it fails. Nothing ran collection before a merge: CI's e2e entry typechecks the specs, and tsc sees only some of the ways a spec can throw there, such as a URL built at module scope from a value that parses on one environment and not on another. e2e's typecheck script now runs `playwright test --list` for staging, prod and local after tsc. Listing loads every spec as a run would, with no browser and no network, so a collection-time throw on any environment fails the typecheck on the pull request, through the npm script CI's web-build already runs, with no workflow change. The listing goes to /dev/null; Playwright reports a collection error on stderr, after a "collecting for <env>" line naming the environment. The environments are listed by name, and playwright.config.ts says so beside its table. A probe spec whose top level throws although tsc accepts it fails here; the suite as it stands collects 98 tests on each environment. ClickUp 3.2 (123zgec4my9). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
packages/shared is the request layer and the sign-in state every surface imports, and it compiled under the base config's strict: false, noImplicitAny: false and strictNullChecks: false like everything else. It already compiles clean with all three on, so its tsconfig.json now extends tsconfig.strict.json as e2e's does. That also compiles strict-probe.ts into it, so switching off any of the three fails its typecheck, which CI's web-build runs per workspace. The dashboard compiles shared's source as part of its own program, still under the base config, so this binds shared's typecheck and not the dashboard's view of it. The dashboard is the rest of 3.2 and is tracked on its own. The image's web stage now copies every root tsconfig rather than tsconfig.base.json alone. Vite's TypeScript transform follows shared's extends chain while it builds the console, and inside the image it could not resolve tsconfig.strict.json. docs/production-hardening.md's section on strict TypeScript says the two already compile strictly. ClickUp 3.2 (123zgec4my9). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e2e/specs/env.d.ts said only tsconfig.e2e.json compiles its directory. That file went when the browser suite got a workspace of its own (f3cb599); e2e/tsconfig.json compiles it now, and the comment's warning (keep this process global out of the browser program) is only actionable if it names the right file. ClickUp 2.8 (123zgec4mxy), its stale-reference item. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
|
Claude finished @jehanazad's task in 1m 48s —— View job Review complete
What's new since the last reviewA prior review on 2026-09-25 (commit - use: { ...devices["Desktop Chrome"] },
+ use: { ...devices["Desktop Chrome"], channel: "chrome" },That's already in Independent verificationI re-derived the key claims rather than just trusting the description:
No bugs found. This is a careful, well-scoped change, and the design (one helper that ties a nullable host's read to its own skip, a probe that fails compilation if any strict flag regresses) directly addresses the failure mode described in the PR ("Why" section) rather than papering over it. |
ClickUp: 3.2 Turn on strict TypeScript, starting with the e2e specs, e2e and packages/shared. Also 2.8's stale-reference item (123zgec4mxy). The dashboard half is 123zgec549h.
Why
The e2e specs gate production: a failed production E2E rolls production back. A spec that uses a host which is null on the environment it runs against throws while Playwright collects the file, because
test.skipstops the tests but not the file's top-level code, and that takes the whole run down. The base config hasstrictNullChecksoff, and the only guard was a comment beside eachas stringor!.What changes
tsconfig.strict.jsonturns onstrict,noImplicitAnyandstrictNullChecks, each by name: the base sets the last two to false outright, andstrictalone does not override that. e2e and packages/shared extend it. Both already compiled clean under it.strict-probe.tsis compiled into every workspace that extends the strict config, through that config'sfiles. It has one@ts-expect-errorper setting, so switching any setting off fails tsc.hostsnow carries only the roles every environment has (api,map,dash), typed as non-null strings.app,adminandtestmapare reachable only throughhostOrSkip(role, reason). It skips the file, group or test it is called in where the role is null, and there it returns an unroutable.invalidstand-in, so it is safe at module scope. A spec's skip and its host can no longer disagree. An unknownE2E_ENVnow fails by name.typecheckscript now also runsplaywright test --listfor staging, prod and local. tsc cannot see every way a spec throws during collection; listing can, with no browser and no network. CI's web-build already runs this script, so no workflow changes.COPY tsconfig*.json ./). Vite follows shared'sextendschain while it builds the console, and withtsconfig.base.jsonalone the image build failed to resolvetsconfig.strict.json.e2e/specs/env.d.tsnow names the config that compiles it.Checked
hosts, or a null in a non-null role.npm run typecheck -w e2eat the listing step.hostOrSkipat module scope (even parsed as a URL) and inside a describe collects cleanly on all three environments.COPYfails withfailed to resolve "extends", and the glob builds.test_dockerfiles.pyandtest_web_build_matrix.pypass, as do shared's unit tests and lint, and the dashboard build.Notes for review
collecting for <env>before any collection error.forbidOnly: !!process.env.CIin the same config. I checked that setting against this listing: withCI=true, a committedtest.onlythen fails the typecheck step on the PR, before merge. The two branches edit nearby lines ofe2e/playwright.config.ts, so whichever lands second needs a small rebase.FROMline, a few lines above this PR'sCOPYchange.🤖 Generated with Claude Code