@owlmeans/test-integration 0.1.7 → 0.1.8
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
|
@@ -9,3 +9,20 @@ Helpers exported here:
|
|
|
9
9
|
- `registerCleanup(fn)` + `runCleanups()` — opt-in `afterAll` cleanup queue.
|
|
10
10
|
|
|
11
11
|
Specs do not call services through these helpers — they consume the per-package real test context built in `tests/context.ts` and only check `gates.<svc>.skip` to self-skip when the dependency is missing. See `testing-integration` skill for the full pattern.
|
|
12
|
+
|
|
13
|
+
<!-- owlmeans:agent-guidance:start -->
|
|
14
|
+
## Agent guidance
|
|
15
|
+
|
|
16
|
+
This package ships embedded Claude Code skills and GitHub Copilot instructions under
|
|
17
|
+
`agent-meta/`. After installing your `@owlmeans/*` packages, run the OwlMeans
|
|
18
|
+
agent-skills installer to place them into your project's native locations
|
|
19
|
+
(`.claude/skills/` and `.github/instructions/`):
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npx @owlmeans/agent-skills
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The embedded files are version-matched to this package release. Do not edit them
|
|
26
|
+
directly — they are regenerated on each publish. To contribute guidance edits,
|
|
27
|
+
open a PR against the source monorepo.
|
|
28
|
+
<!-- owlmeans:agent-guidance:end -->
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*.test.ts, **/*.spec.ts, **/*.ts"
|
|
3
|
+
---
|
|
4
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
5
|
+
|
|
6
|
+
# Category C — Integration Tests (env-gated)
|
|
7
|
+
|
|
8
|
+
- Tests in `<your-package>/tests/*.spec.ts`. Use `bun:test`.
|
|
9
|
+
- No mocks. Connect to real MongoDB / Redis / S3 / Kubernetes via the env values supplied by `<root>/.env`.
|
|
10
|
+
- Open the gate at the top of `tests/context.ts` via `mongoGate()` / `redisGate()` / `s3Gate()` / `kubeGate()`. If `gate.skip`, do **not** register that service in the test context, and have specs self-skip with `gate.reason`.
|
|
11
|
+
- Always `randomNamespace(prefix)` databases / key prefixes / S3 prefixes for parallel safety.
|
|
12
|
+
- Always `registerCleanup(fn)` for resources you provision; call `runCleanups()` in `afterAll`.
|
|
13
|
+
- `<root>/.env.example` is the authoritative documentation of every variable. Add a new key there with a comment when you introduce a new gate.
|
|
14
|
+
- Per-package `package.json` script: `"test": "bun test ./tests"`. Long round-trips: bump timeout in a per-package `bunfig.toml`.
|
|
15
|
+
- Cover `.claude/skills/<pkg>/SKILL.md` and `README.md` cases first.
|
|
16
|
+
- Max 3-4 tests per method/function.
|
|
17
|
+
|
|
18
|
+
See `.claude/skills/testing-integration/SKILL.md` for the full pattern.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"package": "@owlmeans/test-integration",
|
|
4
|
+
"version": "0.1.8",
|
|
5
|
+
"generatedAt": "2026-06-11T16:30:27.166Z",
|
|
6
|
+
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
|
+
"entries": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "skill",
|
|
10
|
+
"name": "testing-integration",
|
|
11
|
+
"category": "package-specific",
|
|
12
|
+
"file": "skills/testing-integration/SKILL.md",
|
|
13
|
+
"canonicalPath": ".claude/skills/testing-integration/SKILL.md"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"kind": "instruction",
|
|
17
|
+
"name": "testing-integration",
|
|
18
|
+
"category": "package-specific",
|
|
19
|
+
"file": "instructions/testing-integration.instructions.md",
|
|
20
|
+
"canonicalPath": ".github/instructions/testing-integration.instructions.md"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-integration
|
|
3
|
+
description: Category-C integration tests for OwlMeans Common packages that talk to external services (MongoDB, Redis, S3, Kubernetes). Env-gated, no mocks, conditional context provisioning. Auto-invoked when writing tests in mongo*, redis*, kluster, storage*, image-resource, server-api, server-app, queue.
|
|
4
|
+
---
|
|
5
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
6
|
+
|
|
7
|
+
# Integration Tests — Category C
|
|
8
|
+
|
|
9
|
+
Category C applies to packages that integrate with external services: `mongo`, `mongo-resource`, `redis`, `redis-resource`, `kluster`, `storage-common`, `storage-resource`, `image-resource`, `server-api`, `server-app`, `queue`. These tests **never** mock the external service. They run only when the corresponding env vars are set, and they self-skip cleanly when those variables are missing.
|
|
10
|
+
|
|
11
|
+
## Helpers from `@owlmeans/test-integration`
|
|
12
|
+
|
|
13
|
+
| Helper | Purpose |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `mongoGate()`, `redisGate()`, `s3Gate()`, `kubeGate()` | Read env, return `{ skip, reason?, env }`. |
|
|
16
|
+
| `randomNamespace(prefix, len?)` | DB / key / object-prefix namespacing for parallel-safe runs. |
|
|
17
|
+
| `registerCleanup(fn)` + `runCleanups()` | LIFO cleanup queue for `afterAll`. |
|
|
18
|
+
|
|
19
|
+
The driver libraries (`mongodb`, `ioredis`, `@aws-sdk/client-s3`, `@kubernetes/client-node`) stay where they already live — in the consuming integration packages — and are imported directly in those packages' `tests/`.
|
|
20
|
+
|
|
21
|
+
## Env contract
|
|
22
|
+
|
|
23
|
+
`/.env.example` documents every required variable, grouped by service, with comments. The single `.env` at the monorepo root supplies real values for local runs. CI sets them via secrets. **Empty value = skip** — never a failure.
|
|
24
|
+
|
|
25
|
+
When a required variable is empty:
|
|
26
|
+
1. The corresponding gate reports `skip: true`.
|
|
27
|
+
2. The per-package `tests/context.ts` does **not** register the dependent service in the real context.
|
|
28
|
+
3. Specs that touch that service self-skip with the reason printed.
|
|
29
|
+
|
|
30
|
+
## `tests/context.ts` pattern
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { mongoGate, randomNamespace, registerCleanup } from '@owlmeans/test-integration'
|
|
34
|
+
|
|
35
|
+
let cached: { gate: ReturnType<typeof mongoGate>, dbName: string } | null = null
|
|
36
|
+
|
|
37
|
+
export const getTestEnv = () => {
|
|
38
|
+
if (cached != null) return cached
|
|
39
|
+
const gate = mongoGate()
|
|
40
|
+
const dbName = randomNamespace(process.env.MONGO_TEST_DB_PREFIX ?? 'omt')
|
|
41
|
+
cached = { gate, dbName }
|
|
42
|
+
if (!gate.skip) {
|
|
43
|
+
registerCleanup(async () => {
|
|
44
|
+
const { MongoClient } = await import('mongodb')
|
|
45
|
+
const client = new MongoClient(gate.env.MONGO_URL!)
|
|
46
|
+
try { await client.connect(); await client.db(dbName).dropDatabase() }
|
|
47
|
+
finally { await client.close() }
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
return cached
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Spec shape
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { afterAll, describe, expect, test } from 'bun:test'
|
|
58
|
+
import { runCleanups } from '@owlmeans/test-integration'
|
|
59
|
+
import { getTestEnv } from './context.js'
|
|
60
|
+
|
|
61
|
+
const env = getTestEnv()
|
|
62
|
+
|
|
63
|
+
afterAll(async () => { await runCleanups() })
|
|
64
|
+
|
|
65
|
+
describe('@owlmeans/<pkg> — <feature>', () => {
|
|
66
|
+
if (env.gate.skip) {
|
|
67
|
+
test.skip(env.gate.reason ?? '<svc> gate closed', () => {})
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
test('round-trips a record via the real <svc>', async () => {
|
|
71
|
+
/* connect, exercise, assert */
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Wiring `bun test`
|
|
77
|
+
|
|
78
|
+
Per-package `package.json`:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
"scripts": {
|
|
82
|
+
"test": "bun test ./tests"
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The Bun runtime auto-loads `<root>/.env` when the test command runs from a workspace package. If you need to override, `bun test --env-file=../../.env` works. Long-running specs may need a higher timeout — set it locally in a per-package `bunfig.toml`:
|
|
87
|
+
|
|
88
|
+
```toml
|
|
89
|
+
[test]
|
|
90
|
+
timeout = 60000
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Rules
|
|
94
|
+
|
|
95
|
+
- **No mocks.** The whole point of category C is to exercise the real driver against a real service.
|
|
96
|
+
- **Always namespace.** Use `randomNamespace(prefix)` for DBs, key prefixes, and S3 object prefixes so parallel runs don't collide.
|
|
97
|
+
- **Always clean up.** `registerCleanup(fn)` + `runCleanups()` in `afterAll`. A failing cleanup is logged, not raised — failure must show up in the test, not the teardown.
|
|
98
|
+
- **Cover SKILL.md cases first.**
|
|
99
|
+
- **Max 3-4 tests per method/function.**
|
|
100
|
+
- **CI runs C only when secrets are set.** Locally, an empty `.env` produces a clean skip.
|
|
101
|
+
|
|
102
|
+
## When the env is partially populated
|
|
103
|
+
|
|
104
|
+
Each gate fails closed. A test that needs both `S3_KEY` and `S3_SECRET` does not run if only one is set — `s3Gate()` reports `skip: true`. This is intentional: a half-configured environment must not produce false positives or partial coverage.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/test-integration",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@owlmeans/test": "^0.1.
|
|
24
|
+
"@owlmeans/test": "^0.1.8"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@owlmeans/dep-config": "^0.1.
|
|
27
|
+
"@owlmeans/dep-config": "^0.1.8",
|
|
28
28
|
"@types/bun": "^1.3.0",
|
|
29
29
|
"nodemon": "^3.1.11",
|
|
30
30
|
"typescript": "^6.0.2"
|