graphql-http 1.7.2 → 1.8.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/lib/audits/server.d.mts +4 -1
- package/lib/audits/server.d.ts +4 -1
- package/lib/audits/server.js +56 -49
- package/lib/audits/server.mjs +56 -49
- package/package.json +1 -1
- package/umd/graphql-http.min.js.gz +0 -0
package/lib/audits/server.d.mts
CHANGED
|
@@ -12,8 +12,11 @@ import { Audit, AuditResult } from './common';
|
|
|
12
12
|
export interface ServerAuditOptions {
|
|
13
13
|
/**
|
|
14
14
|
* The URL of the GraphQL server for the audit.
|
|
15
|
+
*
|
|
16
|
+
* A function can be also supplied, in this case -
|
|
17
|
+
* every audit will invoke the function to get the URL.
|
|
15
18
|
*/
|
|
16
|
-
url: string;
|
|
19
|
+
url: string | (() => string | Promise<string>);
|
|
17
20
|
/**
|
|
18
21
|
* The Fetch function to use.
|
|
19
22
|
*
|
package/lib/audits/server.d.ts
CHANGED
|
@@ -12,8 +12,11 @@ import { Audit, AuditResult } from './common';
|
|
|
12
12
|
export interface ServerAuditOptions {
|
|
13
13
|
/**
|
|
14
14
|
* The URL of the GraphQL server for the audit.
|
|
15
|
+
*
|
|
16
|
+
* A function can be also supplied, in this case -
|
|
17
|
+
* every audit will invoke the function to get the URL.
|
|
15
18
|
*/
|
|
16
|
-
url: string;
|
|
19
|
+
url: string | (() => string | Promise<string>);
|
|
17
20
|
/**
|
|
18
21
|
* The Fetch function to use.
|
|
19
22
|
*
|
package/lib/audits/server.js
CHANGED
|
@@ -19,7 +19,7 @@ function serverAudits(opts) {
|
|
|
19
19
|
(0, utils_1.audit)(
|
|
20
20
|
// TODO: convert to MUST after watershed
|
|
21
21
|
'SHOULD accept application/graphql-response+json and match the content-type', async () => {
|
|
22
|
-
const res = await fetchFn(opts.url, {
|
|
22
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
23
23
|
method: 'POST',
|
|
24
24
|
headers: {
|
|
25
25
|
'content-type': 'application/json',
|
|
@@ -31,7 +31,7 @@ function serverAudits(opts) {
|
|
|
31
31
|
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
|
|
32
32
|
}),
|
|
33
33
|
(0, utils_1.audit)('MUST accept application/json and match the content-type', async () => {
|
|
34
|
-
const res = await fetchFn(opts.url, {
|
|
34
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
35
35
|
method: 'POST',
|
|
36
36
|
headers: {
|
|
37
37
|
'content-type': 'application/json',
|
|
@@ -43,7 +43,7 @@ function serverAudits(opts) {
|
|
|
43
43
|
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/json');
|
|
44
44
|
}),
|
|
45
45
|
(0, utils_1.audit)('SHOULD accept */* and use application/json for the content-type', async () => {
|
|
46
|
-
const res = await fetchFn(opts.url, {
|
|
46
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
47
47
|
method: 'POST',
|
|
48
48
|
headers: {
|
|
49
49
|
'content-type': 'application/json',
|
|
@@ -55,14 +55,14 @@ function serverAudits(opts) {
|
|
|
55
55
|
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/json');
|
|
56
56
|
}),
|
|
57
57
|
(0, utils_1.audit)('SHOULD assume application/json content-type when accept is missing', async () => {
|
|
58
|
-
const url = new URL(opts.url);
|
|
58
|
+
const url = new URL(await getUrl(opts.url));
|
|
59
59
|
url.searchParams.set('query', '{ __typename }');
|
|
60
60
|
const res = await fetchFn(url.toString());
|
|
61
61
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
62
62
|
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/json');
|
|
63
63
|
}),
|
|
64
64
|
(0, utils_1.audit)('MUST use utf-8 encoding when responding', async () => {
|
|
65
|
-
const res = await fetchFn(opts.url, {
|
|
65
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
66
66
|
method: 'POST',
|
|
67
67
|
headers: {
|
|
68
68
|
'content-type': 'application/json',
|
|
@@ -91,7 +91,7 @@ function serverAudits(opts) {
|
|
|
91
91
|
}
|
|
92
92
|
}),
|
|
93
93
|
(0, utils_1.audit)('MUST accept utf-8 encoding', async () => {
|
|
94
|
-
const res = await fetchFn(opts.url, {
|
|
94
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
95
95
|
method: 'POST',
|
|
96
96
|
headers: {
|
|
97
97
|
'content-type': 'application/json; charset=utf-8',
|
|
@@ -102,7 +102,7 @@ function serverAudits(opts) {
|
|
|
102
102
|
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
|
|
103
103
|
}),
|
|
104
104
|
(0, utils_1.audit)('MUST assume utf-8 if encoding is unspecified', async () => {
|
|
105
|
-
const res = await fetchFn(opts.url, {
|
|
105
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
106
106
|
method: 'POST',
|
|
107
107
|
headers: {
|
|
108
108
|
'content-type': 'application/json',
|
|
@@ -114,7 +114,7 @@ function serverAudits(opts) {
|
|
|
114
114
|
}),
|
|
115
115
|
// Request
|
|
116
116
|
(0, utils_1.audit)('MUST accept POST requests', async () => {
|
|
117
|
-
const res = await fetchFn(opts.url, {
|
|
117
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
118
118
|
method: 'POST',
|
|
119
119
|
headers: { 'content-type': 'application/json' },
|
|
120
120
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
@@ -122,7 +122,7 @@ function serverAudits(opts) {
|
|
|
122
122
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
123
123
|
}),
|
|
124
124
|
(0, utils_1.audit)('MAY accept application/x-www-form-urlencoded formatted GET requests', async () => {
|
|
125
|
-
const url = new URL(opts.url);
|
|
125
|
+
const url = new URL(await getUrl(opts.url));
|
|
126
126
|
url.searchParams.set('query', '{ __typename }');
|
|
127
127
|
const res = await fetchFn(url.toString());
|
|
128
128
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
@@ -130,7 +130,7 @@ function serverAudits(opts) {
|
|
|
130
130
|
// Request GET
|
|
131
131
|
// TODO: this is a MUST if the server supports GET requests
|
|
132
132
|
(0, utils_1.audit)('MAY NOT allow executing mutations on GET requests', async () => {
|
|
133
|
-
const url = new URL(opts.url);
|
|
133
|
+
const url = new URL(await getUrl(opts.url));
|
|
134
134
|
url.searchParams.set('query', 'mutation { __typename }');
|
|
135
135
|
const res = await fetchFn(url.toString(), {
|
|
136
136
|
headers: {
|
|
@@ -141,13 +141,13 @@ function serverAudits(opts) {
|
|
|
141
141
|
}),
|
|
142
142
|
// Request POST
|
|
143
143
|
(0, utils_1.audit)('SHOULD respond with 4xx status code if content-type is not supplied on POST requests', async () => {
|
|
144
|
-
const res = await fetchFn(opts.url, {
|
|
144
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
145
145
|
method: 'POST',
|
|
146
146
|
});
|
|
147
147
|
(0, utils_1.assert)('Status code', res.status).toBeBetween(400, 499);
|
|
148
148
|
}),
|
|
149
149
|
(0, utils_1.audit)('MUST accept application/json POST requests', async () => {
|
|
150
|
-
const res = await fetchFn(opts.url, {
|
|
150
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
151
151
|
method: 'POST',
|
|
152
152
|
headers: { 'content-type': 'application/json' },
|
|
153
153
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
@@ -156,7 +156,7 @@ function serverAudits(opts) {
|
|
|
156
156
|
}),
|
|
157
157
|
(0, utils_1.audit)('MUST require a request body on POST', async () => {
|
|
158
158
|
var _a;
|
|
159
|
-
const res = await fetchFn(opts.url, {
|
|
159
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
160
160
|
method: 'POST',
|
|
161
161
|
headers: { 'content-type': 'application/json' },
|
|
162
162
|
});
|
|
@@ -171,7 +171,7 @@ function serverAudits(opts) {
|
|
|
171
171
|
(0, utils_1.audit)(
|
|
172
172
|
// TODO: convert to MUST after watershed
|
|
173
173
|
'SHOULD use 400 status code on missing {query} parameter when accepting application/graphql-response+json', async () => {
|
|
174
|
-
const res = await fetchFn(opts.url, {
|
|
174
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
175
175
|
method: 'POST',
|
|
176
176
|
headers: {
|
|
177
177
|
'content-type': 'application/json',
|
|
@@ -182,7 +182,7 @@ function serverAudits(opts) {
|
|
|
182
182
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
183
183
|
}),
|
|
184
184
|
(0, utils_1.audit)('SHOULD use 200 status code with errors field on missing {query} parameter when accepting application/json', async () => {
|
|
185
|
-
const res = await fetchFn(opts.url, {
|
|
185
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
186
186
|
method: 'POST',
|
|
187
187
|
headers: {
|
|
188
188
|
'content-type': 'application/json',
|
|
@@ -196,7 +196,7 @@ function serverAudits(opts) {
|
|
|
196
196
|
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
|
|
197
197
|
// TODO: convert to MUST after watershed
|
|
198
198
|
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {query} parameter when accepting application/graphql-response+json`, async () => {
|
|
199
|
-
const res = await fetchFn(opts.url, {
|
|
199
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
200
200
|
method: 'POST',
|
|
201
201
|
headers: {
|
|
202
202
|
'content-type': 'application/json',
|
|
@@ -209,7 +209,7 @@ function serverAudits(opts) {
|
|
|
209
209
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
210
210
|
})),
|
|
211
211
|
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => (0, utils_1.audit)(`SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {query} parameter when accepting application/json`, async () => {
|
|
212
|
-
const res = await fetchFn(opts.url, {
|
|
212
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
213
213
|
method: 'POST',
|
|
214
214
|
headers: {
|
|
215
215
|
'content-type': 'application/json',
|
|
@@ -225,7 +225,7 @@ function serverAudits(opts) {
|
|
|
225
225
|
(0, utils_1.audit)(
|
|
226
226
|
// TODO: convert to MUST after watershed
|
|
227
227
|
'SHOULD allow string {query} parameter when accepting application/graphql-response+json', async () => {
|
|
228
|
-
const res = await fetchFn(opts.url, {
|
|
228
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
229
229
|
method: 'POST',
|
|
230
230
|
headers: {
|
|
231
231
|
'content-type': 'application/json',
|
|
@@ -238,7 +238,7 @@ function serverAudits(opts) {
|
|
|
238
238
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
239
239
|
}),
|
|
240
240
|
(0, utils_1.audit)('MUST allow string {query} parameter when accepting application/json', async () => {
|
|
241
|
-
const res = await fetchFn(opts.url, {
|
|
241
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
242
242
|
method: 'POST',
|
|
243
243
|
headers: {
|
|
244
244
|
'content-type': 'application/json',
|
|
@@ -254,7 +254,7 @@ function serverAudits(opts) {
|
|
|
254
254
|
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
|
|
255
255
|
// TODO: convert to MUST after watershed
|
|
256
256
|
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {operationName} parameter when accepting application/graphql-response+json`, async () => {
|
|
257
|
-
const res = await fetchFn(opts.url, {
|
|
257
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
258
258
|
method: 'POST',
|
|
259
259
|
headers: {
|
|
260
260
|
'content-type': 'application/json',
|
|
@@ -268,7 +268,7 @@ function serverAudits(opts) {
|
|
|
268
268
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
269
269
|
})),
|
|
270
270
|
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => (0, utils_1.audit)(`SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {operationName} parameter when accepting application/json`, async () => {
|
|
271
|
-
const res = await fetchFn(opts.url, {
|
|
271
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
272
272
|
method: 'POST',
|
|
273
273
|
headers: {
|
|
274
274
|
'content-type': 'application/json',
|
|
@@ -285,7 +285,7 @@ function serverAudits(opts) {
|
|
|
285
285
|
(0, utils_1.audit)(
|
|
286
286
|
// TODO: convert to MUST after watershed
|
|
287
287
|
'SHOULD allow string {operationName} parameter when accepting application/graphql-response+json', async () => {
|
|
288
|
-
const res = await fetchFn(opts.url, {
|
|
288
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
289
289
|
method: 'POST',
|
|
290
290
|
headers: {
|
|
291
291
|
'content-type': 'application/json',
|
|
@@ -299,7 +299,7 @@ function serverAudits(opts) {
|
|
|
299
299
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
300
300
|
}),
|
|
301
301
|
(0, utils_1.audit)('MUST allow string {operationName} parameter when accepting application/json', async () => {
|
|
302
|
-
const res = await fetchFn(opts.url, {
|
|
302
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
303
303
|
method: 'POST',
|
|
304
304
|
headers: {
|
|
305
305
|
'content-type': 'application/json',
|
|
@@ -316,7 +316,7 @@ function serverAudits(opts) {
|
|
|
316
316
|
...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
|
|
317
317
|
// TODO: convert to MUST after watershed
|
|
318
318
|
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {variables} parameter when accepting application/graphql-response+json`, async () => {
|
|
319
|
-
const res = await fetchFn(opts.url, {
|
|
319
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
320
320
|
method: 'POST',
|
|
321
321
|
headers: {
|
|
322
322
|
'content-type': 'application/json',
|
|
@@ -330,7 +330,7 @@ function serverAudits(opts) {
|
|
|
330
330
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
331
331
|
})),
|
|
332
332
|
...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(`SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {variables} parameter when accepting application/json`, async () => {
|
|
333
|
-
const res = await fetchFn(opts.url, {
|
|
333
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
334
334
|
method: 'POST',
|
|
335
335
|
headers: {
|
|
336
336
|
'content-type': 'application/json',
|
|
@@ -347,7 +347,7 @@ function serverAudits(opts) {
|
|
|
347
347
|
(0, utils_1.audit)(
|
|
348
348
|
// TODO: convert to MUST after watershed
|
|
349
349
|
'SHOULD allow map {variables} parameter when accepting application/graphql-response+json', async () => {
|
|
350
|
-
const res = await fetchFn(opts.url, {
|
|
350
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
351
351
|
method: 'POST',
|
|
352
352
|
headers: {
|
|
353
353
|
'content-type': 'application/json',
|
|
@@ -361,7 +361,7 @@ function serverAudits(opts) {
|
|
|
361
361
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
362
362
|
}),
|
|
363
363
|
(0, utils_1.audit)('MUST allow map {variables} parameter when accepting application/json', async () => {
|
|
364
|
-
const res = await fetchFn(opts.url, {
|
|
364
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
365
365
|
method: 'POST',
|
|
366
366
|
headers: {
|
|
367
367
|
'content-type': 'application/json',
|
|
@@ -376,7 +376,7 @@ function serverAudits(opts) {
|
|
|
376
376
|
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).notToHaveProperty('errors');
|
|
377
377
|
}),
|
|
378
378
|
(0, utils_1.audit)('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json', async () => {
|
|
379
|
-
const url = new URL(opts.url);
|
|
379
|
+
const url = new URL(await getUrl(opts.url));
|
|
380
380
|
url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
|
|
381
381
|
url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
|
|
382
382
|
const res = await fetchFn(url.toString(), {
|
|
@@ -388,7 +388,7 @@ function serverAudits(opts) {
|
|
|
388
388
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
389
389
|
}),
|
|
390
390
|
(0, utils_1.audit)('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json', async () => {
|
|
391
|
-
const url = new URL(opts.url);
|
|
391
|
+
const url = new URL(await getUrl(opts.url));
|
|
392
392
|
url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
|
|
393
393
|
url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
|
|
394
394
|
const res = await fetchFn(url.toString(), {
|
|
@@ -403,7 +403,7 @@ function serverAudits(opts) {
|
|
|
403
403
|
...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
|
|
404
404
|
// TODO: convert to MUST after watershed
|
|
405
405
|
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {extensions} parameter when accepting application/graphql-response+json`, async () => {
|
|
406
|
-
const res = await fetchFn(opts.url, {
|
|
406
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
407
407
|
method: 'POST',
|
|
408
408
|
headers: {
|
|
409
409
|
'content-type': 'application/json',
|
|
@@ -417,7 +417,7 @@ function serverAudits(opts) {
|
|
|
417
417
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
418
418
|
})),
|
|
419
419
|
...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(`SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {extensions} parameter when accepting application/json`, async () => {
|
|
420
|
-
const res = await fetchFn(opts.url, {
|
|
420
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
421
421
|
method: 'POST',
|
|
422
422
|
headers: {
|
|
423
423
|
'content-type': 'application/json',
|
|
@@ -434,7 +434,7 @@ function serverAudits(opts) {
|
|
|
434
434
|
(0, utils_1.audit)(
|
|
435
435
|
// TODO: convert to MUST after watershed
|
|
436
436
|
'SHOULD allow map {extensions} parameter when accepting application/graphql-response+json', async () => {
|
|
437
|
-
const res = await fetchFn(opts.url, {
|
|
437
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
438
438
|
method: 'POST',
|
|
439
439
|
headers: {
|
|
440
440
|
'content-type': 'application/json',
|
|
@@ -448,7 +448,7 @@ function serverAudits(opts) {
|
|
|
448
448
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
449
449
|
}),
|
|
450
450
|
(0, utils_1.audit)('MUST allow map {extensions} parameter when accepting application/json', async () => {
|
|
451
|
-
const res = await fetchFn(opts.url, {
|
|
451
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
452
452
|
method: 'POST',
|
|
453
453
|
headers: {
|
|
454
454
|
'content-type': 'application/json',
|
|
@@ -465,7 +465,7 @@ function serverAudits(opts) {
|
|
|
465
465
|
// TODO: audit('MUST accept a map for the {extensions} parameter'),
|
|
466
466
|
// Response application/json
|
|
467
467
|
(0, utils_1.audit)('SHOULD use 200 status code on JSON parsing failure when accepting application/json', async () => {
|
|
468
|
-
const res = await fetchFn(opts.url, {
|
|
468
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
469
469
|
method: 'POST',
|
|
470
470
|
headers: {
|
|
471
471
|
'content-type': 'application/json',
|
|
@@ -476,7 +476,7 @@ function serverAudits(opts) {
|
|
|
476
476
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
477
477
|
}),
|
|
478
478
|
(0, utils_1.audit)('SHOULD use 200 status code if parameters are invalid when accepting application/json', async () => {
|
|
479
|
-
const res = await fetchFn(opts.url, {
|
|
479
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
480
480
|
method: 'POST',
|
|
481
481
|
headers: {
|
|
482
482
|
'content-type': 'application/json',
|
|
@@ -489,7 +489,7 @@ function serverAudits(opts) {
|
|
|
489
489
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
490
490
|
}),
|
|
491
491
|
(0, utils_1.audit)('SHOULD use 200 status code on document parsing failure when accepting application/json', async () => {
|
|
492
|
-
const res = await fetchFn(opts.url, {
|
|
492
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
493
493
|
method: 'POST',
|
|
494
494
|
headers: {
|
|
495
495
|
'content-type': 'application/json',
|
|
@@ -500,7 +500,7 @@ function serverAudits(opts) {
|
|
|
500
500
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
501
501
|
}),
|
|
502
502
|
(0, utils_1.audit)('SHOULD use 200 status code on document validation failure when accepting application/json', async () => {
|
|
503
|
-
const res = await fetchFn(opts.url, {
|
|
503
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
504
504
|
method: 'POST',
|
|
505
505
|
headers: {
|
|
506
506
|
'content-type': 'application/json',
|
|
@@ -516,7 +516,7 @@ function serverAudits(opts) {
|
|
|
516
516
|
(0, utils_1.audit)(
|
|
517
517
|
// TODO: convert to MUST after watershed
|
|
518
518
|
'SHOULD use 4xx or 5xx status codes on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
519
|
-
const res = await fetchFn(opts.url, {
|
|
519
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
520
520
|
method: 'POST',
|
|
521
521
|
headers: {
|
|
522
522
|
'content-type': 'application/json',
|
|
@@ -527,7 +527,7 @@ function serverAudits(opts) {
|
|
|
527
527
|
(0, utils_1.assert)('Status code', res.status).toBeBetween(400, 499);
|
|
528
528
|
}),
|
|
529
529
|
(0, utils_1.audit)('SHOULD use 400 status code on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
530
|
-
const res = await fetchFn(opts.url, {
|
|
530
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
531
531
|
method: 'POST',
|
|
532
532
|
headers: {
|
|
533
533
|
'content-type': 'application/json',
|
|
@@ -538,7 +538,7 @@ function serverAudits(opts) {
|
|
|
538
538
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
539
539
|
}),
|
|
540
540
|
(0, utils_1.audit)('SHOULD not contain the data entry on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
541
|
-
const res = await fetchFn(opts.url, {
|
|
541
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
542
542
|
method: 'POST',
|
|
543
543
|
headers: {
|
|
544
544
|
'content-type': 'application/json',
|
|
@@ -551,7 +551,7 @@ function serverAudits(opts) {
|
|
|
551
551
|
(0, utils_1.audit)(
|
|
552
552
|
// TODO: convert to MUST after watershed
|
|
553
553
|
'SHOULD use 4xx or 5xx status codes if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
554
|
-
const res = await fetchFn(opts.url, {
|
|
554
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
555
555
|
method: 'POST',
|
|
556
556
|
headers: {
|
|
557
557
|
'content-type': 'application/json',
|
|
@@ -564,7 +564,7 @@ function serverAudits(opts) {
|
|
|
564
564
|
(0, utils_1.assert)('Status code', res.status).toBeBetween(400, 599);
|
|
565
565
|
}),
|
|
566
566
|
(0, utils_1.audit)('SHOULD use 400 status code if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
567
|
-
const res = await fetchFn(opts.url, {
|
|
567
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
568
568
|
method: 'POST',
|
|
569
569
|
headers: {
|
|
570
570
|
'content-type': 'application/json',
|
|
@@ -577,7 +577,7 @@ function serverAudits(opts) {
|
|
|
577
577
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
578
578
|
}),
|
|
579
579
|
(0, utils_1.audit)('SHOULD not contain the data entry if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
580
|
-
const res = await fetchFn(opts.url, {
|
|
580
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
581
581
|
method: 'POST',
|
|
582
582
|
headers: {
|
|
583
583
|
'content-type': 'application/json',
|
|
@@ -592,7 +592,7 @@ function serverAudits(opts) {
|
|
|
592
592
|
(0, utils_1.audit)(
|
|
593
593
|
// TODO: convert to MUST after watershed
|
|
594
594
|
'SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
595
|
-
const res = await fetchFn(opts.url, {
|
|
595
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
596
596
|
method: 'POST',
|
|
597
597
|
headers: {
|
|
598
598
|
'content-type': 'application/json',
|
|
@@ -605,7 +605,7 @@ function serverAudits(opts) {
|
|
|
605
605
|
(0, utils_1.assert)('Status code', res.status).toBeBetween(400, 599);
|
|
606
606
|
}),
|
|
607
607
|
(0, utils_1.audit)('SHOULD use 400 status code on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
608
|
-
const res = await fetchFn(opts.url, {
|
|
608
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
609
609
|
method: 'POST',
|
|
610
610
|
headers: {
|
|
611
611
|
'content-type': 'application/json',
|
|
@@ -618,7 +618,7 @@ function serverAudits(opts) {
|
|
|
618
618
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
619
619
|
}),
|
|
620
620
|
(0, utils_1.audit)('SHOULD not contain the data entry on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
621
|
-
const res = await fetchFn(opts.url, {
|
|
621
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
622
622
|
method: 'POST',
|
|
623
623
|
headers: {
|
|
624
624
|
'content-type': 'application/json',
|
|
@@ -633,7 +633,7 @@ function serverAudits(opts) {
|
|
|
633
633
|
(0, utils_1.audit)(
|
|
634
634
|
// TODO: convert to MUST after watershed
|
|
635
635
|
'SHOULD use 4xx or 5xx status codes on document validation failure when accepting application/graphql-response+json', async () => {
|
|
636
|
-
const res = await fetchFn(opts.url, {
|
|
636
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
637
637
|
method: 'POST',
|
|
638
638
|
headers: {
|
|
639
639
|
'content-type': 'application/json',
|
|
@@ -646,7 +646,7 @@ function serverAudits(opts) {
|
|
|
646
646
|
(0, utils_1.assert)('Status code', res.status).toBeBetween(400, 599);
|
|
647
647
|
}),
|
|
648
648
|
(0, utils_1.audit)('SHOULD use 400 status code on document validation failure when accepting application/graphql-response+json', async () => {
|
|
649
|
-
const res = await fetchFn(opts.url, {
|
|
649
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
650
650
|
method: 'POST',
|
|
651
651
|
headers: {
|
|
652
652
|
'content-type': 'application/json',
|
|
@@ -659,7 +659,7 @@ function serverAudits(opts) {
|
|
|
659
659
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
660
660
|
}),
|
|
661
661
|
(0, utils_1.audit)('SHOULD not contain the data entry on document validation failure when accepting application/graphql-response+json', async () => {
|
|
662
|
-
const res = await fetchFn(opts.url, {
|
|
662
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
663
663
|
method: 'POST',
|
|
664
664
|
headers: {
|
|
665
665
|
'content-type': 'application/json',
|
|
@@ -692,3 +692,10 @@ async function auditServer(opts) {
|
|
|
692
692
|
return await Promise.all(audits.map(({ fn }) => fn()));
|
|
693
693
|
}
|
|
694
694
|
exports.auditServer = auditServer;
|
|
695
|
+
/** @private */
|
|
696
|
+
async function getUrl(url) {
|
|
697
|
+
if (typeof url === 'string') {
|
|
698
|
+
return url;
|
|
699
|
+
}
|
|
700
|
+
return await url();
|
|
701
|
+
}
|
package/lib/audits/server.mjs
CHANGED
|
@@ -16,7 +16,7 @@ export function serverAudits(opts) {
|
|
|
16
16
|
audit(
|
|
17
17
|
// TODO: convert to MUST after watershed
|
|
18
18
|
'SHOULD accept application/graphql-response+json and match the content-type', async () => {
|
|
19
|
-
const res = await fetchFn(opts.url, {
|
|
19
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
20
20
|
method: 'POST',
|
|
21
21
|
headers: {
|
|
22
22
|
'content-type': 'application/json',
|
|
@@ -28,7 +28,7 @@ export function serverAudits(opts) {
|
|
|
28
28
|
assert('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
|
|
29
29
|
}),
|
|
30
30
|
audit('MUST accept application/json and match the content-type', async () => {
|
|
31
|
-
const res = await fetchFn(opts.url, {
|
|
31
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
32
32
|
method: 'POST',
|
|
33
33
|
headers: {
|
|
34
34
|
'content-type': 'application/json',
|
|
@@ -40,7 +40,7 @@ export function serverAudits(opts) {
|
|
|
40
40
|
assert('Content-Type header', res.headers.get('content-type')).toContain('application/json');
|
|
41
41
|
}),
|
|
42
42
|
audit('SHOULD accept */* and use application/json for the content-type', async () => {
|
|
43
|
-
const res = await fetchFn(opts.url, {
|
|
43
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
44
44
|
method: 'POST',
|
|
45
45
|
headers: {
|
|
46
46
|
'content-type': 'application/json',
|
|
@@ -52,14 +52,14 @@ export function serverAudits(opts) {
|
|
|
52
52
|
assert('Content-Type header', res.headers.get('content-type')).toContain('application/json');
|
|
53
53
|
}),
|
|
54
54
|
audit('SHOULD assume application/json content-type when accept is missing', async () => {
|
|
55
|
-
const url = new URL(opts.url);
|
|
55
|
+
const url = new URL(await getUrl(opts.url));
|
|
56
56
|
url.searchParams.set('query', '{ __typename }');
|
|
57
57
|
const res = await fetchFn(url.toString());
|
|
58
58
|
assert('Status code', res.status).toBe(200);
|
|
59
59
|
assert('Content-Type header', res.headers.get('content-type')).toContain('application/json');
|
|
60
60
|
}),
|
|
61
61
|
audit('MUST use utf-8 encoding when responding', async () => {
|
|
62
|
-
const res = await fetchFn(opts.url, {
|
|
62
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
63
63
|
method: 'POST',
|
|
64
64
|
headers: {
|
|
65
65
|
'content-type': 'application/json',
|
|
@@ -88,7 +88,7 @@ export function serverAudits(opts) {
|
|
|
88
88
|
}
|
|
89
89
|
}),
|
|
90
90
|
audit('MUST accept utf-8 encoding', async () => {
|
|
91
|
-
const res = await fetchFn(opts.url, {
|
|
91
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
92
92
|
method: 'POST',
|
|
93
93
|
headers: {
|
|
94
94
|
'content-type': 'application/json; charset=utf-8',
|
|
@@ -99,7 +99,7 @@ export function serverAudits(opts) {
|
|
|
99
99
|
assert('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
|
|
100
100
|
}),
|
|
101
101
|
audit('MUST assume utf-8 if encoding is unspecified', async () => {
|
|
102
|
-
const res = await fetchFn(opts.url, {
|
|
102
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
103
103
|
method: 'POST',
|
|
104
104
|
headers: {
|
|
105
105
|
'content-type': 'application/json',
|
|
@@ -111,7 +111,7 @@ export function serverAudits(opts) {
|
|
|
111
111
|
}),
|
|
112
112
|
// Request
|
|
113
113
|
audit('MUST accept POST requests', async () => {
|
|
114
|
-
const res = await fetchFn(opts.url, {
|
|
114
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
115
115
|
method: 'POST',
|
|
116
116
|
headers: { 'content-type': 'application/json' },
|
|
117
117
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
@@ -119,7 +119,7 @@ export function serverAudits(opts) {
|
|
|
119
119
|
assert('Status code', res.status).toBe(200);
|
|
120
120
|
}),
|
|
121
121
|
audit('MAY accept application/x-www-form-urlencoded formatted GET requests', async () => {
|
|
122
|
-
const url = new URL(opts.url);
|
|
122
|
+
const url = new URL(await getUrl(opts.url));
|
|
123
123
|
url.searchParams.set('query', '{ __typename }');
|
|
124
124
|
const res = await fetchFn(url.toString());
|
|
125
125
|
assert('Status code', res.status).toBe(200);
|
|
@@ -127,7 +127,7 @@ export function serverAudits(opts) {
|
|
|
127
127
|
// Request GET
|
|
128
128
|
// TODO: this is a MUST if the server supports GET requests
|
|
129
129
|
audit('MAY NOT allow executing mutations on GET requests', async () => {
|
|
130
|
-
const url = new URL(opts.url);
|
|
130
|
+
const url = new URL(await getUrl(opts.url));
|
|
131
131
|
url.searchParams.set('query', 'mutation { __typename }');
|
|
132
132
|
const res = await fetchFn(url.toString(), {
|
|
133
133
|
headers: {
|
|
@@ -138,13 +138,13 @@ export function serverAudits(opts) {
|
|
|
138
138
|
}),
|
|
139
139
|
// Request POST
|
|
140
140
|
audit('SHOULD respond with 4xx status code if content-type is not supplied on POST requests', async () => {
|
|
141
|
-
const res = await fetchFn(opts.url, {
|
|
141
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
142
142
|
method: 'POST',
|
|
143
143
|
});
|
|
144
144
|
assert('Status code', res.status).toBeBetween(400, 499);
|
|
145
145
|
}),
|
|
146
146
|
audit('MUST accept application/json POST requests', async () => {
|
|
147
|
-
const res = await fetchFn(opts.url, {
|
|
147
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
148
148
|
method: 'POST',
|
|
149
149
|
headers: { 'content-type': 'application/json' },
|
|
150
150
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
@@ -153,7 +153,7 @@ export function serverAudits(opts) {
|
|
|
153
153
|
}),
|
|
154
154
|
audit('MUST require a request body on POST', async () => {
|
|
155
155
|
var _a;
|
|
156
|
-
const res = await fetchFn(opts.url, {
|
|
156
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
157
157
|
method: 'POST',
|
|
158
158
|
headers: { 'content-type': 'application/json' },
|
|
159
159
|
});
|
|
@@ -168,7 +168,7 @@ export function serverAudits(opts) {
|
|
|
168
168
|
audit(
|
|
169
169
|
// TODO: convert to MUST after watershed
|
|
170
170
|
'SHOULD use 400 status code on missing {query} parameter when accepting application/graphql-response+json', async () => {
|
|
171
|
-
const res = await fetchFn(opts.url, {
|
|
171
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
172
172
|
method: 'POST',
|
|
173
173
|
headers: {
|
|
174
174
|
'content-type': 'application/json',
|
|
@@ -179,7 +179,7 @@ export function serverAudits(opts) {
|
|
|
179
179
|
assert('Status code', res.status).toBe(400);
|
|
180
180
|
}),
|
|
181
181
|
audit('SHOULD use 200 status code with errors field on missing {query} parameter when accepting application/json', async () => {
|
|
182
|
-
const res = await fetchFn(opts.url, {
|
|
182
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
183
183
|
method: 'POST',
|
|
184
184
|
headers: {
|
|
185
185
|
'content-type': 'application/json',
|
|
@@ -193,7 +193,7 @@ export function serverAudits(opts) {
|
|
|
193
193
|
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => audit(
|
|
194
194
|
// TODO: convert to MUST after watershed
|
|
195
195
|
`SHOULD use 400 status code on ${extendedTypeof(invalid)} {query} parameter when accepting application/graphql-response+json`, async () => {
|
|
196
|
-
const res = await fetchFn(opts.url, {
|
|
196
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
197
197
|
method: 'POST',
|
|
198
198
|
headers: {
|
|
199
199
|
'content-type': 'application/json',
|
|
@@ -206,7 +206,7 @@ export function serverAudits(opts) {
|
|
|
206
206
|
assert('Status code', res.status).toBe(400);
|
|
207
207
|
})),
|
|
208
208
|
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => audit(`SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {query} parameter when accepting application/json`, async () => {
|
|
209
|
-
const res = await fetchFn(opts.url, {
|
|
209
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
210
210
|
method: 'POST',
|
|
211
211
|
headers: {
|
|
212
212
|
'content-type': 'application/json',
|
|
@@ -222,7 +222,7 @@ export function serverAudits(opts) {
|
|
|
222
222
|
audit(
|
|
223
223
|
// TODO: convert to MUST after watershed
|
|
224
224
|
'SHOULD allow string {query} parameter when accepting application/graphql-response+json', async () => {
|
|
225
|
-
const res = await fetchFn(opts.url, {
|
|
225
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
226
226
|
method: 'POST',
|
|
227
227
|
headers: {
|
|
228
228
|
'content-type': 'application/json',
|
|
@@ -235,7 +235,7 @@ export function serverAudits(opts) {
|
|
|
235
235
|
assert('Status code', res.status).toBe(200);
|
|
236
236
|
}),
|
|
237
237
|
audit('MUST allow string {query} parameter when accepting application/json', async () => {
|
|
238
|
-
const res = await fetchFn(opts.url, {
|
|
238
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
239
239
|
method: 'POST',
|
|
240
240
|
headers: {
|
|
241
241
|
'content-type': 'application/json',
|
|
@@ -251,7 +251,7 @@ export function serverAudits(opts) {
|
|
|
251
251
|
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => audit(
|
|
252
252
|
// TODO: convert to MUST after watershed
|
|
253
253
|
`SHOULD use 400 status code on ${extendedTypeof(invalid)} {operationName} parameter when accepting application/graphql-response+json`, async () => {
|
|
254
|
-
const res = await fetchFn(opts.url, {
|
|
254
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
255
255
|
method: 'POST',
|
|
256
256
|
headers: {
|
|
257
257
|
'content-type': 'application/json',
|
|
@@ -265,7 +265,7 @@ export function serverAudits(opts) {
|
|
|
265
265
|
assert('Status code', res.status).toBe(400);
|
|
266
266
|
})),
|
|
267
267
|
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => audit(`SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {operationName} parameter when accepting application/json`, async () => {
|
|
268
|
-
const res = await fetchFn(opts.url, {
|
|
268
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
269
269
|
method: 'POST',
|
|
270
270
|
headers: {
|
|
271
271
|
'content-type': 'application/json',
|
|
@@ -282,7 +282,7 @@ export function serverAudits(opts) {
|
|
|
282
282
|
audit(
|
|
283
283
|
// TODO: convert to MUST after watershed
|
|
284
284
|
'SHOULD allow string {operationName} parameter when accepting application/graphql-response+json', async () => {
|
|
285
|
-
const res = await fetchFn(opts.url, {
|
|
285
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
286
286
|
method: 'POST',
|
|
287
287
|
headers: {
|
|
288
288
|
'content-type': 'application/json',
|
|
@@ -296,7 +296,7 @@ export function serverAudits(opts) {
|
|
|
296
296
|
assert('Status code', res.status).toBe(200);
|
|
297
297
|
}),
|
|
298
298
|
audit('MUST allow string {operationName} parameter when accepting application/json', async () => {
|
|
299
|
-
const res = await fetchFn(opts.url, {
|
|
299
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
300
300
|
method: 'POST',
|
|
301
301
|
headers: {
|
|
302
302
|
'content-type': 'application/json',
|
|
@@ -313,7 +313,7 @@ export function serverAudits(opts) {
|
|
|
313
313
|
...['string', 0, false, ['array']].map((invalid) => audit(
|
|
314
314
|
// TODO: convert to MUST after watershed
|
|
315
315
|
`SHOULD use 400 status code on ${extendedTypeof(invalid)} {variables} parameter when accepting application/graphql-response+json`, async () => {
|
|
316
|
-
const res = await fetchFn(opts.url, {
|
|
316
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
317
317
|
method: 'POST',
|
|
318
318
|
headers: {
|
|
319
319
|
'content-type': 'application/json',
|
|
@@ -327,7 +327,7 @@ export function serverAudits(opts) {
|
|
|
327
327
|
assert('Status code', res.status).toBe(400);
|
|
328
328
|
})),
|
|
329
329
|
...['string', 0, false, ['array']].map((invalid) => audit(`SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {variables} parameter when accepting application/json`, async () => {
|
|
330
|
-
const res = await fetchFn(opts.url, {
|
|
330
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
331
331
|
method: 'POST',
|
|
332
332
|
headers: {
|
|
333
333
|
'content-type': 'application/json',
|
|
@@ -344,7 +344,7 @@ export function serverAudits(opts) {
|
|
|
344
344
|
audit(
|
|
345
345
|
// TODO: convert to MUST after watershed
|
|
346
346
|
'SHOULD allow map {variables} parameter when accepting application/graphql-response+json', async () => {
|
|
347
|
-
const res = await fetchFn(opts.url, {
|
|
347
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
348
348
|
method: 'POST',
|
|
349
349
|
headers: {
|
|
350
350
|
'content-type': 'application/json',
|
|
@@ -358,7 +358,7 @@ export function serverAudits(opts) {
|
|
|
358
358
|
assert('Status code', res.status).toBe(200);
|
|
359
359
|
}),
|
|
360
360
|
audit('MUST allow map {variables} parameter when accepting application/json', async () => {
|
|
361
|
-
const res = await fetchFn(opts.url, {
|
|
361
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
362
362
|
method: 'POST',
|
|
363
363
|
headers: {
|
|
364
364
|
'content-type': 'application/json',
|
|
@@ -373,7 +373,7 @@ export function serverAudits(opts) {
|
|
|
373
373
|
assert('Execution result', await assertBodyAsExecutionResult(res)).notToHaveProperty('errors');
|
|
374
374
|
}),
|
|
375
375
|
audit('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json', async () => {
|
|
376
|
-
const url = new URL(opts.url);
|
|
376
|
+
const url = new URL(await getUrl(opts.url));
|
|
377
377
|
url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
|
|
378
378
|
url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
|
|
379
379
|
const res = await fetchFn(url.toString(), {
|
|
@@ -385,7 +385,7 @@ export function serverAudits(opts) {
|
|
|
385
385
|
assert('Status code', res.status).toBe(200);
|
|
386
386
|
}),
|
|
387
387
|
audit('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json', async () => {
|
|
388
|
-
const url = new URL(opts.url);
|
|
388
|
+
const url = new URL(await getUrl(opts.url));
|
|
389
389
|
url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
|
|
390
390
|
url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
|
|
391
391
|
const res = await fetchFn(url.toString(), {
|
|
@@ -400,7 +400,7 @@ export function serverAudits(opts) {
|
|
|
400
400
|
...['string', 0, false, ['array']].map((invalid) => audit(
|
|
401
401
|
// TODO: convert to MUST after watershed
|
|
402
402
|
`SHOULD use 400 status code on ${extendedTypeof(invalid)} {extensions} parameter when accepting application/graphql-response+json`, async () => {
|
|
403
|
-
const res = await fetchFn(opts.url, {
|
|
403
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
404
404
|
method: 'POST',
|
|
405
405
|
headers: {
|
|
406
406
|
'content-type': 'application/json',
|
|
@@ -414,7 +414,7 @@ export function serverAudits(opts) {
|
|
|
414
414
|
assert('Status code', res.status).toBe(400);
|
|
415
415
|
})),
|
|
416
416
|
...['string', 0, false, ['array']].map((invalid) => audit(`SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {extensions} parameter when accepting application/json`, async () => {
|
|
417
|
-
const res = await fetchFn(opts.url, {
|
|
417
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
418
418
|
method: 'POST',
|
|
419
419
|
headers: {
|
|
420
420
|
'content-type': 'application/json',
|
|
@@ -431,7 +431,7 @@ export function serverAudits(opts) {
|
|
|
431
431
|
audit(
|
|
432
432
|
// TODO: convert to MUST after watershed
|
|
433
433
|
'SHOULD allow map {extensions} parameter when accepting application/graphql-response+json', async () => {
|
|
434
|
-
const res = await fetchFn(opts.url, {
|
|
434
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
435
435
|
method: 'POST',
|
|
436
436
|
headers: {
|
|
437
437
|
'content-type': 'application/json',
|
|
@@ -445,7 +445,7 @@ export function serverAudits(opts) {
|
|
|
445
445
|
assert('Status code', res.status).toBe(200);
|
|
446
446
|
}),
|
|
447
447
|
audit('MUST allow map {extensions} parameter when accepting application/json', async () => {
|
|
448
|
-
const res = await fetchFn(opts.url, {
|
|
448
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
449
449
|
method: 'POST',
|
|
450
450
|
headers: {
|
|
451
451
|
'content-type': 'application/json',
|
|
@@ -462,7 +462,7 @@ export function serverAudits(opts) {
|
|
|
462
462
|
// TODO: audit('MUST accept a map for the {extensions} parameter'),
|
|
463
463
|
// Response application/json
|
|
464
464
|
audit('SHOULD use 200 status code on JSON parsing failure when accepting application/json', async () => {
|
|
465
|
-
const res = await fetchFn(opts.url, {
|
|
465
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
466
466
|
method: 'POST',
|
|
467
467
|
headers: {
|
|
468
468
|
'content-type': 'application/json',
|
|
@@ -473,7 +473,7 @@ export function serverAudits(opts) {
|
|
|
473
473
|
assert('Status code', res.status).toBe(200);
|
|
474
474
|
}),
|
|
475
475
|
audit('SHOULD use 200 status code if parameters are invalid when accepting application/json', async () => {
|
|
476
|
-
const res = await fetchFn(opts.url, {
|
|
476
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
477
477
|
method: 'POST',
|
|
478
478
|
headers: {
|
|
479
479
|
'content-type': 'application/json',
|
|
@@ -486,7 +486,7 @@ export function serverAudits(opts) {
|
|
|
486
486
|
assert('Status code', res.status).toBe(200);
|
|
487
487
|
}),
|
|
488
488
|
audit('SHOULD use 200 status code on document parsing failure when accepting application/json', async () => {
|
|
489
|
-
const res = await fetchFn(opts.url, {
|
|
489
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
490
490
|
method: 'POST',
|
|
491
491
|
headers: {
|
|
492
492
|
'content-type': 'application/json',
|
|
@@ -497,7 +497,7 @@ export function serverAudits(opts) {
|
|
|
497
497
|
assert('Status code', res.status).toBe(200);
|
|
498
498
|
}),
|
|
499
499
|
audit('SHOULD use 200 status code on document validation failure when accepting application/json', async () => {
|
|
500
|
-
const res = await fetchFn(opts.url, {
|
|
500
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
501
501
|
method: 'POST',
|
|
502
502
|
headers: {
|
|
503
503
|
'content-type': 'application/json',
|
|
@@ -513,7 +513,7 @@ export function serverAudits(opts) {
|
|
|
513
513
|
audit(
|
|
514
514
|
// TODO: convert to MUST after watershed
|
|
515
515
|
'SHOULD use 4xx or 5xx status codes on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
516
|
-
const res = await fetchFn(opts.url, {
|
|
516
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
517
517
|
method: 'POST',
|
|
518
518
|
headers: {
|
|
519
519
|
'content-type': 'application/json',
|
|
@@ -524,7 +524,7 @@ export function serverAudits(opts) {
|
|
|
524
524
|
assert('Status code', res.status).toBeBetween(400, 499);
|
|
525
525
|
}),
|
|
526
526
|
audit('SHOULD use 400 status code on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
527
|
-
const res = await fetchFn(opts.url, {
|
|
527
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
528
528
|
method: 'POST',
|
|
529
529
|
headers: {
|
|
530
530
|
'content-type': 'application/json',
|
|
@@ -535,7 +535,7 @@ export function serverAudits(opts) {
|
|
|
535
535
|
assert('Status code', res.status).toBe(400);
|
|
536
536
|
}),
|
|
537
537
|
audit('SHOULD not contain the data entry on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
538
|
-
const res = await fetchFn(opts.url, {
|
|
538
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
539
539
|
method: 'POST',
|
|
540
540
|
headers: {
|
|
541
541
|
'content-type': 'application/json',
|
|
@@ -548,7 +548,7 @@ export function serverAudits(opts) {
|
|
|
548
548
|
audit(
|
|
549
549
|
// TODO: convert to MUST after watershed
|
|
550
550
|
'SHOULD use 4xx or 5xx status codes if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
551
|
-
const res = await fetchFn(opts.url, {
|
|
551
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
552
552
|
method: 'POST',
|
|
553
553
|
headers: {
|
|
554
554
|
'content-type': 'application/json',
|
|
@@ -561,7 +561,7 @@ export function serverAudits(opts) {
|
|
|
561
561
|
assert('Status code', res.status).toBeBetween(400, 599);
|
|
562
562
|
}),
|
|
563
563
|
audit('SHOULD use 400 status code if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
564
|
-
const res = await fetchFn(opts.url, {
|
|
564
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
565
565
|
method: 'POST',
|
|
566
566
|
headers: {
|
|
567
567
|
'content-type': 'application/json',
|
|
@@ -574,7 +574,7 @@ export function serverAudits(opts) {
|
|
|
574
574
|
assert('Status code', res.status).toBe(400);
|
|
575
575
|
}),
|
|
576
576
|
audit('SHOULD not contain the data entry if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
577
|
-
const res = await fetchFn(opts.url, {
|
|
577
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
578
578
|
method: 'POST',
|
|
579
579
|
headers: {
|
|
580
580
|
'content-type': 'application/json',
|
|
@@ -589,7 +589,7 @@ export function serverAudits(opts) {
|
|
|
589
589
|
audit(
|
|
590
590
|
// TODO: convert to MUST after watershed
|
|
591
591
|
'SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
592
|
-
const res = await fetchFn(opts.url, {
|
|
592
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
593
593
|
method: 'POST',
|
|
594
594
|
headers: {
|
|
595
595
|
'content-type': 'application/json',
|
|
@@ -602,7 +602,7 @@ export function serverAudits(opts) {
|
|
|
602
602
|
assert('Status code', res.status).toBeBetween(400, 599);
|
|
603
603
|
}),
|
|
604
604
|
audit('SHOULD use 400 status code on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
605
|
-
const res = await fetchFn(opts.url, {
|
|
605
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
606
606
|
method: 'POST',
|
|
607
607
|
headers: {
|
|
608
608
|
'content-type': 'application/json',
|
|
@@ -615,7 +615,7 @@ export function serverAudits(opts) {
|
|
|
615
615
|
assert('Status code', res.status).toBe(400);
|
|
616
616
|
}),
|
|
617
617
|
audit('SHOULD not contain the data entry on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
618
|
-
const res = await fetchFn(opts.url, {
|
|
618
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
619
619
|
method: 'POST',
|
|
620
620
|
headers: {
|
|
621
621
|
'content-type': 'application/json',
|
|
@@ -630,7 +630,7 @@ export function serverAudits(opts) {
|
|
|
630
630
|
audit(
|
|
631
631
|
// TODO: convert to MUST after watershed
|
|
632
632
|
'SHOULD use 4xx or 5xx status codes on document validation failure when accepting application/graphql-response+json', async () => {
|
|
633
|
-
const res = await fetchFn(opts.url, {
|
|
633
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
634
634
|
method: 'POST',
|
|
635
635
|
headers: {
|
|
636
636
|
'content-type': 'application/json',
|
|
@@ -643,7 +643,7 @@ export function serverAudits(opts) {
|
|
|
643
643
|
assert('Status code', res.status).toBeBetween(400, 599);
|
|
644
644
|
}),
|
|
645
645
|
audit('SHOULD use 400 status code on document validation failure when accepting application/graphql-response+json', async () => {
|
|
646
|
-
const res = await fetchFn(opts.url, {
|
|
646
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
647
647
|
method: 'POST',
|
|
648
648
|
headers: {
|
|
649
649
|
'content-type': 'application/json',
|
|
@@ -656,7 +656,7 @@ export function serverAudits(opts) {
|
|
|
656
656
|
assert('Status code', res.status).toBe(400);
|
|
657
657
|
}),
|
|
658
658
|
audit('SHOULD not contain the data entry on document validation failure when accepting application/graphql-response+json', async () => {
|
|
659
|
-
const res = await fetchFn(opts.url, {
|
|
659
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
660
660
|
method: 'POST',
|
|
661
661
|
headers: {
|
|
662
662
|
'content-type': 'application/json',
|
|
@@ -687,3 +687,10 @@ export async function auditServer(opts) {
|
|
|
687
687
|
// audit tests will throw only on fatal errors, tests are contained within the AuditResult
|
|
688
688
|
return await Promise.all(audits.map(({ fn }) => fn()));
|
|
689
689
|
}
|
|
690
|
+
/** @private */
|
|
691
|
+
async function getUrl(url) {
|
|
692
|
+
if (typeof url === 'string') {
|
|
693
|
+
return url;
|
|
694
|
+
}
|
|
695
|
+
return await url();
|
|
696
|
+
}
|
package/package.json
CHANGED
|
Binary file
|