@schmock/express 1.0.0 → 1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAgB,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,KAAK,GAAG,CAAC;IAErD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE3E;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAErE;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CACd,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,KAEX;QACE,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAChC,GACD,SAAS,GACT,OAAO,CAAC,GAAG,CAAC,CAAC;IAEjB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CACf,eAAe,EAAE;QACf,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,GAAG,CAAC;QACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACjC,EACD,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,KAEX;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAC9D,SAAS,GACT,OAAO,CACH;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAC9D,SAAS,CACZ,CAAC;CACP;AAwED;;GAEG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,oBAAoB,EAC1B,OAAO,GAAE,qBAA0B,GAClC,cAAc,CA+EhB;AAED,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAc,MAAM,eAAe,CAAC;AAEtE,OAAO,KAAK,EAAgB,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,KAAK,GAAG,CAAC;IAErD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE3E;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAErE;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CACd,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,KAEX;QACE,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAChC,GACD,SAAS,GACT,OAAO,CAAC,GAAG,CAAC,CAAC;IAEjB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CACf,eAAe,EAAE;QACf,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,GAAG,CAAC;QACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACjC,EACD,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,KAEX;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAC9D,SAAS,GACT,OAAO,CACH;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAC9D,SAAS,CACZ,CAAC;CACP;AAwED;;GAEG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,oBAAoB,EAC1B,OAAO,GAAE,qBAA0B,GAClC,cAAc,CAmFhB;AAED,eAAe,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- class X extends Error{code;context;constructor(A,B,J){super(A);this.code=B;this.context=J;this.name="SchmockError",Error.captureStackTrace(this,this.constructor)}}function z(A,B){if(A.status)B.status(A.status);if(A.headers)Object.entries(A.headers).forEach(([J,U])=>{if(typeof U==="string")B.set(J,U)});if(A.body!==void 0)if(typeof A.body==="string")B.send(A.body);else B.json(A.body);else B.end()}function M(A){return Object.fromEntries(Object.entries(A).map(([B,J])=>[B,Array.isArray(J)?J[0]:J||""]))}function F(A){let B={};for(let[J,U]of Object.entries(A))if(typeof U==="string")B[J]=U;else if(Array.isArray(U))B[J]=U[0]?String(U[0]):"";else if(U!=null)B[J]=String(U);return B}function D(A,B={}){let{errorFormatter:J,passErrorsToNext:U=!0,transformHeaders:O=M,transformQuery:L=F,beforeRequest:_,beforeResponse:$}=B;return async(V,Y,j)=>{try{let G={method:V.method,path:V.path,headers:O(V.headers),body:V.body,query:L(V.query)};if(_){let Z=await _(V,Y);if(Z)G={...G,...Z}}let W=await A.handle(G.method,G.path,{headers:G.headers,body:G.body,query:G.query});if(W){if($){let Z=await $(W,V,Y);if(Z)W=Z}z(W,Y)}else j()}catch(G){if(G instanceof X&&J){let W=J(G,V);Y.status(500).json(W)}else if(U)j(G);else Y.status(500).json({error:G instanceof Error?G.message:"Internal Server Error",code:G instanceof X?G.code:"INTERNAL_ERROR"})}}}var h=D;export{D as toExpress,h as default};
1
+ class $ extends Error{code;context;constructor(H,O,U){super(H);this.code=O;this.context=U;if(this.name="SchmockError",typeof Error.captureStackTrace==="function")Error.captureStackTrace(this,this.constructor)}}var M="ROUTE_NOT_FOUND";function z(H,O){if(H.status)O.status(H.status);if(H.headers)Object.entries(H.headers).forEach(([U,A])=>{if(typeof A==="string")O.set(U,A)});if(H.body!==void 0)if(typeof H.body==="string")O.send(H.body);else O.json(H.body);else O.end()}function F(H){return Object.fromEntries(Object.entries(H).map(([O,U])=>[O,Array.isArray(U)?U[0]:U||""]))}function D(H){let O={};for(let[U,A]of Object.entries(H))if(typeof A==="string")O[U]=A;else if(Array.isArray(A))O[U]=A[0]?String(A[0]):"";else if(A!=null)O[U]=String(A);return O}function N(H,O={}){let{errorFormatter:U,passErrorsToNext:A=!0,transformHeaders:Y=F,transformQuery:Z=D,beforeRequest:V,beforeResponse:W}=O;return async(G,B,X)=>{try{let T={method:G.method,path:G.path,headers:Y(G.headers),body:G.body,query:Z(G.query)};if(V){let J=await V(G,B);if(J)T={...T,...J}}let _=await H.handle(T.method,T.path,{headers:T.headers,body:T.body,query:T.query});if(_.status===404&&_.body&&typeof _.body==="object"&&_.body.code===M){X();return}if(W){let J=await W(_,G,B);if(J)_=J}z(_,B)}catch(T){if(T instanceof $&&U){let _=U(T,G);B.status(500).json(_)}else if(A)X(T);else B.status(500).json({error:T instanceof Error?T.message:"Internal Server Error",code:T instanceof $?T.code:"INTERNAL_ERROR"})}}}var n=N;export{N as toExpress,n as default};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=express-adapter.steps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express-adapter.steps.d.ts","sourceRoot":"","sources":["../../src/steps/express-adapter.steps.ts"],"names":[],"mappings":""}
@@ -0,0 +1,166 @@
1
+ import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
2
+ import { schmock } from "@schmock/core";
3
+ import { expect, vi } from "vitest";
4
+ import { toExpress } from "../index";
5
+ const feature = await loadFeature("../../features/express-adapter.feature");
6
+ function createMockReq(method, path) {
7
+ return {
8
+ method,
9
+ path,
10
+ headers: {},
11
+ body: undefined,
12
+ query: {},
13
+ };
14
+ }
15
+ function createMockRes() {
16
+ const res = {
17
+ _status: 200,
18
+ _body: undefined,
19
+ _headers: {},
20
+ _ended: false,
21
+ status: vi.fn(function (code) {
22
+ this._status = code;
23
+ return this;
24
+ }),
25
+ set: vi.fn(function (key, value) {
26
+ this._headers[key] = value;
27
+ return this;
28
+ }),
29
+ json: vi.fn(function (body) {
30
+ this._body = body;
31
+ this._ended = true;
32
+ }),
33
+ send: vi.fn(function (body) {
34
+ this._body = body;
35
+ this._ended = true;
36
+ }),
37
+ end: vi.fn(function () {
38
+ this._ended = true;
39
+ }),
40
+ };
41
+ return res;
42
+ }
43
+ describeFeature(feature, ({ Scenario }) => {
44
+ let mock;
45
+ let middleware;
46
+ let res;
47
+ let next;
48
+ Scenario("Matched route returns Schmock response", ({ Given, When, Then, And }) => {
49
+ Given("I create an Express middleware from a Schmock mock with:", (_, docString) => {
50
+ mock = schmock();
51
+ mock("GET /users", [{ id: 1, name: "John" }]);
52
+ middleware = toExpress(mock);
53
+ });
54
+ When("a request is made to {string}", async (_, request) => {
55
+ const [method, path] = request.split(" ");
56
+ const req = createMockReq(method, path);
57
+ res = createMockRes();
58
+ next = vi.fn();
59
+ await middleware(req, res, next);
60
+ });
61
+ Then("the Express response should have status {int}", (_, status) => {
62
+ expect(res.status).toHaveBeenCalledWith(status);
63
+ });
64
+ And("the Express response body should be:", (_, docString) => {
65
+ const expected = JSON.parse(docString);
66
+ expect(res.json).toHaveBeenCalledWith(expected);
67
+ });
68
+ And("next should not have been called", () => {
69
+ expect(next).not.toHaveBeenCalled();
70
+ });
71
+ });
72
+ Scenario("Unmatched route calls next for passthrough", ({ Given, When, Then }) => {
73
+ Given("I create an Express middleware from a Schmock mock with:", (_, docString) => {
74
+ mock = schmock();
75
+ mock("GET /users", [{ id: 1 }]);
76
+ middleware = toExpress(mock);
77
+ });
78
+ When("a request is made to {string}", async (_, request) => {
79
+ const [method, path] = request.split(" ");
80
+ const req = createMockReq(method, path);
81
+ res = createMockRes();
82
+ next = vi.fn();
83
+ await middleware(req, res, next);
84
+ });
85
+ Then("next should have been called without error", () => {
86
+ expect(next).toHaveBeenCalledWith();
87
+ });
88
+ });
89
+ Scenario("Unmatched HTTP method calls next for passthrough", ({ Given, When, Then }) => {
90
+ Given("I create an Express middleware from a Schmock mock with:", (_, docString) => {
91
+ mock = schmock();
92
+ mock("GET /users", [{ id: 1 }]);
93
+ middleware = toExpress(mock);
94
+ });
95
+ When("a request is made to {string}", async (_, request) => {
96
+ const [method, path] = request.split(" ");
97
+ const req = createMockReq(method, path);
98
+ res = createMockRes();
99
+ next = vi.fn();
100
+ await middleware(req, res, next);
101
+ });
102
+ Then("next should have been called without error", () => {
103
+ expect(next).toHaveBeenCalledWith();
104
+ });
105
+ });
106
+ Scenario("Error status codes are sent as responses not passthrough", ({ Given, When, Then, And }) => {
107
+ Given("I create an Express middleware from a Schmock mock with:", (_, docString) => {
108
+ mock = schmock();
109
+ mock("GET /error", () => [500, { error: "Server Error" }]);
110
+ middleware = toExpress(mock);
111
+ });
112
+ When("a request is made to {string}", async (_, request) => {
113
+ const [method, path] = request.split(" ");
114
+ const req = createMockReq(method, path);
115
+ res = createMockRes();
116
+ next = vi.fn();
117
+ await middleware(req, res, next);
118
+ });
119
+ Then("the Express response should have status {int}", (_, status) => {
120
+ expect(res.status).toHaveBeenCalledWith(status);
121
+ });
122
+ And("next should not have been called", () => {
123
+ expect(next).not.toHaveBeenCalled();
124
+ });
125
+ });
126
+ Scenario("Generator errors return 500 response", ({ Given, When, Then, And }) => {
127
+ Given("I create an Express middleware from a Schmock mock with:", (_, docString) => {
128
+ mock = schmock();
129
+ mock("GET /fail", () => { throw new Error("Generator exploded"); });
130
+ middleware = toExpress(mock);
131
+ });
132
+ When("a request is made to {string}", async (_, request) => {
133
+ const [method, path] = request.split(" ");
134
+ const req = createMockReq(method, path);
135
+ res = createMockRes();
136
+ next = vi.fn();
137
+ await middleware(req, res, next);
138
+ });
139
+ Then("the Express response should have status {int}", (_, status) => {
140
+ expect(res.status).toHaveBeenCalledWith(status);
141
+ });
142
+ And("next should not have been called", () => {
143
+ expect(next).not.toHaveBeenCalled();
144
+ });
145
+ });
146
+ Scenario("Response headers are forwarded to Express", ({ Given, When, Then, And }) => {
147
+ Given("I create an Express middleware from a Schmock mock with:", (_, docString) => {
148
+ mock = schmock();
149
+ mock("GET /custom", () => [200, { ok: true }, { "x-custom": "value" }]);
150
+ middleware = toExpress(mock);
151
+ });
152
+ When("a request is made to {string}", async (_, request) => {
153
+ const [method, path] = request.split(" ");
154
+ const req = createMockReq(method, path);
155
+ res = createMockRes();
156
+ next = vi.fn();
157
+ await middleware(req, res, next);
158
+ });
159
+ Then("the Express response should have status {int}", (_, status) => {
160
+ expect(res.status).toHaveBeenCalledWith(status);
161
+ });
162
+ And("the Express response should have header {string} with value {string}", (_, header, value) => {
163
+ expect(res.set).toHaveBeenCalledWith(header, value);
164
+ });
165
+ });
166
+ });
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@schmock/express",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Express adapter for Schmock mock API generator",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
- "import": "./dist/index.js",
11
- "types": "./dist/index.d.ts"
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
12
  }
