fixturama 0.0.7 → 0.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: 64d9722c641abfd4aa64fbf45b8f1177f768d1b8d2b99a89aa824e1f64db9417
4
- data.tar.gz: e1186c8944916943bbab46584747553b07b9d5cfc4e9d875d1a401fc8bd7017a
3
+ metadata.gz: 5bfb62ba99d427f8a3f03b6d46a0fb7e6712dd31bfff6da7c17fb075cfa930f0
4
+ data.tar.gz: fa1b0359c0681a73723a915dd499945602b350b3b802b68e6962a66753a5d208
5
5
  SHA512:
6
- metadata.gz: 29d44cd1b06c482ba40df2d4397c064888a64ae1f9a0a4151aa581bf81a83e9ca1a5e84c052340d515032d0f580f11418f9838a5efe00fd722401117248a0311
7
- data.tar.gz: 2b8a86f7fffdb20bae92839790254e052d2dbbbb39172003c9cfb4439620c782e4bc3f2ccdd985540dcba4d19e1fc228a3f7d940d58a865ad289f2f265427589
6
+ metadata.gz: 987b0cf303e78879b18278d85ace7cf26261e6c76000b0081571cb40a3dcf763435cb5560de122bf3a466b9c781684c8ed8d183697fbd1b84aa619c8409e34c8
7
+ data.tar.gz: d85486458d90dbff1e3f2136c5862e081aa1a1861bb5e6320fb68bbc258d11ce1e978de5603c900080ef719809e97a4d0bf793a46c8f90af33e7a6626d258835
data/.rubocop.yml CHANGED
@@ -5,7 +5,7 @@ AllCops:
5
5
  StyleGuideCopsOnly: true
6
6
  TargetRubyVersion: 2.3
7
7
 
8
- Metrics/LineLength:
8
+ Layout/LineLength:
9
9
  AllowHeredoc: true
10
10
  AllowURI: true
11
11
  URISchemes:
data/.travis.yml CHANGED
@@ -10,14 +10,8 @@ script:
10
10
  - bundle exec rubocop
11
11
  rvm:
12
12
  - 2.3.0
13
- - 2.6.0
14
- - jruby-9.2.0.0
13
+ - 2.7.0
15
14
  - ruby-head
16
- - jruby-head
17
- env:
18
- global:
19
- - JRUBY_OPTS='--dev -J-Xmx1024M'
20
15
  matrix:
21
16
  allow_failures:
22
17
  - rvm: ruby-head
23
- - rvm: jruby-head
data/CHANGELOG.md CHANGED
@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/).
7
7
 
8
+ ## [0.1.0] - [2020-02-09]
9
+
10
+ ### Added
11
+
12
+ - Stubbing of the HTTP requests using webmock (nepalez)
13
+
14
+ ```yaml
15
+ ---
16
+ - url: example.com/foo
17
+ method: get
18
+ body: foobar
19
+ query:
20
+ foo: bar
21
+ basic_auth:
22
+ user: foo
23
+ password: bar
24
+ headers:
25
+ Accept: utf-8
26
+ responses:
27
+ - status: 200
28
+ body: foobar
29
+ - status: 404
30
+ ```
31
+
8
32
  ## [0.0.7] - [2019-07-01]
9
33
 
10
34
  ### Added
@@ -175,3 +199,4 @@ This is a first public release with features extracted from production app.
175
199
  [0.0.5]: https://github.com/nepalez/fixturama/compare/v0.0.4...v0.0.5
176
200
  [0.0.6]: https://github.com/nepalez/fixturama/compare/v0.0.5...v0.0.6
177
201
  [0.0.7]: https://github.com/nepalez/fixturama/compare/v0.0.6...v0.0.7
202
+ [0.1.0]: https://github.com/nepalez/fixturama/compare/v0.0.7...v0.1.0
data/README.md CHANGED
@@ -133,12 +133,25 @@ For message chains:
133
133
  - `arguments` (optional) for specific arguments
134
134
  - `actions` for an array of actions for consecutive invocations of the chain
135
135
 
