@bagaar/ember-graphql-mocking 0.5.0 → 0.7.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/CHANGELOG.md +31 -0
- package/README.md +22 -9
- package/addon-test-support/index.js +8 -4
- package/index.js +3 -3
- package/package.json +39 -36
- package/public/mockServiceWorker.js +121 -156
- package/config/environment.js +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## v0.7.0 (2023-02-22)
|
|
8
|
+
|
|
9
|
+
#### :boom: Breaking Change
|
|
10
|
+
* [#104](https://github.com/Bagaar/ember-graphql-mocking/pull/104) Update `msw` to v1 and make it a peer dependency ([@gvdp](https://github.com/gvdp))
|
|
11
|
+
|
|
12
|
+
#### :rocket: Enhancement
|
|
13
|
+
* [#104](https://github.com/Bagaar/ember-graphql-mocking/pull/104) Update `msw` to v1 and make it a peer dependency ([@gvdp](https://github.com/gvdp))
|
|
14
|
+
* [#100](https://github.com/Bagaar/ember-graphql-mocking/pull/100) Speed up requiring `index.js` file ([@bertdeblock](https://github.com/bertdeblock))
|
|
15
|
+
|
|
16
|
+
#### :memo: Documentation
|
|
17
|
+
* [#106](https://github.com/Bagaar/ember-graphql-mocking/pull/106) Update compatibility and installation section ([@bertdeblock](https://github.com/bertdeblock))
|
|
18
|
+
|
|
19
|
+
#### Committers: 2
|
|
20
|
+
- Bert De Block ([@bertdeblock](https://github.com/bertdeblock))
|
|
21
|
+
- [@gvdp](https://github.com/gvdp)
|
|
22
|
+
|
|
23
|
+
## v0.6.0 (2022-09-05)
|
|
24
|
+
|
|
25
|
+
#### :boom: Breaking Change
|
|
26
|
+
* [#38](https://github.com/Bagaar/ember-graphql-mocking/pull/38) Make `setupEmberGraphqlMocking` async ([@bertdeblock](https://github.com/bertdeblock))
|
|
27
|
+
* [#37](https://github.com/Bagaar/ember-graphql-mocking/pull/37) Update `graphql` and `msw` dependencies ([@bertdeblock](https://github.com/bertdeblock))
|
|
28
|
+
* [#34](https://github.com/Bagaar/ember-graphql-mocking/pull/34) Update `msw` to v0.43.0 ([@bertdeblock](https://github.com/bertdeblock))
|
|
29
|
+
|
|
30
|
+
#### :bug: Bug Fix
|
|
31
|
+
* [#38](https://github.com/Bagaar/ember-graphql-mocking/pull/38) Make `setupEmberGraphqlMocking` async ([@bertdeblock](https://github.com/bertdeblock))
|
|
32
|
+
|
|
33
|
+
#### Committers: 1
|
|
34
|
+
- Bert De Block ([@bertdeblock](https://github.com/bertdeblock))
|
|
35
|
+
|
|
5
36
|
## v0.5.0 (2022-06-24)
|
|
6
37
|
|
|
7
38
|
#### :boom: Breaking Change
|
package/README.md
CHANGED
|
@@ -11,11 +11,20 @@ Ember addon for mocking GraphQL requests using [Mock Service Worker (MSW)](https
|
|
|
11
11
|
- Ember.js v3.28 or above
|
|
12
12
|
- Ember CLI v3.28 or above
|
|
13
13
|
- Node.js v14 or above
|
|
14
|
+
- MSW v1 or above
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
17
18
|
```shell
|
|
18
|
-
|
|
19
|
+
npm install -D @bagaar/ember-graphql-mocking msw
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```shell
|
|
23
|
+
pnpm add -D @bagaar/ember-graphql-mocking msw
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```shell
|
|
27
|
+
yarn add -D @bagaar/ember-graphql-mocking msw
|
|
19
28
|
```
|
|
20
29
|
|
|
21
30
|
## Usage
|
|
@@ -25,7 +34,7 @@ ember install @bagaar/ember-graphql-mocking
|
|
|
25
34
|
In `tests/test-helper.js`:
|
|
26
35
|
1. Import `setupEmberGraphqlMocking`
|
|
27
36
|
2. Import your GraphQL schema
|
|
28
|
-
3. Call `setupEmberGraphqlMocking` with your GraphQL schema
|
|
37
|
+
3. Call `setupEmberGraphqlMocking` with your GraphQL schema
|
|
29
38
|
|
|
30
39
|
```javascript
|
|
31
40
|
// tests/test-helper.js
|
|
@@ -39,24 +48,28 @@ import { start } from 'ember-qunit';
|
|
|
39
48
|
import { setupEmberGraphqlMocking } from '@bagaar/ember-graphql-mocking/test-support'; // 1.
|
|
40
49
|
import schema from 'my-app/graphql/schema'; // 2.
|
|
41
50
|
|
|
51
|
+
QUnit.begin(() => setupEmberGraphqlMocking(schema)); // 3.
|
|
52
|
+
|
|
42
53
|
setApplication(Application.create(config.APP));
|
|
43
54
|
|
|
44
55
|
setup(QUnit.assert);
|
|
45
56
|
|
|
46
|
-
setupEmberGraphqlMocking(schema); // 3.
|
|
47
|
-
|
|
48
57
|
start();
|
|
49
58
|
```
|
|
50
59
|
|
|
60
|
+
> **NOTE:** Make sure to use `QUnit.begin`, as `setupEmberGraphqlMocking` returns a Promise.
|
|
61
|
+
|
|
51
62
|
If you want to pass along additional [start options](https://mswjs.io/docs/api/setup-worker/start#options)
|
|
52
63
|
to MSW's service worker, you can do so by defining an `mswStartOptions` object:
|
|
53
64
|
|
|
54
65
|
```js
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
66
|
+
QUnit.begin(() =>
|
|
67
|
+
setupEmberGraphqlMocking(schema, {
|
|
68
|
+
mswStartOptions: {
|
|
69
|
+
// Additional MSW start options...
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
);
|
|
60
73
|
```
|
|
61
74
|
|
|
62
75
|
### 2. Write an Acceptance Test
|
|
@@ -22,8 +22,10 @@ let worker = null;
|
|
|
22
22
|
export function setupEmberGraphqlMocking(schemaDocument, providedOptions) {
|
|
23
23
|
const options = merge({}, DEFAULT_OPTIONS, providedOptions);
|
|
24
24
|
|
|
25
|
-
createWorker(
|
|
25
|
+
createWorker();
|
|
26
26
|
createGraphqlOperationHandler(schemaDocument);
|
|
27
|
+
|
|
28
|
+
return startWorker(options.mswStartOptions);
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
export function setupGraphqlTest(hooks) {
|
|
@@ -51,10 +53,8 @@ export function destroyWorker() {
|
|
|
51
53
|
worker = null;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
function createWorker(
|
|
56
|
+
function createWorker() {
|
|
55
57
|
worker = setupWorker();
|
|
56
|
-
|
|
57
|
-
worker.start(options.mswStartOptions);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
function createGraphqlOperationHandler(schemaDocument) {
|
|
@@ -73,6 +73,10 @@ function createGraphqlOperationHandler(schemaDocument) {
|
|
|
73
73
|
worker.use(graphqlOperation);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
function startWorker(mswStartOptions) {
|
|
77
|
+
return worker.start(mswStartOptions);
|
|
78
|
+
}
|
|
79
|
+
|
|
76
80
|
function clearRoot() {
|
|
77
81
|
root = null;
|
|
78
82
|
}
|
package/index.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const funnel = require('broccoli-funnel');
|
|
4
|
-
const mergeTrees = require('broccoli-merge-trees');
|
|
5
|
-
|
|
6
3
|
module.exports = {
|
|
7
4
|
name: require('./package').name,
|
|
8
5
|
|
|
@@ -14,6 +11,9 @@ module.exports = {
|
|
|
14
11
|
return;
|
|
15
12
|
}
|
|
16
13
|
|
|
14
|
+
const funnel = require('broccoli-funnel');
|
|
15
|
+
const mergeTrees = require('broccoli-merge-trees');
|
|
16
|
+
|
|
17
17
|
return mergeTrees([tree, funnel(host.trees.public)], {
|
|
18
18
|
overwrite: true,
|
|
19
19
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bagaar/ember-graphql-mocking",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Ember addon for mocking GraphQL requests using Mock Service Worker (MSW).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ember-addon"
|
|
@@ -14,15 +14,15 @@
|
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "ember build --environment=production",
|
|
17
|
-
"lint": "
|
|
18
|
-
"lint:fix": "npm
|
|
17
|
+
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
|
|
18
|
+
"lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
|
|
19
19
|
"lint:hbs": "ember-template-lint .",
|
|
20
20
|
"lint:hbs:fix": "ember-template-lint . --fix",
|
|
21
21
|
"lint:js": "eslint . --cache",
|
|
22
22
|
"lint:js:fix": "eslint . --fix",
|
|
23
23
|
"prepare": "husky install",
|
|
24
24
|
"start": "ember serve",
|
|
25
|
-
"test": "npm
|
|
25
|
+
"test": "concurrently \"npm:lint\" \"npm:test:*\" --names \"lint,test:\"",
|
|
26
26
|
"test:ember": "ember test",
|
|
27
27
|
"test:ember-compatibility": "ember try:each"
|
|
28
28
|
},
|
|
@@ -31,61 +31,64 @@
|
|
|
31
31
|
"@commitlint/config-conventional"
|
|
32
32
|
]
|
|
33
33
|
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"ember-source": "^3.28.0 || ^4.0.0",
|
|
36
|
+
"msw": "^1.0.1"
|
|
37
|
+
},
|
|
34
38
|
"dependencies": {
|
|
35
39
|
"broccoli-funnel": "^3.0.5",
|
|
36
40
|
"broccoli-merge-trees": "^4.2.0",
|
|
37
|
-
"ember-auto-import": "^2.
|
|
41
|
+
"ember-auto-import": "^2.5.0",
|
|
38
42
|
"ember-cli-babel": "^7.26.11",
|
|
39
|
-
"graphql": "^16.
|
|
40
|
-
"lodash.merge": "^4.6.2"
|
|
41
|
-
"msw": "^0.42.3"
|
|
43
|
+
"graphql": "^16.6.0",
|
|
44
|
+
"lodash.merge": "^4.6.2"
|
|
42
45
|
},
|
|
43
46
|
"devDependencies": {
|
|
44
|
-
"@commitlint/cli": "^17.
|
|
45
|
-
"@commitlint/config-conventional": "^17.
|
|
47
|
+
"@commitlint/cli": "^17.4.4",
|
|
48
|
+
"@commitlint/config-conventional": "^17.4.4",
|
|
46
49
|
"@ember/optional-features": "^2.0.0",
|
|
47
|
-
"@ember/
|
|
48
|
-
"@
|
|
50
|
+
"@ember/string": "^3.0.1",
|
|
51
|
+
"@ember/test-helpers": "^2.9.3",
|
|
52
|
+
"@embroider/test-setup": "^2.0.2",
|
|
49
53
|
"@glimmer/component": "^1.1.2",
|
|
50
54
|
"@glimmer/tracking": "^1.1.2",
|
|
55
|
+
"@release-it-plugins/lerna-changelog": "^5.0.0",
|
|
51
56
|
"babel-eslint": "^10.1.0",
|
|
52
57
|
"broccoli-asset-rev": "^3.0.0",
|
|
53
|
-
"
|
|
54
|
-
"ember-
|
|
58
|
+
"concurrently": "^7.6.0",
|
|
59
|
+
"ember-apollo-client": "^4.1.0",
|
|
60
|
+
"ember-cli": "~4.10.0",
|
|
55
61
|
"ember-cli-dependency-checker": "^3.3.1",
|
|
56
|
-
"ember-cli-htmlbars": "^6.0
|
|
62
|
+
"ember-cli-htmlbars": "^6.2.0",
|
|
57
63
|
"ember-cli-inject-live-reload": "^2.1.0",
|
|
58
64
|
"ember-cli-sri": "^2.1.1",
|
|
59
65
|
"ember-cli-terser": "^4.0.2",
|
|
60
|
-
"ember-
|
|
61
|
-
"ember-export-application-global": "^2.0.1",
|
|
62
|
-
"ember-fetch": "^8.0.4",
|
|
66
|
+
"ember-fetch": "^8.1.2",
|
|
63
67
|
"ember-load-initializers": "^2.1.2",
|
|
64
68
|
"ember-page-title": "^7.0.0",
|
|
65
|
-
"ember-qunit": "^
|
|
66
|
-
"ember-resolver": "^
|
|
67
|
-
"ember-source": "~4.
|
|
69
|
+
"ember-qunit": "^6.1.1",
|
|
70
|
+
"ember-resolver": "^10.0.0",
|
|
71
|
+
"ember-source": "~4.10.0",
|
|
68
72
|
"ember-source-channel-url": "^3.0.0",
|
|
69
|
-
"ember-template-lint": "^
|
|
73
|
+
"ember-template-lint": "^5.3.1",
|
|
70
74
|
"ember-try": "^2.0.0",
|
|
71
75
|
"eslint": "^7.32.0",
|
|
72
|
-
"eslint-config-prettier": "^8.
|
|
73
|
-
"eslint-plugin-ember": "^
|
|
74
|
-
"eslint-plugin-
|
|
75
|
-
"eslint-plugin-prettier": "^4.
|
|
76
|
-
"eslint-plugin-qunit": "^7.
|
|
77
|
-
"husky": "^8.0.
|
|
76
|
+
"eslint-config-prettier": "^8.6.0",
|
|
77
|
+
"eslint-plugin-ember": "^11.4.3",
|
|
78
|
+
"eslint-plugin-n": "^15.6.1",
|
|
79
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
80
|
+
"eslint-plugin-qunit": "^7.3.4",
|
|
81
|
+
"husky": "^8.0.3",
|
|
78
82
|
"loader.js": "^4.7.0",
|
|
79
|
-
"
|
|
80
|
-
"prettier": "^2.
|
|
81
|
-
"qunit": "^2.19.
|
|
83
|
+
"msw": "^1.0.1",
|
|
84
|
+
"prettier": "^2.8.3",
|
|
85
|
+
"qunit": "^2.19.3",
|
|
82
86
|
"qunit-dom": "^2.0.0",
|
|
83
|
-
"release-it": "^
|
|
84
|
-
"
|
|
85
|
-
"webpack": "^5.72.1"
|
|
87
|
+
"release-it": "^15.6.0",
|
|
88
|
+
"webpack": "^5.75.0"
|
|
86
89
|
},
|
|
87
90
|
"engines": {
|
|
88
|
-
"node": "14.* || >=
|
|
91
|
+
"node": "14.* || 16.* || >= 18"
|
|
89
92
|
},
|
|
90
93
|
"publishConfig": {
|
|
91
94
|
"access": "public",
|
|
@@ -102,7 +105,7 @@
|
|
|
102
105
|
},
|
|
103
106
|
"release-it": {
|
|
104
107
|
"plugins": {
|
|
105
|
-
"release-it-lerna-changelog": {
|
|
108
|
+
"@release-it-plugins/lerna-changelog": {
|
|
106
109
|
"infile": "CHANGELOG.md",
|
|
107
110
|
"launchEditor": false
|
|
108
111
|
}
|
|
@@ -2,22 +2,21 @@
|
|
|
2
2
|
/* tslint:disable */
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Mock Service Worker (0.
|
|
5
|
+
* Mock Service Worker (1.0.1).
|
|
6
6
|
* @see https://github.com/mswjs/msw
|
|
7
7
|
* - Please do NOT modify this file.
|
|
8
8
|
* - Please do NOT serve this file on production.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const INTEGRITY_CHECKSUM = '
|
|
12
|
-
const bypassHeaderName = 'x-msw-bypass'
|
|
11
|
+
const INTEGRITY_CHECKSUM = '3d6b9f06410d179a7f7404d4bf4c3c70'
|
|
13
12
|
const activeClientIds = new Set()
|
|
14
13
|
|
|
15
14
|
self.addEventListener('install', function () {
|
|
16
|
-
|
|
15
|
+
self.skipWaiting()
|
|
17
16
|
})
|
|
18
17
|
|
|
19
|
-
self.addEventListener('activate',
|
|
20
|
-
|
|
18
|
+
self.addEventListener('activate', function (event) {
|
|
19
|
+
event.waitUntil(self.clients.claim())
|
|
21
20
|
})
|
|
22
21
|
|
|
23
22
|
self.addEventListener('message', async function (event) {
|
|
@@ -33,7 +32,9 @@ self.addEventListener('message', async function (event) {
|
|
|
33
32
|
return
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
const allClients = await self.clients.matchAll(
|
|
35
|
+
const allClients = await self.clients.matchAll({
|
|
36
|
+
type: 'window',
|
|
37
|
+
})
|
|
37
38
|
|
|
38
39
|
switch (event.data) {
|
|
39
40
|
case 'KEEPALIVE_REQUEST': {
|
|
@@ -83,30 +84,58 @@ self.addEventListener('message', async function (event) {
|
|
|
83
84
|
}
|
|
84
85
|
})
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// communicate with during the response resolving phase.
|
|
90
|
-
async function resolveMainClient(event) {
|
|
91
|
-
const client = await self.clients.get(event.clientId)
|
|
87
|
+
self.addEventListener('fetch', function (event) {
|
|
88
|
+
const { request } = event
|
|
89
|
+
const accept = request.headers.get('accept') || ''
|
|
92
90
|
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
// Bypass server-sent events.
|
|
92
|
+
if (accept.includes('text/event-stream')) {
|
|
93
|
+
return
|
|
95
94
|
}
|
|
96
95
|
|
|
97
|
-
|
|
96
|
+
// Bypass navigation requests.
|
|
97
|
+
if (request.mode === 'navigate') {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
98
100
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
101
|
+
// Opening the DevTools triggers the "only-if-cached" request
|
|
102
|
+
// that cannot be handled by the worker. Bypass such requests.
|
|
103
|
+
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Bypass all requests when there are no active clients.
|
|
108
|
+
// Prevents the self-unregistered worked from handling requests
|
|
109
|
+
// after it's been deleted (still remains active until the next reload).
|
|
110
|
+
if (activeClientIds.size === 0) {
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Generate unique request ID.
|
|
115
|
+
const requestId = Math.random().toString(16).slice(2)
|
|
116
|
+
|
|
117
|
+
event.respondWith(
|
|
118
|
+
handleRequest(event, requestId).catch((error) => {
|
|
119
|
+
if (error.name === 'NetworkError') {
|
|
120
|
+
console.warn(
|
|
121
|
+
'[MSW] Successfully emulated a network error for the "%s %s" request.',
|
|
122
|
+
request.method,
|
|
123
|
+
request.url,
|
|
124
|
+
)
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// At this point, any exception indicates an issue with the original request/response.
|
|
129
|
+
console.error(
|
|
130
|
+
`\
|
|
131
|
+
[MSW] Caught an exception from the "%s %s" request (%s). This is probably not a problem with Mock Service Worker. There is likely an additional logging output above.`,
|
|
132
|
+
request.method,
|
|
133
|
+
request.url,
|
|
134
|
+
`${error.name}: ${error.message}`,
|
|
135
|
+
)
|
|
136
|
+
}),
|
|
137
|
+
)
|
|
138
|
+
})
|
|
110
139
|
|
|
111
140
|
async function handleRequest(event, requestId) {
|
|
112
141
|
const client = await resolveMainClient(event)
|
|
@@ -128,7 +157,7 @@ async function handleRequest(event, requestId) {
|
|
|
128
157
|
statusText: clonedResponse.statusText,
|
|
129
158
|
body:
|
|
130
159
|
clonedResponse.body === null ? null : await clonedResponse.text(),
|
|
131
|
-
headers:
|
|
160
|
+
headers: Object.fromEntries(clonedResponse.headers.entries()),
|
|
132
161
|
redirected: clonedResponse.redirected,
|
|
133
162
|
},
|
|
134
163
|
})
|
|
@@ -138,14 +167,54 @@ async function handleRequest(event, requestId) {
|
|
|
138
167
|
return response
|
|
139
168
|
}
|
|
140
169
|
|
|
170
|
+
// Resolve the main client for the given event.
|
|
171
|
+
// Client that issues a request doesn't necessarily equal the client
|
|
172
|
+
// that registered the worker. It's with the latter the worker should
|
|
173
|
+
// communicate with during the response resolving phase.
|
|
174
|
+
async function resolveMainClient(event) {
|
|
175
|
+
const client = await self.clients.get(event.clientId)
|
|
176
|
+
|
|
177
|
+
if (client?.frameType === 'top-level') {
|
|
178
|
+
return client
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const allClients = await self.clients.matchAll({
|
|
182
|
+
type: 'window',
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
return allClients
|
|
186
|
+
.filter((client) => {
|
|
187
|
+
// Get only those clients that are currently visible.
|
|
188
|
+
return client.visibilityState === 'visible'
|
|
189
|
+
})
|
|
190
|
+
.find((client) => {
|
|
191
|
+
// Find the client ID that's recorded in the
|
|
192
|
+
// set of clients that have registered the worker.
|
|
193
|
+
return activeClientIds.has(client.id)
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
|
|
141
197
|
async function getResponse(event, client, requestId) {
|
|
142
198
|
const { request } = event
|
|
143
|
-
const
|
|
144
|
-
|
|
199
|
+
const clonedRequest = request.clone()
|
|
200
|
+
|
|
201
|
+
function passthrough() {
|
|
202
|
+
// Clone the request because it might've been already used
|
|
203
|
+
// (i.e. its body has been read and sent to the client).
|
|
204
|
+
const headers = Object.fromEntries(clonedRequest.headers.entries())
|
|
205
|
+
|
|
206
|
+
// Remove MSW-specific request headers so the bypassed requests
|
|
207
|
+
// comply with the server's CORS preflight check.
|
|
208
|
+
// Operate with the headers as an object because request "Headers"
|
|
209
|
+
// are immutable.
|
|
210
|
+
delete headers['x-msw-bypass']
|
|
145
211
|
|
|
146
|
-
|
|
212
|
+
return fetch(clonedRequest, { headers })
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Bypass mocking when the client is not active.
|
|
147
216
|
if (!client) {
|
|
148
|
-
return
|
|
217
|
+
return passthrough()
|
|
149
218
|
}
|
|
150
219
|
|
|
151
220
|
// Bypass initial page load requests (i.e. static assets).
|
|
@@ -153,34 +222,23 @@ async function getResponse(event, client, requestId) {
|
|
|
153
222
|
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
|
|
154
223
|
// and is not ready to handle requests.
|
|
155
224
|
if (!activeClientIds.has(client.id)) {
|
|
156
|
-
return
|
|
225
|
+
return passthrough()
|
|
157
226
|
}
|
|
158
227
|
|
|
159
|
-
// Bypass requests with the explicit bypass header
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
// Remove the bypass header to comply with the CORS preflight check.
|
|
164
|
-
delete cleanRequestHeaders[bypassHeaderName]
|
|
165
|
-
|
|
166
|
-
const originalRequest = new Request(requestClone, {
|
|
167
|
-
headers: new Headers(cleanRequestHeaders),
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
return fetch(originalRequest)
|
|
228
|
+
// Bypass requests with the explicit bypass header.
|
|
229
|
+
// Such requests can be issued by "ctx.fetch()".
|
|
230
|
+
if (request.headers.get('x-msw-bypass') === 'true') {
|
|
231
|
+
return passthrough()
|
|
171
232
|
}
|
|
172
233
|
|
|
173
|
-
//
|
|
174
|
-
const reqHeaders = serializeHeaders(request.headers)
|
|
175
|
-
const body = await request.text()
|
|
176
|
-
|
|
234
|
+
// Notify the client that a request has been intercepted.
|
|
177
235
|
const clientMessage = await sendToClient(client, {
|
|
178
236
|
type: 'REQUEST',
|
|
179
237
|
payload: {
|
|
180
238
|
id: requestId,
|
|
181
239
|
url: request.url,
|
|
182
240
|
method: request.method,
|
|
183
|
-
headers:
|
|
241
|
+
headers: Object.fromEntries(request.headers.entries()),
|
|
184
242
|
cache: request.cache,
|
|
185
243
|
mode: request.mode,
|
|
186
244
|
credentials: request.credentials,
|
|
@@ -189,115 +247,32 @@ async function getResponse(event, client, requestId) {
|
|
|
189
247
|
redirect: request.redirect,
|
|
190
248
|
referrer: request.referrer,
|
|
191
249
|
referrerPolicy: request.referrerPolicy,
|
|
192
|
-
body,
|
|
250
|
+
body: await request.text(),
|
|
193
251
|
bodyUsed: request.bodyUsed,
|
|
194
252
|
keepalive: request.keepalive,
|
|
195
253
|
},
|
|
196
254
|
})
|
|
197
255
|
|
|
198
256
|
switch (clientMessage.type) {
|
|
199
|
-
case '
|
|
200
|
-
return
|
|
201
|
-
() => respondWithMock(clientMessage),
|
|
202
|
-
clientMessage.payload.delay,
|
|
203
|
-
)
|
|
257
|
+
case 'MOCK_RESPONSE': {
|
|
258
|
+
return respondWithMock(clientMessage.data)
|
|
204
259
|
}
|
|
205
260
|
|
|
206
261
|
case 'MOCK_NOT_FOUND': {
|
|
207
|
-
return
|
|
262
|
+
return passthrough()
|
|
208
263
|
}
|
|
209
264
|
|
|
210
265
|
case 'NETWORK_ERROR': {
|
|
211
|
-
const { name, message } = clientMessage.
|
|
266
|
+
const { name, message } = clientMessage.data
|
|
212
267
|
const networkError = new Error(message)
|
|
213
268
|
networkError.name = name
|
|
214
269
|
|
|
215
|
-
// Rejecting a
|
|
270
|
+
// Rejecting a "respondWith" promise emulates a network error.
|
|
216
271
|
throw networkError
|
|
217
272
|
}
|
|
218
|
-
|
|
219
|
-
case 'INTERNAL_ERROR': {
|
|
220
|
-
const parsedBody = JSON.parse(clientMessage.payload.body)
|
|
221
|
-
|
|
222
|
-
console.error(
|
|
223
|
-
`\
|
|
224
|
-
[MSW] Uncaught exception in the request handler for "%s %s":
|
|
225
|
-
|
|
226
|
-
${parsedBody.location}
|
|
227
|
-
|
|
228
|
-
This exception has been gracefully handled as a 500 response, however, it's strongly recommended to resolve this error, as it indicates a mistake in your code. If you wish to mock an error response, please see this guide: https://mswjs.io/docs/recipes/mocking-error-responses\
|
|
229
|
-
`,
|
|
230
|
-
request.method,
|
|
231
|
-
request.url,
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
return respondWithMock(clientMessage)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return getOriginalResponse()
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
self.addEventListener('fetch', function (event) {
|
|
242
|
-
const { request } = event
|
|
243
|
-
const accept = request.headers.get('accept') || ''
|
|
244
|
-
|
|
245
|
-
// Bypass server-sent events.
|
|
246
|
-
if (accept.includes('text/event-stream')) {
|
|
247
|
-
return
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Bypass navigation requests.
|
|
251
|
-
if (request.mode === 'navigate') {
|
|
252
|
-
return
|
|
253
273
|
}
|
|
254
274
|
|
|
255
|
-
|
|
256
|
-
// that cannot be handled by the worker. Bypass such requests.
|
|
257
|
-
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
|
|
258
|
-
return
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Bypass all requests when there are no active clients.
|
|
262
|
-
// Prevents the self-unregistered worked from handling requests
|
|
263
|
-
// after it's been deleted (still remains active until the next reload).
|
|
264
|
-
if (activeClientIds.size === 0) {
|
|
265
|
-
return
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const requestId = uuidv4()
|
|
269
|
-
|
|
270
|
-
return event.respondWith(
|
|
271
|
-
handleRequest(event, requestId).catch((error) => {
|
|
272
|
-
if (error.name === 'NetworkError') {
|
|
273
|
-
console.warn(
|
|
274
|
-
'[MSW] Successfully emulated a network error for the "%s %s" request.',
|
|
275
|
-
request.method,
|
|
276
|
-
request.url,
|
|
277
|
-
)
|
|
278
|
-
return
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// At this point, any exception indicates an issue with the original request/response.
|
|
282
|
-
console.error(
|
|
283
|
-
`\
|
|
284
|
-
[MSW] Caught an exception from the "%s %s" request (%s). This is probably not a problem with Mock Service Worker. There is likely an additional logging output above.`,
|
|
285
|
-
request.method,
|
|
286
|
-
request.url,
|
|
287
|
-
`${error.name}: ${error.message}`,
|
|
288
|
-
)
|
|
289
|
-
}),
|
|
290
|
-
)
|
|
291
|
-
})
|
|
292
|
-
|
|
293
|
-
function serializeHeaders(headers) {
|
|
294
|
-
const reqHeaders = {}
|
|
295
|
-
headers.forEach((value, name) => {
|
|
296
|
-
reqHeaders[name] = reqHeaders[name]
|
|
297
|
-
? [].concat(reqHeaders[name]).concat(value)
|
|
298
|
-
: value
|
|
299
|
-
})
|
|
300
|
-
return reqHeaders
|
|
275
|
+
return passthrough()
|
|
301
276
|
}
|
|
302
277
|
|
|
303
278
|
function sendToClient(client, message) {
|
|
@@ -312,27 +287,17 @@ function sendToClient(client, message) {
|
|
|
312
287
|
resolve(event.data)
|
|
313
288
|
}
|
|
314
289
|
|
|
315
|
-
client.postMessage(
|
|
290
|
+
client.postMessage(message, [channel.port2])
|
|
316
291
|
})
|
|
317
292
|
}
|
|
318
293
|
|
|
319
|
-
function
|
|
294
|
+
function sleep(timeMs) {
|
|
320
295
|
return new Promise((resolve) => {
|
|
321
|
-
setTimeout(
|
|
296
|
+
setTimeout(resolve, timeMs)
|
|
322
297
|
})
|
|
323
298
|
}
|
|
324
299
|
|
|
325
|
-
function respondWithMock(
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
headers: clientMessage.payload.headers,
|
|
329
|
-
})
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function uuidv4() {
|
|
333
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
334
|
-
const r = (Math.random() * 16) | 0
|
|
335
|
-
const v = c == 'x' ? r : (r & 0x3) | 0x8
|
|
336
|
-
return v.toString(16)
|
|
337
|
-
})
|
|
300
|
+
async function respondWithMock(response) {
|
|
301
|
+
await sleep(response.delay)
|
|
302
|
+
return new Response(response.body, response)
|
|
338
303
|
}
|