@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/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ereo/testing - Loader Testing
|
|
3
|
+
*
|
|
4
|
+
* Utilities for testing route loaders.
|
|
5
|
+
*/
|
|
6
|
+
import type { LoaderFunction, RouteParams } from '@ereo/core';
|
|
7
|
+
import { type TestContextOptions, type TestContext } from './context';
|
|
8
|
+
import { type MockRequestOptions } from './request';
|
|
9
|
+
/**
|
|
10
|
+
* Options for testing a loader.
|
|
11
|
+
*/
|
|
12
|
+
export interface LoaderTestOptions<P = RouteParams> {
|
|
13
|
+
/** Route parameters */
|
|
14
|
+
params?: P;
|
|
15
|
+
/** Request options */
|
|
16
|
+
request?: MockRequestOptions;
|
|
17
|
+
/** Context options */
|
|
18
|
+
context?: TestContextOptions;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Result of testing a loader.
|
|
22
|
+
*/
|
|
23
|
+
export interface LoaderTestResult<T = unknown> {
|
|
24
|
+
/** The loader's return value */
|
|
25
|
+
data: T;
|
|
26
|
+
/** The test context (for inspection) */
|
|
27
|
+
context: TestContext;
|
|
28
|
+
/** The request used */
|
|
29
|
+
request: Request;
|
|
30
|
+
/** Execution time in milliseconds */
|
|
31
|
+
duration: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Test a loader function directly.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* import { testLoader } from '@ereo/testing';
|
|
38
|
+
* import { loader } from './routes/blog/[slug]';
|
|
39
|
+
*
|
|
40
|
+
* test('loads blog post', async () => {
|
|
41
|
+
* const result = await testLoader(loader, {
|
|
42
|
+
* params: { slug: 'my-post' },
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* expect(result.data.title).toBe('My Post');
|
|
46
|
+
* expect(result.context.getCacheOperations()).toHaveLength(1);
|
|
47
|
+
* });
|
|
48
|
+
*/
|
|
49
|
+
export declare function testLoader<T = unknown, P = RouteParams>(loader: LoaderFunction<T, P>, options?: LoaderTestOptions<P>): Promise<LoaderTestResult<T>>;
|
|
50
|
+
/**
|
|
51
|
+
* Create a reusable loader tester with preset options.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const testPostLoader = createLoaderTester(loader, {
|
|
55
|
+
* context: { store: { user: testUser } },
|
|
56
|
+
* });
|
|
57
|
+
*
|
|
58
|
+
* test('loads post with user context', async () => {
|
|
59
|
+
* const result = await testPostLoader({ params: { slug: 'test' } });
|
|
60
|
+
* expect(result.data).toBeDefined();
|
|
61
|
+
* });
|
|
62
|
+
*/
|
|
63
|
+
export declare function createLoaderTester<T = unknown, P = RouteParams>(loader: LoaderFunction<T, P>, baseOptions?: LoaderTestOptions<P>): (overrides?: Partial<LoaderTestOptions<P>>) => Promise<LoaderTestResult<T>>;
|
|
64
|
+
/**
|
|
65
|
+
* Test multiple loaders in parallel (for testing combined loaders).
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* const results = await testLoadersParallel([
|
|
69
|
+
* { loader: userLoader, params: { id: '1' } },
|
|
70
|
+
* { loader: postsLoader, params: {} },
|
|
71
|
+
* ]);
|
|
72
|
+
*/
|
|
73
|
+
export declare function testLoadersParallel<T extends unknown[] = unknown[]>(loaders: Array<{
|
|
74
|
+
loader: LoaderFunction<T[number]>;
|
|
75
|
+
params?: RouteParams;
|
|
76
|
+
request?: MockRequestOptions;
|
|
77
|
+
context?: TestContextOptions;
|
|
78
|
+
}>): Promise<LoaderTestResult<T[number]>[]>;
|
|
79
|
+
/**
|
|
80
|
+
* Test loader with multiple param combinations.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* const results = await testLoaderMatrix(loader, {
|
|
84
|
+
* params: [
|
|
85
|
+
* { slug: 'post-1' },
|
|
86
|
+
* { slug: 'post-2' },
|
|
87
|
+
* { slug: 'non-existent' },
|
|
88
|
+
* ],
|
|
89
|
+
* });
|
|
90
|
+
*
|
|
91
|
+
* expect(results[0].data).toBeDefined();
|
|
92
|
+
* expect(results[2].data).toBeNull();
|
|
93
|
+
*/
|
|
94
|
+
export declare function testLoaderMatrix<T = unknown, P = RouteParams>(loader: LoaderFunction<T, P>, options: {
|
|
95
|
+
params: P[];
|
|
96
|
+
request?: MockRequestOptions;
|
|
97
|
+
context?: TestContextOptions;
|
|
98
|
+
}): Promise<LoaderTestResult<T>[]>;
|
|
99
|
+
/**
|
|
100
|
+
* Test loader error handling.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* test('handles missing post', async () => {
|
|
104
|
+
* const result = await testLoaderError(loader, {
|
|
105
|
+
* params: { slug: 'non-existent' },
|
|
106
|
+
* });
|
|
107
|
+
*
|
|
108
|
+
* expect(result.error).toBeInstanceOf(NotFoundError);
|
|
109
|
+
* });
|
|
110
|
+
*/
|
|
111
|
+
export declare function testLoaderError<P = RouteParams>(loader: LoaderFunction<unknown, P>, options?: LoaderTestOptions<P>): Promise<{
|
|
112
|
+
error: Error | null;
|
|
113
|
+
context: TestContext;
|
|
114
|
+
request: Request;
|
|
115
|
+
}>;
|
|
116
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAqB,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACzF,OAAO,EAAqB,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,WAAW;IAChD,uBAAuB;IACvB,MAAM,CAAC,EAAE,CAAC,CAAC;IACX,sBAAsB;IACtB,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,sBAAsB;IACtB,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,OAAO;IAC3C,gCAAgC;IAChC,IAAI,EAAE,CAAC,CAAC;IACR,wCAAwC;IACxC,OAAO,EAAE,WAAW,CAAC;IACrB,uBAAuB;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,UAAU,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,WAAW,EAC3D,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5B,OAAO,GAAE,iBAAiB,CAAC,CAAC,CAAM,GACjC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAe9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,WAAW,EAC7D,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5B,WAAW,GAAE,iBAAiB,CAAC,CAAC,CAAM,IAExB,YAAW,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAM,KAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAc3F;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE,EACvE,OAAO,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B,CAAC,GACD,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAMxC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,WAAW,EACjE,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5B,OAAO,EAAE;IACP,MAAM,EAAE,CAAC,EAAE,CAAC;IACZ,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B,GACA,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAUhC;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CAAC,CAAC,GAAG,WAAW,EACnD,MAAM,EAAE,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,EAClC,OAAO,GAAE,iBAAiB,CAAC,CAAC,CAAM,GACjC,OAAO,CAAC;IACT,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC,CAeD"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ereo/testing - Middleware Testing
|
|
3
|
+
*
|
|
4
|
+
* Utilities for testing middleware functions.
|
|
5
|
+
*/
|
|
6
|
+
import type { MiddlewareHandler, NextFunction } from '@ereo/core';
|
|
7
|
+
import { type TestContextOptions, type TestContext } from './context';
|
|
8
|
+
import { type MockRequestOptions } from './request';
|
|
9
|
+
/**
|
|
10
|
+
* Options for testing middleware.
|
|
11
|
+
*/
|
|
12
|
+
export interface MiddlewareTestOptions {
|
|
13
|
+
/** Request options */
|
|
14
|
+
request?: MockRequestOptions;
|
|
15
|
+
/** Context options */
|
|
16
|
+
context?: TestContextOptions;
|
|
17
|
+
/** Custom next function (defaults to returning 200 OK) */
|
|
18
|
+
next?: NextFunction;
|
|
19
|
+
/** Expected response from next (for pass-through testing) */
|
|
20
|
+
nextResponse?: Response;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Result of testing middleware.
|
|
24
|
+
*/
|
|
25
|
+
export interface MiddlewareTestResult {
|
|
26
|
+
/** The response returned by middleware */
|
|
27
|
+
response: Response;
|
|
28
|
+
/** The test context (for inspection) */
|
|
29
|
+
context: TestContext;
|
|
30
|
+
/** The request used */
|
|
31
|
+
request: Request;
|
|
32
|
+
/** Whether next() was called */
|
|
33
|
+
nextCalled: boolean;
|
|
34
|
+
/** How many times next() was called */
|
|
35
|
+
nextCallCount: number;
|
|
36
|
+
/** Execution time in milliseconds */
|
|
37
|
+
duration: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Test a middleware function directly.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* import { testMiddleware } from '@ereo/testing';
|
|
44
|
+
* import { authMiddleware } from './middleware/auth';
|
|
45
|
+
*
|
|
46
|
+
* test('blocks unauthenticated requests', async () => {
|
|
47
|
+
* const result = await testMiddleware(authMiddleware, {
|
|
48
|
+
* request: { url: '/admin' },
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* expect(result.response.status).toBe(401);
|
|
52
|
+
* expect(result.nextCalled).toBe(false);
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* test('allows authenticated requests', async () => {
|
|
56
|
+
* const result = await testMiddleware(authMiddleware, {
|
|
57
|
+
* request: {
|
|
58
|
+
* url: '/admin',
|
|
59
|
+
* headers: { Authorization: 'Bearer valid-token' },
|
|
60
|
+
* },
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* expect(result.nextCalled).toBe(true);
|
|
64
|
+
* expect(result.response.status).toBe(200);
|
|
65
|
+
* });
|
|
66
|
+
*/
|
|
67
|
+
export declare function testMiddleware(middleware: MiddlewareHandler, options?: MiddlewareTestOptions): Promise<MiddlewareTestResult>;
|
|
68
|
+
/**
|
|
69
|
+
* Create a reusable middleware tester with preset options.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* const testAuth = createMiddlewareTester(authMiddleware, {
|
|
73
|
+
* context: { env: { AUTH_SECRET: 'test-secret' } },
|
|
74
|
+
* });
|
|
75
|
+
*
|
|
76
|
+
* test('allows valid tokens', async () => {
|
|
77
|
+
* const result = await testAuth({
|
|
78
|
+
* request: { headers: { Authorization: 'Bearer valid' } },
|
|
79
|
+
* });
|
|
80
|
+
* expect(result.nextCalled).toBe(true);
|
|
81
|
+
* });
|
|
82
|
+
*/
|
|
83
|
+
export declare function createMiddlewareTester(middleware: MiddlewareHandler, baseOptions?: MiddlewareTestOptions): (overrides?: Partial<MiddlewareTestOptions>) => Promise<MiddlewareTestResult>;
|
|
84
|
+
/**
|
|
85
|
+
* Test a chain of middleware functions.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* const result = await testMiddlewareChain([
|
|
89
|
+
* loggingMiddleware,
|
|
90
|
+
* authMiddleware,
|
|
91
|
+
* rateLimitMiddleware,
|
|
92
|
+
* ], {
|
|
93
|
+
* request: { url: '/api/data' },
|
|
94
|
+
* });
|
|
95
|
+
*
|
|
96
|
+
* expect(result.response.status).toBe(200);
|
|
97
|
+
* expect(result.middlewareResults[0].nextCalled).toBe(true);
|
|
98
|
+
*/
|
|
99
|
+
export declare function testMiddlewareChain(middlewares: MiddlewareHandler[], options?: MiddlewareTestOptions): Promise<{
|
|
100
|
+
response: Response;
|
|
101
|
+
context: TestContext;
|
|
102
|
+
request: Request;
|
|
103
|
+
middlewareResults: Array<{
|
|
104
|
+
index: number;
|
|
105
|
+
nextCalled: boolean;
|
|
106
|
+
duration: number;
|
|
107
|
+
}>;
|
|
108
|
+
}>;
|
|
109
|
+
/**
|
|
110
|
+
* Test middleware with multiple request scenarios.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* const results = await testMiddlewareMatrix(authMiddleware, {
|
|
114
|
+
* requests: [
|
|
115
|
+
* { url: '/public' },
|
|
116
|
+
* { url: '/admin', headers: { Authorization: 'Bearer valid' } },
|
|
117
|
+
* { url: '/admin' }, // No auth
|
|
118
|
+
* ],
|
|
119
|
+
* });
|
|
120
|
+
*
|
|
121
|
+
* expect(results[0].response.status).toBe(200);
|
|
122
|
+
* expect(results[1].response.status).toBe(200);
|
|
123
|
+
* expect(results[2].response.status).toBe(401);
|
|
124
|
+
*/
|
|
125
|
+
export declare function testMiddlewareMatrix(middleware: MiddlewareHandler, options: {
|
|
126
|
+
requests: MockRequestOptions[];
|
|
127
|
+
context?: TestContextOptions;
|
|
128
|
+
}): Promise<MiddlewareTestResult[]>;
|
|
129
|
+
/**
|
|
130
|
+
* Test middleware error handling.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* test('handles errors gracefully', async () => {
|
|
134
|
+
* const result = await testMiddlewareError(errorMiddleware, {
|
|
135
|
+
* next: async () => {
|
|
136
|
+
* throw new Error('Downstream error');
|
|
137
|
+
* },
|
|
138
|
+
* });
|
|
139
|
+
*
|
|
140
|
+
* expect(result.response.status).toBe(500);
|
|
141
|
+
* expect(result.error).toBeNull(); // Middleware caught the error
|
|
142
|
+
* });
|
|
143
|
+
*/
|
|
144
|
+
export declare function testMiddlewareError(middleware: MiddlewareHandler, options: MiddlewareTestOptions & {
|
|
145
|
+
next: NextFunction;
|
|
146
|
+
}): Promise<{
|
|
147
|
+
response: Response | null;
|
|
148
|
+
error: Error | null;
|
|
149
|
+
context: TestContext;
|
|
150
|
+
}>;
|
|
151
|
+
/**
|
|
152
|
+
* Test that middleware modifies context correctly.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* test('sets user in context', async () => {
|
|
156
|
+
* const result = await testMiddlewareContext(authMiddleware, {
|
|
157
|
+
* request: { headers: { Authorization: 'Bearer valid' } },
|
|
158
|
+
* expectContextValues: {
|
|
159
|
+
* user: { id: expect.any(String), role: 'user' },
|
|
160
|
+
* },
|
|
161
|
+
* });
|
|
162
|
+
*
|
|
163
|
+
* expect(result.contextMatches).toBe(true);
|
|
164
|
+
* });
|
|
165
|
+
*/
|
|
166
|
+
export declare function testMiddlewareContext(middleware: MiddlewareHandler, options: MiddlewareTestOptions & {
|
|
167
|
+
expectContextValues: Record<string, unknown>;
|
|
168
|
+
}): Promise<{
|
|
169
|
+
response: Response;
|
|
170
|
+
context: TestContext;
|
|
171
|
+
contextMatches: boolean;
|
|
172
|
+
contextDiff: Record<string, {
|
|
173
|
+
expected: unknown;
|
|
174
|
+
actual: unknown;
|
|
175
|
+
}>;
|
|
176
|
+
}>;
|
|
177
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ereo/testing - Component/Route Rendering
|
|
3
|
+
*
|
|
4
|
+
* Utilities for testing route components with their loaders.
|
|
5
|
+
*/
|
|
6
|
+
import type { ComponentType, ReactElement } from 'react';
|
|
7
|
+
import type { RouteParams, RouteComponentProps, RouteModule } from '@ereo/core';
|
|
8
|
+
import { type TestContextOptions, type TestContext } from './context';
|
|
9
|
+
import { type MockRequestOptions } from './request';
|
|
10
|
+
/**
|
|
11
|
+
* Options for rendering a route.
|
|
12
|
+
*/
|
|
13
|
+
export interface RenderRouteOptions<P = RouteParams> {
|
|
14
|
+
/** Route parameters */
|
|
15
|
+
params?: P;
|
|
16
|
+
/** Request options */
|
|
17
|
+
request?: MockRequestOptions;
|
|
18
|
+
/** Context options */
|
|
19
|
+
context?: TestContextOptions;
|
|
20
|
+
/** Initial loader data (skip loader execution) */
|
|
21
|
+
loaderData?: unknown;
|
|
22
|
+
/** Children to render */
|
|
23
|
+
children?: ReactElement;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Result of rendering a route.
|
|
27
|
+
*/
|
|
28
|
+
export interface RenderResult<T = unknown> {
|
|
29
|
+
/** The rendered element */
|
|
30
|
+
element: ReactElement;
|
|
31
|
+
/** The loader data used */
|
|
32
|
+
loaderData: T;
|
|
33
|
+
/** The test context */
|
|
34
|
+
context: TestContext;
|
|
35
|
+
/** The request used */
|
|
36
|
+
request: Request;
|
|
37
|
+
/** Props passed to the component */
|
|
38
|
+
props: RouteComponentProps<T>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Render a route component with its loader data.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* import { renderRoute } from '@ereo/testing';
|
|
45
|
+
* import { default as BlogPost, loader } from './routes/blog/[slug]';
|
|
46
|
+
*
|
|
47
|
+
* test('renders blog post', async () => {
|
|
48
|
+
* const result = await renderRoute(
|
|
49
|
+
* { default: BlogPost, loader },
|
|
50
|
+
* { params: { slug: 'my-post' } }
|
|
51
|
+
* );
|
|
52
|
+
*
|
|
53
|
+
* // Use with your testing library
|
|
54
|
+
* const { getByText } = render(result.element);
|
|
55
|
+
* expect(getByText('My Post')).toBeInTheDocument();
|
|
56
|
+
* });
|
|
57
|
+
*/
|
|
58
|
+
export declare function renderRoute<T = unknown, P = RouteParams>(module: RouteModule, options?: RenderRouteOptions<P>): Promise<RenderResult<T>>;
|
|
59
|
+
/**
|
|
60
|
+
* Create a reusable route renderer.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const renderBlogPost = createRouteRenderer(
|
|
64
|
+
* { default: BlogPost, loader },
|
|
65
|
+
* { context: { store: { user: testUser } } }
|
|
66
|
+
* );
|
|
67
|
+
*
|
|
68
|
+
* test('renders for authenticated user', async () => {
|
|
69
|
+
* const result = await renderBlogPost({ params: { slug: 'test' } });
|
|
70
|
+
* // ...
|
|
71
|
+
* });
|
|
72
|
+
*/
|
|
73
|
+
export declare function createRouteRenderer<T = unknown, P = RouteParams>(module: RouteModule, baseOptions?: RenderRouteOptions<P>): (overrides?: Partial<RenderRouteOptions<P>>) => Promise<RenderResult<T>>;
|
|
74
|
+
/**
|
|
75
|
+
* Render a standalone component with props.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const element = renderComponent(Counter, { count: 5 });
|
|
79
|
+
*/
|
|
80
|
+
export declare function renderComponent<P extends object>(Component: ComponentType<P>, props: P): ReactElement;
|
|
81
|
+
/**
|
|
82
|
+
* Render a route with multiple param sets for snapshot testing.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* const renders = await renderRouteMatrix(
|
|
86
|
+
* { default: BlogPost, loader },
|
|
87
|
+
* {
|
|
88
|
+
* params: [
|
|
89
|
+
* { slug: 'post-1' },
|
|
90
|
+
* { slug: 'post-2' },
|
|
91
|
+
* ],
|
|
92
|
+
* }
|
|
93
|
+
* );
|
|
94
|
+
*
|
|
95
|
+
* renders.forEach((result, index) => {
|
|
96
|
+
* expect(result.element).toMatchSnapshot(`render-${index}`);
|
|
97
|
+
* });
|
|
98
|
+
*/
|
|
99
|
+
export declare function renderRouteMatrix<T = unknown, P = RouteParams>(module: RouteModule, options: {
|
|
100
|
+
params: P[];
|
|
101
|
+
request?: MockRequestOptions;
|
|
102
|
+
context?: TestContextOptions;
|
|
103
|
+
}): Promise<RenderResult<T>[]>;
|
|
104
|
+
/**
|
|
105
|
+
* Test that a route renders without throwing.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* test('renders without errors', async () => {
|
|
109
|
+
* const result = await testRouteRenders(
|
|
110
|
+
* { default: BlogPost, loader },
|
|
111
|
+
* { params: { slug: 'test' } }
|
|
112
|
+
* );
|
|
113
|
+
*
|
|
114
|
+
* expect(result.renders).toBe(true);
|
|
115
|
+
* expect(result.error).toBeNull();
|
|
116
|
+
* });
|
|
117
|
+
*/
|
|
118
|
+
export declare function testRouteRenders<P = RouteParams>(module: RouteModule, options?: RenderRouteOptions<P>): Promise<{
|
|
119
|
+
renders: boolean;
|
|
120
|
+
error: Error | null;
|
|
121
|
+
result: RenderResult | null;
|
|
122
|
+
}>;
|
|
123
|
+
/**
|
|
124
|
+
* Get the meta tags for a route.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* const meta = await getRouteMeta(
|
|
128
|
+
* { default: BlogPost, loader, meta: metaFn },
|
|
129
|
+
* { params: { slug: 'my-post' } }
|
|
130
|
+
* );
|
|
131
|
+
*
|
|
132
|
+
* expect(meta.find(m => m.title)).toEqual({ title: 'My Post' });
|
|
133
|
+
*/
|
|
134
|
+
export declare function getRouteMeta<P = RouteParams>(module: RouteModule, options?: RenderRouteOptions<P>): Promise<ReturnType<NonNullable<RouteModule['meta']>>>;
|
|
135
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ereo/testing - Request Utilities
|
|
3
|
+
*
|
|
4
|
+
* Create mock requests for testing.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Options for creating a mock request.
|
|
8
|
+
*/
|
|
9
|
+
export interface MockRequestOptions {
|
|
10
|
+
/** HTTP method (default: GET) */
|
|
11
|
+
method?: string;
|
|
12
|
+
/** Request URL or path */
|
|
13
|
+
url?: string;
|
|
14
|
+
/** Request headers */
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
/** Request body (for POST/PUT/PATCH) */
|
|
17
|
+
body?: BodyInit | Record<string, unknown>;
|
|
18
|
+
/** Query parameters */
|
|
19
|
+
searchParams?: Record<string, string | string[]>;
|
|
20
|
+
/** Form data */
|
|
21
|
+
formData?: Record<string, string | Blob>;
|
|
22
|
+
/** Cookies */
|
|
23
|
+
cookies?: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create a mock Request object for testing.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Simple GET request
|
|
30
|
+
* const request = createMockRequest({ url: '/api/posts' });
|
|
31
|
+
*
|
|
32
|
+
* // POST with JSON body
|
|
33
|
+
* const request = createMockRequest({
|
|
34
|
+
* method: 'POST',
|
|
35
|
+
* url: '/api/posts',
|
|
36
|
+
* body: { title: 'Test Post' },
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* // POST with form data
|
|
40
|
+
* const request = createMockRequest({
|
|
41
|
+
* method: 'POST',
|
|
42
|
+
* url: '/api/login',
|
|
43
|
+
* formData: { email: 'test@example.com', password: 'secret' },
|
|
44
|
+
* });
|
|
45
|
+
*/
|
|
46
|
+
export declare function createMockRequest(url?: string | MockRequestOptions, options?: MockRequestOptions): Request;
|
|
47
|
+
/**
|
|
48
|
+
* Create a POST request with form data (convenience function).
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const request = createFormRequest('/api/login', {
|
|
52
|
+
* email: 'test@example.com',
|
|
53
|
+
* password: 'secret',
|
|
54
|
+
* });
|
|
55
|
+
*/
|
|
56
|
+
export declare function createFormRequest(url: string, data: Record<string, string | Blob>): Request;
|
|
57
|
+
/**
|
|
58
|
+
* Create mock FormData for testing.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const formData = createMockFormData({
|
|
62
|
+
* email: 'test@example.com',
|
|
63
|
+
* password: 'secret',
|
|
64
|
+
* });
|
|
65
|
+
*/
|
|
66
|
+
export declare function createMockFormData(data: Record<string, string | Blob | File>): FormData;
|
|
67
|
+
/**
|
|
68
|
+
* Create mock Headers for testing.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* const headers = createMockHeaders({
|
|
72
|
+
* 'Authorization': 'Bearer token123',
|
|
73
|
+
* 'Content-Type': 'application/json',
|
|
74
|
+
* });
|
|
75
|
+
*/
|
|
76
|
+
export declare function createMockHeaders(data: Record<string, string>): Headers;
|
|
77
|
+
/**
|
|
78
|
+
* Parse JSON from a Response.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* const result = await testAction(action, options);
|
|
82
|
+
* const data = await parseJsonResponse<MyData>(result.response);
|
|
83
|
+
*/
|
|
84
|
+
export declare function parseJsonResponse<T = unknown>(response: Response): Promise<T>;
|
|
85
|
+
/**
|
|
86
|
+
* Parse text from a Response.
|
|
87
|
+
*/
|
|
88
|
+
export declare function parseTextResponse(response: Response): Promise<string>;
|
|
89
|
+
/**
|
|
90
|
+
* Create a mock File for testing file uploads.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* const file = createMockFile('test.txt', 'Hello World', 'text/plain');
|
|
94
|
+
*/
|
|
95
|
+
export declare function createMockFile(name: string, content: string | Blob, type?: string): File;
|
|
96
|
+
/**
|
|
97
|
+
* Extract cookies from a Response.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* const cookies = extractCookies(response);
|
|
101
|
+
* expect(cookies.session).toBeDefined();
|
|
102
|
+
*/
|
|
103
|
+
export declare function extractCookies(response: Response): Record<string, string>;
|
|
104
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,wCAAwC;IACxC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,uBAAuB;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IACjD,gBAAgB;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,cAAc;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,kBAAkB,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAU1G;AAiED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAClC,OAAO,CAcT;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,GACzC,QAAQ,CAMV;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAEvE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAOnF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,IAAI,SAA6B,GAChC,IAAI,CAGN;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAazE"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ereo/testing - Test Server
|
|
3
|
+
*
|
|
4
|
+
* Create a test server for integration testing.
|
|
5
|
+
*/
|
|
6
|
+
import type { FrameworkConfig } from '@ereo/core';
|
|
7
|
+
/**
|
|
8
|
+
* Test server options.
|
|
9
|
+
*/
|
|
10
|
+
export interface TestServerOptions {
|
|
11
|
+
/** Framework configuration */
|
|
12
|
+
config?: FrameworkConfig;
|
|
13
|
+
/** Port to run on (default: random available port) */
|
|
14
|
+
port?: number;
|
|
15
|
+
/** Routes directory */
|
|
16
|
+
routesDir?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Test server interface.
|
|
20
|
+
*/
|
|
21
|
+
export interface TestServer {
|
|
22
|
+
/** Server base URL */
|
|
23
|
+
url: string;
|
|
24
|
+
/** Port the server is running on */
|
|
25
|
+
port: number;
|
|
26
|
+
/** Make a request to the server */
|
|
27
|
+
fetch: (path: string, init?: RequestInit) => Promise<Response>;
|
|
28
|
+
/** Make a GET request */
|
|
29
|
+
get: (path: string, init?: Omit<RequestInit, 'method'>) => Promise<Response>;
|
|
30
|
+
/** Make a POST request */
|
|
31
|
+
post: (path: string, body?: unknown, init?: Omit<RequestInit, 'method' | 'body'>) => Promise<Response>;
|
|
32
|
+
/** Make a PUT request */
|
|
33
|
+
put: (path: string, body?: unknown, init?: Omit<RequestInit, 'method' | 'body'>) => Promise<Response>;
|
|
34
|
+
/** Make a DELETE request */
|
|
35
|
+
delete: (path: string, init?: Omit<RequestInit, 'method'>) => Promise<Response>;
|
|
36
|
+
/** Make a PATCH request */
|
|
37
|
+
patch: (path: string, body?: unknown, init?: Omit<RequestInit, 'method' | 'body'>) => Promise<Response>;
|
|
38
|
+
/** Submit a form */
|
|
39
|
+
submitForm: (path: string, formData: Record<string, string>, init?: Omit<RequestInit, 'method' | 'body'>) => Promise<Response>;
|
|
40
|
+
/** Stop the server */
|
|
41
|
+
stop: () => Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create a test server for integration testing.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* import { createTestServer } from '@ereo/testing';
|
|
48
|
+
*
|
|
49
|
+
* describe('API routes', () => {
|
|
50
|
+
* let server: TestServer;
|
|
51
|
+
*
|
|
52
|
+
* beforeAll(async () => {
|
|
53
|
+
* server = await createTestServer({
|
|
54
|
+
* routesDir: './app/routes',
|
|
55
|
+
* });
|
|
56
|
+
* });
|
|
57
|
+
*
|
|
58
|
+
* afterAll(async () => {
|
|
59
|
+
* await server.stop();
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* test('GET /api/posts', async () => {
|
|
63
|
+
* const response = await server.get('/api/posts');
|
|
64
|
+
* expect(response.status).toBe(200);
|
|
65
|
+
*
|
|
66
|
+
* const posts = await response.json();
|
|
67
|
+
* expect(posts).toHaveLength(3);
|
|
68
|
+
* });
|
|
69
|
+
*
|
|
70
|
+
* test('POST /api/posts', async () => {
|
|
71
|
+
* const response = await server.post('/api/posts', {
|
|
72
|
+
* title: 'New Post',
|
|
73
|
+
* content: 'Content here',
|
|
74
|
+
* });
|
|
75
|
+
* expect(response.status).toBe(201);
|
|
76
|
+
* });
|
|
77
|
+
* });
|
|
78
|
+
*/
|
|
79
|
+
export declare function createTestServer(options?: TestServerOptions): Promise<TestServer>;
|
|
80
|
+
/**
|
|
81
|
+
* Create a simple mock server for external API testing.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* const mockApi = await createMockServer({
|
|
85
|
+
* routes: {
|
|
86
|
+
* 'GET /users/1': { id: 1, name: 'Test User' },
|
|
87
|
+
* 'POST /users': (req) => ({ id: 2, ...req.body }),
|
|
88
|
+
* 'GET /users': [{ id: 1 }, { id: 2 }],
|
|
89
|
+
* },
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* // In your test, use mockApi.url as the API base URL
|
|
93
|
+
* process.env.API_URL = mockApi.url;
|
|
94
|
+
*
|
|
95
|
+
* // After test
|
|
96
|
+
* await mockApi.stop();
|
|
97
|
+
*/
|
|
98
|
+
export declare function createMockServer(options: {
|
|
99
|
+
routes: Record<string, unknown | ((request: {
|
|
100
|
+
body?: unknown;
|
|
101
|
+
params?: Record<string, string>;
|
|
102
|
+
}) => unknown)>;
|
|
103
|
+
port?: number;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
url: string;
|
|
106
|
+
port: number;
|
|
107
|
+
stop: () => Promise<void>;
|
|
108
|
+
}>;
|
|
109
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,8BAA8B;IAC9B,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,sBAAsB;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/D,yBAAyB;IACzB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7E,0BAA0B;IAC1B,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,MAAM,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvG,yBAAyB;IACzB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,MAAM,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtG,4BAA4B;IAC5B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChF,2BAA2B;IAC3B,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,MAAM,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxG,oBAAoB;IACpB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,MAAM,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/H,sBAAsB;IACtB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAiH3F;AAoBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,KAAK,OAAO,CAAC,CAAC,CAAC;IAC9G,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAgDpE"}
|