Skip to content

test(showcase): put e2e/global-setup.ts in a tsc program and fix what that reads - #8178

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-8062-showcase-global-setup-typecheck
Aug 12, 2026
Merged

test(showcase): put e2e/global-setup.ts in a tsc program and fix what that reads#8178
hotlong merged 1 commit into
mainfrom
claude/issue-8062-showcase-global-setup-typecheck

Conversation

@hotlong

Copy link
Copy Markdown
Contributor

Fixes#8062

examples/app-showcase/e2e/global-setup.ts — the fixture that authenticates the
whole smoke run — was read by no tsc program at all. The package include was
e2e + /**/*.spec.ts, and the coverage gate counts test files, so nothing
had an opinion on it. This puts it in a program and fixes what that program
then reads.

Re-measurement first (the card's numbers were taken at 3373a29)

Every number in the issue predates PR #8061 landing. Re-measured on
origin/main @ 7cfe7ad in a clean worktree, by widening the package
include to the wholesale e2e + /**/* and running tsc --noEmit:

e2e/global-setup.ts(2,10): error TS2305: Module '"node:fs"' has no exported member 'mkdirSync'.
e2e/global-setup.ts(2,21): error TS2724: '"node:fs"' has no exported member named 'writeFileSync'. Did you mean 'readFileSync'?
e2e/global-setup.ts(3,25): error TS2591: Cannot find name 'node:path'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.
e2e/global-setup.ts(11,21): error TS2339: Property 'env' does not exist on type '{ cwd(): string; }'.
e2e/global-setup.ts(12,23): error TS2339: Property 'env' does not exist on type '{ cwd(): string; }'.
e2e/global-setup.ts(13,26): error TS2339: Property 'env' does not exist on type '{ cwd(): string; }'.

The card reproduces exactly — same six errors, same codes, same lines, same
3+3 split. The baseline (include as on main) is green, so all six are the
widening's, none pre-existing.

What the measurement said beyond the card

A. The widened glob adds exactly one file. Diffing tsc --listFiles
between the narrow and wholesale globs, package-local files only, the entire
delta is e2e/global-setup.ts. (e2e/.gitignore is not a TS file; the tree
holds nothing else.) The card's blast radius holds.

B. The file-local declare const process idiom is still current. Verified
at all three sites the card names — objectstack.config.ts:55,
src/system/self-url.ts:47, test/connector-self-url.test.ts:38 — plus the
three specs #8061 applied it to. Unchanged, so global-setup.ts gets the same
one-liner rather than a new convention.

C. Partly falsified, and it changed a decision. The card reads the shim
gaps as "no @types/node". @types/node@26.1.2is installed at the
workspace root and physically resolvable from this package. It is simply not in
the program — nothing names it in compilerOptions.types. Probing with
types: ["node"] added:

  • the three node-builtin errors go away — so @types/nodewould fix that half;
  • the three process.env errors stay, because the shim's global
    declare const process: { cwd(): string } shadows the real one.

So "just add @types/node" is not the smaller repair: it fixes half the errors,
forces the shim's process global out, and widens the package's type surface —
which two separate comments in this package (objectstack.config.ts,
node-shim.d.ts) record as a deliberate choice. Kept the narrow shim and
extended it; the reasoning is now written into types/node-shim.d.ts so the
next author does not have to re-derive it.

The open question, answered: the shim moves to types/

test/node-shim.d.tstypes/node-shim.d.ts. Measured, not assumed: the shim
is consumed by both trees — test/ for existsSync/readFileSync/
readdirSync and the process.cwd() global, e2e/ for mkdirSync/
writeFileSync/dirname plus that same global (the three specs already
reference it by name in their comments today). Under the test/ name a
narrowing made for the test layer would break the e2e program with nothing in
the path to warn the author. Two callers, both real, so this is not an
abstraction built for one. The four stale path references in comments are
updated with it; a .d.ts is type-only, so the vitest layer is untouched
(re-run below).

playwright.config.ts — a deliberate, measured scope call

It was dark in exactly the same way (three process.env reads, in no tsc
program) and it configures the very smoke lane global-setup.ts authenticates.
Measured separately: naming it in include adds only those three errors and
pulls in no new types, so it takes the identical one-liner. Included.

vitest.config.ts is dark too and is deliberately left out: measured, its
vitest/config import transitively pulls the whole of @types/node into the
program — the exact type-surface widening this package is built to avoid. That
is a separate decision, not a rider on this one.

Runtime equivalence — argued, then proved

test:smoke is non-blocking nightly, so a repair that satisfies tsc while
changing runtime behaviour would be silent. Every change here is type-level:
declare statements erase at emit and .d.ts files emit nothing. Proof rather
than assertion — compiled the pre- and post-change sources and diffed the
emitted JS:

### global-setup.ts emitted JS: old vs new
BYTE-IDENTICAL
0ed6c5bed89c7206b37b9cf09ef72096ab818f11ae574c802cd657aefa5982de
0ed6c5bed89c7206b37b9cf09ef72096ab818f11ae574c802cd657aefa5982de
### playwright.config.ts emitted JS: old vs new
BYTE-IDENTICAL
11c4148dbe79eed49a0679d1adb5226cdd9bf3881ff566e293c57539a60bda0a
11c4148dbe79eed49a0679d1adb5226cdd9bf3881ff566e293c57539a60bda0a

This required care: the first attempt put the declare between the file's
leading block comment and the first statement, which detached the comment and
dropped it from the emit. Declaring it above that comment restores
byte-identity, and each site carries a note saying so. The sign-in call, the
header read, the storage-state write and the env precedence are untouched.

⚠️ The smoke suite itself was not run here — it needs a real backend on
:3000 and this container has parallel agents' work on it. The claim above is a
byte-identity proof of the emitted module, not an execution of the suite.

Verification

  • pnpm --filter @objectstack/example-showcase typecheck → exit 0, and
    --listFiles confirms e2e/global-setup.ts, playwright.config.ts and
    types/node-shim.d.ts are all in the program, with @types/node still absent
    (0 files) — the file is genuinely read, not merely error-free.
  • pnpm --filter @objectstack/example-showcase test20 files, 193 tests
    passed
    , before and after the shim move.
  • eslint over every touched path → exit 0. pnpm check:nul-bytes → OK (7422
    files). pnpm check:type-check-coverage → OK.
  • Reverse verification, direction predicted before running: restore the
    pre-fix global-setup.ts and shim while keeping the widened glob → exactly
    the six errors above, red
    ; restore from the commit → green, git status
    clean.

pnpm check:type-check-debt could not be run locally: --re-measure
refuses without the full package closure built, naming
@objectstack/service-knowledge as unbuilt here, and the script is explicit
that measuring anyway would record a different world. CI builds that closure
first. The diff cannot move a ledger number in any case — this package left
TEST_DEBT in #7923, and the one DEBT entry that tracks showcase files
(@objectstack/spec-monorepo, 4 of its 80) counts files under
examples/app-showcase/src, which this PR does not touch.

Note for the PM, not changed here

scripts/check-type-check-coverage.mjs (~line 1410) uses this exact file as its
worked example of why hidden tests are added one at a time — "e2e/**/* would
have pulled e2e/global-setup.ts into app-showcase's measurement and billed the
test layer 6 errors". The mechanism rationale stays correct, but the illustration
is now historical: the file is in the real program with zero errors. scripts/
was fenced off this card, so it is left untouched and flagged instead.

Related: #7923 · #8061 · #7353 · #7312 · #5286 — none addressed here.


Generated by Claude Code

… that reads
The package include was `e2e/**/*.spec.ts`, so `e2e/global-setup.ts` — the
fixture that authenticates the whole smoke run — was read by no tsc program at
all, and the coverage gate counts test files so nothing else covered it either.
Widen the glob to the wholesale `e2e/**/*` and fix the 6 errors that exposes at
their source rather than excluding them:
- file-local `declare const process` in global-setup.ts, the idiom already used
by objectstack.config.ts, src/system/self-url.ts and the three e2e specs (3x
TS2339);
- `mkdirSync`/`writeFileSync` on the `node:fs` shim and a minimal `node:path`
module declaration (TS2305 / TS2724 / TS2591).
The shim moves `test/node-shim.d.ts` -> `types/node-shim.d.ts`: both trees
depend on it now, and under the old name a narrowing for the test layer would
have broken the e2e program with nothing in the path to warn the author.
`playwright.config.ts` was dark in exactly the same way and takes the same
one-liner. `vitest.config.ts` is deliberately left out — its `vitest/config`
import transitively pulls in the whole of `@types/node`, the type surface this
package is deliberately without.
All changes are type-level (`declare` statements erase at emit, `.d.ts` files
emit nothing), so the smoke run's runtime behaviour is unchanged.
@vercel

vercelBot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 12, 2026 6:45pm

Request Review

@hotlonghotlong added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 12, 2026 — with Claude
@hotlong
hotlong marked this pull request as ready for review August 12, 2026 19:17
@hotlong
hotlong added this pull request to the merge queueAug 12, 2026
Merged via the queue into main with commit 9172fa2Aug 12, 2026
28 checks passed
@hotlong
hotlong deleted the claude/issue-8062-showcase-global-setup-typecheck branch August 12, 2026 19:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gateteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] examples/app-showcase/e2e/global-setup.ts is read by no tsc program — 6 errors, 3 of them holes in test/node-shim.d.ts

2 participants

@hotlong@claude