artemis 0.2.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +9 -11
- data/CHANGELOG.md +14 -5
- data/README.md +99 -5
- data/artemis.gemspec +1 -0
- data/bin/console +6 -8
- data/lib/artemis/adapters/test_adapter.rb +8 -1
- data/lib/artemis/client.rb +44 -20
- data/lib/artemis/exceptions.rb +3 -0
- data/lib/artemis/railtie.rb +24 -6
- data/lib/artemis/rspec.rb +10 -0
- data/lib/artemis/test_helper.rb +103 -0
- data/lib/artemis/version.rb +1 -1
- data/spec/fixtures/responses/artist.yml +17 -0
- data/spec/fixtures/responses/artwork.json +12 -0
- data/spec/test_helper_spec.rb +64 -0
- metadata +21 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b5fc48841d80c3f0ebd0cc161938caf1044b09ce300bb55822df3ae1323aed2
|
4
|
+
data.tar.gz: e42427484c1786929c66a2f8a7650cb2e631230155f92c92e5d36406a20a41b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b0625a78d265426de79dc77ace3f0ff2336e75a914b37b4179356ec3f0c69c2beda8658e1b0cabf914221aea92e6fb86c6510075b6ab9c9c0e9f04cb1c37368
|
7
|
+
data.tar.gz: f80b1e917bfaac00586704ab09a3893f7d879b02a62b5693816f1c7977fed64233585b7e0d17ab8ae7877efdab2a5efc951eab4928f9120d90a41c9895cd0c93
|
data/.travis.yml
CHANGED
@@ -6,12 +6,12 @@ sudo: false
|
|
6
6
|
before_install: gem install bundler -v 1.16.1
|
7
7
|
|
8
8
|
rvm:
|
9
|
-
- 2.
|
10
|
-
- 2.
|
11
|
-
- 2.
|
12
|
-
|
9
|
+
- 2.6.0
|
10
|
+
- 2.5.3
|
11
|
+
- 2.4.5
|
12
|
+
- 2.3.8
|
13
13
|
- ruby-head
|
14
|
-
# - jruby-9.2.
|
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.
|
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.
|
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
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,20 @@
|
|
1
1
|
## Unreleased
|
2
2
|
|
3
3
|
* Add a new entry here
|
4
|
-
* [#
|
5
|
-
* [#
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
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
|
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&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
|
-
|
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
|
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
|
-
|
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
|
|
data/artemis.gemspec
CHANGED
@@ -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
|
|
data/bin/console
CHANGED
@@ -3,12 +3,10 @@
|
|
3
3
|
require "bundler/setup"
|
4
4
|
require "artemis"
|
5
5
|
|
6
|
-
|
7
|
-
|
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
|
-
|
10
|
-
|
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' => {}
|
data/lib/artemis/client.rb
CHANGED
@@ -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
|
data/lib/artemis/exceptions.rb
CHANGED
data/lib/artemis/railtie.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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,
|
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
|
-
#
|
33
|
-
|
34
|
-
|
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,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
|
data/lib/artemis/version.rb
CHANGED
@@ -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,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.
|
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:
|
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:
|