@bagaar/ember-graphql-mocking 0.4.0 → 0.6.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 +40 -0
- package/README.md +26 -11
- package/addon-test-support/index.js +12 -10
- package/package.json +29 -30
- package/public/mockServiceWorker.js +121 -156
- package/.husky/commit-msg +0 -4
- package/RELEASE.md +0 -60
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## v0.6.0 (2022-09-05)
|
|
7
|
+
|
|
8
|
+
#### :boom: Breaking Change
|
|
9
|
+
* [#38](https://github.com/Bagaar/ember-graphql-mocking/pull/38) Make `setupEmberGraphqlMocking` async ([@bertdeblock](https://github.com/bertdeblock))
|
|
10
|
+
* [#37](https://github.com/Bagaar/ember-graphql-mocking/pull/37) Update `graphql` and `msw` dependencies ([@bertdeblock](https://github.com/bertdeblock))
|
|
11
|
+
* [#34](https://github.com/Bagaar/ember-graphql-mocking/pull/34) Update `msw` to v0.43.0 ([@bertdeblock](https://github.com/bertdeblock))
|
|
12
|
+
|
|
13
|
+
#### :bug: Bug Fix
|
|
14
|
+
* [#38](https://github.com/Bagaar/ember-graphql-mocking/pull/38) Make `setupEmberGraphqlMocking` async ([@bertdeblock](https://github.com/bertdeblock))
|
|
15
|
+
|
|
16
|
+
#### Committers: 1
|
|
17
|
+
- Bert De Block ([@bertdeblock](https://github.com/bertdeblock))
|
|
18
|
+
|
|
19
|
+
## v0.5.0 (2022-06-24)
|
|
20
|
+
|
|
21
|
+
#### :boom: Breaking Change
|
|
22
|
+
* [#29](https://github.com/Bagaar/ember-graphql-mocking/pull/29) Update `msw` to v0.42.3 ([@bertdeblock](https://github.com/bertdeblock))
|
|
23
|
+
* [#27](https://github.com/Bagaar/ember-graphql-mocking/pull/27) Drop support for Ember v3.24 ([@bertdeblock](https://github.com/bertdeblock))
|
|
24
|
+
* [#26](https://github.com/Bagaar/ember-graphql-mocking/pull/26) Drop support for Node v12 ([@bertdeblock](https://github.com/bertdeblock))
|
|
25
|
+
|
|
26
|
+
#### Committers: 1
|
|
27
|
+
- Bert De Block ([@bertdeblock](https://github.com/bertdeblock))
|
|
28
|
+
|
|
29
|
+
## v0.4.1 (2022-02-09)
|
|
30
|
+
|
|
31
|
+
#### :bug: Bug Fix
|
|
32
|
+
* [#24](https://github.com/Bagaar/ember-graphql-mocking/pull/24) Don't automatically stop the worker when all tests are done (fix compat with `ember-cli-code-coverage@v1`) ([@bertdeblock](https://github.com/bertdeblock))
|
|
33
|
+
|
|
34
|
+
#### :memo: Documentation
|
|
35
|
+
* [#19](https://github.com/Bagaar/ember-graphql-mocking/pull/19) Fix install command in docs ([@bertdeblock](https://github.com/bertdeblock))
|
|
36
|
+
|
|
37
|
+
#### :house: Internal
|
|
38
|
+
* [#22](https://github.com/Bagaar/ember-graphql-mocking/pull/22) Don't publish `.husky` folder and `RELEASE.md` file ([@bertdeblock](https://github.com/bertdeblock))
|
|
39
|
+
|
|
40
|
+
#### Committers: 1
|
|
41
|
+
- Bert De Block ([@bertdeblock](https://github.com/bertdeblock))
|
|
42
|
+
|
|
3
43
|
## v0.4.0 (2022-02-03)
|
|
4
44
|
|
|
5
45
|
#### :rocket: Enhancement
|
package/README.md
CHANGED
|
@@ -6,18 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
Ember addon for mocking GraphQL requests using [Mock Service Worker (MSW)](https://github.com/mswjs/msw).
|
|
8
8
|
|
|
9
|
-
> :warning: Experimental mocking package used at Bagaar. You probably shouldn't use this for now.
|
|
10
|
-
|
|
11
9
|
## Compatibility
|
|
12
10
|
|
|
13
|
-
- Ember.js v3.
|
|
14
|
-
- Ember CLI v3.
|
|
15
|
-
- Node.js
|
|
11
|
+
- Ember.js v3.28 or above
|
|
12
|
+
- Ember CLI v3.28 or above
|
|
13
|
+
- Node.js v14 or above
|
|
16
14
|
|
|
17
15
|
## Installation
|
|
18
16
|
|
|
19
17
|
```shell
|
|
20
|
-
ember install bagaar/ember-graphql-mocking
|
|
18
|
+
ember install @bagaar/ember-graphql-mocking
|
|
21
19
|
```
|
|
22
20
|
|
|
23
21
|
## Usage
|
|
@@ -27,7 +25,7 @@ ember install bagaar/ember-graphql-mocking#v0.1.1
|
|
|
27
25
|
In `tests/test-helper.js`:
|
|
28
26
|
1. Import `setupEmberGraphqlMocking`
|
|
29
27
|
2. Import your GraphQL schema
|
|
30
|
-
3. Call `setupEmberGraphqlMocking` with your GraphQL schema
|
|
28
|
+
3. Call `setupEmberGraphqlMocking` with your GraphQL schema
|
|
31
29
|
|
|
32
30
|
```javascript
|
|
33
31
|
// tests/test-helper.js
|
|
@@ -41,15 +39,30 @@ import { start } from 'ember-qunit';
|
|
|
41
39
|
import { setupEmberGraphqlMocking } from '@bagaar/ember-graphql-mocking/test-support'; // 1.
|
|
42
40
|
import schema from 'my-app/graphql/schema'; // 2.
|
|
43
41
|
|
|
42
|
+
QUnit.begin(() => setupEmberGraphqlMocking(schema)); // 3.
|
|
43
|
+
|
|
44
44
|
setApplication(Application.create(config.APP));
|
|
45
45
|
|
|
46
46
|
setup(QUnit.assert);
|
|
47
47
|
|
|
48
|
-
setupEmberGraphqlMocking(schema); // 3.
|
|
49
|
-
|
|
50
48
|
start();
|
|
51
49
|
```
|
|
52
50
|
|
|
51
|
+
> **NOTE:** Make sure to use `QUnit.begin`, as `setupEmberGraphqlMocking` returns a Promise.
|
|
52
|
+
|
|
53
|
+
If you want to pass along additional [start options](https://mswjs.io/docs/api/setup-worker/start#options)
|
|
54
|
+
to MSW's service worker, you can do so by defining an `mswStartOptions` object:
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
QUnit.begin(() =>
|
|
58
|
+
setupEmberGraphqlMocking(schema, {
|
|
59
|
+
mswStartOptions: {
|
|
60
|
+
// Additional MSW start options...
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
```
|
|
65
|
+
|
|
53
66
|
### 2. Write an Acceptance Test
|
|
54
67
|
|
|
55
68
|
1. Import `mockResolvers` and `setupGraphqlTest`
|
|
@@ -60,14 +73,14 @@ start();
|
|
|
60
73
|
|
|
61
74
|
`mockResolvers` accepts an object that consists of one or more resolvers. The key must be the name of the mocked operation, the value can either be a response object _or_ a function that returns a response object.
|
|
62
75
|
|
|
63
|
-
> **NOTE:** Make sure that your operations are named in order for `@bagaar/ember-graphql-mocking` to function properly.
|
|
76
|
+
> **NOTE:** Make sure that your operations are [named](https://graphql.org/learn/queries/#operation-name) in order for `@bagaar/ember-graphql-mocking` to function properly.
|
|
64
77
|
|
|
65
78
|
```javascript
|
|
66
79
|
// tests/acceptance/my-acceptance-test.js
|
|
67
80
|
|
|
68
81
|
import { module, test } from 'qunit';
|
|
69
82
|
import { visit, currentURL } from '@ember/test-helpers';
|
|
70
|
-
import { setupApplicationTest } from '
|
|
83
|
+
import { setupApplicationTest } from 'my-app/tests/helpers';
|
|
71
84
|
import { mockResolvers, setupGraphqlTest } from '@bagaar/ember-graphql-mocking/test-support'; // 1.
|
|
72
85
|
|
|
73
86
|
module('Acceptance | ember graphql mocking', function (hooks) {
|
|
@@ -94,6 +107,8 @@ module('Acceptance | ember graphql mocking', function (hooks) {
|
|
|
94
107
|
});
|
|
95
108
|
```
|
|
96
109
|
|
|
110
|
+
> **NOTE:** Calling `mockResolvers` multiple times within a single test, will simply merge all resolvers into a single root.
|
|
111
|
+
|
|
97
112
|
💡 Working versions of these code examples can be found in [this addon's `tests` folder](./tests/).
|
|
98
113
|
|
|
99
114
|
## Contributing
|
|
@@ -2,7 +2,6 @@ import { assert } from '@ember/debug';
|
|
|
2
2
|
import { buildASTSchema, graphql } from 'graphql';
|
|
3
3
|
import merge from 'lodash.merge';
|
|
4
4
|
import { graphql as mswGraphql, setupWorker } from 'msw';
|
|
5
|
-
import { done as qunitDone } from 'qunit';
|
|
6
5
|
|
|
7
6
|
const IS_TESTEM = Boolean(window.Testem);
|
|
8
7
|
const DEFAULT_OPTIONS = {
|
|
@@ -23,9 +22,10 @@ let worker = null;
|
|
|
23
22
|
export function setupEmberGraphqlMocking(schemaDocument, providedOptions) {
|
|
24
23
|
const options = merge({}, DEFAULT_OPTIONS, providedOptions);
|
|
25
24
|
|
|
26
|
-
createWorker(
|
|
25
|
+
createWorker();
|
|
27
26
|
createGraphqlOperationHandler(schemaDocument);
|
|
28
|
-
|
|
27
|
+
|
|
28
|
+
return startWorker(options.mswStartOptions);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export function setupGraphqlTest(hooks) {
|
|
@@ -47,18 +47,16 @@ export function getWorker() {
|
|
|
47
47
|
return worker;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
function
|
|
51
|
-
worker = setupWorker();
|
|
52
|
-
|
|
53
|
-
worker.start(options.mswStartOptions);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function destroyWorker() {
|
|
50
|
+
export function destroyWorker() {
|
|
57
51
|
worker.stop();
|
|
58
52
|
|
|
59
53
|
worker = null;
|
|
60
54
|
}
|
|
61
55
|
|
|
56
|
+
function createWorker() {
|
|
57
|
+
worker = setupWorker();
|
|
58
|
+
}
|
|
59
|
+
|
|
62
60
|
function createGraphqlOperationHandler(schemaDocument) {
|
|
63
61
|
const schema = buildASTSchema(schemaDocument);
|
|
64
62
|
const graphqlOperation = mswGraphql.operation(async (req, res, ctx) => {
|
|
@@ -75,6 +73,10 @@ function createGraphqlOperationHandler(schemaDocument) {
|
|
|
75
73
|
worker.use(graphqlOperation);
|
|
76
74
|
}
|
|
77
75
|
|
|
76
|
+
function startWorker(mswStartOptions) {
|
|
77
|
+
return worker.start(mswStartOptions);
|
|
78
|
+
}
|
|
79
|
+
|
|
78
80
|
function clearRoot() {
|
|
79
81
|
root = null;
|
|
80
82
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bagaar/ember-graphql-mocking",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Ember addon for mocking GraphQL requests using Mock Service Worker (MSW).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ember-addon"
|
|
@@ -34,58 +34,57 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"broccoli-funnel": "^3.0.5",
|
|
36
36
|
"broccoli-merge-trees": "^4.2.0",
|
|
37
|
-
"ember-auto-import": "^2.2
|
|
37
|
+
"ember-auto-import": "^2.4.2",
|
|
38
38
|
"ember-cli-babel": "^7.26.11",
|
|
39
|
-
"graphql": "^16.
|
|
39
|
+
"graphql": "^16.6.0",
|
|
40
40
|
"lodash.merge": "^4.6.2",
|
|
41
|
-
"msw": "0.
|
|
42
|
-
"qunit": "^2.17.2"
|
|
41
|
+
"msw": "^0.47.0"
|
|
43
42
|
},
|
|
44
43
|
"devDependencies": {
|
|
45
|
-
"@commitlint/cli": "^
|
|
46
|
-
"@commitlint/config-conventional": "^
|
|
44
|
+
"@commitlint/cli": "^17.1.2",
|
|
45
|
+
"@commitlint/config-conventional": "^17.1.0",
|
|
47
46
|
"@ember/optional-features": "^2.0.0",
|
|
48
|
-
"@ember/test-helpers": "^2.
|
|
49
|
-
"@embroider/test-setup": "^1.
|
|
50
|
-
"@glimmer/component": "^1.
|
|
51
|
-
"@glimmer/tracking": "^1.
|
|
47
|
+
"@ember/test-helpers": "^2.8.1",
|
|
48
|
+
"@embroider/test-setup": "^1.8.3",
|
|
49
|
+
"@glimmer/component": "^1.1.2",
|
|
50
|
+
"@glimmer/tracking": "^1.1.2",
|
|
51
|
+
"@release-it-plugins/lerna-changelog": "^5.0.0",
|
|
52
52
|
"babel-eslint": "^10.1.0",
|
|
53
53
|
"broccoli-asset-rev": "^3.0.0",
|
|
54
|
-
"ember-apollo-client": "^
|
|
55
|
-
"ember-cli": "~4.
|
|
56
|
-
"ember-cli-dependency-checker": "^3.
|
|
57
|
-
"ember-cli-htmlbars": "^6.0
|
|
54
|
+
"ember-apollo-client": "^4.1.0",
|
|
55
|
+
"ember-cli": "~4.6.0",
|
|
56
|
+
"ember-cli-dependency-checker": "^3.3.1",
|
|
57
|
+
"ember-cli-htmlbars": "^6.1.0",
|
|
58
58
|
"ember-cli-inject-live-reload": "^2.1.0",
|
|
59
59
|
"ember-cli-sri": "^2.1.1",
|
|
60
60
|
"ember-cli-terser": "^4.0.2",
|
|
61
61
|
"ember-disable-prototype-extensions": "^1.1.3",
|
|
62
|
-
"ember-
|
|
63
|
-
"ember-fetch": "^8.0.4",
|
|
62
|
+
"ember-fetch": "^8.1.2",
|
|
64
63
|
"ember-load-initializers": "^2.1.2",
|
|
65
64
|
"ember-page-title": "^7.0.0",
|
|
66
65
|
"ember-qunit": "^5.1.5",
|
|
67
66
|
"ember-resolver": "^8.0.3",
|
|
68
|
-
"ember-source": "~4.
|
|
67
|
+
"ember-source": "~4.6.0",
|
|
69
68
|
"ember-source-channel-url": "^3.0.0",
|
|
70
|
-
"ember-template-lint": "^4.
|
|
69
|
+
"ember-template-lint": "^4.14.0",
|
|
71
70
|
"ember-try": "^2.0.0",
|
|
72
71
|
"eslint": "^7.32.0",
|
|
73
|
-
"eslint-config-prettier": "^8.
|
|
74
|
-
"eslint-plugin-ember": "^
|
|
72
|
+
"eslint-config-prettier": "^8.5.0",
|
|
73
|
+
"eslint-plugin-ember": "^11.0.2",
|
|
75
74
|
"eslint-plugin-node": "^11.1.0",
|
|
76
|
-
"eslint-plugin-prettier": "^4.
|
|
77
|
-
"eslint-plugin-qunit": "^7.
|
|
78
|
-
"husky": "^
|
|
75
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
76
|
+
"eslint-plugin-qunit": "^7.3.1",
|
|
77
|
+
"husky": "^8.0.1",
|
|
79
78
|
"loader.js": "^4.7.0",
|
|
80
79
|
"npm-run-all": "^4.1.5",
|
|
81
|
-
"prettier": "^2.
|
|
80
|
+
"prettier": "^2.7.1",
|
|
81
|
+
"qunit": "^2.19.1",
|
|
82
82
|
"qunit-dom": "^2.0.0",
|
|
83
|
-
"release-it": "^
|
|
84
|
-
"
|
|
85
|
-
"webpack": "^5.65.0"
|
|
83
|
+
"release-it": "^15.4.1",
|
|
84
|
+
"webpack": "^5.74.0"
|
|
86
85
|
},
|
|
87
86
|
"engines": {
|
|
88
|
-
"node": "
|
|
87
|
+
"node": "14.* || >= 16"
|
|
89
88
|
},
|
|
90
89
|
"publishConfig": {
|
|
91
90
|
"access": "public",
|
|
@@ -102,7 +101,7 @@
|
|
|
102
101
|
},
|
|
103
102
|
"release-it": {
|
|
104
103
|
"plugins": {
|
|
105
|
-
"release-it-lerna-changelog": {
|
|
104
|
+
"@release-it-plugins/lerna-changelog": {
|
|
106
105
|
"infile": "CHANGELOG.md",
|
|
107
106
|
"launchEditor": false
|
|
108
107
|
}
|
|
@@ -2,22 +2,21 @@
|
|
|
2
2
|
/* tslint:disable */
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Mock Service Worker (0.
|
|
5
|
+
* Mock Service Worker (0.47.0).
|
|
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 = 'b3066ef78c2f9090b4ce87e874965995'
|
|
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())
|
|
145
205
|
|
|
146
|
-
|
|
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']
|
|
211
|
+
|
|
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
273
|
}
|
|
237
274
|
|
|
238
|
-
return
|
|
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
|
-
}
|
|
254
|
-
|
|
255
|
-
// Opening the DevTools triggers the "only-if-cached" request
|
|
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
|
}
|
package/.husky/commit-msg
DELETED
package/RELEASE.md
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# Release Process
|
|
2
|
-
|
|
3
|
-
Releases are mostly automated using
|
|
4
|
-
[release-it](https://github.com/release-it/release-it/) and
|
|
5
|
-
[lerna-changelog](https://github.com/lerna/lerna-changelog/).
|
|
6
|
-
|
|
7
|
-
## Preparation
|
|
8
|
-
|
|
9
|
-
Since the majority of the actual release process is automated, the primary
|
|
10
|
-
remaining task prior to releasing is confirming that all pull requests that
|
|
11
|
-
have been merged since the last release have been labeled with the appropriate
|
|
12
|
-
`lerna-changelog` labels and the titles have been updated to ensure they
|
|
13
|
-
represent something that would make sense to our users. Some great information
|
|
14
|
-
on why this is important can be found at
|
|
15
|
-
[keepachangelog.com](https://keepachangelog.com/en/1.0.0/), but the overall
|
|
16
|
-
guiding principle here is that changelogs are for humans, not machines.
|
|
17
|
-
|
|
18
|
-
When reviewing merged PR's the labels to be used are:
|
|
19
|
-
|
|
20
|
-
* breaking - Used when the PR is considered a breaking change.
|
|
21
|
-
* enhancement - Used when the PR adds a new feature or enhancement.
|
|
22
|
-
* bug - Used when the PR fixes a bug included in a previous release.
|
|
23
|
-
* documentation - Used when the PR adds or updates documentation.
|
|
24
|
-
* internal - Used for internal changes that still require a mention in the
|
|
25
|
-
changelog/release notes.
|
|
26
|
-
|
|
27
|
-
## Release
|
|
28
|
-
|
|
29
|
-
Once the prep work is completed, the actual release is straight forward:
|
|
30
|
-
|
|
31
|
-
* First, ensure that you have installed your projects dependencies:
|
|
32
|
-
|
|
33
|
-
```sh
|
|
34
|
-
yarn install
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
* Second, ensure that you have obtained a
|
|
38
|
-
[GitHub personal access token][generate-token] with the `repo` scope (no
|
|
39
|
-
other permissions are needed). Make sure the token is available as the
|
|
40
|
-
`GITHUB_AUTH` environment variable.
|
|
41
|
-
|
|
42
|
-
For instance:
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
export GITHUB_AUTH=abc123def456
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
[generate-token]: https://github.com/settings/tokens/new?scopes=repo&description=GITHUB_AUTH+env+variable
|
|
49
|
-
|
|
50
|
-
* And last (but not least 😁) do your release.
|
|
51
|
-
|
|
52
|
-
```sh
|
|
53
|
-
npx release-it
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
[release-it](https://github.com/release-it/release-it/) manages the actual
|
|
57
|
-
release process. It will prompt you to to choose the version number after which
|
|
58
|
-
you will have the chance to hand tweak the changelog to be used (for the
|
|
59
|
-
`CHANGELOG.md` and GitHub release), then `release-it` continues on to tagging,
|
|
60
|
-
pushing the tag and commits, etc.
|