exisjs 0.7.12 → 0.7.14

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 (132) hide show
  1. package/README.md +195 -39
  2. package/dist/cli/commands/run.d.ts.map +1 -1
  3. package/dist/cli/commands/run.js +3 -1
  4. package/dist/cli/commands/run.js.map +1 -1
  5. package/dist/config/types.d.ts +2 -2
  6. package/dist/config/types.d.ts.map +1 -1
  7. package/dist/decorators/params.d.ts +21 -0
  8. package/dist/decorators/params.d.ts.map +1 -1
  9. package/dist/decorators/params.js +21 -1
  10. package/dist/decorators/params.js.map +1 -1
  11. package/dist/di/container.d.ts +15 -6
  12. package/dist/di/container.d.ts.map +1 -1
  13. package/dist/di/container.js +26 -3
  14. package/dist/di/container.js.map +1 -1
  15. package/dist/di/index.d.ts +1 -1
  16. package/dist/di/index.d.ts.map +1 -1
  17. package/dist/di/index.js.map +1 -1
  18. package/dist/di/inject.d.ts +2 -1
  19. package/dist/di/inject.d.ts.map +1 -1
  20. package/dist/di/inject.js +2 -1
  21. package/dist/di/inject.js.map +1 -1
  22. package/dist/docs/ARCHITECTURE.md +130 -78
  23. package/dist/docs/BENCHMARKS.md +4 -4
  24. package/dist/docs/content/README.md +43 -44
  25. package/dist/docs/content/boundaries.mdx +138 -61
  26. package/dist/docs/content/cli/commands.mdx +151 -128
  27. package/dist/docs/content/cli/overview.mdx +61 -47
  28. package/dist/docs/content/cli/usage.mdx +107 -30
  29. package/dist/docs/content/config.mdx +145 -158
  30. package/dist/docs/content/controllers.mdx +193 -464
  31. package/dist/docs/content/cron.mdx +183 -69
  32. package/dist/docs/content/decorators.mdx +449 -154
  33. package/dist/docs/content/errors.mdx +202 -305
  34. package/dist/docs/content/exisjs-mcp.mdx +59 -49
  35. package/dist/docs/content/installation.mdx +243 -157
  36. package/dist/docs/content/introduction.mdx +220 -48
  37. package/dist/docs/content/middleware.mdx +171 -497
  38. package/dist/docs/content/modules.mdx +141 -83
  39. package/dist/docs/content/providers.mdx +216 -180
  40. package/dist/docs/content/requests.mdx +168 -488
  41. package/dist/docs/content/responses.mdx +200 -533
  42. package/dist/docs/content/routing.mdx +235 -598
  43. package/dist/docs/content/security.mdx +233 -57
  44. package/dist/docs/content/structure.mdx +151 -240
  45. package/dist/docs/content/swagger.mdx +192 -91
  46. package/dist/docs/content/testing.mdx +205 -74
  47. package/dist/docs/content/validation.mdx +479 -341
  48. package/dist/docs/reference/README.md +34 -2
  49. package/dist/docs/reference/config.mdx +277 -75
  50. package/dist/docs/reference/context.mdx +197 -106
  51. package/dist/docs/reference/cron.mdx +266 -152
  52. package/dist/docs/reference/database.mdx +135 -53
  53. package/dist/docs/reference/decorators.mdx +234 -116
  54. package/dist/docs/reference/di.mdx +146 -112
  55. package/dist/docs/reference/error.mdx +155 -178
  56. package/dist/docs/reference/exis.mdx +141 -70
  57. package/dist/docs/reference/logger.mdx +110 -126
  58. package/dist/docs/reference/middleware.mdx +235 -158
  59. package/dist/docs/reference/plugin.mdx +136 -64
  60. package/dist/docs/reference/router.mdx +275 -293
  61. package/dist/docs/reference/sanitize.mdx +91 -87
  62. package/dist/docs/reference/swagger.mdx +280 -100
  63. package/dist/docs/reference/testing.mdx +223 -89
  64. package/dist/docs/reference/validator.mdx +194 -206
  65. package/dist/lib/start-server.js +22 -8
  66. package/dist/lib/start-server.js.map +1 -1
  67. package/dist/module/module.d.ts +6 -3
  68. package/dist/module/module.d.ts.map +1 -1
  69. package/dist/module/module.js +17 -3
  70. package/dist/module/module.js.map +1 -1
  71. package/dist/router/controller-registrar.d.ts.map +1 -1
  72. package/dist/router/controller-registrar.js +26 -4
  73. package/dist/router/controller-registrar.js.map +1 -1
  74. package/dist/router/scanner/fs-scanner.d.ts.map +1 -1
  75. package/dist/router/scanner/fs-scanner.js +22 -0
  76. package/dist/router/scanner/fs-scanner.js.map +1 -1
  77. package/dist/router/types.d.ts +6 -4
  78. package/dist/router/types.d.ts.map +1 -1
  79. package/dist/server/app.d.ts +3 -1
  80. package/dist/server/app.d.ts.map +1 -1
  81. package/dist/server/app.js +24 -8
  82. package/dist/server/app.js.map +1 -1
  83. package/dist/server/bootstrapper.d.ts.map +1 -1
  84. package/dist/server/bootstrapper.js +19 -0
  85. package/dist/server/bootstrapper.js.map +1 -1
  86. package/dist/server/request.d.ts +2 -0
  87. package/dist/server/request.d.ts.map +1 -1
  88. package/dist/server/request.js +11 -0
  89. package/dist/server/request.js.map +1 -1
  90. package/dist/server/response.d.ts +10 -5
  91. package/dist/server/response.d.ts.map +1 -1
  92. package/dist/server/response.js +65 -18
  93. package/dist/server/response.js.map +1 -1
  94. package/dist/swagger/generator.d.ts.map +1 -1
  95. package/dist/swagger/generator.js +130 -10
  96. package/dist/swagger/generator.js.map +1 -1
  97. package/dist/telemetry/index.d.ts +12 -0
  98. package/dist/telemetry/index.d.ts.map +1 -0
  99. package/dist/telemetry/index.js +121 -0
  100. package/dist/telemetry/index.js.map +1 -0
  101. package/dist/testing/client.d.ts +1 -0
  102. package/dist/testing/client.d.ts.map +1 -1
  103. package/dist/testing/client.js +4 -1
  104. package/dist/testing/client.js.map +1 -1
  105. package/dist/testing/index.d.ts.map +1 -1
  106. package/dist/testing/index.js +11 -4
  107. package/dist/testing/index.js.map +1 -1
  108. package/dist/validator/builder.d.ts +26 -1
  109. package/dist/validator/builder.d.ts.map +1 -1
  110. package/dist/validator/builder.js +31 -0
  111. package/dist/validator/builder.js.map +1 -1
  112. package/dist/validator/engine.d.ts +23 -0
  113. package/dist/validator/engine.d.ts.map +1 -1
  114. package/dist/validator/engine.js +228 -31
  115. package/dist/validator/engine.js.map +1 -1
  116. package/dist/validator/index.d.ts +8 -4
  117. package/dist/validator/index.d.ts.map +1 -1
  118. package/dist/validator/index.js +4 -1
  119. package/dist/validator/index.js.map +1 -1
  120. package/dist/validator/tex-types.d.ts +19 -4
  121. package/dist/validator/tex-types.d.ts.map +1 -1
  122. package/dist/validator/tex-types.js +102 -0
  123. package/dist/validator/tex-types.js.map +1 -1
  124. package/dist/validator/tex.d.ts +1 -1
  125. package/dist/validator/tex.d.ts.map +1 -1
  126. package/dist/validator/tex.js +3 -1
  127. package/dist/validator/tex.js.map +1 -1
  128. package/dist/validator/types.d.ts +1 -0
  129. package/dist/validator/types.d.ts.map +1 -1
  130. package/package.json +46 -14
  131. package/dist/docs/content/dataloader.mdx +0 -170
  132. package/dist/docs/reference/dataloader.mdx +0 -91
