@asenajs/asena 0.7.0 → 0.8.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.
Files changed (140) hide show
  1. package/README.md +2 -2
  2. package/dist/lib/adapter/AsenaAdapter.d.ts +5 -3
  3. package/dist/lib/adapter/AsenaAdapter.js.map +1 -1
  4. package/dist/lib/adapter/AsenaContext.d.ts +6 -0
  5. package/dist/lib/adapter/types/ServeOptions.d.ts +16 -0
  6. package/dist/lib/ioc/Container.d.ts +25 -0
  7. package/dist/lib/ioc/Container.js +47 -0
  8. package/dist/lib/ioc/Container.js.map +1 -1
  9. package/dist/lib/ioc/CoreContainer.d.ts +5 -3
  10. package/dist/lib/ioc/CoreContainer.js +9 -3
  11. package/dist/lib/ioc/CoreContainer.js.map +1 -1
  12. package/dist/lib/ioc/IocEngine.js +4 -5
  13. package/dist/lib/ioc/IocEngine.js.map +1 -1
  14. package/dist/lib/ioc/component/decorators/Inject.js +16 -0
  15. package/dist/lib/ioc/component/decorators/Inject.js.map +1 -1
  16. package/dist/lib/ioc/constants/ComponentConstants.d.ts +4 -0
  17. package/dist/lib/ioc/constants/ComponentConstants.js +5 -0
  18. package/dist/lib/ioc/constants/ComponentConstants.js.map +1 -1
  19. package/dist/lib/ioc/types/ICoreServiceNamesType.d.ts +1 -0
  20. package/dist/lib/ioc/types/ICoreServiceNamesType.js +1 -0
  21. package/dist/lib/ioc/types/ICoreServiceNamesType.js.map +1 -1
  22. package/dist/lib/ioc/types/InjectableComponent.d.ts +10 -0
  23. package/dist/lib/ioc/types/decorators/ComponentType.d.ts +2 -1
  24. package/dist/lib/ioc/types/decorators/ComponentType.js +1 -0
  25. package/dist/lib/ioc/types/decorators/ComponentType.js.map +1 -1
  26. package/dist/lib/server/AsenaServer.d.ts +46 -3
  27. package/dist/lib/server/AsenaServer.js +159 -29
  28. package/dist/lib/server/AsenaServer.js.map +1 -1
  29. package/dist/lib/server/AsenaServerFactory.d.ts +38 -3
  30. package/dist/lib/server/AsenaServerFactory.js +21 -2
  31. package/dist/lib/server/AsenaServerFactory.js.map +1 -1
  32. package/dist/lib/server/config/AsenaConfig.d.ts +82 -4
  33. package/dist/lib/server/config/AsenaConfig.js +39 -1
  34. package/dist/lib/server/config/AsenaConfig.js.map +1 -1
  35. package/dist/lib/server/decorators/components/FrontendController.js.map +1 -1
  36. package/dist/lib/server/decorators/components/MessageController.d.ts +49 -0
  37. package/dist/lib/server/decorators/components/MessageController.js +62 -0
  38. package/dist/lib/server/decorators/components/MessageController.js.map +1 -0
  39. package/dist/lib/server/decorators/components/index.d.ts +1 -0
  40. package/dist/lib/server/decorators/components/index.js +1 -0
  41. package/dist/lib/server/decorators/components/index.js.map +1 -1
  42. package/dist/lib/server/event/EventDispatchService.d.ts +3 -7
  43. package/dist/lib/server/event/EventDispatchService.js +9 -40
  44. package/dist/lib/server/event/EventDispatchService.js.map +1 -1
  45. package/dist/lib/server/event/PatternHandlerIndex.d.ts +53 -0
  46. package/dist/lib/server/event/PatternHandlerIndex.js +100 -0
  47. package/dist/lib/server/event/PatternHandlerIndex.js.map +1 -0
  48. package/dist/lib/server/event/decorators/On.d.ts +4 -0
  49. package/dist/lib/server/event/decorators/On.js +6 -0
  50. package/dist/lib/server/event/decorators/On.js.map +1 -1
  51. package/dist/lib/server/event/index.d.ts +1 -0
  52. package/dist/lib/server/event/index.js +2 -0
  53. package/dist/lib/server/event/index.js.map +1 -1
  54. package/dist/lib/server/event/types.d.ts +12 -0
  55. package/dist/lib/server/health/HealthServer.d.ts +26 -0
  56. package/dist/lib/server/health/HealthServer.js +63 -0
  57. package/dist/lib/server/health/HealthServer.js.map +1 -0
  58. package/dist/lib/server/health/index.d.ts +1 -0
  59. package/dist/lib/server/health/index.js +2 -0
  60. package/dist/lib/server/health/index.js.map +1 -0
  61. package/dist/lib/server/messaging/Ulak.d.ts +156 -0
  62. package/dist/lib/server/messaging/Ulak.js +174 -0
  63. package/dist/lib/server/messaging/Ulak.js.map +1 -1
  64. package/dist/lib/server/messaging/types.d.ts +5 -1
  65. package/dist/lib/server/messaging/types.js +5 -0
  66. package/dist/lib/server/messaging/types.js.map +1 -1
  67. package/dist/lib/server/microservice/InMemoryTransport.d.ts +45 -0
  68. package/dist/lib/server/microservice/InMemoryTransport.js +124 -0
  69. package/dist/lib/server/microservice/InMemoryTransport.js.map +1 -0
  70. package/dist/lib/server/microservice/MicroserviceTransport.d.ts +132 -0
  71. package/dist/lib/server/microservice/MicroserviceTransport.js +2 -0
  72. package/dist/lib/server/microservice/MicroserviceTransport.js.map +1 -0
  73. package/dist/lib/server/microservice/decorators/EventPattern.d.ts +38 -0
  74. package/dist/lib/server/microservice/decorators/EventPattern.js +59 -0
  75. package/dist/lib/server/microservice/decorators/EventPattern.js.map +1 -0
  76. package/dist/lib/server/microservice/decorators/MessagePattern.d.ts +31 -0
  77. package/dist/lib/server/microservice/decorators/MessagePattern.js +55 -0
  78. package/dist/lib/server/microservice/decorators/MessagePattern.js.map +1 -0
  79. package/dist/lib/server/microservice/decorators/index.d.ts +2 -0
  80. package/dist/lib/server/microservice/decorators/index.js +3 -0
  81. package/dist/lib/server/microservice/decorators/index.js.map +1 -0
  82. package/dist/lib/server/microservice/index.d.ts +5 -0
  83. package/dist/lib/server/microservice/index.js +11 -0
  84. package/dist/lib/server/microservice/index.js.map +1 -0
  85. package/dist/lib/server/microservice/interceptorChain.d.ts +20 -0
  86. package/dist/lib/server/microservice/interceptorChain.js +39 -0
  87. package/dist/lib/server/microservice/interceptorChain.js.map +1 -0
  88. package/dist/lib/server/microservice/types.d.ts +142 -0
  89. package/dist/lib/server/microservice/types.js +5 -0
  90. package/dist/lib/server/microservice/types.js.map +1 -0
  91. package/dist/lib/server/src/services/PrepareEventService.d.ts +4 -1
  92. package/dist/lib/server/src/services/PrepareEventService.js +10 -3
  93. package/dist/lib/server/src/services/PrepareEventService.js.map +1 -1
  94. package/dist/lib/server/src/services/PrepareFrontendControllerService.d.ts +1 -0
  95. package/dist/lib/server/src/services/PrepareFrontendControllerService.js +1 -1
  96. package/dist/lib/server/src/services/PrepareFrontendControllerService.js.map +1 -1
  97. package/dist/lib/server/src/services/PrepareMicroserviceService.d.ts +66 -0
  98. package/dist/lib/server/src/services/PrepareMicroserviceService.js +193 -0
  99. package/dist/lib/server/src/services/PrepareMicroserviceService.js.map +1 -0
  100. package/dist/lib/server/src/services/PrepareScheduleService.js.map +1 -1
  101. package/dist/lib/server/web/decorators/methods/Connect.js +9 -1
  102. package/dist/lib/server/web/decorators/methods/Connect.js.map +1 -1
  103. package/dist/lib/server/web/decorators/methods/Options.js +9 -1
  104. package/dist/lib/server/web/decorators/methods/Options.js.map +1 -1
  105. package/dist/lib/server/web/websocket/AsenaSocket.js.map +1 -1
  106. package/dist/lib/test/factory/deepMock.d.ts +25 -0
  107. package/dist/lib/test/factory/deepMock.js +105 -0
  108. package/dist/lib/test/factory/deepMock.js.map +1 -0
  109. package/dist/lib/test/factory/ulakStub.d.ts +44 -0
  110. package/dist/lib/test/factory/ulakStub.js +40 -0
  111. package/dist/lib/test/factory/ulakStub.js.map +1 -0
  112. package/dist/lib/test/harness/createTestApp.d.ts +33 -0
  113. package/dist/lib/test/harness/createTestApp.js +105 -0
  114. package/dist/lib/test/harness/createTestApp.js.map +1 -0
  115. package/dist/lib/test/harness/createWebTest.d.ts +28 -0
  116. package/dist/lib/test/harness/createWebTest.js +127 -0
  117. package/dist/lib/test/harness/createWebTest.js.map +1 -0
  118. package/dist/lib/test/harness/silentLogger.d.ts +27 -0
  119. package/dist/lib/test/harness/silentLogger.js +54 -0
  120. package/dist/lib/test/harness/silentLogger.js.map +1 -0
  121. package/dist/lib/test/harness/types.d.ts +147 -0
  122. package/dist/lib/test/harness/types.js +2 -0
  123. package/dist/lib/test/harness/types.js.map +1 -0
  124. package/dist/lib/test/http/TestHttpCall.d.ts +78 -0
  125. package/dist/lib/test/http/TestHttpCall.js +149 -0
  126. package/dist/lib/test/http/TestHttpCall.js.map +1 -0
  127. package/dist/lib/test/http/TestHttpResponse.d.ts +46 -0
  128. package/dist/lib/test/http/TestHttpResponse.js +70 -0
  129. package/dist/lib/test/http/TestHttpResponse.js.map +1 -0
  130. package/dist/lib/test/index.d.ts +9 -0
  131. package/dist/lib/test/index.js +8 -0
  132. package/dist/lib/test/index.js.map +1 -1
  133. package/dist/lib/test/metadata/discovery.d.ts +21 -0
  134. package/dist/lib/test/metadata/discovery.js +37 -8
  135. package/dist/lib/test/metadata/discovery.js.map +1 -1
  136. package/dist/lib/test/mockComponent.d.ts +25 -0
  137. package/dist/lib/test/mockComponent.js +39 -6
  138. package/dist/lib/test/mockComponent.js.map +1 -1
  139. package/dist/lib/test/types.d.ts +13 -0
  140. package/package.json +11 -7
@@ -0,0 +1,147 @@
1
+ import type { AsenaAdapter } from '../../adapter';
2
+ import type { Container } from '../../ioc';
3
+ import type { ServerLogger } from '../../logger';
4
+ import type { AsenaServer } from '../../server/AsenaServer';
5
+ import type { Class } from '../../server/types';
6
+ import type { TestHttpCall } from '../http/TestHttpCall';
7
+ /**
8
+ * How the test app accepts requests.
9
+ *
10
+ * - `server` - listens on a TCP port (default). Matches production exactly.
11
+ * - `socket` - listens on a unix domain socket instead. Still the adapter's real routing
12
+ * pipeline, but occupies no port, so parallel suites cannot collide. Requires an adapter
13
+ * that honours `AsenaStartOptions.unix`.
14
+ */
15
+ export type DispatchMode = 'server' | 'socket';
16
+ /**
17
+ * Options for {@link createTestApp}
18
+ */
19
+ export interface TestAppOptions<A extends AsenaAdapter<any, any> = AsenaAdapter<any, any>> {
20
+ /**
21
+ * The adapter instance to boot, e.g. `createHonoAdapter({ logger: silentLogger })[0]`
22
+ */
23
+ adapter: A;
24
+ /**
25
+ * Components to register. Passing this list skips filesystem scanning entirely.
26
+ */
27
+ components: Class[];
28
+ /**
29
+ * Replace registered components with test doubles, keyed by service name (`@MockBean`).
30
+ *
31
+ * Override services, not controllers: a plain object mock carries no `@Controller`
32
+ * metadata, so an overridden controller's routes would never be registered.
33
+ */
34
+ overrides?: Record<string, object>;
35
+ /**
36
+ * Logger for the booted server
37
+ *
38
+ * @default silentLogger
39
+ */
40
+ logger?: ServerLogger;
41
+ /**
42
+ * Port to bind. Ignored in `socket` dispatch.
43
+ *
44
+ * @default 0 - Bun picks a free ephemeral port, which removes the port race entirely
45
+ */
46
+ port?: number;
47
+ /**
48
+ * @default 'server'
49
+ */
50
+ dispatch?: DispatchMode;
51
+ }
52
+ /**
53
+ * A booted test application
54
+ */
55
+ export interface TestApp {
56
+ /**
57
+ * The running server
58
+ */
59
+ readonly server: AsenaServer<any>;
60
+ /**
61
+ * The user component container
62
+ */
63
+ readonly container: Container;
64
+ /**
65
+ * The bound TCP port. `0` in `socket` dispatch, where no port is used.
66
+ */
67
+ readonly port: number;
68
+ /**
69
+ * Base URL for HTTP calls. In `socket` dispatch the host is a placeholder - routing
70
+ * happens over {@link socketPath}.
71
+ */
72
+ readonly baseUrl: string;
73
+ /**
74
+ * Path of the unix socket, when running in `socket` dispatch
75
+ */
76
+ readonly socketPath?: string;
77
+ /**
78
+ * Resolves a component from the container
79
+ *
80
+ * @param name - Registered service name
81
+ */
82
+ resolve<T>(name: string): Promise<T>;
83
+ /**
84
+ * Builds a WebSocket URL for the given path, correct for the active dispatch mode
85
+ *
86
+ * @param path - Route path, e.g. `/ws/chat`
87
+ */
88
+ wsUrl(path: string): string;
89
+ /**
90
+ * Starts a request with an explicit method in `init`
91
+ *
92
+ * @param path - Path relative to the app root
93
+ * @param init - Standard fetch init
94
+ */
95
+ request(path: string, init?: RequestInit): TestHttpCall;
96
+ get(path: string, init?: RequestInit): TestHttpCall;
97
+ post(path: string, init?: RequestInit): TestHttpCall;
98
+ put(path: string, init?: RequestInit): TestHttpCall;
99
+ patch(path: string, init?: RequestInit): TestHttpCall;
100
+ delete(path: string, init?: RequestInit): TestHttpCall;
101
+ head(path: string, init?: RequestInit): TestHttpCall;
102
+ options(path: string, init?: RequestInit): TestHttpCall;
103
+ /**
104
+ * Stops the server and removes the unix socket if one was created. Idempotent.
105
+ */
106
+ stop(): Promise<void>;
107
+ /**
108
+ * Enables `await using app = await createTestApp(...)`
109
+ */
110
+ [Symbol.asyncDispose](): Promise<void>;
111
+ }
112
+ /**
113
+ * Options for {@link createWebTest}
114
+ */
115
+ export interface WebTestOptions<A extends AsenaAdapter<any, any> = AsenaAdapter<any, any>> {
116
+ adapter: A;
117
+ /**
118
+ * Controller(s) under test
119
+ */
120
+ controllers: Class | Class[];
121
+ /**
122
+ * Extra components to register for real, alongside the controllers' middlewares and
123
+ * validators (which are always real, since the framework resolves them by name)
124
+ */
125
+ components?: Class[];
126
+ /**
127
+ * Explicit doubles, keyed by service name. These win over the generated auto-mocks.
128
+ */
129
+ overrides?: Record<string, object>;
130
+ logger?: ServerLogger;
131
+ port?: number;
132
+ dispatch?: DispatchMode;
133
+ }
134
+ /**
135
+ * Result of {@link createWebTest}
136
+ */
137
+ export interface WebTestResult {
138
+ app: TestApp;
139
+ /**
140
+ * Every double in play - both auto-generated mocks and the explicit `overrides` - keyed
141
+ * by **service name** (not field name, unlike `mockComponent`).
142
+ *
143
+ * One shared mock per service, so two controllers injecting the same service see the
144
+ * same double.
145
+ */
146
+ mocks: Record<string, any>;
147
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../lib/test/harness/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,78 @@
1
+ import { TestHttpResponse } from './TestHttpResponse';
2
+ /**
3
+ * A pending HTTP call with a fluent assertion chain.
4
+ *
5
+ * Nothing is sent until the call is awaited. Assertions queue up in the order they were
6
+ * chained and run against the buffered response; the send is memoized, so awaiting the
7
+ * same call twice does not issue a second request.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * await app.get('/users/1').expectStatus(200).expectJson({ id: '1', name: 'Ada' });
12
+ *
13
+ * const res = await app.post('/users', { body: JSON.stringify({ name: 'Ada' }) }).expectStatus(201);
14
+ * expect(res.json().id).toBeString();
15
+ * ```
16
+ */
17
+ export declare class TestHttpCall implements PromiseLike<TestHttpResponse> {
18
+ private readonly assertions;
19
+ private pending?;
20
+ private readonly url;
21
+ private readonly init?;
22
+ constructor(url: string, init?: RequestInit);
23
+ /**
24
+ * Asserts the response status code
25
+ *
26
+ * @param expected - Expected status
27
+ * @returns this, for chaining
28
+ */
29
+ expectStatus(expected: number): this;
30
+ /**
31
+ * Asserts a response header
32
+ *
33
+ * @param name - Header name (case-insensitive)
34
+ * @param expected - Exact value, or a pattern to match
35
+ * @returns this, for chaining
36
+ */
37
+ expectHeader(name: string, expected: string | RegExp): this;
38
+ /**
39
+ * Asserts the whole JSON body deep-equals the expected value
40
+ *
41
+ * @param expected - Expected body
42
+ * @returns this, for chaining
43
+ */
44
+ expectJson<T>(expected: T): this;
45
+ /**
46
+ * Asserts the JSON body contains at least the given properties
47
+ *
48
+ * @param partial - Subset the body must match
49
+ * @returns this, for chaining
50
+ */
51
+ expectJsonContains(partial: object): this;
52
+ /**
53
+ * Asserts the raw text body
54
+ *
55
+ * @param expected - Exact body, or a pattern to match
56
+ * @returns this, for chaining
57
+ */
58
+ expectBody(expected: string | RegExp): this;
59
+ /**
60
+ * Escape hatch for assertions the chain does not cover
61
+ *
62
+ * @param assertion - Runs against the buffered response, may be async
63
+ * @returns this, for chaining
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * await app.get('/users').expect((res) => {
68
+ * expect(res.json<User[]>()).toHaveLength(3);
69
+ * });
70
+ * ```
71
+ */
72
+ expect(assertion: (response: TestHttpResponse) => void | Promise<void>): this;
73
+ then<TResult1 = TestHttpResponse, TResult2 = never>(onfulfilled?: ((value: TestHttpResponse) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
74
+ private enqueue;
75
+ private send;
76
+ private run;
77
+ private describeRequest;
78
+ }
@@ -0,0 +1,149 @@
1
+ import { expect } from 'bun:test';
2
+ import { TestHttpResponse, truncate } from './TestHttpResponse';
3
+ /**
4
+ * A pending HTTP call with a fluent assertion chain.
5
+ *
6
+ * Nothing is sent until the call is awaited. Assertions queue up in the order they were
7
+ * chained and run against the buffered response; the send is memoized, so awaiting the
8
+ * same call twice does not issue a second request.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * await app.get('/users/1').expectStatus(200).expectJson({ id: '1', name: 'Ada' });
13
+ *
14
+ * const res = await app.post('/users', { body: JSON.stringify({ name: 'Ada' }) }).expectStatus(201);
15
+ * expect(res.json().id).toBeString();
16
+ * ```
17
+ */
18
+ export class TestHttpCall {
19
+ assertions = [];
20
+ pending;
21
+ url;
22
+ init;
23
+ constructor(url, init) {
24
+ this.url = url;
25
+ this.init = init;
26
+ }
27
+ /**
28
+ * Asserts the response status code
29
+ *
30
+ * @param expected - Expected status
31
+ * @returns this, for chaining
32
+ */
33
+ expectStatus(expected) {
34
+ // Deliberately not `expect(status).toBe(n)`: a bare number mismatch is the least
35
+ // useful failure in an HTTP test. The body almost always explains why.
36
+ return this.enqueue((response) => {
37
+ if (response.status !== expected) {
38
+ throw new Error(`Expected status ${expected} but received ${response.status} for ${this.describeRequest()}\n` +
39
+ `Body: ${truncate(response.text())}`);
40
+ }
41
+ });
42
+ }
43
+ /**
44
+ * Asserts a response header
45
+ *
46
+ * @param name - Header name (case-insensitive)
47
+ * @param expected - Exact value, or a pattern to match
48
+ * @returns this, for chaining
49
+ */
50
+ expectHeader(name, expected) {
51
+ return this.enqueue((response) => {
52
+ const actual = response.headers.get(name);
53
+ if (actual === null) {
54
+ const received = [];
55
+ response.headers.forEach((_value, key) => received.push(key));
56
+ throw new Error(`Expected header '${name}' to be present for ${this.describeRequest()}, but it was not sent.\n` +
57
+ `Received headers: ${received.join(', ') || '<none>'}`);
58
+ }
59
+ if (expected instanceof RegExp) {
60
+ expect(actual).toMatch(expected);
61
+ }
62
+ else {
63
+ expect(actual).toBe(expected);
64
+ }
65
+ });
66
+ }
67
+ /**
68
+ * Asserts the whole JSON body deep-equals the expected value
69
+ *
70
+ * @param expected - Expected body
71
+ * @returns this, for chaining
72
+ */
73
+ expectJson(expected) {
74
+ return this.enqueue((response) => {
75
+ expect(response.json()).toEqual(expected);
76
+ });
77
+ }
78
+ /**
79
+ * Asserts the JSON body contains at least the given properties
80
+ *
81
+ * @param partial - Subset the body must match
82
+ * @returns this, for chaining
83
+ */
84
+ expectJsonContains(partial) {
85
+ return this.enqueue((response) => {
86
+ expect(response.json()).toMatchObject(partial);
87
+ });
88
+ }
89
+ /**
90
+ * Asserts the raw text body
91
+ *
92
+ * @param expected - Exact body, or a pattern to match
93
+ * @returns this, for chaining
94
+ */
95
+ expectBody(expected) {
96
+ return this.enqueue((response) => {
97
+ if (expected instanceof RegExp) {
98
+ expect(response.text()).toMatch(expected);
99
+ }
100
+ else {
101
+ expect(response.text()).toBe(expected);
102
+ }
103
+ });
104
+ }
105
+ /**
106
+ * Escape hatch for assertions the chain does not cover
107
+ *
108
+ * @param assertion - Runs against the buffered response, may be async
109
+ * @returns this, for chaining
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * await app.get('/users').expect((res) => {
114
+ * expect(res.json<User[]>()).toHaveLength(3);
115
+ * });
116
+ * ```
117
+ */
118
+ expect(assertion) {
119
+ return this.enqueue(assertion);
120
+ }
121
+ then(onfulfilled, onrejected) {
122
+ return this.send().then(onfulfilled, onrejected);
123
+ }
124
+ enqueue(assertion) {
125
+ if (this.pending !== undefined) {
126
+ throw new Error('Cannot add assertions to a TestHttpCall that has already been sent. ' +
127
+ 'Chain every expect* call before awaiting the request.');
128
+ }
129
+ this.assertions.push(assertion);
130
+ return this;
131
+ }
132
+ send() {
133
+ if (this.pending === undefined) {
134
+ this.pending = this.run();
135
+ }
136
+ return this.pending;
137
+ }
138
+ async run() {
139
+ const response = await TestHttpResponse.from(await fetch(this.url, this.init));
140
+ for (const assertion of this.assertions) {
141
+ await assertion(response);
142
+ }
143
+ return response;
144
+ }
145
+ describeRequest() {
146
+ return `${(this.init?.method ?? 'GET').toUpperCase()} ${this.url}`;
147
+ }
148
+ }
149
+ //# sourceMappingURL=TestHttpCall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestHttpCall.js","sourceRoot":"","sources":["../../../../lib/test/http/TestHttpCall.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * A response whose body has already been read.
3
+ *
4
+ * `Response` bodies can only be consumed once, which makes them awkward to assert against
5
+ * more than one way. This buffers the body at construction so `text()` and `json()` are
6
+ * synchronous and repeatable.
7
+ */
8
+ export declare class TestHttpResponse {
9
+ /**
10
+ * The underlying fetch Response. Its body stream is already consumed.
11
+ */
12
+ readonly raw: Response;
13
+ private readonly body;
14
+ private constructor();
15
+ /**
16
+ * Buffers a fetch Response into a TestHttpResponse
17
+ *
18
+ * @param raw - Response to consume
19
+ * @returns The buffered response
20
+ */
21
+ static from(raw: Response): Promise<TestHttpResponse>;
22
+ get status(): number;
23
+ get headers(): Headers;
24
+ /**
25
+ * The response body as text
26
+ *
27
+ * @returns Body string
28
+ */
29
+ text(): string;
30
+ /**
31
+ * The response body parsed as JSON
32
+ *
33
+ * @returns Parsed body
34
+ * @throws When the body is not valid JSON - the message includes the raw body
35
+ */
36
+ json<T = any>(): T;
37
+ }
38
+ /**
39
+ * Shortens a body for error messages so a large HTML page cannot bury the failure
40
+ *
41
+ * @param value - Body text
42
+ * @returns Truncated text
43
+ *
44
+ * @internal
45
+ */
46
+ export declare function truncate(value: string, limit?: number): string;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * A response whose body has already been read.
3
+ *
4
+ * `Response` bodies can only be consumed once, which makes them awkward to assert against
5
+ * more than one way. This buffers the body at construction so `text()` and `json()` are
6
+ * synchronous and repeatable.
7
+ */
8
+ export class TestHttpResponse {
9
+ /**
10
+ * The underlying fetch Response. Its body stream is already consumed.
11
+ */
12
+ raw;
13
+ body;
14
+ constructor(raw, body) {
15
+ this.raw = raw;
16
+ this.body = body;
17
+ }
18
+ /**
19
+ * Buffers a fetch Response into a TestHttpResponse
20
+ *
21
+ * @param raw - Response to consume
22
+ * @returns The buffered response
23
+ */
24
+ static async from(raw) {
25
+ return new TestHttpResponse(raw, await raw.text());
26
+ }
27
+ get status() {
28
+ return this.raw.status;
29
+ }
30
+ get headers() {
31
+ return this.raw.headers;
32
+ }
33
+ /**
34
+ * The response body as text
35
+ *
36
+ * @returns Body string
37
+ */
38
+ text() {
39
+ return this.body;
40
+ }
41
+ /**
42
+ * The response body parsed as JSON
43
+ *
44
+ * @returns Parsed body
45
+ * @throws When the body is not valid JSON - the message includes the raw body
46
+ */
47
+ json() {
48
+ try {
49
+ return JSON.parse(this.body);
50
+ }
51
+ catch {
52
+ throw new Error(`Expected a JSON body but parsing failed. Received: ${truncate(this.body)}`);
53
+ }
54
+ }
55
+ }
56
+ /**
57
+ * Shortens a body for error messages so a large HTML page cannot bury the failure
58
+ *
59
+ * @param value - Body text
60
+ * @returns Truncated text
61
+ *
62
+ * @internal
63
+ */
64
+ export function truncate(value, limit = 500) {
65
+ if (value.length <= limit) {
66
+ return value.length ? value : '<empty body>';
67
+ }
68
+ return `${value.slice(0, limit)}... (${value.length} bytes total)`;
69
+ }
70
+ //# sourceMappingURL=TestHttpResponse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestHttpResponse.js","sourceRoot":"","sources":["../../../../lib/test/http/TestHttpResponse.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,OAAO,gBAAgB;IAC3B;;OAEG;IACa,GAAG,CAAW;IAEb,IAAI,CAAS;IAE9B,YAAoB,GAAa,EAAE,IAAY;QAC7C,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAa;QACpC,OAAO,IAAI,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;IACzB,CAAC;IAED,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACI,IAAI;QACT,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACI,IAAI;QACT,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAM,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,sDAAsD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,KAAK,GAAG,GAAG;IACjD,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC;IAC/C,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,QAAQ,KAAK,CAAC,MAAM,eAAe,CAAC;AACrE,CAAC"}
@@ -1,3 +1,12 @@
1
1
  export { mockComponent, mockComponentAsync } from './mockComponent';
2
2
  export type { MockComponentOptions, MockedComponent } from './types';
3
3
  export { createMockFromClass } from './factory/mockFactory';
4
+ export { createDeepMock } from './factory/deepMock';
5
+ export { createTestUlakStub, type TestUlakNameSpace } from './factory/ulakStub';
6
+ export { discoverInjectedFields, discoverInjectedFieldsFromClass } from './metadata/discovery';
7
+ export { createTestApp } from './harness/createTestApp';
8
+ export { createWebTest } from './harness/createWebTest';
9
+ export { createCapturingLogger, silentLogger, type CapturedLogEntry } from './harness/silentLogger';
10
+ export type { DispatchMode, TestApp, TestAppOptions, WebTestOptions, WebTestResult } from './harness/types';
11
+ export { TestHttpCall } from './http/TestHttpCall';
12
+ export { TestHttpResponse } from './http/TestHttpResponse';
@@ -1,3 +1,11 @@
1
1
  export { mockComponent, mockComponentAsync } from './mockComponent';
2
2
  export { createMockFromClass } from './factory/mockFactory';
3
+ export { createDeepMock } from './factory/deepMock';
4
+ export { createTestUlakStub } from './factory/ulakStub';
5
+ export { discoverInjectedFields, discoverInjectedFieldsFromClass } from './metadata/discovery';
6
+ export { createTestApp } from './harness/createTestApp';
7
+ export { createWebTest } from './harness/createWebTest';
8
+ export { createCapturingLogger, silentLogger } from './harness/silentLogger';
9
+ export { TestHttpCall } from './http/TestHttpCall';
10
+ export { TestHttpResponse } from './http/TestHttpResponse';
3
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAA0B,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAC;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAyB,MAAM,wBAAwB,CAAC;AAEpG,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -16,6 +16,27 @@ import type { FieldMetadata } from '../types';
16
16
  * ```
17
17
  */
18
18
  export declare function discoverInjectedFields(instance: any): FieldMetadata[];
19
+ /**
20
+ * Discovers all fields with @Inject decorator in a component class
21
+ * Traverses the constructor chain to support inheritance - no instantiation required
22
+ *
23
+ * This is the class-based counterpart of {@link discoverInjectedFields}. It is what
24
+ * slice tests use, since they must inspect a component's dependencies before deciding
25
+ * whether to register it for real or replace it with a mock.
26
+ *
27
+ * @param ComponentClass - Component class to inspect
28
+ * @returns Array of field metadata containing field names, service names, class refs and expressions
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const fields = discoverInjectedFieldsFromClass(AuthService);
33
+ * // Returns: [
34
+ * // { fieldName: 'userService', serviceName: 'UserService', serviceClass: UserService },
35
+ * // { fieldName: 'chat', serviceName: '__Ulak__', expression: (u) => u.namespace('/chat') }
36
+ * // ]
37
+ * ```
38
+ */
39
+ export declare function discoverInjectedFieldsFromClass(ComponentClass: any): FieldMetadata[];
19
40
  /**
20
41
  * Checks if a component has any injected dependencies
21
42
  *
@@ -17,16 +17,44 @@ import { getTypedMetadata, getOwnTypedMetadata } from '../../utils';
17
17
  * ```
18
18
  */
19
19
  export function discoverInjectedFields(instance) {
20
+ return discoverInjectedFieldsFromClass(Object.getPrototypeOf(instance)?.constructor);
21
+ }
22
+ /**
23
+ * Discovers all fields with @Inject decorator in a component class
24
+ * Traverses the constructor chain to support inheritance - no instantiation required
25
+ *
26
+ * This is the class-based counterpart of {@link discoverInjectedFields}. It is what
27
+ * slice tests use, since they must inspect a component's dependencies before deciding
28
+ * whether to register it for real or replace it with a mock.
29
+ *
30
+ * @param ComponentClass - Component class to inspect
31
+ * @returns Array of field metadata containing field names, service names, class refs and expressions
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const fields = discoverInjectedFieldsFromClass(AuthService);
36
+ * // Returns: [
37
+ * // { fieldName: 'userService', serviceName: 'UserService', serviceClass: UserService },
38
+ * // { fieldName: 'chat', serviceName: '__Ulak__', expression: (u) => u.namespace('/chat') }
39
+ * // ]
40
+ * ```
41
+ */
42
+ export function discoverInjectedFieldsFromClass(ComponentClass) {
20
43
  const fields = [];
21
44
  const processedFields = new Set();
22
- // Traverse prototype chain (similar to how Container does it)
23
- let currentPrototype = Object.getPrototypeOf(instance);
24
- while (currentPrototype && currentPrototype !== Object.prototype) {
25
- const constructor = currentPrototype.constructor;
45
+ let currentClass = ComponentClass;
46
+ // Traverse the constructor chain (similar to how Container does it)
47
+ while (currentClass && currentClass !== Function.prototype) {
48
+ // Stop at native code - matches Container.getPrototypeChain behaviour
49
+ if (typeof currentClass !== 'function' || currentClass.toString().includes('[native code]')) {
50
+ break;
51
+ }
26
52
  // Get dependencies metadata for this level
27
- const dependencies = getOwnTypedMetadata(ComponentConstants.DependencyKey, constructor);
53
+ const dependencies = getOwnTypedMetadata(ComponentConstants.DependencyKey, currentClass);
54
+ // Get injected class references for this level (class-based injections only)
55
+ const dependencyClasses = getOwnTypedMetadata(ComponentConstants.DependencyClassKey, currentClass);
28
56
  // Get expressions metadata for this level
29
- const expressions = getOwnTypedMetadata(ComponentConstants.ExpressionKey, constructor);
57
+ const expressions = getOwnTypedMetadata(ComponentConstants.ExpressionKey, currentClass);
30
58
  if (dependencies) {
31
59
  // Process each dependency field
32
60
  for (const [fieldName, serviceName] of Object.entries(dependencies)) {
@@ -38,12 +66,13 @@ export function discoverInjectedFields(instance) {
38
66
  fields.push({
39
67
  fieldName,
40
68
  serviceName,
69
+ serviceClass: dependencyClasses?.[fieldName],
41
70
  expression: expressions?.[fieldName],
42
71
  });
43
72
  }
44
73
  }
45
- // Move up the prototype chain
46
- currentPrototype = Object.getPrototypeOf(currentPrototype);
74
+ // Move up the constructor chain
75
+ currentClass = Object.getPrototypeOf(currentClass);
47
76
  }
48
77
  return fields;
49
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../../lib/test/metadata/discovery.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEpE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB,CAAC,QAAa;IAClD,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAE1C,8DAA8D;IAC9D,IAAI,gBAAgB,GAAG,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAEvD,OAAO,gBAAgB,IAAI,gBAAgB,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC;QACjE,MAAM,WAAW,GAAG,gBAAgB,CAAC,WAAW,CAAC;QAEjD,2CAA2C;QAC3C,MAAM,YAAY,GAAG,mBAAmB,CAAe,kBAAkB,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QAEtG,0CAA0C;QAC1C,MAAM,WAAW,GAAG,mBAAmB,CAAc,kBAAkB,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QAEpG,IAAI,YAAY,EAAE,CAAC;YACjB,gCAAgC;YAChC,KAAK,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;gBACpE,oDAAoD;gBACpD,IAAI,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;oBACnC,SAAS;gBACX,CAAC;gBAED,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAE/B,MAAM,CAAC,IAAI,CAAC;oBACV,SAAS;oBACT,WAAW;oBACX,UAAU,EAAE,WAAW,EAAE,CAAC,SAAS,CAAC;iBACrC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,8BAA8B;QAC9B,gBAAgB,GAAG,MAAM,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,cAA2C;IAC3E,MAAM,YAAY,GAAG,gBAAgB,CAAe,kBAAkB,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IACtG,OAAO,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,cAA2C,EAC3C,SAAiB;IAEjB,MAAM,YAAY,GAAG,gBAAgB,CAAe,kBAAkB,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IACtG,OAAO,YAAY,EAAE,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,cAA2C,EAC3C,SAAiB;IAEjB,MAAM,WAAW,GAAG,gBAAgB,CAAc,kBAAkB,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IACpG,OAAO,WAAW,EAAE,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../../lib/test/metadata/discovery.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEpE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB,CAAC,QAAa;IAClD,OAAO,+BAA+B,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC,CAAC;AACvF,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,+BAA+B,CAAC,cAAmB;IACjE,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAE1C,IAAI,YAAY,GAAG,cAAc,CAAC;IAElC,oEAAoE;IACpE,OAAO,YAAY,IAAI,YAAY,KAAK,QAAQ,CAAC,SAAS,EAAE,CAAC;QAC3D,sEAAsE;QACtE,IAAI,OAAO,YAAY,KAAK,UAAU,IAAI,YAAY,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YAC5F,MAAM;QACR,CAAC;QAED,2CAA2C;QAC3C,MAAM,YAAY,GAAG,mBAAmB,CAAe,kBAAkB,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;QAEvG,6EAA6E;QAC7E,MAAM,iBAAiB,GAAG,mBAAmB,CAC3C,kBAAkB,CAAC,kBAAkB,EACrC,YAAY,CACb,CAAC;QAEF,0CAA0C;QAC1C,MAAM,WAAW,GAAG,mBAAmB,CAAc,kBAAkB,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;QAErG,IAAI,YAAY,EAAE,CAAC;YACjB,gCAAgC;YAChC,KAAK,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;gBACpE,oDAAoD;gBACpD,IAAI,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;oBACnC,SAAS;gBACX,CAAC;gBAED,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAE/B,MAAM,CAAC,IAAI,CAAC;oBACV,SAAS;oBACT,WAAW;oBACX,YAAY,EAAE,iBAAiB,EAAE,CAAC,SAAS,CAAC;oBAC5C,UAAU,EAAE,WAAW,EAAE,CAAC,SAAS,CAAC;iBACrC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,cAA2C;IAC3E,MAAM,YAAY,GAAG,gBAAgB,CAAe,kBAAkB,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IACtG,OAAO,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,cAA2C,EAC3C,SAAiB;IAEjB,MAAM,YAAY,GAAG,gBAAgB,CAAe,kBAAkB,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IACtG,OAAO,YAAY,EAAE,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,cAA2C,EAC3C,SAAiB;IAEjB,MAAM,WAAW,GAAG,gBAAgB,CAAc,kBAAkB,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IACpG,OAAO,WAAW,EAAE,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}