faraday-hot_mock 0.4.0 → 0.5.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 +4 -4
- data/README.md +41 -6
- data/lib/faraday/hot_mock/adapter.rb +24 -1
- data/lib/faraday/hot_mock/version.rb +1 -1
- data/lib/faraday/hot_mock.rb +15 -4
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d42875d59eb57c21511d1c8edb287415cfae818f0a5af8b3be38f06086c8920f
|
|
4
|
+
data.tar.gz: 22551de3ae9e35709702c762880abbf797407f4e95e4f84a53e6bc3f930c4337
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8bf83f23c923e2459e5cc1d50005959df3f9113cb029c2cdf28f6a28967f67f2c00003d1ee2f4fcd25a00e2787665ea73056759137266f3e22de604c8cda606e
|
|
7
|
+
data.tar.gz: 30dbdcccbb2bad3aa706614b4b1b759ec18e7e995e422cf8fa6beb568034940732cce587a345e2874fb2afd68d60e1f308817ce815defdcadb95bed016e6ff5a
|
data/README.md
CHANGED
|
@@ -8,15 +8,15 @@ _**This adapter is meant for Faraday usage in Rails, not for Faraday that's used
|
|
|
8
8
|
|
|
9
9
|
## Why Use Faraday::HotMock instead of VCR?
|
|
10
10
|
|
|
11
|
-
VCR focuses on keeping HTTP requests out of tests - Faraday::HotMock focuses on simulating API responses during development.
|
|
11
|
+
[VCR](https://github.com/vcr/vcr) focuses on keeping HTTP requests out of tests - Faraday::HotMock focuses on simulating API responses during development.
|
|
12
12
|
|
|
13
|
-
To use VCR in development would require wrapping code in VCR blocks, which must then be undone before deployment. Simple, but tedious and error-prone.
|
|
13
|
+
To use [VCR](https://github.com/vcr/vcr) in development would require wrapping code in [VCR](https://github.com/vcr/vcr) blocks, which must then be undone before deployment. Simple, but tedious and error-prone.
|
|
14
14
|
|
|
15
15
|
Faraday::HotMock requires no code changes to the application - it doesn't mock anything in production, even if you try. So while the HotMock adapter is "used", it just passes requests to the default or adapter or specified fallback.
|
|
16
16
|
|
|
17
|
-
VCR works with any HTTP library, Faraday::HotMock only works with Faraday. This is a critical limitation unless you use only or primarily Faraday.
|
|
17
|
+
[VCR](https://github.com/vcr/vcr) works with any HTTP library, Faraday::HotMock only works with Faraday. This is a critical limitation unless you use only or primarily Faraday.
|
|
18
18
|
|
|
19
|
-
You could, ostensibly, replace VCR with Faraday::HotMock in tests. VCR is battle-tested, well-written and widely used, so it's likely a better choice for testing. But the goal is to make Faraday::HotMock just as useful in all non-production environments.
|
|
19
|
+
You could, ostensibly, replace VCR with Faraday::HotMock in tests. [VCR](https://github.com/vcr/vcr) is battle-tested, well-written and widely used, so it's likely a better choice for testing. But the goal is to make Faraday::HotMock just as useful in all non-production environments.
|
|
20
20
|
|
|
21
21
|
## How It Works
|
|
22
22
|
|
|
@@ -81,14 +81,49 @@ 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
|
|
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
|
+
### Scenarios
|
|
92
|
+
|
|
93
|
+
You can use directories to conditionally group mocks. For example, you might want a "success" scenario and an "failure" scenario.
|
|
94
|
+
|
|
95
|
+
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.
|
|
96
|
+
|
|
97
|
+
Then call `Faraday::HotMock.scenario = :success` or `Faraday::HotMock.scenario = :failure` to switch between them.
|
|
98
|
+
|
|
99
|
+
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.
|
|
100
|
+
|
|
101
|
+
To use the mocks not in the `scenarios` directory again, simply set `Faraday::HotMock.scenario = nil`.
|
|
102
|
+
|
|
103
|
+
### Testing
|
|
104
|
+
|
|
105
|
+
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.
|
|
106
|
+
|
|
107
|
+
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).
|
|
108
|
+
|
|
109
|
+
The most basic setup would be:
|
|
110
|
+
|
|
111
|
+
- Call `Faraday::HotMock.enable!` in your test setup
|
|
112
|
+
- Call `Faraday::HotMock.disable!` in your test teardown
|
|
113
|
+
- 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.
|
|
114
|
+
- 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
|
|
115
|
+
|
|
116
|
+
If you use scenarios, then you can do a bit less:
|
|
117
|
+
|
|
118
|
+
- Call `Faraday::HotMock.enable!` in your test setup
|
|
119
|
+
- Call `Faraday::HotMock.disable!` in your test teardown
|
|
120
|
+
- Call `Faraday::HotMock.scenario = :your_scenario_name` in a given test/spec
|
|
121
|
+
- Call `Faraday::HotMock.scenario = nil` in your test teardown if using scenarios
|
|
122
|
+
|
|
123
|
+
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.
|
|
124
|
+
|
|
125
|
+
Small bonus: if you use `Faraday::HotMock` everywhere, you can remove the dependency for whichever mocking library/libraries you were using before.
|
|
126
|
+
|
|
92
127
|
### Convenience Methods
|
|
93
128
|
|
|
94
129
|
You can enable or disable mocking programmatically with these methods:
|
|
@@ -23,11 +23,34 @@ module Faraday
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
if Faraday::HotMock.enabled? && (mock = Faraday::HotMock.mocked?(method: env.method, url: env.url))
|
|
26
|
-
|
|
26
|
+
interpolate(mock, env) if mock_interpolated?(mock)
|
|
27
|
+
|
|
28
|
+
save_response(
|
|
29
|
+
env,
|
|
30
|
+
mock["status"] || 200,
|
|
31
|
+
mock["body"] || "",
|
|
32
|
+
(mock["headers"] || {}).merge("x-hot-mocked" => "true")
|
|
33
|
+
)
|
|
27
34
|
else
|
|
28
35
|
@fallback_adapter.new(@app, @options).call(env)
|
|
29
36
|
end
|
|
30
37
|
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def mock_interpolated?(mock)
|
|
42
|
+
mock.key?("interpolate") && mock["body"].is_a?(Hash)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def interpolate(mock, env)
|
|
46
|
+
request_hash = JSON.parse(env.request_body) rescue {}
|
|
47
|
+
|
|
48
|
+
interpolated_hash = mock["interpolate"].transform_values do |v|
|
|
49
|
+
v = request_hash[v]
|
|
50
|
+
end.compact
|
|
51
|
+
|
|
52
|
+
mock["body"].merge!(interpolated_hash || {})
|
|
53
|
+
end
|
|
31
54
|
end
|
|
32
55
|
end
|
|
33
56
|
end
|
data/lib/faraday/hot_mock.rb
CHANGED
|
@@ -7,6 +7,8 @@ module Faraday
|
|
|
7
7
|
module HotMock
|
|
8
8
|
extend self
|
|
9
9
|
|
|
10
|
+
attr_accessor :scenario
|
|
11
|
+
|
|
10
12
|
def disable!
|
|
11
13
|
FileUtils.rm_f(hot_mocking_file)
|
|
12
14
|
end
|
|
@@ -31,7 +33,7 @@ module Faraday
|
|
|
31
33
|
end
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
def
|
|
36
|
+
def delete(method:, url:)
|
|
35
37
|
return unless File.exist?(hot_mock_file)
|
|
36
38
|
|
|
37
39
|
mocks = YAML.load_file(hot_mock_file) || []
|
|
@@ -42,6 +44,7 @@ module Faraday
|
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
def mock!(method:, url:, status:, headers: {}, body: nil)
|
|
47
|
+
FileUtils.mkdir_p(hot_mock_dir)
|
|
45
48
|
FileUtils.touch(hot_mock_file)
|
|
46
49
|
|
|
47
50
|
mocks = YAML.load_file(hot_mock_file) || []
|
|
@@ -78,7 +81,7 @@ module Faraday
|
|
|
78
81
|
"method" => method.to_s.upcase,
|
|
79
82
|
"url_pattern" => url,
|
|
80
83
|
"status" => response.status,
|
|
81
|
-
"headers" => response.headers.to_h.merge("x-
|
|
84
|
+
"headers" => response.headers.to_h.merge("x-hot-mock-recorded-at" => Time.now.utc.iso8601),
|
|
82
85
|
"body" => response.body
|
|
83
86
|
}
|
|
84
87
|
|
|
@@ -102,7 +105,7 @@ module Faraday
|
|
|
102
105
|
"method" => method.to_s.upcase,
|
|
103
106
|
"url_pattern" => url,
|
|
104
107
|
"status" => response.status,
|
|
105
|
-
"headers" => response.headers.to_h.merge("x-
|
|
108
|
+
"headers" => response.headers.to_h.merge("x-hot-mock-recorded-at" => Time.now.utc.iso8601, "x-hot-mock" => "true"),
|
|
106
109
|
"body" => response.body
|
|
107
110
|
}
|
|
108
111
|
|
|
@@ -115,6 +118,10 @@ module Faraday
|
|
|
115
118
|
Rails.root.join "lib/faraday/mocks/#{Rails.env}"
|
|
116
119
|
end
|
|
117
120
|
|
|
121
|
+
def scenario_dir
|
|
122
|
+
Rails.root.join "lib/faraday/mocks/#{Rails.env}/scenarios"
|
|
123
|
+
end
|
|
124
|
+
|
|
118
125
|
def hot_mocking_file
|
|
119
126
|
Rails.root.join "tmp/mocking-#{Rails.env}.txt"
|
|
120
127
|
end
|
|
@@ -137,7 +144,11 @@ module Faraday
|
|
|
137
144
|
end
|
|
138
145
|
|
|
139
146
|
def all_hot_mock_files
|
|
140
|
-
|
|
147
|
+
if scenario
|
|
148
|
+
Dir.glob(File.join(hot_mock_dir, "scenarios", scenario.to_s, "**", "*.{yml,yaml}"))
|
|
149
|
+
else
|
|
150
|
+
Dir.glob(File.join(hot_mock_dir, "**", "*.{yml,yaml}")).reject { |path| path.include?("/scenarios/") }
|
|
151
|
+
end
|
|
141
152
|
end
|
|
142
153
|
end
|
|
143
154
|
end
|