mswjs / msw Goto Github PK
View Code? Open in Web Editor NEWSeamless REST/GraphQL API mocking library for browser and Node.js.
Home Page: https://mswjs.io
License: MIT License
Seamless REST/GraphQL API mocking library for browser and Node.js.
Home Page: https://mswjs.io
License: MIT License
The following request handler:
rest.get('https://test.msw.io', ...)
Will not match https://test.msw.io/
. The trailing slash if often appended automatically. For example, when performing:
fetch('https://test.msw.io')
The request URI would be resolved to https://test.msw.io/
(containing the trailing slash).
https://test.io
=== https://test.io/
https://test.io/foo
=== https://test.io/foo/
I propose to provide a smart request url matching.
https://github.com/kettanaito/msw/blob/a1196004c390d115d29941de405d9db571357107/serviceWorker.js#L38
To support placeholders, params, and other parts of url:
https://domain.com/shop/:shopId
To match all the following:
https://domain.com/shop/foo // { shopId: "foo" }
https://domain.com/shop/bar // { shopId: "bar" }
We can also parse the params and expose them within the req
reference for handler(req)
to access in the mocking handler.
The challenge here is that the logic happens inside a Service Worker, thus it should be done without requiring any package.
There is a Service Mocker library that also utilizes Service Workers for the purpose of API mocking. I'd like to introduce a comparison section to the MSW documentation that highlights the difference between two libraries, helping developers to choose what suits them best.
Please, if you are an active user of Service Mocker feel free to provide suggestions or edits to the comparison table below.
Service Mocker | MSW |
---|---|
Has client and server parts. |
Has only client part. |
Seems like requires to set Service-Worker-Allowed header to register a worker on a path different than root. |
Requires to place the worker file in the public dir of your app. |
I'd say that you need less setup code to start with MSW, making the adoption process faster. The substantial flaw is that MSW requires to place the
mockServiceWorker.js
in your public directory.
Service Mocker | MSW |
---|---|
Adopts Express API in its entirety. Seamless usage for Express users. | Adopts Express API partially. Favors functional composition. Has custom ctx utilities for more efficient mocking. |
Client -- request --> ServiceWorker -- serialize --> Client (MSW) -- get response from schema --> ServiceWorker --> `respondWith()`
I am using the create-react-app in this project.
Following the documentation (https://redd.gitbook.io/msw/recipes/response-patching) and through various combinations of attempts to get it working, I either end up with errors like:
Uncaught TypeError: Cannot read property 'entries' of undefined
at ServiceWorkerContainer. (index.js:1828)
or if I reconstruct the fetch call properly, it creates an infinite loop and still reports errors.
"devDependencies": {
"msw": "^0.8.2"
}
I suggest to add a full support for custom response transformers.
With the functional composition it is easy to create custom response transformers.
text
, json
, delay
, etc.) so the end developer may combine them to their liking.Is your feature request related to a problem? Please describe.
I find it confusing that composeMocks()
function composes request handlers, and not mocks.
Describe the solution you'd like
I think renaming composeMocks()
function to composeHandlers()
would provide a more domain-driven name, and won't confuse the users.
- const { start } = composeMocks(...)
+ const { start } = composeHandlers(...)
Benefits of the change
Drawbacks of the change
Alternatives to consider
I was also thinking about simply naming it compose()
, but I'm afraid this will clash with the similar functional composition utility that is often called compose()
. Also, composeMocks()
is not the traditional compose function per-say, as it's logic is specific to MSW.
I suggest to define a response mocking API supported by the library.
It is essential to have a usable API to define response mocks.
res
from express
Example:
msw.get('...', (req, res) => {
res.status(301).json({ message: 'Item has been moved' })
})
Pros:
res
ObjectCons:
res
Object mutationres
from express is a custom Object)Example:
import { response, status, json } from '–'
msw.get('...', (req) => {
return response(
status(301),
json({ message: 'Item has been moved' }),
)
})
Pros:
Cons:
json
or status
would need to be explicitly imported (may be solved by exposing them as a handler function parameters)Need to add integration tests.
Self-explanatory.
I propose providing a way to supply an alternative function to match the endpoints in the SW. which opens the app for customization according to the open/closed principle.
I am trying to achieve a very similar behavior as in this snippet: https://github.com/GoogleChrome/samples/blob/gh-pages/service-worker/mock-responses/service-worker.js#L24
I need to only serve the mock for some of the endpoints having the X-Mock-Response and regardless of the API base domain URL. which allows me to use both the live API and mock API at the same time.
add additional optional param to the createHandler called matchResolver ( you might want to send more than just the URL param to be but rather the complete request metadata. or adding this same param to the start function and using it inside the interceptRequest function.
If I have a situation like this:
start('/msw.js')
fetch('/something-that-should-be-mocked')
MSW will not be registered as ready until after the request has already been forwarded along. What do you recommend for situations like this where the app is trying to make requests immediately?
Using ctx.fetch inside the response resolver for a POST results in a GET being sent (with no body) instead of a POST (with a body).
Notes:
I wrote an integration test to PR into the repo that replicated the issue, but I did not have permission to push up a branch.
// response-mocking.mocks.ts:
rest.post(
'https://jsonplaceholder.typicode.com/posts',
async (req, res, ctx) => {
const originalResponse = await ctx.fetch(req)
return res(
ctx.json({
...originalResponse,
mocked: true,
}),
)
},
),
// response-patching.test.ts:
describe('given a post request to be patched', () => {
it('should be able to properly request and patch a post', async () => {
const REQUEST_URL = 'https://jsonplaceholder.typicode.com/posts'
api.page.evaluate(
(url) =>
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1,
}),
}),
REQUEST_URL,
)
const res = await api.page.waitForResponse((res) => {
return (
// Await for the response from MSW, so that original response
// from the same URL would not interfere.
res.url() === REQUEST_URL && res.headers()['x-powered-by'] === 'msw'
)
})
const body = await res.json()
expect(res.status()).toBe(200)
expect(body).toEqual({
id: 101,
title: 'foo',
body: 'bar',
userId: 1,
mocked: true,
})
})
})
I tried running yarn msw create public/
, which resulted in an error:
TypeError: yargs.positional is not a function
at Object.yargs.usage.command [as builder] (/path/to/node_modules/msw/cli/msw.js:10:13)
at Object.self.runCommand (/path/to/node_modules/yargs/lib/command.js:193:35)
at Object.Yargs.self._parseArgs (/path/to/node_modules/yargs/yargs.js:990:30)
at Object.get [as argv] (/path/to/node_modules/yargs/yargs.js:930:19)
at Object.<anonymous> (/path/to/node_modules/msw/cli/msw.js:18:10)
at Module._compile (module.js:653:30)
at Object.Module._extensions..js (module.js:664:10)
at Module.load (module.js:566:32)
at tryModuleLoad (module.js:506:12)
at Function.Module._load (module.js:498:3)
error Command failed with exit code 1.
It looks like yargs
is missing as a dep from package.json
in this commit: a8a9854
It would be very helpful to add some documentation and one example to show how to possibly reuse the same mocked APIs code for running Jest tests.
How to set up the Jest test environment so you can leverage the same mocked APIs?
The expectation is that in the node environment, mocks will respond with a shorter latency, compared to when called from the browser.
Successor to #81
Current setup of the IntegrityWebpackPlugin
does not update the global variable injected to contain the latest Service Worker's integrity checksum.
First, the webpack.DefinePlugin()
cannot be used with a simple string value for the injected variable, as it caches the modules by default, so the modules that reference the global variable are cached and won't access the updated checksum.
I've migrated to using
webpack.DefinePlugin.runtimeValue()
instead, which is supposed to skip modules caching and result into updated runtime global variable.
Using runtimeValue()
didn't solve the issue, as the changes in src/mockServiceWorker.js
do not trigger the bundle recompilation. When forcing the recompilation the issue is still not fixed.
The global Service Worker integrity checksum variable must have the latest value in the code in the watch mode of compilation (i.e. using yarn start
). This way the local development always has the Service Worker with the latest integrity.
"msw" abbreviation seems to be used for magicseaweed
. It would be great for a name not to overlap, or be confused with other technologies/brands.
I'd love it if errors my resolvers throw would get converted to rejected responses with a status code of 500. That way the app doesn't come crashing down if I hit something unexpected.
Need to ensure multiple headers with the same name can be handled by MockServiceWorker.
This may also mean to adjust the current algorithm for handling headers between client/sw.
headers
in MSW and interceptRequest
context.set()
to support setting of multiple headers with the same nameWhen we hit msw init public
inside project, throws the following error:
Error: Cannot find module 'chalk'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:582:15)
at Function.Module._load (internal/modules/cjs/loader.js:508:25)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:22:18)
at Object.<anonymous> (/Users/raushan/.nvm/versions/node/v10.15.3/lib/node_modules/msw/cli/init.js:3:15)
at Module._compile (internal/modules/cjs/loader.js:701:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
at Function.Module._load (internal/modules/cjs/loader.js:531:3)
chalk
is not available inside global node_modules
directory.
I have a few ideas for hope this could work, but I was wondering whether anyone had recommendations for hope to integrate this with an unejected react-scripts app.
If I hit ⌘+⇧+R on a page where the service worker is working, then after the reload I'll see that the service worker is activated, but it doesn't handle fetch requests.
I made a video to demonstrate the issue: https://twitter.com/kentcdodds/status/1248642870413680641
Maybe this is related to this: w3c/ServiceWorker#952
pr: #46 , fixs: #43
https://github.com/open-draft/msw/blob/325cf4bbd7247bbb4a4cb7ca5c48b7ace1844f27/src/handleIncomingRequest.ts#L31-L38
const params = relevantRequestHandler.mask
? matchPath(req.url, { path: relevantRequestHandler.mask }).params
: {}
const requestWithParams = {
...req,
params,
}
it will be clearer to take out the params
directly from the match
. We just used the params
of matchPath
tsconfig.json
package.json
The docs don't mention anything about this and I'm not sure of an ergonomic way to create this function...
There should be a way to register the library's ServiceWorker with the proper scope.
In order for it to work, obviously.
.start()
method, instead of manual registration. So that the responsibility of the registration lies on the library, not the end developer.The end developer may have to supply some absolute path to his project's root in order to configure a proper scope.
Originating from #81, I think that treating integrity check failure as an error and disabling the mocking is a safe, but too extreme measure for the users.
npx msw init [PUBLIC_DIR]
Current setup of integration tests does not handle certain asynchronous operations in its setup well, which results into memory leaks often happening when testing locally.
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
This was caused by the missing
afterAll(() => api.cleanup())
hook.
<--- Last few GCs --->
[7874:0x102812000] 85649 ms: Mark-sweep 1381.6 (1455.2) -> 1371.0 (1455.2) MB, 742.3 / 0.0 ms (average mu = 0.160, current mu = 0.072) allocation failure scavenge might not succeed
[7874:0x102812000] 86412 ms: Mark-sweep 1378.7 (1455.7) -> 1375.3 (1436.7) MB, 635.4 / 0.0 ms (+ 78.4 ms in 60 steps since start of marking, biggest step 5.1 ms, walltime since start of marking 739 ms) (average mu = 0.111, current mu = 0.064) allocati
<--- JS stacktrace --->
==== JS stack trace =========================================
0: ExitFrame [pc: 0xaae3f75fd61]
Security context: 0x0317e0f1e6e9 <JSObject>
1: stringSlice(aka stringSlice) [0x317ad8136c1] [buffer.js:~589] [pc=0xaae4065e42f](this=0x0317141826f1 <undefined>,buf=0x0317639bbb89 <Uint8Array map = 0x317d50d5df1>,encoding=0x0317e0f3e981 <String[4]: utf8>,start=0,end=840098)
2: toString [0x3170a7a0819] [buffer.js:~643] [pc=0xaae3f68c2fb](this=0x0317639bbb89 <Uint8Array map = 0x317d50d5df1>,encodi...
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
1: 0x10003d035 node::Abort() [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
2: 0x10003d23f node::OnFatalError(char const*, char const*) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
3: 0x1001b8e15 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
4: 0x100586d72 v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
5: 0x100589845 v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
6: 0x1005856ef v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
7: 0x1005838c4 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
8: 0x100590188 v8::internal::Heap::AllocateRawWithLigthRetry(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
9: 0x1005901df v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
10: 0x100562064 v8::internal::Factory::NewRawTwoByteString(int, v8::internal::PretenureFlag) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
11: 0x100561ca9 v8::internal::Factory::NewStringFromUtf8(v8::internal::Vector<char const>, v8::internal::PretenureFlag) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
12: 0x1001db1b8 v8::String::NewFromUtf8(v8::Isolate*, char const*, v8::NewStringType, int) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
13: 0x1000e8822 node::StringBytes::Encode(v8::Isolate*, char const*, unsigned long, node::encoding, v8::Local<v8::Value>*) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
14: 0x100056889 void node::Buffer::(anonymous namespace)::StringSlice<(node::encoding)1>(v8::FunctionCallbackInfo<v8::Value> const&) [/Users/kettanaito/.nvm/versions/node/v10.16.3/bin/node]
15: 0xaae3f75fd61
runBrowserWith
and spawnServer
utilities have tests that assert they clean up after themselves (i.e. asserting no process is running at the port previously occupied by the server after closing)runBrowserWith
spawnServer
I don't know whether this is possible, but due to the cancelation issues with promises/fetch, XHRs are actually preferable. Can msw support requests made via XHR?
I suggest that MSW would provide a standard set of request handlers for mocking a GraphQL API.
import { composeMocks, graphql } from 'msw'
const { start } = composeMocks(
graphql.query({ operation: 'GetProjectDetail' }, (req, res, ctx) => {
const { projectPath } = req.variables
return res(
ctx.data({
data: {
name: 'mocked-project'
},
}),
)
}),
)
start()
import { composeMocks, graphql } from 'msw'
const { start } = composeMocks(
graphql.mutation({ operation: 'GetProjectDetail' }, (req, res, ctx) => {
return res(
ctx.data({
data: {
name: 'mocked-project'
},
}),
)
}),
)
start()
I have MSW working for a project on localhost:3000, then I close that project and open a new one which does not have MSW and that starts up on localhost:3000 (the default for create-react-app based apps) and MSW hangs around, logs in the console, and generally confuses people.
Can we have MSW's service worker unregister itself when it's not activated when the app starts up? I'd be fine if this is opt-in.
When run, integration tests sometimes result into a timeout on CircleCI.
Integration tests are run without timeouts and exceptions, and report the status of tests appropriately.
I've also encountered a different exception during the CI run of integration tests, when the tests would run, but random test suites would throw an exception.
console.info node_modules/loglevelnext/factory/PrefixFactory.js:43
ℹ 「atl」: Using [email protected] from typescript
console.info node_modules/loglevelnext/factory/PrefixFactory.js:43
ℹ 「atl」: Using tsconfig.json from /root/root/test/tsconfig.json
console.info node_modules/loglevelnext/factory/PrefixFactory.js:43
ℹ 「atl」: Checking started in a separate process...
console.info node_modules/loglevelnext/factory/PrefixFactory.js:43
ℹ 「atl」: Time: 7042ms
console.error node_modules/jest-jasmine2/build/jasmine/Env.js:248
Unhandled error
console.error node_modules/jest-jasmine2/build/jasmine/Env.js:249
Error [ERR_UNHANDLED_ERROR]: Unhandled error. (Error: Page crashed!
at Page._onTargetCrashed (/root/root/node_modules/puppeteer/lib/Page.js:213:24)
at CDPSession.<anonymous> (/root/root/node_modules/puppeteer/lib/Page.js:122:56)
at CDPSession.emit (events.js:196:13)
at CDPSession._onMessage (/root/root/node_modules/puppeteer/lib/Connection.js:200:12)
at Connection._onMessage (/root/root/node_modules/puppeteer/lib/Connection.js:112:17)
at WebSocket.<anonymous> (/root/root/node_modules/puppeteer/lib/WebSocketTransport.js:44:24)
at WebSocket.onMessage (/root/root/node_modules/ws/lib/event-target.js:120:16)
at WebSocket.emit (events.js:196:13)
at Receiver.receiverOnMessage (/root/root/node_modules/ws/lib/websocket.js:789:20)
at Receiver.emit (events.js:196:13)
at Receiver.dataMessage (/root/root/node_modules/ws/lib/receiver.js:422:14)
at Receiver.getData (/root/root/node_modules/ws/lib/receiver.js:352:17)
at Receiver.startLoop (/root/root/node_modules/ws/lib/receiver.js:138:22)
at Receiver._write (/root/root/node_modules/ws/lib/receiver.js:74:10)
at doWrite (_stream_writable.js:417:12)
at writeOrBuffer (_stream_writable.js:401:5)
at Receiver.Writable.write (_stream_writable.js:301:11)
at Socket.socketOnData (/root/root/node_modules/ws/lib/websocket.js:864:35)
at Socket.emit (events.js:196:13)
at addChunk (_stream_readable.js:290:12)
at readableAddChunk (_stream_readable.js:271:11)
at Socket.Readable.push (_stream_readable.js:226:10)
at TCP.onStreamRead (internal/stream_base_commons.js:166:17))
at Page.emit (events.js:185:17)
at Page._onTargetCrashed (/root/root/node_modules/puppeteer/lib/Page.js:213:10)
at CDPSession.<anonymous> (/root/root/node_modules/puppeteer/lib/Page.js:122:56)
at CDPSession.emit (events.js:196:13)
at CDPSession._onMessage (/root/root/node_modules/puppeteer/lib/Connection.js:200:12)
at Connection._onMessage (/root/root/node_modules/puppeteer/lib/Connection.js:112:17)
at WebSocket.<anonymous> (/root/root/node_modules/puppeteer/lib/WebSocketTransport.js:44:24)
at WebSocket.onMessage (/root/root/node_modules/ws/lib/event-target.js:120:16)
at WebSocket.emit (events.js:196:13)
at Receiver.receiverOnMessage (/root/root/node_modules/ws/lib/websocket.js:789:20)
Such test where the failure originates would be marked as passing. It's necessary to ensure that exception does not happen, so there are no false positive tests.
Those requests which have matched the request handlers defined in the composeMocks()
call should be logged into a browser's console.
[MSW] 10:10:02 GET /users
The log entry is represented by console.group
, clicking on which reveals the following information:
3.1. Intercepted request.
3.2. Request handler used.
3.3. Resolved mocked response object.
I suggest to consider adopting matchPath
utility from react-router
.
It's a tested function from one of the most used routing solution. It will most likely handle all the necessary routing scenarios, which are crucial for API mocking as well.
Cons:
I ran into a usecase whereby I needed to personalize mock responses based on the request's body for POST
requests:
msw.post(
"http://localhost:3000/cats",
(req, res, { status, set, delay, json }) => {
if(req.body) {
// do something with body
}
return res(status(404), delay(10000), json({ errorMessage: `no cats :(` }));
}
);
I can send a quick PR for this if there's interest for this.
Usage of classes implies multiple instances of that class. However, this is not the use case for mocking, as you would expect to have a mocking interface configured at one place, once.
const msw = new MSW()
The end usage is also ugly.
Internal usage of class is fine, but it may make sense to expose the instantiated instance of that class to the end developer.
import msw from 'msw'
msw.get(...)
The lib/index.js
file is built via webpack and has a console.warn
in it in the match
function from node-match-path
:
/**
* Matches a given url against a path.
*/
const match = (path, url) => {
const expression = path instanceof RegExp ? path : pathToRegExp(path);
const match = expression.exec(url) || false;
// Matches in strict mode: match string should equal to input (url)
// Otherwise loose matches will be considered truthy:
// match('/messages/:id', '/messages/123/users') // true
const matches = !!match && match[0] === match.input;
console.warn('nmp', { path, url, match, matches })
return {
matches,
params: match && matches ? match.groups || null : null,
};
};
But no version of node-match-path
has a console.warn
in it. Could we get a rebuild of this and a publish to get rid of that warning? It's kind of distracting 😅
Thanks!
I'm pretty sure this is a bug in pathToRegExp
(why is this project not using path-to-regexp
like many other path parsers?). But if I provide the following URL: http://localhost:8989/api/book?query=:query
this gets parsed to the following regex: http:\/\/localhost:8989\/api\/book?query=(?<query>.+?(?=\/|$))\/?
You may notice that the ?
for the search string is not escaped. I believe that to be a bug in the parser. If I escape it myself, then things work just fine.
Need to migrate the existing documentation to a new service provider.
To have stable and free documentation that won't shut down out of the blue.
Please include any topics related to MSW in the comments, I will think of where to put them in the documentation.
I propose to develop a browser extension for MSW.
The library must assert the integrity of the mockServiceWorker.js
file for multiple reasons:
msw
packagemockServiceWorker.js
file contentstart()
invocation to get the integrity information.npx init <PUBLIC_DIR>
to resolve the issue.For example:
import { msw } from "msw";
msw.post(
"http://localhost:3000/cats",
(req, res, { status, set, delay, json }) => {
return res(status(404), delay(10000), json({ errorMessage: `no cats :(` }));
}
);
msw.start();
It seems that the normalizeMask()
function is turning the following URL http://localhost:3000/cats
into ^http://localhost(\w+)/cats\/?$
which will not match successfully since the colon isn't alpha-numeric:
Current success message of running msw init
command is:
https://github.com/open-draft/msw/blob/1fc124726f2d6b1e76e5cb7bfe306d94b3061acd/cli/init.js#L29-L34
The API example illustrated in the message is misleading, as the library does not export the msw
namespace, neither that namespace has the start()
method.
The message of successfully running the msw init
command should link the developer to the documentation.
Methods return nothing, impossible to listen to the registration or removal of registration of the Service Worker.
Such behavior also makes these methods un-testable, as they provide no native method to react to them.
I should be able to do start().then
and stop().then
to react to the respective Service Worker events (registration/unregistration).
It would be great to shoot a small live demo of how the process of using msw
looks like. It can be converted into a GIF later and put at the top of the README file.
The demo would consist of the following steps:
mocks.js
Current behavior expects the developer to either specify an entire hostname (http://backend.com/users
) or use a wildcard (*/users
) to handle request URI.
It's familiar to developers to specify routes with a leading slash and expecting the hostname to be matched implicitly.
When provided the route /users
MSW would match any /users
requests that are fired from the current page's hostname:
http://localhost:8080/users
However, it won't match the same paths from the different hostname:
https://api.dev.backend/users
Mocking response cookies is forbidden by the specification, however, since MSW operates in the client scope, it may fake cookies by setting them directly on document.cookies
.
rest.get('/user', (req, res, ctx) => {
return res(
ctx.cookie('name', 'value')
)
})
// context/cookie.ts
export const cookie = (name: string, value:string) => {
return (res) => {
document.cookies = /* write cookies manually */
return res
}
}
msw: 0.4.2
When defining the following request handler:
rest.get('/users/:userId', (req, res, ctx) => {
return res(ctx.text(req.params.userId)
})
The req.params.userId
reference returns undefined
. I can see that all the parameters are nested in the req.params.params
key, which is not the correct behavior.
Request URL path parameters are listed on the req.params
object, containing only key-value pairs of parameter name and parameter value. There must be no other information (like matches
).
I suggest to implement a support for a feature called audit.
Audit allows to capture outgoing page requests and store them in the cache. Then, the route-less mocking can be performed by returning the original responses stored in the cache. This is, basically, how ServiceWorker is meant to be used for caching purposes.
First, audit mode must be enabled.
msw.startAudit()
While audit mode is enabled, any outgoing requests will be stored in the ServiceWorker's cache.
Complementary, audit mode can be disabled, to prevent caching behavior.
msw.stopAudit()
On a technical level, dispatching of aforementioned methods sends a message to the ServiceWorker, and sets its internal flag to the corresponding boolean value. While the flag is enabled, ServiceWorker will try to cache the received responses in the fetch
event.
(?) Should the request matching the routes be mocked? Or should audit mode explicitly disable mocking behavior while it's on?
Developer needs to explicitly enable to mock requests from the cache:
msw.useCache()
It should be possible to opt-out from this behavior at any point of time.
Since audited requests are stored in the cache, it should be possible to clear the cache.
msw.clearCache()
This issue originates from #77
I suggest to add a support for spawning a local server for the purpose of testing.
There are complex test scenarios (such as "response patching") that assert against an actual server implementation. Relying on third-party servers brings a factor of instability to the CI pipeline of MSW. Having a local server for the sake of testing sounds like a viable option.
The local server can also replace any external dependencies and be used as an actual running server. This is something to consider.
0
for the server to always have a dedicated port)response-matching.test.ts
and any other tests that require an actual server to use the introduced local server implementationafterAll()
test suites are finishedA declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.