@wordpress/api-fetch 7.29.1-next.e256d081a.0 → 7.30.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 +2 -0
- package/build/index.js +28 -20
- package/build/index.js.map +1 -1
- package/build/middlewares/media-upload.js +1 -1
- package/build/middlewares/media-upload.js.map +1 -1
- package/build/utils/response.js +24 -43
- package/build/utils/response.js.map +1 -1
- package/build-module/index.js +28 -20
- package/build-module/index.js.map +1 -1
- package/build-module/middlewares/media-upload.js +1 -1
- package/build-module/middlewares/media-upload.js.map +1 -1
- package/build-module/utils/response.js +23 -41
- package/build-module/utils/response.js.map +1 -1
- package/build-types/index.d.ts.map +1 -1
- package/build-types/utils/response.d.ts +3 -3
- package/build-types/utils/response.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +35 -29
- package/src/middlewares/media-upload.ts +3 -3
- package/src/test/index.js +218 -147
- package/src/utils/response.ts +25 -49
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @return Parsed response.
|
|
8
8
|
*/
|
|
9
|
-
export declare
|
|
9
|
+
export declare function parseResponseAndNormalizeError(response: Response, shouldParseResponse?: boolean): Promise<any>;
|
|
10
10
|
/**
|
|
11
11
|
* Parses a response, throwing an error if parsing the response fails.
|
|
12
12
|
*
|
|
13
13
|
* @param response
|
|
14
14
|
* @param shouldParseResponse
|
|
15
|
-
* @return
|
|
15
|
+
* @return Never returns, always throws.
|
|
16
16
|
*/
|
|
17
|
-
export declare function parseAndThrowError(response: Response, shouldParseResponse?: boolean): Promise<
|
|
17
|
+
export declare function parseAndThrowError(response: Response, shouldParseResponse?: boolean): Promise<void>;
|
|
18
18
|
//# sourceMappingURL=response.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/utils/response.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/utils/response.ts"],"names":[],"mappings":"AAuBA;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CACnD,QAAQ,EAAE,QAAQ,EAClB,mBAAmB,UAAO,gBAW1B;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACvC,QAAQ,EAAE,QAAQ,EAClB,mBAAmB,UAAO,iBAQ1B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/api-fetch",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.30.0",
|
|
4
4
|
"description": "Utility to make WordPress REST API requests.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
"types": "build-types",
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@babel/runtime": "7.25.7",
|
|
33
|
-
"@wordpress/i18n": "^6.
|
|
34
|
-
"@wordpress/url": "^4.
|
|
33
|
+
"@wordpress/i18n": "^6.3.0",
|
|
34
|
+
"@wordpress/url": "^4.30.0"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "c66cb089eed19d4f4956962fa7b4c81abe6dd513"
|
|
40
40
|
}
|
package/src/index.ts
CHANGED
|
@@ -61,21 +61,6 @@ function registerMiddleware( middleware: APIFetchMiddleware ) {
|
|
|
61
61
|
middlewares.unshift( middleware );
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/**
|
|
65
|
-
* Checks the status of a response, throwing the Response as an error if
|
|
66
|
-
* it is outside the 200 range.
|
|
67
|
-
*
|
|
68
|
-
* @param response
|
|
69
|
-
* @return The response if the status is in the 200 range.
|
|
70
|
-
*/
|
|
71
|
-
const checkStatus = ( response: Response ) => {
|
|
72
|
-
if ( response.status >= 200 && response.status < 300 ) {
|
|
73
|
-
return response;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
throw response;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
64
|
const defaultFetchHandler: FetchHandler = ( nextOptions ) => {
|
|
80
65
|
const { url, path, data, parse = true, ...remainingOptions } = nextOptions;
|
|
81
66
|
let { body, headers } = nextOptions;
|
|
@@ -89,7 +74,7 @@ const defaultFetchHandler: FetchHandler = ( nextOptions ) => {
|
|
|
89
74
|
headers[ 'Content-Type' ] = 'application/json';
|
|
90
75
|
}
|
|
91
76
|
|
|
92
|
-
const responsePromise =
|
|
77
|
+
const responsePromise = globalThis.fetch(
|
|
93
78
|
// Fall back to explicitly passing `window.location` which is the behavior if `undefined` is passed.
|
|
94
79
|
url || path || window.location.href,
|
|
95
80
|
{
|
|
@@ -101,24 +86,38 @@ const defaultFetchHandler: FetchHandler = ( nextOptions ) => {
|
|
|
101
86
|
);
|
|
102
87
|
|
|
103
88
|
return responsePromise.then(
|
|
104
|
-
(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
89
|
+
( response ) => {
|
|
90
|
+
// If the response is not 2xx, still parse the response body as JSON
|
|
91
|
+
// but throw the JSON as error.
|
|
92
|
+
if ( ! response.ok ) {
|
|
93
|
+
return parseAndThrowError( response, parse );
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return parseResponseAndNormalizeError( response, parse );
|
|
97
|
+
},
|
|
111
98
|
( err ) => {
|
|
112
99
|
// Re-throw AbortError for the users to handle it themselves.
|
|
113
100
|
if ( err && err.name === 'AbortError' ) {
|
|
114
101
|
throw err;
|
|
115
102
|
}
|
|
116
103
|
|
|
117
|
-
//
|
|
118
|
-
//
|
|
104
|
+
// If the browser reports being offline, we'll just assume that
|
|
105
|
+
// this is why the request failed.
|
|
106
|
+
if ( ! globalThis.navigator.onLine ) {
|
|
107
|
+
throw {
|
|
108
|
+
code: 'offline_error',
|
|
109
|
+
message: __(
|
|
110
|
+
'Unable to connect. Please check your Internet connection.'
|
|
111
|
+
),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Hard to diagnose further due to how Window.fetch reports errors.
|
|
119
116
|
throw {
|
|
120
117
|
code: 'fetch_error',
|
|
121
|
-
message: __(
|
|
118
|
+
message: __(
|
|
119
|
+
'Could not get a valid response from the server.'
|
|
120
|
+
),
|
|
122
121
|
};
|
|
123
122
|
}
|
|
124
123
|
);
|
|
@@ -177,10 +176,17 @@ const apiFetch: apiFetch = ( options ) => {
|
|
|
177
176
|
}
|
|
178
177
|
|
|
179
178
|
// If the nonce is invalid, refresh it and try again.
|
|
180
|
-
return
|
|
179
|
+
return globalThis
|
|
181
180
|
.fetch( apiFetch.nonceEndpoint! )
|
|
182
|
-
.then(
|
|
183
|
-
|
|
181
|
+
.then( ( response ) => {
|
|
182
|
+
// If the nonce refresh fails, it means we failed to recover from the original
|
|
183
|
+
// `rest_cookie_invalid_nonce` error and that it's time to finally re-throw it.
|
|
184
|
+
if ( ! response.ok ) {
|
|
185
|
+
return Promise.reject( error );
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return response.text();
|
|
189
|
+
} )
|
|
184
190
|
.then( ( text ) => {
|
|
185
191
|
apiFetch.nonceMiddleware!.nonce = text;
|
|
186
192
|
return apiFetch( options );
|
|
@@ -63,9 +63,9 @@ const mediaUploadMiddleware: APIFetchMiddleware = ( options, next ) => {
|
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
return next( { ...options, parse: false } )
|
|
66
|
-
.catch( ( response ) => {
|
|
66
|
+
.catch( ( response: Response ) => {
|
|
67
67
|
// `response` could actually be an error thrown by `defaultFetchHandler`.
|
|
68
|
-
if ( ! response.
|
|
68
|
+
if ( ! ( response instanceof globalThis.Response ) ) {
|
|
69
69
|
return Promise.reject( response );
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -92,7 +92,7 @@ const mediaUploadMiddleware: APIFetchMiddleware = ( options, next ) => {
|
|
|
92
92
|
}
|
|
93
93
|
return parseAndThrowError( response, options.parse );
|
|
94
94
|
} )
|
|
95
|
-
.then( ( response ) =>
|
|
95
|
+
.then( ( response: Response ) =>
|
|
96
96
|
parseResponseAndNormalizeError( response, options.parse )
|
|
97
97
|
);
|
|
98
98
|
};
|
package/src/test/index.js
CHANGED
|
@@ -1,56 +1,57 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*/
|
|
4
|
-
import apiFetch from '../';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Mock return value for a successful fetch JSON return value.
|
|
2
|
+
* Mock response value for a successful fetch.
|
|
8
3
|
*
|
|
9
|
-
* @return {
|
|
4
|
+
* @return {Response} Mock return value.
|
|
10
5
|
*/
|
|
11
|
-
const DEFAULT_FETCH_MOCK_RETURN =
|
|
6
|
+
const DEFAULT_FETCH_MOCK_RETURN = {
|
|
7
|
+
ok: true,
|
|
12
8
|
status: 200,
|
|
13
9
|
json: () => Promise.resolve( {} ),
|
|
14
|
-
}
|
|
10
|
+
};
|
|
15
11
|
|
|
16
12
|
describe( 'apiFetch', () => {
|
|
17
|
-
|
|
13
|
+
let apiFetch;
|
|
14
|
+
const originalFetch = globalThis.fetch;
|
|
15
|
+
|
|
16
|
+
beforeEach( async () => {
|
|
17
|
+
// Reset the `apiFetch` module before each test to clear
|
|
18
|
+
// internal variables (middlewares, fetch handler, etc.).
|
|
19
|
+
jest.resetModules();
|
|
20
|
+
apiFetch = ( await import( '../' ) ).default;
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
window.fetch = jest.fn();
|
|
22
|
+
globalThis.fetch = jest.fn();
|
|
21
23
|
} );
|
|
22
24
|
|
|
23
25
|
afterAll( () => {
|
|
24
|
-
|
|
26
|
+
globalThis.fetch = originalFetch;
|
|
25
27
|
} );
|
|
26
28
|
|
|
27
|
-
it( 'should call the API properly', () => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
);
|
|
29
|
+
it( 'should call the API properly', async () => {
|
|
30
|
+
globalThis.fetch.mockResolvedValue( {
|
|
31
|
+
ok: true,
|
|
32
|
+
status: 200,
|
|
33
|
+
async json() {
|
|
34
|
+
return { message: 'ok' };
|
|
35
|
+
},
|
|
36
|
+
} );
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
await expect( apiFetch( { path: '/random' } ) ).resolves.toEqual( {
|
|
39
|
+
message: 'ok',
|
|
39
40
|
} );
|
|
40
41
|
} );
|
|
41
42
|
|
|
42
|
-
it( 'should fetch with non-JSON body', () => {
|
|
43
|
-
|
|
43
|
+
it( 'should fetch with non-JSON body', async () => {
|
|
44
|
+
globalThis.fetch.mockResolvedValue( DEFAULT_FETCH_MOCK_RETURN );
|
|
44
45
|
|
|
45
46
|
const body = 'FormData';
|
|
46
47
|
|
|
47
|
-
apiFetch( {
|
|
48
|
+
await apiFetch( {
|
|
48
49
|
path: '/wp/v2/media',
|
|
49
50
|
method: 'POST',
|
|
50
51
|
body,
|
|
51
52
|
} );
|
|
52
53
|
|
|
53
|
-
expect(
|
|
54
|
+
expect( globalThis.fetch ).toHaveBeenCalledWith(
|
|
54
55
|
'/wp/v2/media?_locale=user',
|
|
55
56
|
{
|
|
56
57
|
credentials: 'include',
|
|
@@ -63,10 +64,10 @@ describe( 'apiFetch', () => {
|
|
|
63
64
|
);
|
|
64
65
|
} );
|
|
65
66
|
|
|
66
|
-
it( 'should fetch with a JSON body', () => {
|
|
67
|
-
|
|
67
|
+
it( 'should fetch with a JSON body', async () => {
|
|
68
|
+
globalThis.fetch.mockResolvedValue( DEFAULT_FETCH_MOCK_RETURN );
|
|
68
69
|
|
|
69
|
-
apiFetch( {
|
|
70
|
+
await apiFetch( {
|
|
70
71
|
path: '/wp/v2/posts',
|
|
71
72
|
method: 'POST',
|
|
72
73
|
headers: {
|
|
@@ -75,7 +76,7 @@ describe( 'apiFetch', () => {
|
|
|
75
76
|
data: {},
|
|
76
77
|
} );
|
|
77
78
|
|
|
78
|
-
expect(
|
|
79
|
+
expect( globalThis.fetch ).toHaveBeenCalledWith(
|
|
79
80
|
'/wp/v2/posts?_locale=user',
|
|
80
81
|
{
|
|
81
82
|
body: '{}',
|
|
@@ -89,17 +90,17 @@ describe( 'apiFetch', () => {
|
|
|
89
90
|
);
|
|
90
91
|
} );
|
|
91
92
|
|
|
92
|
-
it( 'should respect developer-provided options', () => {
|
|
93
|
-
|
|
93
|
+
it( 'should respect developer-provided options', async () => {
|
|
94
|
+
globalThis.fetch.mockResolvedValue( DEFAULT_FETCH_MOCK_RETURN );
|
|
94
95
|
|
|
95
|
-
apiFetch( {
|
|
96
|
+
await apiFetch( {
|
|
96
97
|
path: '/wp/v2/posts',
|
|
97
98
|
method: 'POST',
|
|
98
99
|
data: {},
|
|
99
100
|
credentials: 'omit',
|
|
100
101
|
} );
|
|
101
102
|
|
|
102
|
-
expect(
|
|
103
|
+
expect( globalThis.fetch ).toHaveBeenCalledWith(
|
|
103
104
|
'/wp/v2/posts?_locale=user',
|
|
104
105
|
{
|
|
105
106
|
body: '{}',
|
|
@@ -113,83 +114,86 @@ describe( 'apiFetch', () => {
|
|
|
113
114
|
);
|
|
114
115
|
} );
|
|
115
116
|
|
|
116
|
-
it( 'should return the error message properly', () => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
);
|
|
117
|
+
it( 'should return the error message properly', async () => {
|
|
118
|
+
globalThis.fetch.mockResolvedValue( {
|
|
119
|
+
ok: false,
|
|
120
|
+
status: 400,
|
|
121
|
+
async json() {
|
|
122
|
+
return {
|
|
123
|
+
code: 'bad_request',
|
|
124
|
+
message: 'Bad Request',
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
} );
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
code: 'bad_request',
|
|
133
|
-
message: 'Bad Request',
|
|
134
|
-
} );
|
|
129
|
+
await expect( apiFetch( { path: '/random' } ) ).rejects.toEqual( {
|
|
130
|
+
code: 'bad_request',
|
|
131
|
+
message: 'Bad Request',
|
|
135
132
|
} );
|
|
136
133
|
} );
|
|
137
134
|
|
|
138
|
-
it( 'should return invalid JSON error if no json response', () => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
135
|
+
it( 'should return invalid JSON error if no json response', async () => {
|
|
136
|
+
globalThis.fetch.mockResolvedValue( {
|
|
137
|
+
ok: true,
|
|
138
|
+
status: 200,
|
|
139
|
+
async json() {
|
|
140
|
+
return JSON.parse( '' );
|
|
141
|
+
},
|
|
142
|
+
} );
|
|
144
143
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
code: 'invalid_json',
|
|
149
|
-
message: 'The response is not a valid JSON response.',
|
|
150
|
-
} );
|
|
144
|
+
await expect( apiFetch( { path: '/random' } ) ).rejects.toEqual( {
|
|
145
|
+
code: 'invalid_json',
|
|
146
|
+
message: 'The response is not a valid JSON response.',
|
|
151
147
|
} );
|
|
152
148
|
} );
|
|
153
149
|
|
|
154
|
-
it( 'should return invalid JSON error if response is not valid', () => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
);
|
|
150
|
+
it( 'should return invalid JSON error if response is not valid', async () => {
|
|
151
|
+
globalThis.fetch.mockResolvedValue( {
|
|
152
|
+
ok: true,
|
|
153
|
+
status: 200,
|
|
154
|
+
async json() {
|
|
155
|
+
return JSON.parse( '' );
|
|
156
|
+
},
|
|
157
|
+
} );
|
|
163
158
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
code: 'invalid_json',
|
|
168
|
-
message: 'The response is not a valid JSON response.',
|
|
169
|
-
} );
|
|
159
|
+
await expect( apiFetch( { path: '/random' } ) ).rejects.toEqual( {
|
|
160
|
+
code: 'invalid_json',
|
|
161
|
+
message: 'The response is not a valid JSON response.',
|
|
170
162
|
} );
|
|
171
163
|
} );
|
|
172
164
|
|
|
173
|
-
it( 'should return offline error when fetch errors', () => {
|
|
174
|
-
|
|
165
|
+
it( 'should return offline error when fetch errors', async () => {
|
|
166
|
+
globalThis.fetch.mockRejectedValue(
|
|
167
|
+
new TypeError( 'Failed to fetch' )
|
|
168
|
+
);
|
|
175
169
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
code: 'fetch_error',
|
|
180
|
-
message: 'You are probably offline.',
|
|
181
|
-
} );
|
|
170
|
+
await expect( apiFetch( { path: '/random' } ) ).rejects.toEqual( {
|
|
171
|
+
code: 'fetch_error',
|
|
172
|
+
message: 'Could not get a valid response from the server.',
|
|
182
173
|
} );
|
|
183
174
|
} );
|
|
184
175
|
|
|
185
176
|
it( 'should throw AbortError when fetch aborts', async () => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
177
|
+
globalThis.fetch.mockImplementation(
|
|
178
|
+
( path, { signal } ) =>
|
|
179
|
+
new Promise( ( _, reject ) => {
|
|
180
|
+
if ( ! signal ) {
|
|
181
|
+
reject( new Error( 'Expected signal as argument' ) );
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
signal.throwIfAborted();
|
|
186
|
+
signal.addEventListener(
|
|
187
|
+
'abort',
|
|
188
|
+
( e ) => {
|
|
189
|
+
reject( e.target.reason );
|
|
190
|
+
},
|
|
191
|
+
{ once: true }
|
|
192
|
+
);
|
|
193
|
+
} )
|
|
194
|
+
);
|
|
191
195
|
|
|
192
|
-
const controller = new
|
|
196
|
+
const controller = new globalThis.AbortController();
|
|
193
197
|
|
|
194
198
|
const promise = apiFetch( {
|
|
195
199
|
path: '/random',
|
|
@@ -198,85 +202,149 @@ describe( 'apiFetch', () => {
|
|
|
198
202
|
|
|
199
203
|
controller.abort();
|
|
200
204
|
|
|
201
|
-
|
|
205
|
+
await expect( promise ).rejects.toMatchObject( {
|
|
206
|
+
name: 'AbortError',
|
|
207
|
+
} );
|
|
208
|
+
} );
|
|
209
|
+
|
|
210
|
+
it( 'should return null if response has no content status code', async () => {
|
|
211
|
+
globalThis.fetch.mockResolvedValue( {
|
|
212
|
+
ok: true,
|
|
213
|
+
status: 204,
|
|
214
|
+
} );
|
|
215
|
+
|
|
216
|
+
await expect( apiFetch( { path: '/random' } ) ).resolves.toBe( null );
|
|
217
|
+
} );
|
|
218
|
+
|
|
219
|
+
it( 'should not try to parse the response', async () => {
|
|
220
|
+
const mockResponse = {
|
|
221
|
+
ok: true,
|
|
222
|
+
status: 200,
|
|
223
|
+
};
|
|
202
224
|
|
|
203
|
-
|
|
204
|
-
await promise;
|
|
205
|
-
} catch ( err ) {
|
|
206
|
-
error = err;
|
|
207
|
-
}
|
|
225
|
+
globalThis.fetch.mockResolvedValue( mockResponse );
|
|
208
226
|
|
|
209
|
-
expect(
|
|
227
|
+
await expect(
|
|
228
|
+
apiFetch( { path: '/random', parse: false } )
|
|
229
|
+
).resolves.toBe( mockResponse );
|
|
210
230
|
} );
|
|
211
231
|
|
|
212
|
-
it( 'should
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
);
|
|
232
|
+
it( 'should not try to parse the error', async () => {
|
|
233
|
+
const mockResponse = {
|
|
234
|
+
ok: false,
|
|
235
|
+
status: 400,
|
|
236
|
+
};
|
|
218
237
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
238
|
+
globalThis.fetch.mockResolvedValue( mockResponse );
|
|
239
|
+
|
|
240
|
+
await expect(
|
|
241
|
+
apiFetch( { path: '/random', parse: false } )
|
|
242
|
+
).rejects.toBe( mockResponse );
|
|
223
243
|
} );
|
|
224
244
|
|
|
225
|
-
it( 'should
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
245
|
+
it( 'should refetch after successful nonce refresh', async () => {
|
|
246
|
+
apiFetch.nonceMiddleware =
|
|
247
|
+
apiFetch.createNonceMiddleware( 'old-nonce' );
|
|
248
|
+
apiFetch.use( apiFetch.nonceMiddleware );
|
|
249
|
+
apiFetch.nonceEndpoint = '/rest-nonce';
|
|
250
|
+
|
|
251
|
+
globalThis.fetch.mockImplementation( async ( path, options ) => {
|
|
252
|
+
if ( path.startsWith( '/random' ) ) {
|
|
253
|
+
if ( options?.headers[ 'X-WP-Nonce' ] === 'new-nonce' ) {
|
|
254
|
+
return {
|
|
255
|
+
ok: true,
|
|
256
|
+
status: 200,
|
|
257
|
+
json: async () => ( { code: 'success' } ),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
ok: false,
|
|
263
|
+
status: 403,
|
|
264
|
+
json: async () => ( { code: 'rest_cookie_invalid_nonce' } ),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
231
267
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
268
|
+
if ( path.startsWith( '/rest-nonce' ) ) {
|
|
269
|
+
return {
|
|
270
|
+
ok: true,
|
|
235
271
|
status: 200,
|
|
236
|
-
|
|
272
|
+
text: async () => 'new-nonce',
|
|
273
|
+
};
|
|
237
274
|
}
|
|
238
|
-
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
ok: false,
|
|
278
|
+
status: 404,
|
|
279
|
+
json: async () => ( { code: 'rest_no_route' } ),
|
|
280
|
+
};
|
|
281
|
+
} );
|
|
282
|
+
|
|
283
|
+
await expect( apiFetch( { path: '/random' } ) ).resolves.toEqual( {
|
|
284
|
+
code: 'success',
|
|
285
|
+
} );
|
|
239
286
|
} );
|
|
240
287
|
|
|
241
|
-
it( 'should
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
288
|
+
it( 'should fail with rest_cookie_invalid_nonce after failed nonce refresh', async () => {
|
|
289
|
+
apiFetch.nonceMiddleware =
|
|
290
|
+
apiFetch.createNonceMiddleware( 'old-nonce' );
|
|
291
|
+
apiFetch.use( apiFetch.nonceMiddleware );
|
|
292
|
+
apiFetch.nonceEndpoint = '/rest-nonce';
|
|
293
|
+
|
|
294
|
+
globalThis.fetch.mockImplementation( async ( path, options ) => {
|
|
295
|
+
if ( path.startsWith( '/random' ) ) {
|
|
296
|
+
if ( options?.headers[ 'X-WP-Nonce' ] === 'new-nonce' ) {
|
|
297
|
+
return {
|
|
298
|
+
ok: true,
|
|
299
|
+
status: 200,
|
|
300
|
+
json: async () => ( { code: 'success' } ),
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
ok: false,
|
|
306
|
+
status: 403,
|
|
307
|
+
json: async () => ( { code: 'rest_cookie_invalid_nonce' } ),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
247
310
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
expect( response ).toEqual( {
|
|
311
|
+
if ( path.startsWith( '/rest-nonce' ) ) {
|
|
312
|
+
return {
|
|
313
|
+
ok: false,
|
|
252
314
|
status: 400,
|
|
253
|
-
|
|
315
|
+
text: async () => '0',
|
|
316
|
+
};
|
|
254
317
|
}
|
|
255
|
-
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
ok: false,
|
|
321
|
+
status: 404,
|
|
322
|
+
json: async () => ( { code: 'rest_no_route' } ),
|
|
323
|
+
};
|
|
324
|
+
} );
|
|
325
|
+
|
|
326
|
+
await expect( apiFetch( { path: '/random' } ) ).rejects.toEqual( {
|
|
327
|
+
code: 'rest_cookie_invalid_nonce',
|
|
328
|
+
} );
|
|
256
329
|
} );
|
|
257
330
|
|
|
258
|
-
it( 'should not use the default fetch handler when using a custom fetch handler', () => {
|
|
331
|
+
it( 'should not use the default fetch handler when using a custom fetch handler', async () => {
|
|
259
332
|
const customFetchHandler = jest.fn();
|
|
260
333
|
|
|
261
334
|
apiFetch.setFetchHandler( customFetchHandler );
|
|
262
335
|
|
|
263
|
-
apiFetch( { path: '/random' } );
|
|
336
|
+
await apiFetch( { path: '/random' } );
|
|
264
337
|
|
|
265
|
-
expect(
|
|
338
|
+
expect( globalThis.fetch ).not.toHaveBeenCalled();
|
|
266
339
|
|
|
267
340
|
expect( customFetchHandler ).toHaveBeenCalledWith( {
|
|
268
341
|
path: '/random?_locale=user',
|
|
269
342
|
} );
|
|
270
343
|
} );
|
|
271
344
|
|
|
272
|
-
it( 'should run the last-registered user-defined middleware first', () => {
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
// to ensure that the last-registered middleware receives the original
|
|
276
|
-
// options object. It also assumes that some built-in middleware would
|
|
277
|
-
// either mutate or clone the original options if the extra middleware
|
|
278
|
-
// had been pushed to the stack.
|
|
279
|
-
expect.assertions( 1 );
|
|
345
|
+
it( 'should run the last-registered user-defined middleware first', async () => {
|
|
346
|
+
// The test assumes that some built-in middleware will either mutate or clone
|
|
347
|
+
// the original options if the extra middleware had been pushed to the stack.
|
|
280
348
|
|
|
281
349
|
const expectedOptions = {};
|
|
282
350
|
|
|
@@ -286,6 +354,9 @@ describe( 'apiFetch', () => {
|
|
|
286
354
|
return next( actualOptions );
|
|
287
355
|
} );
|
|
288
356
|
|
|
289
|
-
|
|
357
|
+
// Set a custom fetch handler to avoid using the default fetch handler.
|
|
358
|
+
apiFetch.setFetchHandler( jest.fn() );
|
|
359
|
+
|
|
360
|
+
await apiFetch( expectedOptions );
|
|
290
361
|
} );
|
|
291
362
|
} );
|