136
+ Every action either `return` some value, or `raise` some exception
137
+
136
138
  For constants:
137
139
 
138
140
  - `const` for stubbed constant
139
141
  - `value` for a value of the constant
140
142
 
141
- Every action either `return` some value, or `raise` some exception
143
+ For http requests:
144
+
145
+ - `url` or `uri` for the URI of the request (treats values like `/.../` as regular expressions)
146
+ - `method` for the specific http-method (like `get` or `post`)
147
+ - `body` for the request body (treats values like `/.../` as regular expressions)
148
+ - `headers` for the request headers
149
+ - `query` for the request query
150
+ - `basic_auth` for the `user` and `password` of basic authentication
151
+ - `response` or `responses` for consecutively envoked responses with keys:
152
+ - `status`
153
+ - `body`
154
+ - `headers`
142
155
 
143
156
  ```yaml
144
157
  # ./stubs.yml
@@ -170,6 +183,21 @@ Every action either `return` some value, or `raise` some exception
170
183
 
171
184
  - const: NOTIFIER_TIMEOUT_SEC
172
185
  value: 10
186
+
187
+ # Examples for stubbing HTTP
188
+ - uri: /example.com/foo/ # regexp!
189
+ method: delete
190
+ basic_auth:
191
+ user: foo
192
+ password: bar
193
+ responses:
194
+ - status: 200 # for the first call
195
+ - status: 404 # for any other call
196
+
197
+ - uri: htpps://example.com/foo # exact string!
198
+ method: delete
199
+ responses:
200
+ - status: 401
173
201
  ```
174
202
 
