@owlmeans/test 0.1.18-rc.35 → 0.1.18-rc.36
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/README.md
CHANGED
|
@@ -1,14 +1,130 @@
|
|
|
1
1
|
# @owlmeans/test
|
|
2
2
|
|
|
3
|
-
Foundation helpers shared by the OwlMeans test packages and individual package test suites
|
|
3
|
+
Foundation helpers shared by the OwlMeans test packages and individual package test suites: the
|
|
4
|
+
repo-root `.env` loader, environment gates that let a spec self-skip with a printed reason, and a
|
|
5
|
+
JSON fixture loader. Every package's `tests/` uses it directly or through one of the harness
|
|
6
|
+
packages built on it. It holds no auth mocks, no service gates and no browser driver — those are
|
|
7
|
+
`@owlmeans/test-auth` (category B), `@owlmeans/test-integration` (category C) and
|
|
8
|
+
`@owlmeans/test-ui` (category D). Tests run on `bun:test`; this package adds no runner. The
|
|
9
|
+
package's skills are `testing-overview` (which category a package is in) and `testing-unit`.
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
- `envHelper.requireEnv(keys)` — returns `{ ok: true }` or `{ skip: true, reason }` so callers can `test.skip(...)` when an integration variable is missing.
|
|
7
|
-
- `envHelper.hasEnv(key)` — boolean shorthand for conditional service provisioning in `tests/context.ts`.
|
|
8
|
-
- `makeGates(spec)` — builds a frozen record of `{ <name>: { skip, reason } }` so a per-package `tests/context.ts` exposes one source of truth and individual specs can self-skip.
|
|
9
|
-
- `loadFixture<T>(relPath)` — JSON fixture loader rooted at the consuming package's `tests/fixtures/`.
|
|
11
|
+
## Installation
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
```bash
|
|
14
|
+
bun add -d @owlmeans/test@^0.1.18-rc.36
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Concepts
|
|
18
|
+
|
|
19
|
+
- **Env file** — `<monorepo-root>/.env`, found by walking up from `process.cwd()` to a directory
|
|
20
|
+
holding `bun.lock`, or a `package.json` beside a `packages/` directory. Merged into `process.env`
|
|
21
|
+
once per process; a variable already set to a non-empty value wins. A missing file is not an error.
|
|
22
|
+
- **Gate** — `EnvGate`: `{ ok: true }` when every required variable is set, otherwise
|
|
23
|
+
`{ skip: true, reason }` naming the missing ones.
|
|
24
|
+
- **Gate map** — `makeGates({ name: [envKey, …] })`, a frozen record built once in a suite's
|
|
25
|
+
`tests/context.ts`; specs read it to choose `test` or `test.skip`.
|
|
26
|
+
- **Fixture** — a JSON file under the consuming package's `tests/`, read relative to it.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Declare the suite's gates
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// tests/context.ts
|
|
34
|
+
import { makeGates } from '@owlmeans/test'
|
|
35
|
+
|
|
36
|
+
export const gates = makeGates({
|
|
37
|
+
openrouter: ['OPENROUTER_SECRET'],
|
|
38
|
+
anthropic: ['ANTHROPIC_SECRET'],
|
|
39
|
+
})
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Self-skip a spec
|
|
43
|
+
|
|
44
|
+
Bun picks `test` or `test.skip` synchronously, so decide from the gate at module scope:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// tests/inference.spec.ts
|
|
48
|
+
import { describe, expect, test } from 'bun:test'
|
|
49
|
+
import { isSkip } from '@owlmeans/test'
|
|
50
|
+
import { gates } from './context.js'
|
|
51
|
+
|
|
52
|
+
const gate = gates.openrouter
|
|
53
|
+
const it = isSkip(gate) ? test.skip : test
|
|
54
|
+
|
|
55
|
+
describe('llm — openrouter', () => {
|
|
56
|
+
it(`answers a prompt${isSkip(gate) ? ` (${gate.reason})` : ''}`, async () => {
|
|
57
|
+
/* exercise the real provider */
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Read the environment directly
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { envHelper } from '@owlmeans/test'
|
|
66
|
+
|
|
67
|
+
envHelper.loadEnv() // idempotent; `{ force: true }` re-reads
|
|
68
|
+
envHelper.loadEnv({ file: '/path/to/other/.env' }) // a workspace shaped differently
|
|
69
|
+
|
|
70
|
+
if (envHelper.hasEnv('MONGO_URL')) {
|
|
71
|
+
/* provision the optional service in tests/context.ts */
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const gate = envHelper.requireEnv(['SMTP_HOST', 'SMTP_PORT'])
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Load a fixture
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { loadFixture } from '@owlmeans/test'
|
|
81
|
+
|
|
82
|
+
const profile = loadFixture<ProfileRecord>('fixtures/profile.json') // <package>/tests/fixtures/profile.json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## API
|
|
86
|
+
|
|
87
|
+
| Symbol | Kind | Purpose |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `envHelper` (`createEnvHelper()`) | helper | The env loader and gates below |
|
|
90
|
+
| `envHelper.loadEnv(opts?)` | member | Locate `<monorepo-root>/.env`, parse it, merge into `process.env` (idempotent; no-op for variables Bun already loaded via `--env-file`) |
|
|
91
|
+
| `envHelper.hasEnv(key)` | member | `loadEnv()`, then whether the variable is set and non-empty |
|
|
92
|
+
| `envHelper.requireEnv(keys)` | member | `{ ok: true }` or `{ skip: true, reason }` so callers can `test.skip(...)` when an integration variable is missing |
|
|
93
|
+
| `makeGates(spec)` | function | Frozen record of `{ <name>: EnvGate }` — one source of truth in `tests/context.ts` |
|
|
94
|
+
| `isSkip(gate)` | function | Type guard narrowing an `EnvGate` to `{ skip: true, reason }` |
|
|
95
|
+
| `loadFixture<T>(relPath)` | function | JSON fixture loader rooted at the consuming package's `tests/` |
|
|
96
|
+
|
|
97
|
+
| Type | Purpose |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `EnvGate`, `EnvOk`, `EnvSkip` | Gate outcome union and its branches |
|
|
100
|
+
| `GateSpec`, `Gates<S>` | `{ name: string[] }` input and the frozen gate map it produces |
|
|
101
|
+
| `LoadEnvOptions` | `{ force?, file? }` |
|
|
102
|
+
| `EnvHelper` | The helper's interface |
|
|
103
|
+
|
|
104
|
+
## Test layout
|
|
105
|
+
|
|
106
|
+
Tests are located at `packages/<pkg>/tests/`, named `*.spec.ts`, and run with `bun test ./tests`
|
|
107
|
+
from the package root. List `"./tests/**/*"` in the package `tsconfig.json` `exclude` so `tsc -b`
|
|
108
|
+
never compiles specs. One real context per package lives in `tests/context.ts`; specs import its
|
|
109
|
+
helper instead of building contexts themselves.
|
|
110
|
+
|
|
111
|
+
## Common pitfalls
|
|
112
|
+
|
|
113
|
+
- Awaiting anything before choosing `test` / `test.skip` — the choice must be a value already in hand.
|
|
114
|
+
- A missing variable must skip, never fail; do not throw from a gate.
|
|
115
|
+
- `loadFixture` resolves against `process.cwd()`, which `bun test` sets to the package root; running
|
|
116
|
+
specs from another directory breaks the path.
|
|
117
|
+
- A workspace without `bun.lock` and without a `packages/` directory beside its `package.json` is not
|
|
118
|
+
found by `loadEnv` — pass `file` explicitly.
|
|
119
|
+
- Do not add mocks here; auth mocks belong in `@owlmeans/test-auth`, and anything else is an
|
|
120
|
+
integration test.
|
|
121
|
+
|
|
122
|
+
## Related packages
|
|
123
|
+
|
|
124
|
+
- [`@owlmeans/test-auth`](../test-auth) — auth/authz mocks for category-B unit tests
|
|
125
|
+
- [`@owlmeans/test-integration`](../test-integration) — service gates, namespaces and cleanup for category-C tests
|
|
126
|
+
- [`@owlmeans/test-ui`](../test-ui) — Playwright-driven component acceptance for category D
|
|
127
|
+
- [`@owlmeans/context`](../context) — the real context a suite's `tests/context.ts` builds
|
|
12
128
|
|
|
13
129
|
<!-- owlmeans:agent-guidance:start -->
|
|
14
130
|
## Agent guidance
|
|
@@ -18,7 +134,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
18
134
|
your project's skill store (`.agents/skills/`):
|
|
19
135
|
|
|
20
136
|
```sh
|
|
21
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
137
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.52
|
|
22
138
|
```
|
|
23
139
|
|
|
24
140
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/test",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.36",
|
|
5
|
+
"generatedAt": "2026-10-08T21:27:54.292Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -31,9 +31,9 @@ New auth mocks belong in `@owlmeans/test-auth`, never in a package's own `tests/
|
|
|
31
31
|
|
|
32
32
|
## Package → category map
|
|
33
33
|
|
|
34
|
-
All
|
|
34
|
+
All 103 packages, one category each.
|
|
35
35
|
|
|
36
|
-
- **A** (
|
|
36
|
+
- **A** (52): `agent`, `agent-common`, `agent-skills`, `api`, `api-config`, `api-config-client`, `api-config-server`, `astro`, `basic-ids`, `client-config`, `client-context`, `client-entrypoint`, `client-flow`, `client-job`, `client-resource`, `client-route`, `client-socket`, `common-inquiry`, `config`, `consent`, `context`, `create-app`, `entrypoint`, `error`, `flow`, `i18n`, `iam`, `image-resource`, `llm-common`, `mailer`, `payment`, `queue`, `resource`, `route`, `router`, `server-auth-identity`, `server-context`, `server-entrypoint`, `server-iam`, `server-job`, `server-route`, `server-config`, `server-socket`, `server-wl`, `socket`, `state`, `static-resource`, `storage-common`, `web-db`, `web-gtm`, `web-inquiry`, `web-router-react-router`
|
|
37
37
|
- **B** (20): `auth`, `auth-common`, `auth-otp`, `basic-envelope`, `basic-keys`, `client-auth`, `client-did`, `client-iam`, `client-payment`, `did`, `mui-oidc-rp`, `oidc`, `server-auth`, `server-auth-otp`, `server-oidc-provider`, `server-oidc-rp`, `web-auth`, `web-oidc-provider`, `web-oidc-rp`, `wled`
|
|
38
38
|
- **C** (15): `kluster`, `llm` (live inference providers), `mailer-smtp`, `mongo`, `mongo-resource`, `planning-postgres`, `postgres`, `postgres-resource`, `redis`, `redis-queue`, `redis-resource`, `server-api`, `server-app`, `server-mailer-mailgun`, `storage-resource`
|
|
39
39
|
- **D** (11): `client`, `client-i18n`, `client-panel`, `client-wl`, `mui-panel`, `web-client`, `web-consent`, `web-flow`, `web-panel`, `web-router`, `web-wl`
|
|
@@ -52,8 +52,8 @@ while one whose code issues real commands against the service is C even when it
|
|
|
52
52
|
`web-router` is D, not A: it drives the History API, so its routing behaviour is only observable in
|
|
53
53
|
a browser and its specs mount a real harness in chromium. A client-side package stays in A when it
|
|
54
54
|
ships no component at all — `client-config`, `client-context`, `client-entrypoint`, `client-flow`,
|
|
55
|
-
`client-job`, `client-resource`, `client-route`, `client-socket`, `web-db`, `web-gtm`
|
|
56
|
-
`web-router-react-router` are services, models and adapters, so `bun test` alone covers them.
|
|
55
|
+
`client-job`, `client-resource`, `client-route`, `client-socket`, `web-db`, `web-gtm`, `web-inquiry`
|
|
56
|
+
and `web-router-react-router` are services, models and adapters, so `bun test` alone covers them.
|
|
57
57
|
|
|
58
58
|
A new package takes the category its own behaviour implies: an external service it cannot fake ⇒ C,
|
|
59
59
|
a rendered React surface ⇒ D, an authenticated identity it must stand in for ⇒ B, otherwise A.
|
|
@@ -6,7 +6,7 @@ description: Category-A unit tests for OwlMeans Common packages — no mocks, re
|
|
|
6
6
|
|
|
7
7
|
# Unit Tests — Category A (no mocks)
|
|
8
8
|
|
|
9
|
-
**Install:** `"@owlmeans/test": "^0.1.18-rc.
|
|
9
|
+
**Install:** `"@owlmeans/test": "^0.1.18-rc.36"` in `devDependencies`
|
|
10
10
|
|
|
11
11
|
Apply this skill when adding tests to packages in category A (see `testing-overview`). The list includes core abstractions (`context`, `config`, `error`, `entrypoint`, `route`, `resource`, …) and platform-agnostic services (`api`, `state`, `flow`, `i18n`, `client-flow`, `client-socket`, `client-job`, `server-route`, `server-context`, `web-db`, …).
|
|
12
12
|
|