@@ -1,145 +1,279 @@
1
1
  ---
2
- title: "Testing"
3
- description: "Strict API Reference for all Testing utilities and mocking objects."
2
+ title: "exisjs/testing"
3
+ description: "API Reference for ExisJS testing framework: test runner, createTestApp, HTTP assertions, matchers (expect), mocks (ex), and unit mocks."
4
+ nextUrl: "/docs/reference/plugin"
5
+ nextTitle: "Plugin Reference"
4
6
  ---
5
7
 
6
- # Testing (`exisjs/testing`)
8
+ # `exisjs/testing`
7
9
 
8
- This document provides the strict API signatures and TypeScript interfaces exported by the `exisjs/testing` module. For high-level testing guides, see the [Testing Guide](/docs/testing).
10
+ The `exisjs/testing` module provides an integrated testing framework built on Node's native runner (`node:test`) and assertion engine (`node:assert`). It includes the `createTestApp` synthetic HTTP client, fluent `expect` assertions, Jest-compatible `ex` spies/mocks, and unit-level mock factories (`createMockRequest`, `createMockResponse`).
9
11
 
10
12
  ---
11
13
 
12
- ## Native Node Runner Exports
13
-
14
- ExisJS fully re-exports the native `node:test` runner methods, ensuring maximum IDE compatibility while providing powerful internal enhancements (like `.each()`).
14
+ ## Module Exports
15
15
 
