@schmock/core 1.0.3 → 1.0.4
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/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +9 -2
- package/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +20 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/types.d.ts +17 -13
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/builder.ts +17 -2
- package/src/constants.test.ts +59 -0
- package/src/constants.ts +25 -0
- package/src/errors.ts +3 -1
- package/src/index.ts +9 -0
- package/src/route-matching.test.ts +1 -1
- package/src/steps/developer-experience.steps.ts +18 -0
- package/src/steps/error-handling.steps.ts +25 -0
- package/src/types.ts +27 -15
package/dist/builder.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,SAAS,EAET,YAAY,EACZ,UAAU,EACV,MAAM,EAGN,cAAc,EACd,QAAQ,EACR,WAAW,EACX,QAAQ,EACT,MAAM,YAAY,CAAC;AA4CpB;;;;GAIG;AACH,qBAAa,oBAAoB;IAKnB,OAAO,CAAC,YAAY;IAJhC,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,MAAM,CAAc;gBAER,YAAY,GAAE,YAAiB;IAanD,WAAW,CACT,KAAK,EAAE,QAAQ,EACf,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,WAAW,GAClB,IAAI;
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,SAAS,EAET,YAAY,EACZ,UAAU,EACV,MAAM,EAGN,cAAc,EACd,QAAQ,EACR,WAAW,EACX,QAAQ,EACT,MAAM,YAAY,CAAC;AA4CpB;;;;GAIG;AACH,qBAAa,oBAAoB;IAKnB,OAAO,CAAC,YAAY;IAJhC,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,MAAM,CAAc;gBAER,YAAY,GAAE,YAAiB;IAanD,WAAW,CACT,KAAK,EAAE,QAAQ,EACf,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,WAAW,GAClB,IAAI;IAuEP,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAepB,MAAM,CACV,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC;IAiLpB;;;;OAIG;YACW,UAAU;IAcxB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IA0DrB;;;;;;;;;;OAUG;YACW,iBAAiB;IAuF/B;;;;;;;;OAQG;IACH,OAAO,CAAC,SAAS;IA6BjB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;CActB"}
|
package/dist/builder.js
CHANGED
|
@@ -88,6 +88,11 @@ export class CallableMockInstance {
|
|
|
88
88
|
}
|
|
89
89
|
// Parse the route key to create pattern and extract parameters
|
|
90
90
|
const parsed = parseRouteKey(route);
|
|
91
|
+
// Check for duplicate routes
|
|
92
|
+
const existing = this.routes.find((r) => r.method === parsed.method && r.path === parsed.path);
|
|
93
|
+
if (existing) {
|
|
94
|
+
this.logger.log("warning", `Duplicate route: ${route} — first registration wins`);
|
|
95
|
+
}
|
|
91
96
|
// Compile the route
|
|
92
97
|
const compiledRoute = {
|
|
93
98
|
pattern: parsed.pattern,
|
|
@@ -116,7 +121,7 @@ export class CallableMockInstance {
|
|
|
116
121
|
return this;
|
|
117
122
|
}
|
|
118
123
|
async handle(method, path, options) {
|
|
119
|
-
const requestId = Math.random().toString(36).substring(
|
|
124
|
+
const requestId = Math.random().toString(36).substring(2, 10) || "00000000";
|
|
120
125
|
this.logger.log("request", `[${requestId}] ${method} ${path}`, {
|
|
121
126
|
headers: options?.headers,
|
|
122
127
|
query: options?.query,
|
|
@@ -365,7 +370,9 @@ export class CallableMockInstance {
|
|
|
365
370
|
if (errorResult) {
|
|
366
371
|
this.logger.log("pipeline", `Plugin ${plugin.name} handled error`);
|
|
367
372
|
// If error handler returns response, use it and stop pipeline
|
|
368
|
-
if (typeof errorResult === "object" &&
|
|
373
|
+
if (typeof errorResult === "object" &&
|
|
374
|
+
errorResult !== null &&
|
|
375
|
+
"status" in errorResult) {
|
|
369
376
|
// Return the error response as the current response, stop pipeline
|
|
370
377
|
response = errorResult;
|
|
371
378
|
break;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { HttpMethod } from "./types.js";
|
|
2
|
+
export declare const ROUTE_NOT_FOUND_CODE: "ROUTE_NOT_FOUND";
|
|
3
|
+
export declare const HTTP_METHODS: readonly HttpMethod[];
|
|
4
|
+
export declare function isHttpMethod(method: string): method is HttpMethod;
|
|
5
|
+
export declare function toHttpMethod(method: string): HttpMethod;
|
|
6
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,oBAAoB,EAAG,iBAA0B,CAAC;AAE/D,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAQpC,CAAC;AAEX,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,UAAU,CAEjE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAMvD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const ROUTE_NOT_FOUND_CODE = "ROUTE_NOT_FOUND";
|
|
2
|
+
export const HTTP_METHODS = [
|
|
3
|
+
"GET",
|
|
4
|
+
"POST",
|
|
5
|
+
"PUT",
|
|
6
|
+
"DELETE",
|
|
7
|
+
"PATCH",
|
|
8
|
+
"HEAD",
|
|
9
|
+
"OPTIONS",
|
|
10
|
+
];
|
|
11
|
+
export function isHttpMethod(method) {
|
|
12
|
+
return HTTP_METHODS.includes(method);
|
|
13
|
+
}
|
|
14
|
+
export function toHttpMethod(method) {
|
|
15
|
+
const upper = method.toUpperCase();
|
|
16
|
+
if (!isHttpMethod(upper)) {
|
|
17
|
+
throw new Error(`Invalid HTTP method: "${method}"`);
|
|
18
|
+
}
|
|
19
|
+
return upper;
|
|
20
|
+
}
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,YAAa,SAAQ,KAAK;aAGnB,IAAI,EAAE,MAAM;aACZ,OAAO,CAAC,EAAE,OAAO;gBAFjC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,YAAA;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,YAAa,SAAQ,KAAK;aAGnB,IAAI,EAAE,MAAM;aACZ,OAAO,CAAC,EAAE,OAAO;gBAFjC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,YAAA;CAQpC;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;gBACtC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAOzC;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,YAAY;gBACnC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAQ7C;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,YAAY;gBAC3C,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK;CAQxC;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,YAAY;gBAC/B,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK;CAO7C;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;gBACxC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAQ7C;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,YAAY;gBACzC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAQnE;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,YAAY;gBACzC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,OAAO;CAQ1D;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;gBACtC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAQ7D"}
|
package/dist/errors.js
CHANGED
|
@@ -9,7 +9,9 @@ export class SchmockError extends Error {
|
|
|
9
9
|
this.code = code;
|
|
10
10
|
this.context = context;
|
|
11
11
|
this.name = "SchmockError";
|
|
12
|
-
Error.captureStackTrace
|
|
12
|
+
if (typeof Error.captureStackTrace === "function") {
|
|
13
|
+
Error.captureStackTrace(this, this.constructor);
|
|
14
|
+
}
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ import type { CallableMockInstance, GlobalConfig } from "./types.js";
|
|
|
23
23
|
* @returns A callable mock instance
|
|
24
24
|
*/
|
|
25
25
|
export declare function schmock(config?: GlobalConfig): CallableMockInstance;
|
|
26
|
+
export { HTTP_METHODS, isHttpMethod, ROUTE_NOT_FOUND_CODE, toHttpMethod, } from "./constants.js";
|
|
26
27
|
export { PluginError, ResourceLimitError, ResponseGenerationError, RouteDefinitionError, RouteNotFoundError, RouteParseError, SchemaGenerationError, SchemaValidationError, SchmockError, } from "./errors.js";
|
|
27
|
-
export type { CallableMockInstance, Generator, GeneratorFunction, GlobalConfig, HttpMethod, Plugin, PluginContext, PluginResult, RequestContext, RequestOptions, Response, ResponseResult, RouteConfig, RouteKey, } from "./types.js";
|
|
28
|
+
export type { CallableMockInstance, Generator, GeneratorFunction, GlobalConfig, HttpMethod, Plugin, PluginContext, PluginResult, RequestContext, RequestOptions, Response, ResponseBody, ResponseResult, RouteConfig, RouteKey, StaticData, } from "./types.js";
|
|
28
29
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EAEpB,YAAY,EAIb,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,oBAAoB,CAsBnE;AAGD,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACrB,YAAY,GACb,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,MAAM,EACN,aAAa,EACb,YAAY,EACZ,cAAc,EACd,cAAc,EACd,QAAQ,EACR,cAAc,EACd,WAAW,EACX,QAAQ,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EAEpB,YAAY,EAIb,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,oBAAoB,CAsBnE;AAGD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,oBAAoB,EACpB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACrB,YAAY,GACb,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,MAAM,EACN,aAAa,EACb,YAAY,EACZ,cAAc,EACd,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,WAAW,EACX,QAAQ,EACR,UAAU,GACX,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -38,5 +38,7 @@ export function schmock(config) {
|
|
|
38
38
|
callableInstance.handle = instance.handle.bind(instance);
|
|
39
39
|
return callableInstance;
|
|
40
40
|
}
|
|
41
|
+
// Re-export constants and utilities
|
|
42
|
+
export { HTTP_METHODS, isHttpMethod, ROUTE_NOT_FOUND_CODE, toHttpMethod, } from "./constants.js";
|
|
41
43
|
// Re-export errors
|
|
42
44
|
export { PluginError, ResourceLimitError, ResponseGenerationError, RouteDefinitionError, RouteNotFoundError, RouteParseError, SchemaGenerationError, SchemaValidationError, SchmockError, } from "./errors.js";
|
package/dist/types.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export interface Plugin {
|
|
|
39
39
|
* @param response - Response from previous plugin (if any)
|
|
40
40
|
* @returns Updated context and response
|
|
41
41
|
*/
|
|
42
|
-
process(context: PluginContext, response?:
|
|
42
|
+
process(context: PluginContext, response?: unknown): PluginResult | Promise<PluginResult>;
|
|
43
43
|
/**
|
|
44
44
|
* Called when an error occurs
|
|
45
45
|
* Can handle, transform, or suppress errors
|
|
@@ -56,7 +56,7 @@ export interface PluginResult {
|
|
|
56
56
|
/** Updated context */
|
|
57
57
|
context: PluginContext;
|
|
58
58
|
/** Response data (if generated/modified) */
|
|
59
|
-
response?:
|
|
59
|
+
response?: unknown;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
62
|
* Context passed through plugin pipeline
|
|
@@ -65,7 +65,7 @@ export interface PluginContext {
|
|
|
65
65
|
/** Request path */
|
|
66
66
|
path: string;
|
|
67
67
|
/** Matched route configuration */
|
|
68
|
-
route:
|
|
68
|
+
route: RouteConfig;
|
|
69
69
|
/** HTTP method */
|
|
70
70
|
method: HttpMethod;
|
|
71
71
|
/** Route parameters */
|
|
@@ -75,11 +75,11 @@ export interface PluginContext {
|
|
|
75
75
|
/** Request headers */
|
|
76
76
|
headers: Record<string, string>;
|
|
77
77
|
/** Request body */
|
|
78
|
-
body?:
|
|
78
|
+
body?: unknown;
|
|
79
79
|
/** Shared state between plugins for this request */
|
|
80
|
-
state: Map<string,
|
|
80
|
+
state: Map<string, unknown>;
|
|
81
81
|
/** Route-specific state */
|
|
82
|
-
routeState?:
|
|
82
|
+
routeState?: Record<string, unknown>;
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
85
|
* Global configuration options for the mock instance
|
|
@@ -92,7 +92,7 @@ export interface GlobalConfig {
|
|
|
92
92
|
/** Enable debug mode for detailed logging */
|
|
93
93
|
debug?: boolean;
|
|
94
94
|
/** Initial shared state object */
|
|
95
|
-
state?:
|
|
95
|
+
state?: Record<string, unknown>;
|
|
96
96
|
}
|
|
97
97
|
/**
|
|
98
98
|
* Route-specific configuration options
|
|
@@ -111,10 +111,14 @@ export type Generator = GeneratorFunction | StaticData | JSONSchema;
|
|
|
111
111
|
* Function that generates responses
|
|
112
112
|
*/
|
|
113
113
|
export type GeneratorFunction = (context: RequestContext) => ResponseResult | Promise<ResponseResult>;
|
|
114
|
+
/**
|
|
115
|
+
* Response body type alias
|
|
116
|
+
*/
|
|
117
|
+
export type ResponseBody = unknown;
|
|
114
118
|
/**
|
|
115
119
|
* Static data (non-function) that gets returned as-is
|
|
116
120
|
*/
|
|
117
|
-
export type StaticData =
|
|
121
|
+
export type StaticData = string | number | boolean | null | undefined | Record<string, unknown> | unknown[];
|
|
118
122
|
/**
|
|
119
123
|
* Context passed to generator functions
|
|
120
124
|
*/
|
|
@@ -130,9 +134,9 @@ export interface RequestContext {
|
|
|
130
134
|
/** Request headers */
|
|
131
135
|
headers: Record<string, string>;
|
|
132
136
|
/** Request body (for POST, PUT, PATCH) */
|
|
133
|
-
body?:
|
|
137
|
+
body?: unknown;
|
|
134
138
|
/** Shared mutable state */
|
|
135
|
-
state:
|
|
139
|
+
state: Record<string, unknown>;
|
|
136
140
|
}
|
|
137
141
|
/**
|
|
138
142
|
* Response result types:
|
|
@@ -140,13 +144,13 @@ export interface RequestContext {
|
|
|
140
144
|
* - [status, body]: custom status with body
|
|
141
145
|
* - [status, body, headers]: custom status, body, and headers
|
|
142
146
|
*/
|
|
143
|
-
export type ResponseResult =
|
|
147
|
+
export type ResponseResult = ResponseBody | [number, ResponseBody] | [number, ResponseBody, Record<string, string>];
|
|
144
148
|
/**
|
|
145
149
|
* Response object returned by handle method
|
|
146
150
|
*/
|
|
147
151
|
export interface Response {
|
|
148
152
|
status: number;
|
|
149
|
-
body:
|
|
153
|
+
body: unknown;
|
|
150
154
|
headers: Record<string, string>;
|
|
151
155
|
}
|
|
152
156
|
/**
|
|
@@ -154,7 +158,7 @@ export interface Response {
|
|
|
154
158
|
*/
|
|
155
159
|
export interface RequestOptions {
|
|
156
160
|
headers?: Record<string, string>;
|
|
157
|
-
body?:
|
|
161
|
+
body?: unknown;
|
|
158
162
|
query?: Record<string, string>;
|
|
159
163
|
}
|
|
160
164
|
/**
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,EAAE,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACb,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,GAClB,KAAK,GACL,MAAM,GACN,KAAK,GACL,QAAQ,GACR,OAAO,GACP,MAAM,GACN,SAAS,CAAC;AAEd;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,GAAG,UAAU,IAAI,MAAM,EAAE,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;;OAMG;IACH,OAAO,CACL,OAAO,EAAE,aAAa,EACtB,QAAQ,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schmock/core",
|
|
3
3
|
"description": "Core functionality for Schmock",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
},
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@amiceli/vitest-cucumber": "^6.
|
|
35
|
-
"@types/node": "^25.
|
|
36
|
-
"@vitest/ui": "^4.0.
|
|
34
|
+
"@amiceli/vitest-cucumber": "^6.2.0",
|
|
35
|
+
"@types/node": "^25.1.0",
|
|
36
|
+
"@vitest/ui": "^4.0.16",
|
|
37
37
|
"vitest": "^4.0.15"
|
|
38
38
|
}
|
|
39
39
|
}
|
package/src/builder.ts
CHANGED
|
@@ -128,6 +128,17 @@ export class CallableMockInstance {
|
|
|
128
128
|
// Parse the route key to create pattern and extract parameters
|
|
129
129
|
const parsed = parseRouteKey(route);
|
|
130
130
|
|
|
131
|
+
// Check for duplicate routes
|
|
132
|
+
const existing = this.routes.find(
|
|
133
|
+
(r) => r.method === parsed.method && r.path === parsed.path,
|
|
134
|
+
);
|
|
135
|
+
if (existing) {
|
|
136
|
+
this.logger.log(
|
|
137
|
+
"warning",
|
|
138
|
+
`Duplicate route: ${route} — first registration wins`,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
131
142
|
// Compile the route
|
|
132
143
|
const compiledRoute: CompiledCallableRoute = {
|
|
133
144
|
pattern: parsed.pattern,
|
|
@@ -168,7 +179,7 @@ export class CallableMockInstance {
|
|
|
168
179
|
path: string,
|
|
169
180
|
options?: RequestOptions,
|
|
170
181
|
): Promise<Response> {
|
|
171
|
-
const requestId = Math.random().toString(36).substring(
|
|
182
|
+
const requestId = Math.random().toString(36).substring(2, 10) || "00000000";
|
|
172
183
|
this.logger.log("request", `[${requestId}] ${method} ${path}`, {
|
|
173
184
|
headers: options?.headers,
|
|
174
185
|
query: options?.query,
|
|
@@ -502,7 +513,11 @@ export class CallableMockInstance {
|
|
|
502
513
|
`Plugin ${plugin.name} handled error`,
|
|
503
514
|
);
|
|
504
515
|
// If error handler returns response, use it and stop pipeline
|
|
505
|
-
if (
|
|
516
|
+
if (
|
|
517
|
+
typeof errorResult === "object" &&
|
|
518
|
+
errorResult !== null &&
|
|
519
|
+
"status" in errorResult
|
|
520
|
+
) {
|
|
506
521
|
// Return the error response as the current response, stop pipeline
|
|
507
522
|
response = errorResult;
|
|
508
523
|
break;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
HTTP_METHODS,
|
|
4
|
+
isHttpMethod,
|
|
5
|
+
ROUTE_NOT_FOUND_CODE,
|
|
6
|
+
toHttpMethod,
|
|
7
|
+
} from "./constants";
|
|
8
|
+
|
|
9
|
+
describe("constants", () => {
|
|
10
|
+
it("exports ROUTE_NOT_FOUND_CODE", () => {
|
|
11
|
+
expect(ROUTE_NOT_FOUND_CODE).toBe("ROUTE_NOT_FOUND");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("exports all HTTP methods", () => {
|
|
15
|
+
expect(HTTP_METHODS).toEqual([
|
|
16
|
+
"GET",
|
|
17
|
+
"POST",
|
|
18
|
+
"PUT",
|
|
19
|
+
"DELETE",
|
|
20
|
+
"PATCH",
|
|
21
|
+
"HEAD",
|
|
22
|
+
"OPTIONS",
|
|
23
|
+
]);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("isHttpMethod", () => {
|
|
28
|
+
it("returns true for valid HTTP methods", () => {
|
|
29
|
+
for (const method of HTTP_METHODS) {
|
|
30
|
+
expect(isHttpMethod(method)).toBe(true);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("returns false for invalid methods", () => {
|
|
35
|
+
expect(isHttpMethod("INVALID")).toBe(false);
|
|
36
|
+
expect(isHttpMethod("")).toBe(false);
|
|
37
|
+
expect(isHttpMethod("get")).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("toHttpMethod", () => {
|
|
42
|
+
it("converts lowercase to uppercase", () => {
|
|
43
|
+
expect(toHttpMethod("get")).toBe("GET");
|
|
44
|
+
expect(toHttpMethod("post")).toBe("POST");
|
|
45
|
+
expect(toHttpMethod("delete")).toBe("DELETE");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("returns already uppercase methods", () => {
|
|
49
|
+
expect(toHttpMethod("GET")).toBe("GET");
|
|
50
|
+
expect(toHttpMethod("PATCH")).toBe("PATCH");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("throws for invalid methods", () => {
|
|
54
|
+
expect(() => toHttpMethod("INVALID")).toThrow(
|
|
55
|
+
'Invalid HTTP method: "INVALID"',
|
|
56
|
+
);
|
|
57
|
+
expect(() => toHttpMethod("")).toThrow('Invalid HTTP method: ""');
|
|
58
|
+
});
|
|
59
|
+
});
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { HttpMethod } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export const ROUTE_NOT_FOUND_CODE = "ROUTE_NOT_FOUND" as const;
|
|
4
|
+
|
|
5
|
+
export const HTTP_METHODS: readonly HttpMethod[] = [
|
|
6
|
+
"GET",
|
|
7
|
+
"POST",
|
|
8
|
+
"PUT",
|
|
9
|
+
"DELETE",
|
|
10
|
+
"PATCH",
|
|
11
|
+
"HEAD",
|
|
12
|
+
"OPTIONS",
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
export function isHttpMethod(method: string): method is HttpMethod {
|
|
16
|
+
return HTTP_METHODS.includes(method as HttpMethod);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function toHttpMethod(method: string): HttpMethod {
|
|
20
|
+
const upper = method.toUpperCase();
|
|
21
|
+
if (!isHttpMethod(upper)) {
|
|
22
|
+
throw new Error(`Invalid HTTP method: "${method}"`);
|
|
23
|
+
}
|
|
24
|
+
return upper;
|
|
25
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -9,7 +9,9 @@ export class SchmockError extends Error {
|
|
|
9
9
|
) {
|
|
10
10
|
super(message);
|
|
11
11
|
this.name = "SchmockError";
|
|
12
|
-
Error.captureStackTrace
|
|
12
|
+
if (typeof Error.captureStackTrace === "function") {
|
|
13
|
+
Error.captureStackTrace(this, this.constructor);
|
|
14
|
+
}
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
|
package/src/index.ts
CHANGED
|
@@ -55,6 +55,13 @@ export function schmock(config?: GlobalConfig): CallableMockInstance {
|
|
|
55
55
|
return callableInstance as CallableMockInstance;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
// Re-export constants and utilities
|
|
59
|
+
export {
|
|
60
|
+
HTTP_METHODS,
|
|
61
|
+
isHttpMethod,
|
|
62
|
+
ROUTE_NOT_FOUND_CODE,
|
|
63
|
+
toHttpMethod,
|
|
64
|
+
} from "./constants.js";
|
|
58
65
|
// Re-export errors
|
|
59
66
|
export {
|
|
60
67
|
PluginError,
|
|
@@ -81,7 +88,9 @@ export type {
|
|
|
81
88
|
RequestContext,
|
|
82
89
|
RequestOptions,
|
|
83
90
|
Response,
|
|
91
|
+
ResponseBody,
|
|
84
92
|
ResponseResult,
|
|
85
93
|
RouteConfig,
|
|
86
94
|
RouteKey,
|
|
95
|
+
StaticData,
|
|
87
96
|
} from "./types.js";
|
|
@@ -311,7 +311,7 @@ describe("route matching", () => {
|
|
|
311
311
|
mock("GET /items/:id", ({ params }) => ({
|
|
312
312
|
id: params.id,
|
|
313
313
|
type: typeof params.id,
|
|
314
|
-
parsed: Number.parseInt(params.id),
|
|
314
|
+
parsed: Number.parseInt(params.id, 10),
|
|
315
315
|
}));
|
|
316
316
|
|
|
317
317
|
const response = await mock.handle("GET", "/items/12345");
|
|
@@ -413,6 +413,24 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
413
413
|
});
|
|
414
414
|
});
|
|
415
415
|
|
|
416
|
+
Scenario("Registering duplicate routes first route wins", ({ Given, When, Then }) => {
|
|
417
|
+
Given("I create a mock with duplicate routes:", (_, docString: string) => {
|
|
418
|
+
mock = schmock();
|
|
419
|
+
mock('GET /items', [{ id: 1 }]);
|
|
420
|
+
mock('GET /items', [{ id: 2 }]);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
When("I request {string}", async (_, request: string) => {
|
|
424
|
+
const [method, path] = request.split(" ");
|
|
425
|
+
response = await mock.handle(method as any, path);
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
Then("the first route response should win:", (_, docString: string) => {
|
|
429
|
+
const expected = JSON.parse(docString);
|
|
430
|
+
expect(response.body).toEqual(expected);
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
|
|
416
434
|
Scenario("Plugin returning unexpected structure", ({ Given, When, Then, And }) => {
|
|
417
435
|
Given("I create a mock with malformed plugin:", (_, docString: string) => {
|
|
418
436
|
mock = schmock();
|
|
@@ -361,6 +361,31 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
361
361
|
});
|
|
362
362
|
});
|
|
363
363
|
|
|
364
|
+
Scenario("Plugin onError returns response with status 0", ({ Given, When, Then, And }) => {
|
|
365
|
+
Given("I create a mock with status-zero error handler:", (_, docString: string) => {
|
|
366
|
+
mock = schmock();
|
|
367
|
+
const plugin = {
|
|
368
|
+
name: 'zero-status',
|
|
369
|
+
process: () => { throw new Error('fail'); },
|
|
370
|
+
onError: () => ({ status: 0, body: 'zero status', headers: {} })
|
|
371
|
+
};
|
|
372
|
+
mock('GET /zero', 'original').pipe(plugin);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
When("I request {string}", async (_, request: string) => {
|
|
376
|
+
const [method, path] = request.split(" ");
|
|
377
|
+
response = await mock.handle(method as any, path);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
Then("I should receive status {int}", (_, status: number) => {
|
|
381
|
+
expect(response.status).toBe(status);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
And("I should receive text {string}", (_, expectedText: string) => {
|
|
385
|
+
expect(response.body).toBe(expectedText);
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
364
389
|
Scenario("Plugin null/undefined return handling", ({ Given, When, Then, And }) => {
|
|
365
390
|
Given("I create a mock with null-returning plugin:", (_, docString: string) => {
|
|
366
391
|
mock = schmock();
|
package/src/types.ts
CHANGED
|
@@ -52,7 +52,7 @@ export interface Plugin {
|
|
|
52
52
|
*/
|
|
53
53
|
process(
|
|
54
54
|
context: PluginContext,
|
|
55
|
-
response?:
|
|
55
|
+
response?: unknown,
|
|
56
56
|
): PluginResult | Promise<PluginResult>;
|
|
57
57
|
|
|
58
58
|
/**
|
|
@@ -79,7 +79,7 @@ export interface PluginResult {
|
|
|
79
79
|
/** Updated context */
|
|
80
80
|
context: PluginContext;
|
|
81
81
|
/** Response data (if generated/modified) */
|
|
82
|
-
response?:
|
|
82
|
+
response?: unknown;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
@@ -89,7 +89,7 @@ export interface PluginContext {
|
|
|
89
89
|
/** Request path */
|
|
90
90
|
path: string;
|
|
91
91
|
/** Matched route configuration */
|
|
92
|
-
route:
|
|
92
|
+
route: RouteConfig;
|
|
93
93
|
/** HTTP method */
|
|
94
94
|
method: HttpMethod;
|
|
95
95
|
/** Route parameters */
|
|
@@ -99,11 +99,11 @@ export interface PluginContext {
|
|
|
99
99
|
/** Request headers */
|
|
100
100
|
headers: Record<string, string>;
|
|
101
101
|
/** Request body */
|
|
102
|
-
body?:
|
|
102
|
+
body?: unknown;
|
|
103
103
|
/** Shared state between plugins for this request */
|
|
104
|
-
state: Map<string,
|
|
104
|
+
state: Map<string, unknown>;
|
|
105
105
|
/** Route-specific state */
|
|
106
|
-
routeState?:
|
|
106
|
+
routeState?: Record<string, unknown>;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
/**
|
|
@@ -117,7 +117,7 @@ export interface GlobalConfig {
|
|
|
117
117
|
/** Enable debug mode for detailed logging */
|
|
118
118
|
debug?: boolean;
|
|
119
119
|
/** Initial shared state object */
|
|
120
|
-
state?:
|
|
120
|
+
state?: Record<string, unknown>;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
/**
|
|
@@ -142,10 +142,22 @@ export type GeneratorFunction = (
|
|
|
142
142
|
context: RequestContext,
|
|
143
143
|
) => ResponseResult | Promise<ResponseResult>;
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Response body type alias
|
|
147
|
+
*/
|
|
148
|
+
export type ResponseBody = unknown;
|
|
149
|
+
|
|
145
150
|
/**
|
|
146
151
|
* Static data (non-function) that gets returned as-is
|
|
147
152
|
*/
|
|
148
|
-
export type StaticData =
|
|
153
|
+
export type StaticData =
|
|
154
|
+
| string
|
|
155
|
+
| number
|
|
156
|
+
| boolean
|
|
157
|
+
| null
|
|
158
|
+
| undefined
|
|
159
|
+
| Record<string, unknown>
|
|
160
|
+
| unknown[];
|
|
149
161
|
|
|
150
162
|
/**
|
|
151
163
|
* Context passed to generator functions
|
|
@@ -162,9 +174,9 @@ export interface RequestContext {
|
|
|
162
174
|
/** Request headers */
|
|
163
175
|
headers: Record<string, string>;
|
|
164
176
|
/** Request body (for POST, PUT, PATCH) */
|
|
165
|
-
body?:
|
|
177
|
+
body?: unknown;
|
|
166
178
|
/** Shared mutable state */
|
|
167
|
-
state:
|
|
179
|
+
state: Record<string, unknown>;
|
|
168
180
|
}
|
|
169
181
|
|
|
170
182
|
/**
|
|
@@ -174,16 +186,16 @@ export interface RequestContext {
|
|
|
174
186
|
* - [status, body, headers]: custom status, body, and headers
|
|
175
187
|
*/
|
|
176
188
|
export type ResponseResult =
|
|
177
|
-
|
|
|
178
|
-
| [number,
|
|
179
|
-
| [number,
|
|
189
|
+
| ResponseBody
|
|
190
|
+
| [number, ResponseBody]
|
|
191
|
+
| [number, ResponseBody, Record<string, string>];
|
|
180
192
|
|
|
181
193
|
/**
|
|
182
194
|
* Response object returned by handle method
|
|
183
195
|
*/
|
|
184
196
|
export interface Response {
|
|
185
197
|
status: number;
|
|
186
|
-
body:
|
|
198
|
+
body: unknown;
|
|
187
199
|
headers: Record<string, string>;
|
|
188
200
|
}
|
|
189
201
|
|
|
@@ -192,7 +204,7 @@ export interface Response {
|
|
|
192
204
|
*/
|
|
193
205
|
export interface RequestOptions {
|
|
194
206
|
headers?: Record<string, string>;
|
|
195
|
-
body?:
|
|
207
|
+
body?: unknown;
|
|
196
208
|
query?: Record<string, string>;
|
|
197
209
|
}
|
|
198
210
|
|