rspec-graphql-integration 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 39c4ff53e15be806adbd54539c31cd15f92b7733f6161fbbd3d90b4d827d6d23
4
+ data.tar.gz: '0780649082510a767cc3bf76225539837a1f0bb4caef92b5f610406b7567d5de'
5
+ SHA512:
6
+ metadata.gz: 26c78cddba206449f656a17f8ec4e0fe4edf6527b1104be5fd490a8e785be56bec083b2f8d21c155c696b201989a0036898c05f59b3576de3f2e0ba1189c2e66
7
+ data.tar.gz: a6ae1678e9c113928c98c3c45cd3e7ef33aa432cd9a03eb2ceedc80aa350fd8d1e44d2f77417eae5d5925b36ebdc69b386dedae9b89b595b311274ca5ca7e78f
@@ -0,0 +1,30 @@
1
+ module RSpec
2
+ ##
3
+ # This module sets up GraphQL integration testing for RSpec.
4
+ module GraphqlIntegration
5
+ def self.initialize_configuration(config) # rubocop:disable Metrics/MethodLength
6
+ config.add_setting(:graphql_schema_class, default: nil)
7
+
8
+ config.include(RSpec::GraphqlIntegration::Matchers::DeepEq, type: :graphql)
9
+ config.include(RSpec::GraphqlIntegration::Matchers::MatchGraphqlResponse, type: :graphql)
10
+
11
+ config.instance_exec do
12
+ # This method is inspired by the one from the RSpec::Rails gem.
13
+ # See https://github.com/rspec/rspec-rails/blob/main/lib/rspec/rails/configuration.rb
14
+ # => #infer_spec_type_from_file_location!
15
+ #
16
+ # It has to be called explicitly in the spec_helper.rb file to be enabled.
17
+ # See the README for more information.
18
+ def infer_graphql_spec_type_from_file_location!
19
+ escaped_path = Regexp.compile("#{%w[spec graphql].join("[\\\\/]")}[\\/]")
20
+
21
+ define_derived_metadata(file_path: escaped_path) do |metadata|
22
+ metadata[:type] ||= :graphql
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ initialize_configuration RSpec.configuration
29
+ end
30
+ end
@@ -0,0 +1,44 @@
1
+ module RSpec
2
+ module GraphqlIntegration
3
+ module Matchers
4
+ ##
5
+ # This matcher recursively compares nested Ruby Hashes and Arrays while ignoring
6
+ # the order of elements in Arrays.
7
+ module DeepEq
8
+ extend RSpec::Matchers::DSL
9
+
10
+ matcher(:deep_eq) { |expected| match { |actual| deep_eq?(actual, expected) } }
11
+
12
+ def deep_eq?(actual, expected)
13
+ return arrays_deep_eq?(actual, expected) if expected.is_a?(Array) && actual.is_a?(Array)
14
+
15
+ return hashes_deep_eq?(actual, expected) if expected.is_a?(Hash) && actual.is_a?(Hash)
16
+
17
+ expected == actual
18
+ end
19
+
20
+ def arrays_deep_eq?(actual, expected)
21
+ expected = expected.clone
22
+
23
+ actual.each do |array|
24
+ index = expected.find_index { |element| deep_eq?(array, element) }
25
+ return false if index.nil?
26
+
27
+ expected.delete_at(index)
28
+ end
29
+
30
+ expected.empty?
31
+ end
32
+
33
+ def hashes_deep_eq?(actual, expected)
34
+ return false if actual.keys.sort != expected.keys.sort
35
+
36
+ # TODO: use any or all
37
+ actual.each { |key, value| return false unless deep_eq?(value, expected[key]) }
38
+
39
+ true
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,115 @@
1
+ module RSpec
2
+ module GraphqlIntegration
3
+ module Matchers
4
+ ##
5
+ # This module contains the matchers that are used to test GraphQL queries and mutations.
6
+ module MatchGraphqlResponse
7
+ extend RSpec::Matchers::DSL
8
+
9
+ ##
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)
14
+ super <<~TEXT
15
+ Test variable #{variable_name} is missing.
16
+
17
+ Please define it, e.g. with:
18
+ let(:#{variable_name}) { #{example_value} }
19
+ TEXT
20
+ end
21
+ end
22
+
23
+ ##
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
29
+
30
+ matcher(:match_graphql_response) do |_expected| # rubocop:disable Metrics/BlockLength
31
+ match do |_actual|
32
+ check_variables!
33
+
34
+ # We need to test the responses with be_deep_equal so that we ignore
35
+ # 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
40
+ end
41
+
42
+ # For the failure message, we want to show the diff between the actual and
43
+ # the expected response and the standard eq matcher from RSpec does that best.
44
+ failure_message { expect(actual_response).to eq(expected_response) }
45
+
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)
50
+ end
51
+ end
52
+ end
53
+
54
+ def expected_response
55
+ expected_response = load_response(test_dir, response_template, response_variables)
56
+
57
+ expected_response = [expected_response] unless expected_response.is_a?(Array)
58
+
59
+ expected_response
60
+ end
61
+
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
71
+ end
72
+
73
+ def schema_class
74
+ # It's possible to overwrite the schema class if an app has multiple schemas.
75
+ return schema_class_overwrite if defined?(schema_class_overwrite)
76
+
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
80
+
81
+ RSpec.configuration.graphql_schema_class
82
+ end
83
+ end
84
+
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
+ ##
95
+ # Loads a response in a JSON file and substitute the passed variables that
96
+ # are surrounded by {{...}} in the file.
97
+ #
98
+ # Example:
99
+ # load_response(
100
+ # __FILE__,
101
+ # 'current_user/response.json',
102
+ # {
103
+ # user_id: user.id,
104
+ # },
105
+ # )
106
+ def load_response(dir, filename, variables = {})
107
+ json_file = File.read(File.join(File.dirname(dir), filename))
108
+ variables.each { |key, value| json_file.gsub!("\"{{#{key}}}\"", JSON.dump(value)) }
109
+
110
+ JSON.parse(json_file)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,5 @@
1
+ module RSpec
2
+ module GraphqlIntegration
3
+ VERSION = "0.1.0".freeze
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ require "rspec/core"
2
+
3
+ require "rspec/graphql_integration/matchers/deep_eq"
4
+ require "rspec/graphql_integration/matchers/match_graphql_response"
5
+
6
+ require "rspec/graphql_integration/configuration"
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-graphql-integration
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter Gundel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-12-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: graphql
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: prettier
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'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - gundel.peter@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/rspec/graphql_integration.rb
77
+ - lib/rspec/graphql_integration/configuration.rb
78
+ - lib/rspec/graphql_integration/matchers/deep_eq.rb
79
+ - lib/rspec/graphql_integration/matchers/match_graphql_response.rb
80
+ - lib/rspec/graphql_integration/version.rb
81
+ homepage: https://github.com/peterfication/rspec-graphql-integration
82
+ licenses:
83
+ - MIT
84
+ metadata:
85
+ rubygems_mfa_required: 'true'
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '2.6'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.3.7
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: An RSpec plugin to simplify integration tests for GraphQL
105
+ test_files: []