faraday-hot_mock 0.4.1 → 0.6.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: 0bb26f02c836add4b2e94acfb00997c4d4b5df893240d05b664c357a361b2bc7
4
- data.tar.gz: e302adfe01517cc6cafa86bc569652e5890a163776510b665502506a45a79eb4
3
+ metadata.gz: 25e4f2498095f7292d5e11855332f571948d41f93e16afb2b7d3e3f29bebd243
4
+ data.tar.gz: d0a18131c29b31575ae29064f995c0eca098305ea776768fec305ef758122009
5
5
  SHA512:
6
- metadata.gz: 5dd69fdff2fa19a114557e6c307a7be3d45ae3acc36778c2aefe0fa84966441479336b9286743511424e85ae62a3a50b8937234311e30dd2f97786f396a2cdaa
7
- data.tar.gz: 7e75041ce558508cfd07317e6c537b5b14a520c76f32abade2c39360d7136a053cf0b859013a104ea10528866bcbf62fd444fcfb6a7fdab4a3b9c31a046f6f75
6
+ metadata.gz: be6477e0289f117c0bbdd6e0b8d90d0b3bbe6897c51d61569d34b4bca8dffce90b34fce352e5aa9b2002acb2190373ce20ada2032ea629aceb9da4dedf7c3297
7
+ data.tar.gz: d6f897cc2f27bf7a4813968018acbbbcdedebb953790a19efa75544c6b51eaf85f1a3289cbe546f2d7443c5407a079a16727915589d890f737428ffa1d82aa63
data/README.md CHANGED
@@ -81,14 +81,69 @@ It can also be a terrible idea if your mocks are designed for your specific need
81
81
 
82
82
  It's up to you and your team what makes sense.
83
83
 
84
- In most cases, it makes sense to check in the mocks for the test environment, and ignore all the rest so in most cases you should add to your `.gitignore`:
84
+ In most cases, it makes sense to not check in the mocks for any environment, so in most cases you should add to your `.gitignore`:
85
85
 
86
86
  ```
87
87
  # Ignore Faraday HotMocks except in test env
88
88
  lib/faraday/mocks/**
89
- !lib/faraday/mocks/test
90
89
  ```
91
90
 
91
+ If you're using scenarios, however, it's probably useful to check in any environment directory that has scenarios since they're only activated when a scenario is directly selected.
92
+
93
+ ### Scenarios
94
+
95
+ You can use directories to conditionally group mocks. For example, you might want a "success" scenario and a "failure" scenario.
96
+
97
+ To do that, simply create the `/scenarios/success` and `/scenarios/failure` subdirectories within `lib/faraday/mocks/#{Rails.env}/`, and place the appropriate mock files in each, probably with the same endpoints but with different responses.
98
+
99
+ Then call `Faraday::HotMock.scenario = :success` or `Faraday::HotMock.scenario = :failure` to switch between them.
100
+
101
+ When a scenario is active, only mocks in that scenario directory will be considered. If no matching mock is found in that scenario, then the real request will be made.
102
+
103
+ To use the mocks not in the `scenarios` directory again, simply set `Faraday::HotMock.scenario = nil`.
104
+
105
+ ### VCR Mode
106
+
107
+ VCR mode basically calls `Faraday::HotMock.record` on all requests made until it's turned off. You can start it with:
108
+
109
+ ```ruby
110
+ Faraday::HotMock.vcr = true
111
+ ```
112
+
113
+ Just like using `Faraday::HotMock.record` individually, these mocks are recorded to the main default file (`Faraday::HotMock.hot_mock_file`)
114
+
115
+ You can also record directly into a scenario, which will create the scenario directory structure, switch the current scenario and begin recording responses. This will continue until you set `Faraday::HotMock.vcr` to `false` or another scenario name.
116
+
117
+ ```ruby
118
+ Faraday::HotMock.vcr = :new_scenario
119
+ ```
120
+
121
+ > NOTE: VCR Mode does not overwrite previously recorded mocks
122
+
123
+ ### Testing
124
+
125
+ In tests, you can certainly use a mocking library of choice. In many cases, that might be easier. This is because Faraday::HotMock is built for quick iteration using runtime-loaded YAML files, which isn't needed in tests.
126
+
127
+ If instead you want to use Faraday::HotMock, you can create mocked responses by hand, or use `Faraday::HotMock.mock!` to define mocks in a very similar way to other mocking libraries (similar to `stub_request` in WebMock, for example).
128
+
129
+ The most basic setup would be:
130
+
131
+ - Call `Faraday::HotMock.enable!` in your test setup
132
+ - Call `Faraday::HotMock.disable!` in your test teardown
133
+ - In a given test/spec or in a method, call `Faraday::HotMock.mock!(method: [method], url_pattern: [url], status: [status code], headers: [headers hash], body: [body])` to define a mock for that test/spec.
134
+ - Remove the mock file in teardown by referencing `Faraday::HotMock.hot_mock_file` (via `File.delete` or `FileUtils.rm`) since you probably don't want them to persist between tests
135
+
136
+ If you use scenarios, then you can do a bit less:
137
+
138
+ - Call `Faraday::HotMock.enable!` in your test setup
139
+ - Call `Faraday::HotMock.disable!` in your test teardown
140
+ - Call `Faraday::HotMock.scenario = :your_scenario_name` in a given test/spec
141
+ - Call `Faraday::HotMock.scenario = nil` in your test teardown if using scenarios
142
+
143
+ Overall, this may be a bit more work but it has the advantage that you can use the same mocking mechanism in both development and testing, which can reduce surprises when moving code between the two.
144
+
145
+ Small bonus: if you use `Faraday::HotMock` everywhere, you can remove the dependency for whichever mocking library/libraries you were using before.
146
+
92
147
  ### Convenience Methods
