@wild-framework/testing 0.1.1
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 +21 -0
- package/README.md +39 -0
- package/dist/create-test-application.d.ts +30 -0
- package/dist/create-test-application.d.ts.map +1 -0
- package/dist/create-test-application.js +81 -0
- package/dist/create-test-application.js.map +1 -0
- package/dist/fake-events.d.ts +26 -0
- package/dist/fake-events.d.ts.map +1 -0
- package/dist/fake-events.js +60 -0
- package/dist/fake-events.js.map +1 -0
- package/dist/fake-mail.d.ts +21 -0
- package/dist/fake-mail.d.ts.map +1 -0
- package/dist/fake-mail.js +37 -0
- package/dist/fake-mail.js.map +1 -0
- package/dist/fake-queue.d.ts +32 -0
- package/dist/fake-queue.d.ts.map +1 -0
- package/dist/fake-queue.js +30 -0
- package/dist/fake-queue.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wild Framework 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,39 @@
|
|
|
1
|
+
# @wild-framework/testing
|
|
2
|
+
|
|
3
|
+
Testing helpers for [Wild Framework](https://github.com/KhandaSoftware/wild-framework).
|
|
4
|
+
|
|
5
|
+
Fakes and a test application builder so features can be tested without
|
|
6
|
+
real infrastructure — mock events, queue, and mail via the container.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pnpm add -D @wild-framework/testing
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { createTestApplication, FakeEventBus, FakeQueue, FakeMail } from "@wild-framework/testing";
|
|
18
|
+
import { OrderService, OrderPlaced } from "./features/orders/index.js";
|
|
19
|
+
import { OrderProvider } from "./features/orders/order-provider.js";
|
|
20
|
+
|
|
21
|
+
const app = await createTestApplication({ providers: [OrderProvider] });
|
|
22
|
+
|
|
23
|
+
const events = app.resolve(FakeEventBus); // or FakeQueue / FakeMail
|
|
24
|
+
await app.resolve(OrderService).place(...);
|
|
25
|
+
|
|
26
|
+
expect(events.wasDispatched(OrderPlaced)).toBe(true);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## What it provides
|
|
30
|
+
|
|
31
|
+
- **`FakeEventBus`** — captures dispatched events (`dispatchedOf`, `wasDispatched`, `dispatchCount`)
|
|
32
|
+
- **`FakeQueue`** — captures dispatched jobs without running them
|
|
33
|
+
- **`FakeMail`** — captures sent messages (`sentWithSubject`, `sentCount`)
|
|
34
|
+
- **`createTestApplication()`** — boots a container-wired app and binds the
|
|
35
|
+
fakes under both the fake tokens and the real `EventBus`/`Queue`/`Mail`
|
|
36
|
+
tokens, so your feature code gets the fakes automatically
|
|
37
|
+
|
|
38
|
+
Pass `realEvents: true`, `realQueue: true`, or `realMail: true` to use the
|
|
39
|
+
real providers instead.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Application, type ProviderConstructor } from "@wild-framework/core";
|
|
2
|
+
/**
|
|
3
|
+
* Options for the test application builder.
|
|
4
|
+
*/
|
|
5
|
+
export interface TestAppOptions {
|
|
6
|
+
/** Use the real EventProvider/EventBus instead of the fake. */
|
|
7
|
+
realEvents?: boolean;
|
|
8
|
+
/** Use the real QueueProvider/Queue instead of the fake. */
|
|
9
|
+
realQueue?: boolean;
|
|
10
|
+
/** Use the real MailProvider/Mail instead of the fake. */
|
|
11
|
+
realMail?: boolean;
|
|
12
|
+
/** Additional providers to register (e.g. your feature providers). */
|
|
13
|
+
providers?: ProviderConstructor[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Build a booted application for testing.
|
|
17
|
+
*
|
|
18
|
+
* Binds `FakeEventBus`, `FakeQueue`, and `FakeMail` into the container
|
|
19
|
+
* (under both the fake token and the real `EventBus`/`Queue`/`Mail`
|
|
20
|
+
* tokens), so feature code uses the fakes and tests can resolve them:
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* const app = await createTestApplication({ providers: [MyFeatureProvider] });
|
|
24
|
+
* const events = app.resolve(FakeEventBus);
|
|
25
|
+
* await myService.doSomething();
|
|
26
|
+
* expect(events.wasDispatched(UserRegistered)).toBe(true);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function createTestApplication(options?: TestAppOptions): Promise<Application>;
|
|
30
|
+
//# sourceMappingURL=create-test-application.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-test-application.d.ts","sourceRoot":"","sources":["../src/create-test-application.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,WAAW,EAAiB,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AASpH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACrC;AA+BD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,CAgC9F"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createApplication } from "@wild-framework/core";
|
|
2
|
+
import { ContainerProvider, Container } from "@wild-framework/container";
|
|
3
|
+
import { EventProvider, EventBus } from "@wild-framework/events";
|
|
4
|
+
import { QueueProvider, Queue } from "@wild-framework/queue";
|
|
5
|
+
import { MailProvider, Mail } from "@wild-framework/mail";
|
|
6
|
+
import { FakeEventBus } from "./fake-events.js";
|
|
7
|
+
import { FakeQueue } from "./fake-queue.js";
|
|
8
|
+
import { FakeMail } from "./fake-mail.js";
|
|
9
|
+
/**
|
|
10
|
+
* A provider that binds the test fakes into the container, so feature
|
|
11
|
+
* code resolving `EventBus`/`Queue`/`Mail` gets the fake automatically.
|
|
12
|
+
*
|
|
13
|
+
* The class is declared inside `createTestApplication` so it closes over
|
|
14
|
+
* the fakes while still being a no-arg constructor (core instantiates
|
|
15
|
+
* providers with `new ProviderCtor()`).
|
|
16
|
+
*/
|
|
17
|
+
function fakeProviderFor(fakes) {
|
|
18
|
+
return class FakeProvider {
|
|
19
|
+
register(app) {
|
|
20
|
+
const container = app.resolve(Container);
|
|
21
|
+
if (fakes.events) {
|
|
22
|
+
container.singleton(EventBus, () => fakes.events);
|
|
23
|
+
container.singleton(FakeEventBus, () => fakes.events);
|
|
24
|
+
}
|
|
25
|
+
if (fakes.queue) {
|
|
26
|
+
container.singleton(Queue, () => fakes.queue);
|
|
27
|
+
container.singleton(FakeQueue, () => fakes.queue);
|
|
28
|
+
}
|
|
29
|
+
if (fakes.mail) {
|
|
30
|
+
container.singleton(Mail, () => fakes.mail);
|
|
31
|
+
container.singleton(FakeMail, () => fakes.mail);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build a booted application for testing.
|
|
38
|
+
*
|
|
39
|
+
* Binds `FakeEventBus`, `FakeQueue`, and `FakeMail` into the container
|
|
40
|
+
* (under both the fake token and the real `EventBus`/`Queue`/`Mail`
|
|
41
|
+
* tokens), so feature code uses the fakes and tests can resolve them:
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* const app = await createTestApplication({ providers: [MyFeatureProvider] });
|
|
45
|
+
* const events = app.resolve(FakeEventBus);
|
|
46
|
+
* await myService.doSomething();
|
|
47
|
+
* expect(events.wasDispatched(UserRegistered)).toBe(true);
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export async function createTestApplication(options = {}) {
|
|
51
|
+
const app = createApplication();
|
|
52
|
+
const fakes = {};
|
|
53
|
+
app.register(ContainerProvider);
|
|
54
|
+
if (options.realEvents) {
|
|
55
|
+
app.register(EventProvider);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
fakes.events = new FakeEventBus();
|
|
59
|
+
}
|
|
60
|
+
if (options.realQueue) {
|
|
61
|
+
app.register(QueueProvider);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
fakes.queue = new FakeQueue();
|
|
65
|
+
}
|
|
66
|
+
if (options.realMail) {
|
|
67
|
+
app.register(MailProvider);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
fakes.mail = new FakeMail();
|
|
71
|
+
}
|
|
72
|
+
if (!options.realEvents || !options.realQueue || !options.realMail) {
|
|
73
|
+
app.register(fakeProviderFor(fakes));
|
|
74
|
+
}
|
|
75
|
+
for (const provider of options.providers ?? []) {
|
|
76
|
+
app.register(provider);
|
|
77
|
+
}
|
|
78
|
+
await app.boot();
|
|
79
|
+
return app;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=create-test-application.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-test-application.js","sourceRoot":"","sources":["../src/create-test-application.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A test double for the EventBus.
|
|
3
|
+
*
|
|
4
|
+
* Records dispatched events so tests can assert on them, instead of
|
|
5
|
+
* relying on side-effect listeners. Shares the same public shape as
|
|
6
|
+
* the real EventBus (`listen`, `dispatch`, `remove`, `has`).
|
|
7
|
+
*/
|
|
8
|
+
export declare class FakeEventBus {
|
|
9
|
+
private listeners;
|
|
10
|
+
private dispatched;
|
|
11
|
+
listen<T>(eventClass: new (...args: any[]) => T, listener: (event: T) => void | Promise<void>): void;
|
|
12
|
+
dispatch<T extends object>(event: T): Promise<void>;
|
|
13
|
+
remove<T>(eventClass: new (...args: any[]) => T, listener: (event: T) => void | Promise<void>): void;
|
|
14
|
+
has<T>(eventClass: new (...args: any[]) => T): boolean;
|
|
15
|
+
/** All dispatched events, in order. */
|
|
16
|
+
dispatchedEvents(): unknown[];
|
|
17
|
+
/** Dispatched events of a specific class. */
|
|
18
|
+
dispatchedOf<T>(eventClass: new (...args: any[]) => T): T[];
|
|
19
|
+
/** Whether a given event class was dispatched at least once. */
|
|
20
|
+
wasDispatched<T>(eventClass: new (...args: any[]) => T): boolean;
|
|
21
|
+
/** Number of events dispatched so far. */
|
|
22
|
+
dispatchCount(): number;
|
|
23
|
+
/** Reset captured state (keeps listeners). */
|
|
24
|
+
clear(): void;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=fake-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-events.d.ts","sourceRoot":"","sources":["../src/fake-events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,qBAAa,YAAY;IACrB,OAAO,CAAC,SAAS,CAAyF;IAC1G,OAAO,CAAC,UAAU,CAA8E;IAEhG,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAS9F,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzD,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIpG,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,OAAO;IAQtD,uCAAuC;IACvC,gBAAgB,IAAI,OAAO,EAAE;IAI7B,6CAA6C;IAC7C,YAAY,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE;IAM3D,gEAAgE;IAChE,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,OAAO;IAIhE,0CAA0C;IAC1C,aAAa,IAAI,MAAM;IAIvB,8CAA8C;IAC9C,KAAK,IAAI,IAAI;CAGhB"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A test double for the EventBus.
|
|
3
|
+
*
|
|
4
|
+
* Records dispatched events so tests can assert on them, instead of
|
|
5
|
+
* relying on side-effect listeners. Shares the same public shape as
|
|
6
|
+
* the real EventBus (`listen`, `dispatch`, `remove`, `has`).
|
|
7
|
+
*/
|
|
8
|
+
export class FakeEventBus {
|
|
9
|
+
listeners = new Map();
|
|
10
|
+
dispatched = [];
|
|
11
|
+
listen(eventClass, listener) {
|
|
12
|
+
let set = this.listeners.get(eventClass);
|
|
13
|
+
if (!set) {
|
|
14
|
+
set = new Set();
|
|
15
|
+
this.listeners.set(eventClass, set);
|
|
16
|
+
}
|
|
17
|
+
set.add(listener);
|
|
18
|
+
}
|
|
19
|
+
async dispatch(event) {
|
|
20
|
+
this.dispatched.push({ eventClass: event.constructor, event });
|
|
21
|
+
const listeners = this.listeners.get(event.constructor);
|
|
22
|
+
if (!listeners)
|
|
23
|
+
return;
|
|
24
|
+
for (const listener of listeners) {
|
|
25
|
+
await listener(event);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
remove(eventClass, listener) {
|
|
29
|
+
this.listeners.get(eventClass)?.delete(listener);
|
|
30
|
+
}
|
|
31
|
+
has(eventClass) {
|
|
32
|
+
return (this.listeners.get(eventClass)?.size ?? 0) > 0;
|
|
33
|
+
}
|
|
34
|
+
// ------------------------------------------------------------------
|
|
35
|
+
// Test helpers
|
|
36
|
+
// ------------------------------------------------------------------
|
|
37
|
+
/** All dispatched events, in order. */
|
|
38
|
+
dispatchedEvents() {
|
|
39
|
+
return this.dispatched.map((d) => d.event);
|
|
40
|
+
}
|
|
41
|
+
/** Dispatched events of a specific class. */
|
|
42
|
+
dispatchedOf(eventClass) {
|
|
43
|
+
return this.dispatched
|
|
44
|
+
.filter((d) => d.eventClass === eventClass)
|
|
45
|
+
.map((d) => d.event);
|
|
46
|
+
}
|
|
47
|
+
/** Whether a given event class was dispatched at least once. */
|
|
48
|
+
wasDispatched(eventClass) {
|
|
49
|
+
return this.dispatched.some((d) => d.eventClass === eventClass);
|
|
50
|
+
}
|
|
51
|
+
/** Number of events dispatched so far. */
|
|
52
|
+
dispatchCount() {
|
|
53
|
+
return this.dispatched.length;
|
|
54
|
+
}
|
|
55
|
+
/** Reset captured state (keeps listeners). */
|
|
56
|
+
clear() {
|
|
57
|
+
this.dispatched = [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=fake-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-events.js","sourceRoot":"","sources":["../src/fake-events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,OAAO,YAAY;IACb,SAAS,GAAG,IAAI,GAAG,EAA8E,CAAC;IAClG,UAAU,GAA2E,EAAE,CAAC;IAEhG,MAAM,CAAI,UAAqC,EAAE,QAA4C;QACzF,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACxC,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAmB,KAAQ;QACrC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,WAA8C,EAAE,KAAK,EAAE,CAAC,CAAC;QAElG,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,WAA8C,CAAC,CAAC;QAC3F,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YAC/B,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;IACL,CAAC;IAED,MAAM,CAAI,UAAqC,EAAE,QAA4C;QACzF,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,GAAG,CAAI,UAAqC;QACxC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC3D,CAAC;IAED,qEAAqE;IACrE,eAAe;IACf,qEAAqE;IAErE,uCAAuC;IACvC,gBAAgB;QACZ,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC;IAED,6CAA6C;IAC7C,YAAY,CAAI,UAAqC;QACjD,OAAO,IAAI,CAAC,UAAU;aACjB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC;aAC1C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAU,CAAC,CAAC;IAClC,CAAC;IAED,gEAAgE;IAChE,aAAa,CAAI,UAAqC;QAClD,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;IACpE,CAAC;IAED,0CAA0C;IAC1C,aAAa;QACT,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAClC,CAAC;IAED,8CAA8C;IAC9C,KAAK;QACD,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;IACzB,CAAC;CACJ"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MailMessage } from "@wild-framework/mail";
|
|
2
|
+
/**
|
|
3
|
+
* A test double for Mail — a real `Mail` facade backed by the
|
|
4
|
+
* in-memory driver, which captures messages instead of sending them.
|
|
5
|
+
*/
|
|
6
|
+
export declare class FakeMail {
|
|
7
|
+
private mail;
|
|
8
|
+
private driver;
|
|
9
|
+
constructor();
|
|
10
|
+
/** Delegate to the underlying Mail facade. */
|
|
11
|
+
send(message: MailMessage): Promise<void>;
|
|
12
|
+
/** Messages sent so far. */
|
|
13
|
+
sent(): MailMessage[];
|
|
14
|
+
/** Whether a message with the given subject was sent. */
|
|
15
|
+
sentWithSubject(subject: string): MailMessage | undefined;
|
|
16
|
+
/** Number of messages sent so far. */
|
|
17
|
+
sentCount(): number;
|
|
18
|
+
/** Reset captured state. */
|
|
19
|
+
clear(): void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=fake-mail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-mail.d.ts","sourceRoot":"","sources":["../src/fake-mail.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD;;;GAGG;AACH,qBAAa,QAAQ;IACjB,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,MAAM,CAAqB;;IAOnC,8CAA8C;IAC9C,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,4BAA4B;IAC5B,IAAI,IAAI,WAAW,EAAE;IAIrB,yDAAyD;IACzD,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIzD,sCAAsC;IACtC,SAAS,IAAI,MAAM;IAInB,4BAA4B;IAC5B,KAAK,IAAI,IAAI;CAGhB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Mail, InMemoryMailDriver } from "@wild-framework/mail";
|
|
2
|
+
/**
|
|
3
|
+
* A test double for Mail — a real `Mail` facade backed by the
|
|
4
|
+
* in-memory driver, which captures messages instead of sending them.
|
|
5
|
+
*/
|
|
6
|
+
export class FakeMail {
|
|
7
|
+
mail;
|
|
8
|
+
driver;
|
|
9
|
+
constructor() {
|
|
10
|
+
this.driver = new InMemoryMailDriver();
|
|
11
|
+
this.mail = new Mail(this.driver);
|
|
12
|
+
}
|
|
13
|
+
/** Delegate to the underlying Mail facade. */
|
|
14
|
+
send(message) {
|
|
15
|
+
return this.mail.send(message);
|
|
16
|
+
}
|
|
17
|
+
// ------------------------------------------------------------------
|
|
18
|
+
// Test helpers
|
|
19
|
+
// ------------------------------------------------------------------
|
|
20
|
+
/** Messages sent so far. */
|
|
21
|
+
sent() {
|
|
22
|
+
return [...this.driver.sent];
|
|
23
|
+
}
|
|
24
|
+
/** Whether a message with the given subject was sent. */
|
|
25
|
+
sentWithSubject(subject) {
|
|
26
|
+
return this.driver.sent.find((m) => m.subject === subject);
|
|
27
|
+
}
|
|
28
|
+
/** Number of messages sent so far. */
|
|
29
|
+
sentCount() {
|
|
30
|
+
return this.driver.sent.length;
|
|
31
|
+
}
|
|
32
|
+
/** Reset captured state. */
|
|
33
|
+
clear() {
|
|
34
|
+
this.driver.clear();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=fake-mail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-mail.js","sourceRoot":"","sources":["../src/fake-mail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAGhE;;;GAGG;AACH,MAAM,OAAO,QAAQ;IACT,IAAI,CAAO;IACX,MAAM,CAAqB;IAEnC;QACI,IAAI,CAAC,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,8CAA8C;IAC9C,IAAI,CAAC,OAAoB;QACrB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,qEAAqE;IACrE,eAAe;IACf,qEAAqE;IAErE,4BAA4B;IAC5B,IAAI;QACA,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,yDAAyD;IACzD,eAAe,CAAC,OAAe;QAC3B,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;IAC/D,CAAC;IAED,sCAAsC;IACtC,SAAS;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;IACnC,CAAC;IAED,4BAA4B;IAC5B,KAAK;QACD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACJ"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A test double for the Queue.
|
|
3
|
+
*
|
|
4
|
+
* Captures dispatched jobs instead of running them, so tests can assert
|
|
5
|
+
* on what was queued. Shares the same public `dispatch` shape as the
|
|
6
|
+
* real Queue.
|
|
7
|
+
*/
|
|
8
|
+
export interface FakeDispatchedJob<TPayload = unknown> {
|
|
9
|
+
job: new (...args: any[]) => {
|
|
10
|
+
handle(payload: TPayload): void | Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
payload: TPayload;
|
|
13
|
+
}
|
|
14
|
+
export declare class FakeQueue {
|
|
15
|
+
private jobs;
|
|
16
|
+
dispatch<TPayload>(job: new (...args: any[]) => {
|
|
17
|
+
handle(payload: TPayload): void | Promise<void>;
|
|
18
|
+
}, payload: TPayload): Promise<void>;
|
|
19
|
+
/** All dispatched jobs, in order. */
|
|
20
|
+
dispatchedJobs(): FakeDispatchedJob[];
|
|
21
|
+
/** Dispatched jobs of a specific job class. */
|
|
22
|
+
dispatchedOf<TPayload>(jobClass: new (...args: any[]) => {
|
|
23
|
+
handle(payload: TPayload): void | Promise<void>;
|
|
24
|
+
}): FakeDispatchedJob<TPayload>[];
|
|
25
|
+
/** Whether a given job class was dispatched at least once. */
|
|
26
|
+
wasDispatched(jobClass: new (...args: any[]) => unknown): boolean;
|
|
27
|
+
/** Number of jobs dispatched so far. */
|
|
28
|
+
dispatchCount(): number;
|
|
29
|
+
/** Reset captured state. */
|
|
30
|
+
clear(): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=fake-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-queue.d.ts","sourceRoot":"","sources":["../src/fake-queue.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB,CAAC,QAAQ,GAAG,OAAO;IACjD,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK;QAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IACjF,OAAO,EAAE,QAAQ,CAAC;CACrB;AAED,qBAAa,SAAS;IAClB,OAAO,CAAC,IAAI,CAA2B;IAEjC,QAAQ,CAAC,QAAQ,EACnB,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK;QAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,EAChF,OAAO,EAAE,QAAQ,GAClB,OAAO,CAAC,IAAI,CAAC;IAQhB,qCAAqC;IACrC,cAAc,IAAI,iBAAiB,EAAE;IAIrC,+CAA+C;IAC/C,YAAY,CAAC,QAAQ,EACjB,QAAQ,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK;QAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,GACtF,iBAAiB,CAAC,QAAQ,CAAC,EAAE;IAIhC,8DAA8D;IAC9D,aAAa,CAAC,QAAQ,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,GAAG,OAAO;IAIjE,wCAAwC;IACxC,aAAa,IAAI,MAAM;IAIvB,4BAA4B;IAC5B,KAAK,IAAI,IAAI;CAGhB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class FakeQueue {
|
|
2
|
+
jobs = [];
|
|
3
|
+
async dispatch(job, payload) {
|
|
4
|
+
this.jobs.push({ job, payload });
|
|
5
|
+
}
|
|
6
|
+
// ------------------------------------------------------------------
|
|
7
|
+
// Test helpers
|
|
8
|
+
// ------------------------------------------------------------------
|
|
9
|
+
/** All dispatched jobs, in order. */
|
|
10
|
+
dispatchedJobs() {
|
|
11
|
+
return [...this.jobs];
|
|
12
|
+
}
|
|
13
|
+
/** Dispatched jobs of a specific job class. */
|
|
14
|
+
dispatchedOf(jobClass) {
|
|
15
|
+
return this.jobs.filter((j) => j.job === jobClass);
|
|
16
|
+
}
|
|
17
|
+
/** Whether a given job class was dispatched at least once. */
|
|
18
|
+
wasDispatched(jobClass) {
|
|
19
|
+
return this.jobs.some((j) => j.job === jobClass);
|
|
20
|
+
}
|
|
21
|
+
/** Number of jobs dispatched so far. */
|
|
22
|
+
dispatchCount() {
|
|
23
|
+
return this.jobs.length;
|
|
24
|
+
}
|
|
25
|
+
/** Reset captured state. */
|
|
26
|
+
clear() {
|
|
27
|
+
this.jobs = [];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=fake-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-queue.js","sourceRoot":"","sources":["../src/fake-queue.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,SAAS;IACV,IAAI,GAAwB,EAAE,CAAC;IAEvC,KAAK,CAAC,QAAQ,CACV,GAAgF,EAChF,OAAiB;QAEjB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,qEAAqE;IACrE,eAAe;IACf,qEAAqE;IAErE,qCAAqC;IACrC,cAAc;QACV,OAAO,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,+CAA+C;IAC/C,YAAY,CACR,QAAqF;QAErF,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAkC,CAAC;IACxF,CAAC;IAED,8DAA8D;IAC9D,aAAa,CAAC,QAAyC;QACnD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,wCAAwC;IACxC,aAAa;QACT,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED,4BAA4B;IAC5B,KAAK;QACD,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;IACnB,CAAC;CACJ"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { FakeEventBus } from "./fake-events.js";
|
|
2
|
+
export { FakeQueue, type FakeDispatchedJob } from "./fake-queue.js";
|
|
3
|
+
export { FakeMail } from "./fake-mail.js";
|
|
4
|
+
export { createTestApplication, type TestAppOptions } from "./create-test-application.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,SAAS,EAA0B,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAuB,MAAM,8BAA8B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wild-framework/testing",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "Sphah",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/KhandaSoftware/wild-framework.git"
|
|
24
|
+
},
|
|
25
|
+
"description": "Testing helpers for Wild Framework — fake events, queue, mail, and a test application builder.",
|
|
26
|
+
"keywords": [
|
|
27
|
+
"wild",
|
|
28
|
+
"framework",
|
|
29
|
+
"testing",
|
|
30
|
+
"test",
|
|
31
|
+
"fake",
|
|
32
|
+
"mock"
|
|
33
|
+
],
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@wild-framework/core": "0.1.1",
|
|
36
|
+
"@wild-framework/container": "0.1.1",
|
|
37
|
+
"@wild-framework/events": "0.1.1",
|
|
38
|
+
"@wild-framework/queue": "0.1.1",
|
|
39
|
+
"@wild-framework/mail": "0.1.1"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc",
|
|
43
|
+
"clean": "rm -rf dist",
|
|
44
|
+
"test": "vitest run"
|
|
45
|
+
}
|
|
46
|
+
}
|