Summary
TinyPen's test suite is roughly 40% the size and depth of its sister project TinyNode. The Jest → node:test migration in #47 is complete and clean, but it did not bring over the route-level behavioral tests that TinyNode has. The two repos are meant to be kin; the testing harness should be kin too.
Coverage gap
| Subject |
TinyNode |
TinyPen |
Status |
create.test.js |
200 lines |
— |
Missing |
delete.test.js |
171 lines |
— |
Missing |
overwrite.test.js |
247 lines |
— |
Missing |
query.test.js |
178 lines |
— |
Missing |
update.test.js |
182 lines |
— |
Missing |
rest.test.js (verifyJsonContentType) |
31 lines |
0 lines |
Missing |
mount.test.js (HTTP-driven via supertest) |
73 lines |
97 lines, but stack-inspection only |
Weak |
tokens.test.js |
158 |
172 ✓ |
At parity |
rerum.test.js |
89 |
88 ✓ |
At parity |
openapi_sync_artifacts.test.js |
44 |
77 ✓ |
At parity (or stronger) |
| Total |
~1616 |
~654 |
~40% |
Concrete blind spots (mutation-verified)
These code mutations in routes/ pass the current TinyPen suite. They would fail TinyNode's:
routes/create.js:50 changing res.status(201) to res.status(200) — the contract declares 201 but nothing verifies it on the wire.
routes/delete.js:38 changing res.status(204) to res.status(200) — same.
routes/create.js:13 removing the _id = req.body.id.split('/').pop() extraction — nothing verifies the upstream body shape.
routes/overwrite.js:52-58 short-circuiting the 409 branch so conflicts are mapped to 502 — the conflict-passthrough contract is undocumented in tests.
app.js:99 swapping app.use('/create', createRouter) to app.use('/create', deleteRouter) — mount.test.js's stack-inspection accepts it (path matcher still matches); only an HTTP-driven request would notice.
rest.js:17-31 (hasMultipleContentTypes) — this is the MIME-smuggling detector. Its own docstring enumerates 8 attack patterns. Zero of them are tested. Mutating the function to return false passes the suite.
Root cause
The Jest → node:test migration in #47 also removed supertest as a dev dependency (commit c38ad90). TinyNode's route tests are all supertest-driven against a minimal Express tester app. Without supertest, the same patterns can't be ported one-for-one.
Proposed work
- Re-add
supertest to devDependencies. It's a peer-of-express testing utility with no runtime impact and TinyNode is already using it on the same Express 5 stack.
- Port the five route test files from TinyNode (
create, delete, overwrite, query, update). They are already in node:test + assert form. The only TinyPen-specific adaptations are:
/create _id extraction from req.body.id
/overwrite If-Overwritten-Version header passthrough and 409 conflict-body JSON response
- Add a
rest_content_type.test.js (or expand rest.test.js) covering all 8 MIME-smuggling cases documented in rest.js:1-13.
- Replace
mount.test.js with an HTTP-driven version following TinyNode's pattern (or delete it once the route-level tests cover registration implicitly).
- Walk through
__tests__/*.testcases.md and convert documented behaviors into real it(...) blocks. Delete or significantly trim the Markdown punch lists once their cases have a real test home.
Acceptance criteria
__tests__/ total line count is roughly at parity with TinyNode (~1500+ lines).
- Each of the six route-level mutations listed above causes at least one test to fail.
npm test continues to be c8 --reporter=… node --test — no Jest, no global mocks.
- All sync workflows continue to pass.
Context
Surfaced during the #47 static review. Out-of-scope for that PR by agreement; tracked here.
Summary
TinyPen's test suite is roughly 40% the size and depth of its sister project TinyNode. The Jest →
node:testmigration in #47 is complete and clean, but it did not bring over the route-level behavioral tests that TinyNode has. The two repos are meant to be kin; the testing harness should be kin too.Coverage gap
create.test.jsdelete.test.jsoverwrite.test.jsquery.test.jsupdate.test.jsrest.test.js(verifyJsonContentType)mount.test.js(HTTP-driven via supertest)tokens.test.jsrerum.test.jsopenapi_sync_artifacts.test.jsConcrete blind spots (mutation-verified)
These code mutations in
routes/pass the current TinyPen suite. They would fail TinyNode's:routes/create.js:50changingres.status(201)tores.status(200)— the contract declares201but nothing verifies it on the wire.routes/delete.js:38changingres.status(204)tores.status(200)— same.routes/create.js:13removing the_id = req.body.id.split('/').pop()extraction — nothing verifies the upstream body shape.routes/overwrite.js:52-58short-circuiting the409branch so conflicts are mapped to502— the conflict-passthrough contract is undocumented in tests.app.js:99swappingapp.use('/create', createRouter)toapp.use('/create', deleteRouter)—mount.test.js's stack-inspection accepts it (path matcher still matches); only an HTTP-driven request would notice.rest.js:17-31(hasMultipleContentTypes) — this is the MIME-smuggling detector. Its own docstring enumerates 8 attack patterns. Zero of them are tested. Mutating the function toreturn falsepasses the suite.Root cause
The Jest →
node:testmigration in #47 also removedsupertestas a dev dependency (commitc38ad90). TinyNode's route tests are allsupertest-driven against a minimal Express tester app. Withoutsupertest, the same patterns can't be ported one-for-one.Proposed work
supertesttodevDependencies. It's a peer-of-expresstesting utility with no runtime impact and TinyNode is already using it on the same Express 5 stack.create,delete,overwrite,query,update). They are already innode:test + assertform. The only TinyPen-specific adaptations are:/create_idextraction fromreq.body.id/overwriteIf-Overwritten-Versionheader passthrough and409conflict-body JSON responserest_content_type.test.js(or expandrest.test.js) covering all 8 MIME-smuggling cases documented inrest.js:1-13.mount.test.jswith an HTTP-driven version following TinyNode's pattern (or delete it once the route-level tests cover registration implicitly).__tests__/*.testcases.mdand convert documented behaviors into realit(...)blocks. Delete or significantly trim the Markdown punch lists once their cases have a real test home.Acceptance criteria
__tests__/total line count is roughly at parity with TinyNode (~1500+ lines).npm testcontinues to bec8 --reporter=… node --test— no Jest, no global mocks.Context
Surfaced during the #47 static review. Out-of-scope for that PR by agreement; tracked here.