93
148
 
94
149
  You can enable or disable mocking programmatically with these methods:
@@ -18,16 +18,52 @@ module Faraday
18
18
  def call(env)
19
19
  super
20
20
 
21
- if Rails.env.production?
21
+ if Rails.env.production? || Faraday::HotMock.disabled?
22
22
  return @fallback_adapter.new(@app, @options).call(env)
23
23
  end
24
24
 
25
- if Faraday::HotMock.enabled? && (mock = Faraday::HotMock.mocked?(method: env.method, url: env.url))
26
- save_response(env, mock["status"] || 200, mock["body"] || "", mock["headers"] || {})
25
+ if Faraday::HotMock.vcr && !Faraday::HotMock.mocked?(method: env.method, url: env.url)
26
+ case Faraday::HotMock.vcr
27
+ when Symbol, String
28
+ Faraday::HotMock.record(method: env.method, url: env.url, into_scenario: Faraday::HotMock.vcr)
29
+ else
30
+ Faraday::HotMock.record(method: env.method, url: env.url)
31
+ end
32
+ end
33
+
34
+ if (mock = Faraday::HotMock.mocked?(method: env.method, url: env.url))
35
+ interpolate(mock, env) if mock_interpolated?(mock)
36
+
37
+ mock_response!(env, mock)
27
38
  else
28
39
  @fallback_adapter.new(@app, @options).call(env)
29
40
  end
30
41
  end
42
+
43
+ private
44
+
45
+ def mock_interpolated?(mock)
46
+ mock.key?("interpolate") && mock["body"].is_a?(Hash)
47
+ end
48
+
49
+ def interpolate(mock, env)
50
+ request_hash = JSON.parse(env.request_body) rescue {}
51
+
52
+ interpolated_hash = mock["interpolate"].transform_values do |v|
53
+ v = request_hash[v]
54
+ end.compact
55
+
56
+ mock["body"].merge!(interpolated_hash || {})
57
+ end
58
+
59
+ def mock_response!(env, mock)
60
+ save_response(
61
+ env,
62
+ mock["status"] || 200,
63
+ mock["body"] || "",
64
+ (mock["headers"] || {}).merge(Faraday::HotMock::HEADERS[:mocked] => "true")
65
+ )
66
+ end
31
67
  end
32
68
  end
33
69
  end
@@ -1,5 +1,5 @@
1
1
  module Faraday
2
2
  module HotMock
3
- VERSION = "0.4.1"
3
+ VERSION = "0.6.0"
4
4
  end
5
5
  end
@@ -7,6 +7,14 @@ module Faraday
7
7
  module HotMock
8
8
  extend self
9
9
 
