rspec-graphql-integration 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39c4ff53e15be806adbd54539c31cd15f92b7733f6161fbbd3d90b4d827d6d23
4
- data.tar.gz: '0780649082510a767cc3bf76225539837a1f0bb4caef92b5f610406b7567d5de'
3
+ metadata.gz: c741c1c9dcf41ac20bad890effdfde5ffa121b63b60f6704f07c0638a6001e6e
4
+ data.tar.gz: 74742a1424ec5ff2587bf945eab4cc5bf8ea059552da4f9b61ef01676b284477
5
5
  SHA512:
6
- metadata.gz: 26c78cddba206449f656a17f8ec4e0fe4edf6527b1104be5fd490a8e785be56bec083b2f8d21c155c696b201989a0036898c05f59b3576de3f2e0ba1189c2e66
7
- data.tar.gz: a6ae1678e9c113928c98c3c45cd3e7ef33aa432cd9a03eb2ceedc80aa350fd8d1e44d2f77417eae5d5925b36ebdc69b386dedae9b89b595b311274ca5ca7e78f
6
+ metadata.gz: 1dc6131393b96403f4054cb9a75c9d44c00a23dc6e5b101525290f1ba9f55d05b8ac4e3d071df262c14f53c4508d7a6f72357a10ca30eb611e1ad760fa3aa7bd
7
+ data.tar.gz: c6ed7377e513b4e12589f0ae8f1986bbedfbe8c43c31e773427e7b96926089ecac242b930cab4c858994b001776625e34af078b2fb56e2fed42931884b8acebb
@@ -4,6 +4,7 @@ module RSpec
4
4
  module GraphqlIntegration
5
5
  def self.initialize_configuration(config) # rubocop:disable Metrics/MethodLength
6
6
  config.add_setting(:graphql_schema_class, default: nil)
7
+ config.add_setting(:graphql_put_files_in_folder, default: false)
7
8
 
8
9
  config.include(RSpec::GraphqlIntegration::Matchers::DeepEq, type: :graphql)
9
10
  config.include(RSpec::GraphqlIntegration::Matchers::MatchGraphqlResponse, type: :graphql)
@@ -2,12 +2,10 @@ module RSpec
2
2
  module GraphqlIntegration
3
3
  module Matchers
4
4
  ##
5
- # This matcher recursively compares nested Ruby Hashes and Arrays while ignoring
5
+ # This helper method recursively compares nested Ruby Hashes and Arrays while ignoring
6
6
  # the order of elements in Arrays.
7
7
  module DeepEq
8
- extend RSpec::Matchers::DSL
9
-
10
- matcher(:deep_eq) { |expected| match { |actual| deep_eq?(actual, expected) } }
8
+ module_function
11
9
 
12
10
  def deep_eq?(actual, expected)
13
11
  return arrays_deep_eq?(actual, expected) if expected.is_a?(Array) && actual.is_a?(Array)
@@ -20,8 +18,8 @@ module RSpec
20
18
  def arrays_deep_eq?(actual, expected)
21
19
  expected = expected.clone
22
20
 
23
- actual.each do |array|
24
- index = expected.find_index { |element| deep_eq?(array, element) }
21
+ actual.each do |actual_array|
22
+ index = expected.find_index { |expected_array| deep_eq?(actual_array, expected_array) }
25
23
  return false if index.nil?
26
24
 
27
25
  expected.delete_at(index)
@@ -1,3 +1,5 @@
1
+ require "json"
2
+
1
3
  module RSpec
2
4
  module GraphqlIntegration
3
5
  module Matchers
@@ -7,104 +9,239 @@ module RSpec
7
9
  extend RSpec::Matchers::DSL
8
10
 
9
11
  ##
10
- # This error is thrown when a variable is missing that is required for
11
- # the GraphQL response matcher.
12
- class TestVariableMissing < ArgumentError
13
- def initialize(variable_name, example_value)
12
+ # This error is raised when the schema class is not set in the RSpec configuration.
13
+ class SchemaNotSetError < StandardError
14
+ def initialize
14
15
  super <<~TEXT
15
- Test variable #{variable_name} is missing.
16
+ Please define
17
+
18
+ config.graphql_schema_class
16
19
 
