Skip to content

Enforce plain node:assert test style: migrate node:assert/strict usages + add oxlint no-restricted-imports #1555

Description

@heskew

Problem

AGENTS.md (test-style section, ~line 195) makes plain node:assert the house style for new tests and explicitly rules out node:assert/strict ("strict mode's deep-equality and coercion rules cause more friction and surprising failures than they prevent"). But the convention isn't enforced and the codebase overwhelmingly violates it:

  • 208 test files import node:assert/strict vs 29 on plain node:assert (unitTests + integrationTests).
  • Even the "target-shape" dirs AGENTS.md names are mostly /strict: unitTests/config 11, unitTests/resources 25, unitTests/components 48.

The only thing catching new /strict usage today is the AI reviewer, which raises it as a non-blocking suggestion on every affected PR — recurring noise that never gets systematically resolved (see e.g. PR #1106).

Goal

Make the documented convention deterministic — caught by CI's linter before review — so the reviewer nit disappears and new code can't regress.

The rule to standardize on: default to require('node:assert'); never import node:assert/strict; when a specific assertion genuinely needs strict/deep-strict semantics, call assert.strictEqual / assert.deepStrictEqual explicitly (both available from plain node:assert). This keeps strictness opt-in and visible at the call site rather than silently applied to every assert.equal by the import.

Plan

  1. Migrate existing node:assert/strict imports → node:assert across test files. This is mechanical and safe: strict→loose only ever weakens an assertion, so no currently-green test can turn red. (Optionally, spot-convert assertions that should stay strict to explicit strictEqual/deepStrictEqual.) Consider staging by dir — the target-shape dirs (config/resources/components, ~84 files) first.
  2. Enforce with oxlint no-restricted-imports so regressions fail runLinter:
    "no-restricted-imports": ["error", { "paths": [
      { "name": "node:assert/strict", "message": "Use plain node:assert; call assert.strictEqual/deepStrictEqual for strict checks (AGENTS.md house style)." },
      { "name": "assert/strict" }
    ]}]
    Can be scoped to unitTests/{config,resources,components}/** first via oxlint overrides, then widened as legacy dirs are migrated.

Notes

  • oxlint supports no-restricted-imports (verified against the installed version's rule list).
  • Enabling the rule repo-wide before migrating will fail lint on the 208 existing files — hence migrate first (or scope via overrides).
  • Older unitTests/security/* and unitTests/utility/* are not the target shape (they also use sinon/rewire per AGENTS.md); their imports are still safe to migrate but can be de-prioritized.
  • Pattern to follow: PR feat(models): add openaiStream() OpenAI-compatible SSE formatter #1106 already switched the two openaiStream test files to plain node:assert — use as the reference for the mechanical change.

Acceptance

  • No node:assert/strict imports remain in the enforced scope.
  • oxlint no-restricted-imports rule added and green in CI.
  • AGENTS.md test-style note updated to point at the lint rule as the enforcement mechanism.

🤖 Generated with Claude Code

Activity

  1. self-assigned this
    on Jul 2, 2026
  2. heskew commented on Jul 2, 2026

    @heskew
    ContributorAuthor

    Correction to the migration plan above: the claim "strict→loose only ever weakens an assertion, so no green test can turn red" is wrong for negative assertions.

    node:assert/strict makes notEqual===notStrictEqual (!==) and notDeepEqual===notDeepStrictEqual. Swapping to plain node:assert makes them loose (!=), so e.g. assert.notEqual(x, undefined) where x is null flips from pass (null !== undefined) to throw (null != undefined is false). This deterministically broke integrationTests/apiTests/northwind.test.mjs (LEFT OUTER JOIN rows have null columns; notEqual(row[key], undefined) at :4963/:4983) — red on all 4 runtimes in PR #1558.

    Corrected rule for this migration: positive equal/deepEqual only weaken silently (accepted per house style), but negative notEqual/notDeepEqual can flip pass→fail — convert those call sites to notStrictEqual/notDeepStrictEqual (identical in both modules; the lint rule only bans the node:assert/strict import path). 17 files / 37 sites are affected; being fixed in PR #1558.

    Worth baking into the AGENTS.md note and the lint enforcement so future migrations don't reintroduce it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

Priority

None yet

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions