artemis 0.5.1 → 0.7.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +64 -0
  3. data/.gitignore +1 -0
  4. data/Appraisals +12 -20
  5. data/CHANGELOG.md +45 -0
  6. data/Gemfile +2 -0
  7. data/README.md +71 -6
  8. data/artemis.gemspec +0 -1
  9. data/gemfiles/rails_50.gemfile +3 -1
  10. data/gemfiles/rails_51.gemfile +3 -1
  11. data/gemfiles/rails_52.gemfile +3 -1
  12. data/gemfiles/rails_60.gemfile +3 -1
  13. data/gemfiles/{rails_40.gemfile → rails_61.gemfile} +5 -3
  14. data/gemfiles/{rails_41.gemfile → rails_70.gemfile} +5 -4
  15. data/gemfiles/rails_edge.gemfile +2 -0
  16. data/lib/artemis/adapters/abstract_adapter.rb +1 -1
  17. data/lib/artemis/adapters/curb_adapter.rb +17 -7
  18. data/lib/artemis/adapters/multi_domain_adapter.rb +58 -0
  19. data/lib/artemis/adapters/net_http_adapter.rb +25 -16
  20. data/lib/artemis/adapters/net_http_persistent_adapter.rb +7 -1
  21. data/lib/artemis/adapters/test_adapter.rb +22 -3
  22. data/lib/artemis/adapters.rb +1 -0
  23. data/lib/artemis/client.rb +42 -8
  24. data/lib/artemis/graphql_endpoint.rb +11 -5
  25. data/lib/artemis/railtie.rb +16 -8
  26. data/lib/artemis/test_helper.rb +2 -1
  27. data/lib/artemis/version.rb +1 -1
  28. data/lib/generators/artemis/mutation/templates/mutation.graphql +1 -1
  29. data/lib/generators/artemis/query/query_generator.rb +14 -2
  30. data/lib/generators/artemis/query/templates/fixture.yml +19 -0
  31. data/lib/generators/artemis/query/templates/query.graphql +2 -2
  32. data/spec/adapters_spec.rb +165 -10
  33. data/spec/autoloading_spec.rb +4 -4
  34. data/spec/client_spec.rb +38 -2
  35. data/spec/fixtures/metaphysics/{_artist_fragment.graphql → _artist_fields.graphql} +0 -0
  36. data/spec/fixtures/metaphysics/artists.graphql +1 -1
  37. data/spec/fixtures/responses/{spotify → spotify_client}/artist.yml +0 -0
  38. data/spec/test_helper_spec.rb +10 -1
  39. metadata +13 -26
  40. data/.travis.yml +0 -69
  41. data/gemfiles/rails_42.gemfile +0 -12
@@ -167,17 +167,19 @@ module Artemis
167
167
  end
168
168
 
169
169
  def resolve_graphql_file_path(filename, fragment: false)
170
- namespace = name.underscore
171
- filename = filename.to_s.underscore
170
+ filename = filename.to_s.underscore
172
171
 
173
172
  graphql_file_paths.detect do |path|
174
- path.end_with?("#{namespace}/#{filename}.graphql") ||
175
- (fragment && filename.end_with?('fragment') && path.end_with?("#{namespace}/_#{filename}.graphql"))
173
+ path.end_with?("#{namespace}/#{filename}.graphql") || (fragment && path.end_with?("#{namespace}/_#{filename}.graphql"))
176
174
  end
177
175
  end
178
176
 
179
177
  def graphql_file_paths
180
- @graphql_file_paths ||= query_paths.flat_map {|path| Dir["#{path}/#{name.underscore}/*.graphql"] }
178
+ @graphql_file_paths ||= query_paths.flat_map {|path| Dir["#{path}/#{namespace}/*.graphql"] }
179
+ end
180
+
181
+ def namespace
182
+ name.underscore
181
183
  end
182
184
 
183
185
  def preload!
@@ -218,6 +220,19 @@ module Artemis
218
220
  new(default_context).execute(query, context: context, **arguments)
219
221
  end
220
222
 
