@classytic/arc-testkit 0.1.1 → 0.2.0
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 +65 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +27 -0
- package/package.json +35 -20
- package/dist/index-C0gS_j5G.d.ts +0 -29
- package/dist/index.js +0 -62
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# @classytic/arc-testkit
|
|
2
|
+
|
|
3
|
+
> Boot a real [`@classytic/arc`](https://www.npmjs.com/package/@classytic/arc) app around the module(s) under test, on a real (in-memory) database.
|
|
4
|
+
|
|
5
|
+
The ecosystem's contributor contract for the `@classytic/arc-*` module fleet: **if your module boots green here, it composes into any arc host.**
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i -D @classytic/arc-testkit @classytic/mongokit mongodb-memory-server
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`@classytic/mongokit` + `mongodb-memory-server` are **optional peers** — needed only for the default backend, and dynamically imported so they never enter a production bundle. Pass your own `backend` to skip them entirely.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { bootModuleApp } from '@classytic/arc-testkit';
|
|
19
|
+
import { createAccountingModule } from '@classytic/arc-accounting';
|
|
20
|
+
|
|
21
|
+
const t = await bootModuleApp(({ connection }) => [
|
|
22
|
+
createAccountingModule({ connection, permissions }),
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
const res = await t.app.inject({ method: 'GET', url: '/accounting/accounts' });
|
|
26
|
+
expect(res.statusCode).toBe(200);
|
|
27
|
+
|
|
28
|
+
await t.close();
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The module input is a factory receiving `{ connection, mongoUri }` (or a plain module / array). It boots arc with `preset: 'testing'`, `auth: false` — override via `options.app`.
|
|
32
|
+
|
|
33
|
+
## Transactions
|
|
34
|
+
|
|
35
|
+
Modules that open multi-document transactions need a replica set:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const t = await bootModuleApp(({ connection }) => [createReservationModule({ connection, permissions })],
|
|
39
|
+
{ replset: true });
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Bring your own backend
|
|
43
|
+
|
|
44
|
+
The default backend is `mongoMemoryBackend()` from `@classytic/mongokit/testkit`. Override it to point at a shared server, a real Atlas cluster, or a different kit's backend — anything that satisfies the `TestBackend` shape (`setup() → { ctx: { connection, uri }, teardown }`):
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { mongoMemoryBackend } from '@classytic/mongokit/testkit';
|
|
48
|
+
|
|
49
|
+
const t = await bootModuleApp(mods, {
|
|
50
|
+
backend: mongoMemoryBackend({ uri: process.env.ATLAS_TEST_URI }), // real cluster
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## API
|
|
55
|
+
|
|
56
|
+
| Export | |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `bootModuleApp(modules, options?)` | boot arc around modules on a backend; returns `{ app, connection, mongoUri, close }` |
|
|
59
|
+
| `TestBackend` | the backend seam — `setup() → { ctx: { connection, uri }, teardown }` |
|
|
60
|
+
| `TestkitContext` | what a module factory receives: `{ connection, mongoUri }` |
|
|
61
|
+
| `BootModuleAppOptions` | `{ replset?, app?, backend? }` |
|
|
62
|
+
|
|
63
|
+
## License
|
|
64
|
+
|
|
65
|
+
MIT © Classytic
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BootModuleAppOptions as BootModuleAppOptions$1, BootModulesInput, ModuleTestApp as ModuleTestApp$1, TestkitContext as TestkitContext$1 } from "@classytic/arc/testing";
|
|
2
|
+
import { Connection } from "mongoose";
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
type TestkitContext = TestkitContext$1<Connection>;
|
|
5
|
+
type ModulesInput = BootModulesInput<Connection>;
|
|
6
|
+
type BootModuleAppOptions = BootModuleAppOptions$1<Connection>;
|
|
7
|
+
type ModuleTestApp = ModuleTestApp$1<Connection>;
|
|
8
|
+
declare function bootModuleApp(modules: ModulesInput, options?: BootModuleAppOptions): Promise<ModuleTestApp>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { BootModuleAppOptions, ModuleTestApp, ModulesInput, TestkitContext, bootModuleApp };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { bootModuleApp as bootModuleApp$1 } from "@classytic/arc/testing";
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
/**
|
|
4
|
+
* @classytic/arc-testkit — boots a REAL arc app around the module(s) under
|
|
5
|
+
* test on in-memory MongoDB. The contributor contract: if your module boots
|
|
6
|
+
* green here, it composes into any arc vertical.
|
|
7
|
+
*
|
|
8
|
+
* const t = await bootModuleApp(({ connection }) => [
|
|
9
|
+
* createAccountingModule({ connection, country, permissions }),
|
|
10
|
+
* ]);
|
|
11
|
+
* const res = await t.app.inject({ method: 'GET', url: '/accounting/accounts' });
|
|
12
|
+
* const engine = t.exports<AccountingEngine>('accounting'); // typed module export
|
|
13
|
+
* await t.close();
|
|
14
|
+
*
|
|
15
|
+
* Since arc 2.22 the harness itself lives in `@classytic/arc/testing`
|
|
16
|
+
* (upstreamed from this package — default-connection ownership, boot-failure
|
|
17
|
+
* cleanup, idempotent close, the typed `exports()` accessor, `sensible: false`
|
|
18
|
+
* and all). This package is now the MONGO-TYPED face of it: arc core stays
|
|
19
|
+
* DB-agnostic (`connection: unknown` generic), the module fleet is Mongoose —
|
|
20
|
+
* the wrapper pins `TConn = Connection` once so every module test gets a typed
|
|
21
|
+
* connection with zero casts.
|
|
22
|
+
*/
|
|
23
|
+
function bootModuleApp(modules, options = {}) {
|
|
24
|
+
return bootModuleApp$1(modules, options);
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { bootModuleApp };
|
package/package.json
CHANGED
|
@@ -1,40 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/arc-testkit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Boot a real @classytic/arc app around the module(s) under test on in-memory MongoDB — the ecosystem test harness. Thin Mongo-typed wrapper over @classytic/arc/testing (arc 2.22+). If your arc module boots green here, it composes into any arc host.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"license": "UNLICENSED",
|
|
7
|
-
"sideEffects": false,
|
|
8
6
|
"exports": {
|
|
9
7
|
".": {
|
|
10
|
-
"types": "./dist/index.d.
|
|
11
|
-
"default": "./dist/index.
|
|
12
|
-
}
|
|
13
|
-
"./package.json": "./package.json"
|
|
8
|
+
"types": "./dist/index.d.mts",
|
|
9
|
+
"default": "./dist/index.mjs"
|
|
10
|
+
}
|
|
14
11
|
},
|
|
12
|
+
"main": "./dist/index.mjs",
|
|
13
|
+
"types": "./dist/index.d.mts",
|
|
14
|
+
"sideEffects": false,
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
|
-
"README.md"
|
|
18
|
-
"CHANGELOG.md"
|
|
17
|
+
"README.md"
|
|
19
18
|
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=22"
|
|
24
|
+
},
|
|
20
25
|
"scripts": {
|
|
21
26
|
"build": "tsdown",
|
|
22
27
|
"typecheck": "tsc --noEmit",
|
|
23
|
-
"
|
|
28
|
+
"test": "vitest run --root ../.. packages/arc-testkit/tests",
|
|
29
|
+
"lint": "biome check src/",
|
|
30
|
+
"prepublishOnly": "node ../../scripts/prepublish-gate.mjs"
|
|
24
31
|
},
|
|
25
32
|
"dependencies": {
|
|
26
|
-
"mongodb-memory-server": "
|
|
33
|
+
"mongodb-memory-server": ">=10.0.0"
|
|
27
34
|
},
|
|
28
35
|
"peerDependencies": {
|
|
29
|
-
"@classytic/arc": ">=2.
|
|
36
|
+
"@classytic/arc": ">=2.23.0",
|
|
30
37
|
"mongoose": ">=9.4.1"
|
|
31
38
|
},
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
+
"keywords": [
|
|
40
|
+
"arc",
|
|
41
|
+
"fastify",
|
|
42
|
+
"testing",
|
|
43
|
+
"test-harness",
|
|
44
|
+
"mongodb",
|
|
45
|
+
"in-memory",
|
|
46
|
+
"classytic"
|
|
47
|
+
],
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"author": "Classytic",
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "https://github.com/classytic/arc-ecosystem.git",
|
|
53
|
+
"directory": "packages/arc-testkit"
|
|
39
54
|
}
|
|
40
55
|
}
|
package/dist/index-C0gS_j5G.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Connection } from "mongoose";
|
|
2
|
-
import { ArcModuleInput, CreateAppOptions } from "@classytic/arc/factory";
|
|
3
|
-
import { FastifyInstance } from "fastify";
|
|
4
|
-
|
|
5
|
-
//#region src/index.d.ts
|
|
6
|
-
interface TestkitContext {
|
|
7
|
-
connection: Connection;
|
|
8
|
-
mongoUri: string;
|
|
9
|
-
}
|
|
10
|
-
type ModulesInput = ArcModuleInput | readonly ArcModuleInput[] | ((ctx: TestkitContext) => ArcModuleInput | readonly ArcModuleInput[]);
|
|
11
|
-
interface BootModuleAppOptions {
|
|
12
|
-
/**
|
|
13
|
-
* Use a single-node replica set instead of a standalone mongod. Required
|
|
14
|
-
* when the domain under test uses multi-document transactions.
|
|
15
|
-
*/
|
|
16
|
-
replset?: boolean;
|
|
17
|
-
/** Merged over the testkit defaults (`preset: 'testing'`, `auth: false`). */
|
|
18
|
-
app?: Partial<CreateAppOptions>;
|
|
19
|
-
}
|
|
20
|
-
interface ModuleTestApp {
|
|
21
|
-
app: FastifyInstance;
|
|
22
|
-
connection: Connection;
|
|
23
|
-
mongoUri: string;
|
|
24
|
-
/** Close app → disconnect mongoose → stop the in-memory server. Idempotent. */
|
|
25
|
-
close(): Promise<void>;
|
|
26
|
-
}
|
|
27
|
-
declare function bootModuleApp(modules: ModulesInput, options?: BootModuleAppOptions): Promise<ModuleTestApp>;
|
|
28
|
-
//#endregion
|
|
29
|
-
export { BootModuleAppOptions, ModuleTestApp, ModulesInput, TestkitContext, bootModuleApp };
|
package/dist/index.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { MongoMemoryReplSet, MongoMemoryServer } from "mongodb-memory-server";
|
|
2
|
-
import mongoose from "mongoose";
|
|
3
|
-
import { createApp } from "@classytic/arc/factory";
|
|
4
|
-
//#region src/index.ts
|
|
5
|
-
/**
|
|
6
|
-
* @classytic/spine-testkit — boots a REAL arc app around the module(s) under
|
|
7
|
-
* test on in-memory MongoDB (the Next.js `nextTestSetup` fixture-app pattern,
|
|
8
|
-
* backend-shaped). The contributor contract: if your module boots green here,
|
|
9
|
-
* it composes into any arc vertical.
|
|
10
|
-
*
|
|
11
|
-
* const t = await bootModuleApp(({ connection }) => [
|
|
12
|
-
* createAccountingModule({ connection, country, permissions }),
|
|
13
|
-
* ]);
|
|
14
|
-
* const res = await t.app.inject({ method: 'GET', url: '/accounting/accounts' });
|
|
15
|
-
* await t.close();
|
|
16
|
-
*
|
|
17
|
-
* Modules usually need the live DB connection in their deps, so the primary
|
|
18
|
-
* input is a FACTORY receiving `{ connection, mongoUri }` — mirroring the
|
|
19
|
-
* AppContext convention (wiki/modules.md). Plain module lists also accepted.
|
|
20
|
-
*/
|
|
21
|
-
async function bootModuleApp(modules, options = {}) {
|
|
22
|
-
const server = options.replset ? await MongoMemoryReplSet.create({ replSet: { count: 1 } }) : await MongoMemoryServer.create();
|
|
23
|
-
const mongoUri = server.getUri();
|
|
24
|
-
if (mongoose.connection.readyState !== 0) await mongoose.disconnect();
|
|
25
|
-
await mongoose.connect(mongoUri);
|
|
26
|
-
const connection = mongoose.connection;
|
|
27
|
-
const resolved = typeof modules === "function" ? modules({
|
|
28
|
-
connection,
|
|
29
|
-
mongoUri
|
|
30
|
-
}) : modules;
|
|
31
|
-
const list = Array.isArray(resolved) ? resolved : [resolved];
|
|
32
|
-
let app;
|
|
33
|
-
try {
|
|
34
|
-
app = await createApp({
|
|
35
|
-
preset: "testing",
|
|
36
|
-
auth: false,
|
|
37
|
-
sensible: false,
|
|
38
|
-
...options.app,
|
|
39
|
-
modules: list
|
|
40
|
-
});
|
|
41
|
-
await app.ready();
|
|
42
|
-
} catch (err) {
|
|
43
|
-
await mongoose.disconnect().catch(() => void 0);
|
|
44
|
-
await server.stop().catch(() => void 0);
|
|
45
|
-
throw err;
|
|
46
|
-
}
|
|
47
|
-
let closed = false;
|
|
48
|
-
return {
|
|
49
|
-
app,
|
|
50
|
-
connection,
|
|
51
|
-
mongoUri,
|
|
52
|
-
close: async () => {
|
|
53
|
-
if (closed) return;
|
|
54
|
-
closed = true;
|
|
55
|
-
await app.close().catch(() => void 0);
|
|
56
|
-
if (mongoose.connection.readyState !== 0) await mongoose.disconnect().catch(() => void 0);
|
|
57
|
-
await server.stop().catch(() => void 0);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
//#endregion
|
|
62
|
-
export { bootModuleApp };
|