175
203
  ```graphql
data/fixturama.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = "fixturama"
3
- gem.version = "0.0.7"
3
+ gem.version = "0.1.0"
4
4
  gem.author = "Andrew Kozin (nepalez)"
5
5
  gem.email = "andrew.kozin@gmail.com"
6
6
  gem.homepage = "https://github.com/nepalez/fixturama"
@@ -15,9 +15,10 @@ Gem::Specification.new do |gem|
15
15
 
16
16
  gem.add_runtime_dependency "factory_bot", "~> 4.0"
17
17
  gem.add_runtime_dependency "rspec", "~> 3.0"
18
- gem.add_runtime_dependency "hashie", "~> 3.6"
18
+ gem.add_runtime_dependency "hashie", "~> 3.0"
19
+ gem.add_runtime_dependency "webmock", "~> 3.0"
19
20
 
20
21
  gem.add_development_dependency "rake", "~> 10"
21
- gem.add_development_dependency "rspec-its", "~> 1.2"
22
+ gem.add_development_dependency "rspec-its", "~> 1.0"
22
23
  gem.add_development_dependency "rubocop", "~> 0.49"
23
24
  end
data/lib/fixturama.rb CHANGED
@@ -3,6 +3,7 @@ require "factory_bot"
3
3
  require "hashie/mash"
4
4
  require "json"
5
5
  require "rspec"
6
+ require "webmock/rspec"
6
7
  require "yaml"
7
8
 
8
9
  module Fixturama
@@ -5,6 +5,7 @@ module Fixturama
5
5
  class Stubs
6
6
  require_relative "stubs/chain"
7
7
  require_relative "stubs/const"
8
+ require_relative "stubs/request"
8
9
 
9
10
  #
10
11
  # Register new action and apply the corresponding stub
@@ -35,14 +36,15 @@ module Fixturama
35
36
  stub = case stub_type(options)
36
37
  when :message_chain then Chain.new(options)
37
38
  when :constant then Const.new(options)
39
+ when :request then Request.new(options)
38
40
  end
39
41
 
40
- @stubs[stub.to_s] ||= stub if stub
42
+ @stubs[stub.key] ||= stub if stub
41
43
  end
42
44
 
43
45
  def stub_type(options)
44
- return :message_chain if options[:class] || options[:object]
45
- return :constant if options[:const]
46
+ key = (TYPES.keys & options.keys).first
47
+ return TYPES[key] if key
46
48
 
47
49
  raise ArgumentError, <<~MESSAGE
48
50
  Cannot figure out what to stub from #{options}.
@@ -50,6 +52,26 @@ module Fixturama
50
52
  MESSAGE
51
53
  end
52
54
 
55
+ # Matches keys to the type of the stub
56
+ TYPES = {
57
+ arguments: :message_chain,
58
+ actions: :message_chain,
59
+ basic_auth: :request,
60
+ body: :request,
61
+ chain: :message_chain,
62
+ class: :message_chain,
63
+ const: :constant,
64
+ headers: :request,
65
+ http_method: :request,
66
+ object: :message_chain,
67
+ query: :request,
68
+ response: :request,
69
+ responses: :request,
70
+ uri: :request,
71
+ url: :request,
72
+ value: :constant,
73
+ }.freeze
74
+
53
75
  def symbolize(options)
54
76
  Hash(options).transform_keys { |key| key.to_s.to_sym }
55
77
  end
@@ -16,6 +16,7 @@ module Fixturama
16
16
  "#{receiver}.#{messages.join(".")}"
17
17
  end
18
18
  alias to_str to_s
19
+ alias key to_s
19
20
 
20
21
  #
21
22
  # Register new action for some arguments
@@ -13,6 +13,7 @@ module Fixturama
13
13
  const.to_s
14
14
  end
15
15
  alias to_str to_s
16
+ alias key to_s
16
17
 
17
18
  #
18
19
  # Overload the definition for the constant
@@ -0,0 +1,98 @@
1
+ #
2
+ # Stubbed request
3
+ #
4
+ class Fixturama::Stubs::Request
5
+ require_relative "request/response"
6
+ require_relative "request/responses"
7
+
8
+ def to_s
9
+ "#{http_method.upcase} #{uri.to_s == "" ? "*" : uri}"
10
+ end
11
+ alias to_str to_s
12
+
13
+ # every stub is unique
14
+ alias key hash
15
+ def update!(_); end
16
+
17
+ def apply!(example)
18
+ stub = example.stub_request(http_method, uri)
19
+ stub = stub.with(request) if request.any?
20
+ stub.to_return { |_| responses.next }
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :options
26
+
27
+ def initialize(options)
28
+ @options = options
29
+ with_error { @options = Hash(options).symbolize_keys }
30
+ end
31
+
32
+ HTTP_METHODS = %i[get post put patch delete head options any].freeze
33
+
34
+ def http_method
35
+ value = with_error("method") { options[:method]&.to_sym&.downcase } || :any
36
+ return value if HTTP_METHODS.include?(value)
37
+
38
+ raise ArgumentError, "Invalid HTTP method #{value} in #{@optons}"
39
+ end
40
+
41
+ def uri
42
+ with_error("uri") { maybe_regexp(options[:uri] || options[:url]) }
43
+ end
44
+
45
+ def headers
46
+ with_error("headers") do
47
+ Hash(options[:headers]).transform_keys(&:to_s) if options.key?(:headers)
48
+ end
49
+ end
50
+
51
+ def query
52
+ with_error("query") do
53
+ Hash(options[:query]).transform_keys(&:to_s) if options.key?(:query)
54
+ end
55
+ end
56
+
57
+ def body
58
+ with_error("body") do
59
+ case options[:body]
60
+ when NilClass then nil
61
+ when Hash then options[:body]
62
+ else maybe_regexp(options[:body])
63
+ end
64
+ end
65
+ end
66
+
67
+ def basic_auth
68
+ with_error("basic auth") do
69
+ value = options[:auth] || options[:basic_auth]
70
+ Hash(value).transform_keys(&:to_s).values_at("user", "pass") if value
71
+ end
72
+ end
73
+
74
+ def request
75
+ @request ||= {
76
+ headers: headers,
77
+ body: body,
78
+ query: query,
79
+ basic_auth: basic_auth
80
+ }.select { |_, val| val }
81
+ end
82
+
83
+ def responses
84
+ @responses ||= Responses.new(options[:response] || options[:responses])
85
+ end
86
+
87
+ def with_error(part = nil)
88
+ yield
89
+ rescue RuntimeError
90
+ message = ["Cannot extract a request", part, "from #{options}"].join(" ")
91
+ raise ArgumentError, message, __FILE__, __LINE__ - 1
92
+ end
93
+
94
+ def maybe_regexp(str)
95
+ str = str.to_s
96
+ str[%r{\A/.*/\z}] ? Regexp.new(str[1..-2]) : str
97
+ end
98
+ end
@@ -0,0 +1,43 @@
1
+ class Fixturama::Stubs::Request
2
+ class Response
3
+ def to_h
4
+ { status: status, body: body, headers: headers }.select { |_, val| val }
5
+ end
6
+
7
+ private
8
+
9
+ def initialize(options)
10
+ @options = options
11
+ @options = with_error { Hash(options).transform_keys(&:to_sym) }
12
+ end
13
+
14
+ attr_reader :options
15
+
16
+ def status
17
+ with_error("status") { options[:status]&.to_i } || 200
18
+ end
19
+
20
+ def body
21
+ with_error("body") do
22
+ case options[:body]
23
+ when NilClass then nil
24
+ when Hash then JSON.dump(options[:body])
25
+ else options[:body].to_s
26
+ end
27
+ end
28
+ end
29
+
30
+ def headers
31
+ with_error("headers") do
32
+ Hash(options[:headers]).map { |k, v| [k.to_s, v.to_s] }.to_h
33
+ end
34
+ end
35
+
36
+ def with_error(part = nil)
37
+ yield
38
+ rescue RuntimeError
39
+ text = ["Cannot extract a response", part, "from #{options}"].join(" ")
40
+ raise ArgumentError, text, __FILE__, __LINE__ - 1
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,20 @@
1
+ class Fixturama::Stubs::Request
2
+ class Responses
3
+ def next
4
+ list.count > @count ? list[@count].tap { @count += 1 } : list.last
5
+ end
6
+
7
+ private
8
+
9
+ def initialize(list)
10
+ @count = 0
11
+ list ||= [{ status: 200 }]
12
+ @list = case list
13
+ when Array then list.map { |item| Response.new(item).to_h }
14
+ else [Response.new(list).to_h]
15
+ end
16
+ end
17
+
18
+ attr_reader :list
19
+ end
20
+ end
@@ -26,7 +26,10 @@ RSpec.describe "seed_fixture" do
26
26
 
27
27
  it "runs the factory", aggregate_failures: true do
28
28
  expect(FactoryBot).to receive(:create_list).with(:foo, 1, :baz, qux: 42)
29
- expect(FactoryBot).to receive(:create_list).with(:foo, 3, :bar, {})
29
+ expect(FactoryBot).to receive(:create_list) do |*args, **opts|
30
+ expect(args).to eq [:foo, 3, :bar]
31
+ expect(opts).to be_empty
32
+ end
30
33
 
31
34
  subject
32
35
  end
@@ -93,4 +93,28 @@ RSpec.describe "stub_fixture" do
93
93
  expect(TIMEOUT).to eq 10
94
94
  end
95
95
  end
96
+
97
+ context "when http request stubbed" do
98
+ before { stub_fixture "#{__dir__}/stub.yml" }
99
+
100
+ it "stubs the request properly" do
101
+ req = Net::HTTP::Get.new("/foo")
102
+ res = Net::HTTP.start("www.example.com") { |http| http.request(req) }
103
+
104
+ expect(res.code).to eq "200"
105
+ expect(res.body).to eq "foo"
106
+ expect(res["Content-Length"]).to eq "3"
107
+ end
108
+
109
+ def delete_request
110
+ req = Net::HTTP::Delete.new("/foo")
111
+ Net::HTTP.start("www.example.com") { |http| http.request(req) }
112
+ end
113
+
114
+ it "stubs repetitive requests properly" do
115
+ expect(delete_request.code).to eq "200"
116
+ expect(delete_request.code).to eq "404"
117
+ expect(delete_request.code).to eq "404"
118
+ end
119
+ end
96
120
  end
@@ -58,3 +58,16 @@
58
58
 
59
59
  - const: TIMEOUT
60
60
  value: 10
61
+
62
+ - method: get
63
+ uri: www.example.com/foo
64
+ responses:
65
+ - body: foo
66
+ headers:
67
+ Content-Length: 3
68
+
69
+ - method: delete
70
+ uri: /example.com/foo/ # Regexp!
71
+ responses:
72
+ - status: 200
73
+ - status: 404 # for any request except for the first one
metadata CHANGED
@@ -1,100 +1,114 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fixturama
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kozin (nepalez)
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-01 00:00:00.000000000 Z
11
+ date: 2020-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: factory_bot
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
18
  version: '4.0'
20
- type: :runtime
19
+ name: factory_bot
21
20
  prerelease: false
21
+ type: :runtime
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rspec
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
32
  version: '3.0'
34
- type: :runtime
33
+ name: rspec
35
34
  prerelease: false
35
+ type: :runtime
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: hashie
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - "~>"
46
45
  - !ruby/object:Gem::Version
47
- version: '3.6'
46
+ version: '3.0'
47
+ name: hashie
48
+ prerelease: false
48
49
  type: :runtime
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ name: webmock
49
62
  prerelease: false
63
+ type: :runtime
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '3.6'
68
+ version: '3.0'
55
69
  - !ruby/object:Gem::Dependency
56
- name: rake
57
70
  requirement: !ruby/object:Gem::Requirement
58
71
  requirements:
59
72
  - - "~>"
60
73
  - !ruby/object:Gem::Version
61
74
  version: '10'
62
- type: :development
75
+ name: rake
63
76
  prerelease: false
77
+ type: :development
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '10'
69
83
  - !ruby/object:Gem::Dependency
70
- name: rspec-its
71
84
  requirement: !ruby/object:Gem::Requirement
72
85
  requirements:
73
86
  - - "~>"
74
87
  - !ruby/object:Gem::Version
75
- version: '1.2'
76
- type: :development
88
+ version: '1.0'
89
+ name: rspec-its
77
90
  prerelease: false
91
+ type: :development
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '1.2'
96
+ version: '1.0'
83
97
  - !ruby/object:Gem::Dependency
84
- name: rubocop
85
98
  requirement: !ruby/object:Gem::Requirement
86
99
  requirements:
87
100
  - - "~>"
88
101
  - !ruby/object:Gem::Version
89
102
  version: '0.49'
90
- type: :development
103
+ name: rubocop
91
104
  prerelease: false
105
+ type: :development
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
108
  - - "~>"
95
109
  - !ruby/object:Gem::Version
96
110
  version: '0.49'
97
- description:
111
+ description:
98
112
  email: andrew.kozin@gmail.com
99
113
  executables: []
100
114
  extensions: []
@@ -126,6 +140,9 @@ files:
126
140
  - lib/fixturama/stubs/chain/actions/return.rb
127
141
  - lib/fixturama/stubs/chain/arguments.rb
128
142
  - lib/fixturama/stubs/const.rb
143
+ - lib/fixturama/stubs/request.rb
144
+ - lib/fixturama/stubs/request/response.rb
145
+ - lib/fixturama/stubs/request/responses.rb
129
146
  - lib/fixturama/utils.rb
130
147
  - spec/fixturama/load_fixture/_spec.rb
131
148
  - spec/fixturama/load_fixture/data.json
@@ -140,7 +157,7 @@ homepage: https://github.com/nepalez/fixturama
140
157
  licenses:
141
158
  - MIT
142
159
  metadata: {}
143
- post_install_message:
160
+ post_install_message:
144
161
  rdoc_options: []
145
162
  require_paths:
146
163
  - lib
@@ -155,8 +172,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
172
  - !ruby/object:Gem::Version
156
173
  version: '0'
157
174
  requirements: []
158
- rubygems_version: 3.0.3
159
- signing_key:
175
+ rubyforge_project:
176
+ rubygems_version: 2.7.6
177
+ signing_key:
160
178
  specification_version: 4
161
179
  summary: A set of helpers to prettify specs with fixtures
162
180
  test_files: