rspec-graphql_matchers 1.0.0.pre.0.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2c995f57264270239040010ba138b480e7280b05e1ca75b54dbc4a03426ba42c
4
- data.tar.gz: fcbc1410d22f83530270cd24db7cbe81541754a0b8cd58d27265dd7b248cdf3c
3
+ metadata.gz: d19eb108a03226d730c4ef1cc10afe2b54e2ae3e922e9617cd8d69dec4650d26
4
+ data.tar.gz: 49882ece0fb24f10899e6f4f923c2c639d9859ec6309c46135e7c3ea6f486a51
5
5
  SHA512:
6
- metadata.gz: 150c4f842ffef148a7063803d09d4c5433f7ff63637e70fb9cafc2ddb3e6d480ccc1662af7f30aaf241791ae6c53e03e24698b8bd4055cf5dc2d47bd273ed10b
7
- data.tar.gz: 2779881b25f48f04c8f276c4ce5ea6aee3e376f6058e83ecfa54b9c5e04c7e24c31127cb66c07f5a861b1da2af2fe8e12517fb369d52cb3edeb810e09d924552
6
+ metadata.gz: b0f0ec4e822a9ba1ae174edace4b3a77d76ece28df8c46fe128b75d02e97652191506890be7101c52b8c32644a6e48d401bf623c69a6fc60d81a434063281ae9
7
+ data.tar.gz: 56c4388cfa19bcc95967e2f16ec726a49a935c5ecccf5f30ae722384283cecac29ba3409c21dd925f40683f55f5d2fef7aa2ec872834980477498e7d015f619a
@@ -16,11 +16,14 @@
16
16
 
17
17
  ### Deprecations
18
18
 
19
- - `.with_metadata` and `.with_property` matchers for fields will be removed on the next release.
19
+ - `.with_metadata` and `.with_property` matchers for fields will be removed on the next release;
20
+ - `.accept_arguments` (plural form) will be removed on the next release;
21
+ - `.accept_argument` (singular form) receiving a hash with a single or multiple arguments will no longer be supported, use `accept_argument(name).of_type('MyType')` instead.
20
22
 
21
23
  ### New features
22
24
 
23
25
  - Add support for Class-based type definition api (adds support for graphql-ruby v1.8.x). Please note that `.with_metadata` and `.with_property` support has been kept but will only work on fields defined using the legacy api.
26
+ - Implemented `accept_argument(arg_name).of_type('MyType')´ matcher, which returns much clearer error messages when the arguments are not found on the target type.
24
27
 
25
28
  ### Bug fixes
26
29
 
data/README.md CHANGED
@@ -14,18 +14,17 @@ gem 'rspec-graphql_matchers'
14
14
 
15
15
  The matchers currently supported are:
16
16
 
17
- - `expect(a_graphql_object).to have_a_field(field_name).that_returns(valid_type)`
17
+ - `expect(a_graphql_object).to have_a_field(field_name).of_type(valid_type)`
18
18
  - `expect(a_graphql_object).to implement(interface_name, ...)`
19
19
  - `expect(a_mutation_type).to have_a_return_field(field_name).returning(valid_type)`
20
20
  - `expect(a_mutation_type).to have_an_input_field(field_name).of_type(valid_type)`
21
21
  - `expect(a_field).to be_of_type(valid_type)`
22
- - `expect(an_input).to accept_arguments(hash_of_arg_names_and_valid_types)`
23
- - `expect(an_input).to accept_arguments(hash_of_arg_names_and_valid_types)`
22
+ - `expect(an_input).to accept_argument(argument_name).of_type(valid_type)`
24
23
 
25
24
  Where a valid type for the expectation is either:
26
25
 
27
26
  - A reference to the actual type you expect;
28
- - A String representation of a type: `"String!"`, `"Int!"`, `"[String]!"`
27
+ - [Recommended] A String representation of a type: `"String!"`, `"Int!"`, `"[String]!"`
29
28
  (note the exclamation mark at the end, as required by the [GraphQL specs](http://graphql.org/).
30
29
 
31
30
  For objects defined with the legacy `#define` api, testing `:property`, `:hash_key` and _metadata_ is also possible by chaining `.with_property`, `.with_hash_key` and `.with_metadata`. For example:
@@ -35,31 +34,22 @@ For objects defined with the legacy `#define` api, testing `:property`, `:hash_k
35
34
 
36
35
  ## Examples
37
36
 
38
- Given a `GraphQL::ObjectType` defined as
37
+ Given a GraphQL object defined as
39
38
 
40
39
  ```ruby