16
16
  ```typescript
17
- export function test(name: string, fn?: TestFunction): void
18
- export function test(name: string, options: TestOptions, fn?: TestFunction): void
17
+ import {
18
+ // Test Runner & Lifecycle
19
+ test,
20
+ describe,
21
+ it,
22
+ before,
23
+ beforeAll,
24
+ after,
25
+ afterAll,
26
+ beforeEach,
27
+ afterEach,
28
+ registerCleanup,
19
29
 
20
- export function describe(name: string, fn?: TestFunction): void
21
- export function it(name: string, fn?: TestFunction): void
30
+ // Assertions & Matchers
31
+ expect,
22
32
 
23
- export function before(fn: HookFunction): void
24
- export function after(fn: HookFunction): void
25
- export function beforeEach(fn: HookFunction): void
26
- export function afterEach(fn: HookFunction): void
27
- ```
33
+ // Mocks, Spies & Timers
34
+ ex,
35
+ mock,
28
36
 
29
- ### Parametrized Tests (`.each`)
30
- All test blocks (`test`, `describe`, `it`) support a Jest-like `.each()` signature.
37
+ // HTTP Integration Testing Client
38
+ createTestApp,
39
+ TestRequest,
31
40
 
32
- ```typescript
33
- test.each([
34
- [1, 1, 2],
35
- [2, 3, 5]
36
- ])('adds %d and %d to equal %d', (a, b, expected) => {
37
- assert.equal(a + b, expected)
38
- })
41
+ // Unit Mocking Helpers
42
+ createMockRequest,
43
+ createMockResponse,
44
+ createMockLogger,
45
+ createMockNext,
46
+ getResponseBody,
47
+ getResponseHeader,
48
+ } from 'exisjs/testing'
49
+
50
+ import type {
51
+ TestApp,
52
+ TestRequest,
53
+ TestResponse,
54
+ TestOptions,
55
+ TestContext,
56
+ TestFunction,
57
+ HookFunction,
58
+ MockRequestOptions,
59
+ MockResponse,
60
+ } from 'exisjs/testing'
39
61
  ```
40
62
 
41
63
  ---
42
64
 
43
- ## Context Management
65
+ ## 1. Native Test Runner API
44
66
 
45
- ### `createTestContext`
46
- Automatically handles booting an ExisJS `App`, processing its startup hooks, and safely closing all database and worker connections. Returns a `TestApp` client for performing HTTP requests.
67
+ ExisJS enhances the native Node test runner with Jest-like `.each()` parameterization and typed test hooks.
47
68
 
