rules.lua 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. local parse = require 'graphql.parse'
  2. local validate = require 'graphql.validate'
  3. local schema = require 'tests/data/schema'
  4. local function expectError(message, document)
  5. if not message then
  6. expect(function() validate(schema, parse(document)) end).to_not.fail()
  7. else
  8. expect(function() validate(schema, parse(document)) end).to.fail.with(message)
  9. end
  10. end
  11. describe('rules', function()
  12. local document
  13. describe('uniqueOperationNames', function()
  14. local message = 'Multiple operations exist named'
  15. it('errors if two operations have the same name', function()
  16. expectError(message, [[
  17. query foo { }
  18. query foo { }
  19. ]])
  20. end)
  21. it('passes if all operations have different names', function()
  22. expectError(nil, [[
  23. query foo { }
  24. query bar { }
  25. ]])
  26. end)
  27. end)
  28. describe('loneAnonymousOperation', function()
  29. local message = 'Cannot have more than one operation when'
  30. it('fails if there is more than one operation and one of them is anonymous', function()
  31. expectError(message, [[
  32. query { }
  33. query named { }
  34. ]])
  35. expectError(message, [[
  36. query named { }
  37. query { }
  38. ]])
  39. expectError(message, [[
  40. query { }
  41. query { }
  42. ]])
  43. end)
  44. it('passes if there is one anonymous operation', function()
  45. expectError(nil, '{}')
  46. end)
  47. it('passes if there are two named operations', function()
  48. expectError(nil, [[
  49. query one {}
  50. query two {}
  51. ]])
  52. end)
  53. end)
  54. describe('fieldsDefinedOnType', function()
  55. local message = 'is not defined on type'
  56. it('fails if a field does not exist on an object type', function()
  57. expectError(message, '{ doggy { name } }')
  58. expectError(message, '{ dog { age } }')
  59. end)
  60. it('passes if all fields exist on object types', function()
  61. expectError(nil, '{ dog { name } }')
  62. end)
  63. it('understands aliases', function()
  64. expectError(nil, '{ doggy: dog { name } }')
  65. expectError(message, '{ dog: doggy { name } }')
  66. end)
  67. end)
  68. describe('argumentsDefinedOnType', function()
  69. local message = 'Non%-existent argument'
  70. it('passes if no arguments are supplied', function()
  71. expectError(nil, '{ dog { isHouseTrained } }')
  72. end)
  73. it('errors if an argument name does not match the schema', function()
  74. expectError(message, [[{
  75. dog {
  76. doesKnowCommand(doggyCommand: SIT)
  77. }
  78. }]])
  79. end)
  80. it('errors if an argument is supplied to a field that takes none', function()
  81. expectError(message, [[{
  82. dog {
  83. name(truncateToLength: 32)
  84. }
  85. }]])
  86. end)
  87. it('passes if all argument names match the schema', function()
  88. expectError(nil, [[{
  89. dog {
  90. doesKnowCommand(dogCommand: SIT)
  91. }
  92. }]])
  93. end)
  94. end)
  95. describe('scalarFieldsAreLeaves', function()
  96. local message = 'Scalar values cannot have subselections'
  97. it('fails if a scalar field has a subselection', function()
  98. expectError(message, '{ dog { name { firstLetter } } }')
  99. end)
  100. it('passes if all scalar fields are leaves', function()
  101. expectError(nil, '{ dog { name nickname } }')
  102. end)
  103. end)
  104. describe('compositeFieldsAreNotLeaves', function()
  105. local message = 'Composite types must have subselections'
  106. it('fails if an object is a leaf', function()
  107. expectError(message, '{ dog }')
  108. end)
  109. it('fails if an interface is a leaf', function()
  110. expectError(message, '{ pet }')
  111. end)
  112. it('fails if a union is a leaf', function()
  113. expectError(message, '{ catOrDog }')
  114. end)
  115. it('passes if all composite types have subselections', function()
  116. expectError(nil, '{ dog { name } pet { } }')
  117. end)
  118. end)
  119. describe('unambiguousSelections', function()
  120. it('fails if two fields with identical response keys have different types', function()
  121. expectError('Type name mismatch', [[{
  122. dog {
  123. barkVolume
  124. barkVolume: name
  125. }
  126. }]])
  127. end)
  128. it('fails if two fields have different argument sets', function()
  129. expectError('Argument mismatch', [[{
  130. dog {
  131. doesKnowCommand(dogCommand: SIT)
  132. doesKnowCommand(dogCommand: DOWN)
  133. }
  134. }]])
  135. end)
  136. it('passes if fields are identical', function()
  137. expectError(nil, [[{
  138. dog {
  139. doesKnowCommand(dogCommand: SIT)
  140. doesKnowCommand: doesKnowCommand(dogCommand: SIT)
  141. }
  142. }]])
  143. end)
  144. end)
  145. describe('uniqueArgumentNames', function()
  146. local message = 'Encountered multiple arguments named'
  147. it('fails if a field has two arguments with the same name', function()
  148. expectError(message, [[{
  149. dog {
  150. doesKnowCommand(dogCommand: SIT, dogCommand: DOWN)
  151. }
  152. }]])
  153. end)
  154. end)
  155. describe('argumentsOfCorrectType', function()
  156. it('fails if an argument has an incorrect type', function()
  157. expectError('Expected enum value', [[{
  158. dog {
  159. doesKnowCommand(dogCommand: 4)
  160. }
  161. }]])
  162. end)
  163. end)
  164. describe('requiredArgumentsPresent', function()
  165. local message = 'was not supplied'
  166. it('fails if a non-null argument is not present', function()
  167. expectError(message, [[{
  168. dog {
  169. doesKnowCommand
  170. }
  171. }]])
  172. end)
  173. end)
  174. describe('uniqueFragmentNames', function()
  175. local message = 'Encountered multiple fragments named'
  176. it('fails if there are two fragment definitions with the same name', function()
  177. expectError(message, [[
  178. query { dog { ...nameFragment } }
  179. fragment nameFragment on Dog { name }
  180. fragment nameFragment on Dog { name }
  181. ]])
  182. end)
  183. it('passes if all fragment definitions have different names', function()
  184. expectError(nil, [[
  185. query { dog { ...one ...two } }
  186. fragment one on Dog { name }
  187. fragment two on Dog { name }
  188. ]])
  189. end)
  190. end)
  191. describe('fragmentHasValidType', function()
  192. it('fails if a framgent refers to a non-composite type', function()
  193. expectError('Fragment type must be an Object, Interface, or Union', 'fragment f on DogCommand {}')
  194. end)
  195. it('fails if a fragment refers to a non-existent type', function()
  196. expectError('Fragment refers to non%-existent type', 'fragment f on Hyena {}')
  197. end)
  198. it('passes if a fragment refers to a composite type', function()
  199. expectError(nil, '{ dog { ...f } } fragment f on Dog {}')
  200. end)
  201. end)
  202. describe('noUnusedFragments', function()
  203. local message = 'was not used'
  204. it('fails if a fragment is not used', function()
  205. expectError(message, 'fragment f on Dog {}')
  206. end)
  207. end)
  208. describe('fragmentSpreadTargetDefined', function()
  209. local message = 'Fragment spread refers to non%-existent'
  210. it('fails if the fragment does not exist', function()
  211. expectError(message, '{ dog { ...f } }')
  212. end)
  213. end)
  214. describe('fragmentDefinitionHasNoCycles', function()
  215. local message = 'Fragment definition has cycles'
  216. it('fails if a fragment spread has cycles', function()
  217. expectError(message, [[
  218. { dog { ...f } }
  219. fragment f on Dog { ...g }
  220. fragment g on Dog { ...h }
  221. fragment h on Dog { ...f }
  222. ]])
  223. end)
  224. end)
  225. describe('fragmentSpreadIsPossible', function()
  226. local message = 'Fragment type condition is not possible'
  227. it('fails if a fragment type condition refers to a different object than the parent object', function()
  228. expectError(message, [[
  229. { dog { ...f } }
  230. fragment f on Cat { }
  231. ]])
  232. end)
  233. it('fails if a fragment type condition refers to an interface that the parent object does not implement', function()
  234. expectError(message, [[
  235. { dog { ...f } }
  236. fragment f on Sentient { }
  237. ]])
  238. end)
  239. it('fails if a fragment type condition refers to a union that the parent object does not belong to', function()
  240. expectError(message, [[
  241. { dog { ...f } }
  242. fragment f on HumanOrAlien { }
  243. ]])
  244. end)
  245. end)
  246. describe('uniqueInputObjectFields', function()
  247. local message = 'Multiple input object fields named'
  248. it('fails if an input object has two fields with the same name', function()
  249. expectError(message, [[
  250. {
  251. dog {
  252. complicatedField(complicatedArgument: {x: "hi", x: "hi"})
  253. }
  254. }
  255. ]])
  256. end)
  257. it('passes if an input object has nested fields with the same name', function()
  258. expectError(nil, [[
  259. {
  260. dog {
  261. complicatedField(complicatedArgument: {x: "hi", z: {x: "hi"}})
  262. }
  263. }
  264. ]])
  265. end)
  266. end)
  267. describe('directivesAreDefined', function()
  268. local message = 'Unknown directive'
  269. it('fails if a directive does not exist', function()
  270. expectError(message, 'query @someRandomDirective {}')
  271. end)
  272. it('passes if directives exists', function()
  273. expectError(nil, 'query @skip {}')
  274. end)
  275. end)
  276. end)