Skip to content
This repository was archived by the owner on Aug 7, 2026. It is now read-only.

ci: bring test/ into the typecheck - #127

Merged
rubenhensen merged 3 commits into
masterfrom
ci/typecheck-test-dir-126
Jul 27, 2026
Merged

ci: bring test/ into the typecheck#127
rubenhensen merged 3 commits into
masterfrom
ci/typecheck-test-dir-126

Conversation

@dobby-coder

@dobby-coder dobby-coder Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Issue #126 has two halves. One lands here; the other needs a human.

In this PR

tsconfig.json excluded test/, so tsc --noEmit never looked at the five node:test suites. Dropping that exclusion pulls in two more options:

allowImportingTsExtensions, because the suites import source modules as ../src/lib/foo.ts and the extension is mandatory under node --experimental-strip-types. And noEmit, which TypeScript requires whenever allowImportingTsExtensions is set. Nothing in this repo emits through tsc anyway, webpack and Babel do the build.

@types/node goes from a transitive dep of the office-addin-* chain to a declared devDependency. The suites import node:test and node:assert/strict; the typecheck resolves those only through it, so it should not depend on whatever the next dep-scan sweep does to that chain.

Before and after, with a deliberate type error appended to test/render-body.test.ts:

# on master
$ npx tsc --noEmit; echo $?
0

# on this branch
$ npx tsc --noEmit; echo $?
test/render-body.test.ts(129,7): error TS2322: Type 'string' is not assignable to type 'number'.
test/render-body.test.ts(129,33): error TS2554: Expected 2 arguments, but got 1.
2

The suites themselves needed no changes; they already typecheck clean.

Not in this PR

The npm test job. dobby-coder[bot] has no workflows permission, and the remote rejects the push:

! [remote rejected] (refusing to allow a GitHub App to create or update
  workflow `.github/workflows/ci.yml` without `workflows` permission)

The patch is in a comment below. Please leave #126 open until someone applies it, which is why this PR says Part of rather than Closes.

--experimental-strip-types needs Node 22.6 or newer, so the new job cannot reuse the check job's Node 20. The patch pins it to 22 and leaves check untouched.

Verified locally on Node 22.23.1

Every step the check job runs, plus the suite:

  • npm ci, clean
  • npx eslint -c eslint.config.mjs --max-warnings=0 "src/**/*.{ts,js}", 0
  • npx prettier --check "src/**/*.{ts,js}", 0
  • npx tsc --noEmit, 0 (now over src/ and test/)
  • npm run build, 0, with the pre-existing entrypoint size warnings on taskpane.js and yivi-dialog.js
  • npm run validate, manifest valid
  • npm test, 39 pass, 0 fail, 0 cancelled, exit 0

CLAUDE.md claimed there were no automated tests and that test/ sat in the tsconfig exclude. Both updated.

Part of #126
Part of encryption4all/postguard#247 (workstream A)

The five node:test suites under test/ were excluded from tsconfig.json, so
tsc --noEmit never looked at them. Drop the exclusion.

The suites import source modules with an explicit .ts extension (required by
node --experimental-strip-types), which needs allowImportingTsExtensions, and
that option in turn requires noEmit. Nothing emits through tsc here anyway —
webpack + Babel do the build.

@types/node becomes a declared devDependency: the suites import node:test and
node:assert/strict, which the typecheck can only resolve through it.

Part of #126
@dobby-coder
dobby-coder Bot requested a review from rubenhensen July 27, 2026 07:56
@dobby-coder

dobby-coder Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Workflow patch for a maintainer to apply

dobby-coder[bot] has no workflows permission, so this half of #126 cannot be pushed. Verified against the remote on a throwaway branch:

! [remote rejected] (refusing to allow a GitHub App to create or update
  workflow `.github/workflows/ci.yml` without `workflows` permission)

Add this job to .github/workflows/ci.yml, between check and nginx:

  test:
    name: Unit tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      # node --test --experimental-strip-types needs Node >= 22.6, so this job
      # cannot share the check job's Node 20.
      - uses: actions/setup-node@v5
        with:
          node-version: 22
          cache: npm

      - run: npm ci

      - name: Unit tests (node:test)
        run: npm test

