@stratal/testing 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +332 -0
- package/package.json +10 -10
- package/dist/core/env/index.d.ts +0 -2
- package/dist/core/env/index.d.ts.map +0 -1
- package/dist/core/env/index.js +0 -2
- package/dist/core/env/index.js.map +0 -1
- package/dist/core/env/test-env.d.ts +0 -9
- package/dist/core/env/test-env.d.ts.map +0 -1
- package/dist/core/env/test-env.js +0 -14
- package/dist/core/env/test-env.js.map +0 -1
- package/dist/core/http/fetch-mock.d.ts +0 -236
- package/dist/core/http/fetch-mock.d.ts.map +0 -1
- package/dist/core/http/fetch-mock.js +0 -290
- package/dist/core/http/fetch-mock.js.map +0 -1
- package/dist/core/http/fetch-mock.types.d.ts +0 -48
- package/dist/core/http/fetch-mock.types.d.ts.map +0 -1
- package/dist/core/http/fetch-mock.types.js +0 -2
- package/dist/core/http/fetch-mock.types.js.map +0 -1
- package/dist/core/http/index.d.ts +0 -6
- package/dist/core/http/index.d.ts.map +0 -1
- package/dist/core/http/index.js +0 -5
- package/dist/core/http/index.js.map +0 -1
- package/dist/core/http/test-http-client.d.ts +0 -54
- package/dist/core/http/test-http-client.d.ts.map +0 -1
- package/dist/core/http/test-http-client.js +0 -75
- package/dist/core/http/test-http-client.js.map +0 -1
- package/dist/core/http/test-http-request.d.ts +0 -44
- package/dist/core/http/test-http-request.d.ts.map +0 -1
- package/dist/core/http/test-http-request.js +0 -75
- package/dist/core/http/test-http-request.js.map +0 -1
- package/dist/core/http/test-response.d.ts +0 -161
- package/dist/core/http/test-response.d.ts.map +0 -1
- package/dist/core/http/test-response.js +0 -309
- package/dist/core/http/test-response.js.map +0 -1
- package/dist/core/index.d.ts +0 -7
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -7
- package/dist/core/index.js.map +0 -1
- package/dist/core/override/index.d.ts +0 -2
- package/dist/core/override/index.d.ts.map +0 -1
- package/dist/core/override/index.js +0 -2
- package/dist/core/override/index.js.map +0 -1
- package/dist/core/override/provider-override-builder.d.ts +0 -77
- package/dist/core/override/provider-override-builder.d.ts.map +0 -1
- package/dist/core/override/provider-override-builder.js +0 -94
- package/dist/core/override/provider-override-builder.js.map +0 -1
- package/dist/core/test.d.ts +0 -48
- package/dist/core/test.d.ts.map +0 -1
- package/dist/core/test.js +0 -53
- package/dist/core/test.js.map +0 -1
- package/dist/core/testing-module-builder.d.ts +0 -98
- package/dist/core/testing-module-builder.d.ts.map +0 -1
- package/dist/core/testing-module-builder.js +0 -154
- package/dist/core/testing-module-builder.js.map +0 -1
- package/dist/core/testing-module.d.ts +0 -77
- package/dist/core/testing-module.d.ts.map +0 -1
- package/dist/core/testing-module.js +0 -99
- package/dist/core/testing-module.js.map +0 -1
- package/dist/errors/index.d.ts +0 -3
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js +0 -3
- package/dist/errors/index.js.map +0 -1
- package/dist/errors/setup-error.d.ts +0 -9
- package/dist/errors/setup-error.d.ts.map +0 -1
- package/dist/errors/setup-error.js +0 -11
- package/dist/errors/setup-error.js.map +0 -1
- package/dist/errors/test-error.d.ts +0 -9
- package/dist/errors/test-error.d.ts.map +0 -1
- package/dist/errors/test-error.js +0 -15
- package/dist/errors/test-error.js.map +0 -1
- package/dist/index.d.ts +0 -14
- package/dist/mocks/index.d.ts +0 -4
- package/dist/mocks/index.d.ts.map +0 -1
- package/dist/mocks/index.js +0 -4
- package/dist/mocks/index.js.map +0 -1
- package/dist/mocks/nodemailer.d.ts +0 -10
- package/dist/mocks/nodemailer.d.ts.map +0 -1
- package/dist/mocks/nodemailer.js +0 -9
- package/dist/mocks/nodemailer.js.map +0 -1
- package/dist/storage/fake-storage.service.d.ts +0 -114
- package/dist/storage/fake-storage.service.d.ts.map +0 -1
- package/dist/storage/fake-storage.service.js +0 -233
- package/dist/storage/fake-storage.service.js.map +0 -1
- package/dist/storage/index.d.ts +0 -2
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js +0 -2
- package/dist/storage/index.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# @stratal/testing
|
|
2
|
+
|
|
3
|
+
Testing utilities and mocks for [Stratal](https://github.com/strataljs/stratal) framework applications.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@stratal/testing)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install -D @stratal/testing
|
|
12
|
+
# or
|
|
13
|
+
yarn add -D @stratal/testing
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Peer dependencies
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -D stratal vitest
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
Set up base modules once in your Vitest setup file, then create test modules in each test:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// vitest.setup.ts
|
|
28
|
+
import 'reflect-metadata'
|
|
29
|
+
import { Test } from '@stratal/testing'
|
|
30
|
+
import { CoreModule } from './src/core.module'
|
|
31
|
+
|
|
32
|
+
Test.setBaseModules([CoreModule])
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// users/__tests__/users.spec.ts
|
|
37
|
+
import { Test, type TestingModule } from '@stratal/testing'
|
|
38
|
+
import { UsersModule } from '../users.module'
|
|
39
|
+
|
|
40
|
+
describe('UsersController', () => {
|
|
41
|
+
let module: TestingModule
|
|
42
|
+
|
|
43
|
+
beforeAll(async () => {
|
|
44
|
+
module = await Test.createTestingModule({
|
|
45
|
+
imports: [UsersModule],
|
|
46
|
+
}).compile()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
afterAll(async () => {
|
|
50
|
+
await module.close()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('lists users', async () => {
|
|
54
|
+
const response = await module.http
|
|
55
|
+
.get('/api/users')
|
|
56
|
+
.send()
|
|
57
|
+
|
|
58
|
+
response.assertOk()
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Core API
|
|
64
|
+
|
|
65
|
+
### `Test`
|
|
66
|
+
|
|
67
|
+
Static entry point for creating testing modules.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { Test } from '@stratal/testing'
|
|
71
|
+
|
|
72
|
+
// Set once in vitest.setup.ts — included in every test module
|
|
73
|
+
Test.setBaseModules([CoreModule])
|
|
74
|
+
|
|
75
|
+
// Create a test module in each test file
|
|
76
|
+
const builder = Test.createTestingModule({
|
|
77
|
+
imports: [UsersModule, AuthModule],
|
|
78
|
+
providers: [{ provide: MOCK_TOKEN, useValue: mockValue }],
|
|
79
|
+
controllers: [TestController],
|
|
80
|
+
env: { DATABASE_URL: 'test://db' },
|
|
81
|
+
})
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `TestingModuleBuilder`
|
|
85
|
+
|
|
86
|
+
Fluent builder returned by `Test.createTestingModule()`. Chain provider overrides, then call `.compile()`.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const module = await Test.createTestingModule({
|
|
90
|
+
imports: [OrdersModule],
|
|
91
|
+
})
|
|
92
|
+
.overrideProvider(PAYMENT_TOKEN)
|
|
93
|
+
.useValue(mockPaymentService)
|
|
94
|
+
.withEnv({ STRIPE_KEY: 'sk_test_xxx' })
|
|
95
|
+
.compile()
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### `TestingModule`
|
|
99
|
+
|
|
100
|
+
The compiled test context. Provides access to services, HTTP client, storage, and lifecycle management.
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// Resolve services from the DI container
|
|
104
|
+
const service = module.get(ORDER_TOKENS.OrderService)
|
|
105
|
+
|
|
106
|
+
// Access the HTTP test client
|
|
107
|
+
module.http
|
|
108
|
+
|
|
109
|
+
// Access fake storage for assertions
|
|
110
|
+
module.storage
|
|
111
|
+
|
|
112
|
+
// Execute code in a request-scoped container
|
|
113
|
+
await module.runInRequestScope(async () => {
|
|
114
|
+
const scoped = module.get(REQUEST_SCOPED_TOKEN)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// Cleanup in afterAll
|
|
118
|
+
await module.close()
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## HTTP Testing
|
|
122
|
+
|
|
123
|
+
The built-in HTTP client provides a fluent API for making requests and asserting responses.
|
|
124
|
+
|
|
125
|
+
### Making requests
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const response = await module.http
|
|
129
|
+
.forHost('api.example.com') // optional — defaults to localhost
|
|
130
|
+
.post('/api/v1/orders')
|
|
131
|
+
.withHeaders({ Authorization: 'Bearer token' })
|
|
132
|
+
.withBody({ item: 'Widget', qty: 3 })
|
|
133
|
+
.send()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
All HTTP methods are supported: `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`.
|
|
137
|
+
|
|
138
|
+
### Response assertions
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
response
|
|
142
|
+
.assertCreated() // 201
|
|
143
|
+
.assertHeader('Content-Type', 'application/json')
|
|
144
|
+
|
|
145
|
+
// Status helpers
|
|
146
|
+
response.assertOk() // 200
|
|
147
|
+
response.assertNoContent() // 204
|
|
148
|
+
response.assertBadRequest() // 400
|
|
149
|
+
response.assertUnauthorized() // 401
|
|
150
|
+
response.assertForbidden() // 403
|
|
151
|
+
response.assertNotFound() // 404
|
|
152
|
+
response.assertUnprocessable() // 422
|
|
153
|
+
response.assertServerError() // 500
|
|
154
|
+
response.assertStatus(418) // any status
|
|
155
|
+
response.assertSuccessful() // 2xx range
|
|
156
|
+
|
|
157
|
+
// JSON assertions (async — chainable with await)
|
|
158
|
+
await response.assertJson({ success: true })
|
|
159
|
+
await response.assertJsonPath('data.user.id', expect.any(String))
|
|
160
|
+
await response.assertJsonPaths({ 'data.name': 'Alice', 'data.role': 'admin' })
|
|
161
|
+
await response.assertJsonStructure(['id', 'name', 'email'])
|
|
162
|
+
await response.assertJsonPathExists('data.createdAt')
|
|
163
|
+
await response.assertJsonPathMissing('data.password')
|
|
164
|
+
await response.assertJsonPathCount('data.items', 3)
|
|
165
|
+
await response.assertJsonPathContains('data.bio', 'engineer')
|
|
166
|
+
await response.assertJsonPathIncludes('data.tags', 'featured')
|
|
167
|
+
|
|
168
|
+
// Header assertions
|
|
169
|
+
response.assertHeader('X-Request-Id') // exists
|
|
170
|
+
response.assertHeader('X-Request-Id', '123') // exact value
|
|
171
|
+
response.assertHeaderMissing('X-Debug')
|
|
172
|
+
|
|
173
|
+
// Raw access
|
|
174
|
+
const json = await response.json<OrderResponse>()
|
|
175
|
+
const text = await response.text()
|
|
176
|
+
response.status // number
|
|
177
|
+
response.headers // Headers
|
|
178
|
+
response.raw // underlying Response
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Provider Overrides
|
|
182
|
+
|
|
183
|
+
Replace any provider in the DI container for testing:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
const module = await Test.createTestingModule({
|
|
187
|
+
imports: [NotificationModule],
|
|
188
|
+
})
|
|
189
|
+
// Static value
|
|
190
|
+
.overrideProvider(EMAIL_TOKEN)
|
|
191
|
+
.useValue(mockEmailService)
|
|
192
|
+
|
|
193
|
+
// Class replacement
|
|
194
|
+
.overrideProvider(LOGGER_TOKEN)
|
|
195
|
+
.useClass(SilentLogger)
|
|
196
|
+
|
|
197
|
+
// Factory with container access
|
|
198
|
+
.overrideProvider(CACHE_TOKEN)
|
|
199
|
+
.useFactory((container) => new InMemoryCache(container.resolve(CONFIG_TOKEN)))
|
|
200
|
+
|
|
201
|
+
// Alias to existing token
|
|
202
|
+
.overrideProvider(PAYMENT_TOKEN)
|
|
203
|
+
.useExisting(MOCK_PAYMENT_TOKEN)
|
|
204
|
+
|
|
205
|
+
.compile()
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Fetch Mocking
|
|
209
|
+
|
|
210
|
+
Mock external HTTP calls with `createFetchMock()`, backed by [undici MockAgent](https://undici.nodejs.org/#/docs/api/MockAgent):
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import { createFetchMock, type FetchMock } from '@stratal/testing'
|
|
214
|
+
|
|
215
|
+
describe('GeoService', () => {
|
|
216
|
+
let module: TestingModule
|
|
217
|
+
let fetchMock: FetchMock
|
|
218
|
+
|
|
219
|
+
beforeEach(() => {
|
|
220
|
+
fetchMock = createFetchMock()
|
|
221
|
+
fetchMock.activate()
|
|
222
|
+
fetchMock.disableNetConnect()
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
afterEach(() => {
|
|
226
|
+
fetchMock.reset()
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
it('looks up coordinates', async () => {
|
|
230
|
+
fetchMock.mockJsonResponse('https://geo.api.com/lookup', {
|
|
231
|
+
lat: 40.7128,
|
|
232
|
+
lng: -74.006,
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
const response = await module.http
|
|
236
|
+
.get('/api/geo/lookup?address=NYC')
|
|
237
|
+
.send()
|
|
238
|
+
|
|
239
|
+
response.assertOk()
|
|
240
|
+
await response.assertJsonPath('data.lat', 40.7128)
|
|
241
|
+
fetchMock.assertNoPendingInterceptors()
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it('handles API errors', async () => {
|
|
245
|
+
fetchMock.mockError('https://geo.api.com/lookup', 503, 'Service Unavailable')
|
|
246
|
+
|
|
247
|
+
const response = await module.http
|
|
248
|
+
.get('/api/geo/lookup?address=NYC')
|
|
249
|
+
.send()
|
|
250
|
+
|
|
251
|
+
response.assertServerError()
|
|
252
|
+
})
|
|
253
|
+
})
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
For advanced scenarios, access the undici `MockPool` directly:
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
fetchMock
|
|
260
|
+
.get('https://api.example.com')
|
|
261
|
+
.intercept({ path: '/users', method: 'POST' })
|
|
262
|
+
.reply(201, { id: '1' })
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Storage Testing
|
|
266
|
+
|
|
267
|
+
`FakeStorageService` is an in-memory storage implementation auto-registered in every test module. It replaces the real storage service and provides assertion helpers.
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
it('uploads a document', async () => {
|
|
271
|
+
await module.http
|
|
272
|
+
.post('/api/documents')
|
|
273
|
+
.withBody({ name: 'report.pdf' })
|
|
274
|
+
.send()
|
|
275
|
+
|
|
276
|
+
// Assert files were stored
|
|
277
|
+
module.storage.assertExists('documents/report.pdf')
|
|
278
|
+
module.storage.assertMissing('documents/old.pdf')
|
|
279
|
+
module.storage.assertCount(1)
|
|
280
|
+
|
|
281
|
+
// Inspect stored files
|
|
282
|
+
const file = module.storage.getFile('documents/report.pdf')
|
|
283
|
+
expect(file?.mimeType).toBe('application/pdf')
|
|
284
|
+
expect(file?.size).toBeGreaterThan(0)
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
afterEach(() => {
|
|
288
|
+
module.storage.clear() // reset between tests
|
|
289
|
+
})
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Deep Mocking
|
|
293
|
+
|
|
294
|
+
Create deeply-mocked instances of any interface or class with `createMock()` from [`@golevelup/ts-vitest`](https://github.com/golevelup/nestjs/tree/master/packages/ts-vitest):
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
import { createMock, type DeepMocked } from '@stratal/testing/mocks'
|
|
298
|
+
|
|
299
|
+
let mockService: DeepMocked<PaymentService>
|
|
300
|
+
|
|
301
|
+
beforeEach(() => {
|
|
302
|
+
mockService = createMock<PaymentService>()
|
|
303
|
+
mockService.charge.mockResolvedValue({ id: 'ch_123', status: 'paid' })
|
|
304
|
+
})
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Nodemailer mock
|
|
308
|
+
|
|
309
|
+
A drop-in mock for nodemailer, useful in Vitest's module mocking:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
// vitest.config.ts (or inline vi.mock)
|
|
313
|
+
export default defineConfig({
|
|
314
|
+
test: {
|
|
315
|
+
alias: {
|
|
316
|
+
nodemailer: '@stratal/testing/mocks/nodemailer',
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
})
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Sub-path Exports
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
import { Test, TestingModule, createFetchMock } from '@stratal/testing'
|
|
326
|
+
import { createMock, type DeepMocked } from '@stratal/testing/mocks'
|
|
327
|
+
import nodemailer from '@stratal/testing/mocks/nodemailer'
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## License
|
|
331
|
+
|
|
332
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stratal/testing",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Testing utilities and mocks for Stratal framework applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
|
-
"build": "tsc -p tsconfig.build.json",
|
|
46
|
+
"build": "yarn prebuild && tsc -p tsconfig.build.json",
|
|
47
47
|
"clean": "rm -rf dist",
|
|
48
48
|
"prebuild": "yarn clean",
|
|
49
49
|
"typecheck": "tsc --noEmit",
|
|
@@ -51,19 +51,19 @@
|
|
|
51
51
|
"lint:fix": "npx eslint --fix ."
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@faker-js/faker": "^
|
|
55
|
-
"@golevelup/ts-vitest": "^2.
|
|
54
|
+
"@faker-js/faker": "^10.3.0",
|
|
55
|
+
"@golevelup/ts-vitest": "^2.2.0"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"stratal": "^0.0.
|
|
58
|
+
"stratal": "^0.0.2",
|
|
59
59
|
"vitest": "^3.2.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@cloudflare/vitest-pool-workers": "^0.
|
|
63
|
-
"@cloudflare/workers-types": "
|
|
64
|
-
"@types/node": "^
|
|
62
|
+
"@cloudflare/vitest-pool-workers": "^0.12.18",
|
|
63
|
+
"@cloudflare/workers-types": "4.20260228.1",
|
|
64
|
+
"@types/node": "^25.3.2",
|
|
65
65
|
"stratal": "workspace:*",
|
|
66
|
-
"typescript": "^5.
|
|
67
|
-
"vitest": "^3.2.
|
|
66
|
+
"typescript": "^5.9.3",
|
|
67
|
+
"vitest": "^3.2.4"
|
|
68
68
|
}
|
|
69
69
|
}
|
package/dist/core/env/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/env/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/core/env/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/env/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type StratalEnv } from 'stratal';
|
|
2
|
-
/**
|
|
3
|
-
* Get test environment with optional overrides
|
|
4
|
-
*
|
|
5
|
-
* @param overrides - Optional partial env to merge with cloudflare:test env
|
|
6
|
-
* @returns Complete Env object for testing
|
|
7
|
-
*/
|
|
8
|
-
export declare function getTestEnv(overrides?: Partial<StratalEnv>): StratalEnv;
|
|
9
|
-
//# sourceMappingURL=test-env.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"test-env.d.ts","sourceRoot":"","sources":["../../../src/core/env/test-env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAA;AAGzC;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAKtE"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { env as cloudflareEnv } from 'cloudflare:test';
|
|
2
|
-
/**
|
|
3
|
-
* Get test environment with optional overrides
|
|
4
|
-
*
|
|
5
|
-
* @param overrides - Optional partial env to merge with cloudflare:test env
|
|
6
|
-
* @returns Complete Env object for testing
|
|
7
|
-
*/
|
|
8
|
-
export function getTestEnv(overrides) {
|
|
9
|
-
return {
|
|
10
|
-
...cloudflareEnv,
|
|
11
|
-
...overrides,
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
//# sourceMappingURL=test-env.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"test-env.js","sourceRoot":"","sources":["../../../src/core/env/test-env.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,SAA+B;IACxD,OAAO;QACL,GAAG,aAAa;QAChB,GAAG,SAAS;KACC,CAAA;AACjB,CAAC"}
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
import type { MockJsonOptions, MockErrorOptions } from './fetch-mock.types';
|
|
2
|
-
/**
|
|
3
|
-
* Wrapper around Cloudflare's fetchMock for declarative fetch mocking in tests
|
|
4
|
-
*
|
|
5
|
-
* Based on undici's MockAgent, fetchMock.get(origin) returns a MockPool for that origin.
|
|
6
|
-
* The MockPool's intercept() method is used to define which requests to mock.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```typescript
|
|
10
|
-
* import { createFetchMock } from '@stratal/testing'
|
|
11
|
-
*
|
|
12
|
-
* const mock = createFetchMock()
|
|
13
|
-
*
|
|
14
|
-
* beforeEach(() => {
|
|
15
|
-
* mock.activate()
|
|
16
|
-
* mock.disableNetConnect()
|
|
17
|
-
* })
|
|
18
|
-
*
|
|
19
|
-
* afterEach(() => {
|
|
20
|
-
* mock.reset()
|
|
21
|
-
* })
|
|
22
|
-
*
|
|
23
|
-
* it('should mock external API', async () => {
|
|
24
|
-
* // Using helper method
|
|
25
|
-
* mock.mockJsonResponse('https://api.example.com/data', { success: true })
|
|
26
|
-
*
|
|
27
|
-
* // Or using direct API
|
|
28
|
-
* mock.get('https://api.example.com')
|
|
29
|
-
* .intercept({ path: '/users', method: 'POST' })
|
|
30
|
-
* .reply(201, JSON.stringify({ created: true }))
|
|
31
|
-
*
|
|
32
|
-
* const response = await fetch('https://api.example.com/data')
|
|
33
|
-
* const json = await response.json()
|
|
34
|
-
*
|
|
35
|
-
* expect(json.success).toBe(true)
|
|
36
|
-
* mock.assertNoPendingInterceptors()
|
|
37
|
-
* })
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
export declare class FetchMock {
|
|
41
|
-
/**
|
|
42
|
-
* Get a MockPool for the specified origin
|
|
43
|
-
*
|
|
44
|
-
* This is the underlying fetchMock.get() method that returns a MockPool
|
|
45
|
-
* for mocking requests to the specified origin.
|
|
46
|
-
*
|
|
47
|
-
* @param origin - The origin URL (e.g., 'https://api.example.com')
|
|
48
|
-
* @returns MockPool for chaining .intercept() and .reply()
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```typescript
|
|
52
|
-
* // Mock a GET request
|
|
53
|
-
* mock.get('https://api.example.com')
|
|
54
|
-
* .intercept({ path: '/users', method: 'GET' })
|
|
55
|
-
* .reply(200, JSON.stringify({ users: [] }))
|
|
56
|
-
*
|
|
57
|
-
* // Mock a POST request with body matching
|
|
58
|
-
* mock.get('https://api.example.com')
|
|
59
|
-
* .intercept({
|
|
60
|
-
* path: '/users',
|
|
61
|
-
* method: 'POST',
|
|
62
|
-
* body: (body) => body.includes('test')
|
|
63
|
-
* })
|
|
64
|
-
* .reply(201, JSON.stringify({ created: true }))
|
|
65
|
-
* ```
|
|
66
|
-
*/
|
|
67
|
-
get(origin: string): import("cloudflare:test").Interceptable;
|
|
68
|
-
/**
|
|
69
|
-
* Activate fetch mocking for the current test
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```typescript
|
|
73
|
-
* beforeEach(() => {
|
|
74
|
-
* mock.activate()
|
|
75
|
-
* })
|
|
76
|
-
* ```
|
|
77
|
-
*/
|
|
78
|
-
activate(): void;
|
|
79
|
-
/**
|
|
80
|
-
* Deactivate fetch mocking
|
|
81
|
-
*/
|
|
82
|
-
deactivate(): void;
|
|
83
|
-
/**
|
|
84
|
-
* Disable all network connections, forcing all requests to use mocks
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* ```typescript
|
|
88
|
-
* beforeEach(() => {
|
|
89
|
-
* mock.activate()
|
|
90
|
-
* mock.disableNetConnect() // Ensure all requests are mocked
|
|
91
|
-
* })
|
|
92
|
-
* ```
|
|
93
|
-
*/
|
|
94
|
-
disableNetConnect(): void;
|
|
95
|
-
/**
|
|
96
|
-
* Enable network connections for specific hosts
|
|
97
|
-
*
|
|
98
|
-
* @example
|
|
99
|
-
* ```typescript
|
|
100
|
-
* mock.enableNetConnect('localhost')
|
|
101
|
-
* mock.enableNetConnect(/^https:\/\/trusted\.com/)
|
|
102
|
-
* ```
|
|
103
|
-
*/
|
|
104
|
-
enableNetConnect(host?: string | RegExp): void;
|
|
105
|
-
/**
|
|
106
|
-
* Assert that all defined interceptors were called
|
|
107
|
-
*
|
|
108
|
-
* @throws {Error} If there are pending interceptors that weren't matched
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* ```typescript
|
|
112
|
-
* it('should call all mocked endpoints', async () => {
|
|
113
|
-
* mock.mockJsonResponse('https://api.example.com/data', { data: [] })
|
|
114
|
-
*
|
|
115
|
-
* await fetch('https://api.example.com/data')
|
|
116
|
-
*
|
|
117
|
-
* mock.assertNoPendingInterceptors() // Pass
|
|
118
|
-
* })
|
|
119
|
-
* ```
|
|
120
|
-
*/
|
|
121
|
-
assertNoPendingInterceptors(): void;
|
|
122
|
-
/**
|
|
123
|
-
* Reset all mocks and interceptors
|
|
124
|
-
*
|
|
125
|
-
* @example
|
|
126
|
-
* ```typescript
|
|
127
|
-
* afterEach(() => {
|
|
128
|
-
* mock.reset()
|
|
129
|
-
* })
|
|
130
|
-
* ```
|
|
131
|
-
*/
|
|
132
|
-
reset(): void;
|
|
133
|
-
/**
|
|
134
|
-
* Helper method to mock JSON responses
|
|
135
|
-
*
|
|
136
|
-
* Automatically parses the URL into origin and path, and sets up the mock.
|
|
137
|
-
*
|
|
138
|
-
* @param url - Full URL to mock (e.g., 'https://api.example.com/users')
|
|
139
|
-
* @param data - JSON data to return
|
|
140
|
-
* @param options - Additional options for the mock
|
|
141
|
-
*
|
|
142
|
-
* @example
|
|
143
|
-
* ```typescript
|
|
144
|
-
* // Mock a GET request
|
|
145
|
-
* mock.mockJsonResponse('https://api.example.com/users', { users: [] })
|
|
146
|
-
*
|
|
147
|
-
* // Mock a POST request
|
|
148
|
-
* mock.mockJsonResponse(
|
|
149
|
-
* 'https://api.example.com/users',
|
|
150
|
-
* { created: true },
|
|
151
|
-
* { method: 'POST', status: 201 }
|
|
152
|
-
* )
|
|
153
|
-
*
|
|
154
|
-
* // With custom headers and delay
|
|
155
|
-
* mock.mockJsonResponse(
|
|
156
|
-
* 'https://api.example.com/users',
|
|
157
|
-
* { users: [] },
|
|
158
|
-
* {
|
|
159
|
-
* status: 200,
|
|
160
|
-
* method: 'GET',
|
|
161
|
-
* headers: { 'X-Custom': 'value' },
|
|
162
|
-
* delay: 100
|
|
163
|
-
* }
|
|
164
|
-
* )
|
|
165
|
-
* ```
|
|
166
|
-
*/
|
|
167
|
-
mockJsonResponse(url: string, data: unknown, options?: MockJsonOptions): import("cloudflare:test").MockScope<object>;
|
|
168
|
-
/**
|
|
169
|
-
* Helper method to mock error responses
|
|
170
|
-
*
|
|
171
|
-
* @param url - Full URL to mock
|
|
172
|
-
* @param status - HTTP error status code
|
|
173
|
-
* @param message - Optional error message
|
|
174
|
-
* @param options - Additional options for the error mock
|
|
175
|
-
*
|
|
176
|
-
* @example
|
|
177
|
-
* ```typescript
|
|
178
|
-
* // Mock a 401 error
|
|
179
|
-
* mock.mockError('https://api.example.com/fail', 401, 'Unauthorized')
|
|
180
|
-
*
|
|
181
|
-
* // Mock a 500 error with custom method
|
|
182
|
-
* mock.mockError(
|
|
183
|
-
* 'https://api.example.com/fail',
|
|
184
|
-
* 500,
|
|
185
|
-
* 'Server Error',
|
|
186
|
-
* { method: 'POST' }
|
|
187
|
-
* )
|
|
188
|
-
* ```
|
|
189
|
-
*/
|
|
190
|
-
mockError(url: string, status: number, message?: string, options?: MockErrorOptions): import("cloudflare:test").MockScope<object>;
|
|
191
|
-
/**
|
|
192
|
-
* Generic helper to mock any HTTP request
|
|
193
|
-
*
|
|
194
|
-
* @param origin - The origin URL (e.g., 'https://api.example.com')
|
|
195
|
-
* @param options - Request matching and response options
|
|
196
|
-
*
|
|
197
|
-
* @example
|
|
198
|
-
* ```typescript
|
|
199
|
-
* mock.mockRequest('https://api.example.com', {
|
|
200
|
-
* path: '/users',
|
|
201
|
-
* method: 'PUT',
|
|
202
|
-
* status: 200,
|
|
203
|
-
* body: { updated: true }
|
|
204
|
-
* })
|
|
205
|
-
* ```
|
|
206
|
-
*/
|
|
207
|
-
mockRequest(origin: string, options: {
|
|
208
|
-
path: string;
|
|
209
|
-
method?: string;
|
|
210
|
-
status?: number;
|
|
211
|
-
body?: unknown;
|
|
212
|
-
}): import("cloudflare:test").MockScope<object>;
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Factory function to create a new FetchMock instance
|
|
216
|
-
*
|
|
217
|
-
* @returns A new FetchMock instance
|
|
218
|
-
*
|
|
219
|
-
* @example
|
|
220
|
-
* ```typescript
|
|
221
|
-
* import { createFetchMock } from '@stratal/testing'
|
|
222
|
-
*
|
|
223
|
-
* const mock = createFetchMock()
|
|
224
|
-
*
|
|
225
|
-
* beforeEach(() => {
|
|
226
|
-
* mock.activate()
|
|
227
|
-
* mock.disableNetConnect()
|
|
228
|
-
* })
|
|
229
|
-
*
|
|
230
|
-
* afterEach(() => {
|
|
231
|
-
* mock.reset()
|
|
232
|
-
* })
|
|
233
|
-
* ```
|
|
234
|
-
*/
|
|
235
|
-
export declare function createFetchMock(): FetchMock;
|
|
236
|
-
//# sourceMappingURL=fetch-mock.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-mock.d.ts","sourceRoot":"","sources":["../../../src/core/http/fetch-mock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,qBAAa,SAAS;IACrB;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM;IAIlB;;;;;;;;;OASG;IACH,QAAQ;IAIR;;OAEG;IACH,UAAU;IAIV;;;;;;;;;;OAUG;IACH,iBAAiB;IAIjB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAOvC;;;;;;;;;;;;;;;OAeG;IACH,2BAA2B;IAI3B;;;;;;;;;OASG;IACH,KAAK;IAKL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,eAAoB;IAwB1E;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB;IAkBvF;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE;CAS5E;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,IAAI,SAAS,CAE3C"}
|