41
-
42
- PostType = GraphQL::ObjectType.define do
43
- name "Post"
40
+ class PostType < GraphQL::Schema::Object
41
+ graphql_name "Post"
44
42
  description "A blog post"
45
43
 
46
- interfaces [GraphQL::Relay::Node.interface]
47
-
48
- field :id, !types.ID,
49
- property: :post_id
44
+ implements GraphQL::Relay::Node.interface
50
45
 
51
- field :comments,
52
- !types[types.String],
53
- hash_key: :post_comments
46
+ field :id, ID, null: false
47
+ field :comments, [String], null: false
48
+ field :isPublished, Boolean, null: true
54
49
 
55
- field :isPublished,
56
- admin_only: true
57
-
58
- field :subposts, PostType do
59
- type !PostType
60
-
61
- argument :filter, types.String
62
- argument :id, types.ID
50
+ field :subposts, PostType, null: true do
51
+ argument :filter, types.String, required: false
52
+ argument :id, types.ID, required: false
63
53
  end
64
54
  end
65
55
  ```
@@ -68,13 +58,11 @@ end
68
58
 
69
59
  ```ruby
70
60
  describe PostType do
71
- it 'defines a field id of type ID!' do
72
- expect(subject).to have_field(:id).that_returns(!types.ID)
73
- end
61
+ subject { described_class }
74
62
 
75
- # Fluent alternatives
76
- it { is_expected.to have_field(:id).of_type("ID!") }
77
- it { is_expected.to have_a_field(:id).returning("ID!") }
63
+ it { is_expected.to have_field(:id).of_type(!types.ID) }
64
+ it { is_expected.to have_field(:comments).of_type("[String!]!") }
65
+ it { is_expected.to have_field(:isPublished).of_type("Boolean") }
78
66
  end
79
67
  ```
80
68
 
@@ -92,80 +80,54 @@ describe PostType do
92
80
  describe 'subposts' do
93
81
  subject { PostType.fields['subposts'] }
94
82
 
95
- # You can use your type object directly when building expectations
96
- it 'has type PostType' do
97
- expect(subject).to be_of_type(!PostType)
98
- end
99
-
100
- # Or as usual, a literal String
101
- it { is_expected.to be_of_type('Post!') }
83
+ it { is_expected.to be_of_type('Post') }
102
84
  end
103
85
  end
104
86
  ```
105
87
 
