Chisle
코딩 에이전트 플러그인, 20개 실시간 작업에서 기본 모델 52% 활용, 간결한 페르소나와 출력 압축 제공
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
Find tests that test nothing: no assertions, toBeNull without (), asserts that only run in catch, unawaited expects. JS, TS and Python.
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Find tests that test nothing.
A hollow test passes no matter what the code does: no assertions, expect(x).toBe(x), a mock of the very module under test, an expect inside a catch that never runs, a .resolves nobody awaits, assert (cond, "msg") in Python. Coverage goes green. The bug ships.
hollowtest reads your test files and flags those tests in seconds (7,400 NestJS tests in about 3 s), then (optionally) breaks your code on purpose to prove which behavior no test notices. They hide in well-known projects too: zod, NestJS, swr and requests all have a few (examples below). And when a coding agent writes your tests, the Claude Code plugin checks every test file it writes, on the spot.
npx hollowtest
Or try it in the browser, no install: jeffev.github.io/hollowtest.
examples/checkout/checkout.test.ts
warn checkout.test.ts:9 calculates the subtotal Only weak checks (toBeDefined): almost any result passes.
error checkout.test.ts:14 applies the HALF coupon Compares a value with itself: `expect(total).toEqual(total)`.
error checkout.test.ts:18 rejects an invalid quantity The assertions live in `catch`; if the code stops throwing, this test still passes.
error checkout.test.ts:27 loads the cart from the API `toHaveLength` is asynchronous but not awaited or returned: the test finishes before it runs.
warn checkout.test.ts:33 calls the API Only weak checks (toHaveBeenCalled): almost any result passes.
error checkout.test.ts:36 handles an empty cart No assertions: this test passes as long as nothing throws.
Test integrity 29/100 grade F
7 tests in 1 files · 4 hollow · 2 weak · 1 solid
That is the real output for examples/checkout: seven tests that all pass, and most of them would keep passing with the code broken.
Zero config. Works with Jest, Vitest, Mocha + Chai, node:test, ava, tap, Playwright, Testing Library, supertest in JS and TS, and with pytest and unittest in Python (it uses the Python on your machine; nothing to install). One dependency (the Babel parser).
| Rule | Severity | Example |
|---|---|---|
no-assertions | error | it('works', () => { total(cart) }) |
empty-test | error | it('handles errors', () => {}) |
tautology | error | expect(result).toBe(result), expect(true).toBe(true) |
bare-expect | error | expect(x) with no matcher, or expect(x).toBeNull without () |
swallowed-error | error | try { parse('') } catch (e) { expect(e.message)... } passes when nothing throws |
unawaited-assertion | error | expect(p).resolves.toBe(1) without await; expect inside an un-awaited .then() or setTimeout |
mocked-subject | error | cart.test.ts that calls vi.mock('./cart') |
focused-test | error | .only left in: every other test in the file silently stops running |
conditional-assertion | warn | every expect sits behind an if, or in a loop over a list that may be empty |
weak-assertions | warn | only toBeDefined(), toBeTruthy(), not.toBeNull(), bare toHaveBeenCalled() |
commented-assertion | warn | // expect(total).toBe(35) |
skipped-test | warn | it.skip(...), the classic way to "fix" a failing test |
snapshot-only | info | the only check is a snapshot that gets regenerated with -u |
Python gets the same rules, plus two of its own: assert (cond, "msg"), which is always true because a non-empty tuple is truthy, and except Exception: around assertions, which also catches AssertionError. @pytest.mark.skip and non-strict xfail count as skipped; Hypothesis @given property tests and benchmark tests are understood.
npx hollowtest --rules prints the list with explanations.
It is careful about false positives. It understands helpers that assert (local, or imported from your test utils), Testing Library queries that throw (getByText), the mocha done callback contract, expect.assertions(n), the let threw = false pattern, compile-time type tests (expectTypeOf, Expect<Equal<A, B>>, @ts-expect-error), loops over literal arrays, and "does not throw" smoke tests (reported as warnings, not errors).
npx hollowtest --fix # or --fix --dry-run to preview
fixed checkout.test.ts: add expect.assertions(1), await .toHaveLength
fixed focused.test.js: remove .only
fixed test_hollow.py: assert (cond, msg) -> assert cond, msg
It only rewrites what has one correct answer: expect(x).toBeNull gets its (), a floating .resolves/.rejects gets await (and the test becomes async), .only/fit/fdescribe are removed, a catch-only test gets expect.assertions(n), and Python's assert (cond, "msg") becomes assert cond, "msg". Some fixed tests will start failing. That is the point: they were hiding a failure. Tautologies, missing assertions and weak checks need a human (or your agent with the skill), because only you know the expected value.
Static rules find tests that look hollow. --mutate proves it. It changes your code the way a real bug would (> becomes >=, && becomes ||, a condition is forced to true, a return value becomes null), runs only the tests that import that file, and restores the file.
npx hollowtest --mutate pricing.js
여기까지가 README 앞부분입니다. 나머지는 원문에서 읽을 수 있습니다. README 전문 보기 ↗