rspec-graphql_matchers 1.0.0.pre.0.1 → 1.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: 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