rspec-graphql-integration 0.1.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.
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: []