Skip to content

feat(lint): add bun:test expect-expect oxlint plugin#373

Merged
rhuanbarreto merged 2 commits into
mainfrom
claude/blissful-feynman-5abd24
May 28, 2026
Merged

feat(lint): add bun:test expect-expect oxlint plugin#373
rhuanbarreto merged 2 commits into
mainfrom
claude/blissful-feynman-5abd24

Conversation

@rhuanbarreto

Copy link
Copy Markdown
Contributor

Summary

Tests with no expect() calls silently pass and give false confidence. oxlint ships jest/expect-expect, but its Rust implementation only recognizes jest/vitest imports and silently ignores bun:test — so assertion-less tests accumulated over time (discovered in #352).

This PR adds a custom oxlint JS plugin that implements expect-expect for bun:test, wires it up, and fixes the violations it surfaces.

Closes #353.

What changed

File Change
lint/expect-expect.ts New custom oxlint JS plugin (rule bun-test/expect-expect). Plain TypeScript, runs natively under Bun — no build step.
.oxlintrc.json Register the plugin via jsPlugins; enable the rule (error) scoped to tests/**/*.test.ts.
tests/helpers/{telemetry,sentry,auth,credential-store-impl,platform,git}.test.ts Fix the 44 assertion-less smoke tests the rule surfaced.
.archgate/adrs/ARCH-005-testing-standards.md Document the new convention (Do's/Don'ts, Compliance, reviewer checklist).

How the rule works

Flags any runnable test() / it() call whose body contains no expect():

  • Handles test(), it(), test.only(...), test.skipIf(cond)(...), test.each(rows)(...), etc. — it resolves the leftmost callee identifier (test/it) through member/call chains.
  • Ignores test.skip and test.todo (intentional placeholders), per the rule's own guidance.
  • Does not double-flag the inner test.skipIf(cond) call (only the outermost invocation carrying the callback is checked).

Fixing the 44 violations

Rather than add tautological assertions, the implicit "does not throw" contract is made explicit:

  • Sync void calls → expect(() => fn()).not.toThrow()
  • Async void calls → await expect(promise).resolves.toBeUndefined()
  • The Windows-only placeholder in git.test.ts (which previously asserted nothing and even documented that it didn't) is turned into a real test by stubbing Bun.spawn/Bun.which so installGit() reaches its .rejects.toThrow path.

Reviewer notes

  • lint/ is intentionally outside tsconfig.json include and knip.json project, but is linted by oxlint --deny-warnings ., so the plugin file passes all oxlint rules itself.
  • The npm .oxlintrc.json jsPlugins feature loads the plugin top-level; the rule is enabled only in the tests/**/*.test.ts override.

Test plan

  • bun run lint — 0 errors (rule active; manually verified it fires on empty tests and ignores asserting/test.skip ones)
  • bun run typecheck / bun run build:check / bun run format:check
  • bun run test — 1212 pass, 0 fail
  • archgate check — 31/31 ADR rules pass

oxlint ships `jest/expect-expect`, but its Rust implementation only
recognizes `jest`/`vitest` imports and silently ignores `bun:test`, so
assertion-less tests passed silently and accumulated over time.

Adds a custom oxlint JS plugin (`lint/expect-expect.ts`, rule
`bun-test/expect-expect`) registered via `jsPlugins` in `.oxlintrc.json`
and scoped to `tests/**/*.test.ts`. It fails the build for any runnable
`test()`/`it()` (incl. `test.skipIf(...)()`, `test.each(...)()`) whose
body contains no `expect()` call, while ignoring `test.skip`/`test.todo`.

Also fixes the 44 pre-existing assertion-less smoke tests it surfaced by
making their implicit "does not throw" contracts explicit, and documents
the new convention in ARCH-005.

Closes #353

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented May 28, 2026

Copy link
Copy Markdown

Deploying archgate-cli with  Cloudflare Pages  Cloudflare Pages

Latest commit: 8b12e7a
Status: ✅  Deploy successful!
Preview URL: https://784c375a.archgate-cli.pages.dev
Branch Preview URL: https://claude-blissful-feynman-5abd.archgate-cli.pages.dev

View logs

…an-5abd24

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>

# Conflicts:
#	.archgate/adrs/ARCH-005-testing-standards.md
#	.claude/agent-memory/archgate-developer/MEMORY.md
@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage

Metric Value
Lines 90.2% (6568 / 7280)
Threshold 90% minimum — met
Platforms Linux + Windows

Full HTML report available in workflow artifacts.

Per-directory breakdown
Directory Coverage Lines
src/commands/ 88.1% 2069 / 2348
src/engine/ 93.1% 1209 / 1299
src/formats/ 100.0% 141 / 141
src/helpers/ 90.2% 3149 / 3492

@rhuanbarreto rhuanbarreto merged commit 1bda975 into main May 28, 2026
18 checks passed
@rhuanbarreto rhuanbarreto deleted the claude/blissful-feynman-5abd24 branch May 28, 2026 23:21
@archgatebot archgatebot Bot mentioned this pull request May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add oxlint config and custom expect-expect JS plugin for bun:test

1 participant