Skip to content

Testing

Terminal window
pnpm verify # typecheck + lint + tests + build

Nothing ships without it. The test suite is hermetic: no network, no API keys, no database. Every adapter has a fake, so the whole thing runs offline in well under a minute.

Terminal window
pnpm test # once
pnpm test:watch # while working
Kind What it covers Style
Domain unit tests Every decision rule, exhaustively Plain values in, assertions out, no mocks
Loop tests The processing loop through injected fakes Assemble deps, run, assert outcome and stored state
Adapter tests One per adapter, with an injected transport and a fixture No network
API tests Routes through in-process injection, including auth and ownership No listening socket
Integration test One test against a real database Excluded from the gate; self-skips
Terminal window
MONGO_TEST_URI="mongodb://localhost:27017" pnpm test:integration
Change Tests it needs
A decision rule Direct unit tests and a loop test proving the effect end to end
A collector Happy path, malformed item, transport failure, trust resolution
A notifier Formatting per tier, destination override, throwing on failure
A route Success, validation failure, unauthenticated, wrong owner
Anything persisted A round-trip test through the real repository adapter

Assemble the dependencies from fakes, run, and assert both the returned outcome and what was persisted:

const repository = new InMemoryRepository([watch])
const notifier = new InMemoryNotifier('telegram')
const result = await runWatch(watch, {
collectors: { rss: new FakeCollector({ [FEED]: [item] }) },
evaluator: new FakeEvaluator(verdict),
notifiers: { telegram: notifier },
repository,
})
expect(result.outcome).toBe('notified')
expect(notifier.sent).toHaveLength(1)
expect((await repository.loadState(watch.id)).notifiedFingerprints).toHaveLength(1)

Asserting only the return value is half a test: most regressions in this system are state that was or was not written.

  • Inject the clock. Domain functions take time as an argument; adapters accept a now option.
  • Never depend on wall-clock ordering, and never sleep.
  • Fixtures live beside the tests; a test that needs a page fetches it from a fixture, never from the internet.

Describe the behaviour and, where relevant, the reason:

it('caps an unrated source at the weak tier')
it('redelivers an undelivered alert on the NEXT run through the Mongo repository')

A failing test should tell you what broke without opening the file.

Unit tests prove the machinery. Whether the decisions are good is measured by the golden-set harness — see The evaluation harness.