@schmock/express 2.1.2 → 2.1.3
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/index.js +147 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1 +1,147 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference path="../../core/schmock.d.ts" />
|
|
2
|
+
import { isRouteNotFound, SchmockError, toHttpMethod } from "@schmock/core";
|
|
3
|
+
/**
|
|
4
|
+
* Convert Schmock response to Express response
|
|
5
|
+
*/
|
|
6
|
+
function schmockToExpressResponse(schmockResponse, res) {
|
|
7
|
+
// Set status code
|
|
8
|
+
if (schmockResponse.status != null) {
|
|
9
|
+
res.status(schmockResponse.status);
|
|
10
|
+
}
|
|
11
|
+
// Set headers
|
|
12
|
+
if (schmockResponse.headers) {
|
|
13
|
+
Object.entries(schmockResponse.headers).forEach(([key, value]) => {
|
|
14
|
+
if (typeof value === "string") {
|
|
15
|
+
res.set(key, value);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
// Send body
|
|
20
|
+
if (schmockResponse.body !== undefined) {
|
|
21
|
+
if (typeof schmockResponse.body === "string") {
|
|
22
|
+
res.send(schmockResponse.body);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
res.json(schmockResponse.body);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
res.end();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Default header transformer
|
|
34
|
+
*/
|
|
35
|
+
function defaultTransformHeaders(headers) {
|
|
36
|
+
return Object.fromEntries(Object.entries(headers)
|
|
37
|
+
.map(([key, value]) => [key, Array.isArray(value) ? value[0] : value])
|
|
38
|
+
.filter((entry) => typeof entry[1] === "string"));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Default query transformer
|
|
42
|
+
*/
|
|
43
|
+
function defaultTransformQuery(query) {
|
|
44
|
+
const result = {};
|
|
45
|
+
for (const [key, value] of Object.entries(query)) {
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
result[key] = value;
|
|
48
|
+
}
|
|
49
|
+
else if (Array.isArray(value)) {
|
|
50
|
+
result[key] = value[0] ? String(value[0]) : "";
|
|
51
|
+
}
|
|
52
|
+
else if (value != null) {
|
|
53
|
+
result[key] = String(value);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Convert a Schmock mock instance to Express middleware
|
|
60
|
+
*/
|
|
61
|
+
export function toExpress(mock, options = {}) {
|
|
62
|
+
const { errorFormatter, passErrorsToNext = true, transformHeaders = defaultTransformHeaders, transformQuery = defaultTransformQuery, beforeRequest, beforeResponse, } = options;
|
|
63
|
+
return async (req, res, next) => {
|
|
64
|
+
try {
|
|
65
|
+
// Skip non-standard HTTP methods (e.g. WebDAV PROPFIND, LOCK)
|
|
66
|
+
let method;
|
|
67
|
+
try {
|
|
68
|
+
method = toHttpMethod(req.method);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return next();
|
|
72
|
+
}
|
|
73
|
+
// Run request interceptor if provided
|
|
74
|
+
let requestData = {
|
|
75
|
+
method,
|
|
76
|
+
path: req.path,
|
|
77
|
+
headers: transformHeaders(req.headers),
|
|
78
|
+
body: req.body,
|
|
79
|
+
query: transformQuery(req.query),
|
|
80
|
+
};
|
|
81
|
+
if (beforeRequest) {
|
|
82
|
+
const intercepted = await beforeRequest(req, res);
|
|
83
|
+
if (intercepted) {
|
|
84
|
+
requestData = {
|
|
85
|
+
...requestData,
|
|
86
|
+
...intercepted,
|
|
87
|
+
method: toHttpMethod(intercepted.method || requestData.method),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Handle request with Schmock
|
|
92
|
+
let schmockResponse = await mock.handle(requestData.method, requestData.path, {
|
|
93
|
+
headers: requestData.headers,
|
|
94
|
+
body: requestData.body,
|
|
95
|
+
query: requestData.query,
|
|
96
|
+
});
|
|
97
|
+
// Detect ROUTE_NOT_FOUND responses and pass to next middleware
|
|
98
|
+
if (isRouteNotFound(schmockResponse)) {
|
|
99
|
+
next();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Run response interceptor if provided
|
|
103
|
+
if (beforeResponse) {
|
|
104
|
+
const intercepted = await beforeResponse(schmockResponse, req, res);
|
|
105
|
+
if (intercepted) {
|
|
106
|
+
schmockResponse = intercepted;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Auto-route schmock's internal 500 ({ error, code }) through
|
|
110
|
+
// errorFormatter so the formatter sees every error path, not just
|
|
111
|
+
// those caught here. Mirrors the Angular adapter behaviour.
|
|
112
|
+
if (errorFormatter &&
|
|
113
|
+
schmockResponse.status === 500 &&
|
|
114
|
+
schmockResponse.body !== null &&
|
|
115
|
+
typeof schmockResponse.body === "object" &&
|
|
116
|
+
"error" in schmockResponse.body &&
|
|
117
|
+
"code" in schmockResponse.body) {
|
|
118
|
+
const respBody = schmockResponse.body;
|
|
119
|
+
const errMsg = typeof respBody.error === "string" ? respBody.error : "Unknown error";
|
|
120
|
+
const formatted = errorFormatter(new Error(errMsg), req);
|
|
121
|
+
res.status(500).json(formatted);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// Convert and send Schmock response
|
|
125
|
+
schmockToExpressResponse(schmockResponse, res);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
// Handle errors based on configuration
|
|
129
|
+
if (errorFormatter) {
|
|
130
|
+
// Fires for any Error from the handler/pipeline, not just
|
|
131
|
+
// SchmockError — matches the Angular adapter's behavior.
|
|
132
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
133
|
+
const formatted = errorFormatter(err, req);
|
|
134
|
+
res.status(500).json(formatted);
|
|
135
|
+
}
|
|
136
|
+
else if (passErrorsToNext) {
|
|
137
|
+
next(error);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
res.status(500).json({
|
|
141
|
+
error: error instanceof Error ? error.message : "Internal Server Error",
|
|
142
|
+
code: error instanceof SchmockError ? error.code : "INTERNAL_ERROR",
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schmock/express",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "Express adapter for Schmock mock API generator",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"@types/node": "^25.8.0",
|
|
34
34
|
"express": "^5.2.1",
|
|
35
35
|
"typescript": "^6.0.3",
|
|
36
|
-
"vitest": "^4.1.
|
|
36
|
+
"vitest": "^4.1.7"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@schmock/core": "^2.1.
|
|
39
|
+
"@schmock/core": "^2.1.3",
|
|
40
40
|
"express": "^4.18.0 || ^5.0.0"
|
|
41
41
|
},
|
|
42
42
|
"keywords": [
|