223
+ def multiplex(**context, &block)
224
+ queue = MultiplexQueue.new
225
+ wrapped_executor = Executor.new(queue, callbacks, default_context.deep_merge(context))
226
+ api_client = ::GraphQL::Client.new(schema: endpoint.schema, execute: wrapped_executor)
227
+
228
+ service_client = new
229
+ service_client.instance_variable_set(:@client, api_client)
230
+
231
+ block.call(service_client)
232
+
233
+ connection.multiplex(queue.queries, context: context)
234
+ end
235
+
221
236
  private
222
237
 
223
238
  # Looks up the GraphQL file that matches the given +const_name+ and sets it to a constant. If the files it not
@@ -248,9 +263,9 @@ module Artemis
248
263
  # Github.user # => delegates to Github.new(default_context).user
249
264
  #
250
265
  # @api private
251
- def method_missing(method_name, *arguments, &block)
266
+ def method_missing(method_name, **arguments, &block)
252
267
  if resolve_graphql_file_path(method_name)
253
- new(default_context).public_send(method_name, *arguments, &block)
268
+ new(default_context).public_send(method_name, **arguments, &block)
254
269
  else
255
270
  super
256
271
  end
@@ -345,6 +360,25 @@ module Artemis
345
360
  end
346
361
  end
347
362
 
348
- private_constant :Callbacks, :Executor
363
+ class MultiplexQueue
364
+ attr_reader :queries
365
+
366
+ def initialize
367
+ @queries = []
368
+ end
369
+
370
+ def execute(document:, operation_name: nil, variables: {}, context: {}) #:nodoc:
371
+ @queries << {
372
+ query: document.to_query_string,
373
+ variables: variables.presence || {},
374
+ operationName: operation_name,
375
+ context: context
376
+ }
377
+
378
+ {}
379
+ end
380
+ end
381
+
382
+ private_constant :Callbacks, :Executor, :MultiplexQueue
349
383
  end
350
384
  end
@@ -33,7 +33,7 @@ module Artemis
33
33
  end
34
34
 
35
35
  def register!(service_name, configurations)
36
- ENDPOINT_INSTANCES[service_name.to_s.underscore] = new(service_name.to_s, configurations.symbolize_keys)
36
+ ENDPOINT_INSTANCES[service_name.to_s.underscore] = new(service_name.to_s, **configurations.symbolize_keys)
37
37
  end
38
38
 
39
39
  ##
@@ -44,10 +44,16 @@ module Artemis
44
44
  end
45
45
  end
46
46
 
47
- attr_reader :name, :url, :adapter, :timeout, :schema_path, :pool_size
47
+ attr_reader :name, :url, :adapter, :timeout, :schema_path, :pool_size, :adapter_options
48
48
 
49
- def initialize(name, url: nil, adapter: :net_http, timeout: 10, schema_path: nil, pool_size: 25)
50
- @name, @url, @adapter, @timeout, @schema_path, @pool_size = name.to_s, url, adapter, timeout, schema_path, pool_size
49
+ def initialize(name, url: nil, adapter: :net_http, timeout: 10, schema_path: nil, pool_size: 25, adapter_options: {})
50
+ @name = name.to_s
51
+ @url = url
52
+ @adapter = adapter
53
+ @timeout = timeout
54
+ @schema_path = schema_path
55
+ @pool_size = pool_size
56
+ @adapter_options = adapter_options
51
57
 
52
58
  @mutex_for_schema = Mutex.new
53
59
  @mutex_for_connection = Mutex.new
@@ -66,7 +72,7 @@ module Artemis
66
72
 
67
73
  def connection
68
74
  @connection || @mutex_for_connection.synchronize do
69
- @connection ||= ::Artemis::Adapters.lookup(adapter).new(url, service_name: name, timeout: timeout, pool_size: pool_size)
75
+ @connection ||= ::Artemis::Adapters.lookup(adapter).new(url, service_name: name, timeout: timeout, pool_size: pool_size, adapter_options: adapter_options)
70
76
  end
71
77
  end
72
78
  end
@@ -35,10 +35,9 @@ module Artemis
35
35
  files_to_watch = Artemis::Client.query_paths.map {|path| [path, config.artemis.graphql_extentions] }.to_h
36
36
 
37
37
  app.reloaders << ActiveSupport::FileUpdateChecker.new([], files_to_watch) do
38
- endpoint_names = Artemis.config_for_graphql(app).keys
39
- endpoint_names.each do |endpoint_name|
38
+ Artemis.config_for_graphql(app).each_key do |endpoint_name|
40
39
  Artemis::Client.query_paths.each do |path|
