@schmock/core 1.13.0 → 2.0.0
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 +2 -0
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +10 -0
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +12 -0
- package/dist/helpers.d.ts +9 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +37 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/interceptor.d.ts +5 -0
- package/dist/interceptor.d.ts.map +1 -0
- package/dist/interceptor.js +196 -0
- package/dist/plugin-pipeline.js +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/builder.ts +20 -0
- package/src/constants.test.ts +40 -0
- package/src/constants.ts +18 -0
- package/src/helpers.test.ts +106 -0
- package/src/helpers.ts +58 -0
- package/src/index.ts +21 -0
- package/src/interceptor.test.ts +160 -0
- package/src/interceptor.ts +252 -0
- package/src/plugin-pipeline.ts +1 -1
- package/src/steps/interceptor.steps.ts +206 -0
- package/src/types.ts +4 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/// <reference path="../../schmock.d.ts" />
|
|
2
|
+
|
|
3
|
+
import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
|
|
4
|
+
import { expect, vi } from "vitest";
|
|
5
|
+
import { schmock } from "../index.js";
|
|
6
|
+
|
|
7
|
+
const feature = await loadFeature("../../features/fetch-interceptor.feature");
|
|
8
|
+
|
|
9
|
+
describeFeature(feature, ({ Scenario, AfterEachScenario }) => {
|
|
10
|
+
let mock: Schmock.CallableMockInstance;
|
|
11
|
+
let handle: Schmock.InterceptHandle | undefined;
|
|
12
|
+
let originalFetch: typeof globalThis.fetch;
|
|
13
|
+
let savedFetch: ReturnType<typeof vi.fn>;
|
|
14
|
+
let fetchResponse: Response | undefined;
|
|
15
|
+
|
|
16
|
+
function setup() {
|
|
17
|
+
originalFetch = globalThis.fetch;
|
|
18
|
+
savedFetch = vi.fn().mockResolvedValue(new Response("real backend"));
|
|
19
|
+
globalThis.fetch = savedFetch;
|
|
20
|
+
mock = schmock();
|
|
21
|
+
fetchResponse = undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
AfterEachScenario(() => {
|
|
25
|
+
handle?.restore();
|
|
26
|
+
handle = undefined;
|
|
27
|
+
globalThis.fetch = originalFetch;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
Scenario("Intercept a matched fetch request", ({ Given, When, Then, And }) => {
|
|
31
|
+
Given("a Schmock instance with route \"GET /api/users\" returning users", () => {
|
|
32
|
+
setup();
|
|
33
|
+
mock("GET /api/users", [{ id: 1, name: "Alice" }]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
And("fetch is intercepted", () => {
|
|
37
|
+
handle = mock.intercept();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
When("I fetch \"/api/users\"", async () => {
|
|
41
|
+
fetchResponse = await fetch("http://localhost/api/users");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
Then("the fetch response status should be 200", () => {
|
|
45
|
+
expect(fetchResponse?.status).toBe(200);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
And("the fetch response body should be the mocked users", async () => {
|
|
49
|
+
const body = await fetchResponse?.json();
|
|
50
|
+
expect(body).toEqual([{ id: 1, name: "Alice" }]);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
Scenario("Passthrough for unmatched routes", ({ Given, When, Then, And }) => {
|
|
55
|
+
Given("a Schmock instance with route \"GET /api/users\" returning users", () => {
|
|
56
|
+
setup();
|
|
57
|
+
mock("GET /api/users", [{ id: 1 }]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
And("fetch is intercepted with passthrough enabled", () => {
|
|
61
|
+
handle = mock.intercept({ passthrough: true });
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
When("I fetch \"/api/other\"", async () => {
|
|
65
|
+
fetchResponse = await fetch("http://localhost/api/other");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
Then("the original fetch should have been called", () => {
|
|
69
|
+
expect(savedFetch).toHaveBeenCalled();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
Scenario("Passthrough disabled returns 404", ({ Given, When, Then, And }) => {
|
|
74
|
+
Given("a Schmock instance with route \"GET /api/users\" returning users", () => {
|
|
75
|
+
setup();
|
|
76
|
+
mock("GET /api/users", [{ id: 1 }]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
And("fetch is intercepted with passthrough disabled", () => {
|
|
80
|
+
handle = mock.intercept({ passthrough: false });
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
When("I fetch \"/api/other\"", async () => {
|
|
84
|
+
fetchResponse = await fetch("http://localhost/api/other");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
Then("the fetch response status should be 404", () => {
|
|
88
|
+
expect(fetchResponse?.status).toBe(404);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
Scenario("Restore puts original fetch back", ({ Given, When, Then, And }) => {
|
|
93
|
+
let savedRef: typeof globalThis.fetch;
|
|
94
|
+
|
|
95
|
+
Given("a Schmock instance with route \"GET /api/users\" returning users", () => {
|
|
96
|
+
setup();
|
|
97
|
+
mock("GET /api/users", [{ id: 1 }]);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
And("fetch is intercepted", () => {
|
|
101
|
+
savedRef = globalThis.fetch;
|
|
102
|
+
handle = mock.intercept();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
When("I restore the interceptor", () => {
|
|
106
|
+
handle?.restore();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
Then("globalThis.fetch should be the original function", () => {
|
|
110
|
+
expect(globalThis.fetch).toBe(savedRef);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
Scenario("BaseUrl filters which requests are intercepted", ({ Given, When, Then, And }) => {
|
|
115
|
+
Given("a Schmock instance with route \"GET /api/users\" returning users", () => {
|
|
116
|
+
setup();
|
|
117
|
+
mock("GET /api/users", [{ id: 1 }]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
And("fetch is intercepted with baseUrl \"/api\"", () => {
|
|
121
|
+
handle = mock.intercept({ baseUrl: "/api" });
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
When("I fetch \"/other/endpoint\"", async () => {
|
|
125
|
+
await fetch("http://localhost/other/endpoint");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
Then("the original fetch should have been called", () => {
|
|
129
|
+
expect(savedFetch).toHaveBeenCalled();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
Scenario("beforeRequest hook modifies the request", ({ Given, When, Then, And }) => {
|
|
134
|
+
Given("a Schmock instance with route \"GET /api/users\" that reads headers", () => {
|
|
135
|
+
setup();
|
|
136
|
+
mock("GET /api/users", ({ headers }) => [200, { token: headers["x-token"] }]);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
And("fetch is intercepted with a beforeRequest hook that adds a header", () => {
|
|
140
|
+
handle = mock.intercept({
|
|
141
|
+
beforeRequest: (req) => ({
|
|
142
|
+
...req,
|
|
143
|
+
headers: { ...req.headers, "x-token": "injected" },
|
|
144
|
+
}),
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
When("I fetch \"/api/users\"", async () => {
|
|
149
|
+
fetchResponse = await fetch("http://localhost/api/users");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
Then("the response should contain the injected header value", async () => {
|
|
153
|
+
const body = await fetchResponse?.json();
|
|
154
|
+
expect(body).toEqual({ token: "injected" });
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
Scenario("beforeResponse hook modifies the response", ({ Given, When, Then, And }) => {
|
|
159
|
+
Given("a Schmock instance with route \"GET /api/users\" returning users", () => {
|
|
160
|
+
setup();
|
|
161
|
+
mock("GET /api/users", [{ id: 1 }]);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
And("fetch is intercepted with a beforeResponse hook that adds a header", () => {
|
|
165
|
+
handle = mock.intercept({
|
|
166
|
+
beforeResponse: (res) => ({
|
|
167
|
+
...res,
|
|
168
|
+
headers: { ...res.headers, "x-mock": "true" },
|
|
169
|
+
}),
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
When("I fetch \"/api/users\"", async () => {
|
|
174
|
+
fetchResponse = await fetch("http://localhost/api/users");
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
Then("the fetch response should have the injected header", () => {
|
|
178
|
+
expect(fetchResponse?.headers.get("x-mock")).toBe("true");
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
Scenario("Double intercept throws an error", ({ Given, When, Then, And }) => {
|
|
183
|
+
let error: Error | undefined;
|
|
184
|
+
|
|
185
|
+
Given("a Schmock instance with route \"GET /api/users\" returning users", () => {
|
|
186
|
+
setup();
|
|
187
|
+
mock("GET /api/users", [{ id: 1 }]);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
And("fetch is intercepted", () => {
|
|
191
|
+
handle = mock.intercept();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
When("I try to intercept again", () => {
|
|
195
|
+
try {
|
|
196
|
+
mock.intercept();
|
|
197
|
+
} catch (e) {
|
|
198
|
+
error = e as Error;
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
Then("it should throw an error about already intercepting", () => {
|
|
203
|
+
expect(error?.message).toMatch(/already intercepting/i);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
});
|
package/src/types.ts
CHANGED
|
@@ -29,3 +29,7 @@ export type SeedSource = Schmock.SeedSource;
|
|
|
29
29
|
export type SeedConfig = Schmock.SeedConfig;
|
|
30
30
|
export type CliOptions = Schmock.CliOptions;
|
|
31
31
|
export type CliServer = Schmock.CliServer;
|
|
32
|
+
export type AdapterRequest = Schmock.AdapterRequest;
|
|
33
|
+
export type AdapterResponse = Schmock.AdapterResponse;
|
|
34
|
+
export type InterceptOptions = Schmock.InterceptOptions;
|
|
35
|
+
export type InterceptHandle = Schmock.InterceptHandle;
|