@ereo/testing 0.1.6
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 +94 -0
- package/dist/action.d.ts +147 -0
- package/dist/action.d.ts.map +1 -0
- package/dist/assertions.d.ts +97 -0
- package/dist/assertions.d.ts.map +1 -0
- package/dist/context.d.ts +72 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +658 -0
- package/dist/loader.d.ts +116 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/middleware.d.ts +177 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/render.d.ts +135 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/request.d.ts +104 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/server.d.ts +109 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/snapshot.d.ts +96 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @ereo/testing
|
|
2
|
+
|
|
3
|
+
Testing utilities for EreoJS applications. Makes testing loaders, actions, middleware, and components trivial with a clean, intuitive API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @ereo/testing
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { testLoader, testAction, createTestContext } from '@ereo/testing';
|
|
15
|
+
import { loader, action } from './routes/users';
|
|
16
|
+
|
|
17
|
+
// Test a loader
|
|
18
|
+
const result = await testLoader(loader, {
|
|
19
|
+
params: { id: '123' },
|
|
20
|
+
});
|
|
21
|
+
expect(result.data.user.id).toBe('123');
|
|
22
|
+
|
|
23
|
+
// Test an action
|
|
24
|
+
const actionResult = await testAction(action, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
formData: { name: 'John' },
|
|
27
|
+
});
|
|
28
|
+
expect(actionResult.status).toBe(200);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Key Features
|
|
32
|
+
|
|
33
|
+
- **Loader Testing** - Test loaders with `testLoader` and `createLoaderTester`
|
|
34
|
+
- **Action Testing** - Test actions with `testAction` and `createActionTester`
|
|
35
|
+
- **Middleware Testing** - Test middleware with `testMiddleware` and `createMiddlewareTester`
|
|
36
|
+
- **Component Testing** - Render routes with `renderRoute` and `createRouteRenderer`
|
|
37
|
+
- **Mock Utilities** - Create mock requests with `createMockRequest` and `createFormRequest`
|
|
38
|
+
- **Assertions** - Built-in assertions: `assertRedirect`, `assertJson`, `assertStatus`
|
|
39
|
+
- **Snapshot Testing** - Snapshot loaders and actions with `snapshotLoader` and `snapshotAction`
|
|
40
|
+
- **Test Server** - Spin up a test server with `createTestServer`
|
|
41
|
+
|
|
42
|
+
## Middleware Testing
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { testMiddleware, createMockRequest } from '@ereo/testing';
|
|
46
|
+
|
|
47
|
+
const result = await testMiddleware(authMiddleware, {
|
|
48
|
+
request: createMockRequest('/protected', {
|
|
49
|
+
headers: { Authorization: 'Bearer token' },
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(result.continued).toBe(true);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Component Testing
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { renderRoute, assertStatus } from '@ereo/testing';
|
|
60
|
+
|
|
61
|
+
const result = await renderRoute('/users/123', {
|
|
62
|
+
loaderData: { user: { id: '123', name: 'John' } },
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
expect(result.html).toContain('John');
|
|
66
|
+
assertStatus(result.response, 200);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Test Server
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { createTestServer } from '@ereo/testing';
|
|
73
|
+
|
|
74
|
+
const server = await createTestServer({
|
|
75
|
+
routesDir: './src/routes',
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const response = await server.fetch('/api/users');
|
|
79
|
+
expect(response.status).toBe(200);
|
|
80
|
+
|
|
81
|
+
await server.close();
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Documentation
|
|
85
|
+
|
|
86
|
+
For full documentation, visit [https://ereojs.dev/docs/testing](https://ereojs.dev/docs/testing)
|
|
87
|
+
|
|
88
|
+
## Part of EreoJS
|
|
89
|
+
|
|
90
|
+
This package is part of the [EreoJS](https://github.com/ereojs/ereo) monorepo - a modern full-stack framework built for Bun.
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
package/dist/action.d.ts
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ereo/testing - Action Testing
|
|
3
|
+
*
|
|
4
|
+
* Utilities for testing route actions.
|
|
5
|
+
*/
|
|
6
|
+
import type { ActionFunction, RouteParams } from '@ereo/core';
|
|
7
|
+
import { type TestContextOptions, type TestContext } from './context';
|
|
8
|
+
import { type MockRequestOptions } from './request';
|
|
9
|
+
/**
|
|
10
|
+
* Options for testing an action.
|
|
11
|
+
*/
|
|
12
|
+
export interface ActionTestOptions<P = RouteParams> {
|
|
13
|
+
/** Route parameters */
|
|
14
|
+
params?: P;
|
|
15
|
+
/** Request options (method defaults to POST) */
|
|
16
|
+
request?: MockRequestOptions;
|
|
17
|
+
/** Context options */
|
|
18
|
+
context?: TestContextOptions;
|
|
19
|
+
/** Form data to submit */
|
|
20
|
+
formData?: Record<string, string | Blob>;
|
|
21
|
+
/** JSON body to submit */
|
|
22
|
+
body?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Result of testing an action.
|
|
26
|
+
*/
|
|
27
|
+
export interface ActionTestResult<T = unknown> {
|
|
28
|
+
/** The action's return value (parsed if Response) */
|
|
29
|
+
data: T;
|
|
30
|
+
/** The raw response if action returned a Response */
|
|
31
|
+
response: Response | null;
|
|
32
|
+
/** The test context (for inspection) */
|
|
33
|
+
context: TestContext;
|
|
34
|
+
/** The request used */
|
|
35
|
+
request: Request;
|
|
36
|
+
/** Execution time in milliseconds */
|
|
37
|
+
duration: number;
|
|
38
|
+
/** Whether the action returned a redirect */
|
|
39
|
+
isRedirect: boolean;
|
|
40
|
+
/** Redirect location if applicable */
|
|
41
|
+
redirectTo: string | null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Test an action function directly.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* import { testAction } from '@ereo/testing';
|
|
48
|
+
* import { action } from './routes/blog/[slug]';
|
|
49
|
+
*
|
|
50
|
+
* test('creates a comment', async () => {
|
|
51
|
+
* const result = await testAction(action, {
|
|
52
|
+
* params: { slug: 'my-post' },
|
|
53
|
+
* formData: { content: 'Great post!' },
|
|
54
|
+
* });
|
|
55
|
+
*
|
|
56
|
+
* expect(result.data.success).toBe(true);
|
|
57
|
+
* });
|
|
58
|
+
*/
|
|
59
|
+
export declare function testAction<T = unknown, P = RouteParams>(action: ActionFunction<T | Response, P>, options?: ActionTestOptions<P>): Promise<ActionTestResult<T>>;
|
|
60
|
+
/**
|
|
61
|
+
* Create a reusable action tester with preset options.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* const testCommentAction = createActionTester(action, {
|
|
65
|
+
* context: { store: { user: testUser } },
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* test('creates comment', async () => {
|
|
69
|
+
* const result = await testCommentAction({
|
|
70
|
+
* params: { slug: 'test' },
|
|
71
|
+
* formData: { content: 'Hello!' },
|
|
72
|
+
* });
|
|
73
|
+
* expect(result.data.success).toBe(true);
|
|
74
|
+
* });
|
|
75
|
+
*/
|
|
76
|
+
export declare function createActionTester<T = unknown, P = RouteParams>(action: ActionFunction<T | Response, P>, baseOptions?: ActionTestOptions<P>): (overrides?: Partial<ActionTestOptions<P>>) => Promise<ActionTestResult<T>>;
|
|
77
|
+
/**
|
|
78
|
+
* Test action with multiple form submissions.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* const results = await testActionMatrix(action, {
|
|
82
|
+
* params: { slug: 'post-1' },
|
|
83
|
+
* submissions: [
|
|
84
|
+
* { formData: { content: 'Comment 1' } },
|
|
85
|
+
* { formData: { content: 'Comment 2' } },
|
|
86
|
+
* { formData: { content: '' } }, // Invalid
|
|
87
|
+
* ],
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* expect(results[0].data.success).toBe(true);
|
|
91
|
+
* expect(results[2].data.error).toBeDefined();
|
|
92
|
+
*/
|
|
93
|
+
export declare function testActionMatrix<T = unknown, P = RouteParams>(action: ActionFunction<T | Response, P>, options: {
|
|
94
|
+
params?: P;
|
|
95
|
+
submissions: Array<{
|
|
96
|
+
formData?: Record<string, string | Blob>;
|
|
97
|
+
body?: Record<string, unknown>;
|
|
98
|
+
}>;
|
|
99
|
+
context?: TestContextOptions;
|
|
100
|
+
}): Promise<ActionTestResult<T>[]>;
|
|
101
|
+
/**
|
|
102
|
+
* Test action error handling.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* test('handles validation error', async () => {
|
|
106
|
+
* const result = await testActionError(action, {
|
|
107
|
+
* formData: { content: '' },
|
|
108
|
+
* });
|
|
109
|
+
*
|
|
110
|
+
* expect(result.error).toBeInstanceOf(ValidationError);
|
|
111
|
+
* });
|
|
112
|
+
*/
|
|
113
|
+
export declare function testActionError<P = RouteParams>(action: ActionFunction<unknown, P>, options?: ActionTestOptions<P>): Promise<{
|
|
114
|
+
error: Error | null;
|
|
115
|
+
context: TestContext;
|
|
116
|
+
request: Request;
|
|
117
|
+
}>;
|
|
118
|
+
/**
|
|
119
|
+
* Test action with file upload.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* test('uploads file', async () => {
|
|
123
|
+
* const result = await testActionWithFile(action, {
|
|
124
|
+
* params: { id: '1' },
|
|
125
|
+
* file: {
|
|
126
|
+
* field: 'avatar',
|
|
127
|
+
* name: 'avatar.png',
|
|
128
|
+
* content: imageBlob,
|
|
129
|
+
* type: 'image/png',
|
|
130
|
+
* },
|
|
131
|
+
* });
|
|
132
|
+
*
|
|
133
|
+
* expect(result.data.url).toContain('avatar.png');
|
|
134
|
+
* });
|
|
135
|
+
*/
|
|
136
|
+
export declare function testActionWithFile<T = unknown, P = RouteParams>(action: ActionFunction<T | Response, P>, options: {
|
|
137
|
+
params?: P;
|
|
138
|
+
file: {
|
|
139
|
+
field: string;
|
|
140
|
+
name: string;
|
|
141
|
+
content: string | Blob;
|
|
142
|
+
type?: string;
|
|
143
|
+
};
|
|
144
|
+
extraFields?: Record<string, string>;
|
|
145
|
+
context?: TestContextOptions;
|
|
146
|
+
}): Promise<ActionTestResult<T>>;
|
|
147
|
+
//# sourceMappingURL=action.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ereo/testing - Assertions
|
|
3
|
+
*
|
|
4
|
+
* Common assertions for testing responses.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Assertion options.
|
|
8
|
+
*/
|
|
9
|
+
export interface AssertionOptions {
|
|
10
|
+
/** Custom error message */
|
|
11
|
+
message?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Assert that a response is a redirect.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const result = await testAction(action, { formData: {} });
|
|
18
|
+
* assertRedirect(result.response, '/login');
|
|
19
|
+
*/
|
|
20
|
+
export declare function assertRedirect(response: Response | null, expectedLocation?: string, options?: AssertionOptions & {
|
|
21
|
+
status?: number;
|
|
22
|
+
}): void;
|
|
23
|
+
/**
|
|
24
|
+
* Assert that a response has the expected JSON body.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* const result = await testLoader(loader, { params: { id: '1' } });
|
|
28
|
+
* await assertJson(result.data, { id: 1, name: 'Test' });
|
|
29
|
+
*/
|
|
30
|
+
export declare function assertJson<T = unknown>(responseOrData: Response | T, expected: Partial<T>, options?: AssertionOptions): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Assert that a response has the expected status code.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const result = await testMiddleware(authMiddleware, {});
|
|
36
|
+
* assertStatus(result.response, 401);
|
|
37
|
+
*/
|
|
38
|
+
export declare function assertStatus(response: Response | null, expected: number | number[], options?: AssertionOptions): void;
|
|
39
|
+
/**
|
|
40
|
+
* Assert that a response has the expected headers.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const result = await testLoader(loader, {});
|
|
44
|
+
* assertHeaders(result.response, {
|
|
45
|
+
* 'Content-Type': 'application/json',
|
|
46
|
+
* 'Cache-Control': /max-age=\d+/,
|
|
47
|
+
* });
|
|
48
|
+
*/
|
|
49
|
+
export declare function assertHeaders(response: Response | null, expected: Record<string, string | RegExp>, options?: AssertionOptions): void;
|
|
50
|
+
/**
|
|
51
|
+
* Assert that a response sets the expected cookies.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const result = await testAction(loginAction, {
|
|
55
|
+
* formData: { email: 'test@example.com', password: 'secret' },
|
|
56
|
+
* });
|
|
57
|
+
* assertCookies(result.response, {
|
|
58
|
+
* session: { exists: true, httpOnly: true },
|
|
59
|
+
* });
|
|
60
|
+
*/
|
|
61
|
+
export declare function assertCookies(response: Response | null, expected: Record<string, {
|
|
62
|
+
exists?: boolean;
|
|
63
|
+
value?: string | RegExp;
|
|
64
|
+
httpOnly?: boolean;
|
|
65
|
+
secure?: boolean;
|
|
66
|
+
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
67
|
+
path?: string;
|
|
68
|
+
maxAge?: number;
|
|
69
|
+
expires?: boolean;
|
|
70
|
+
}>, options?: AssertionOptions): void;
|
|
71
|
+
/**
|
|
72
|
+
* Assert that an error was thrown.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* await assertThrows(
|
|
76
|
+
* () => testLoader(loader, { params: { id: 'invalid' } }),
|
|
77
|
+
* { message: /not found/i, status: 404 }
|
|
78
|
+
* );
|
|
79
|
+
*/
|
|
80
|
+
export declare function assertThrows(fn: () => Promise<unknown>, expected?: {
|
|
81
|
+
message?: string | RegExp;
|
|
82
|
+
name?: string;
|
|
83
|
+
status?: number;
|
|
84
|
+
}, options?: AssertionOptions): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Assert that a value matches a schema (basic type checking).
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* await assertSchema(result.data, {
|
|
90
|
+
* id: 'number',
|
|
91
|
+
* name: 'string',
|
|
92
|
+
* tags: 'array',
|
|
93
|
+
* meta: 'object',
|
|
94
|
+
* });
|
|
95
|
+
*/
|
|
96
|
+
export declare function assertSchema(data: unknown, schema: Record<string, 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null' | 'undefined'>, options?: AssertionOptions): void;
|
|
97
|
+
//# sourceMappingURL=assertions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assertions.d.ts","sourceRoot":"","sources":["../src/assertions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,gBAAgB,CAAC,EAAE,MAAM,EACzB,OAAO,GAAE,gBAAgB,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GACnD,IAAI,CAuCN;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,CAAC,GAAG,OAAO,EAC1C,cAAc,EAAE,QAAQ,GAAG,CAAC,EAC5B,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,EAC3B,OAAO,GAAE,gBAAqB,GAC7B,IAAI,CAaN;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EACzC,OAAO,GAAE,gBAAqB,GAC7B,IAAI,CA+BN;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,EACF,OAAO,GAAE,gBAAqB,GAC7B,IAAI,CAsGN;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC1B,QAAQ,GAAE;IACR,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACZ,EACN,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA4Cf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC,EACnG,OAAO,GAAE,gBAAqB,GAC7B,IAAI,CA4BN"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ereo/testing - Test Context
|
|
3
|
+
*
|
|
4
|
+
* Create mock contexts for testing loaders, actions, and middleware.
|
|
5
|
+
*/
|
|
6
|
+
import type { AppContext, CacheOptions } from '@ereo/core';
|
|
7
|
+
/**
|
|
8
|
+
* Options for creating a test context.
|
|
9
|
+
*/
|
|
10
|
+
export interface TestContextOptions {
|
|
11
|
+
/** Initial context store values */
|
|
12
|
+
store?: Record<string, unknown>;
|
|
13
|
+
/** Initial environment variables */
|
|
14
|
+
env?: Record<string, string>;
|
|
15
|
+
/** Request URL */
|
|
16
|
+
url?: string | URL;
|
|
17
|
+
/** Initial cache tags */
|
|
18
|
+
cacheTags?: string[];
|
|
19
|
+
/** Initial response headers */
|
|
20
|
+
responseHeaders?: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Extended test context with inspection utilities.
|
|
24
|
+
*/
|
|
25
|
+
export interface TestContext extends AppContext {
|
|
26
|
+
/** Get all values set in the context store */
|
|
27
|
+
getStore(): Record<string, unknown>;
|
|
28
|
+
/** Get all cache operations performed */
|
|
29
|
+
getCacheOperations(): CacheOperation[];
|
|
30
|
+
/** Reset the context to initial state */
|
|
31
|
+
reset(): void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Cache operation record for inspection.
|
|
35
|
+
*/
|
|
36
|
+
export interface CacheOperation {
|
|
37
|
+
type: 'set' | 'get';
|
|
38
|
+
options?: CacheOptions;
|
|
39
|
+
timestamp: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a test context for testing loaders, actions, and middleware.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const ctx = createTestContext({
|
|
46
|
+
* store: { user: { id: 1, name: 'Test' } },
|
|
47
|
+
* env: { DATABASE_URL: 'test://db' },
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
* const result = await loader({ request, params, context: ctx });
|
|
51
|
+
*/
|
|
52
|
+
export declare function createTestContext(options?: TestContextOptions): TestContext;
|
|
53
|
+
/**
|
|
54
|
+
* Create a context factory for repeated test setup.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const contextFactory = createContextFactory({
|
|
58
|
+
* store: { user: testUser },
|
|
59
|
+
* });
|
|
60
|
+
*
|
|
61
|
+
* test('loader test 1', async () => {
|
|
62
|
+
* const ctx = contextFactory();
|
|
63
|
+
* // ...
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* test('loader test 2', async () => {
|
|
67
|
+
* const ctx = contextFactory({ store: { user: differentUser } });
|
|
68
|
+
* // ...
|
|
69
|
+
* });
|
|
70
|
+
*/
|
|
71
|
+
export declare function createContextFactory(baseOptions?: TestContextOptions): (overrides?: Partial<TestContextOptions>) => TestContext;
|
|
72
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAgB,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,oCAAoC;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,kBAAkB;IAClB,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,+BAA+B;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,8CAA8C;IAC9C,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,yCAAyC;IACzC,kBAAkB,IAAI,cAAc,EAAE,CAAC;IACvC,yCAAyC;IACzC,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAsE/E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,GAAE,kBAAuB,GACnC,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,KAAK,WAAW,CAgB1D"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ereo/testing
|
|
3
|
+
*
|
|
4
|
+
* Testing utilities for EreoJS applications.
|
|
5
|
+
* Makes testing loaders, actions, middleware, and components trivial.
|
|
6
|
+
*/
|
|
7
|
+
export { createTestContext, createContextFactory, type TestContextOptions, type TestContext, } from './context';
|
|
8
|
+
export { testLoader, createLoaderTester, type LoaderTestOptions, type LoaderTestResult, } from './loader';
|
|
9
|
+
export { testAction, createActionTester, type ActionTestOptions, type ActionTestResult, } from './action';
|
|
10
|
+
export { testMiddleware, createMiddlewareTester, type MiddlewareTestOptions, type MiddlewareTestResult, } from './middleware';
|
|
11
|
+
export { createMockRequest, createFormRequest, createMockFormData, createMockHeaders, parseJsonResponse, parseTextResponse, type MockRequestOptions, } from './request';
|
|
12
|
+
export { renderRoute, createRouteRenderer, type RenderRouteOptions, type RenderResult, } from './render';
|
|
13
|
+
export { assertRedirect, assertJson, assertStatus, assertHeaders, assertCookies, type AssertionOptions, } from './assertions';
|
|
14
|
+
export { createTestServer, type TestServer, type TestServerOptions, } from './server';
|
|
15
|
+
export { snapshotLoader, snapshotAction, type SnapshotOptions, } from './snapshot';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,kBAAkB,EACvB,KAAK,WAAW,GACjB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,kBAAkB,GACxB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,cAAc,EACd,UAAU,EACV,YAAY,EACZ,aAAa,EACb,aAAa,EACb,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,iBAAiB,GACvB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,cAAc,EACd,cAAc,EACd,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC"}
|