41
- FileUtils.touch("#{path}/#{endpoint_name}.rb")
40
+ FileUtils.touch("#{path}/#{endpoint_name}.rb") if File.exist?("#{path}/#{endpoint_name}.rb")
42
41
  end
43
42
  end
44
43
  end
@@ -48,17 +47,26 @@ module Artemis
48
47
  initializer 'graphql.client.load_config' do |app|
49
48
  if Pathname.new("#{app.paths["config"].existent.first}/graphql.yml").exist?
50
49
  Artemis.config_for_graphql(app).each do |endpoint_name, options|
51
- Artemis::GraphQLEndpoint.register!(endpoint_name, {
52
- schema_path: app.root.join(config.artemis.schema_path, "#{endpoint_name}.json").to_s
53
- }.merge(options.symbolize_keys))
50
+ Artemis::GraphQLEndpoint
51
+ .register!(
52
+ endpoint_name,
53
+ schema_path: app.root.join(config.artemis.schema_path, "#{endpoint_name}.json").to_s,
54
+ **options.symbolize_keys
55
+ )
54
56
  end
55
57
  end
56
58
  end
57
59
 
58
60
  initializer 'graphql.client.preload', after: 'graphql.client.load_config' do |app|
59
61
  if app.config.eager_load && app.config.cache_classes
60
- Artemis.config_for_graphql(app).keys.each do |endpoint_name|
61
- endpoint_name.to_s.camelize.constantize.preload!
62
+ Artemis::GraphQLEndpoint.registered_services.each do |endpoint_name|
63
+ begin
64
+ require endpoint_name # Rails 7.0 requires this.
65
+ rescue LoadError
66
+ # no-op...
67
+ end
68
+
69
+ endpoint_name.camelize.constantize.preload!
62
70
  end
63
71
  end
64
72
  end
@@ -4,6 +4,7 @@ require 'erb'
4
4
  require 'yaml'
5
5
 
6
6
  require 'active_support/core_ext/module/attribute_accessors'
7
+ require 'active_support/core_ext/string/inflections'
7
8
 
8
9
  require 'artemis/exceptions'
9
10
 
@@ -110,7 +111,7 @@ module Artemis
110
111
 
111
112
  def find_fixture_set
112
113
  fixture_set = fixture_sets
