@alloy-di/testing 0.1.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/LICENSE.md +21 -0
- package/README.md +56 -0
- package/dist/adapters/jest.d.ts +40 -0
- package/dist/adapters/jest.js +43 -0
- package/dist/adapters/node.d.ts +40 -0
- package/dist/adapters/node.js +43 -0
- package/dist/adapters/vitest.d.ts +40 -0
- package/dist/adapters/vitest.js +43 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/lib/core.d.ts +93 -0
- package/dist/lib/core.js +85 -0
- package/dist/lib/mocking.d.ts +23 -0
- package/dist/lib/mocking.js +105 -0
- package/dist/lib/registry.js +17 -0
- package/package.json +98 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 The Alloy DI Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# @alloy-di/testing
|
|
2
|
+
|
|
3
|
+
Runner-neutral test-container utilities for [Alloy DI](https://alloy-di.dev), with thin
|
|
4
|
+
adapters for popular test runners.
|
|
5
|
+
|
|
6
|
+
- `@alloy-di/testing` — the runner-neutral core (`createTestContainer`, mocking types). Requires
|
|
7
|
+
you to supply a `mockFn` when using `autoMock`.
|
|
8
|
+
- `@alloy-di/testing/vitest` — wires `vi.fn` from Vitest.
|
|
9
|
+
- `@alloy-di/testing/jest` — wires `jest.fn` from `@jest/globals`.
|
|
10
|
+
- `@alloy-di/testing/node` — wires `mock.fn()` from `node:test`.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { createTestContainer } from "@alloy-di/testing/vitest";
|
|
16
|
+
|
|
17
|
+
const test = createTestContainer({
|
|
18
|
+
autoMock: true,
|
|
19
|
+
target: UserService,
|
|
20
|
+
providers,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => test.restore());
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or let the adapter manage cleanup for you:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { setupAlloyTesting } from "@alloy-di/testing/vitest";
|
|
30
|
+
|
|
31
|
+
const alloyTesting = setupAlloyTesting(); // registers afterEach once
|
|
32
|
+
|
|
33
|
+
const test = alloyTesting.createTestContainer({
|
|
34
|
+
autoMock: true,
|
|
35
|
+
target: UserService,
|
|
36
|
+
providers,
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Importing an adapter never registers test hooks on its own — only `setupAlloyTesting()` does.
|
|
41
|
+
|
|
42
|
+
## Migration from `alloy-di/test`
|
|
43
|
+
|
|
44
|
+
`alloy-di/test` was removed in `alloy-di` 2.0. Replace:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { createTestContainer } from "alloy-di/test";
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
with:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { createTestContainer } from "@alloy-di/testing/vitest";
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The API is identical — only the import specifier changes.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { GenericSpy, MockFnFactory, MockOf } from "../lib/mocking.js";
|
|
2
|
+
import { CreateTestContainerOptions, FactoryOverrideSpec, OverrideSpec, TestContainerHandle, TestScopeHierarchy } from "../lib/core.js";
|
|
3
|
+
import { createToken } from "../index.js";
|
|
4
|
+
import { Mock } from "jest-mock";
|
|
5
|
+
|
|
6
|
+
//#region src/adapters/jest.d.ts
|
|
7
|
+
/** A Jest spy, as produced by `jest.fn()`. */
|
|
8
|
+
type JestSpy = Mock;
|
|
9
|
+
/** Options accepted by the Jest adapter (the `mockFn`/`resetFn` bindings are supplied for you). */
|
|
10
|
+
type JestTestContainerOptions = Omit<CreateTestContainerOptions<JestSpy>, "mockFn" | "resetFn">;
|
|
11
|
+
/**
|
|
12
|
+
* Create a test container wired to Jest spies (`jest.fn`). Does not register
|
|
13
|
+
* any cleanup hooks — call `handle.restore()` yourself, or use
|
|
14
|
+
* {@link setupAlloyTesting} for automatic cleanup.
|
|
15
|
+
*/
|
|
16
|
+
declare function createTestContainer(opts?: JestTestContainerOptions | OverrideSpec): TestContainerHandle<JestSpy> & {
|
|
17
|
+
getMock<T>(ctor: import("alloy-di/runtime").Newable<T>): MockOf<T, JestSpy> | undefined;
|
|
18
|
+
getMocks<T extends readonly import("alloy-di/runtime").Newable<unknown>[]>(ctors: T): { [K in keyof T]: T[K] extends import("alloy-di/runtime").Newable<infer I> ? MockOf<I, JestSpy> | undefined : never };
|
|
19
|
+
provideToken<T>(token: import("alloy-di/runtime").Token<T>, value: T): void;
|
|
20
|
+
provideFactory<T>(token: import("alloy-di/runtime").Token<T>, factory: import("alloy-di/runtime").FactoryFn<T>, options?: {
|
|
21
|
+
lifecycle?: import("alloy-di/runtime").ServiceScope;
|
|
22
|
+
}): void;
|
|
23
|
+
overrideFactory<T>(token: import("alloy-di/runtime").Token<T>, factory: import("alloy-di/runtime").FactoryFn<T>, options?: {
|
|
24
|
+
lifecycle?: import("alloy-di/runtime").ServiceScope;
|
|
25
|
+
}): void;
|
|
26
|
+
createScope(scopeName: import("alloy-di/runtime").ServiceScope): import("alloy-di/scopes").Scope;
|
|
27
|
+
spyOf<T>(ctor: import("alloy-di/runtime").Newable<T>, method: Extract<keyof T, string>): JestSpy | undefined;
|
|
28
|
+
clearMockSpies(): void;
|
|
29
|
+
};
|
|
30
|
+
type JestTestContainer = ReturnType<typeof createTestContainer>;
|
|
31
|
+
/**
|
|
32
|
+
* Register a Jest `afterEach` hook that restores and clears every container
|
|
33
|
+
* created through the returned `createTestContainer`. Call this once per test
|
|
34
|
+
* file (or in a shared setup file).
|
|
35
|
+
*/
|
|
36
|
+
declare function setupAlloyTesting(): {
|
|
37
|
+
createTestContainer(opts?: JestTestContainerOptions | OverrideSpec): JestTestContainer;
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { type CreateTestContainerOptions, type FactoryOverrideSpec, type GenericSpy, JestSpy, JestTestContainer, JestTestContainerOptions, type MockFnFactory, type MockOf, type OverrideSpec, type TestContainerHandle, type TestScopeHierarchy, createTestContainer, createToken, setupAlloyTesting };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createTestContainer as createTestContainer$1 } from "../lib/core.js";
|
|
2
|
+
import { createToken } from "../index.js";
|
|
3
|
+
import { afterEach, jest } from "@jest/globals";
|
|
4
|
+
//#region src/adapters/jest.ts
|
|
5
|
+
const binding = {
|
|
6
|
+
mockFn: () => jest.fn(),
|
|
7
|
+
resetFn: (spy) => {
|
|
8
|
+
spy.mockReset();
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Create a test container wired to Jest spies (`jest.fn`). Does not register
|
|
13
|
+
* any cleanup hooks — call `handle.restore()` yourself, or use
|
|
14
|
+
* {@link setupAlloyTesting} for automatic cleanup.
|
|
15
|
+
*/
|
|
16
|
+
function createTestContainer(opts) {
|
|
17
|
+
return createTestContainer$1({
|
|
18
|
+
...opts,
|
|
19
|
+
...binding
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Register a Jest `afterEach` hook that restores and clears every container
|
|
24
|
+
* created through the returned `createTestContainer`. Call this once per test
|
|
25
|
+
* file (or in a shared setup file).
|
|
26
|
+
*/
|
|
27
|
+
function setupAlloyTesting() {
|
|
28
|
+
const handles = /* @__PURE__ */ new Set();
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
for (const handle of [...handles].toReversed()) {
|
|
31
|
+
handle.clearMockSpies();
|
|
32
|
+
handle.restore();
|
|
33
|
+
}
|
|
34
|
+
handles.clear();
|
|
35
|
+
});
|
|
36
|
+
return { createTestContainer(opts) {
|
|
37
|
+
const handle = createTestContainer(opts);
|
|
38
|
+
handles.add(handle);
|
|
39
|
+
return handle;
|
|
40
|
+
} };
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { createTestContainer, createToken, setupAlloyTesting };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { GenericSpy, MockFnFactory, MockOf } from "../lib/mocking.js";
|
|
2
|
+
import { CreateTestContainerOptions, FactoryOverrideSpec, OverrideSpec, TestContainerHandle, TestScopeHierarchy } from "../lib/core.js";
|
|
3
|
+
import { createToken } from "../index.js";
|
|
4
|
+
import { mock } from "node:test";
|
|
5
|
+
|
|
6
|
+
//#region src/adapters/node.d.ts
|
|
7
|
+
/** A `node:test` mock function, as produced by `mock.fn()`. */
|
|
8
|
+
type NodeSpy = ReturnType<typeof mock.fn>;
|
|
9
|
+
/** Options accepted by the node:test adapter (the `mockFn`/`resetFn` bindings are supplied for you). */
|
|
10
|
+
type NodeTestContainerOptions = Omit<CreateTestContainerOptions<NodeSpy>, "mockFn" | "resetFn">;
|
|
11
|
+
/**
|
|
12
|
+
* Create a test container wired to `node:test` mocks (`mock.fn()`). Does not
|
|
13
|
+
* register any cleanup hooks — call `handle.restore()` yourself, or use
|
|
14
|
+
* {@link setupAlloyTesting} for automatic cleanup.
|
|
15
|
+
*/
|
|
16
|
+
declare function createTestContainer(opts?: NodeTestContainerOptions | OverrideSpec): TestContainerHandle<import("node:test").Mock<Function>> & {
|
|
17
|
+
getMock<T>(ctor: import("alloy-di/runtime").Newable<T>): MockOf<T, import("node:test").Mock<Function>> | undefined;
|
|
18
|
+
getMocks<T extends readonly import("alloy-di/runtime").Newable<unknown>[]>(ctors: T): { [K in keyof T]: T[K] extends import("alloy-di/runtime").Newable<infer I> ? MockOf<I, import("node:test").Mock<Function>> | undefined : never };
|
|
19
|
+
provideToken<T>(token: import("alloy-di/runtime").Token<T>, value: T): void;
|
|
20
|
+
provideFactory<T>(token: import("alloy-di/runtime").Token<T>, factory: import("alloy-di/runtime").FactoryFn<T>, options?: {
|
|
21
|
+
lifecycle?: import("alloy-di/runtime").ServiceScope;
|
|
22
|
+
}): void;
|
|
23
|
+
overrideFactory<T>(token: import("alloy-di/runtime").Token<T>, factory: import("alloy-di/runtime").FactoryFn<T>, options?: {
|
|
24
|
+
lifecycle?: import("alloy-di/runtime").ServiceScope;
|
|
25
|
+
}): void;
|
|
26
|
+
createScope(scopeName: import("alloy-di/runtime").ServiceScope): import("alloy-di/scopes").Scope;
|
|
27
|
+
spyOf<T>(ctor: import("alloy-di/runtime").Newable<T>, method: Extract<keyof T, string>): import("node:test").Mock<Function> | undefined;
|
|
28
|
+
clearMockSpies(): void;
|
|
29
|
+
};
|
|
30
|
+
type NodeTestContainer = ReturnType<typeof createTestContainer>;
|
|
31
|
+
/**
|
|
32
|
+
* Register a `node:test` `afterEach` hook that restores and clears every
|
|
33
|
+
* container created through the returned `createTestContainer`. Call this once
|
|
34
|
+
* per test file (or in a shared setup file).
|
|
35
|
+
*/
|
|
36
|
+
declare function setupAlloyTesting(): {
|
|
37
|
+
createTestContainer(opts?: NodeTestContainerOptions | OverrideSpec): NodeTestContainer;
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { type CreateTestContainerOptions, type FactoryOverrideSpec, type GenericSpy, type MockFnFactory, type MockOf, NodeSpy, NodeTestContainer, NodeTestContainerOptions, type OverrideSpec, type TestContainerHandle, type TestScopeHierarchy, createTestContainer, createToken, setupAlloyTesting };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createTestContainer as createTestContainer$1 } from "../lib/core.js";
|
|
2
|
+
import { createToken } from "../index.js";
|
|
3
|
+
import { afterEach, mock } from "node:test";
|
|
4
|
+
//#region src/adapters/node.ts
|
|
5
|
+
const binding = {
|
|
6
|
+
mockFn: () => mock.fn(),
|
|
7
|
+
resetFn: (spy) => {
|
|
8
|
+
spy.mock.resetCalls();
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Create a test container wired to `node:test` mocks (`mock.fn()`). Does not
|
|
13
|
+
* register any cleanup hooks — call `handle.restore()` yourself, or use
|
|
14
|
+
* {@link setupAlloyTesting} for automatic cleanup.
|
|
15
|
+
*/
|
|
16
|
+
function createTestContainer(opts) {
|
|
17
|
+
return createTestContainer$1({
|
|
18
|
+
...opts,
|
|
19
|
+
...binding
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Register a `node:test` `afterEach` hook that restores and clears every
|
|
24
|
+
* container created through the returned `createTestContainer`. Call this once
|
|
25
|
+
* per test file (or in a shared setup file).
|
|
26
|
+
*/
|
|
27
|
+
function setupAlloyTesting() {
|
|
28
|
+
const handles = /* @__PURE__ */ new Set();
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
for (const handle of [...handles].toReversed()) {
|
|
31
|
+
handle.clearMockSpies();
|
|
32
|
+
handle.restore();
|
|
33
|
+
}
|
|
34
|
+
handles.clear();
|
|
35
|
+
});
|
|
36
|
+
return { createTestContainer(opts) {
|
|
37
|
+
const handle = createTestContainer(opts);
|
|
38
|
+
handles.add(handle);
|
|
39
|
+
return handle;
|
|
40
|
+
} };
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { createTestContainer, createToken, setupAlloyTesting };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { GenericSpy, MockFnFactory, MockOf } from "../lib/mocking.js";
|
|
2
|
+
import { CreateTestContainerOptions, FactoryOverrideSpec, OverrideSpec, TestContainerHandle, TestScopeHierarchy } from "../lib/core.js";
|
|
3
|
+
import { createToken } from "../index.js";
|
|
4
|
+
import { Mock } from "vitest";
|
|
5
|
+
|
|
6
|
+
//#region src/adapters/vitest.d.ts
|
|
7
|
+
/** A Vitest spy, as produced by `vi.fn()`. */
|
|
8
|
+
type VitestSpy = Mock;
|
|
9
|
+
/** Options accepted by the Vitest adapter (the `mockFn`/`resetFn` bindings are supplied for you). */
|
|
10
|
+
type VitestTestContainerOptions = Omit<CreateTestContainerOptions<VitestSpy>, "mockFn" | "resetFn">;
|
|
11
|
+
/**
|
|
12
|
+
* Create a test container wired to Vitest spies (`vi.fn`). Does not register
|
|
13
|
+
* any cleanup hooks — call `handle.restore()` yourself, or use
|
|
14
|
+
* {@link setupAlloyTesting} for automatic cleanup.
|
|
15
|
+
*/
|
|
16
|
+
declare function createTestContainer(opts?: VitestTestContainerOptions | OverrideSpec): TestContainerHandle<VitestSpy> & {
|
|
17
|
+
getMock<T>(ctor: import("alloy-di/runtime").Newable<T>): MockOf<T, VitestSpy> | undefined;
|
|
18
|
+
getMocks<T extends readonly import("alloy-di/runtime").Newable<unknown>[]>(ctors: T): { [K in keyof T]: T[K] extends import("alloy-di/runtime").Newable<infer I> ? MockOf<I, VitestSpy> | undefined : never };
|
|
19
|
+
provideToken<T>(token: import("alloy-di/runtime").Token<T>, value: T): void;
|
|
20
|
+
provideFactory<T>(token: import("alloy-di/runtime").Token<T>, factory: import("alloy-di/runtime").FactoryFn<T>, options?: {
|
|
21
|
+
lifecycle?: import("alloy-di/runtime").ServiceScope;
|
|
22
|
+
}): void;
|
|
23
|
+
overrideFactory<T>(token: import("alloy-di/runtime").Token<T>, factory: import("alloy-di/runtime").FactoryFn<T>, options?: {
|
|
24
|
+
lifecycle?: import("alloy-di/runtime").ServiceScope;
|
|
25
|
+
}): void;
|
|
26
|
+
createScope(scopeName: import("alloy-di/runtime").ServiceScope): import("alloy-di/scopes").Scope;
|
|
27
|
+
spyOf<T>(ctor: import("alloy-di/runtime").Newable<T>, method: Extract<keyof T, string>): VitestSpy | undefined;
|
|
28
|
+
clearMockSpies(): void;
|
|
29
|
+
};
|
|
30
|
+
type VitestTestContainer = ReturnType<typeof createTestContainer>;
|
|
31
|
+
/**
|
|
32
|
+
* Register a Vitest `afterEach` hook that restores and clears every container
|
|
33
|
+
* created through the returned `createTestContainer`. Call this once per test
|
|
34
|
+
* file (or in a shared setup file).
|
|
35
|
+
*/
|
|
36
|
+
declare function setupAlloyTesting(): {
|
|
37
|
+
createTestContainer(opts?: VitestTestContainerOptions | OverrideSpec): VitestTestContainer;
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { type CreateTestContainerOptions, type FactoryOverrideSpec, type GenericSpy, type MockFnFactory, type MockOf, type OverrideSpec, type TestContainerHandle, type TestScopeHierarchy, VitestSpy, VitestTestContainer, VitestTestContainerOptions, createTestContainer, createToken, setupAlloyTesting };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createTestContainer as createTestContainer$1 } from "../lib/core.js";
|
|
2
|
+
import { createToken } from "../index.js";
|
|
3
|
+
import { afterEach, vi } from "vitest";
|
|
4
|
+
//#region src/adapters/vitest.ts
|
|
5
|
+
const binding = {
|
|
6
|
+
mockFn: () => vi.fn(),
|
|
7
|
+
resetFn: (spy) => {
|
|
8
|
+
spy.mockReset();
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Create a test container wired to Vitest spies (`vi.fn`). Does not register
|
|
13
|
+
* any cleanup hooks — call `handle.restore()` yourself, or use
|
|
14
|
+
* {@link setupAlloyTesting} for automatic cleanup.
|
|
15
|
+
*/
|
|
16
|
+
function createTestContainer(opts) {
|
|
17
|
+
return createTestContainer$1({
|
|
18
|
+
...opts,
|
|
19
|
+
...binding
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Register a Vitest `afterEach` hook that restores and clears every container
|
|
24
|
+
* created through the returned `createTestContainer`. Call this once per test
|
|
25
|
+
* file (or in a shared setup file).
|
|
26
|
+
*/
|
|
27
|
+
function setupAlloyTesting() {
|
|
28
|
+
const handles = /* @__PURE__ */ new Set();
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
for (const handle of [...handles].toReversed()) {
|
|
31
|
+
handle.clearMockSpies();
|
|
32
|
+
handle.restore();
|
|
33
|
+
}
|
|
34
|
+
handles.clear();
|
|
35
|
+
});
|
|
36
|
+
return { createTestContainer(opts) {
|
|
37
|
+
const handle = createTestContainer(opts);
|
|
38
|
+
handles.add(handle);
|
|
39
|
+
return handle;
|
|
40
|
+
} };
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { createTestContainer, createToken, setupAlloyTesting };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { GenericSpy, MockFnFactory, MockOf } from "./lib/mocking.js";
|
|
2
|
+
import { CreateTestContainerOptions, FactoryOverrideSpec, OverrideSpec, TestContainerHandle, TestScopeHierarchy, createTestContainer } from "./lib/core.js";
|
|
3
|
+
import { createToken } from "alloy-di/runtime";
|
|
4
|
+
export { type CreateTestContainerOptions, type FactoryOverrideSpec, type GenericSpy, type MockFnFactory, type MockOf, type OverrideSpec, type TestContainerHandle, type TestScopeHierarchy, createTestContainer, createToken };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { GenericSpy, MockFnFactory, MockOf } from "./mocking.js";
|
|
2
|
+
import { Container, FactoryFn, Newable, ProviderDefinitions, ServiceIdentifier, ServiceScope, Token } from "alloy-di/runtime";
|
|
3
|
+
import { Scope } from "alloy-di/scopes";
|
|
4
|
+
|
|
5
|
+
//#region src/lib/core.d.ts
|
|
6
|
+
type FactoryOverrideSpec<T = unknown> = [token: Token<T>, factory: FactoryFn<T>, options?: {
|
|
7
|
+
lifecycle?: ServiceScope;
|
|
8
|
+
}];
|
|
9
|
+
type TestScopeHierarchy = Record<string, {
|
|
10
|
+
parent?: ServiceScope;
|
|
11
|
+
}>;
|
|
12
|
+
interface OverrideSpec {
|
|
13
|
+
/** Class constructor instance overrides */
|
|
14
|
+
instances?: Array<[Newable<unknown>, unknown]>;
|
|
15
|
+
/** Token value overrides */
|
|
16
|
+
tokens?: Array<[Token<unknown>, unknown]>;
|
|
17
|
+
/**
|
|
18
|
+
* Token factory overrides. These are explicit token-keyed overrides and are
|
|
19
|
+
* not affected by autoMock, which only mocks class constructor dependencies.
|
|
20
|
+
* Token value overrides still take precedence for the same token.
|
|
21
|
+
*/
|
|
22
|
+
factories?: FactoryOverrideSpec[];
|
|
23
|
+
}
|
|
24
|
+
interface CreateTestContainerOptions<S = GenericSpy> {
|
|
25
|
+
overrides?: OverrideSpec;
|
|
26
|
+
autoMock?: boolean;
|
|
27
|
+
target?: Newable<unknown>;
|
|
28
|
+
providers?: ProviderDefinitions | ProviderDefinitions[];
|
|
29
|
+
/** Custom scope hierarchy for tests, matching alloy({ scopes }) shape. */
|
|
30
|
+
scopes?: TestScopeHierarchy;
|
|
31
|
+
/**
|
|
32
|
+
* Factory used to create spies for auto-mocked methods. Required when
|
|
33
|
+
* `autoMock` is enabled. Runner adapters (e.g. `@alloy-di/testing/vitest`)
|
|
34
|
+
* pre-wire this to the runner's mock function.
|
|
35
|
+
*/
|
|
36
|
+
mockFn?: MockFnFactory<S>;
|
|
37
|
+
/**
|
|
38
|
+
* Resets a single spy created by `mockFn`. Used by `clearMockSpies()`.
|
|
39
|
+
* Runner adapters pre-wire this to the runner's reset semantics.
|
|
40
|
+
*/
|
|
41
|
+
resetFn?: (spy: S) => void;
|
|
42
|
+
}
|
|
43
|
+
interface TestContainerHandle<S = GenericSpy> {
|
|
44
|
+
container: Container;
|
|
45
|
+
get<T>(target: Newable<T> | ServiceIdentifier<T>): Promise<T>;
|
|
46
|
+
getIdentifier?<T>(ctor: Newable<T>): ServiceIdentifier<T>;
|
|
47
|
+
/** Retrieve a token value via a synthetic classless access */
|
|
48
|
+
getToken<T>(token: Token<T>): T;
|
|
49
|
+
/** Provide a token value into the container */
|
|
50
|
+
provideToken?<T>(token: Token<T>, value: T): void;
|
|
51
|
+
/** Provide a token factory into the container */
|
|
52
|
+
provideFactory?<T>(token: Token<T>, factory: FactoryFn<T>, options?: {
|
|
53
|
+
lifecycle?: ServiceScope;
|
|
54
|
+
}): void;
|
|
55
|
+
/** Alias for provideFactory when replacing an existing test factory. */
|
|
56
|
+
overrideFactory?<T>(token: Token<T>, factory: FactoryFn<T>, options?: {
|
|
57
|
+
lifecycle?: ServiceScope;
|
|
58
|
+
}): void;
|
|
59
|
+
/** Create a scope under the test container. */
|
|
60
|
+
createScope?(scopeName: ServiceScope): Scope;
|
|
61
|
+
/** Placeholder restore hook (future phases may implement overlay stacks). */
|
|
62
|
+
restore(): void;
|
|
63
|
+
/** Retrieve a single class mock (if autoMock enabled). */
|
|
64
|
+
getMock?<T>(ctor: Newable<T>): MockOf<T, S> | undefined;
|
|
65
|
+
/** Retrieve multiple class mocks preserving tuple order. */
|
|
66
|
+
getMocks?<T extends readonly Newable<unknown>[]>(ctors: T): { [K in keyof T]: T[K] extends Newable<infer I> ? MockOf<I, S> | undefined : never };
|
|
67
|
+
/** Convenience: get a specific method spy from a mock. */
|
|
68
|
+
spyOf?<T>(ctor: Newable<T>, method: Extract<keyof T, string>): S | undefined;
|
|
69
|
+
/** Convenience: reset all mock spies (requires a `resetFn` binding). */
|
|
70
|
+
clearMockSpies?(): void;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Create a test-focused container with manual overrides.
|
|
74
|
+
* - Auto-mocking, when enabled, only mocks class constructor dependencies and
|
|
75
|
+
* requires a `mockFn` binding (supplied directly or by a runner adapter).
|
|
76
|
+
* - Token factories are explicit overrides and are applied after provider blocks.
|
|
77
|
+
*/
|
|
78
|
+
declare function createTestContainer<S = GenericSpy>(opts?: CreateTestContainerOptions<S> | OverrideSpec): TestContainerHandle<S> & {
|
|
79
|
+
getMock<T>(ctor: Newable<T>): MockOf<T, S> | undefined;
|
|
80
|
+
getMocks<T extends readonly Newable<unknown>[]>(ctors: T): { [K in keyof T]: T[K] extends Newable<infer I> ? MockOf<I, S> | undefined : never };
|
|
81
|
+
provideToken<T>(token: Token<T>, value: T): void;
|
|
82
|
+
provideFactory<T>(token: Token<T>, factory: FactoryFn<T>, options?: {
|
|
83
|
+
lifecycle?: ServiceScope;
|
|
84
|
+
}): void;
|
|
85
|
+
overrideFactory<T>(token: Token<T>, factory: FactoryFn<T>, options?: {
|
|
86
|
+
lifecycle?: ServiceScope;
|
|
87
|
+
}): void;
|
|
88
|
+
createScope(scopeName: ServiceScope): Scope;
|
|
89
|
+
spyOf<T>(ctor: Newable<T>, method: Extract<keyof T, string>): S | undefined;
|
|
90
|
+
clearMockSpies(): void;
|
|
91
|
+
};
|
|
92
|
+
//#endregion
|
|
93
|
+
export { CreateTestContainerOptions, FactoryOverrideSpec, OverrideSpec, TestContainerHandle, TestScopeHierarchy, createTestContainer };
|
package/dist/lib/core.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { restoreRegistry, snapshotRegistry } from "./registry.js";
|
|
2
|
+
import { applyAutoMocks } from "./mocking.js";
|
|
3
|
+
import { Container, applyProviders } from "alloy-di/runtime";
|
|
4
|
+
import { createScope } from "alloy-di/scopes";
|
|
5
|
+
//#region src/lib/core.ts
|
|
6
|
+
function normalizeScopeHierarchy(scopes) {
|
|
7
|
+
const hierarchy = {};
|
|
8
|
+
for (const [scopeName, config] of Object.entries(scopes)) hierarchy[scopeName] = config.parent ?? "singleton";
|
|
9
|
+
return hierarchy;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create a test-focused container with manual overrides.
|
|
13
|
+
* - Auto-mocking, when enabled, only mocks class constructor dependencies and
|
|
14
|
+
* requires a `mockFn` binding (supplied directly or by a runner adapter).
|
|
15
|
+
* - Token factories are explicit overrides and are applied after provider blocks.
|
|
16
|
+
*/
|
|
17
|
+
function createTestContainer(opts) {
|
|
18
|
+
const isLegacy = !!opts && !("autoMock" in opts) && !("target" in opts) && !("overrides" in opts) && !("providers" in opts) && !("scopes" in opts);
|
|
19
|
+
const normalizedOpts = isLegacy ? { overrides: opts } : opts ?? {};
|
|
20
|
+
const overrides = normalizedOpts.overrides ?? (isLegacy ? opts : void 0);
|
|
21
|
+
const container = new Container();
|
|
22
|
+
const snapshot = snapshotRegistry();
|
|
23
|
+
if (normalizedOpts.scopes) container._registerScopeHierarchy(normalizeScopeHierarchy(normalizedOpts.scopes));
|
|
24
|
+
if (normalizedOpts.providers) applyProviders(container, normalizedOpts.providers);
|
|
25
|
+
for (const [tok, factory, options] of overrides?.factories ?? []) container.provideFactory(tok, factory, options);
|
|
26
|
+
for (const [tok, value] of overrides?.tokens ?? []) container.provideValue(tok, value);
|
|
27
|
+
const overriddenCtors = new Set(overrides?.instances?.map(([c]) => c) ?? []);
|
|
28
|
+
for (const [ctor, instance] of overrides?.instances ?? []) container.overrideInstance(ctor, instance);
|
|
29
|
+
const resetFn = normalizedOpts.resetFn;
|
|
30
|
+
let mocks;
|
|
31
|
+
let lazyPatches;
|
|
32
|
+
if (normalizedOpts.autoMock && normalizedOpts.target) {
|
|
33
|
+
if (!normalizedOpts.mockFn) throw new Error("createTestContainer: `autoMock` requires a `mockFn` factory. Use a runner adapter (e.g. `@alloy-di/testing/vitest`) or pass `mockFn` explicitly.");
|
|
34
|
+
const auto = applyAutoMocks({
|
|
35
|
+
target: normalizedOpts.target,
|
|
36
|
+
container,
|
|
37
|
+
overridesCtors: overriddenCtors,
|
|
38
|
+
mockFn: normalizedOpts.mockFn
|
|
39
|
+
});
|
|
40
|
+
mocks = auto.mocks;
|
|
41
|
+
lazyPatches = auto.lazyPatches;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
container,
|
|
45
|
+
get: (target) => typeof target === "symbol" ? container.getByIdentifier(target) : container.get(target),
|
|
46
|
+
getIdentifier: (ctor) => container.getIdentifier(ctor),
|
|
47
|
+
getToken: (token) => {
|
|
48
|
+
return container.getToken(token);
|
|
49
|
+
},
|
|
50
|
+
provideToken: (token, value) => {
|
|
51
|
+
container.provideValue(token, value);
|
|
52
|
+
},
|
|
53
|
+
provideFactory: (token, factory, options) => {
|
|
54
|
+
container.provideFactory(token, factory, options);
|
|
55
|
+
},
|
|
56
|
+
overrideFactory: (token, factory, options) => {
|
|
57
|
+
container.provideFactory(token, factory, options);
|
|
58
|
+
},
|
|
59
|
+
createScope: (scopeName) => {
|
|
60
|
+
return createScope(container, scopeName);
|
|
61
|
+
},
|
|
62
|
+
getMock: (ctor) => {
|
|
63
|
+
return mocks?.get(ctor) ?? void 0;
|
|
64
|
+
},
|
|
65
|
+
getMocks: (ctors) => {
|
|
66
|
+
return ctors.map((c) => mocks?.get(c));
|
|
67
|
+
},
|
|
68
|
+
spyOf: (ctor, method) => {
|
|
69
|
+
return (mocks?.get(ctor))?.spies[method];
|
|
70
|
+
},
|
|
71
|
+
clearMockSpies: () => {
|
|
72
|
+
if (!mocks || !resetFn) return;
|
|
73
|
+
for (const [, m] of mocks) {
|
|
74
|
+
const spies = m.spies;
|
|
75
|
+
for (const key of Object.keys(spies)) resetFn(spies[key]);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
restore: () => {
|
|
79
|
+
for (const patch of lazyPatches ?? []) patch.lazy.importer = patch.originalImporter;
|
|
80
|
+
restoreRegistry(snapshot);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
export { createTestContainer };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Container, Newable } from "alloy-di/runtime";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/mocking.d.ts
|
|
4
|
+
type MethodKeys<T> = { [K in keyof T]: T[K] extends ((...args: any[]) => any) ? K : never }[keyof T];
|
|
5
|
+
/**
|
|
6
|
+
* The minimal shape the runner-neutral core relies on for a spy. Runner
|
|
7
|
+
* adapters supply richer spy types (e.g. Vitest's `Mock`) which flow through
|
|
8
|
+
* the generic `S` parameter, so callers keep full runner-specific typing.
|
|
9
|
+
*/
|
|
10
|
+
type GenericSpy = ((...args: any[]) => any) & {
|
|
11
|
+
mock?: {
|
|
12
|
+
calls: any[][];
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
/** Factory that produces a fresh spy function (e.g. `vi.fn`, `jest.fn`). */
|
|
16
|
+
type MockFnFactory<S = GenericSpy> = () => S;
|
|
17
|
+
/** Typed mock shape returned for class auto-mocking. */
|
|
18
|
+
type MockOf<T, S = GenericSpy> = Partial<T> & {
|
|
19
|
+
/** Map of method name -> spy function */spies: Record<Extract<MethodKeys<T>, string>, S>; /** Original constructor reference for introspection */
|
|
20
|
+
__target: Newable<T>;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { GenericSpy, MockFnFactory, MockOf };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { getRawDependencies } from "./registry.js";
|
|
2
|
+
import { isConstructor, isLazy } from "alloy-di/runtime";
|
|
3
|
+
//#region src/lib/mocking.ts
|
|
4
|
+
/** Create a lightweight auto-mock instance for a class constructor. */
|
|
5
|
+
function mockClass(ctor, mockFn) {
|
|
6
|
+
const proto = ctor.prototype;
|
|
7
|
+
const spies = {};
|
|
8
|
+
const mockObj = {
|
|
9
|
+
spies,
|
|
10
|
+
__target: ctor
|
|
11
|
+
};
|
|
12
|
+
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
13
|
+
if (key === "constructor") continue;
|
|
14
|
+
if (typeof proto[key] === "function") {
|
|
15
|
+
const fn = mockFn();
|
|
16
|
+
spies[key] = fn;
|
|
17
|
+
mockObj[key] = fn;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
target: ctor,
|
|
22
|
+
mock: mockObj
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function collectDependencyGraph(target) {
|
|
26
|
+
const constructors = /* @__PURE__ */ new Set();
|
|
27
|
+
const lazyDependencies = [];
|
|
28
|
+
const queue = [target];
|
|
29
|
+
const visited = /* @__PURE__ */ new Set();
|
|
30
|
+
while (queue.length) {
|
|
31
|
+
const current = queue.shift();
|
|
32
|
+
if (!current || visited.has(current)) continue;
|
|
33
|
+
visited.add(current);
|
|
34
|
+
constructors.add(current);
|
|
35
|
+
const deps = getRawDependencies(current);
|
|
36
|
+
for (const dep of deps) {
|
|
37
|
+
if (isLazy(dep)) {
|
|
38
|
+
lazyDependencies.push({ lazy: dep });
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (isConstructor(dep)) queue.push(dep);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
constructors,
|
|
46
|
+
lazyDependencies
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function createMocksForConstructors(constructors, target, overrides, mockFn) {
|
|
50
|
+
const mocks = /* @__PURE__ */ new Map();
|
|
51
|
+
for (const ctor of constructors) {
|
|
52
|
+
if (ctor === target) continue;
|
|
53
|
+
if (overrides.has(ctor)) continue;
|
|
54
|
+
const classMock = mockClass(ctor, mockFn);
|
|
55
|
+
mocks.set(ctor, classMock.mock);
|
|
56
|
+
}
|
|
57
|
+
return mocks;
|
|
58
|
+
}
|
|
59
|
+
function applyMocksToContainer(container, mocks) {
|
|
60
|
+
for (const [ctor, mock] of mocks.entries()) container.overrideInstance(ctor, mock);
|
|
61
|
+
}
|
|
62
|
+
function patchLazyDependencies(lazyDeps, mocks, overrides, mockFn) {
|
|
63
|
+
const patches = [];
|
|
64
|
+
for (const { lazy } of lazyDeps) {
|
|
65
|
+
const originalImporter = lazy.importer;
|
|
66
|
+
lazy.importer = async () => {
|
|
67
|
+
const realCtor = await originalImporter();
|
|
68
|
+
let mockObj = mocks.get(realCtor);
|
|
69
|
+
if (!overrides.has(realCtor) && !mockObj) {
|
|
70
|
+
mockObj = mockClass(realCtor, mockFn).mock;
|
|
71
|
+
mocks.set(realCtor, mockObj);
|
|
72
|
+
}
|
|
73
|
+
if (!mockObj) return realCtor;
|
|
74
|
+
return buildMockCtorFrom(realCtor, mockObj);
|
|
75
|
+
};
|
|
76
|
+
patches.push({
|
|
77
|
+
lazy,
|
|
78
|
+
originalImporter
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return patches;
|
|
82
|
+
}
|
|
83
|
+
/** Traverse dependency graph (deep) and create class mocks, including lazy deps. */
|
|
84
|
+
function applyAutoMocks(options) {
|
|
85
|
+
const { target, container, overridesCtors, mockFn } = options;
|
|
86
|
+
const graph = collectDependencyGraph(target);
|
|
87
|
+
const mocks = createMocksForConstructors(graph.constructors, target, overridesCtors, mockFn);
|
|
88
|
+
applyMocksToContainer(container, mocks);
|
|
89
|
+
return {
|
|
90
|
+
mocks,
|
|
91
|
+
lazyPatches: patchLazyDependencies(graph.lazyDependencies, mocks, overridesCtors, mockFn)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** Build a class constructor that exposes spies from a mock object via prototype methods */
|
|
95
|
+
function buildMockCtorFrom(realCtor, mock) {
|
|
96
|
+
function MockCtor() {}
|
|
97
|
+
const proto = realCtor.prototype;
|
|
98
|
+
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
99
|
+
if (key === "constructor") continue;
|
|
100
|
+
if (typeof proto[key] === "function" && key in mock.spies) MockCtor.prototype[key] = mock.spies[key];
|
|
101
|
+
}
|
|
102
|
+
return MockCtor;
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
export { applyAutoMocks };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { dependenciesRegistry } from "alloy-di/runtime";
|
|
2
|
+
//#region src/lib/registry.ts
|
|
3
|
+
/** Take a deep(ish) snapshot of current dependency registry state. */
|
|
4
|
+
function snapshotRegistry() {
|
|
5
|
+
return new Map(dependenciesRegistry);
|
|
6
|
+
}
|
|
7
|
+
/** Restore dependency registry from a prior snapshot. */
|
|
8
|
+
function restoreRegistry(snapshot) {
|
|
9
|
+
dependenciesRegistry.clear();
|
|
10
|
+
for (const [k, v] of snapshot.entries()) dependenciesRegistry.set(k, v);
|
|
11
|
+
}
|
|
12
|
+
/** Get raw declared dependencies including constructors, Lazy and Tokens */
|
|
13
|
+
function getRawDependencies(target) {
|
|
14
|
+
return (dependenciesRegistry.get(target)?.dependencies ?? (() => []))();
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { getRawDependencies, restoreRegistry, snapshotRegistry };
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@alloy-di/testing",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Runner-neutral test-container utilities for Alloy DI, with Vitest, Jest, and node:test adapters",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dependency-injection",
|
|
7
|
+
"di",
|
|
8
|
+
"jest",
|
|
9
|
+
"mocking",
|
|
10
|
+
"testing",
|
|
11
|
+
"typescript",
|
|
12
|
+
"vitest"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://alloy-di.dev",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "Mikael Selander",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/ciddan/alloy-di/tree/main/packages/testing"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./vitest": {
|
|
35
|
+
"types": "./dist/adapters/vitest.d.ts",
|
|
36
|
+
"import": "./dist/adapters/vitest.js"
|
|
37
|
+
},
|
|
38
|
+
"./jest": {
|
|
39
|
+
"types": "./dist/adapters/jest.d.ts",
|
|
40
|
+
"import": "./dist/adapters/jest.js"
|
|
41
|
+
},
|
|
42
|
+
"./node": {
|
|
43
|
+
"types": "./dist/adapters/node.d.ts",
|
|
44
|
+
"import": "./dist/adapters/node.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"provenance": true
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"tslib": "^2.8.1"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@babel/core": "^7.26.0",
|
|
56
|
+
"@babel/preset-env": "^7.26.0",
|
|
57
|
+
"@babel/preset-typescript": "^7.26.0",
|
|
58
|
+
"@jest/globals": "^30.0.0",
|
|
59
|
+
"babel-jest": "^30.0.0",
|
|
60
|
+
"jest": "^30.0.0",
|
|
61
|
+
"jest-mock": "^30.0.0",
|
|
62
|
+
"rimraf": "^6.1.3",
|
|
63
|
+
"rolldown": "^1.1.0",
|
|
64
|
+
"rolldown-plugin-dts": "^0.25.2",
|
|
65
|
+
"tsx": "^4.22.4",
|
|
66
|
+
"vitest": "^4.1.8",
|
|
67
|
+
"alloy-di": "1.5.0"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"@jest/globals": ">=29.0.0",
|
|
71
|
+
"alloy-di": ">=1.5.0",
|
|
72
|
+
"typescript": ">=5.0.0",
|
|
73
|
+
"vitest": ">=4.0.14 <5.0.0"
|
|
74
|
+
},
|
|
75
|
+
"peerDependenciesMeta": {
|
|
76
|
+
"@jest/globals": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"vitest": {
|
|
80
|
+
"optional": true
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"scripts": {
|
|
84
|
+
"build": "rimraf dist && rolldown -c",
|
|
85
|
+
"dev": "rolldown -c rolldown.config.ts --watch",
|
|
86
|
+
"format": "oxfmt",
|
|
87
|
+
"format:check": "oxfmt --check",
|
|
88
|
+
"lint": "oxlint --fix --type-aware --config ./.oxlintrc.json .",
|
|
89
|
+
"lint:check": "oxlint --type-aware --config ./.oxlintrc.json .",
|
|
90
|
+
"test": "vitest --run && pnpm test:node && pnpm test:jest",
|
|
91
|
+
"test:vitest": "vitest --run",
|
|
92
|
+
"test:node": "node --import tsx --test src/runner-tests/*.node.test.ts",
|
|
93
|
+
"test:jest": "node --experimental-vm-modules node_modules/jest/bin/jest.js --config jest.config.mjs",
|
|
94
|
+
"test:cover": "vitest --run --coverage",
|
|
95
|
+
"test:watch": "vitest",
|
|
96
|
+
"typecheck": "tsc -b . --noEmit"
|
|
97
|
+
}
|
|
98
|
+
}
|