@@ -74,7 +74,7 @@ semantic precision:
7474``` typescript
7575import {test , assert } from ' vitest' ;
7676
77- assert .ok (value ); // narrows away null/undefined
77+ assert .ok (value ); // narrows away null/undefined
7878assert .strictEqual (a , b );
7979assert .deepStrictEqual (a , b );
8080```
@@ -120,16 +120,20 @@ assert.throws(() => fn(), TypeError);
120120assert .doesNotThrow (() => fn ());
121121```
122122
123- ` assert.throws() ` returns ` void ` . To inspect the error, use try/catch:
123+ ` assert.throws() ` returns ` void ` . To inspect the error, place ` assert.fail `
124+ ** after** the catch block — never inside the try block, where it would be
125+ caught and swallowed:
124126
125127``` typescript
126128try {
127129 fn ();
128- assert . fail ( ' Expected error ' );
129- } catch ( e : any ) {
130+ } catch ( e ) {
131+ assert ( e instanceof Error );
130132 assert .include (e .message , ' expected substring' );
131- assert .strictEqual (e .code , ' EXPECTED_CODE' );
133+ assert .strictEqual ((e as any ).code , ' EXPECTED_CODE' );
134+ return ;
132135}
136+ assert .fail (' Expected error' );
133137```
134138
135139### Async Rejection Testing
@@ -148,8 +152,8 @@ await assert_rejects(
148152);
149153
150154// Pattern is optional — returns the Error for further assertions
151- const err = await assert_rejects (
152- () => local_repos_load ({local_repo_paths: paths , git_ops , npm_ops }),
155+ const err = await assert_rejects (() =>
156+ local_repos_load ({local_repo_paths: paths , git_ops , npm_ops }),
153157);
154158assert .include (err .message , ' repo-a' );
155159assert .include (err .message , ' repo-b' );
@@ -359,28 +363,28 @@ fuz_ui's `test_helpers.ts` also provides generic fixture infrastructure
359363
360364` {domain}_test_helpers.ts ` pattern:
361365
362- | File | Repo | Purpose |
363- | ------------------------------------ | -------- | ---------------------------------------- |
364- | ` csp_test_helpers.ts ` | fuz_ui | CSP test constants and source factories |
365- | ` contextmenu_test_helpers.ts ` | fuz_ui | Contextmenu mounting and attachment setup |
366- | ` module_test_helpers.ts ` | fuz_ui | Module analysis test options and program setup |
367- | ` deep_equal_test_helpers.ts ` | fuz_util | Bidirectional equality assertions and batch helpers |
368- | ` log_test_helpers.ts ` | fuz_util | Logger mock console with captured args |
369- | ` random_test_helpers.ts ` | fuz_util | Custom PRNG factories for distribution testing |
370- | ` build_cache_test_helpers.ts ` | gro | Build cache mock factories |
371- | ` build_task_test_helpers.ts ` | gro | Build task context and mock plugins |
372- | ` deploy_task_test_helpers.ts ` | gro | Deploy task context and git mock setup |
373- | ` css_class_extractor_test_helpers.ts ` | fuz_css | Extractor assertion helpers |
366+ | File | Repo | Purpose |
367+ | ------------------------------------- | -------- | ----------- ---------------------------------------- |
368+ | ` csp_test_helpers.ts ` | fuz_ui | CSP test constants and source factories |
369+ | ` contextmenu_test_helpers.ts ` | fuz_ui | Contextmenu mounting and attachment setup |
370+ | ` module_test_helpers.ts ` | fuz_ui | Module analysis test options and program setup |
371+ | ` deep_equal_test_helpers.ts ` | fuz_util | Bidirectional equality assertions and batch helpers |
372+ | ` log_test_helpers.ts ` | fuz_util | Logger mock console with captured args |
373+ | ` random_test_helpers.ts ` | fuz_util | Custom PRNG factories for distribution testing |
374+ | ` build_cache_test_helpers.ts ` | gro | Build cache mock factories |
375+ | ` build_task_test_helpers.ts ` | gro | Build task context and mock plugins |
376+ | ` deploy_task_test_helpers.ts ` | gro | Deploy task context and git mock setup |
377+ | ` css_class_extractor_test_helpers.ts ` | fuz_css | Extractor assertion helpers |
374378
375379Fixture-specific helpers live inside the fixture directory:
376380
377- | File | Repo | Purpose |
378- | --------------------------------------------------------------------- | - ------ | ---------------------------- |
379- | ` fixtures/mdz/mdz_test_helpers.ts ` | fuz_ui | mdz fixture loading |
380- | ` fixtures/tsdoc/tsdoc_test_helpers.ts ` | fuz_ui | tsdoc fixture loading |
381- | ` fixtures/ts/ts_test_helpers.ts ` | fuz_ui | TypeScript fixture loading |
382- | ` fixtures/svelte/svelte_test_helpers.ts ` | fuz_ui | Svelte fixture loading |
383- | ` fixtures/svelte_preprocess_mdz/svelte_preprocess_mdz_test_helpers.ts ` | fuz_ui | Preprocessor fixture loading |
381+ | File | Repo | Purpose |
382+ | ---------------------------------------------------------------------- | ------ | ---------------------------- |
383+ | ` fixtures/mdz/mdz_test_helpers.ts ` | fuz_ui | mdz fixture loading |
384+ | ` fixtures/tsdoc/tsdoc_test_helpers.ts ` | fuz_ui | tsdoc fixture loading |
385+ | ` fixtures/ts/ts_test_helpers.ts ` | fuz_ui | TypeScript fixture loading |
386+ | ` fixtures/svelte/svelte_test_helpers.ts ` | fuz_ui | Svelte fixture loading |
387+ | ` fixtures/svelte_preprocess_mdz/svelte_preprocess_mdz_test_helpers.ts ` | fuz_ui | Preprocessor fixture loading |
384388
385389### Svelte Component Test Helpers
386390
@@ -459,8 +463,8 @@ create_shared_core_tests(
459463);
460464```
461465
462- fuz_ui uses this for contextmenu components with 8 factory modules
463- (` contextmenu_test_ {core,rendering,keyboard,nested,positioning,scoped,edge_cases,link_entries}.ts` ).
466+ fuz * ui uses this for contextmenu components with 8 factory modules
467+ (` contextmenu_test* {core,rendering,keyboard,nested,positioning,scoped,edge_cases,link_entries}.ts` ).
464468
465469## Fixture-Based Testing
466470
@@ -619,8 +623,14 @@ See [dependency-injection.md](./dependency-injection.md) for the full pattern.
619623// src/lib/operations.ts — interfaces for all side effects
620624// each method uses options objects and returns Result
621625export interface GitOperations {
622- current_branch_name: (options ? : {cwd? : string }) => Promise <Result <{value: string }, {message: string }>>;
623- add_and_commit: (options : {files: string | Array <string >; message: string ; cwd? : string }) => Promise <Result <object , {message: string }>>;
626+ current_branch_name: (options ? : {
627+ cwd? : string ;
628+ }) => Promise <Result <{value: string }, {message: string }>>;
629+ add_and_commit: (options : {
630+ files: string | Array <string >;
631+ message: string ;
632+ cwd? : string ;
633+ }) => Promise <Result <object , {message: string }>>;
624634 // ... ~15 more methods
625635}
626636export interface GitopsOperations {
@@ -656,7 +666,7 @@ fuz_gitops uses **zero vi.mock()** — all tests inject mock operations via DI.
656666import {stub_app_deps } from ' $lib/testing/stubs.js' ;
657667import {create_mock_runtime } from ' $lib/runtime/mock.js' ;
658668
659- const deps = stub_app_deps ; // throwing stubs for auth deps
669+ const deps = stub_app_deps ; // throwing stubs for auth deps
660670const runtime = create_mock_runtime (); // MockRuntime for CLI tests
661671```
662672
@@ -719,9 +729,9 @@ describe.skipIf(SKIP)('vite plugin examples', () => {
719729SKIP_EXAMPLE_TESTS=1 gro test
720730```
721731
722- | Flag | Repo | Purpose |
723- | -------------------- | ------- | ----------------------------------- |
724- | ` SKIP_EXAMPLE_TESTS ` | fuz_css | Skip slow Vite plugin integration tests |
732+ | Flag | Repo | Purpose |
733+ | -------------------- | ------- | -------------------------------------------- |
734+ | ` SKIP_EXAMPLE_TESTS ` | fuz_css | Skip slow Vite plugin integration tests |
725735| ` TEST_DATABASE_URL ` | fuz_app | Enable PostgreSQL tests (PGlite always runs) |
726736
727737## Test Structure
@@ -735,10 +745,13 @@ import {query_create_account} from '$lib/auth/account_queries.js';
735745describe (' account queries' , () => {
736746 test (' create returns an account with generated uuid' , async () => {
737747 const db = get_db ();
738- const account = await query_create_account ({db }, {
739- username: ' alice' ,
740- password_hash: ' hash123' ,
741- });
748+ const account = await query_create_account (
749+ {db },
750+ {
751+ username: ' alice' ,
752+ password_hash: ' hash123' ,
753+ },
754+ );
742755
743756 assert .ok (account .id );
744757 assert .strictEqual (account .username , ' alice' );
@@ -831,52 +844,52 @@ Tests with dynamic expected values or extra assertions should stay standalone.
831844
832845### Composable Test Suites (fuz_app)
833846
834- | Suite | Groups | Purpose |
835- | ---------------------------------------------- | ------ | ---------------------------------------- |
836- | ` describe_standard_attack_surface_tests ` | 5 | Snapshot, structure, adversarial auth/input/404 |
837- | ` describe_standard_integration_tests ` | 10 | Login, cookies, sessions, bearer, passwords |
838- | ` describe_standard_admin_integration_tests ` | 7 | Accounts, permits, sessions, audit log |
839- | ` describe_rate_limiting_tests ` | 3 | IP, per-account, bearer rate limiting |
840- | ` describe_round_trip_validation ` | varies | Schema-driven positive-path validation |
841- | ` describe_data_exposure_tests ` | 6 | Schema-level + runtime field blocklists |
842- | ` describe_standard_adversarial_headers ` | 7 | Header injection cases |
843- | ` describe_standard_tests ` | - | Convenience wrapper: integration + admin |
847+ | Suite | Groups | Purpose |
848+ | ------------------------------------------- | ------ | ------- ---------------------------------------- |
849+ | ` describe_standard_attack_surface_tests ` | 5 | Snapshot, structure, adversarial auth/input/404 |
850+ | ` describe_standard_integration_tests ` | 10 | Login, cookies, sessions, bearer, passwords |
851+ | ` describe_standard_admin_integration_tests ` | 7 | Accounts, permits, sessions, audit log |
852+ | ` describe_rate_limiting_tests ` | 3 | IP, per-account, bearer rate limiting |
853+ | ` describe_round_trip_validation ` | varies | Schema-driven positive-path validation |
854+ | ` describe_data_exposure_tests ` | 6 | Schema-level + runtime field blocklists |
855+ | ` describe_standard_adversarial_headers ` | 7 | Header injection cases |
856+ | ` describe_standard_tests ` | - | Convenience wrapper: integration + admin |
844857
845858Live in ` fuz_app/src/lib/testing/ ` (library exports, not test files). Accept
846859configuration with ` session_options ` and ` create_route_specs ` .
847860
848861## Quick Reference
849862
850- | Pattern | Purpose |
851- | --------------------------------- | ------------------------------------------------ |
852- | ` src/test/ ` | All tests live here, not co-located |
853- | ` src/test/domain/ ` | Mirrors ` src/lib/domain/ ` subdirectories |
854- | ` module.aspect.test.ts ` | Split test suites by aspect |
855- | ` module.db.test.ts ` | DB test — shared WASM worker via vitest projects |
856- | ` module.fixtures.test.ts ` | Fixture-based test file |
857- | ` test_helpers.ts ` | General shared test utilities (most repos) |
858- | ` {domain}_test_helpers.ts ` | Domain-specific test utilities |
859- | ` {domain}_test_{aspect}.ts ` | Shared test factory modules (not test files) |
860- | ` create_shared_*_tests() ` | Factory function for reusable test suites |
861- | ` fixtures/feature/case/ ` | Subdirectory per fixture case |
862- | ` fixtures/update.task.ts ` | Parent: runs all child update tasks |
863- | ` fixtures/feature/update.task.ts ` | Child: regenerates one feature |
864- | ` assert ` from vitest | Ecosystem-wide standard |
865- | ` assert.isDefined(x); x.prop ` | Narrows to NonNullable — no ` x! ` needed |
866- | ` assert(x instanceof T); x.prop ` | Narrows union types — the key advantage over ` expect ` |
867- | ` assert.throws(fn, /regex/) ` | Returns void; second arg: constructor/string/RegExp (not function) |
868- | ` assert_rejects(fn, /regex?/) ` | Shared — async rejection, optional pattern, returns Error |
869- | ` create_mock_logger() ` | Shared — ` vi.fn() ` methods + tracking arrays |
870- | try/catch + ` assert.include ` | For inspecting thrown errors when helper isn't enough |
871- | ` assert_* ` (not ` expect_* ` ) | Custom assertion helper naming convention |
872- | ` describe ` + ` test ` (not ` it ` ) | Default structure; 1-2 levels of ` describe ` typical |
873- | ` // @vitest-environment jsdom ` | Pragma for UI tests needing DOM |
874- | ` vi.stubGlobal('ResizeObserver') ` | Required in jsdom for components using ResizeObserver |
875- | ` describe_db(name, fn) ` | DB test wrapper (fuz_app) |
876- | ` create_test_app() ` | Full Hono app for integration tests (fuz_app) |
877- | ` stub_app_deps ` | Throwing stub deps for unit tests (fuz_app) |
878- | DI via ` *Operations ` /` *Deps ` | Preferred over vi.mock() for side effects |
879- | ` create_mock_*() ` | Factory functions for test data |
880- | ` SKIP_EXAMPLE_TESTS=1 ` | Skip slow fuz_css integration tests |
881- | ` TEST_DATABASE_URL ` | Enable PostgreSQL tests alongside PGlite |
882- | Never edit ` expected.json ` | Always regenerate via task |
863+ | Pattern | Purpose |
864+ | --------------------------------- | ------------------------------------------------------------------ |
865+ | ` src/test/ ` | All tests live here, not co-located |
866+ | ` src/test/domain/ ` | Mirrors ` src/lib/domain/ ` subdirectories |
867+ | ` module.aspect.test.ts ` | Split test suites by aspect |
868+ | ` module.db.test.ts ` | DB test — shared WASM worker via vitest projects |
869+ | ` module.fixtures.test.ts ` | Fixture-based test file |
870+ | ` test_helpers.ts ` | General shared test utilities (most repos) |
871+ | ` {domain}_test_helpers.ts ` | Domain-specific test utilities |
872+ | ` {domain}_test_{aspect}.ts ` | Shared test factory modules (not test files) |
873+ | ` create_shared_*_tests() ` | Factory function for reusable test suites |
874+ | ` fixtures/feature/case/ ` | Subdirectory per fixture case |
875+ | ` fixtures/update.task.ts ` | Parent: runs all child update tasks |
876+ | ` fixtures/feature/update.task.ts ` | Child: regenerates one feature |
877+ | ` assert ` from vitest | Ecosystem-wide standard |
878+ | ` assert.isDefined(x); x.prop ` | Narrows to NonNullable — no ` x! ` needed |
879+ | ` assert(x instanceof T); x.prop ` | Narrows union types — the key advantage over ` expect ` |
880+ | ` assert.throws(fn, /regex/) ` | Returns void; second arg: constructor/string/RegExp (not function) |
881+ | ` assert_rejects(fn, /regex?/) ` | Shared — async rejection, optional pattern, returns Error |
882+ | ` create_mock_logger() ` | Shared — ` vi.fn() ` methods + tracking arrays |
883+ | try/catch + ` assert.include ` | For inspecting thrown errors when helper isn't enough |
884+ | ` assert_* ` (not ` expect_* ` ) | Custom assertion helper naming convention |
885+ | ` describe ` + ` test ` (not ` it ` ) | Default structure; 1-2 levels of ` describe ` typical |
886+ | ` // @vitest-environment jsdom ` | Pragma for UI tests needing DOM |
887+ | ` vi.stubGlobal('ResizeObserver') ` | Required in jsdom for components using ResizeObserver |
888+ | ` describe_db(name, fn) ` | DB test wrapper (fuz_app) |
889+ | ` create_test_app() ` | Full Hono app for integration tests (fuz_app) |
890+ | ` stub_app_deps ` | Throwing stub deps for unit tests (fuz_app) |
891+ | DI via ` *Operations ` /` *Deps ` | Preferred over vi.mock() for side effects |
892+ | ` create_mock_*() ` | Factory functions for test data |
893+ | ` SKIP_EXAMPLE_TESTS=1 ` | Skip slow fuz_css integration tests |
894+ | ` TEST_DATABASE_URL ` | Enable PostgreSQL tests alongside PGlite |
895+ | Never edit ` expected.json ` | Always regenerate via task |
0 commit comments