113
- .detect { |fixture| %r{#{service_name.downcase}/#{query_name}\.(yml|json)\z} =~ fixture.path }
114
+ .detect { |fixture| %r{#{service_name.underscore}/#{query_name}\.(yml|json)\z} =~ fixture.path }
114
115
  fixture_set ||= fixture_sets.detect { |fixture| fixture.name == query_name.to_s }
115
116
 
116
117
  if fixture_set.nil?
@@ -1,3 +1,3 @@
1
1
  module Artemis
2
- VERSION = "0.5.1"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -1,4 +1,4 @@
1
- mutation<%= arguments.present? && "(#{ arguments.map {|name, type| "$#{name}: #{type.type}" }.join(", ") })" %> {
1
+ mutation<%= arguments.present? && "(#{ arguments.map {|name, type| "$#{name}: #{type.type.to_type_signature}" }.join(", ") })" %> {
2
2
  <%= target_mutation.name %><%= arguments.present? && "(#{ arguments.map {|name, type| "#{name}: $#{name}" }.join(", ") })" %> {
3
3
  # Add fields here...
4
4
  }
@@ -14,6 +14,10 @@ class Artemis::QueryGenerator < Rails::Generators::Base
14
14
  template "query.graphql", graphql_file_path
15
15
  end
16
16
 
17
+ # def generate_text_fixture_file
18
+ # template "fixture.yml", text_fixture_path
19
+ # end
20
+
17
21
  private
18
22
 
19
23
  def query_name
@@ -21,7 +25,11 @@ class Artemis::QueryGenerator < Rails::Generators::Base
21
25
  end
22
26
 
23
27
  def graphql_file_path
24
- "app/operations/#{service_name.underscore}/#{graphql_file_name.presence || query_name}.graphql"
28
+ "app/operations/#{service_name.underscore}/#{qualified_name}.graphql"
29
+ end
30
+
31
+ def text_fixture_path
32
+ File.join(Artemis::Railtie.config.artemis.fixture_path, service_name.underscore, "#{qualified_name}.yml")
25
33
  end
26
34
 
27
35
  def arguments
@@ -29,7 +37,7 @@ class Artemis::QueryGenerator < Rails::Generators::Base
29
37
  end
30
38
 
31
39
  def target_query
32
- schema.find("Query").fields[query_type] ||
40
+ schema.query.fields[query_type] ||
33
41
  raise(GraphQL::Schema::Finder::MemberNotFoundError, "Could not find type `#{query_type}` in schema.")
34
42
  end
35
43
 
@@ -49,4 +57,8 @@ class Artemis::QueryGenerator < Rails::Generators::Base
49
57
  end
50
58
  end
51
59
  end
60
+
61
+ def qualified_name
62
+ graphql_file_name.presence || query_name
63
+ end
52
64
  end
@@ -0,0 +1,19 @@
1
+ # You can stub GraphQL queries by calling the `stub_graphql' method in test:
2
+ #
3
+ # stub_graphql(<%= service_name.camelize %>, :<%= qualified_name.underscore %>).to_return(:<%= target_query.name %>_1)
4
+ #
5
+ # Or with a arguments matcher:
6
+ #
7
+ # stub_graphql(<%= service_name.camelize %>, :<%= qualified_name.underscore %>, <%= arguments.map {|name, _| "#{name}: \"...\"" }.join(", ") %>).to_return(:<%= target_query.name %>_2)
8
+ #
9
+
10
+ <%= target_query.name %>_1:
11
+ data:
12
+ <% target_query.type.fields.values.each do |field| -%>
13
+ <%= field.name %>: # type: <%= field.type.to_type_signature %>
14
+ <% end %>
15
+ <%= target_query.name %>_2:
16
+ data:
17
+ <% target_query.type.fields.values.each do |field| -%>
18
+ <%= field.name %>: # type: <%= field.type.to_type_signature %>
19
+ <% end %>
@@ -1,5 +1,5 @@
1
- query<%= arguments.present? && "(#{ arguments.map {|name, type| "$#{name}: #{type.type}" }.join(", ") })" %> {
2
- <%= target_query.name %><%= arguments.present? && "(#{ arguments.map {|name, type| "#{name}: $#{name}" }.join(", ") })" %> {
1
+ query<%= arguments.present? ? "(#{ arguments.map {|name, type| "$#{name}: #{type.type.to_type_signature}" }.join(", ") })" : "" %> {
2
+ <%= target_query.name %><%= arguments.present? ? "(#{ arguments.map {|name, type| "#{name}: $#{name}" }.join(", ") })" : "" %> {
3
3
  # Add fields here...
4
4
  }
5
5
  }
@@ -1,28 +1,59 @@
1
1
  require 'json'
2
2
  require 'rack'
3
+ require 'webrick'
3
4
 
4
5
  describe 'Adapters' do
5
6
  FakeServer = ->(env) {
6
7
  case env['PATH_INFO']
7
8
  when '/slow_server'
8
- sleep 1.1
9
+ sleep 2.1
9
10
 
10
11
  [200, {}, ['{}']]
11
12
  when '/500'
12
13
  [500, {}, ['Server error']]
13
- else
14
+ when '/test_multi_domain'
14
15
  body = {
15
16
  data: {
16
- body: JSON.parse(env['rack.input'].read),
17
+ body: "Endpoint switched.",
17
18
  headers: env.select {|key, val| key.match("^HTTP.*|^CONTENT.*|^AUTHORIZATION.*") }
18
- .collect {|key, val| [key.gsub(/^HTTP_/, ''), val.downcase] }
19
- .to_h,
19
+ .collect {|key, val| [key.gsub(/^HTTP_/, ''), val.downcase] }
20
+ .to_h,
20
21
  },
21
22
  errors: [],
22
23
  extensions: {}
23
24
  }.to_json
24
25
 
25
26
  [200, {}, [body]]
27
+ else
28
+ request_body = JSON.parse(env['rack.input'].read)
29
+
30
+ response_body = if request_body['_json']
31
+ request_body['_json'].map do |query|
32
+ {
33
+ data: {
34
+ body: query,
35
+ headers: env.select {|key, val| key.match("^HTTP.*|^CONTENT.*|^AUTHORIZATION.*") }
36
+ .collect {|key, val| [key.gsub(/^HTTP_/, ''), val.downcase] }
37
+ .to_h,
38
+ },
39
+ errors: [],
40
+ extensions: {}
41
+ }
42
+ end.to_json
43
+ else
44
+ {
45
+ data: {
46
+ body: request_body,
47
+ headers: env.select {|key, val| key.match("^HTTP.*|^CONTENT.*|^AUTHORIZATION.*") }
48
+ .collect {|key, val| [key.gsub(/^HTTP_/, ''), val.downcase] }
49
+ .to_h,
50
+ },
51
+ errors: [],
52
+ extensions: {}
53
+ }.to_json
54
+ end
55
+
56
+ [200, {}, [response_body]]
26
57
  end
27
58
  }
28
59
 
@@ -91,6 +122,51 @@ describe 'Adapters' do
91
122
  end.to raise_error(timeout_error)
92
123
  end
93
124
  end
125
+
126
+ describe '#multiplex' do
127
+ it 'makes an HTTP request with multiple queries' do
128
+ response = adapter.multiplex(
129
+ [
130
+ {
131
+ query: GraphQL::Client::IntrospectionDocument.to_query_string,
132
+ operationName: 'IntrospectionQuery',
133
+ variables: {
134
+ id: 'yayoi-kusama'
135
+ },
136
+ },
137
+ ],
138
+ context: {
139
+ user_id: 1
140
+ }
141
+ )
142
+
143
+ introspection_query = response[0]
144
+
145
+ expect(introspection_query['data']['body']['query']).to eq(GraphQL::Client::IntrospectionDocument.to_query_string)
146
+ expect(introspection_query['data']['body']['variables']).to eq('id' => 'yayoi-kusama')
147
+ expect(introspection_query['data']['body']['operationName']).to eq('IntrospectionQuery')
148
+ expect(introspection_query['data']['headers']['CONTENT_TYPE']).to eq('application/json')
149
+ expect(introspection_query['data']['headers']['ACCEPT']).to eq('application/json')
150
+ expect(introspection_query['errors']).to eq([])
151
+ expect(introspection_query['extensions']).to eq({})
152
+ end
153
+
154
+ it 'raises an error when it receives a server error' do
155
+ adapter.uri = URI.parse('http://localhost:8000/500')
156
+
157
+ expect do
158
+ adapter.multiplex([])
159
+ end.to raise_error(Artemis::GraphQLServerError, "Received server error status 500: Server error")
160
+ end
161
+
162
+ it 'allows for overriding timeout' do
163
+ adapter.uri = URI.parse('http://localhost:8000/slow_server')
164
+
165
+ expect do
166
+ adapter.multiplex([])
167
+ end.to raise_error(timeout_error)
168
+ end
169
+ end
94
170
  end
95
171
 
96
172
  describe Artemis::Adapters::NetHttpAdapter do
@@ -102,15 +178,94 @@ describe 'Adapters' do
102
178
 
103
179
  describe Artemis::Adapters::NetHttpPersistentAdapter do
104
180
  let(:adapter) { Artemis::Adapters::NetHttpPersistentAdapter.new('http://localhost:8000', service_name: nil, timeout: 0.5, pool_size: 5) }
105
- let(:timeout_error) { Net::HTTP::Persistent::Error }
181
+ let(:timeout_error) { Net::ReadTimeout }
106
182
 
107
183
  it_behaves_like 'an adapter'
108
184
  end
109
185
 
110
- describe Artemis::Adapters::CurbAdapter do
111
- let(:adapter) { Artemis::Adapters::CurbAdapter.new('http://localhost:8000', service_name: nil, timeout: 2, pool_size: 5) }
112
- let(:timeout_error) { Curl::Err::TimeoutError }
186
+ describe Artemis::Adapters::MultiDomainAdapter do
187
+ let(:adapter) { Artemis::Adapters::MultiDomainAdapter.new('ignored', service_name: nil, timeout: 0.5, pool_size: 5, adapter_options: { adapter: :net_http }) }
113
188
 
114
- it_behaves_like 'an adapter'
189
+ it 'makes an actual HTTP request' do
190
+ response = adapter.execute(document: GraphQL::Client::IntrospectionDocument, context: { url: 'http://localhost:8000/test_multi_domain' })
191
+
192
+ expect(response['data']['body']).to eq("Endpoint switched.")
193
+ expect(response['errors']).to eq([])
194
+ expect(response['extensions']).to eq({})
195
+ end
196
+
197
+ it 'can make a multiplex (the graphql feature, not HTTP/2) request' do
198
+ response = adapter.multiplex(
199
+ [
200
+ {
201
+ query: GraphQL::Client::IntrospectionDocument.to_query_string,
202
+ operationName: 'IntrospectionQuery',
203
+ variables: {
204
+ id: 'yayoi-kusama'
205
+ },
206
+ },
207
+ ],
208
+ context: {
209
+ url: 'http://localhost:8000/test_multi_domain'
210
+ }
211
+ )
212
+
213
+ expect(response['data']['body']).to eq("Endpoint switched.")
214
+ expect(response['errors']).to eq([])
215
+ expect(response['extensions']).to eq({})
216
+ end
217
+
218
+ it 'can make a multiplex request with custom HTTP headers' do
219
+ response = adapter.multiplex(
220
+ [
221
+ {
222
+ query: GraphQL::Client::IntrospectionDocument.to_query_string,
223
+ operationName: 'IntrospectionQuery',
224
+ },
225
+ ],
226
+ context: {
227
+ headers: {
228
+ Authorization: "Token token",
229
+ },
230
+ url: 'http://localhost:8000/test_multi_domain'
231
+ }
232
+ )
233
+
234
+ expect(response['data']['headers']['AUTHORIZATION']).to eq("token token")
235
+ end
236
+
237
+ it 'raises an error when adapter_options.adapter is set to :multi domain' do
238
+ expect do
239
+ Artemis::Adapters::MultiDomainAdapter.new('ignored', service_name: nil, timeout: 0.5, pool_size: 5, adapter_options: { adapter: :multi_domain })
240
+ end.to raise_error(ArgumentError, 'You can not use the :multi_domain adapter with the :multi_domain adapter.')
241
+ end
242
+
243
+ it 'raises an error when context.url is not specified' do
244
+ expect do
245
+ adapter.execute(document: GraphQL::Client::IntrospectionDocument)
246
+ end.to raise_error(ArgumentError, 'The MultiDomain adapter requires a url on every request. Please specify a ' \
247
+ 'url with a context: Client.with_context(url: "https://awesomeshop.domain.conm")')
248
+ end
249
+
250
+ it 'raises an error when it receives a server error' do
251
+ expect do
252
+ adapter.execute(document: GraphQL::Client::IntrospectionDocument, context: { url: 'http://localhost:8000/500' })
253
+ end.to raise_error(Artemis::GraphQLServerError, "Received server error status 500: Server error")
254
+ end
255
+
256
+ it 'allows for overriding timeout' do
257
+ expect do
258
+ adapter.execute(document: GraphQL::Client::IntrospectionDocument, context: { url: 'http://localhost:8000/slow_server' })
259
+ end.to raise_error(Net::ReadTimeout)
260
+ end
261
+ end
262
+
263
+ if RUBY_ENGINE == 'ruby'
264
+ describe Artemis::Adapters::CurbAdapter do
265
+ let(:adapter) { Artemis::Adapters::CurbAdapter.new('http://localhost:8000', service_name: nil, timeout: 2, pool_size: 5) }
266
+ let(:timeout_error) { Curl::Err::TimeoutError }
267
+
268
+ it_behaves_like 'an adapter'
269
+ end
115
270
  end
116
271
  end
@@ -15,7 +15,7 @@ describe "#{GraphQL::Client} Autoloading" do
15
15
 
16
16
  describe ".preload!" do
17
17
  it "preloads all the graphQL files in the query paths" do
18
- %i(Artist Artwork ArtistFragment)
18
+ %i(Artist Artists Artwork ArtistFields)
19
19
  .select {|const_name| Metaphysics.constants.include?(const_name) }
20
20
  .each {|const_name| Metaphysics.send(:remove_const, const_name) }
21
21
 
@@ -43,12 +43,12 @@ describe "#{GraphQL::Client} Autoloading" do
43
43
  end
44
44
 
45
45
  it "dynamically loads the matching GraphQL fragment and sets it to a constant" do
46
- Metaphysics.send(:remove_const, :ArtistFragment) if Metaphysics.constants.include?(:ArtistFragment)
46
+ Metaphysics.send(:remove_const, :ArtistFields) if Metaphysics.constants.include?(:ArtistFields)
47
47
 
48
- query = Metaphysics::ArtistFragment
48
+ query = Metaphysics::ArtistFields
49
49
 
50
50
  expect(query.document.to_query_string).to eq(<<~GRAPHQL.strip)
51
- fragment Metaphysics__ArtistFragment on Artist {
51
+ fragment Metaphysics__ArtistFields on Artist {
52
52
  hometown
53
53
  deathday
54
54
  }
data/spec/client_spec.rb CHANGED
@@ -86,11 +86,11 @@ describe GraphQL::Client do
86
86
  name
87
87
  bio
88
88
  birthday
89
- ...Metaphysics__ArtistFragment
89
+ ...Metaphysics__ArtistFields
90
90
  }
91
91
  }