48
69
  ```typescript
49
- function createTestContext(app: App | typeof Class): TestApp
70
+ // Test suites and cases
71
+ describe(name: string, fn?: TestFunction): void
72
+ test(name: string, fn?: TestFunction): void
73
+ test(name: string, options: TestOptions, fn?: TestFunction): void
74
+ it(name: string, fn?: TestFunction): void
75
+
76
+ // Modifiers
77
+ test.only(name: string, fn?: TestFunction): void
78
+ test.skip(name: string, fn?: TestFunction): void
79
+ test.todo(name: string, fn?: TestFunction): void
80
+
81
+ // Lifecycle hooks
82
+ before(fn: HookFunction): void
83
+ beforeEach(fn: HookFunction): void
84
+ after(fn: HookFunction): void
85
+ afterEach(fn: HookFunction): void
50
86
  ```
51
87
 
52
- ### `registerCleanup`
53
- Allows third-party plugins or custom test setups to register a global cleanup function that will be executed when the test runner terminates.
88
+ ### Parametrized Tests (`.each`)
54
89
 
55
90
  ```typescript
56
- function registerCleanup(fn: () => Promise<void> | void): void
91
+ test.each([
92
+ [1, 2, 3],
93
+ [10, 20, 30],
94
+ [-5, 5, 0],
95
+ ])('calculates %d + %d = %d', (a, b, expected) => {
96
+ expect(a + b).toBe(expected)
97
+ })
57
98
  ```
58
99
 
59
100
  ---
60
101
 
61
- ## HTTP Client (TestApp & TestRequest)
102
+ ## 2. HTTP Integration Testing (`createTestApp`)
62
103
 
63
- The `TestApp` interface provides a fluent API for making HTTP requests directly against your application without binding to a network port.
104
+ Instantiates an in-memory HTTP test client that dispatches synthetic requests into an ExisJS `App` instance without binding a network port.
64
105
 
65
- ### `TestApp`
66
106
  ```typescript
67
- interface TestApp {
68
- get(path: string): TestRequest
69
- post(path: string): TestRequest
70
- put(path: string): TestRequest
71
- patch(path: string): TestRequest
72
- delete(path: string): TestRequest
73
- options(path: string): TestRequest
74
- head(path: string): TestRequest
75
- request(method: string, path: string): TestRequest
76
- }
107
+ function createTestApp(app: App | ExisAppDefinition | ExisConfig): TestApp
77
108
  ```
78
109
 
79
- ### `TestRequest`
80
- Supports chaining headers, bodies, and assertions. Once `.execute()` is called (or awaited), it returns a `TestResponse`.
110
+ ### `TestApp` Interface
111
+
112
+ | Method | Signature | Description |
113
+ | :--- | :--- | :--- |
114
+ | `get` | `(path: string, options?: RequestOptions): TestRequest` | Initiates a synthetic `GET` request. |
115
+ | `post` | `(path: string, options?: RequestOptions \| unknown): TestRequest` | Initiates a synthetic `POST` request. |
116
+ | `put` | `(path: string, options?: RequestOptions \| unknown): TestRequest` | Initiates a synthetic `PUT` request. |
117
+ | `patch` | `(path: string, options?: RequestOptions \| unknown): TestRequest` | Initiates a synthetic `PATCH` request. |
118
+ | `delete` | `(path: string, options?: RequestOptions): TestRequest` | Initiates a synthetic `DELETE` request. |
119
+ | `options` | `(path: string, options?: RequestOptions): TestRequest` | Initiates an `OPTIONS` preflight request. |
120
+ | `head` | `(path: string, options?: RequestOptions): TestRequest` | Initiates a `HEAD` request. |
121
+ | `request` | `(method: string, path: string, options?: RequestOptions): TestRequest` | Dispatches an arbitrary HTTP method request. |
122
+
123
+ ### `TestRequest` Builder
124
+
125
+ Fluent request builder allowing header configuration, payload attachment, and response assertions:
81
126
 
82
127
  ```typescript
83
- class TestRequest {
128
+ class TestRequest implements PromiseLike<TestResponse> {
84
129
  send(body: unknown): this
85
130
  set(header: string, value: string): this
86
-
87
- // Assertions
88
131
  expect(status: number): this
89
132
  expect(header: string, value: string | RegExp): this
90
133
  expect(body: unknown): this
91
-
92
- // Execution
93
134
  execute(): Promise<TestResponse>
94
- then<T>(onfulfilled: (res: TestResponse) => T): Promise<T>
95
135
  }
96
136
  ```
97
137
 
98
- ### `TestResponse`
99
- ```typescript
100
- interface TestResponse {
101
- status: number
102
- headers: Record<string, string | string[] | undefined>
103
- body: any // The parsed JSON payload (if applicable)
104
- text: string // The raw string response
105
- }
138
+ ### `TestResponse` Interface
139
+
140
+ | Property | Type | Description |
141
+ | :--- | :--- | :--- |
142
+ | `status` | `number` | HTTP status code returned by the route handler. |
143
+ | `headers` | `http.IncomingHttpHeaders` | Dictionary of HTTP response headers. |
144
+ | `body` | `any` | Parsed JSON response payload (or undefined if not JSON). |
145
+ | `text` | `string` | Raw UTF-8 string content of the response payload. |
146
+
147
+ ### Integration Test Example
148
+
149
+ ```typescript filename="tests/users.test.ts"
150
+ import { describe, it, expect, createTestApp } from 'exisjs/testing'
151
+ import server from '../src/http/server'
152
+
153
+ describe('Users API', () => {
154
+ const client = createTestApp(server)
155
+
156
+ it('creates and returns a user payload', async () => {
157
+ const res = await client
158
+ .post('/users', { name: 'Alice', email: 'alice@example.com' })
159
+ .set('Authorization', 'Bearer token_123')
160
+ .expect(201)
161
+ .expect('content-type', /application\/json/)
162
+
163
+ expect(res.body).toMatchObject({
164
+ success: true,
165
+ data: {
166
+ name: 'Alice',
167
+ email: 'alice@example.com',
168
+ },
169
+ })
170
+ })
171
+ })
106
172
  ```
107
173
 
108
174
  ---
109
175
 
110
- ## Mocks & Spies (`ex`)
176
+ ## 3. Assertion Engine (`expect`)
111
177
 
112
- The `ex` object provides a Jest-compatible API wrapper over the native `node:test` mocking utilities.
178
+ The `expect(actual)` function returns a rich matcher engine with negative chaining via `.not`:
179
+
180
+ ### Equality & Truthiness
181
+
182
+ | Matcher | Description |
183
+ | :--- | :--- |
184
+ | `toBe(value)` | Strict referential equality (`===`). |
185
+ | `toEqual(value)` | Deep equality check across objects and arrays. |
186
+ | `toStrictEqual(value)` | Deep strict equality checking prototypes and `undefined` keys. |
187
+ | `toMatchObject(subset)` | Verifies that the target object contains the specified subset of properties. |
188
+ | `toBeTruthy()` | Asserts truthy value. |
189
+ | `toBeFalsy()` | Asserts falsy value. |
190
+ | `toBeNull()` | Asserts `null`. |
191
+ | `toBeUndefined()` | Asserts `undefined`. |
192
+ | `toBeDefined()` | Asserts not `undefined`. |
193
+
194
+ ### Numeric Matchers
195
+
196
+ | Matcher | Description |
197
+ | :--- | :--- |
198
+ | `toBeGreaterThan(n)` | Asserts `actual > n`. |
199
+ | `toBeGreaterThanOrEqual(n)` | Asserts `actual >= n`. |
200
+ | `toBeLessThan(n)` | Asserts `actual < n`. |
201
+ | `toBeLessThanOrEqual(n)` | Asserts `actual <= n`. |
202
+ | `toBeCloseTo(n, precision?)` | Asserts floating point approximation. |
203
+
204
+ ### Strings, Arrays & Errors
205
+
206
+ | Matcher | Description |
207
+ | :--- | :--- |
208
+ | `toContain(item)` | Checks if a string contains a substring or array contains an element. |
209
+ | `toMatch(regex)` | Asserts string matches regular expression. |
210
+ | `toHaveLength(length)` | Asserts `.length` property matches. |
211
+ | `toThrow(error?)` | Asserts that a function throws an error matching the predicate. |
212
+ | `toBeInstanceOf(constructor)` | Asserts `actual instanceof constructor`. |
213
+
214
+ ### Mock Assertions
215
+
216
+ | Matcher | Description |
217
+ | :--- | :--- |
218
+ | `toHaveBeenCalled()` | Asserts the mock was called at least once. |
219
+ | `toHaveBeenCalledTimes(count)` | Asserts the mock was invoked an exact number of times. |
220
+ | `toHaveBeenCalledWith(...args)` | Asserts the mock was called with matching arguments. |
221
+
222
+ ---
223
+
224
+ ## 4. Spies, Mocks & Timers (`ex`)
225
+
226
+ Jest-compatible API wrapping Node's native mocking subsystem:
113
227
 
114
228
  ```typescript