106
- Keep in mind that when using strings as type expectation you have to use the
107
- type name (`Post`) and not the constant name (`PostType`).
108
-
109
- Using your type objects directly is riskier than the string representation, since
110
- renaming the graphql name of an object is potentially a breaking change that
111
- wouldn't get caught by your test suite.
112
-
113
- You can also use the built-in [graphql-ruby](https://github.com/rmosolgo/graphql-ruby) scalar types:
88
+ ### 3) For objects defined using the legacy `#define` api, you can also use `with_property`, `with_hash_key` and `with_metadata`:
114
89
 
115
90
  ```ruby
116
- # ensure you have the GraphQL type definer available in your tests
117
- types = GraphQL::Define::TypeDefiner.instance
91
+ PostTypeWithDefineApi = GraphQL::ObjectType.define do
92
+ name "DefinedPost"
118
93
 
119
- describe PostType do
120
- describe 'comments' do
121
- subject { PostType.fields['comments'] }
122
- it { is_expected.to be_of_type(!types[types.String]) }
123
- it { is_expected.to be_of_type('[String]!') }
124
- end
125
- end
126
- ```
94
+ interfaces [GraphQL::Relay::Node.interface]
127
95
 
128
- ### 3) Test a specific field with `with_property`, `with_hash_key` and `with_metadata`
96
+ field :id, !types.ID, property: :post_id
97
+ field :comments, !types[types.String], hash_key: :post_comments
98
+ field :isPublished, admin_only: true
99
+ end
129
100
 
130
- ```ruby
131
- describe PostType do
132
- it { is_expected.to have_a_field(:id).with_property(:post_id) }
101
+ describe PostTypeWithDefineApi do
102
+ it { is_expected.to have_a_field(:id).of_type('ID!').with_property(:post_id) }
133
103
  it { is_expected.to have_a_field(:comments).with_hash_key(:post_comments) }
134
104
  it { is_expected.to have_a_field(:isPublished).with_metadata(admin_only: true) }
135
105
  end
136
106
  ```
137
107
 
138
- ### 4) Test the arguments accepted by a field with `accept_arguments` matcher:
108
+ ### 4) Test the arguments accepted by a field with `accept_argument` matcher:
139
109
 
140
110
  ```ruby
141
111
  describe PostType do
142
112
  describe 'subposts' do
143
113
  subject { PostType.fields['subposts'] }
144
114
 
145
- let(:a_whole_bunch_of_args) do
146
- { filter: 'String', id: types.Int, pippo: 'Float', posts: PostType }
147
- end
148
-
149
115
  it 'accepts a filter and an id argument, of types String and ID' do
150
- expect(subject).to accept_arguments(filter: types.String, id: types.ID)
116
+ expect(subject).to accept_argument(:filter).of_type('String')
117
+ expect(subject).to accept_argument(:id).of_type('ID')
151
118
  end
152
119
 
153
- # You can also test if a field does not accept args. Not quite useful :D.
154
- it { is_expected.not_to accept_arguments(a_whole_bunch_of_args) }
120
+ it { is_expected.not_to accept_argument(:weirdo) }
155
121
  end
156
122
  end
157
123
  ```
158
124
 
159
- The spec will only pass if all attributes/types specified in the hash are
160
- defined on the field.
161
-
162
- For better fluency, `accept_arguments` is also available in singular form, as
163
- `accept_argument`.
164
-
165
125
  ### 5) Test an object's interface implementations:
166
126
 
167
127
  ```ruby
168
128
  describe PostType do
129
+ subject { described_class }
130
+
169
131
  it 'implements interface Node' do
170
132
  expect(subject).to implement('Node')
171
133
  end
@@ -178,6 +140,8 @@ end
178
140
 
179
141
  ## TODO
180
142
 
143
+ - Support GraphQL 1.9.x;
144
+ - Check the method used for resolving a field;
181
145
  - New matchers!
182
146
 
183
147
  ## Contributing
@@ -0,0 +1,73 @@
1
+ require_relative 'base_matcher'
2
+ require_relative './have_a_field_matchers/of_type'
3
+
4
+ module RSpec
5
+ module GraphqlMatchers
6
+ class AcceptArgument < BaseMatcher
7
+ def initialize(expected_arg_name)
8
+ @expectations = []
9
+
10
+ if expected_arg_name.is_a?(Hash)
11
+ (expected_arg_name, expected_type) = expected_arg_name.to_a.first
12
+ of_type(expected_type)
13
+
14
+ warn 'DEPRECATION WARNING: using accept_arguments with a hash will be '\
15
+ 'deprecated on the next major release. Use the format ' \
16
+ "`accept_argument(:argument_name).of_type('ExpectedType!') instead.`"
17
+ end
18
+
19
+ @expected_arg_name = expected_arg_name.to_s
20
+ end
21
+
22
+ def matches?(graph_object)
23
+ @graph_object = graph_object
24
+
25
+ @actual_argument = field_arguments[@expected_arg_name]
26
+ return false if @actual_argument.nil?
27
+
28
+ @results = @expectations.select do |matcher|
29
+ !matcher.matches?(@actual_argument)
30
+ end
31
+
32
+ @results.empty?
33
+ end
34
+
35
+ def of_type(expected_field_type)
36
+ @expectations << HaveAFieldMatchers::OfType.new(expected_field_type)
37
+ self
38
+ end
39
+
40
+ def failure_message
41
+ base_msg = "expected #{member_name(@graph_object)} " \
42
+ "to accept argument `#{@expected_arg_name}`" \
43
+
44
+ return "#{base_msg} #{failure_messages.join(', ')}" if @actual_argument
45
+
46
+ "#{base_msg} but no argument was found with that name"
47
+ end
48
+
49
+ def description
50
+ ["accept argument `#{@expected_arg_name}`"].concat(descriptions).join(', ')
51
+ end
52
+
53
+ private
54
+
55
+ def descriptions
56
+ @results.map(&:description)
57
+ end
58
+
59
+ def failure_messages
60
+ @results.map(&:failure_message)
61
+ end
62
+
63
+ def field_arguments
64
+ if @graph_object.respond_to?(:arguments)
65
+ @graph_object.public_send(:arguments)
66
+ else
67
+ raise "Invalid object #{@graph_object} provided to accept_argument " \
68
+ 'matcher. It does not seem to be a valid GraphQL object type.'
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,5 +1,5 @@
1
1
  require_relative 'base_matcher'
2
- require 'pry'
2
+
3
3
  module RSpec
4
4
  module GraphqlMatchers
5
5
  class AcceptArguments < BaseMatcher
@@ -10,10 +10,13 @@ module RSpec
10
10
  end
11
11
 
12
12
  def types_match?(actual_type, expected_type)
13
- actual_type = actual_type.to_graphql if actual_type.respond_to?(:to_graphql)
14
- expected_type = expected_type.to_graphql if expected_type.respond_to?(:to_graphql)
13
+ expected_type.nil? || type_name(expected_type) == type_name(actual_type)
14
+ end
15
+
16
+ def type_name(a_type)
17
+ a_type = a_type.to_graphql if a_type.respond_to?(:to_graphql)
15
18
 
16
- expected_type.nil? || expected_type.to_s == actual_type.to_s
19
+ a_type.to_s
17
20
  end
18
21
  end
19
22
  end
@@ -1,4 +1,5 @@
1
1
  require_relative 'base_matcher'
2
+ require 'pry'
2
3
 
3
4
  module RSpec
4
5
  module GraphqlMatchers
@@ -11,12 +12,12 @@ module RSpec
11
12
 
12
13
  def matches?(actual_sample)
13
14
  @sample = actual_sample
14
- sample.respond_to?(:type) && sample.type.to_s == @expected.to_s
15
+ sample.respond_to?(:type) && types_match?(sample.type, @expected)
15
16
  end
16
17
 
17
18
  def failure_message
18
19
  "expected field '#{member_name(sample)}' to be of type '#{expected}', " \
19
- "but it was '#{sample.type}'"
20
+ "but it was '#{type_name(sample.type)}'"
20
21
  end
21
22
 
22
23
  def description
@@ -7,18 +7,10 @@ require_relative './have_a_field_matchers/with_hash_key'
7
7
  module RSpec
8
8
  module GraphqlMatchers
9
9
  class HaveAField < BaseMatcher
10
- DESCRIPTIONS = {
11
- type: 'of type `%s`',
12
- property: 'reading from the `%s` property',
13
- hash_key: 'reading from the `%s` hash_key',
14
- metadata: 'with metadata `%s`'
15
- }.freeze
16
-
17
10
  def initialize(expected_field_name, fields = :fields)
18
11
  @expected_field_name = expected_field_name.to_s
19
12
  @fields = fields.to_sym
20
13
  @expectations = []
21
- @descriptions = []
22
14
  end
23
15
 
24
16
  def matches?(graph_object)
@@ -62,7 +54,7 @@ module RSpec
62
54
  base_msg = "expected #{member_name(@graph_object)} " \
63
55
  "to define field `#{@expected_field_name}`" \
64
56
 
65
- return "#{base_msg} #{descriptions.join(', ')}" if @actual_field
57
+ return "#{base_msg} #{failure_messages.join(', ')}" if @actual_field
66
58
 
67
59
  "#{base_msg} but no field was found with that name"
68
60
  end
@@ -77,6 +69,10 @@ module RSpec
77
69
  @results.map(&:description)
78
70
  end
79
71
 
72
+ def failure_messages
73
+ @results.map(&:failure_message)
74
+ end
75
+
80
76
  def field_collection
81
77
  if @graph_object.respond_to?(@fields)
82
78
  @graph_object.public_send(@fields)
@@ -5,6 +5,10 @@ module RSpec
5
5
  def description
6
6
  "of type `#{expected}`"
7
7
  end
8
+
9
+ def failure_message
10
+ "#{description}, but it was `#{type_name(sample.type)}`"
11
+ end
8
12
  end
9
13
  end
10
14
  end
@@ -11,7 +11,12 @@ module RSpec
11
11
  end
12
12
 
13
13
  def matches?(actual_field)
14
- get_hash_key(actual_field) == @expected_hash_key.to_sym
14
+ @actual_hash_key = get_hash_key(actual_field)
15
+ @actual_hash_key == @expected_hash_key.to_sym
16
+ end
17
+
18
+ def failure_message
19
+ "#{description}, but it was `#{@actual_hash_key}`"
15
20
  end
16
21
 
17
22
  private
@@ -11,8 +11,13 @@ module RSpec
11
11
  end
12
12
 
13
13
  def matches?(actual_field)
14
+ @actual_metadata = actual_field.metadata
14
15
  actual_field.metadata == @expected_metadata
15
16
  end
17
+
18
+ def failure_message
19
+ "#{description}, but it was `#{@actual_metadata}`"
20
+ end
16
21
  end
17
22
  end
18
23
  end
@@ -11,7 +11,12 @@ module RSpec
11
11
  end
12
12
 
13
13
  def matches?(actual_field)
14
- actual_field.property.to_sym == @expected_property_name.to_sym
14
+ @actual_property = actual_field.property.to_sym
15
+ @actual_property == @expected_property_name.to_sym
16
+ end
17
+
18
+ def failure_message
19
+ "#{description}, but it was `#{@actual_property}`"
15
20
  end
16
21
  end
17
22
  end
@@ -3,8 +3,8 @@ require_relative 'base_matcher'
3
3
  module RSpec
4
4
  module GraphqlMatchers
5
5
  class Implement < BaseMatcher
6
- def initialize(interface_names)
7
- @expected = interface_names.map(&:to_s)
6
+ def initialize(interfaces)
7
+ @expected = interfaces.map {|interface| interface_name(interface) }
8
8
  end
9
9
 
10
10
  def matches?(graph_object)
@@ -33,13 +33,13 @@ module RSpec
33
33
 
34
34
  def actual
35
35
  if @graph_object.respond_to?(:interfaces)
36
- @graph_object.interfaces.map do |interface|
36
+ return @graph_object.interfaces.map do |interface|
37
37
  interface_name(interface)
38
38
  end
39
- else
40
- raise "Invalid object #{@graph_object} provided to #{matcher_name} " \
41
- 'matcher. It does not seem to be a valid GraphQL object type.'
42
39
  end
40
+
41
+ raise "Invalid object #{@graph_object} provided to #{matcher_name} " \
42
+ 'matcher. It does not seem to be a valid GraphQL object type.'
43
43
  end
44
44
 
45
45
  def interface_name(interface)
@@ -1,6 +1,7 @@
1
1
  require 'rspec/matchers'
2
2
  require 'rspec/graphql_matchers/be_of_type'
3
3
  require 'rspec/graphql_matchers/accept_arguments'
4
+ require 'rspec/graphql_matchers/accept_argument'
4
5
  require 'rspec/graphql_matchers/have_a_field'
5
6
  require 'rspec/graphql_matchers/implement'
6
7
 
@@ -10,10 +11,13 @@ module RSpec
10
11
  RSpec::GraphqlMatchers::BeOfType.new(expected)
11
12
  end
12
13
 
14
+ def accept_argument(expected_argument)
15
+ RSpec::GraphqlMatchers::AcceptArgument.new(expected_argument)
16
+ end
17
+
13
18
  def accept_arguments(expected_args)
14
19
  RSpec::GraphqlMatchers::AcceptArguments.new(expected_args)
15
20
  end
16
- alias accept_argument accept_arguments
17
21
 
18
22
  # rubocop:disable Style/PredicateName
19
23
  def have_a_field(field_name)
@@ -1,5 +1,5 @@
1
1
  module Rspec
2
2
  module GraphqlMatchers
3
- VERSION = '1.0.0-0.1'.freeze
3
+ VERSION = '1.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_matchers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.0.1
4
+ version: '1.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Brandão
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-18 00:00:00.000000000 Z
11
+ date: 2019-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -108,6 +108,7 @@ files:
108
108
  - bin/console
109
109
  - bin/setup
110
110
  - lib/rspec/graphql_matchers.rb
111
+ - lib/rspec/graphql_matchers/accept_argument.rb
111
112
  - lib/rspec/graphql_matchers/accept_arguments.rb
112
113
  - lib/rspec/graphql_matchers/base_matcher.rb
113
114
  - lib/rspec/graphql_matchers/be_of_type.rb
@@ -120,6 +121,7 @@ files:
120
121
  - lib/rspec/graphql_matchers/matchers.rb
121
122
  - lib/rspec/graphql_matchers/types_helper.rb
122
123
  - lib/rspec/graphql_matchers/version.rb
124
+ - rspec-graphql_matchers-1.0.0.pre.0.1.gem
123
125
  - rspec-graphql_matchers.gemspec
124
126
  homepage: https://github.com/khamusa/rspec-graphql_matchers
125
127
  licenses:
@@ -136,9 +138,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
138
  version: '0'
137
139
  required_rubygems_version: !ruby/object:Gem::Requirement
138
140
  requirements:
139
- - - ">"
141
+ - - ">="
140
142
  - !ruby/object:Gem::Version
141
- version: 1.3.1
143
+ version: '0'
142
144
  requirements: []
143
145
  rubyforge_project:
144
146
  rubygems_version: 2.7.8