As a unified diff against master, if you prefer git apply:

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 559ed48..b2aff24 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -38,6 +38,24 @@ jobs:
       - name: Validate manifest
         run: npm run validate
 
+  test:
+    name: Unit tests
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v6
+
+      # node --test --experimental-strip-types needs Node >= 22.6, so this job
+      # cannot share the check job's Node 20.
+      - uses: actions/setup-node@v5
+        with:
+          node-version: 22
+          cache: npm
+
+      - run: npm ci
+
+      - name: Unit tests (node:test)
+        run: npm test
+
   nginx:
     name: nginx config test
     runs-on: ubuntu-latest

Why Node 22 and not the check job's Node 20: type stripping arrived in 22.6, and npm test passes --experimental-strip-types. On Node 20 the flag is rejected before any test runs. Bumping check to 22 as well would work too, but that is a bigger call than this issue asked for, so the patch leaves it alone.

The npm test line in CLAUDE.md's command list already documents the Node requirement. If you want the CI bullet in the agent notes to match, - CI (\ci.yml`) runs ...around line 105 can gainnpm test` when you apply this.

…a transitive reference

The `types` array switches off automatic inclusion of every `@types/*`
package, so declaring `@types/node` in devDependencies did not put it in
the program. The only thing resolving `node:test` / `node:assert/strict`
was a `/// <reference types="node" />` inside the office-addin-dev-certs
and undici-types declarations, reached via webpack.config.js. Any
unrelated dep bump could have dropped that link and broken CI.

    # test/ in isolation, before
    $ npx tsc -p tsconfig.testonly.json --noEmit
    test/encryption-flow.test.ts(13,22): error TS2591: Cannot find name 'node:test'.
    ... 10 errors across all five suites

    # after
    $ npx tsc -p tsconfig.testonly.json --noEmit ; echo $?
    0
    $ npx tsc --noEmit ; echo $?
    0

Also drop `noEmitOnError`, `outDir` and `sourceMap`, which `noEmit`
makes inert. The only tsc invocation in the repo is `npx tsc --noEmit`
in ci.yml. Verified tsc still exits 2 on a type error in either src/ or
test/ without noEmitOnError, and writes no lib/.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@dobby-coder dobby-coder Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: approve

Rule sweep plus the handed-forward review findings. One blocking issue, confirmed and fixed on the branch in 893016b; CI green on the new HEAD.

The blocker (fixed, not looped)

"types": ["office-js", "office-runtime"] switches off automatic inclusion of every other @types/* package, so declaring @types/node in devDependencies did not actually put it in the program. Reproduced against 72568f2 with a tsconfig.testonly.json that extends tsconfig.json and includes only test/**/*.ts:

$ npx tsc -p tsconfig.testonly.json --noEmit
test/encryption-flow.test.ts(13,22): error TS2591: Cannot find name 'node:test'.
test/encryption-flow.test.ts(14,20): error TS2591: Cannot find name 'node:assert/strict'.
... 10 errors across all five suites
exit=2

--explainFiles names the real carriers:

node_modules/@types/node/index.d.ts
  Type library referenced via 'node' from 'node_modules/office-addin-dev-certs/lib/httpsServerOptions.d.ts'
  Type library referenced via 'node' from 'node_modules/undici-types/formdata.d.ts'

Both reached through webpack.config.js, which is in the program via allowJs. So the typecheck was passing on a /// <reference types="node" /> buried in an unrelated dependency's declarations. Latent rather than live, but it would have surfaced as Cannot find name 'process' in src/lib/pkg-client.ts and src/taskpane/settings-view.ts alongside the five suites on the next dep bump that moved that chain.

Fixed by adding "node" to the array. Verified both directions: test/ in isolation exits 0, and the full program exits 0 with no dom/node global collisions.

Also folded in

noEmit made noEmitOnError, outDir: "lib" and sourceMap inert. Confirmed the only tsc invocation in the repo is npx tsc --noEmit at ci.yml:33 and that lib/ is never produced, so all three are gone. Checked the one thing that could regress: without noEmitOnError, tsc still exits 2 on a type error in either src/ or test/, and writes no lib/. CI's failure behaviour is unchanged.