92
92
 
93
- fragment Metaphysics__ArtistFragment on Artist {
93
+ fragment Metaphysics__ArtistFields on Artist {
94
94
  hometown
95
95
  deathday
96
96
  }
@@ -171,6 +171,42 @@ describe GraphQL::Client do
171
171
  end
172
172
  end
173
173
 
174
+ it "can batch multiple requests using Multiplex" do
175
+ responses = Metaphysics.multiplex do |queue|
176
+ queue.artist(id: "yayoi-kusama", context: { headers: { Authorization: 'bearer ...' } })
177
+ queue.artwork
178
+ end
179
+
180
+ artist_query, artwork_query = requests[0].queries
181
+
182
+ expect(artist_query[:operationName]).to eq('Metaphysics__Artist')
183
+ expect(artist_query[:variables]).to eq('id' => 'yayoi-kusama')
184
+ expect(artist_query[:context]).to eq({ headers: { Authorization: 'bearer ...' } })
185
+ expect(artist_query[:query]).to eq(<<~GRAPHQL.strip)
186
+ query Metaphysics__Artist($id: String!) {
187
+ artist(id: $id) {
188
+ name
189
+ bio
190
+ birthday
191
+ }
192
+ }
193
+ GRAPHQL
194
+
195
+ expect(artwork_query[:operationName]).to eq('Metaphysics__Artwork')
196
+ expect(artwork_query[:variables]).to be_empty
197
+ expect(artwork_query[:context]).to eq({})
198
+ expect(artwork_query[:query]).to eq(<<~GRAPHQL.strip)
199
+ query Metaphysics__Artwork {
200
+ artwork(id: "yayoi-kusama-pumpkin-yellow-and-black") {
201
+ title
202
+ artist {
203
+ name
204
+ }
205
+ }
206
+ }
207
+ GRAPHQL
208
+ end
209
+
174
210
  private
175
211
 
176
212
  def requests
@@ -3,6 +3,6 @@ query($size: Int!) {
3
3
  name
4
4
  bio
5
5
  birthday
6
- ...Metaphysics::ArtistFragment
6
+ ...Metaphysics::ArtistFields
7
7
  }
8
8
  }
@@ -70,8 +70,17 @@ describe Artemis::TestHelper do
70
70
  expect(yoshiki.data.artist.name).to eq("Artist Yoshiki")
71
71
  end
72
72
 
73
+ it "can mock separate GraphQL queries with the same arguments" do
74
+ stub_graphql("SpotifyClient", :artist, id: "yoshiki").to_return(:yoshiki)
75
+ stub_graphql(Metaphysics, :artist, id: "yoshiki").to_return(:yoshiki)
76
+
77
+ yoshiki = Metaphysics.artist(id: "yoshiki")
78
+
79
+ expect(yoshiki.data.artist.name).to eq("Artist Yoshiki")
80
+ end
81
+
73
82
  it "allows to get raw fixture data as a Hash" do
74
- data = stub_graphql("Spotify", :artist).get(:yoshiki)
83
+ data = stub_graphql("SpotifyClient", :artist).get(:yoshiki)
75
84
 
76
85
  expect(data).to eq({
77
86
  "data" => {