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 +7 -0
- data/lib/rspec/graphql_integration/configuration.rb +30 -0
- data/lib/rspec/graphql_integration/matchers/deep_eq.rb +44 -0
- data/lib/rspec/graphql_integration/matchers/match_graphql_response.rb +115 -0
- data/lib/rspec/graphql_integration/version.rb +5 -0
- data/lib/rspec/graphql_integration.rb +6 -0
- metadata +105 -0
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
|
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: []
|