115
- const ex = {
116
- // Spies
117
- fn: (impl?: Function) => MockFunction,
118
- spyOn: (obj: any, methodName: string) => MockFunction,
119
-
120
- // Modules
121
- mock: (specifier: string, factory?: () => any) => void,
122
-
123
- // Timers
124
- setSystemTime: (time: number | Date) => void,
125
- advanceTimersByTime: (ms: number) => void,
126
- useFakeTimers: () => void,
127
- useRealTimers: () => void,
128
-
129
- clearAllMocks: () => void
130
- }
229
+ // Function & Method Spies
230
+ const fn = ex.fn((x: number) => x * 2)
231
+ const spy = ex.spyOn(userService, 'findById')
232
+
233
+ // Mock Implementations
234
+ fn.mockReturnValue(42)
235
+ fn.mockResolvedValue({ id: '1' })
236
+ fn.mockRejectedValue(new Error('Failed'))
237
+ fn.mockImplementation((name) => `Hello ${name}`)
238
+ fn.mockClear()
239
+ fn.mockRestore()
240
+
241
+ // Timer Manipulation
242
+ ex.setSystemTime(new Date('2026-01-01T00:00:00Z'))
243
+ ex.advanceTimersByTime(5000)
244
+
245
+ // Module Mocking
246
+ ex.mock('./mail-client', () => ({
247
+ sendMail: ex.fn().mockResolvedValue(true),
248
+ }))
131
249
  ```
132
250
 
133
- ### `MockFunction` Extensions
134
- ExisJS extends the native `MockFunction` returned by `ex.fn()` and `ex.spyOn()` with Jest-like helpers:
251
+ ---
252
+
253
+ ## 5. Unit-Level Mocking Helpers
254
+
255
+ For unit testing individual middleware, guards, or filters without booting an entire server:
135
256
 
136
257
  ```typescript
137
- interface MockFunction {
138
- mockRestore(): void
139
- mockImplementation(impl: Function): this
140
- mockResolvedValue(val: any): this
141
- mockReturnValue(val: any): this
142
- mockRejectedValue(err: any): this
143
- mockClear(): void
144
- }
258
+ import {
259
+ createMockRequest,
260
+ createMockResponse,
261
+ createMockNext,
262
+ getResponseBody,
263
+ getResponseHeader,
264
+ } from 'exisjs/testing'
265
+
266
+ const req = createMockRequest({
267
+ method: 'POST',
268
+ url: '/api/v1/checkout',
269
+ headers: { 'x-tenant-id': 'tenant_123' },
270
+ body: { amount: 5000 },
271
+ })
272
+
273
+ const res = createMockResponse()
274
+ const next = createMockNext()
275
+
276
+ await authGuard(req, res, next)
277
+
278
+ expect(next.called).toBe(true)
145
279
  ```