@@ -2,7 +2,11 @@ import { describe, it } from 'mocha';
2
2
3
3
import { SingleFieldSubscriptionsRule } from '../rules/SingleFieldSubscriptionsRule' ;
4
4
5
- import { expectValidationErrors } from './harness' ;
5
+ import {
6
+ expectValidationErrors ,
7
+ expectValidationErrorsWithSchema ,
8
+ emptySchema ,
9
+ } from './harness' ;
6
10
7
11
function expectErrors ( queryStr : string ) {
8
12
return expectValidationErrors ( SingleFieldSubscriptionsRule , queryStr ) ;
@@ -21,6 +25,41 @@ describe('Validate: Subscriptions with single field', () => {
21
25
` ) ;
22
26
} ) ;
23
27
28
+ it ( 'valid subscription with fragment' , ( ) => {
29
+ // From https://spec.graphql.org/draft/#example-13061
30
+ expectValid ( `
31
+ subscription sub {
32
+ ...newMessageFields
33
+ }
34
+
35
+ fragment newMessageFields on SubscriptionRoot {
36
+ newMessage {
37
+ body
38
+ sender
39
+ }
40
+ }
41
+ ` ) ;
42
+ } ) ;
43
+
44
+ it ( 'valid subscription with fragment and field' , ( ) => {
45
+ // From https://spec.graphql.org/draft/#example-13061
46
+ expectValid ( `
47
+ subscription sub {
48
+ newMessage {
49
+ body
50
+ }
51
+ ...newMessageFields
52
+ }
53
+
54
+ fragment newMessageFields on SubscriptionRoot {
55
+ newMessage {
56
+ body
57
+ sender
58
+ }
59
+ }
60
+ ` ) ;
61
+ } ) ;
62
+
24
63
it ( 'fails with more than one root field' , ( ) => {
25
64
expectErrors ( `
26
65
subscription ImportantEmails {
@@ -48,6 +87,34 @@ describe('Validate: Subscriptions with single field', () => {
48
87
'Subscription "ImportantEmails" must select only one top level field.' ,
49
88
locations : [ { line : 4 , column : 9 } ] ,
50
89
} ,
90
+ {
91
+ message :
92
+ 'Subscription "ImportantEmails" must not select an introspection top level field.' ,
93
+ locations : [ { line : 4 , column : 9 } ] ,
94
+ } ,
95
+ ] ) ;
96
+ } ) ;
97
+
98
+ it ( 'fails with more than one root field including aliased introspection via fragment' , ( ) => {
99
+ expectErrors ( `
100
+ subscription ImportantEmails {
101
+ importantEmails
102
+ ...Introspection
103
+ }
104
+ fragment Introspection on SubscriptionRoot {
105
+ typename: __typename
106
+ }
107
+ ` ) . to . deep . equal ( [
108
+ {
109
+ message :
110
+ 'Subscription "ImportantEmails" must select only one top level field.' ,
111
+ locations : [ { line : 7 , column : 9 } ] ,
112
+ } ,
113
+ {
114
+ message :
115
+ 'Subscription "ImportantEmails" must not select an introspection top level field.' ,
116
+ locations : [ { line : 7 , column : 9 } ] ,
117
+ } ,
51
118
] ) ;
52
119
} ) ;
53
120
@@ -70,6 +137,86 @@ describe('Validate: Subscriptions with single field', () => {
70
137
] ) ;
71
138
} ) ;
72
139
140
+ it ( 'fails with many more than one root field via fragments' , ( ) => {
141
+ expectErrors ( `
142
+ subscription ImportantEmails {
143
+ importantEmails
144
+ ... {
145
+ more: moreImportantEmails
146
+ }
147
+ ...NotImportantEmails
148
+ }
149
+ fragment NotImportantEmails on SubscriptionRoot {
150
+ notImportantEmails
151
+ deleted: deletedEmails
152
+ ...SpamEmails
153
+ }
154
+ fragment SpamEmails on SubscriptionRoot {
155
+ spamEmails
156
+ }
157
+ ` ) . to . deep . equal ( [
158
+ {
159
+ message :
160
+ 'Subscription "ImportantEmails" must select only one top level field.' ,
161
+ locations : [
162
+ { line : 5 , column : 11 } ,
163
+ { line : 10 , column : 9 } ,
164
+ { line : 11 , column : 9 } ,
165
+ { line : 15 , column : 9 } ,
166
+ ] ,
167
+ } ,
168
+ ] ) ;
169
+ } ) ;
170
+
171
+ it ( 'does not infinite loop on recursive fragments' , ( ) => {
172
+ expectErrors ( `
173
+ subscription NoInfiniteLoop {
174
+ ...A
175
+ }
176
+ fragment A on SubscriptionRoot {
177
+ ...A
178
+ }
179
+ ` ) . to . deep . equal ( [ ] ) ;
180
+ } ) ;
181
+
182
+ it ( 'fails with many more than one root field via fragments (anonymous)' , ( ) => {
183
+ expectErrors ( `
184
+ subscription {
185
+ importantEmails
186
+ ... {
187
+ more: moreImportantEmails
188
+ ...NotImportantEmails
189
+ }
190
+ ...NotImportantEmails
191
+ }
192
+ fragment NotImportantEmails on SubscriptionRoot {
193
+ notImportantEmails
194
+ deleted: deletedEmails
195
+ ... {
196
+ ... {
197
+ archivedEmails
198
+ }
199
+ }
200
+ ...SpamEmails
201
+ }
202
+ fragment SpamEmails on SubscriptionRoot {
203
+ spamEmails
204
+ ...NonExistentFragment
205
+ }
206
+ ` ) . to . deep . equal ( [
207
+ {
208
+ message : 'Anonymous Subscription must select only one top level field.' ,
209
+ locations : [
210
+ { line : 5 , column : 11 } ,
211
+ { line : 11 , column : 9 } ,
212
+ { line : 12 , column : 9 } ,
213
+ { line : 15 , column : 13 } ,
214
+ { line : 21 , column : 9 } ,
215
+ ] ,
216
+ } ,
217
+ ] ) ;
218
+ } ) ;
219
+
73
220
it ( 'fails with more than one root field in anonymous subscriptions' , ( ) => {
74
221
expectErrors ( `
75
222
subscription {
@@ -83,4 +230,44 @@ describe('Validate: Subscriptions with single field', () => {
83
230
} ,
84
231
] ) ;
85
232
} ) ;
233
+
234
+ it ( 'fails with introspection field' , ( ) => {
235
+ expectErrors ( `
236
+ subscription ImportantEmails {
237
+ __typename
238
+ }
239
+ ` ) . to . deep . equal ( [
240
+ {
241
+ message :
242
+ 'Subscription "ImportantEmails" must not select an introspection top level field.' ,
243
+ locations : [ { line : 3 , column : 9 } ] ,
244
+ } ,
245
+ ] ) ;
246
+ } ) ;
247
+
248
+ it ( 'fails with introspection field in anonymous subscription' , ( ) => {
249
+ expectErrors ( `
250
+ subscription {
251
+ __typename
252
+ }
253
+ ` ) . to . deep . equal ( [
254
+ {
255
+ message :
256
+ 'Anonymous Subscription must not select an introspection top level field.' ,
257
+ locations : [ { line : 3 , column : 9 } ] ,
258
+ } ,
259
+ ] ) ;
260
+ } ) ;
261
+
262
+ it ( 'skips if not subscription type' , ( ) => {
263
+ expectValidationErrorsWithSchema (
264
+ emptySchema ,
265
+ SingleFieldSubscriptionsRule ,
266
+ `
267
+ subscription {
268
+ __typename
269
+ }
270
+ ` ,
271
+ ) . to . deep . equal ( [ ] ) ;
272
+ } ) ;
86
273
} ) ;
0 commit comments