10
+ attr_accessor :scenario, :vcr
11
+
12
+ HEADERS = {
13
+ recorded: "x-hot-mock-recorded-at",
14
+ mocked: "x-hot-mocked"
15
+ }
16
+ FILE_NAME = "hot_mocks.yml"
17
+
10
18
  def disable!
11
19
  FileUtils.rm_f(hot_mocking_file)
12
20
  end
@@ -31,7 +39,7 @@ module Faraday
31
39
  end
32
40
  end
33
41
 
34
- def delete_mock(method:, url:)
42
+ def delete(method:, url:)
35
43
  return unless File.exist?(hot_mock_file)
36
44
 
37
45
  mocks = YAML.load_file(hot_mock_file) || []
@@ -64,22 +72,25 @@ module Faraday
64
72
  mocks.find { |entry| entry["method"].to_s.upcase == method.to_s.upcase && Regexp.new(entry["url_pattern"]).match?(url.to_s) } || false
65
73
  end
66
74
 
67
- def record(method:, url:)
75
+ def record(method:, url:, into_scenario: nil)
76
+ self.scenario = into_scenario if into_scenario.present?
77
+
68
78
  return false if mocked?(method:, url:)
69
79
 
70
80
  faraday = Faraday.new
71
81
 
72
82
  response = faraday.send(method.downcase.to_sym, url)
73
83
 
84
+ FileUtils.mkdir_p(hot_mock_dir)
74
85
  FileUtils.touch(hot_mock_file)
75
86
 
76
87
  hot_mocks = YAML.load_file(hot_mock_file) || []
77
88
 
78
89
  hot_mocks << {
79
90
  "method" => method.to_s.upcase,
80
- "url_pattern" => url,
91
+ "url_pattern" => url.to_s,
81
92
  "status" => response.status,
82
- "headers" => response.headers.to_h.merge("x-hotmock-recorded-at" => Time.now.utc.iso8601),
93
+ "headers" => response.headers.to_h.merge(HEADERS[:recorded] => Time.now.utc.iso8601),
83
94
  "body" => response.body
84
95
  }
85
96
 
@@ -101,9 +112,9 @@ module Faraday
101
112
 
102
113
  hot_mocks << {
103
114
  "method" => method.to_s.upcase,
104
- "url_pattern" => url,
115
+ "url_pattern" => url.to_s,
105
116
  "status" => response.status,
106
- "headers" => response.headers.to_h.merge("x-hotmock-recorded-at" => Time.now.utc.iso8601),
117
+ "headers" => response.headers.to_h.merge(HEADERS[:recorded] => Time.now.utc.iso8601, "x-hot-mock" => "true"),
107
118
  "body" => response.body
108
119
  }
109
120
 
@@ -113,7 +124,15 @@ module Faraday
113
124
  end
114
125
 
115
126
  def hot_mock_dir
116
- Rails.root.join "lib/faraday/mocks/#{Rails.env}"
127
+ if self.scenario
128
+ Rails.root.join "lib/faraday/mocks/#{Rails.env}/scenarios/#{self.scenario}"
129
+ else
130
+ Rails.root.join "lib/faraday/mocks/#{Rails.env}"
131
+ end
132
+ end
133
+
134
+ def scenario_dir
135
+ Rails.root.join "lib/faraday/mocks/#{Rails.env}/scenarios"
117
136
  end
118
137
 
119
138
  def hot_mocking_file
@@ -121,7 +140,7 @@ module Faraday
121
140
  end
122
141
 
123
142
  def hot_mock_file
124
- Rails.root.join(hot_mock_dir, "hot_mocks.yml")
143
+ Rails.root.join(hot_mock_dir, FILE_NAME)
125
144
  end
126
145
 
127
146
  def mocks
@@ -138,7 +157,11 @@ module Faraday
138
157
  end
139
158
 
140
159
  def all_hot_mock_files
141
- Dir.glob(File.join(hot_mock_dir, "**", "*.{yml,yaml}"))
160
+ if scenario.present?
161
+ Dir.glob(File.join(hot_mock_dir, "**", "*.{yml,yaml}"))
162
+ else
163
+ Dir.glob(File.join(hot_mock_dir, "**", "*.{yml,yaml}")).reject { |path| path.include?("/scenarios/") }
164
+ end
142
165
  end
143
166
  end
144
167
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday-hot_mock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Hogge