17
- Please define it, e.g. with:
18
- let(:#{variable_name}) { #{example_value} }
20
+ in your spec_helper.rb
19
21
  TEXT
20
22
  end
21
23
  end
22
24
 
23
25
  ##
24
- # Defines the required variables as a hash for a test that uses
25
- # the GraphQL response matcher.
26
- #
27
- # Key is the variable name, value is an example value.
28
- REQUIRED_TEST_VARIABLES = { test_dir: "__FILE__" }.freeze
26
+ # This error is thrown if neither the default request file is present nor
27
+ # the request_file_overwrite variable is set in a test.
28
+ class DefaultRequestFileMissing < StandardError
29
+ def initialize(default_request_file)
30
+ super <<~TEXT
31
+ No default request file found for this test.
32
+
33
+ Please create either a default request file:
34
+ #{default_request_file}
35
+
36
+ or define a file with the request_file_overwrite variable:
37
+ let(:request_file_overwrite) { File.join(File.dirname(__FILE__), "my_request_file.graphql") }
38
+ TEXT
39
+ end
40
+ end
41
+
42
+ ##
43
+ # This error is thrown if neither the default request file is present nor
44
+ # the response_file_overwrite variable is set in a test.
45
+ class DefaultResponseFileMissing < StandardError
46
+ def initialize(default_response_file)
47
+ super <<~TEXT
48
+ No default response file found for this test.
49
+
50
+ Please create either a default response file:
51
+ #{default_response_file}
52
+
53
+ or define a file with the response_file_overwrite variable:
54
+ let(:response_file_overwrite) { File.join(File.dirname(__FILE__), "my_response_file.graphql") }
55
+ TEXT
56
+ end
57
+ end
29
58
 
30
59
  matcher(:match_graphql_response) do |_expected| # rubocop:disable Metrics/BlockLength
31
60
  match do |_actual|
32
- check_variables!
61
+ # expected_response needs to be loaded first because it might contain variables
62
+ # that are required in the request and that aren't loaded yet. Such variables
63
+ # could be database objects that could be created while loading the response.
64
+ expected_response
33
65
 
34
- # We need to test the responses with be_deep_equal so that we ignore
66
+ # We need to test the responses with DeepEq so that we ignore
35
67
  # the order in nested hashes.
36
- expect(actual_response).to deep_eq(expected_response)
37
- rescue RSpec::Expectations::ExpectationNotMetError => e
38
- @error = e
39
- raise
68
+ DeepEq.deep_eq?(actual_response, expected_response)
40
69
  end
41
70
 
42
71
  # For the failure message, we want to show the diff between the actual and
43
72
  # the expected response and the standard eq matcher from RSpec does that best.
44
73
  failure_message { expect(actual_response).to eq(expected_response) }
45
74
 
46
- def check_variables!
47
- REQUIRED_TEST_VARIABLES.each do |variable_name, example_value|
48
- unless defined?(send(variable_name))
49
- raise TestVariableMissing.new(variable_name, example_value)
75
+ ##
76
+ # Loads the response file and substitutes the variables in the response file.
77
+ def expected_response
78
+ @expected_response ||=
79
+ begin
80
+ expected_response =
81
+ load_response(
82
+ response_file,
83
+ defined?(response_variables) ? response_variables : {},
84
+ )
85
+
86
+ expected_response = [expected_response] unless expected_response.is_a?(Array)
87
+
88
+ expected_response
50
89
  end
90
+ end
91
+
92
+ ##
93
+ # Executes the query with the context and the variables against the schema and
94
+ # returns the response.
95
+ def actual_response
96
+ @actual_response ||=
97
+ begin
98
+ response =
99
+ schema_class.execute(
100
+ File.read(request_file),
101
+ context: defined?(context) ? context : {},
102
+ variables: defined?(request_variables) ? request_variables : {},
103
+ )
104
+
105
+ response.values
106
+ end
107
+ end
108
+
109
+ ##
110
+ # This method tries to get the file path for the file that is running the tests.
111
+ #
112
+ # The magic of this method can be overwritten by defining:
113
+ # let(:test_file_overwrite) { __FILE__ }
114
+ def test_file
115
+ return test_file_overwrite if defined?(test_file_overwrite)
116
+
117
+ caller_location =
118
+ caller_locations.find { |location| location.path.include?("/spec/graphql") }
119
+
120
+ caller_location.path
121
+ end
122
+
123
+ ##
124
+ # This method defines the folder where the request and response files are stored.
125
+ #
126
+ # It's either the folder of the file that is running the tests or a subfolder
127
+ # named like the test file.
128
+ def files_folder
129
+ if RSpec.configuration.graphql_put_files_in_folder
130
+ test_file.gsub("_spec.rb", "")
131
+ else
132
+ File.dirname(test_file)
51
133
  end
52
134
  end
53
135
 
54
- def expected_response
55
- expected_response = load_response(test_dir, response_template, response_variables)
136
+ ##
137
+ # This method tries to get the file path for the request file.
138
+ #
139
+ # If the request_file_overwrite variable is set, it uses that.
140
+ #
141
+ # raises DefaultRequestFileMissing if no request file is found.
142
+ def request_file
143
+ if defined?(request_file_overwrite)
144
+ return File.join(files_folder, request_file_overwrite)
145
+ end
56
146
 
57
- expected_response = [expected_response] unless expected_response.is_a?(Array)
147
+ default_request_file = File.join(files_folder, default_request_file_name)
58
148
 
59
- expected_response
149
+ unless File.exist?(default_request_file)
150
+ raise DefaultRequestFileMissing, default_request_file
151
+ end
152
+
153
+ default_request_file
60
154
  end
61
155
 
62
- def actual_response
63
- response =
64
- schema_class.execute(
65
- load_query(test_dir, query_file),
66
- context: context,
67
- variables: defined?(request_variables) ? request_variables : {},
68
- )
69
-
70
- response.values
156
+ ##
157
+ # The default request file is either called like the test file without _spec
158
+ # but with .graphql or it's in the subfolder of the test file called "request.graphql".
159
+ def default_request_file_name
160
+ if RSpec.configuration.graphql_put_files_in_folder
161
+ "request.graphql"
162
+ else
163
+ test_file.split("/").last.gsub("_spec.rb", ".graphql")
164
+ end
71
165
  end
72
166
 
167
+ ##
168
+ # This method tries to get the file path for the response file.
169
+ #
170
+ # If the response_file_overwrite variable is set, it uses that.
171
+ #
172
+ # raises DefaultRequestFileMissing if no response file is found.
173
+ def response_file
174
+ if defined?(response_file_overwrite)
175
+ return File.join(files_folder, response_file_overwrite)
176
+ end
177
+
178
+ default_response_file = File.join(files_folder, default_response_file_name)
179
+
180
+ unless File.exist?(default_response_file)
181
+ raise DefaultResponseFileMissing, default_response_file
182
+ end
183
+
184
+ default_response_file
185
+ end
186
+
187
+ ##
188
+ # The default response file is either called like the test file without _spec
189
+ # but with .json or it's in the subfolder of the test file called "response.json".
190
+ def default_response_file_name
191
+ if RSpec.configuration.graphql_put_files_in_folder
192
+ "response.json"
193
+ else
194
+ test_file.split("/").last.gsub("_spec.rb", ".json")
195
+ end
196
+ end
197
+
198
+ ##
199
+ # This method gets the schema class from the RSpec configuration.
200
+ #
201
+ # If schema_class_overwrite is set, it uses that.
202
+ #
203
+ # raises SchemaNotSetError if the schema class is not set.
73
204
  def schema_class
74
205
  # It's possible to overwrite the schema class if an app has multiple schemas.
75
206
  return schema_class_overwrite if defined?(schema_class_overwrite)
76
207
 
77
- if RSpec.configuration.graphql_schema_class.nil? && !Object.const_defined?(:Schema)
78
- raise "Please define config.graphql_schema_class in your rails_helper.rb"
79
- end
208
+ raise SchemaNotSetError if RSpec.configuration.graphql_schema_class.nil?
80
209
 
81
210
  RSpec.configuration.graphql_schema_class
82
211
  end
83
212
  end
84
213
 
85
- ##
86
- # Loads a query in a GraphQL file.
87
- #
88
- # Example:
89
- # load_query(__FILE__, 'current_user/query.graphql'),
90
- def load_query(dir, filename)
91
- File.read(File.join(File.dirname(dir), filename))
92
- end
93
-
94
214
  ##
95
215
  # Loads a response in a JSON file and substitute the passed variables that
96
216
  # are surrounded by {{...}} in the file.
97
217
  #
98
218
  # Example:
99
219
  # load_response(
100
- # __FILE__,
101
- # 'current_user/response.json',
220
+ # "current_user.json",
102
221
  # {
103
- # user_id: user.id,
222
+ # user_id: 1,
104
223
  # },
105
224
  # )
106
- def load_response(dir, filename, variables = {})
107
- json_file = File.read(File.join(File.dirname(dir), filename))
225
+ #
226
+ # current_user.json:
227
+ # {
228
+ # "data": {
229
+ # "currentUser": {
230
+ # "id": "{{user_id}}",
231
+ # }
232
+ # }
233
+ # }
234
+ #
235
+ # Result:
236
+ # {
237
+ # "data": {
238
+ # "currentUser": {
239
+ # "id": "1",
240
+ # }
241
+ # }
242
+ # }
243
+ def load_response(filename, variables = {})
244
+ json_file = File.read(filename)
108
245
  variables.each { |key, value| json_file.gsub!("\"{{#{key}}}\"", JSON.dump(value)) }
109
246
 
110
247
  JSON.parse(json_file)
@@ -1,5 +1,5 @@
1
1
  module RSpec
2
2
  module GraphqlIntegration
3
- VERSION = "0.1.0".freeze
3
+ VERSION = "0.2.0".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-graphql-integration
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Gundel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-31 00:00:00.000000000 Z
11
+ date: 2023-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 3.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: prettier
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,48 @@ dependencies:
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
55
111
  - !ruby/object:Gem::Dependency
56
112
  name: rubocop
57
113
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +122,34 @@ dependencies:
66
122
  - - ">="
67
123
  - !ruby/object:Gem::Version
68
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
69
153
  description:
70
154
  email:
71
155
  - gundel.peter@gmail.com
@@ -91,14 +175,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
175
  requirements:
92
176
  - - ">="
93
177
  - !ruby/object:Gem::Version
94
- version: '2.6'
178
+ version: '2.7'
95
179
  required_rubygems_version: !ruby/object:Gem::Requirement
96
180
  requirements:
97
181
  - - ">="
98
182
  - !ruby/object:Gem::Version
99
183
  version: '0'
100
184
  requirements: []
101
- rubygems_version: 3.3.7
185
+ rubygems_version: 3.1.6
102
186
  signing_key:
103
187
  specification_version: 4
104
188
  summary: An RSpec plugin to simplify integration tests for GraphQL