You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/src/content/docs/advanced.md
+142-1
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,7 @@ title: Advanced
3
3
description: Advanced usage as well as tips, tricks, and best practices
4
4
---
5
5
6
-
Various anselary topics and advanced usage.
6
+
Advanced usage and various topics.
7
7
8
8
## Data fetching
9
9
@@ -16,6 +16,147 @@ Fetching data can be done simply and safely using an **automatically-typed fetch
16
16
>
17
17
> A good fetch wrapper should **never use generics.** Generics require more typing and can hide errors!
18
18
19
+
## Testing
20
+
21
+
One of the most common causes of false positive tests is when mocks are out-of-date with the actual API responses.
22
+
23
+
`openapi-typescript` offers a fantastic way to guard against this with minimal effort. Here’s one example how you could write your own helper function to typecheck all mocks to match your OpenAPI schema (we’ll use [vitest](https://vitest.dev/)/[vitest-fetch-mock](https://www.npmjs.com/package/vitest-fetch-mock) but the same principle could work for any setup):
24
+
25
+
Let’s say we want to write our mocks in the following object structure, so we can mock multiple endpoints at once:
26
+
27
+
```
28
+
{
29
+
[pathname]: {
30
+
[HTTP method]: {
31
+
[HTTP status code]: { [some mock data] }
32
+
}
33
+
}
34
+
}
35
+
```
36
+
37
+
Using our generated types we can then infer **the correct data shape** for any given path + HTTP method + status code. An example test would look like this:
body: JSON.stringify({ id: "new-user", name: "New User" }),
69
+
});
70
+
71
+
// test cleanup
72
+
fetchMock.resetMocks();
73
+
});
74
+
});
75
+
```
76
+
77
+
_Note: this example uses a vanilla `fetch()` function, but any fetch wrapper—including [openapi-fetch](/openapi-fetch)—could be dropped in instead without any changes._
78
+
79
+
And the magic that produces this would live in a `test/utils.ts` file that can be copy + pasted where desired (hidden for simplicity):
// note: we get lazy with the types here, because the inference is bad anyway and this has a `void` return signature. The important bit is the parameter signature.
112
+
if (!mockedPath|| (!responsesasany)[mockedPath]) thrownewError(`No mocked response for ${req.url}`); // throw error if response not mocked (remove or modify if you’d like different behavior)
113
+
const method =req.method.toLowerCase();
114
+
if (!(responsesasany)[mockedPath][method]) thrownewError(`${req.method} called but not mocked on ${mockedPath}`); // likewise throw error if other parts of response aren’t mocked
if (actualParts.length!==testParts.length) continue; // automatically not a match if lengths differ
132
+
for (let i =0; i<testParts.length; i++) {
133
+
if (testParts[i]!.startsWith("{")) continue; // path params ({user_id}) always count as a match
134
+
if (actualParts[i] !==testParts[i]) {
135
+
matched=false;
136
+
break;
137
+
}
138
+
}
139
+
if (matched) returnp;
140
+
}
141
+
}
142
+
```
143
+
144
+
> **Additional Explanation** That code is quite above is quite a doozy! For the most part, it’s a lot of implementation detail you can ignore. The `mockResponses(…)` function signature is where all the important magic happens—you’ll notice a direct link between this structure and our design. From there, the rest of the code is just making the runtime work as expected.
0 commit comments