artemis 0.2.0 → 0.4.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: ac727e89f6d2c0845b888ea9eeb526bf2607689fa268c9f815b9af3c25c83d72
4
- data.tar.gz: 1cb2c9c3de64e95b729f579dfb4a8bd93a07d6ac4732647bf7aa94a360a6624a
3
+ metadata.gz: 0b5fc48841d80c3f0ebd0cc161938caf1044b09ce300bb55822df3ae1323aed2
4
+ data.tar.gz: e42427484c1786929c66a2f8a7650cb2e631230155f92c92e5d36406a20a41b0
5
5
  SHA512:
6
- metadata.gz: 041b006e10af9271e6cb024f2acfdc1597969ad44ccf371235a12f95c2464afac66110967db926ece6df3c46c3161b3b3f54436ea276b0362234c27f13e5933e
7
- data.tar.gz: 0daaea8bebcbf4ea6c9225781f591b4cd069aa6517dacb09043500b29357c1140d4169ed00e55046003702489addbfea60ef7703bc607692186ef61c7d94c0ac
6
+ metadata.gz: 1b0625a78d265426de79dc77ace3f0ff2336e75a914b37b4179356ec3f0c69c2beda8658e1b0cabf914221aea92e6fb86c6510075b6ab9c9c0e9f04cb1c37368
7
+ data.tar.gz: f80b1e917bfaac00586704ab09a3893f7d879b02a62b5693816f1c7977fed64233585b7e0d17ab8ae7877efdab2a5efc951eab4928f9120d90a41c9895cd0c93
@@ -6,12 +6,12 @@ sudo: false
6
6
  before_install: gem install bundler -v 1.16.1
7
7
 
8
8
  rvm:
9
- - 2.5.1
10
- - 2.4.4
11
- - 2.3.7
12
- # - 2.2.10
9
+ - 2.6.0
10
+ - 2.5.3
11
+ - 2.4.5
12
+ - 2.3.8
13
13
  - ruby-head
14
- # - jruby-9.2.0.0
14
+ # - jruby-9.2.3.0
15
15
  # - jruby-head
16
16
 
17
17
  gemfile:
@@ -24,13 +24,11 @@ gemfile:
24
24
  matrix:
25
25
  allow_failures:
26
26
  - rvm: ruby-head
27
- # - rvm: jruby-9.2.0.0
27
+ # - rvm: jruby-9.2.3.0
28
28
  # - rvm: jruby-head
29
29
  - gemfile: gemfiles/rails_edge.gemfile
30
30
  exclude:
31
- - rvm: 2.3.7
31
+ - rvm: 2.4.5
32
+ gemfile: gemfiles/rails_edge.gemfile
33
+ - rvm: 2.3.8
32
34
  gemfile: gemfiles/rails_edge.gemfile
33
- # - rvm: 2.2.10
34
- # gemfile: gemfiles/rails_52.gemfile
35
- # - rvm: 2.2.10
36
- # gemfile: gemfiles/rails_edge.gemfile
@@ -1,11 +1,20 @@
1
1
  ## Unreleased
2
2
 
3
3
  * Add a new entry here
4
- * [#43](https://github.com/yuki24/artemis/pull/43): Keep persistent connections open for 30 minutes
5
- * [#42](https://github.com/yuki24/artemis/pull/42): Allow for setting up the test adapter without `url`
6
- * [#41](https://github.com/yuki24/artemis/pull/41): Add a mutation generator
7
- * [#40](https://github.com/yuki24/artemis/pull/40): Add a query generator
8
- * [#39](https://github.com/yuki24/artemis/pull/39): Installer now adds a new service if config/graphql.yml is present
4
+ * [#48](https://github.com/yuki24/artemis/pull/48): Do not transform keys of query variables [@erikdstock](https://github.com/erikdstock)
5
+ * [#47](https://github.com/yuki24/artemis/pull/47): Fixes an issue where errors thrown from `config/graphql.yml` get swallowed
6
+
7
+ ## [v0.2.0: New generators and small improvements](https://github.com/yuki24/artemis/tree/v0.2.0)
8
+
9
+ _<sup>released at 2018-10-30 02:09:59 UTC</sup>_
10
+
11
+ #### Features
12
+
13
+ - [#43](https://github.com/yuki24/artemis/pull/43): Keep persistent connections open for 30 minutes
14
+ - [#42](https://github.com/yuki24/artemis/pull/42): Allow for setting up the test adapter without `url`
15
+ - [#41](https://github.com/yuki24/artemis/pull/41): Add a mutation generator
16
+ - [#40](https://github.com/yuki24/artemis/pull/40): Add a query generator
17
+ - [#39](https://github.com/yuki24/artemis/pull/39): Installer now adds a new service if config/graphql.yml is present
9
18
 
10
19
  ## [v0.1.0: First release!](https://github.com/yuki24/artemis/tree/v0.1.0)
11
20
 
data/README.md CHANGED
@@ -1,12 +1,35 @@
1
1
  # Artemis [![Build Status](https://travis-ci.org/yuki24/artemis.svg?branch=master)](https://travis-ci.org/yuki24/artemis)
2
2
 
3
+ Artemis is a GraphQL client that is designed to fit well on Rails.
4
+
3
5
  * **Convention over Configuration**: You'll never have to make trivial decisions or spend time on boring setup. Start
4
- making a GraphQL request in literally 30sec.
6
+ making a GraphQL request in literally 30s.
5
7
  * **Performant by default**: You can't do wrong when it comes to performance. All GraphQL files are pre-loaded only
6
8
  once in production and it'll never affect runtime performance. Comes with options that enable persistent connections
7
- and even HTTP/2.0, the next-gen high-performance protocol.
9
+ and even HTTP/2, the next-gen high-performance protocol.
10
+ * **First-class support for testing**: Testing and stubbing GraphQL requests couldn't be simpler. No need to add
11
+ external dependencies to test well.
12
+
13
+ <img width="24" height="24" src="https://avatars1.githubusercontent.com/u/541332?s=48&amp;v=4"> Battle-tested at [Artsy](https://www.artsy.net)
14
+
15
+ ## Quick start
16
+
17
+ You could set up Artemis with just a few commands. See it in action:
8
18
 
9
- <img width="24" height="24" src="https://avatars1.githubusercontent.com/u/541332?s=48&amp;v=4"> Battled-tested at [Artsy](https://www.artsy.net)
19
+ ```bash
20
+ $ bundle add artemis
21
+ $ rails g artemis:install artsy https://metaphysics-production.artsy.net/
22
+ $ echo '
23
+ query($id: String!) {
24
+ artist(id: $id) {
25
+ name
26
+ birthday
27
+ }
28
+ }' > app/operations/artsy/artist.graphql
29
+ $ rails c
30
+ > Artsy.artist(id: "leonardo-da-vinci").data.artist.name # => "Leonardo da Vinci"
31
+ > Artsy.artist(id: "leonardo-da-vinci").data.artist.birthday # => "1452/04/15"
32
+ ```
10
33
 
11
34
  ## Getting started
12
35
 
@@ -85,6 +108,11 @@ Artemis assumes that the files related to GraphQL are organized in a certain way
85
108
  │   │   └── artists.graphql
86
109
  │   └── artsy.rb
87
110
  ├──config/graphql.yml
111
+ ├──test/fixtures/graphql
112
+ │  └── artsy
113
+ │  ├── artwork.yml
114
+ │  ├── artist.yml
115
+ │  └── artists.yml
88
116
  └──vendor/graphql/schema/artsy.json
89
117
  ```
90
118
 
@@ -136,7 +164,7 @@ There are four adapter options available. Choose the adapter that best fits on y
136
164
 
137
165
  | Adapter | Protocol | Keep-alive | Performance | Dependencies |
138
166
  | ---------------------- | ------------------------ | ----------- | ----------- | ------------ |
139
- | `:curb` | HTTP/1.1, **HTTP/2.0** | **Yes** | **Fastest** | [`curb 0.9.6+`][curb]<br>[`libcurl 7.64.0+`][curl]<br>[`nghttp2 1.0.0+`][nghttp]
167
+ | `:curb` | HTTP/1.1, **HTTP/2** | **Yes** | **Fastest** | [`curb 0.9.6+`][curb]<br>[`libcurl 7.64.0+`][curl]<br>[`nghttp2 1.0.0+`][nghttp]
140
168
  | `:net_http` (default) | HTTP/1.1 only | No | Slow | **None**
141
169
  | `:net_http_persistent` | HTTP/1.1 only | **Yes** | **Fast** | [`net-http-persistent 3.0.0+`][nhp]
142
170
  | `:test` | N/A (See Testing)
@@ -152,7 +180,73 @@ Artemis also adds a useful `rake graphql:schema:update` rake task that downloads
152
180
 
153
181
  ## Testing
154
182
 
155
- **The testing support is incomplete, but there are some examples [available in Artemis' client spec](https://github.com/yuki24/artemis/blob/74095f3acb050e87251439aed5f8b17778ffdd06/spec/client_spec.rb#L36-L54).**
183
+ Given that you have `app/operations/artsy/artist.graphql` and fixture file for the `artist.yml`:
184
+
185
+ ```yml
186
+ # test/fixtures/graphql/artist.yml:
187
+ leonardo_da_vinci:
188
+ data:
189
+ artist:
190
+ name: Leonardo da Vinci
191
+ birthday: 1452/04/15
192
+
193
+ yayoi_kusama:
194
+ data:
195
+ artist:
196
+ name: Yayoi Kusama
197
+ birthday: 1929/03/22
198
+ ```
199
+
200
+ Then you can stub the request with the `stub_graphql` DSL:
201
+
202
+ ```ruby
203
+ stub_graphql(Artsy, :artist, id: "yayoi-kusama").to_return(:yayoi_kusama)
204
+ stub_graphql(Artsy, :artist, id: "leonardo-da-vinci").to_return(:leonardo_da_vinci)
205
+
206
+ yayoi_kusama = Artsy.artist(id: "yayoi-kusama")
207
+ yayoi_kusama.data.artist.name # => "Yayoi Kusama"
208
+ yayoi_kusama.data.artist.birthday # => "1452/04/15"
209
+
210
+ da_vinci = Artsy.artist(id: "leonardo-da-vinci")
211
+ da_vinci.data.artist.name # => "Leonardo da Vinci"
212
+ da_vinci.data.artist.birthday # => "1452/04/15"
213
+ ```
214
+
215
+ You can also use JSON instead of YAML. See [example fixtures](https://github.com/yuki24/artemis/tree/master/spec/fixtures/responses)
216
+ and [test cases](https://github.com/yuki24/artemis/blob/master/spec/test_helper_spec.rb#L16-L51).
217
+
218
+ ### MiniTest
219
+
220
+ Setting up the test helper with Artemis is very easy and simple. Just add the following code to the
221
+ `test/test_helper.rb` in your app:
222
+
223
+ ```ruby
224
+ # spec/test_helper.rb
225
+ require 'artemis/test_helper'
226
+
227
+ class ActiveSupport::TestCase
228
+ setup do
229
+ graphql_requests.clear
230
+ graphql_responses.clear
231
+ end
232
+ end
233
+ ```
234
+
235
+ ### RSpec
236
+
237
+ Artemis also comes with a script that wires up helper methods on Rspec. Because it is more common to use the `spec/`
238
+ directory to organize spec files in RSpec, the `config.artemis.fixture_path` config needs to point to
239
+ `spec/fixtures/graphql`. Other than that, it is very straightforward to set it up:
240
+
241
+ ```ruby
242
+ # config/application.rb
243
+ config.artemis.fixture_path = 'spec/fixtures/graphql'
244
+ ```
245
+
246
+ ```ruby
247
+ # Add this to your spec/rails_helper.rb or spec_helper.rb if you don't have rails_helper.rb
248
+ require 'artemis/rspec'
249
+ ```
156
250
 
157
251
  ## Development
158
252
 
@@ -16,6 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.require_paths = ["lib"]
17
17
 
18
18
  spec.add_dependency "activesupport", ">= 4.2.0"
19
+ spec.add_dependency "graphql", ">= 1.8"
19
20
  spec.add_dependency "graphql-client", ">= 0.13.0"
20
21
  spec.add_dependency "railties", ">= 4.2.0"
21
22
 
@@ -3,12 +3,10 @@
3
3
  require "bundler/setup"
4
4
  require "artemis"
5
5
 
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
6
+ Artemis::Client.query_paths = [File.join(__dir__, '../spec/fixtures')]
7
+ Artemis::GraphQLEndpoint.register!(:metaphysics, adapter: :test, url: '', schema_path: 'spec/fixtures/metaphysics/schema.json')
8
+ Artemis::GraphQLEndpoint.lookup(:metaphysics).load_schema!
9
+ require_relative '../spec/fixtures/metaphysics'
8
10
 
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
11
+ require "pry"
12
+ Pry.start
@@ -8,6 +8,9 @@ module Artemis
8
8
  cattr_accessor :requests
9
9
  self.requests = []
10
10
 
11
+ cattr_accessor :responses
12
+ self.responses = []
13
+
11
14
  Request = Struct.new(:document, :operation_name, :variables, :context)
12
15
 
13
16
  private_constant :Request
@@ -18,7 +21,11 @@ module Artemis
18
21
  def execute(**arguments)
19
22
  self.requests << Request.new(*arguments.values_at(:document, :operation_name, :variables, :context))
20
23
 
21
- {
24
+ response = responses.detect do |mock|
25
+ arguments[:operation_name] == mock.operation_name && mock.arguments == :__unspecified__ || arguments[:variables] == mock.arguments
26
+ end
27
+
28
+ response&.data || {
22
29
  'data' => { 'test' => 'data' },
23
30
  'errors' => [],
24
31
  'extensions' => {}
@@ -177,6 +177,18 @@ module Artemis
177
177
  end
178
178
  end
179
179
 
180
+ # Looks up the GraphQL file that matches the given +const_name+ and sets it to a constant.
181
+ #
182
+ # # app/operations/github.rb
183
+ # class Github < Artemis::Client
184
+ # end
185
+ #
186
+ # defined?(Github::User) # => nil
187
+ # Github.load_constant(:User) # => loads an operation definition from app/operations/github/user.graphql
188
+ # defined?(Github::User) # => 'constant'
189
+ #
190
+ # Github.load_constant(:None) # => nil
191
+ #
180
192
  def load_constant(const_name)
181
193
  graphql_file = resolve_graphql_file_path(const_name.to_s.underscore, fragment: true)
182
194
 
@@ -195,11 +207,33 @@ module Artemis
195
207
 
196
208
  private
197
209
 
210
+ # Looks up the GraphQL file that matches the given +const_name+ and sets it to a constant. If the files it not
211
+ # found it will raise an +NameError+.
212
+ #
213
+ # # app/operations/github.rb
214
+ # class Github < Artemis::Client
215
+ # end
216
+ #
217
+ # defined?(Github::User) # => nil
218
+ # Github::User # => loads an operation definition from app/operations/github/user.graphql
219
+ # defined?(Github::User) # => 'constant'
220
+ #
221
+ # Github::DoesNotExist # => raises an NameError
222
+ #
198
223
  # @api private
199
224
  def const_missing(const_name)
200
225
  load_constant(const_name) || super
201
226
  end
202
227
 
228
+ # Delegates a class method call to an instance method call, which in turn looks up the GraphQL file that matches
229
+ # the given +method_name+ and delegates the call to it.
230
+ #
231
+ # # app/operations/github.rb
232
+ # class Github < Artemis::Client
233
+ # end
234
+ #
235
+ # Github.user # => delegates to Github.new(default_context).user
236
+ #
203
237
  # @api private
204
238
  def method_missing(method_name, *arguments, &block)
205
239
  if resolve_graphql_file_path(method_name)
@@ -223,6 +257,15 @@ module Artemis
223
257
 
224
258
  private
225
259
 
260
+ # Delegates a method call to a GraphQL call.
261
+ #
262
+ # # app/operations/github.rb
263
+ # class Github < Artemis::Client
264
+ # end
265
+ #
266
+ # github = Github.new
267
+ # github.user # => delegates to app/operations/github/user.graphql
268
+ #
226
269
  # @api private
227
270
  def method_missing(method_name, context: {}, **arguments)
228
271
  if self.class.resolve_graphql_file_path(method_name)
@@ -233,11 +276,7 @@ module Artemis
233
276
  self.class.load_constant(const_name)
234
277
  end
235
278
 
236
- client.query(
237
- self.class.const_get(const_name),
238
- variables: arguments.deep_transform_keys {|key| key.to_s.camelize(:lower) },
239
- context: context
240
- )
279
+ client.query(self.class.const_get(const_name), variables: arguments, context: context)
241
280
  else
242
281
  super
243
282
  end
@@ -247,21 +286,6 @@ module Artemis
247
286
  self.class.resolve_graphql_file_path(method_name) || super
248
287
  end
249
288
 
250
- # @api private
251
- def compile_query_method!(method_name)
252
- const_name = method_name.to_s.camelize
253
-
254
- self.class.send(:class_eval, <<-RUBY, __FILE__, __LINE__ + 1)
255
- def #{method_name}(context: {}, **arguments)
256
- client.query(
257
- self.class::#{const_name},
258
- variables: arguments.deep_transform_keys {|key| key.to_s.camelize(:lower) },
259
- context: context
260
- )
261
- end
262
- RUBY
263
- end
264
-
265
289
  # Internal collection object that holds references to the callback blocks.
266
290
  #
267
291
  # @api private
@@ -11,6 +11,9 @@ module Artemis
11
11
  class GraphQLFileNotFound < Error
12
12
  end
13
13
 
14
+ class FixtureNotFound < Error
15
+ end
16
+
14
17
  class GraphQLError < Error
15
18
  end
16
19
 
@@ -2,6 +2,12 @@ require 'active_support/file_update_checker'
2
2
 
3
3
  module Artemis
4
4
  class Railtie < ::Rails::Railtie #:nodoc:
5
+ config.artemis = ActiveSupport::OrderedOptions.new
6
+ config.artemis.query_path = "app/operations"
7
+ config.artemis.fixture_path = "test/fixtures/graphql"
8
+ config.artemis.schema_path = "vendor/graphql/schema"
9
+ config.artemis.graphql_extentions = ["graphql"]
10
+
5
11
  initializer 'graphql.client.attach_log_subscriber' do
6
12
  if !defined?(GraphQL::Client::LogSubscriber)
7
13
  require "graphql/client/log_subscriber"
@@ -10,13 +16,22 @@ module Artemis
10
16
  end
11
17
 
12
18
  initializer 'graphql.client.set_query_paths' do |app|
13
- app.paths.add "app/operations"
19
+ query_path = config.artemis.query_path
20
+
21
+ app.paths.add query_path
22
+
23
+ Artemis::Client.query_paths = app.paths[query_path].existent
24
+ end
14
25
 
15
- Artemis::Client.query_paths = app.paths["app/operations"].existent
26
+ initializer 'graphql.test_helper' do |app|
27
+ if !Rails.env.production?
28
+ require 'artemis/test_helper'
29
+ Artemis::TestHelper.__graphql_fixture_path__ = app.root.join(config.artemis.fixture_path)
30
+ end
16
31
  end
17
32
 
18
33
  initializer 'graphql.client.set_reloader', after: 'graphql.client.set_query_paths' do |app|
19
- files_to_watch = Artemis::Client.query_paths.map {|path| [path, ["graphql"]] }.to_h
34
+ files_to_watch = Artemis::Client.query_paths.map {|path| [path, config.artemis.graphql_extentions] }.to_h
20
35
 
21
36
  app.reloaders << ActiveSupport::FileUpdateChecker.new([], files_to_watch) do
22
37
  endpoint_names = app.config_for(:graphql).keys
@@ -29,9 +44,12 @@ module Artemis
29
44
  end
30
45
 
31
46
  initializer 'graphql.client.load_config' do |app|
32
- # TODO: Remove the +rescue+ call
33
- (app.config_for(:graphql) rescue {}).each do |endpoint_name, options|
34
- Artemis::GraphQLEndpoint.register!(endpoint_name, { 'schema_path' => app.root.join("vendor/graphql/schema/#{endpoint_name}.json").to_s }.merge(options))
47
+ if Pathname.new("#{app.paths["config"].existent.first}/graphql.yml").exist?
48
+ app.config_for(:graphql).each do |endpoint_name, options|
49
+ Artemis::GraphQLEndpoint.register!(endpoint_name, {
50
+ 'schema_path' => app.root.join(config.artemis.schema_path, "#{endpoint_name}.json").to_s
51
+ }.merge(options))
52
+ end
35
53
  end
36
54
  end
37
55
 
@@ -0,0 +1,10 @@
1
+ require 'artemis/test_helper'
2
+
3
+ RSpec.configure do |config|
4
+ config.include ::Artemis::TestHelper
5
+
6
+ config.before :each do
7
+ graphql_requests.clear
8
+ graphql_responses.clear
9
+ end
10
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erb'
4
+
5
+ require 'active_support/core_ext/module/attribute_accessors'
6
+
7
+ require 'artemis/exceptions'
8
+
9
+ module Artemis
10
+ # TODO: Write documentation for +TestHelper+
11
+ module TestHelper
12
+ cattr_accessor :__graphql_fixture_path__
13
+
14
+ # Creates an object that stubs a GraphQL request for the given +service+. No mock response is registered until the
15
+ # +to_return+ method.
16
+ #
17
+ # # test/fixtures/graphql/metaphysics/artist.yml
18
+ # leonardo_da_vinci:
19
+ # data:
20
+ # artist:
21
+ # name: Leonardo da Vinci
22
+ # birthday: 1452/04/15
23
+ #
24
+ # # In a test:
25
+ # stub_graphql(Metaphysics, :artist).to_return(:leonardo_da_vinci)
26
+ #
27
+ # response = Metaphysics.artist(id: "leonardo-da-vinci")
28
+ #
29
+ # response.data.artist.name # => "Leonardo da Vinci"
30
+ # response.data.artist.birthday # => "1452/04/15"
31
+ #
32
+ # Test responses could also be parameterized by specifying the +arguments+ argument for the query name.
33
+ #
34
+ # stub_graphql(Metaphysics, :artist, id: "pablo-picasso").to_return(:pablo_picasso)
35
+ # stub_graphql(Metaphysics, :artist, id: "leonardo-da-vinci").to_return(:leonardo_da_vinci)
36
+ #
37
+ # pablo_picasso = Metaphysics.artist(id: "pablo-picasso")
38
+ # da_vinci = Metaphysics.artist(id: "leonardo-da-vinci")
39
+ #
40
+ # pablo_picasso.data.artist.name # => "Pablo Picasso"
41
+ # da_vinci.data.artist.name # => "Leonardo da Vinci"
42
+ #
43
+ def stub_graphql(service, query_name, arguments = :__unspecified__)
44
+ StubbingDSL.new(service.to_s, graphql_fixtures(query_name), arguments)
45
+ end
46
+
47
+ # Returns out-going GraphQL requests.
48
+ #
49
+ def graphql_requests
50
+ Artemis::Adapters::TestAdapter.requests
51
+ end
52
+
53
+ private
54
+
55
+ def graphql_responses #:nodoc:
56
+ Artemis::Adapters::TestAdapter.responses
57
+ end
58
+
59
+ def graphql_fixture_path #:nodoc:
60
+ __graphql_fixture_path__ || raise(Artemis::ConfigurationError, "GraphQL fixture path is unset")
61
+ end
62
+
63
+ def graphql_fixtures(query_name) #:nodoc:
64
+ graphql_fixture_files.detect {|fixture| fixture.name == query_name.to_s } || \
65
+ raise(Artemis::FixtureNotFound, "Fixture file `#{File.join(graphql_fixture_path, "#{query_name}.{yml,json}")}' not found")
66
+ end
67
+
68
+ def graphql_fixture_files #:nodoc:
69
+ @graphql_fixture_sets ||= Dir["#{graphql_fixture_path}/{**,*}/*.{yml,json}"]
70
+ .select {|file| ::File.file?(file) }
71
+ .map {|file| GraphQLFixture.new(File.basename(file, File.extname(file)), file, read_erb_yaml(file)) }
72
+ end
73
+
74
+ def read_erb_yaml(path) #:nodoc:
75
+ YAML.load(ERB.new(File.read(path)).result)
76
+ end
77
+
78
+ class StubbingDSL #:nodoc:
79
+ attr_reader :service_name, :fixture_set, :arguments
80
+
81
+ def initialize(service_name, fixture_set, arguments) #:nodoc:
82
+ @service_name, @fixture_set, @arguments = service_name, fixture_set, arguments
83
+ end
84
+
85
+ def to_return(fixture_key) #:nodoc:
86
+ fixture = fixture_set.data[fixture_key.to_s] || \
87
+ raise(Artemis::FixtureNotFound, "Fixture `#{fixture_key}' not found in #{fixture_set.path}")
88
+
89
+ Artemis::Adapters::TestAdapter.responses <<
90
+ TestResponse.new(
91
+ "#{service_name}__#{fixture_set.name.to_s.camelcase}",
92
+ arguments.respond_to?(:deep_stringify_keys) ? arguments.deep_stringify_keys : arguments,
93
+ fixture
94
+ )
95
+ end
96
+ end
97
+
98
+ TestResponse = Struct.new(:operation_name, :arguments, :data) #:nodoc:
99
+ GraphQLFixture = Struct.new(:name, :path, :data) #:nodoc
100
+
101
+ private_constant :GraphQLFixture, :StubbingDSL, :TestResponse
102
+ end
103
+ end
@@ -1,3 +1,3 @@
1
1
  module Artemis
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -0,0 +1,17 @@
1
+ yayoi_kusama:
2
+ data:
3
+ artist:
4
+ name: Yayoi Kusama
5
+ birthday: 1929/03/22
6
+
7
+ leonardo_da_vinci:
8
+ data:
9
+ artist:
10
+ name: Leonardo da Vinci
11
+ birthday: 1452/04/15
12
+
13
+ yuki:
14
+ data:
15
+ artist:
16
+ name: Yuki Nishijima
17
+ birthday: <%= Date.today.year %>/01/01
@@ -0,0 +1,12 @@
1
+ {
2
+ "the_last_supper": {
3
+ "data": {
4
+ "artwork": {
5
+ "title": "The Last Supper",
6
+ "artist": {
7
+ "name": "Leonardo da Vinci"
8
+ }
9
+ }
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,64 @@
1
+ require 'artemis/test_helper'
2
+ require 'date'
3
+
4
+ describe GraphQL::Client do
5
+ include Artemis::TestHelper
6
+
7
+ def graphql_fixture_path
8
+ File.join(PROJECT_DIR, "spec/fixtures/responses")
9
+ end
10
+
11
+ before do
12
+ graphql_requests.clear
13
+ graphql_responses.clear
14
+ end
15
+
16
+ it "can mock a GraphQL request" do
17
+ stub_graphql(Metaphysics, :artist).to_return(:yayoi_kusama)
18
+
19
+ response = Metaphysics.artist(id: "yayoi-kusama")
20
+
21
+ expect(response.data.artist.name).to eq("Yayoi Kusama")
22
+ expect(response.data.artist.birthday).to eq("1929/03/22")
23
+ end
24
+
25
+ it "can mock a GraphQL request with an ERB-enabled fixture" do
26
+ stub_graphql(Metaphysics, :artist).to_return(:yuki)
27
+
28
+ response = Metaphysics.artist(id: "yuki")
29
+
30
+ expect(response.data.artist.birthday).to eq("#{Date.today.year}/01/01")
31
+ end
32
+
33
+ it "can mock a GraphQL request with variables using exact match" do
34
+ stub_graphql(Metaphysics, :artist, id: "yayoi-kusama").to_return(:yayoi_kusama)
35
+ stub_graphql(Metaphysics, :artist, id: "leonardo-da-vinci").to_return(:leonardo_da_vinci)
36
+
37
+ yayoi_kusama = Metaphysics.artist(id: "yayoi-kusama")
38
+ da_vinci = Metaphysics.artist(id: "leonardo-da-vinci")
39
+
40
+ expect(yayoi_kusama.data.artist.name).to eq("Yayoi Kusama")
41
+ expect(da_vinci.data.artist.name).to eq("Leonardo da Vinci")
42
+ end
43
+
44
+ it "can mock a GraphQL request with a JSON file" do
45
+ stub_graphql(Metaphysics, :artwork).to_return(:the_last_supper)
46
+
47
+ response = Metaphysics.artwork(id: "leonardo-da-vinci-the-last-supper")
48
+
49
+ expect(response.data.artwork.title).to eq("The Last Supper")
50
+ expect(response.data.artwork.artist.name).to eq("Leonardo da Vinci")
51
+ end
52
+
53
+ it "can mock a GraphQL request for a query that has a query name"
54
+
55
+ it "raises an exception if the specified fixture file does not exist" do
56
+ expect { stub_graphql(Metaphysics, :does_not_exist) }
57
+ .to raise_error(Artemis::FixtureNotFound, %r|spec/fixtures/responses/does_not_exist.{yml,json}|)
58
+ end
59
+
60
+ it "raises an exception if the specified fixture file exists but fixture key does not exist" do
61
+ expect { stub_graphql(Metaphysics, :artist).to_return(:does_not_exist) }
62
+ .to raise_error(Artemis::FixtureNotFound, %r|spec/fixtures/responses/artist.yml|)
63
+ end
64
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: artemis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Allured
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-10-30 00:00:00.000000000 Z
12
+ date: 2019-01-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -25,6 +25,20 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: 4.2.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: graphql
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '1.8'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '1.8'
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: graphql-client
30
44
  requirement: !ruby/object:Gem::Requirement
@@ -177,6 +191,8 @@ files:
177
191
  - lib/artemis/exceptions.rb
178
192
  - lib/artemis/graphql_endpoint.rb
179
193
  - lib/artemis/railtie.rb
194
+ - lib/artemis/rspec.rb
195
+ - lib/artemis/test_helper.rb
180
196
  - lib/artemis/version.rb
181
197
  - lib/generators/artemis/install/USAGE
182
198
  - lib/generators/artemis/install/install_generator.rb
@@ -200,7 +216,10 @@ files:
200
216
  - spec/fixtures/metaphysics/artists.graphql
201
217
  - spec/fixtures/metaphysics/artwork.graphql
202
218
  - spec/fixtures/metaphysics/schema.json
219
+ - spec/fixtures/responses/artist.yml
220
+ - spec/fixtures/responses/artwork.json
203
221
  - spec/spec_helper.rb
222
+ - spec/test_helper_spec.rb
204
223
  - tmp/.gitkeep
205
224
  homepage: https://github.com/yuki24/artemis
206
225
  licenses: