This repo uses a small unit-test layer for pure TypeScript modules plus the existing type-check and build verification steps.
npm run test
npm run test:watch
npm run check
npm run buildRecommended local sequence before pushing:
npm run testnpm run checknpm run build
For PWA or speech work, also verify the built app exposes the expected manifest/service-worker assets and that browser-only speech helpers degrade cleanly when APIs are unavailable.
The current unit tests focus on fast, deterministic modules that do not require live provider APIs, a browser, or a database:
src/lib/utils/note-structure.test.ts- verifies the shared assistant note-section contract
- checks required section order, approved optional-section placement, deprecated-heading rejection, and heading normalization
src/lib/server/ai/prompts.test.ts- verifies create/update assistant prompts both inject the same shared note-structure contract
src/lib/server/assistant/routing.test.ts- verifies inference-first routing keeps plain learning prompts conversational
- verifies follow-up asks like
add it to notesorsave this to my notesroute into note creation
src/lib/client/speech.test.ts- verifies
canSpeakandcanListenreturn false in SSR (no window) and correctly detect API presence usingvi.stubGlobal - verifies
extractHtmlTextstrips tags, decodes common entities, and collapses whitespace - verifies
extractMarkdownTextstrips headings, bold/italic, links, images, wikilinks, code blocks, and list markers - verifies
speakandstopSpeakingmanage utterance lifecycle, cancel before starting new speech, triggeronEndon end/error events, and no-op when the API is absent - browser speech APIs are mocked via
vi.stubGlobal; no real microphone or system voices required
- verifies
src/lib/server/practice/practice.test.ts- verifies
validateManualImportaccepts valid complete and minimal payloads, rejects missing or whitespace-only required fields, trims whitespace, and filters empty tag strings - verifies
isValidStatusaccepts all four documented status values and rejects invalid strings, null, and numeric values - verifies
validateProgressInputaccepts valid minimal and full payloads; rejects missing fields, invalid status, negative or fractional attempts, non-string notes, and non-string non-null codeSnapshot; accepts null codeSnapshot - verifies
LeetCodeFetchDisabledErrorandLeetCodeFetchUpstreamErrorcarry their documented error codes and names - verifies
fetchLeetCodeDailythrowsLeetCodeFetchDisabledErrorwhenLEETCODE_DAILY_FETCH_ENABLEDis absent or not"true", confirming the disabled state documented indocs/API.md - verifies
validateTutorInputaccepts valid minimal and full payloads; rejects missing fields, invalid hint levels, non-string code, and disallowed model identifiers; accepts all documented hint levels - verifies
isValidHintLevelaccepts the four documented levels and rejects out-of-vocabulary strings - verifies the tutor module's non-persistence contract:
tutor.tsexports no conversation creation or message append functions, confirming that tutor turns are never written toconversationsorconversation_messages $env/dynamic/privateand the DB module are mocked viavi.mockso tests run without live secrets or a database connection
- verifies
Remaining planned additions for the PWA and voice phase:
- route tests for optional speech transcription error states where practical
- build checks that the PWA manifest and service-worker registration compile without server-only import leaks
The assistant note-section rules live in src/lib/utils/note-structure.ts.
That module is the source of truth for:
- required sections
- approved optional sections
- deprecated headings
- the shared prompt guidance text
- pure note-body validation used by the assistant commit boundary
This keeps prompt-time instructions and commit-time validation aligned.
GitHub Actions runs .github/workflows/ci.yml on pushes to main and on pull requests targeting main.
The CI sequence is:
npm cinpm run testnpm run buildnpm run check
Build still uses dummy private env values so the workflow catches server-only import leaks without requiring real secrets.
Prefer unit tests for pure modules first. They are faster, easier to maintain, and run cleanly in CI without app bootstrapping.
When adding tests:
- keep them close to the module under test with
*.test.ts - avoid live network calls and provider SDK calls
- mock or isolate runtime-heavy boundaries instead of depending on external services
- add route-level or browser-level tests only when unit coverage is not enough to protect the behavior
- for speech features, mock browser speech APIs instead of depending on device microphone, installed system voices, or live transcription providers
- for PWA features, prefer build/output verification and manifest assertions over brittle install-prompt automation