CLAUDE.md:111 recorded the incomplete rationale as fact ("@types/node is a declared devDependency ... without it the typecheck cannot resolve them" — true, but it read as a guarantee that was not there). Rewritten to say both the devDependency and the types entry are needed, and why.

Non-blocking, out of scope

test/render-body.test.ts and test/verified-sender.test.ts have Prettier violations that also fail on master:

$ git checkout master && npx prettier --check "test/**/*.ts"
[warn] test/render-body.test.ts
[warn] test/verified-sender.test.ts

Pre-existing, not introduced here, and invisible to CI because the lint and prettier steps are scoped to src/**/*.{ts,js} — which CLAUDE.md:107 now documents accurately. This PR closes the typecheck half of test/ coverage; the lint/format half is still open. Better as a follow-up than a change to this diff.

Rule sweep

Checked the rules that apply to a TypeScript build-config diff. All clean:

  • Conventional-commit PR title — pr-title.yml is present on this repo and the check passes.
  • Part of #126 is deliberate and correct: the npm test job needs the workflows permission the bot does not have, so it ships as a patch in a comment. closingIssuesReferences verified empty via GraphQL, so merging will not orphan the issue.
  • Cross-repo reference to postguard#247 uses the full markdown link form.
  • Reviewer assigned (rubenhensen).
  • @types/node is genuinely consumed rather than dead weight, now that types lists it.
  • npm test: 39 pass, 0 fail, 0 cancelled, exit 0 — checked for cancelled tests, not just # fail 0.

The two em-dash flags the sweep raised on CLAUDE.md were dropped: master already carries 28 em-dashes in 2200 words and every bullet in that command list is written command — description. Matching the file is right; making the new line inconsistent with its neighbours would not be.

Full local gate on 893016b: eslint 0, prettier 0, tsc --noEmit 0, npm test exit 0, npm run build 0 (pre-existing entrypoint size warnings only), npm run validate valid.

Comment thread tsconfig.json
"target": "es2020",
"lib": ["es2022", "dom"],
"types": ["office-js", "office-runtime"]
"types": ["office-js", "office-runtime", "node"]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking issue found here and fixed on the branch in 893016b"node" added to the array.

Without it this line switched off automatic inclusion of every other @types/* package, @types/node included, so the @types/node devDependency this PR declares never reached the program. test/ typechecked only because webpack.config.js (in the program via allowJs) drags in dependency declarations that carry /// <reference types="node" />office-addin-dev-certs/lib/httpsServerOptions.d.ts and undici-types. Verified with --explainFiles; verified the fix with test/ in isolation (exit 0) and the full program (exit 0).

Comment thread CLAUDE.md

Those `.ts` import specifiers are why `tsconfig.json` sets `allowImportingTsExtensions` (and therefore `noEmit`, which the option requires). Nothing emits through `tsc` anyway, webpack + Babel do the build, so `outDir` / `sourceMap` / `noEmitOnError` are not set.

The suites import `node:test` / `node:assert/strict`, so `@types/node` is a declared devDependency and `node` is listed in the `types` compiler option. Both are needed: `types` is set explicitly, which switches off automatic inclusion of every `@types/*` package, so installing `@types/node` on its own does not put it in the program. Before `node` was added to that array the only thing pulling node types in was a `/// <reference types="node" />` deep inside the `office-addin-dev-certs` and `undici-types` declarations, reached through `webpack.config.js` (in the program via `allowJs`). That link would have broken on any unrelated dependency bump.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewritten in 893016b. The original wording ("@types/node is a declared devDependency ... without it the typecheck cannot resolve them") was true but read as a guarantee that was not there — the devDependency alone did not put node types in the program, because types is set explicitly. Recording both halves so the next person editing tsconfig.json does not drop the types entry and reintroduce the accidental transitive link.

@dobby-coder
dobby-coder Bot marked this pull request as ready for review July 27, 2026 08:13
@rubenhensen
rubenhensen merged commit b600aab into master Jul 27, 2026
4 checks passed
@rubenhensen
rubenhensen deleted the ci/typecheck-test-dir-126 branch July 27, 2026 13:08
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant