Skip to content

Commit

Permalink
feat!: upgrade to msw v1, and support using the mocker with non-node …
Browse files Browse the repository at this point in the history
…environments
  • Loading branch information
swain committed Nov 2, 2023
1 parent 649f338 commit 5079d32
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 50 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,15 @@ cache.updateInfiniteCache(
If you're using [`jest`](https://jestjs.io/) for testing, use `createAPIMockingUtility` to create a shareable utility for mocking network calls.
```typescript
import { setupServer } from 'msw/node';

// Set up your server, and start listening.
const server = setupServer();
server.listen({ onUnhandledRequest: 'error' });

// Specify your custom "APIEndpoints" type as the generic parameter here.
export const useAPIMocking = createAPIMockingUtility<APIEndpoints>({
server,
baseUrl: 'https://my.api.com',
});

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.2.1",
"jest-environment-jsdom": "^29.2.1",
"msw": "^0.47.4",
"msw": "^1.0.0",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
4 changes: 4 additions & 0 deletions src/hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { createAPIHooks } from './hooks';
import { createAPIMockingUtility } from './test-utils';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { CacheUtils, EndpointInvalidationMap, RequestPayloadOf } from './types';
import { setupServer } from 'msw/node';

type TestEndpoints = {
'GET /items': {
Expand Down Expand Up @@ -54,7 +55,10 @@ const {
client,
});

const server = setupServer();
server.listen({ onUnhandledRequest: 'error' });
const network = createAPIMockingUtility<TestEndpoints>({
server,
baseUrl: 'https://www.lifeomic.com',
})();

Expand Down
5 changes: 5 additions & 0 deletions src/test-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import axios from 'axios';
import { v4 } from 'uuid';
import { createAPIMockingUtility } from './test-utils';
import { APIClient } from './util';
import { setupServer } from 'msw/node';

describe('createAPIMockingUtility', () => {
type TestEndpoints = {
Expand All @@ -19,7 +20,11 @@ describe('createAPIMockingUtility', () => {
};
};

const server = setupServer();
server.listen({ onUnhandledRequest: 'error' });

const useNetworkMocking = createAPIMockingUtility<TestEndpoints>({
server,
baseUrl: 'https://www.lifeomic.com',
});

Expand Down
34 changes: 26 additions & 8 deletions src/test-utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
import * as msw from 'msw';
import { setupServer, SetupServerApi } from 'msw/node';
import { RequestHandler, rest } from 'msw';
/**
* Important: we need to avoid import actual values from these imports:
* - 'msw/node'
* - 'msw/native'
*
* Why: importing from those platform-specific modules can cause import-time
* failures for consumers that are using a different platform.
*
* It's okay to import _types_ from those paths, but not values.
*/
import type { SetupServer } from 'msw/node';
import { PathParamsOf, RoughEndpoints } from './types';

// This type is the "least common denominator" between the Node
// and browser variants of MSW.
type MSWUsable = {
use: (...handlers: RequestHandler[]) => void;
resetHandlers: () => void;
};

export type APIMockerResponse<T> =
| { status: 200; data: T }
| { status: 400 | 401 | 403 | 404 | 500; data: any };
Expand Down Expand Up @@ -76,7 +93,7 @@ export type APIMocker<Endpoints extends RoughEndpoints> = {
};

export const createAPIMocker = <Endpoints extends RoughEndpoints>(
server: SetupServerApi,
server: MSWUsable,
baseUrl: string,
): APIMocker<Endpoints> => {
const api: APIMocker<Endpoints> = {} as any;
Expand All @@ -94,7 +111,7 @@ export const createAPIMocker = <Endpoints extends RoughEndpoints>(
| 'post';

server.use(
msw.rest[lowercaseMethod](`${baseUrl}${url}`, async (req, res, ctx) => {
rest[lowercaseMethod](`${baseUrl}${url}`, async (req, res, ctx) => {
const resolve = options.once ? res.once : res;

if (typeof handlerOrResponse !== 'function') {
Expand Down Expand Up @@ -164,6 +181,7 @@ export const createAPIMocker = <Endpoints extends RoughEndpoints>(
};

export type CreateAPIMockingConfig = {
server: SetupServer;
baseUrl: string;
};

Expand All @@ -187,11 +205,11 @@ export type CreateAPIMockingConfig = {
* api.mock('GET /something', { status: 200, data: { message: 'test-message' } })
*/
export const createAPIMockingUtility =
<Endpoints extends RoughEndpoints>({ baseUrl }: CreateAPIMockingConfig) =>
<Endpoints extends RoughEndpoints>({
server,
baseUrl,
}: CreateAPIMockingConfig) =>
() => {
const server = setupServer();
server.listen({ onUnhandledRequest: 'error' });

const mocker = createAPIMocker<Endpoints>(server, baseUrl);

beforeEach(() => {
Expand Down
78 changes: 37 additions & 41 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -724,16 +724,16 @@
"@types/set-cookie-parser" "^2.4.0"
set-cookie-parser "^2.4.6"

"@mswjs/interceptors@^0.17.5":
version "0.17.6"
resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.17.6.tgz#7f7900f4cd26f70d9f698685e4485b2f4101d26a"
integrity sha512-201pBIWehTURb6q8Gheu4Zhvd3Ox1U4BJq5KiOQsYzkWyfiOG4pwcz5hPZIEryztgrf8/sdwABpvY757xMmfrQ==
"@mswjs/interceptors@^0.17.10":
version "0.17.10"
resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.17.10.tgz#857b41f30e2b92345ed9a4e2b1d0a08b8b6fcad4"
integrity sha512-N8x7eSLGcmUFNWZRxT1vsHvypzIRgQYdG0rJey/rZCy6zT/30qDt8Joj7FxzGNLSwXbeZqJOMqDurp7ra4hgbw==
dependencies:
"@open-draft/until" "^1.0.3"
"@types/debug" "^4.1.7"
"@xmldom/xmldom" "^0.8.3"
debug "^4.3.3"
headers-polyfill "^3.1.0"
headers-polyfill "3.2.5"
outvariant "^1.2.1"
strict-event-emitter "^0.2.4"
web-encoding "^1.1.5"
Expand Down Expand Up @@ -1916,14 +1916,6 @@ cardinal@^2.1.1:
ansicolors "~0.3.2"
redeyed "~2.1.0"

[email protected]:
version "4.1.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"

chalk@^2.0.0, chalk@^2.3.2, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
Expand Down Expand Up @@ -3100,7 +3092,7 @@ grapheme-splitter@^1.0.4:
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==

"graphql@^15.0.0 || ^16.0.0":
graphql@^16.8.1:
version "16.8.1"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07"
integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==
Expand Down Expand Up @@ -3168,10 +3160,10 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"

headers-polyfill@^3.1.0:
version "3.1.2"
resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-3.1.2.tgz#9a4dcb545c5b95d9569592ef7ec0708aab763fbe"
integrity sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==
headers-polyfill@3.2.5:
version "3.2.5"
resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-3.2.5.tgz#6e67d392c9d113d37448fe45014e0afdd168faed"
integrity sha512-tUCGvt191vNSQgttSyJoibR+VO+I6+iCHIUdhzEMJKE+EAL8BwCN7fUOZlY4ofOelNHsK+gEjxB/B+9N3EWtdA==

hook-std@^2.0.0:
version "2.0.0"
Expand Down Expand Up @@ -3504,10 +3496,10 @@ is-negative-zero@^2.0.2:
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==

is-node-process@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.0.1.tgz#4fc7ac3a91e8aac58175fe0578abbc56f2831b23"
integrity sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ==
is-node-process@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134"
integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==

is-number-object@^1.0.4:
version "1.0.7"
Expand Down Expand Up @@ -4696,29 +4688,28 @@ ms@^2.0.0, ms@^2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==

msw@^0.47.4:
version "0.47.4"
resolved "https://registry.yarnpkg.com/msw/-/msw-0.47.4.tgz#5551011609890c6b62a2047055f475a9afae2ad4"
integrity sha512-Psftt8Yfl0+l+qqg9OlmKEsxF8S/vtda0CmlR6y8wTaWrMMzuCDa55n2hEGC0ZRDwuV6FFWc/4CjoDsBpATKBw==
msw@^1.0.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/msw/-/msw-1.3.2.tgz#35e0271293e893fc3c55116e90aad5d955c66899"
integrity sha512-wKLhFPR+NitYTkQl5047pia0reNGgf0P6a1eTnA5aNlripmiz0sabMvvHcicE8kQ3/gZcI0YiPFWmYfowfm3lA==
dependencies:
"@mswjs/cookies" "^0.2.2"
"@mswjs/interceptors" "^0.17.5"
"@mswjs/interceptors" "^0.17.10"
"@open-draft/until" "^1.0.3"
"@types/cookie" "^0.4.1"
"@types/js-levenshtein" "^1.1.1"
chalk "4.1.1"
chalk "^4.1.1"
chokidar "^3.4.2"
cookie "^0.4.2"
graphql "^15.0.0 || ^16.0.0"
headers-polyfill "^3.1.0"
graphql "^16.8.1"
headers-polyfill "3.2.5"
inquirer "^8.2.0"
is-node-process "^1.0.1"
is-node-process "^1.2.0"
js-levenshtein "^1.1.6"
node-fetch "^2.6.7"
outvariant "^1.3.0"
outvariant "^1.4.0"
path-to-regexp "^6.2.0"
statuses "^2.0.0"
strict-event-emitter "^0.2.6"
strict-event-emitter "^0.4.3"
type-fest "^2.19.0"
yargs "^17.3.1"

Expand Down Expand Up @@ -5110,11 +5101,16 @@ os-tmpdir@~1.0.2:
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==

outvariant@^1.2.1, outvariant@^1.3.0:
outvariant@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.3.0.tgz#c39723b1d2cba729c930b74bf962317a81b9b1c9"
integrity sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ==

outvariant@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.0.tgz#e742e4bda77692da3eca698ef5bfac62d9fba06e"
integrity sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==

p-each-series@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a"
Expand Down Expand Up @@ -5994,11 +5990,6 @@ stack-utils@^2.0.3:
dependencies:
escape-string-regexp "^2.0.0"

statuses@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==

stream-combiner2@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe"
Expand All @@ -6007,13 +5998,18 @@ stream-combiner2@~1.1.1:
duplexer2 "~0.1.0"
readable-stream "^2.0.2"

strict-event-emitter@^0.2.4, strict-event-emitter@^0.2.6:
strict-event-emitter@^0.2.4:
version "0.2.7"
resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.2.7.tgz#5326a21811551995ab5f8158ea250de57fb2b04e"
integrity sha512-TavbHJ87WD2tDbKI7bTrmc6U4J4Qjh8E9fVvFkIFw2gCu34Wxstn2Yas0+4D78FJN8DOTEzxiT+udBdraRk4UQ==
dependencies:
events "^3.3.0"

strict-event-emitter@^0.4.3:
version "0.4.6"
resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz#ff347c8162b3e931e3ff5f02cfce6772c3b07eb3"
integrity sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==

string-length@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
Expand Down

0 comments on commit 5079d32

Please sign in to comment.