graphql-http 1.11.0 → 1.13.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/README.md +15 -7
- package/lib/audits/common.d.mts +16 -0
- package/lib/audits/common.d.ts +16 -0
- package/lib/audits/server.js +126 -149
- package/lib/audits/server.mjs +127 -150
- package/lib/audits/utils.d.mts +35 -16
- package/lib/audits/utils.d.ts +35 -16
- package/lib/audits/utils.js +90 -59
- package/lib/audits/utils.mjs +88 -57
- package/lib/handler.js +24 -25
- package/lib/handler.mjs +25 -26
- package/lib/utils.d.mts +4 -1
- package/lib/utils.d.ts +4 -1
- package/lib/utils.js +9 -4
- package/lib/utils.mjs +7 -3
- package/package.json +20 -20
- package/umd/graphql-http.js +2 -2
- package/umd/graphql-http.min.js +1 -1
- package/umd/graphql-http.min.js.gz +0 -0
package/lib/audits/server.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* audit/server
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { ressert, audit, extendedTypeof, AuditError } from './utils.mjs';
|
|
7
7
|
/**
|
|
8
8
|
* List of server audits required to check GraphQL over HTTP spec conformance.
|
|
9
9
|
*
|
|
@@ -15,7 +15,7 @@ export function serverAudits(opts) {
|
|
|
15
15
|
// Media Types
|
|
16
16
|
audit(
|
|
17
17
|
// TODO: convert to MUST after watershed
|
|
18
|
-
'SHOULD accept application/graphql-response+json and match the content-type', async () => {
|
|
18
|
+
'22EB', 'SHOULD accept application/graphql-response+json and match the content-type', async () => {
|
|
19
19
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
20
20
|
method: 'POST',
|
|
21
21
|
headers: {
|
|
@@ -24,10 +24,12 @@ export function serverAudits(opts) {
|
|
|
24
24
|
},
|
|
25
25
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
26
26
|
});
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
ressert(res).status.toBe(200);
|
|
28
|
+
ressert(res)
|
|
29
|
+
.header('content-type')
|
|
30
|
+
.toContain('application/graphql-response+json');
|
|
29
31
|
}),
|
|
30
|
-
audit('MUST accept application/json and match the content-type', async () => {
|
|
32
|
+
audit('4655', 'MUST accept application/json and match the content-type', async () => {
|
|
31
33
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
32
34
|
method: 'POST',
|
|
33
35
|
headers: {
|
|
@@ -36,10 +38,10 @@ export function serverAudits(opts) {
|
|
|
36
38
|
},
|
|
37
39
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
38
40
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
ressert(res).status.toBe(200);
|
|
42
|
+
ressert(res).header('content-type').toContain('application/json');
|
|
41
43
|
}),
|
|
42
|
-
audit('SHOULD accept */* and use application/json for the content-type', async () => {
|
|
44
|
+
audit('47DE', 'SHOULD accept */* and use application/json for the content-type', async () => {
|
|
43
45
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
44
46
|
method: 'POST',
|
|
45
47
|
headers: {
|
|
@@ -48,17 +50,17 @@ export function serverAudits(opts) {
|
|
|
48
50
|
},
|
|
49
51
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
50
52
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
ressert(res).status.toBe(200);
|
|
54
|
+
ressert(res).header('content-type').toContain('application/json');
|
|
53
55
|
}),
|
|
54
|
-
audit('SHOULD assume application/json content-type when accept is missing', async () => {
|
|
56
|
+
audit('80D8', 'SHOULD assume application/json content-type when accept is missing', async () => {
|
|
55
57
|
const url = new URL(await getUrl(opts.url));
|
|
56
58
|
url.searchParams.set('query', '{ __typename }');
|
|
57
59
|
const res = await fetchFn(url.toString());
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
ressert(res).status.toBe(200);
|
|
61
|
+
ressert(res).header('content-type').toContain('application/json');
|
|
60
62
|
}),
|
|
61
|
-
audit('MUST use utf-8 encoding when responding', async () => {
|
|
63
|
+
audit('82A3', 'MUST use utf-8 encoding when responding', async () => {
|
|
62
64
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
63
65
|
method: 'POST',
|
|
64
66
|
headers: {
|
|
@@ -66,28 +68,16 @@ export function serverAudits(opts) {
|
|
|
66
68
|
},
|
|
67
69
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
68
70
|
});
|
|
69
|
-
|
|
70
|
-
// has charset set to utf-8
|
|
71
|
-
try {
|
|
72
|
-
assert('Content-Type header', res.headers.get('content-type')).toContain('charset=utf-8');
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
catch (_a) {
|
|
76
|
-
// noop, continue
|
|
77
|
-
}
|
|
78
|
-
// has no charset specified
|
|
79
|
-
assert('Content-Type header', res.headers.get('content-type')).notToContain('charset');
|
|
80
|
-
// and the content is utf-8 encoded
|
|
71
|
+
ressert(res).status.toBe(200);
|
|
81
72
|
try {
|
|
82
73
|
const decoder = new TextDecoder('utf-8');
|
|
83
|
-
|
|
84
|
-
assert('UTF-8 decoded body', decoded).toBe('{"data":{"__typename":"Query"}}');
|
|
74
|
+
decoder.decode(await res.arrayBuffer());
|
|
85
75
|
}
|
|
86
|
-
catch (
|
|
87
|
-
throw '
|
|
76
|
+
catch (_a) {
|
|
77
|
+
throw new AuditError(res, 'Response body is not UTF-8 encoded');
|
|
88
78
|
}
|
|
89
79
|
}),
|
|
90
|
-
audit('MUST accept utf-8
|
|
80
|
+
audit('BF61', 'MUST accept utf-8 encoded request', async () => {
|
|
91
81
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
92
82
|
method: 'POST',
|
|
93
83
|
headers: {
|
|
@@ -95,10 +85,9 @@ export function serverAudits(opts) {
|
|
|
95
85
|
},
|
|
96
86
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
97
87
|
});
|
|
98
|
-
|
|
99
|
-
assert('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
|
|
88
|
+
ressert(res).status.toBe(200);
|
|
100
89
|
}),
|
|
101
|
-
audit('MUST assume utf-8 if encoding is unspecified', async () => {
|
|
90
|
+
audit('78D5', 'MUST assume utf-8 in request if encoding is unspecified', async () => {
|
|
102
91
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
103
92
|
method: 'POST',
|
|
104
93
|
headers: {
|
|
@@ -106,27 +95,26 @@ export function serverAudits(opts) {
|
|
|
106
95
|
},
|
|
107
96
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
108
97
|
});
|
|
109
|
-
|
|
110
|
-
assert('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
|
|
98
|
+
ressert(res).status.toBe(200);
|
|
111
99
|
}),
|
|
112
100
|
// Request
|
|
113
|
-
audit('MUST accept POST requests', async () => {
|
|
101
|
+
audit('2C94', 'MUST accept POST requests', async () => {
|
|
114
102
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
115
103
|
method: 'POST',
|
|
116
104
|
headers: { 'content-type': 'application/json' },
|
|
117
105
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
118
106
|
});
|
|
119
|
-
|
|
107
|
+
ressert(res).status.toBe(200);
|
|
120
108
|
}),
|
|
121
|
-
audit('MAY accept application/x-www-form-urlencoded formatted GET requests', async () => {
|
|
109
|
+
audit('5A70', 'MAY accept application/x-www-form-urlencoded formatted GET requests', async () => {
|
|
122
110
|
const url = new URL(await getUrl(opts.url));
|
|
123
111
|
url.searchParams.set('query', '{ __typename }');
|
|
124
112
|
const res = await fetchFn(url.toString());
|
|
125
|
-
|
|
113
|
+
ressert(res).status.toBe(200);
|
|
126
114
|
}),
|
|
127
115
|
// Request GET
|
|
128
116
|
// TODO: this is a MUST if the server supports GET requests
|
|
129
|
-
audit('MAY NOT allow executing mutations on GET requests', async () => {
|
|
117
|
+
audit('9C48', 'MAY NOT allow executing mutations on GET requests', async () => {
|
|
130
118
|
const url = new URL(await getUrl(opts.url));
|
|
131
119
|
url.searchParams.set('query', 'mutation { __typename }');
|
|
132
120
|
const res = await fetchFn(url.toString(), {
|
|
@@ -134,40 +122,40 @@ export function serverAudits(opts) {
|
|
|
134
122
|
accept: 'application/graphql-response+json',
|
|
135
123
|
},
|
|
136
124
|
});
|
|
137
|
-
|
|
125
|
+
ressert(res).status.toBeBetween(400, 499);
|
|
138
126
|
}),
|
|
139
127
|
// Request POST
|
|
140
|
-
audit('SHOULD respond with 4xx status code if content-type is not supplied on POST requests', async () => {
|
|
128
|
+
audit('9ABE', 'SHOULD respond with 4xx status code if content-type is not supplied on POST requests', async () => {
|
|
141
129
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
142
130
|
method: 'POST',
|
|
143
131
|
});
|
|
144
|
-
|
|
132
|
+
ressert(res).status.toBeBetween(400, 499);
|
|
145
133
|
}),
|
|
146
|
-
audit('MUST accept application/json POST requests', async () => {
|
|
134
|
+
audit('03D4', 'MUST accept application/json POST requests', async () => {
|
|
147
135
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
148
136
|
method: 'POST',
|
|
149
137
|
headers: { 'content-type': 'application/json' },
|
|
150
138
|
body: JSON.stringify({ query: '{ __typename }' }),
|
|
151
139
|
});
|
|
152
|
-
|
|
140
|
+
ressert(res).status.toBe(200);
|
|
153
141
|
}),
|
|
154
|
-
audit('MUST require a request body on POST', async () => {
|
|
142
|
+
audit('7267', 'MUST require a request body on POST', async () => {
|
|
155
143
|
var _a;
|
|
156
144
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
157
145
|
method: 'POST',
|
|
158
146
|
headers: { 'content-type': 'application/json' },
|
|
159
147
|
});
|
|
160
148
|
if ((_a = res.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.includes('application/json')) {
|
|
161
|
-
|
|
149
|
+
await ressert(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
162
150
|
}
|
|
163
151
|
else {
|
|
164
|
-
|
|
152
|
+
ressert(res).status.toBe(400);
|
|
165
153
|
}
|
|
166
154
|
}),
|
|
167
155
|
// Request Parameters
|
|
168
156
|
audit(
|
|
169
157
|
// TODO: convert to MUST after watershed
|
|
170
|
-
'SHOULD use 400 status code on missing {query} parameter when accepting application/graphql-response+json', async () => {
|
|
158
|
+
'6610', 'SHOULD use 400 status code on missing {query} parameter when accepting application/graphql-response+json', async () => {
|
|
171
159
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
172
160
|
method: 'POST',
|
|
173
161
|
headers: {
|
|
@@ -176,9 +164,9 @@ export function serverAudits(opts) {
|
|
|
176
164
|
},
|
|
177
165
|
body: JSON.stringify({ notquery: '{ __typename }' }),
|
|
178
166
|
});
|
|
179
|
-
|
|
167
|
+
ressert(res).status.toBe(400);
|
|
180
168
|
}),
|
|
181
|
-
audit('SHOULD use 200 status code with errors field on missing {query} parameter when accepting application/json', async () => {
|
|
169
|
+
audit('3715', 'SHOULD use 200 status code with errors field on missing {query} parameter when accepting application/json', async () => {
|
|
182
170
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
183
171
|
method: 'POST',
|
|
184
172
|
headers: {
|
|
@@ -187,10 +175,10 @@ export function serverAudits(opts) {
|
|
|
187
175
|
},
|
|
188
176
|
body: JSON.stringify({ notquery: '{ __typename }' }),
|
|
189
177
|
});
|
|
190
|
-
|
|
191
|
-
|
|
178
|
+
ressert(res).status.toBe(200);
|
|
179
|
+
await ressert(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
192
180
|
}),
|
|
193
|
-
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => audit(
|
|
181
|
+
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid, index) => audit(`4F5${index}`,
|
|
194
182
|
// TODO: convert to MUST after watershed
|
|
195
183
|
`SHOULD use 400 status code on ${extendedTypeof(invalid)} {query} parameter when accepting application/graphql-response+json`, async () => {
|
|
196
184
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
@@ -203,9 +191,9 @@ export function serverAudits(opts) {
|
|
|
203
191
|
query: invalid,
|
|
204
192
|
}),
|
|
205
193
|
});
|
|
206
|
-
|
|
194
|
+
ressert(res).status.toBe(400);
|
|
207
195
|
})),
|
|
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 () => {
|
|
196
|
+
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid, index) => audit(`9FE${index}`, `SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {query} parameter when accepting application/json`, async () => {
|
|
209
197
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
210
198
|
method: 'POST',
|
|
211
199
|
headers: {
|
|
@@ -216,12 +204,12 @@ export function serverAudits(opts) {
|
|
|
216
204
|
query: invalid,
|
|
217
205
|
}),
|
|
218
206
|
});
|
|
219
|
-
|
|
220
|
-
|
|
207
|
+
ressert(res).status.toBe(200);
|
|
208
|
+
await ressert(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
221
209
|
})),
|
|
222
210
|
audit(
|
|
223
211
|
// TODO: convert to MUST after watershed
|
|
224
|
-
'SHOULD allow string {query} parameter when accepting application/graphql-response+json', async () => {
|
|
212
|
+
'34A2', 'SHOULD allow string {query} parameter when accepting application/graphql-response+json', async () => {
|
|
225
213
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
226
214
|
method: 'POST',
|
|
227
215
|
headers: {
|
|
@@ -232,9 +220,9 @@ export function serverAudits(opts) {
|
|
|
232
220
|
query: '{ __typename }',
|
|
233
221
|
}),
|
|
234
222
|
});
|
|
235
|
-
|
|
223
|
+
ressert(res).status.toBe(200);
|
|
236
224
|
}),
|
|
237
|
-
audit('MUST allow string {query} parameter when accepting application/json', async () => {
|
|
225
|
+
audit('13EE', 'MUST allow string {query} parameter when accepting application/json', async () => {
|
|
238
226
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
239
227
|
method: 'POST',
|
|
240
228
|
headers: {
|
|
@@ -245,10 +233,10 @@ export function serverAudits(opts) {
|
|
|
245
233
|
query: '{ __typename }',
|
|
246
234
|
}),
|
|
247
235
|
});
|
|
248
|
-
|
|
249
|
-
|
|
236
|
+
ressert(res).status.toBe(200);
|
|
237
|
+
await ressert(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
250
238
|
}),
|
|
251
|
-
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => audit(
|
|
239
|
+
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid, index) => audit(`E3E${index}`,
|
|
252
240
|
// TODO: convert to MUST after watershed
|
|
253
241
|
`SHOULD use 400 status code on ${extendedTypeof(invalid)} {operationName} parameter when accepting application/graphql-response+json`, async () => {
|
|
254
242
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
@@ -262,9 +250,9 @@ export function serverAudits(opts) {
|
|
|
262
250
|
query: '{ __typename }',
|
|
263
251
|
}),
|
|
264
252
|
});
|
|
265
|
-
|
|
253
|
+
ressert(res).status.toBe(400);
|
|
266
254
|
})),
|
|
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 () => {
|
|
255
|
+
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid, index) => audit(`FB9${index}`, `SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {operationName} parameter when accepting application/json`, async () => {
|
|
268
256
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
269
257
|
method: 'POST',
|
|
270
258
|
headers: {
|
|
@@ -276,12 +264,12 @@ export function serverAudits(opts) {
|
|
|
276
264
|
query: '{ __typename }',
|
|
277
265
|
}),
|
|
278
266
|
});
|
|
279
|
-
|
|
280
|
-
|
|
267
|
+
ressert(res).status.toBe(200);
|
|
268
|
+
await ressert(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
281
269
|
})),
|
|
282
270
|
audit(
|
|
283
271
|
// TODO: convert to MUST after watershed
|
|
284
|
-
'SHOULD allow string {operationName} parameter when accepting application/graphql-response+json', async () => {
|
|
272
|
+
'8161', 'SHOULD allow string {operationName} parameter when accepting application/graphql-response+json', async () => {
|
|
285
273
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
286
274
|
method: 'POST',
|
|
287
275
|
headers: {
|
|
@@ -293,9 +281,9 @@ export function serverAudits(opts) {
|
|
|
293
281
|
query: 'query Query { __typename }',
|
|
294
282
|
}),
|
|
295
283
|
});
|
|
296
|
-
|
|
284
|
+
ressert(res).status.toBe(200);
|
|
297
285
|
}),
|
|
298
|
-
audit('MUST allow string {operationName} parameter when accepting application/json', async () => {
|
|
286
|
+
audit('B8B3', 'MUST allow string {operationName} parameter when accepting application/json', async () => {
|
|
299
287
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
300
288
|
method: 'POST',
|
|
301
289
|
headers: {
|
|
@@ -307,11 +295,11 @@ export function serverAudits(opts) {
|
|
|
307
295
|
query: 'query Query { __typename }',
|
|
308
296
|
}),
|
|
309
297
|
});
|
|
310
|
-
|
|
311
|
-
|
|
298
|
+
ressert(res).status.toBe(200);
|
|
299
|
+
await ressert(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
312
300
|
}),
|
|
313
|
-
...['variables', 'operationName', 'extensions'].flatMap((parameter) => [
|
|
314
|
-
audit(
|
|
301
|
+
...['variables', 'operationName', 'extensions'].flatMap((parameter, index) => [
|
|
302
|
+
audit(`94B${index}`,
|
|
315
303
|
// TODO: convert to MUST after watershed
|
|
316
304
|
`SHOULD allow null {${parameter}} parameter when accepting application/graphql-response+json`, async () => {
|
|
317
305
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
@@ -325,10 +313,10 @@ export function serverAudits(opts) {
|
|
|
325
313
|
[parameter]: null,
|
|
326
314
|
}),
|
|
327
315
|
});
|
|
328
|
-
|
|
329
|
-
|
|
316
|
+
ressert(res).status.toBe(200);
|
|
317
|
+
await ressert(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
330
318
|
}),
|
|
331
|
-
audit(`MUST allow null {${parameter}} parameter when accepting application/json`, async () => {
|
|
319
|
+
audit(`022${index}`, `MUST allow null {${parameter}} parameter when accepting application/json`, async () => {
|
|
332
320
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
333
321
|
method: 'POST',
|
|
334
322
|
headers: {
|
|
@@ -340,11 +328,11 @@ export function serverAudits(opts) {
|
|
|
340
328
|
[parameter]: null,
|
|
341
329
|
}),
|
|
342
330
|
});
|
|
343
|
-
|
|
344
|
-
|
|
331
|
+
ressert(res).status.toBe(200);
|
|
332
|
+
await ressert(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
345
333
|
}),
|
|
346
334
|
]),
|
|
347
|
-
...['string', 0, false, ['array']].map((invalid) => audit(
|
|
335
|
+
...['string', 0, false, ['array']].map((invalid, index) => audit(`69B${index}`,
|
|
348
336
|
// TODO: convert to MUST after watershed
|
|
349
337
|
`SHOULD use 400 status code on ${extendedTypeof(invalid)} {variables} parameter when accepting application/graphql-response+json`, async () => {
|
|
350
338
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
@@ -358,9 +346,9 @@ export function serverAudits(opts) {
|
|
|
358
346
|
variables: invalid,
|
|
359
347
|
}),
|
|
360
348
|
});
|
|
361
|
-
|
|
349
|
+
ressert(res).status.toBe(400);
|
|
362
350
|
})),
|
|
363
|
-
...['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 () => {
|
|
351
|
+
...['string', 0, false, ['array']].map((invalid, index) => audit(`F05${index}`, `SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {variables} parameter when accepting application/json`, async () => {
|
|
364
352
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
365
353
|
method: 'POST',
|
|
366
354
|
headers: {
|
|
@@ -372,12 +360,12 @@ export function serverAudits(opts) {
|
|
|
372
360
|
variables: invalid,
|
|
373
361
|
}),
|
|
374
362
|
});
|
|
375
|
-
|
|
376
|
-
|
|
363
|
+
ressert(res).status.toBe(200);
|
|
364
|
+
await ressert(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
377
365
|
})),
|
|
378
366
|
audit(
|
|
379
367
|
// TODO: convert to MUST after watershed
|
|
380
|
-
'SHOULD allow map {variables} parameter when accepting application/graphql-response+json', async () => {
|
|
368
|
+
'2EA1', 'SHOULD allow map {variables} parameter when accepting application/graphql-response+json', async () => {
|
|
381
369
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
382
370
|
method: 'POST',
|
|
383
371
|
headers: {
|
|
@@ -389,9 +377,9 @@ export function serverAudits(opts) {
|
|
|
389
377
|
variables: { name: 'sometype' },
|
|
390
378
|
}),
|
|
391
379
|
});
|
|
392
|
-
|
|
380
|
+
ressert(res).status.toBe(200);
|
|
393
381
|
}),
|
|
394
|
-
audit('MUST allow map {variables} parameter when accepting application/json', async () => {
|
|
382
|
+
audit('28B9', 'MUST allow map {variables} parameter when accepting application/json', async () => {
|
|
395
383
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
396
384
|
method: 'POST',
|
|
397
385
|
headers: {
|
|
@@ -403,10 +391,10 @@ export function serverAudits(opts) {
|
|
|
403
391
|
variables: { name: 'sometype' },
|
|
404
392
|
}),
|
|
405
393
|
});
|
|
406
|
-
|
|
407
|
-
|
|
394
|
+
ressert(res).status.toBe(200);
|
|
395
|
+
await ressert(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
408
396
|
}),
|
|
409
|
-
audit('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json', async () => {
|
|
397
|
+
audit('D6D5', 'MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json', async () => {
|
|
410
398
|
const url = new URL(await getUrl(opts.url));
|
|
411
399
|
url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
|
|
412
400
|
url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
|
|
@@ -416,9 +404,9 @@ export function serverAudits(opts) {
|
|
|
416
404
|
accept: 'application/graphql-response+json',
|
|
417
405
|
},
|
|
418
406
|
});
|
|
419
|
-
|
|
407
|
+
ressert(res).status.toBe(200);
|
|
420
408
|
}),
|
|
421
|
-
audit('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json', async () => {
|
|
409
|
+
audit('6A70', 'MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json', async () => {
|
|
422
410
|
const url = new URL(await getUrl(opts.url));
|
|
423
411
|
url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
|
|
424
412
|
url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
|
|
@@ -428,10 +416,10 @@ export function serverAudits(opts) {
|
|
|
428
416
|
accept: 'application/json',
|
|
429
417
|
},
|
|
430
418
|
});
|
|
431
|
-
|
|
432
|
-
|
|
419
|
+
ressert(res).status.toBe(200);
|
|
420
|
+
await ressert(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
433
421
|
}),
|
|
434
|
-
...['string', 0, false, ['array']].map((invalid) => audit(
|
|
422
|
+
...['string', 0, false, ['array']].map((invalid, index) => audit(`904${index}`,
|
|
435
423
|
// TODO: convert to MUST after watershed
|
|
436
424
|
`SHOULD use 400 status code on ${extendedTypeof(invalid)} {extensions} parameter when accepting application/graphql-response+json`, async () => {
|
|
437
425
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
@@ -445,9 +433,9 @@ export function serverAudits(opts) {
|
|
|
445
433
|
extensions: invalid,
|
|
446
434
|
}),
|
|
447
435
|
});
|
|
448
|
-
|
|
436
|
+
ressert(res).status.toBe(400);
|
|
449
437
|
})),
|
|
450
|
-
...['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 () => {
|
|
438
|
+
...['string', 0, false, ['array']].map((invalid, index) => audit(`368${index}`, `SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {extensions} parameter when accepting application/json`, async () => {
|
|
451
439
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
452
440
|
method: 'POST',
|
|
453
441
|
headers: {
|
|
@@ -459,12 +447,12 @@ export function serverAudits(opts) {
|
|
|
459
447
|
extensions: invalid,
|
|
460
448
|
}),
|
|
461
449
|
});
|
|
462
|
-
|
|
463
|
-
|
|
450
|
+
ressert(res).status.toBe(200);
|
|
451
|
+
await ressert(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
464
452
|
})),
|
|
465
453
|
audit(
|
|
466
454
|
// TODO: convert to MUST after watershed
|
|
467
|
-
'SHOULD allow map {extensions} parameter when accepting application/graphql-response+json', async () => {
|
|
455
|
+
'428F', 'SHOULD allow map {extensions} parameter when accepting application/graphql-response+json', async () => {
|
|
468
456
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
469
457
|
method: 'POST',
|
|
470
458
|
headers: {
|
|
@@ -476,9 +464,9 @@ export function serverAudits(opts) {
|
|
|
476
464
|
extensions: { some: 'value' },
|
|
477
465
|
}),
|
|
478
466
|
});
|
|
479
|
-
|
|
467
|
+
ressert(res).status.toBe(200);
|
|
480
468
|
}),
|
|
481
|
-
audit('MUST allow map {extensions} parameter when accepting application/json', async () => {
|
|
469
|
+
audit('1B7A', 'MUST allow map {extensions} parameter when accepting application/json', async () => {
|
|
482
470
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
483
471
|
method: 'POST',
|
|
484
472
|
headers: {
|
|
@@ -490,12 +478,12 @@ export function serverAudits(opts) {
|
|
|
490
478
|
extensions: { some: 'value' },
|
|
491
479
|
}),
|
|
492
480
|
});
|
|
493
|
-
|
|
494
|
-
|
|
481
|
+
ressert(res).status.toBe(200);
|
|
482
|
+
await ressert(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
495
483
|
}),
|
|
496
|
-
// TODO: audit('MUST accept a map for the {extensions} parameter'),
|
|
484
|
+
// TODO: audit('39AA', 'MUST accept a map for the {extensions} parameter'),
|
|
497
485
|
// Response application/json
|
|
498
|
-
audit('SHOULD use 200 status code on JSON parsing failure when accepting application/json', async () => {
|
|
486
|
+
audit('D477', 'SHOULD use 200 status code on JSON parsing failure when accepting application/json', async () => {
|
|
499
487
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
500
488
|
method: 'POST',
|
|
501
489
|
headers: {
|
|
@@ -504,9 +492,9 @@ export function serverAudits(opts) {
|
|
|
504
492
|
},
|
|
505
493
|
body: '{ "not a JSON',
|
|
506
494
|
});
|
|
507
|
-
|
|
495
|
+
ressert(res).status.toBe(200);
|
|
508
496
|
}),
|
|
509
|
-
audit('SHOULD use 200 status code if parameters are invalid when accepting application/json', async () => {
|
|
497
|
+
audit('F5AF', 'SHOULD use 200 status code if parameters are invalid when accepting application/json', async () => {
|
|
510
498
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
511
499
|
method: 'POST',
|
|
512
500
|
headers: {
|
|
@@ -517,9 +505,9 @@ export function serverAudits(opts) {
|
|
|
517
505
|
qeury: /* typo */ '{ __typename }',
|
|
518
506
|
}),
|
|
519
507
|
});
|
|
520
|
-
|
|
508
|
+
ressert(res).status.toBe(200);
|
|
521
509
|
}),
|
|
522
|
-
audit('SHOULD use 200 status code on document parsing failure when accepting application/json', async () => {
|
|
510
|
+
audit('572B', 'SHOULD use 200 status code on document parsing failure when accepting application/json', async () => {
|
|
523
511
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
524
512
|
method: 'POST',
|
|
525
513
|
headers: {
|
|
@@ -528,9 +516,9 @@ export function serverAudits(opts) {
|
|
|
528
516
|
},
|
|
529
517
|
body: JSON.stringify({ query: '{' }),
|
|
530
518
|
});
|
|
531
|
-
|
|
519
|
+
ressert(res).status.toBe(200);
|
|
532
520
|
}),
|
|
533
|
-
audit('SHOULD use 200 status code on document validation failure when accepting application/json', async () => {
|
|
521
|
+
audit('FDE2', 'SHOULD use 200 status code on document validation failure when accepting application/json', async () => {
|
|
534
522
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
535
523
|
method: 'POST',
|
|
536
524
|
headers: {
|
|
@@ -541,23 +529,12 @@ export function serverAudits(opts) {
|
|
|
541
529
|
query: '{ 8f31403dfe404bccbb0e835f2629c6a7 }', // making sure the field doesnt exist
|
|
542
530
|
}),
|
|
543
531
|
});
|
|
544
|
-
|
|
532
|
+
ressert(res).status.toBe(200);
|
|
545
533
|
}),
|
|
546
534
|
// Response application/graphql-response+json
|
|
547
535
|
audit(
|
|
548
536
|
// TODO: convert to MUST after watershed
|
|
549
|
-
'SHOULD use 4xx or 5xx status codes on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
550
|
-
const res = await fetchFn(await getUrl(opts.url), {
|
|
551
|
-
method: 'POST',
|
|
552
|
-
headers: {
|
|
553
|
-
'content-type': 'application/json',
|
|
554
|
-
accept: 'application/graphql-response+json',
|
|
555
|
-
},
|
|
556
|
-
body: '{ "not a JSON',
|
|
557
|
-
});
|
|
558
|
-
assert('Status code', res.status).toBeBetween(400, 499);
|
|
559
|
-
}),
|
|
560
|
-
audit('SHOULD use 400 status code on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
537
|
+
'60AA', 'SHOULD use 4xx or 5xx status codes on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
561
538
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
562
539
|
method: 'POST',
|
|
563
540
|
headers: {
|
|
@@ -566,9 +543,9 @@ export function serverAudits(opts) {
|
|
|
566
543
|
},
|
|
567
544
|
body: '{ "not a JSON',
|
|
568
545
|
});
|
|
569
|
-
|
|
546
|
+
ressert(res).status.toBeBetween(400, 499);
|
|
570
547
|
}),
|
|
571
|
-
audit('SHOULD
|
|
548
|
+
audit('2163', 'SHOULD use 400 status code on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
572
549
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
573
550
|
method: 'POST',
|
|
574
551
|
headers: {
|
|
@@ -577,11 +554,11 @@ export function serverAudits(opts) {
|
|
|
577
554
|
},
|
|
578
555
|
body: '{ "not a JSON',
|
|
579
556
|
});
|
|
580
|
-
|
|
557
|
+
ressert(res).status.toBe(400);
|
|
581
558
|
}),
|
|
582
559
|
audit(
|
|
583
560
|
// TODO: convert to MUST after watershed
|
|
584
|
-
'SHOULD use 4xx or 5xx status codes if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
561
|
+
'3E36', 'SHOULD use 4xx or 5xx status codes if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
585
562
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
586
563
|
method: 'POST',
|
|
587
564
|
headers: {
|
|
@@ -592,9 +569,9 @@ export function serverAudits(opts) {
|
|
|
592
569
|
qeury /* typo */: '{ __typename }',
|
|
593
570
|
}),
|
|
594
571
|
});
|
|
595
|
-
|
|
572
|
+
ressert(res).status.toBeBetween(400, 599);
|
|
596
573
|
}),
|
|
597
|
-
audit('SHOULD use 400 status code if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
574
|
+
audit('17C5', 'SHOULD use 400 status code if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
598
575
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
599
576
|
method: 'POST',
|
|
600
577
|
headers: {
|
|
@@ -605,9 +582,9 @@ export function serverAudits(opts) {
|
|
|
605
582
|
qeury: /* typo */ '{ __typename }',
|
|
606
583
|
}),
|
|
607
584
|
});
|
|
608
|
-
|
|
585
|
+
ressert(res).status.toBe(400);
|
|
609
586
|
}),
|
|
610
|
-
audit('SHOULD not contain the data entry if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
587
|
+
audit('34D6', 'SHOULD not contain the data entry if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
611
588
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
612
589
|
method: 'POST',
|
|
613
590
|
headers: {
|
|
@@ -618,11 +595,11 @@ export function serverAudits(opts) {
|
|
|
618
595
|
qeury: /* typo */ '{ __typename }',
|
|
619
596
|
}),
|
|
620
597
|
});
|
|
621
|
-
|
|
598
|
+
await ressert(res).bodyAsExecutionResult.data.toBe(undefined);
|
|
622
599
|
}),
|
|
623
600
|
audit(
|
|
624
601
|
// TODO: convert to MUST after watershed
|
|
625
|
-
'SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
602
|
+
'865D', 'SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
626
603
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
627
604
|
method: 'POST',
|
|
628
605
|
headers: {
|
|
@@ -633,9 +610,9 @@ export function serverAudits(opts) {
|
|
|
633
610
|
query: '{',
|
|
634
611
|
}),
|
|
635
612
|
});
|
|
636
|
-
|
|
613
|
+
ressert(res).status.toBeBetween(400, 599);
|
|
637
614
|
}),
|
|
638
|
-
audit('SHOULD use 400 status code on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
615
|
+
audit('556A', 'SHOULD use 400 status code on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
639
616
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
640
617
|
method: 'POST',
|
|
641
618
|
headers: {
|
|
@@ -646,9 +623,9 @@ export function serverAudits(opts) {
|
|
|
646
623
|
query: '{',
|
|
647
624
|
}),
|
|
648
625
|
});
|
|
649
|
-
|
|
626
|
+
ressert(res).status.toBe(400);
|
|
650
627
|
}),
|
|
651
|
-
audit('SHOULD not contain the data entry on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
628
|
+
audit('D586', 'SHOULD not contain the data entry on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
652
629
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
653
630
|
method: 'POST',
|
|
654
631
|
headers: {
|
|
@@ -659,11 +636,11 @@ export function serverAudits(opts) {
|
|
|
659
636
|
query: '{',
|
|
660
637
|
}),
|
|
661
638
|
});
|
|
662
|
-
|
|
639
|
+
await ressert(res).bodyAsExecutionResult.data.toBe(undefined);
|
|
663
640
|
}),
|
|
664
641
|
audit(
|
|
665
642
|
// TODO: convert to MUST after watershed
|
|
666
|
-
'SHOULD use 4xx or 5xx status codes on document validation failure when accepting application/graphql-response+json', async () => {
|
|
643
|
+
'51FE', 'SHOULD use 4xx or 5xx status codes on document validation failure when accepting application/graphql-response+json', async () => {
|
|
667
644
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
668
645
|
method: 'POST',
|
|
669
646
|
headers: {
|
|
@@ -674,9 +651,9 @@ export function serverAudits(opts) {
|
|
|
674
651
|
query: '{ 8f31403dfe404bccbb0e835f2629c6a7 }', // making sure the field doesnt exist
|
|
675
652
|
}),
|
|
676
653
|
});
|
|
677
|
-
|
|
654
|
+
ressert(res).status.toBeBetween(400, 599);
|
|
678
655
|
}),
|
|
679
|
-
audit('SHOULD use 400 status code on document validation failure when accepting application/graphql-response+json', async () => {
|
|
656
|
+
audit('74FF', 'SHOULD use 400 status code on document validation failure when accepting application/graphql-response+json', async () => {
|
|
680
657
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
681
658
|
method: 'POST',
|
|
682
659
|
headers: {
|
|
@@ -687,9 +664,9 @@ export function serverAudits(opts) {
|
|
|
687
664
|
query: '{ 8f31403dfe404bccbb0e835f2629c6a7 }', // making sure the field doesnt exist
|
|
688
665
|
}),
|
|
689
666
|
});
|
|
690
|
-
|
|
667
|
+
ressert(res).status.toBe(400);
|
|
691
668
|
}),
|
|
692
|
-
audit('SHOULD not contain the data entry on document validation failure when accepting application/graphql-response+json', async () => {
|
|
669
|
+
audit('5E5B', 'SHOULD not contain the data entry on document validation failure when accepting application/graphql-response+json', async () => {
|
|
693
670
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
694
671
|
method: 'POST',
|
|
695
672
|
headers: {
|
|
@@ -700,13 +677,13 @@ export function serverAudits(opts) {
|
|
|
700
677
|
query: '{ 8f31403dfe404bccbb0e835f2629c6a7 }', // making sure the field doesnt exist
|
|
701
678
|
}),
|
|
702
679
|
});
|
|
703
|
-
|
|
680
|
+
await ressert(res).bodyAsExecutionResult.data.toBe(undefined);
|
|
704
681
|
}),
|
|
705
682
|
// TODO: how to fail and have the data entry?
|
|
706
|
-
// audit('MUST use 2xx status code if response contains the data entry and it is not null when accepting application/graphql-response+json'),
|
|
683
|
+
// audit('EE52', 'MUST use 2xx status code if response contains the data entry and it is not null when accepting application/graphql-response+json'),
|
|
707
684
|
// TODO: how to make an unauthorized request?
|
|
708
685
|
// https://graphql.github.io/graphql-over-http/draft/#sel-EANNNDTAAEVBAAqqc
|
|
709
|
-
// audit('SHOULD use 401 or 403 status codes when the request is not permitted')
|
|
686
|
+
// audit('BC58', 'SHOULD use 401 or 403 status codes when the request is not permitted')
|
|
710
687
|
];
|
|
711
688
|
}
|
|
712
689
|
/**
|