13
13
  },
14
14
  "files": [
@@ -20,11 +20,14 @@
20
20
  "build:types": "tsc -p tsconfig.json",
21
21
  "test": "vitest",
22
22
  "test:watch": "vitest --watch",
23
+ "test:bdd": "vitest run --config vitest.config.bdd.ts",
23
24
  "lint": "biome check src/",
24
- "lint:fix": "biome check --write --unsafe src/"
25
+ "lint:fix": "biome check --write --unsafe src/",
26
+ "check:publish": "publint && attw --pack --ignore-rules cjs-resolves-to-esm"
25
27
  },
26
28
  "dependencies": {},
27
29
  "devDependencies": {
30
+ "@amiceli/vitest-cucumber": "^6.2.0",
28
31
  "@types/express": "^5.0.6",
29
32
  "express": "^5.2.1",
30
33
  "typescript": "^5.9.3",
@@ -32,7 +35,7 @@
32
35
  },
33
36
  "peerDependencies": {
34
37
  "@schmock/core": "^1.0.0",
35
- "express": "^4.18.0"
38
+ "express": "^4.18.0 || ^5.0.0"
36
39
  },
37
40
  "keywords": [
38
41
  "mock",
@@ -43,4 +46,4 @@
43
46
  ],
44
47
  "author": "Khalic Lab",
45
48
  "license": "MIT"
46
- }
49
+ }