create-monolayer-app 0.5.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +91 -59
- package/package.json +19 -16
- package/template/.agents/skills/{monolayer-application-permissions → application-permissions}/SKILL.md +2 -2
- package/template/.agents/skills/application-permissions/agents/openai.yaml +4 -0
- package/template/.agents/skills/kysely/SKILL.md +48 -0
- package/template/.agents/skills/kysely/agents/openai.yaml +4 -0
- package/template/.agents/skills/kysely/references/execution-plugins-and-runtime.md +67 -0
- package/template/.agents/skills/kysely/references/expressions-and-helpers.md +102 -0
- package/template/.agents/skills/kysely/references/migrations.md +43 -0
- package/template/.agents/skills/kysely/references/official-docs-map.md +97 -0
- package/template/.agents/skills/kysely/references/query-building.md +119 -0
- package/template/.agents/skills/kysely/references/transactions.md +47 -0
- package/template/.agents/skills/kysely/references/troubleshooting-and-boundaries.md +67 -0
- package/template/.agents/skills/kysely/references/types.md +58 -0
- package/template/.agents/skills/persistent-app-data/SKILL.md +74 -0
- package/template/.agents/skills/persistent-app-data/agents/openai.yaml +4 -0
- package/template/.agents/skills/persistent-app-data/references/generated-types.md +23 -0
- package/template/.agents/skills/persistent-app-data/references/migrations.md +68 -0
- package/template/.agents/skills/vitest/GENERATION.md +25 -0
- package/template/.agents/skills/vitest/SKILL.md +59 -0
- package/template/.agents/skills/vitest/references/advanced-environments.md +26 -0
- package/template/.agents/skills/vitest/references/advanced-projects.md +31 -0
- package/template/.agents/skills/vitest/references/advanced-type-testing.md +30 -0
- package/template/.agents/skills/vitest/references/advanced-vi.md +23 -0
- package/template/.agents/skills/vitest/references/core-cli.md +23 -0
- package/template/.agents/skills/vitest/references/core-config.md +24 -0
- package/template/.agents/skills/vitest/references/core-describe.md +24 -0
- package/template/.agents/skills/vitest/references/core-expect.md +35 -0
- package/template/.agents/skills/vitest/references/core-hooks.md +26 -0
- package/template/.agents/skills/vitest/references/core-test-api.md +29 -0
- package/template/.agents/skills/vitest/references/features-benchmarking.md +25 -0
- package/template/.agents/skills/vitest/references/features-concurrency.md +20 -0
- package/template/.agents/skills/vitest/references/features-context.md +27 -0
- package/template/.agents/skills/vitest/references/features-coverage.md +17 -0
- package/template/.agents/skills/vitest/references/features-filtering.md +24 -0
- package/template/.agents/skills/vitest/references/features-mocking.md +32 -0
- package/template/.agents/skills/vitest/references/features-reporters.md +22 -0
- package/template/.agents/skills/vitest/references/features-snapshots.md +23 -0
- package/template/.agents/skills/vitest/references/features-test-tags.md +30 -0
- package/template/.agents/skills/vitest/references/version-compatibility.md +19 -0
- package/template/.claude/CLAUDE.md +2 -2
- package/template/.react-router/types/+routes.ts +41 -0
- package/template/.react-router/types/+server-build.d.ts +18 -0
- package/template/.react-router/types/app/+types/root.ts +68 -0
- package/template/.react-router/types/app/routes/+types/files.ts +71 -0
- package/template/.react-router/types/app/routes/+types/home.ts +71 -0
- package/template/AGENTS.md +6 -2
- package/template/README.md +10 -0
- package/template/app/routes/files.ts +3 -3
- package/template/build/client/assets/entry.client-Bc58m2-m.js +9 -0
- package/template/build/client/assets/errorBoundaries-CQxPIuVU.js +16 -0
- package/template/build/client/assets/files-BvRk9kiK.js +0 -0
- package/template/build/client/assets/home-CH2INc5e.js +1 -0
- package/template/build/client/assets/jsx-runtime-eLCqVKHJ.js +1 -0
- package/template/build/client/assets/logo-dark-pX2395Y0.svg +23 -0
- package/template/build/client/assets/logo-light-CVbx2LBR.svg +23 -0
- package/template/build/client/assets/manifest-2d65dd0f.js +1 -0
- package/template/build/client/assets/root-BeNS6njP.css +2 -0
- package/template/build/client/assets/root-C1tmjS9o.js +1 -0
- package/template/build/client/favicon.ico +0 -0
- package/template/build/server/index.js +1096 -0
- package/template/lib/db/client.ts +1 -27
- package/template/package-lock.json +8221 -0
- package/template/package.json +7 -3
- package/template/vendor/file-bucket/{client.ts → index.client.ts} +11 -9
- package/template/vendor/file-bucket/{server.ts → index.server.ts} +13 -8
- package/template/vendor/file-bucket/{index.ts → lib/file-bucket.ts} +2 -1
- package/template/vendor/file-bucket/{react-router.ts → react-router.server.ts} +15 -13
- package/template/vendor/kysely-dsql/dsql/dsql-kysely.ts +31 -3
- package/template/vendor/kysely-dsql/generator/migration-file.ts +3 -3
- package/template/vendor/kysely-dsql/plugins/index.ts +0 -2
- package/template/vendor/package-app/package-app.mjs +10 -3
- package/template/vendor/package-app/package-app.test.mjs +167 -0
- package/template/vite.config.ts +3 -1
- package/template/vitest.config.ts +7 -2
- package/template/.agents/skills/monolayer-application-permissions/agents/openai.yaml +0 -4
- package/template/vendor/kysely-dsql/plugins/soft-delete.plugin.ts +0 -217
- /package/template/.agents/skills/{monolayer-application-permissions → application-permissions}/references/development-and-verification.md +0 -0
- /package/template/.agents/skills/{monolayer-application-permissions → application-permissions}/references/interface-examples.md +0 -0
- /package/template/.agents/skills/{monolayer-application-permissions → application-permissions}/references/server-examples.md +0 -0
- /package/template/vendor/file-bucket/{errors.ts → lib/errors.server.ts} +0 -0
- /package/template/vendor/file-bucket/{multipart.ts → lib/multipart.ts} +0 -0
- /package/template/vendor/file-bucket/{protocol.ts → lib/protocol.ts} +0 -0
- /package/template/vendor/file-bucket/{transport.ts → lib/transport.client.ts} +0 -0
- /package/template/vendor/file-bucket/{types.ts → lib/types.ts} +0 -0
- /package/template/vendor/file-bucket/{transfers.ts → lib/upload-signed-url.ts} +0 -0
- /package/template/vendor/file-bucket/{xml.ts → lib/xml.ts} +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Environments
|
|
2
|
+
|
|
3
|
+
Select an environment from the APIs that the test needs.
|
|
4
|
+
|
|
5
|
+
| Execution | Use |
|
|
6
|
+
| ------------ | ---------------------------------------------------- |
|
|
7
|
+
| `node` | Server logic and code without DOM requirements |
|
|
8
|
+
| `jsdom` | DOM emulation in Node.js |
|
|
9
|
+
| `happy-dom` | Alternative DOM emulation with different API support |
|
|
10
|
+
| Browser Mode | Actual browser behavior through a browser provider |
|
|
11
|
+
|
|
12
|
+
The template currently uses `node`. DOM environments require their corresponding packages. Check installed dependencies before you select one.
|
|
13
|
+
|
|
14
|
+
Use a file comment when one file needs a different Node.js environment:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
// @vitest-environment jsdom
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Browser Mode uses `test.browser` configuration. It is not an `environment: "browser"` option. Use a browser project when tests need actual layout, focus, or browser integration. Mock external service boundaries while retaining real UI behavior.
|
|
21
|
+
|
|
22
|
+
A custom environment exports an object that matches `Environment` from `vitest/runtime` in Vitest 5. Define its Vite environment and cleanup behavior from the installed types. Avoid adding a custom environment when an existing environment meets the need.
|
|
23
|
+
|
|
24
|
+
For CSS import errors in an external dependency chain, inspect `server.deps.inline`. Include the relevant chain only when transformation is necessary. A simulated DOM does not prove browser rendering behavior.
|
|
25
|
+
|
|
26
|
+
Sources: [Environments](https://vitest.dev/guide/environment), [Browser Mode](https://vitest.dev/guide/browser/).
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Projects
|
|
2
|
+
|
|
3
|
+
Use `test.projects` when test groups need different environments or runner settings. Give each project a distinct name. Use `defineProject` for an independent project file.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { defineConfig } from "vitest/config";
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
test: {
|
|
10
|
+
projects: [
|
|
11
|
+
{
|
|
12
|
+
test: {
|
|
13
|
+
name: "unit",
|
|
14
|
+
environment: "node",
|
|
15
|
+
include: ["src/**/*.test.ts"],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
In Vitest 5, inline projects inherit their declaring configuration by default. Arrays such as `setupFiles` concatenate. `name` and `projects` do not inherit. Root `globalSetup` runs once and does not inherit into child projects. A project's own `tags` replace the inherited tags. Use `extends: false` when a project must be independent.
|
|
24
|
+
|
|
25
|
+
Vitest 4 requires explicit `extends: true` for this inheritance.
|
|
26
|
+
|
|
27
|
+
Projects referenced as files or directories do not inherit root settings automatically. Merge a shared configuration explicitly when necessary. Referenced configurations can define nested projects in Vitest 5. Avoid merging a root `projects` list back into its children.
|
|
28
|
+
|
|
29
|
+
Keep coverage and reporters at the root. Use `--project` to select projects through the local runner. Inspect shared Vite server behavior when plugin initialization must occur separately.
|
|
30
|
+
|
|
31
|
+
Sources: [Projects](https://vitest.dev/guide/projects), [Version compatibility](version-compatibility.md).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Type testing
|
|
2
|
+
|
|
3
|
+
Use `expectTypeOf` or `assertType` for TypeScript contracts. Run a compiler check to evaluate those contracts. Ordinary runtime execution does not check TypeScript types.
|
|
4
|
+
|
|
5
|
+
Put dedicated type tests in files that match `typecheck.include`, normally `*.test-d.ts`:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { assertType, describe, expectTypeOf, test } from "vitest";
|
|
9
|
+
|
|
10
|
+
describe("record shape", () => {
|
|
11
|
+
test("preserves field types", () => {
|
|
12
|
+
const record = { id: "record-1", revision: 1 };
|
|
13
|
+
expectTypeOf(record).toEqualTypeOf<{ id: string; revision: number }>();
|
|
14
|
+
assertType<string>(record.id);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Enable type checks through the local runner:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npm exec --no -- vitest run --typecheck
|
|
23
|
+
npm exec --no -- vitest run --typecheck.only
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Dedicated type test files undergo static analysis. They do not execute their callbacks or lifecycle hooks. Keep runtime assertions in runtime test files. Overlapping runtime and type patterns can produce separate results for the same file.
|
|
27
|
+
|
|
28
|
+
Use `toEqualTypeOf` for type equality. Use the installed assignability matcher for subtype checks. Keep `@ts-expect-error` comments specific to the intended compiler error. A misspelled identifier can otherwise satisfy an expected-error test. Run the application's complete type check when changes affect its consumers.
|
|
29
|
+
|
|
30
|
+
Source: [Type testing](https://vitest.dev/guide/testing-types).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Vi utilities
|
|
2
|
+
|
|
3
|
+
## Mock cleanup
|
|
4
|
+
|
|
5
|
+
| Operation | Effect |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| `vi.clearAllMocks()` | Clears call history and preserves implementations. |
|
|
8
|
+
| `vi.resetAllMocks()` | Clears history and resets implementations to their original mock state. |
|
|
9
|
+
| `vi.restoreAllMocks()` | Restores original object descriptors for `vi.spyOn` spies. |
|
|
10
|
+
| `vi.unstubAllGlobals()` | Restores globals changed with `vi.stubGlobal`. |
|
|
11
|
+
| `vi.unstubAllEnvs()` | Restores environment values changed with `vi.stubEnv`. |
|
|
12
|
+
|
|
13
|
+
`vi.restoreAllMocks()` does not clear retained spy history or remove module mocks. `vi.fn(implementation).mockReset()` restores the initial implementation. A reset of `vi.fn()` restores an empty function. Vitest 5 enables `clearMocks` by default. Call history can still conflict between concurrent tests.
|
|
14
|
+
|
|
15
|
+
## Timers and modules
|
|
16
|
+
|
|
17
|
+
Use `vi.useFakeTimers()` before code schedules timers. Await `vi.advanceTimersByTimeAsync()` when timer callbacks use promises. Use `vi.setSystemTime()` to control the clock. It does not execute scheduled timers. Restore real timers after each applicable test.
|
|
18
|
+
|
|
19
|
+
`vi.resetModules()` clears the module cache for subsequent imports. It does not remove mock registrations or repeat existing static imports.
|
|
20
|
+
|
|
21
|
+
Use `vi.waitFor` when a callback must stop throwing. Use `vi.waitUntil` when its result must become truthy. Use Vitest 5's `vi.when` for argument-dependent mock behavior when ordinary mock implementations become unclear. Check its installed signature before use.
|
|
22
|
+
|
|
23
|
+
Sources: [Vi API](https://vitest.dev/api/vi), [Mock API](https://vitest.dev/api/mock).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# CLI
|
|
2
|
+
|
|
3
|
+
Prefer the existing package scripts when they invoke the correct local runner. Check the manifest before you assume that a `test` script exists. The template currently has no test script.
|
|
4
|
+
|
|
5
|
+
Run these examples from the application directory with its installed dependencies:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm exec --no -- vitest --version
|
|
9
|
+
npm exec --no -- vitest --help
|
|
10
|
+
npm exec --no -- vitest list
|
|
11
|
+
npm exec --no -- vitest run
|
|
12
|
+
npm exec --no -- vitest run src/parser.test.ts -t "rejects empty input"
|
|
13
|
+
npm exec --no -- vitest watch src/parser.test.ts
|
|
14
|
+
npm exec --no -- vitest related src/parser.ts --run
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Replace example paths with existing application files. Use `run` for commands that must finish. The default command can enter watch mode in an interactive terminal. `related` follows the import graph. It cannot resolve arbitrary paths that application code calculates at runtime.
|
|
18
|
+
|
|
19
|
+
Use `--config` when the task requires an explicit configuration file. Use `--project` for a named project. Use `--coverage.enabled=false` for focused feedback when configuration enables coverage. Run complete coverage separately when required.
|
|
20
|
+
|
|
21
|
+
Inspect `list` output when a command discovers no tests. Check the working directory, configuration, include patterns, and filters. Do not use `--passWithNoTests` to conceal missing tests.
|
|
22
|
+
|
|
23
|
+
Source: [CLI](https://vitest.dev/guide/cli).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Import `defineConfig` from `vitest/config`. Put runner options inside `test`. Put Vite options, such as `resolve.alias` and `plugins`, at the top level.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { defineConfig } from "vitest/config";
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
test: {
|
|
10
|
+
environment: "node",
|
|
11
|
+
include: ["src/**/*.test.ts"],
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
A separate `vitest.config.ts` takes priority over `vite.config.ts`. It does not automatically merge the application configuration. Use `mergeConfig` when tests need selected Vite settings. Check application plugins before you include them in a test process. Extend `configDefaults.exclude` when additional exclusions must preserve the defaults.
|
|
17
|
+
|
|
18
|
+
Use `setupFiles` for setup that each test file requires. Use `globalSetup` for resources that span the run. Global setup executes outside test workers. Use `provide` and `inject` for serializable values across that boundary.
|
|
19
|
+
|
|
20
|
+
## Template discovery
|
|
21
|
+
|
|
22
|
+
The current template includes `.test.ts` files under `src`, `lib`, and `app`. Its patterns exclude `.test.tsx` files and tests under `vendor`. A CLI filename filter does not add excluded files to discovery. Its `virtual:db-migrations` alias resolves to a test fixture. Preserve that alias when tests depend on it. Recheck these facts after configuration changes.
|
|
23
|
+
|
|
24
|
+
Sources: [Configuration](https://vitest.dev/config/), [Projects](advanced-projects.md).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Describe API
|
|
2
|
+
|
|
3
|
+
Use `describe` to group tests with the same subject or setup. `suite` is an alias. Keep the hierarchy shallow enough to make test names clear.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { describe, expect, test } from "vitest";
|
|
7
|
+
|
|
8
|
+
describe.each([
|
|
9
|
+
{ input: "one", expected: "ONE" },
|
|
10
|
+
{ input: "two", expected: "TWO" },
|
|
11
|
+
])("conversion of $input", ({ input, expected }) => {
|
|
12
|
+
test("returns uppercase text", () => {
|
|
13
|
+
expect(input.toUpperCase()).toBe(expected);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Suite options apply to child tests unless a child overrides them. Use suite options for shared timeouts or concurrency when that behavior fits all children. Use `describe.each` for repeated suite cases. Use `describe.for` when the case should remain one value.
|
|
19
|
+
|
|
20
|
+
Suite callbacks collect tests before test execution. Do not put assertions, service calls, or resource setup in the collection callback. Use lifecycle hooks or fixtures for setup and cleanup. Keep `vi.mock` at module scope in Vitest 5.
|
|
21
|
+
|
|
22
|
+
`describe.concurrent` permits child tests to overlap. Use `{ concurrent: false }` for a child that needs sequential execution. This setting does not serialize other files that share an external resource. See [concurrency](features-concurrency.md) for those boundaries.
|
|
23
|
+
|
|
24
|
+
Source: [Describe API](https://vitest.dev/api/describe).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Expect API
|
|
2
|
+
|
|
3
|
+
Select assertions that check the required result.
|
|
4
|
+
|
|
5
|
+
| Result | Matcher |
|
|
6
|
+
| ----------------------------------- | ---------------------------------- |
|
|
7
|
+
| Primitive value or object identity | `toBe` |
|
|
8
|
+
| Complete object structure and types | `toStrictEqual` |
|
|
9
|
+
| Required object fields | `toMatchObject` |
|
|
10
|
+
| Synchronous error | `toThrow` with an expected message |
|
|
11
|
+
| Promise result or error | Await `resolves` or `rejects` |
|
|
12
|
+
| Mock arguments | `toHaveBeenCalledWith` |
|
|
13
|
+
| Eventual state | Await `expect.poll` |
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { describe, expect, test } from "vitest";
|
|
17
|
+
|
|
18
|
+
describe("asynchronous results", () => {
|
|
19
|
+
test("returns the result", async () => {
|
|
20
|
+
await expect(Promise.resolve({ count: 2 })).resolves.toStrictEqual({
|
|
21
|
+
count: 2,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("reports the failure", async () => {
|
|
26
|
+
await expect(Promise.reject(new Error("Missing record"))).rejects.toThrow("Missing record");
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Pass a callback to `toThrow` for synchronous operations. Do not call the operation before the assertion receives it. Use asymmetric matchers only for fields that the contract permits to vary. Use `expect.assertions` when callback execution could otherwise leave no assertion.
|
|
32
|
+
|
|
33
|
+
A false result does not make `vi.waitFor` retry. Use an assertion that throws, or use `vi.waitUntil` for a truthy condition. Use the context's `expect` for concurrent snapshots and assertion counts.
|
|
34
|
+
|
|
35
|
+
Sources: [Expect API](https://vitest.dev/api/expect), [Vi API](https://vitest.dev/api/vi).
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Hooks
|
|
2
|
+
|
|
3
|
+
Use `beforeEach` and `afterEach` for resources that each test requires. Use `beforeAll` and `afterAll` for resources that the suite shares. Await asynchronous setup and cleanup.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { afterEach, describe, expect, test, vi } from "vitest";
|
|
7
|
+
|
|
8
|
+
describe("runtime configuration", () => {
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
vi.unstubAllEnvs();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("uses the test region", () => {
|
|
14
|
+
vi.stubEnv("APP_REGION", "test-region");
|
|
15
|
+
expect(process.env.APP_REGION).toBe("test-region");
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
A setup hook can return a cleanup callback. Vitest runs that callback after the corresponding explicit cleanup hooks. Hook ordering depends on `sequence.hooks`. Inspect that setting before a test depends on cleanup order.
|
|
21
|
+
|
|
22
|
+
`aroundEach` wraps per-test setup, execution, and cleanup. `aroundAll` wraps a suite. Call and await the supplied execution function. Use `try` and `finally` when resource release must occur after a failure.
|
|
23
|
+
|
|
24
|
+
Use the context's `onTestFinished` for cleanup that belongs to one concurrent test. Use `onTestFailed` for failure evidence. Concurrent hooks must not change shared globals or resources without isolation. Increase a hook timeout only when the operation needs that time.
|
|
25
|
+
|
|
26
|
+
Source: [Hooks API](https://vitest.dev/api/hooks).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Test API
|
|
2
|
+
|
|
3
|
+
`test` and `it` define tests with the same API. Use a name that states the expected behavior. Put options before the callback.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { describe, expect, test } from "vitest";
|
|
7
|
+
|
|
8
|
+
describe("number conversion", () => {
|
|
9
|
+
test("converts a decimal", { timeout: 1_000 }, async () => {
|
|
10
|
+
const value = await Promise.resolve(Number("12"));
|
|
11
|
+
expect(value).toBe(12);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test.each([
|
|
15
|
+
["0", 0],
|
|
16
|
+
["12", 12],
|
|
17
|
+
])("converts %s", (input, expected) => {
|
|
18
|
+
expect(Number(input)).toBe(expected);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Use `test.each` for data cases with separate arguments. Use `test.for` when each case needs the test context. For array cases, `test.for` passes the array as one argument.
|
|
24
|
+
|
|
25
|
+
Use `test.concurrent` only for independent tests. Use `{ concurrent: false }` to override inherited concurrency. A retry repeats the test and its per-test setup. Do not use retries as the only correction for unstable behavior.
|
|
26
|
+
|
|
27
|
+
A callback without an implementation creates a pending test. Keep pending cases separate from completion evidence. Use `.only`, `.skip`, and conditional selection only within repository rules. Remove temporary selection before completion.
|
|
28
|
+
|
|
29
|
+
Source: [Test API](https://vitest.dev/api/test).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Benchmarking
|
|
2
|
+
|
|
3
|
+
Vitest 5 provides `bench` through the test context. Do not import a top-level `bench` function from `vitest` for this version.
|
|
4
|
+
|
|
5
|
+
Put benchmark tests in a file that matches `benchmark.include`, such as `parser.bench.ts`:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { describe, test } from "vitest";
|
|
9
|
+
|
|
10
|
+
describe("parser throughput", () => {
|
|
11
|
+
test("measures JSON parsing", async ({ bench }) => {
|
|
12
|
+
await bench("parse a record", () => {
|
|
13
|
+
return JSON.parse('{"state":"ready","revision":1}');
|
|
14
|
+
}).run();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Run `vitest bench --run` through the local installation for one benchmark run. Use `benchmark.enabled` when the regular run must also include benchmarks. The fixture is unavailable in ordinary test files outside benchmark discovery.
|
|
20
|
+
|
|
21
|
+
Use `bench.compare` for comparisons within the same measurement conditions. Use a practical tolerance for performance assertions. Use `writeResult` to save a result and `bench.from` to read a baseline. Give baseline files names that identify the measured version.
|
|
22
|
+
|
|
23
|
+
Consume or return computed results to reduce dead-code elimination. Keep warmup, input data, and the runtime consistent across comparisons. Worker load and module transformation can affect measurements. Do not infer production performance from one local result.
|
|
24
|
+
|
|
25
|
+
Source: [Benchmarking](https://vitest.dev/guide/benchmarking).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Concurrency
|
|
2
|
+
|
|
3
|
+
Distinguish file parallelism from concurrency inside one file. Vitest normally runs files in separate workers. Tests inside each file normally run sequentially.
|
|
4
|
+
|
|
5
|
+
| Setting | Boundary |
|
|
6
|
+
| ------------------------ | ------------------------------------ |
|
|
7
|
+
| `maxWorkers` | Maximum workers for files |
|
|
8
|
+
| `fileParallelism: false` | Sequential files within the run |
|
|
9
|
+
| `test.concurrent` | Overlapping tests in one worker |
|
|
10
|
+
| `maxConcurrency` | Maximum concurrent tests |
|
|
11
|
+
| `{ concurrent: false }` | Override inherited test concurrency |
|
|
12
|
+
| `--shard=1/3` | Select one part of a distributed run |
|
|
13
|
+
|
|
14
|
+
Use concurrent tests for independent asynchronous operations. Synchronous CPU work does not gain worker parallelism from `test.concurrent`.
|
|
15
|
+
|
|
16
|
+
Use the context's `expect` for concurrent snapshots and assertion counts. Use per-test fixtures and cleanup for mutable resources. Avoid overlapping tests that change shared timers, environment values, or mock implementations. Vitest 5's automatic mock clearing can affect another concurrent test's call history.
|
|
17
|
+
|
|
18
|
+
Separate workers do not isolate an external database, filesystem path, or service account. Give each test independent resources where possible. A sequential suite does not serialize other files or other processes. Inspect resource ownership before changing isolation settings. Do not disable isolation only to hide test-order dependencies.
|
|
19
|
+
|
|
20
|
+
Source: [Parallelism](https://vitest.dev/guide/parallelism).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Test context and fixtures
|
|
2
|
+
|
|
3
|
+
Use the callback's context for values that belong to one test. The context includes `expect`, `task`, `signal`, and cleanup hooks. Pass `signal` to cancellable operations when a test timeout must stop the operation.
|
|
4
|
+
|
|
5
|
+
Use `test.extend` for reusable typed fixtures. The builder API supports inferred fixture types in Vitest 4.1 and later.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { describe, test as baseTest } from "vitest";
|
|
9
|
+
|
|
10
|
+
const test = baseTest
|
|
11
|
+
.extend("settings", { region: "test-region" })
|
|
12
|
+
.extend("region", async ({ settings }) => settings.region);
|
|
13
|
+
|
|
14
|
+
describe("fixture dependencies", () => {
|
|
15
|
+
test("provides the configured region", ({ expect, region }) => {
|
|
16
|
+
expect(region).toBe("test-region");
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
For a resource fixture, register its teardown with `onCleanup` in the builder callback's second argument. Register one cleanup callback per fixture. Combine related release operations in that callback when necessary.
|
|
22
|
+
|
|
23
|
+
The object syntax supports setup before `await use(value)` and teardown after it. Fixtures initialize when requested unless their options make them automatic. Choose test scope for mutable state that each test must own. Use a broader scope only when resource sharing remains safe.
|
|
24
|
+
|
|
25
|
+
Global setup values cross worker boundaries through `provide` and `inject`. Those values must support serialization.
|
|
26
|
+
|
|
27
|
+
Source: [Test context](https://vitest.dev/guide/test-context).
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Coverage
|
|
2
|
+
|
|
3
|
+
Use the existing provider and source boundaries. Vitest supports V8 and Istanbul coverage through separate companion packages. Match the provider package version to the runner version. The template selects V8, but its manifest does not currently declare `@vitest/coverage-v8`. Check the local installation before a coverage run. Do not accept an automatic package installation without the task's dependency-change scope.
|
|
4
|
+
|
|
5
|
+
Use the application's local runner:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm exec --no -- vitest run --coverage
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Use `coverage.include` to define the measured source files. Review exclusions for tests, generated output, and entrypoints. The template currently measures `src/**/*.ts`. That setting does not measure all application code under `lib` or `app`. State the measured scope in the result.
|
|
12
|
+
|
|
13
|
+
A filtered run can fail global thresholds because it leaves other source files unexecuted. Disable coverage for focused development feedback when necessary. Then run the complete required suite with coverage enabled.
|
|
14
|
+
|
|
15
|
+
Inspect missing branches and failure behavior before adding tests. Do not lower thresholds, narrow source patterns, or add ignore comments to obtain a pass. Separate passing assertions from provider failures and threshold failures.
|
|
16
|
+
|
|
17
|
+
Sources: [Coverage](https://vitest.dev/guide/coverage), [Coverage configuration](https://vitest.dev/config/coverage).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Filtering
|
|
2
|
+
|
|
3
|
+
Use a file filter first when the affected file is known. This avoids collecting unrelated files for a name filter. A positional file filter matches path substrings. It is not a glob or regular expression.
|
|
4
|
+
|
|
5
|
+
Run these examples through the application's local runner:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm exec --no -- vitest run src/parser.test.ts
|
|
9
|
+
npm exec --no -- vitest run src/parser.test.ts -t "rejects empty input"
|
|
10
|
+
npm exec --no -- vitest run src/parser.test.ts:20
|
|
11
|
+
npm exec --no -- vitest related src/parser.ts --run
|
|
12
|
+
npm exec --no -- vitest run --changed=HEAD
|
|
13
|
+
npm exec --no -- vitest run --project=unit
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Replace the paths and line number with actual test locations. A line filter requires the complete filename and extension. Line ranges are not supported.
|
|
17
|
+
|
|
18
|
+
`-t` matches the full test name. Vitest 5 joins suite names and the test name with `>`. A pattern for one name segment avoids separator differences between major versions.
|
|
19
|
+
|
|
20
|
+
`related` follows imports from the specified source files. `--changed` uses Git changes and their affected tests. Neither proves that an external service integration works.
|
|
21
|
+
|
|
22
|
+
Inspect `vitest list` when selection gives no tests. Configuration include patterns still apply to positional filters. Use [tags](features-test-tags.md) for category expressions.
|
|
23
|
+
|
|
24
|
+
Source: [Test filtering](https://vitest.dev/guide/filtering).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Mocking
|
|
2
|
+
|
|
3
|
+
Keep application logic real where practical. Mock external service boundaries with the behavior that each test requires.
|
|
4
|
+
|
|
5
|
+
`vi.mock` replaces an imported module before static imports execute. Put `vi.mock`, `vi.unmock`, and `vi.hoisted` at module scope. Vitest 5 rejects these calls inside suites, tests, functions, or blocks. Use `vi.hoisted` for values that a mock factory needs before imports.
|
|
6
|
+
|
|
7
|
+
The following example assumes an adjacent `gateway.ts` module with a `read` export:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { describe, expect, test, vi } from "vitest";
|
|
11
|
+
import { read } from "./gateway";
|
|
12
|
+
|
|
13
|
+
const mocks = vi.hoisted(() => ({
|
|
14
|
+
read: vi.fn<(id: string) => Promise<string>>(),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
vi.mock(import("./gateway"), () => ({ read: mocks.read }));
|
|
18
|
+
|
|
19
|
+
describe("gateway substitution", () => {
|
|
20
|
+
test("returns the configured response", async () => {
|
|
21
|
+
mocks.read.mockResolvedValueOnce("ready");
|
|
22
|
+
await expect(read("record-1")).resolves.toBe("ready");
|
|
23
|
+
expect(mocks.read).toHaveBeenCalledWith("record-1");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Use `vi.doMock` for subsequent dynamic imports when the factory needs runtime values. It does not replace existing static imports. Use `importOriginal` for partial replacements. Include a `default` property when the module has a default export.
|
|
29
|
+
|
|
30
|
+
`vi.mocked` changes TypeScript's view of a value. It does not create a runtime mock. Browser Mode requires `{ spy: true }` when tracking native module exports.
|
|
31
|
+
|
|
32
|
+
Sources: [Module mocking](https://vitest.dev/guide/mocking/modules), [Vi API](https://vitest.dev/api/vi).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Reporters
|
|
2
|
+
|
|
3
|
+
Select terminal output for developers and machine output for CI consumers. Configure reporters at the root when using projects.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { configDefaults, defineConfig } from "vitest/config";
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
test: {
|
|
10
|
+
reporters: [...configDefaults.reporters, "junit"],
|
|
11
|
+
outputFile: { junit: "reports/tests.xml" },
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
An explicit reporter list replaces the automatic selection. Extend `configDefaults.reporters` when the task needs the default selection as well. Without explicit configuration, Vitest selects output for the execution environment. It can add GitHub Actions output or select compact output for coding agents.
|
|
17
|
+
|
|
18
|
+
Use `verbose` when individual test names help diagnosis. Use JSON or JUnit for a machine consumer. Specify output paths when CI requires a stable artifact location. The HTML reporter uses its `outputDir` option. Check whether its companion package is installed before use.
|
|
19
|
+
|
|
20
|
+
Keep test reports separate from coverage reports. A passing machine report does not establish coverage thresholds or external service acceptance. Check the command exit status as well as the report file.
|
|
21
|
+
|
|
22
|
+
Source: [Reporters](https://vitest.dev/guide/reporters).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Snapshots
|
|
2
|
+
|
|
3
|
+
Use snapshots for output whose complete shape matters. Use direct assertions when a small contract gives clearer failure evidence.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { describe, expect, test } from "vitest";
|
|
7
|
+
|
|
8
|
+
describe("status serialization", () => {
|
|
9
|
+
test("keeps the status text", () => {
|
|
10
|
+
expect("ready").toMatchInlineSnapshot('"ready"');
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Use `toMatchSnapshot` for a separate snapshot file. Use `toMatchInlineSnapshot` when the expected output belongs beside the test. Await `toMatchFileSnapshot` for a file comparison.
|
|
16
|
+
|
|
17
|
+
Stabilize dates, generated identifiers, and ordering before snapshot comparison. Use property matchers when specific values may vary. Use custom serializers only when they improve the result's meaning.
|
|
18
|
+
|
|
19
|
+
Inspect each snapshot change before acceptance. Run `vitest run <file> --update` through the local runner for an intended update. Commit the snapshot with its test. An update can record a defect if the received output is wrong.
|
|
20
|
+
|
|
21
|
+
Use the context's `expect` for concurrent tests. Browser screenshots and ARIA snapshots require their applicable browser APIs. A DOM serialization does not prove layout, focus behavior, or accessibility.
|
|
22
|
+
|
|
23
|
+
Source: [Snapshots](https://vitest.dev/guide/snapshot).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Test tags
|
|
2
|
+
|
|
3
|
+
Tags require Vitest 4.1 or later. Use tags for categories that span files and share timeout or retry options. Use projects when environments or worker settings differ.
|
|
4
|
+
|
|
5
|
+
Declare each tag in the configuration:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { defineConfig } from "vitest/config";
|
|
9
|
+
|
|
10
|
+
export default defineConfig({
|
|
11
|
+
test: {
|
|
12
|
+
tags: [{ name: "database", timeout: 30_000 }, { name: "slow" }],
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Apply `{ tags: ["database"] }` in a test's options. Suite tags apply to child tests. A `@module-tag` comment applies to all tests in the file. Unknown tags fail by default through `strictTags`. Keep this check unless the task requires permissive tags.
|
|
18
|
+
|
|
19
|
+
Run tag commands through the local installation:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npm exec --no -- vitest run --tags-filter "database && !slow"
|
|
23
|
+
npm exec --no -- vitest --list-tags
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Expressions support conjunction, disjunction, negation, parentheses, and wildcard names. When tags conflict, lower numeric priorities win. Tag order resolves remaining conflicts. Explicit test options take priority over tags.
|
|
27
|
+
|
|
28
|
+
Use `TestRunner.matchesTags` when expensive setup depends on the active tag expression. Check its installed API before use. Do not add retries to a tag as the only correction for unstable tests.
|
|
29
|
+
|
|
30
|
+
Sources: [Test tags](https://vitest.dev/guide/test-tags), [Tag configuration](https://vitest.dev/config/tags).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Version compatibility
|
|
2
|
+
|
|
3
|
+
Use installed package types when documentation describes a different release. Use versioned documentation for Vitest 4 tasks.
|
|
4
|
+
|
|
5
|
+
| Area | Vitest 5 behavior | Action |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| Runtime | Requires Node.js 22.12 or later and Vite 6.4 or later | Check the installed package's engine constraints. |
|
|
8
|
+
| Mock history | `clearMocks` defaults to `true` | Make required calls inside each test or its setup. |
|
|
9
|
+
| Name filters | Full names use `>` between suite segments | Match one segment or use an explicit separator. |
|
|
10
|
+
| Inline projects | Root configuration applies by default | Inspect inherited arrays and setup files. |
|
|
11
|
+
| Referenced projects | Configuration files retain independent settings | Share configuration explicitly when necessary. |
|
|
12
|
+
| Hoisted mocks | Nested `vi.mock`, `vi.unmock`, and `vi.hoisted` calls throw | Put these calls at module scope. |
|
|
13
|
+
| Benchmarks | Tests receive the `bench` fixture | Replace top-level `bench` imports during migration. |
|
|
14
|
+
|
|
15
|
+
Inline projects can share their declaring Vite server in Vitest 5. Inspect plugin initialization when project behavior changes. Use `sharedViteServer: false` only when separate initialization is necessary.
|
|
16
|
+
|
|
17
|
+
Vitest 4 benchmark examples use a different API. Do not copy them into Vitest 5 tests. Keep companion Vitest packages aligned with the runner version.
|
|
18
|
+
|
|
19
|
+
Sources: [Vitest 5 migration](https://vitest.dev/guide/migration/), [Vitest 4 documentation](https://v4.vitest.dev/guide/).
|
|
@@ -12,9 +12,9 @@ Oxlint + Oxfmt (the underlying engine) provides robust linting and formatting. M
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Application Permissions
|
|
16
16
|
|
|
17
|
-
Preserve existing authentication and workspace role behavior during feature work, including demos. Use [
|
|
17
|
+
Preserve existing authentication and workspace role behavior during feature work, including demos. Use [application-permissions](.agents/skills/application-permissions/SKILL.md) for application content access, editing interactions, or authentication/context changes.
|
|
18
18
|
|
|
19
19
|
The default development role is `owner`, so testing only with that role can miss permission errors affecting other users. When verifying role-dependent behavior, temporarily change the role in the `import.meta.env.DEV` branch of [lib/user-context.server.ts](lib/user-context.server.ts):
|
|
20
20
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Generated by React Router
|
|
2
|
+
|
|
3
|
+
import "react-router"
|
|
4
|
+
|
|
5
|
+
declare module "react-router" {
|
|
6
|
+
interface Register {
|
|
7
|
+
pages: Pages
|
|
8
|
+
routeFiles: RouteFiles
|
|
9
|
+
routeModules: RouteModules
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type Pages = {
|
|
14
|
+
"/": {
|
|
15
|
+
params: {};
|
|
16
|
+
};
|
|
17
|
+
"/resources/files": {
|
|
18
|
+
params: {};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type RouteFiles = {
|
|
23
|
+
"root.tsx": {
|
|
24
|
+
id: "root";
|
|
25
|
+
page: "/" | "/resources/files";
|
|
26
|
+
};
|
|
27
|
+
"routes/home.tsx": {
|
|
28
|
+
id: "routes/home";
|
|
29
|
+
page: "/";
|
|
30
|
+
};
|
|
31
|
+
"routes/files.ts": {
|
|
32
|
+
id: "routes/files";
|
|
33
|
+
page: "/resources/files";
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type RouteModules = {
|
|
38
|
+
"root": typeof import("./app/root.tsx");
|
|
39
|
+
"routes/home": typeof import("./app/routes/home.tsx");
|
|
40
|
+
"routes/files": typeof import("./app/routes/files.ts");
|
|
41
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Generated by React Router
|
|
2
|
+
|
|
3
|
+
declare module "virtual:react-router/server-build" {
|
|
4
|
+
import { ServerBuild } from "react-router";
|
|
5
|
+
export const assets: ServerBuild["assets"];
|
|
6
|
+
export const assetsBuildDirectory: ServerBuild["assetsBuildDirectory"];
|
|
7
|
+
export const basename: ServerBuild["basename"];
|
|
8
|
+
export const entry: ServerBuild["entry"];
|
|
9
|
+
export const future: ServerBuild["future"];
|
|
10
|
+
export const isSpaMode: ServerBuild["isSpaMode"];
|
|
11
|
+
export const prerender: ServerBuild["prerender"];
|
|
12
|
+
export const publicPath: ServerBuild["publicPath"];
|
|
13
|
+
export const routeDiscovery: ServerBuild["routeDiscovery"];
|
|
14
|
+
export const routes: ServerBuild["routes"];
|
|
15
|
+
export const ssr: ServerBuild["ssr"];
|
|
16
|
+
export const allowedActionOrigins: ServerBuild["allowedActionOrigins"];
|
|
17
|
+
export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"];
|
|
18
|
+
}
|