wayfarer 0.4.6 → 0.4.8

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.
Files changed (259) hide show
  1. checksums.yaml +4 -4
  2. data/.env +17 -0
  3. data/.github/workflows/lint.yaml +27 -0
  4. data/.github/workflows/release.yaml +30 -0
  5. data/.github/workflows/tests.yaml +21 -0
  6. data/.gitignore +5 -1
  7. data/.rubocop.yml +36 -0
  8. data/.vale.ini +8 -0
  9. data/.yardopts +1 -3
  10. data/Dockerfile +6 -4
  11. data/Gemfile +24 -0
  12. data/Gemfile.lock +274 -164
  13. data/Rakefile +7 -51
  14. data/bin/wayfarer +1 -1
  15. data/docker-compose.yml +23 -13
  16. data/docs/cookbook/consent_screen.md +2 -2
  17. data/docs/cookbook/executing_javascript.md +3 -3
  18. data/docs/cookbook/navigation.md +12 -12
  19. data/docs/cookbook/querying_html.md +3 -3
  20. data/docs/cookbook/screenshots.md +2 -2
  21. data/docs/guides/callbacks.md +25 -125
  22. data/docs/guides/cli.md +71 -0
  23. data/docs/guides/configuration.md +10 -35
  24. data/docs/guides/development.md +67 -0
  25. data/docs/guides/handlers.md +60 -0
  26. data/docs/guides/index.md +1 -0
  27. data/docs/guides/jobs.md +142 -31
  28. data/docs/guides/navigation.md +1 -1
  29. data/docs/guides/networking/capybara.md +13 -22
  30. data/docs/guides/networking/custom_adapters.md +103 -41
  31. data/docs/guides/networking/ferrum.md +4 -4
  32. data/docs/guides/networking/http.md +9 -13
  33. data/docs/guides/networking/selenium.md +10 -11
  34. data/docs/guides/pages.md +78 -10
  35. data/docs/guides/redis.md +10 -0
  36. data/docs/guides/routing.md +156 -0
  37. data/docs/guides/tasks.md +53 -9
  38. data/docs/guides/tutorial.md +66 -0
  39. data/docs/guides/user_agents.md +115 -0
  40. data/docs/index.md +17 -40
  41. data/lib/wayfarer/base.rb +125 -46
  42. data/lib/wayfarer/batch_completion.rb +60 -0
  43. data/lib/wayfarer/callbacks.rb +22 -48
  44. data/lib/wayfarer/cli/route_printer.rb +85 -89
  45. data/lib/wayfarer/cli.rb +103 -0
  46. data/lib/wayfarer/gc.rb +18 -6
  47. data/lib/wayfarer/handler.rb +15 -7
  48. data/lib/wayfarer/kv.rb +28 -0
  49. data/lib/wayfarer/logging.rb +38 -0
  50. data/lib/wayfarer/middleware/base.rb +2 -0
  51. data/lib/wayfarer/middleware/batch_completion.rb +19 -0
  52. data/lib/wayfarer/middleware/chain.rb +7 -1
  53. data/lib/wayfarer/middleware/content_type.rb +59 -0
  54. data/lib/wayfarer/middleware/controller.rb +19 -15
  55. data/lib/wayfarer/middleware/dedup.rb +22 -13
  56. data/lib/wayfarer/middleware/dispatch.rb +17 -4
  57. data/lib/wayfarer/middleware/normalize.rb +7 -14
  58. data/lib/wayfarer/middleware/redis.rb +15 -0
  59. data/lib/wayfarer/middleware/router.rb +33 -35
  60. data/lib/wayfarer/middleware/stage.rb +5 -5
  61. data/lib/wayfarer/middleware/uri_parser.rb +31 -0
  62. data/lib/wayfarer/middleware/user_agent.rb +49 -0
  63. data/lib/wayfarer/networking/capybara.rb +1 -1
  64. data/lib/wayfarer/networking/context.rb +14 -3
  65. data/lib/wayfarer/networking/ferrum.rb +1 -4
  66. data/lib/wayfarer/networking/follow.rb +14 -7
  67. data/lib/wayfarer/networking/http.rb +1 -1
  68. data/lib/wayfarer/networking/pool.rb +23 -13
  69. data/lib/wayfarer/networking/selenium.rb +15 -7
  70. data/lib/wayfarer/networking/strategy.rb +2 -2
  71. data/lib/wayfarer/page.rb +34 -14
  72. data/lib/wayfarer/parsing/xml.rb +6 -6
  73. data/lib/wayfarer/parsing.rb +21 -0
  74. data/lib/wayfarer/redis/barrier.rb +26 -21
  75. data/lib/wayfarer/redis/counter.rb +18 -9
  76. data/lib/wayfarer/redis/pool.rb +1 -1
  77. data/lib/wayfarer/redis/resettable.rb +19 -0
  78. data/lib/wayfarer/routing/dsl.rb +166 -30
  79. data/lib/wayfarer/routing/hash_stack.rb +33 -0
  80. data/lib/wayfarer/routing/matchers/custom.rb +8 -5
  81. data/lib/wayfarer/routing/matchers/{suffix.rb → empty_params.rb} +2 -6
  82. data/lib/wayfarer/routing/matchers/host.rb +15 -9
  83. data/lib/wayfarer/routing/matchers/path.rb +11 -31
  84. data/lib/wayfarer/routing/matchers/query.rb +41 -17
  85. data/lib/wayfarer/routing/matchers/result.rb +12 -0
  86. data/lib/wayfarer/routing/matchers/scheme.rb +13 -5
  87. data/lib/wayfarer/routing/matchers/url.rb +13 -5
  88. data/lib/wayfarer/routing/path_consumer.rb +130 -0
  89. data/lib/wayfarer/routing/path_finder.rb +151 -23
  90. data/lib/wayfarer/routing/result.rb +1 -1
  91. data/lib/wayfarer/routing/root_route.rb +17 -1
  92. data/lib/wayfarer/routing/route.rb +66 -19
  93. data/lib/wayfarer/routing/serializable.rb +28 -0
  94. data/lib/wayfarer/routing/sub_route.rb +53 -0
  95. data/lib/wayfarer/routing/target_route.rb +17 -1
  96. data/lib/wayfarer/stringify.rb +21 -30
  97. data/lib/wayfarer/task.rb +9 -17
  98. data/lib/wayfarer/uri/normalization.rb +120 -0
  99. data/lib/wayfarer.rb +72 -5
  100. data/mise.toml +2 -0
  101. data/mkdocs.yml +44 -8
  102. data/rake/docs.rake +26 -0
  103. data/rake/lint.rake +9 -0
  104. data/rake/release.rake +23 -0
  105. data/rake/tests.rake +32 -0
  106. data/requirements.txt +1 -1
  107. data/spec/factories/job.rb +8 -0
  108. data/spec/factories/middleware.rb +2 -2
  109. data/spec/factories/path_finder.rb +11 -0
  110. data/spec/factories/redis.rb +19 -0
  111. data/spec/factories/task.rb +46 -2
  112. data/spec/spec_helpers.rb +55 -51
  113. data/spec/support/active_job_helpers.rb +8 -0
  114. data/spec/support/integration_helpers.rb +21 -0
  115. data/spec/support/redis_helpers.rb +9 -0
  116. data/spec/support/test_app.rb +66 -37
  117. data/spec/wayfarer/base_spec.rb +200 -0
  118. data/spec/wayfarer/batch_completion_spec.rb +142 -0
  119. data/spec/wayfarer/cli/job_spec.rb +88 -0
  120. data/spec/wayfarer/cli/routing_spec.rb +322 -0
  121. data/spec/{cli → wayfarer/cli}/version_spec.rb +1 -1
  122. data/spec/wayfarer/gc_spec.rb +29 -0
  123. data/spec/wayfarer/handler_spec.rb +9 -0
  124. data/spec/wayfarer/integration/callbacks_spec.rb +200 -0
  125. data/spec/wayfarer/integration/content_type_spec.rb +37 -0
  126. data/spec/wayfarer/integration/custom_routing_spec.rb +51 -0
  127. data/spec/wayfarer/integration/gc_spec.rb +40 -0
  128. data/spec/wayfarer/integration/handler_spec.rb +65 -0
  129. data/spec/wayfarer/integration/page_spec.rb +79 -0
  130. data/spec/wayfarer/integration/params_spec.rb +64 -0
  131. data/spec/wayfarer/integration/parsing_spec.rb +99 -0
  132. data/spec/wayfarer/integration/retry_spec.rb +112 -0
  133. data/spec/wayfarer/integration/stage_spec.rb +58 -0
  134. data/spec/wayfarer/middleware/batch_completion_spec.rb +33 -0
  135. data/spec/{middleware → wayfarer/middleware}/chain_spec.rb +24 -19
  136. data/spec/wayfarer/middleware/content_type_spec.rb +83 -0
  137. data/spec/{middleware → wayfarer/middleware}/controller_spec.rb +24 -22
  138. data/spec/wayfarer/middleware/dedup_spec.rb +66 -0
  139. data/spec/wayfarer/middleware/normalize_spec.rb +32 -0
  140. data/spec/wayfarer/middleware/router_spec.rb +102 -0
  141. data/spec/wayfarer/middleware/stage_spec.rb +63 -0
  142. data/spec/wayfarer/middleware/uri_parser_spec.rb +63 -0
  143. data/spec/wayfarer/middleware/user_agent_spec.rb +158 -0
  144. data/spec/wayfarer/networking/capybara_spec.rb +13 -0
  145. data/spec/{networking → wayfarer/networking}/context_spec.rb +46 -38
  146. data/spec/wayfarer/networking/ferrum_spec.rb +13 -0
  147. data/spec/{networking → wayfarer/networking}/follow_spec.rb +11 -6
  148. data/spec/wayfarer/networking/http_spec.rb +12 -0
  149. data/spec/{networking → wayfarer/networking}/pool_spec.rb +16 -14
  150. data/spec/wayfarer/networking/selenium_spec.rb +12 -0
  151. data/spec/{networking → wayfarer/networking}/strategy.rb +33 -54
  152. data/spec/wayfarer/page_spec.rb +69 -0
  153. data/spec/{parsing → wayfarer/parsing}/json_spec.rb +1 -1
  154. data/spec/wayfarer/parsing/xml_parse_spec.rb +25 -0
  155. data/spec/wayfarer/redis/barrier_spec.rb +39 -0
  156. data/spec/wayfarer/redis/counter_spec.rb +34 -0
  157. data/spec/{redis → wayfarer/redis}/pool_spec.rb +4 -3
  158. data/spec/{routing → wayfarer/routing}/dsl_spec.rb +12 -22
  159. data/spec/wayfarer/routing/hash_stack_spec.rb +63 -0
  160. data/spec/wayfarer/routing/integration_spec.rb +101 -0
  161. data/spec/wayfarer/routing/matchers/custom_spec.rb +39 -0
  162. data/spec/wayfarer/routing/matchers/host_spec.rb +56 -0
  163. data/spec/wayfarer/routing/matchers/matcher.rb +17 -0
  164. data/spec/wayfarer/routing/matchers/path_spec.rb +43 -0
  165. data/spec/wayfarer/routing/matchers/query_spec.rb +123 -0
  166. data/spec/wayfarer/routing/matchers/scheme_spec.rb +45 -0
  167. data/spec/wayfarer/routing/matchers/url_spec.rb +33 -0
  168. data/spec/wayfarer/routing/path_consumer_spec.rb +123 -0
  169. data/spec/wayfarer/routing/path_finder_spec.rb +409 -0
  170. data/spec/wayfarer/routing/root_route_spec.rb +51 -0
  171. data/spec/wayfarer/routing/route_spec.rb +74 -0
  172. data/spec/wayfarer/routing/sub_route_spec.rb +103 -0
  173. data/spec/wayfarer/task_spec.rb +13 -0
  174. data/spec/wayfarer/uri/normalization_spec.rb +98 -0
  175. data/spec/wayfarer_spec.rb +2 -2
  176. data/wayfarer.gemspec +18 -28
  177. metadata +797 -265
  178. data/.github/workflows/ci.yaml +0 -32
  179. data/.rbenv-gemsets +0 -1
  180. data/.ruby-version +0 -1
  181. data/RELEASING.md +0 -17
  182. data/docs/cookbook/user_agent.md +0 -7
  183. data/docs/guides/error_handling.md +0 -53
  184. data/docs/guides/networking.md +0 -94
  185. data/docs/guides/performance.md +0 -130
  186. data/docs/guides/reliability.md +0 -41
  187. data/docs/guides/routing/steering.md +0 -30
  188. data/docs/reference/api/base.md +0 -48
  189. data/docs/reference/cli.md +0 -61
  190. data/docs/reference/configuration_keys.md +0 -43
  191. data/docs/reference/environment_variables.md +0 -83
  192. data/lib/wayfarer/cli/base.rb +0 -45
  193. data/lib/wayfarer/cli/generate.rb +0 -17
  194. data/lib/wayfarer/cli/job.rb +0 -56
  195. data/lib/wayfarer/cli/route.rb +0 -29
  196. data/lib/wayfarer/cli/runner.rb +0 -34
  197. data/lib/wayfarer/cli/templates/Gemfile.tt +0 -5
  198. data/lib/wayfarer/cli/templates/job.rb.tt +0 -10
  199. data/lib/wayfarer/config/capybara.rb +0 -10
  200. data/lib/wayfarer/config/ferrum.rb +0 -11
  201. data/lib/wayfarer/config/networking.rb +0 -29
  202. data/lib/wayfarer/config/redis.rb +0 -14
  203. data/lib/wayfarer/config/root.rb +0 -11
  204. data/lib/wayfarer/config/selenium.rb +0 -21
  205. data/lib/wayfarer/config/strconv.rb +0 -45
  206. data/lib/wayfarer/config/struct.rb +0 -72
  207. data/lib/wayfarer/middleware/fetch.rb +0 -56
  208. data/lib/wayfarer/redis/connection.rb +0 -13
  209. data/lib/wayfarer/redis/version.rb +0 -19
  210. data/lib/wayfarer/routing/router.rb +0 -28
  211. data/spec/base_spec.rb +0 -224
  212. data/spec/callbacks_spec.rb +0 -102
  213. data/spec/cli/generate_spec.rb +0 -39
  214. data/spec/cli/job_spec.rb +0 -78
  215. data/spec/config/capybara_spec.rb +0 -18
  216. data/spec/config/ferrum_spec.rb +0 -24
  217. data/spec/config/networking_spec.rb +0 -73
  218. data/spec/config/redis_spec.rb +0 -32
  219. data/spec/config/root_spec.rb +0 -31
  220. data/spec/config/selenium_spec.rb +0 -56
  221. data/spec/config/strconv_spec.rb +0 -58
  222. data/spec/config/struct_spec.rb +0 -66
  223. data/spec/fixtures/dummy_job.rb +0 -7
  224. data/spec/gc_spec.rb +0 -59
  225. data/spec/handler_spec.rb +0 -11
  226. data/spec/integration/callbacks_spec.rb +0 -85
  227. data/spec/integration/page_spec.rb +0 -62
  228. data/spec/integration/params_spec.rb +0 -56
  229. data/spec/integration/stage_spec.rb +0 -51
  230. data/spec/integration/steering_spec.rb +0 -57
  231. data/spec/middleware/dedup_spec.rb +0 -88
  232. data/spec/middleware/dispatch_spec.rb +0 -43
  233. data/spec/middleware/fetch_spec.rb +0 -155
  234. data/spec/middleware/normalize_spec.rb +0 -29
  235. data/spec/middleware/router_spec.rb +0 -105
  236. data/spec/middleware/stage_spec.rb +0 -62
  237. data/spec/networking/capybara_spec.rb +0 -12
  238. data/spec/networking/ferrum_spec.rb +0 -12
  239. data/spec/networking/http_spec.rb +0 -12
  240. data/spec/networking/selenium_spec.rb +0 -12
  241. data/spec/page_spec.rb +0 -47
  242. data/spec/parsing/xml_spec.rb +0 -25
  243. data/spec/redis/barrier_spec.rb +0 -78
  244. data/spec/redis/counter_spec.rb +0 -32
  245. data/spec/redis/version_spec.rb +0 -13
  246. data/spec/routing/integration_spec.rb +0 -110
  247. data/spec/routing/matchers/custom_spec.rb +0 -31
  248. data/spec/routing/matchers/host_spec.rb +0 -49
  249. data/spec/routing/matchers/path_spec.rb +0 -43
  250. data/spec/routing/matchers/query_spec.rb +0 -137
  251. data/spec/routing/matchers/scheme_spec.rb +0 -25
  252. data/spec/routing/matchers/suffix_spec.rb +0 -41
  253. data/spec/routing/matchers/uri_spec.rb +0 -27
  254. data/spec/routing/path_finder_spec.rb +0 -33
  255. data/spec/routing/root_route_spec.rb +0 -29
  256. data/spec/routing/route_spec.rb +0 -43
  257. data/spec/routing/router_spec.rb +0 -24
  258. data/spec/task_spec.rb +0 -34
  259. data/spec/{stringify_spec.rb → wayfarer/stringify_spec.rb} +2 -2
@@ -3,62 +3,69 @@
3
3
  require "spec_helpers"
4
4
 
5
5
  describe Wayfarer::Networking::Context do
6
- let(:instance) { Object.new }
7
- let(:strategy) { spy }
8
- let(:renewing_error) { Class.new(StandardError) }
9
- subject(:context) { Wayfarer::Networking::Context.new(strategy) }
6
+ subject(:context) { described_class.new(strategy) }
10
7
 
11
- before do
12
- allow(strategy).to receive(:renew_on).and_return([renewing_error])
13
- allow(strategy).to receive(:create).and_return(instance)
8
+ let(:instance) { Object.new }
9
+ let(:strategy) do
10
+ double( # rubocop:disable RSpec/VerifiedDoubles
11
+ create: instance,
12
+ destroy: nil,
13
+ renew_on: [renewing_error],
14
+ fetch: nil,
15
+ live: nil
16
+ )
14
17
  end
15
18
 
16
- describe "#new" do
17
- it "assigns the strategy" do
18
- expect(context.strategy).to be(strategy)
19
- end
19
+ let(:renewing_error) { Class.new(StandardError) }
20
20
 
21
- it "assigns the instance" do
22
- expect(context.strategy).to be(strategy)
23
- end
21
+ before do
22
+ allow(strategy).to receive(:destroy)
24
23
  end
25
24
 
26
25
  describe "#fetch" do
27
26
  let(:url) { Object.new }
28
27
 
29
- it "fetches" do
30
- expect(strategy).to receive(:fetch).with(instance, url)
28
+ specify do
31
29
  context.fetch(url)
30
+
31
+ expect(strategy).to have_received(:fetch).with(instance, url)
32
32
  end
33
33
 
34
- context "with renewing exception raised" do
34
+ context "with renewing exception" do
35
35
  before do
36
36
  allow(strategy).to receive(:fetch).and_raise(renewing_error)
37
37
  end
38
38
 
39
39
  it "renews and reraises" do
40
- expect(context).to receive(:renew)
41
-
42
40
  expect {
43
41
  context.fetch(url)
44
42
  }.to raise_error(renewing_error)
43
+
44
+ expect(strategy).to have_received(:destroy).with(instance)
45
45
  end
46
46
  end
47
47
 
48
- context "with configured renewing exception raised" do
48
+ context "with renewing exception raised" do
49
49
  let(:other_error) { Class.new(StandardError) }
50
50
 
51
+ around do |example|
52
+ original_renew_on = Wayfarer.config[:network][:renew_on]
53
+ Wayfarer.config[:network][:renew_on] = [other_error]
54
+ example.run
55
+ Wayfarer.config[:network][:renew_on] = original_renew_on
56
+ end
57
+
51
58
  before do
52
- Wayfarer.config.network.renew_on = [other_error]
59
+ allow(strategy).to receive(:renew_on).and_return([renewing_error, other_error])
53
60
  allow(strategy).to receive(:fetch).and_raise(other_error)
54
61
  end
55
62
 
56
63
  it "renews and reraises" do
57
- expect(context).to receive(:renew)
58
-
59
64
  expect {
60
65
  context.fetch(url)
61
66
  }.to raise_error(other_error)
67
+
68
+ expect(strategy).to have_received(:destroy).with(instance)
62
69
  end
63
70
  end
64
71
 
@@ -67,12 +74,12 @@ describe Wayfarer::Networking::Context do
67
74
  allow(strategy).to receive(:fetch).and_raise(StandardError)
68
75
  end
69
76
 
70
- it "reraises" do
71
- expect(context).not_to receive(:renew)
72
-
77
+ it "reraises without renewing" do
73
78
  expect {
74
79
  context.fetch(url)
75
80
  }.to raise_error(StandardError)
81
+
82
+ expect(strategy).not_to have_received(:destroy)
76
83
  end
77
84
  end
78
85
  end
@@ -81,28 +88,29 @@ describe Wayfarer::Networking::Context do
81
88
  let(:page) { Object.new }
82
89
 
83
90
  it "calls live" do
84
- expect(strategy).to receive(:live).with(instance)
85
91
  context.live
92
+
93
+ expect(strategy).to have_received(:live).with(instance)
86
94
  end
87
95
 
88
- context "with renewing exception raised" do
96
+ context "with renewing exception" do
89
97
  before do
90
98
  allow(strategy).to receive(:live).and_raise(renewing_error)
91
99
  end
92
100
 
93
101
  it "renews and reraises" do
94
- expect(context).to receive(:renew)
95
-
96
102
  expect {
97
103
  context.live
98
104
  }.to raise_error(renewing_error)
105
+
106
+ expect(strategy).to have_received(:destroy).with(instance)
99
107
  end
100
108
 
101
109
  context "when renewing raises" do
102
110
  let(:other_error) { Class.new(StandardError) }
103
111
 
104
112
  before do
105
- allow(context).to receive(:renew).and_raise(other_error)
113
+ allow(strategy).to receive(:destroy).and_raise(other_error)
106
114
  end
107
115
 
108
116
  it "reraises the original exception" do
@@ -118,27 +126,27 @@ describe Wayfarer::Networking::Context do
118
126
  allow(strategy).to receive(:live).and_raise(StandardError)
119
127
  end
120
128
 
121
- it "reraises" do
122
- expect(context).not_to receive(:renew)
123
-
129
+ it "reraises without renewing" do
124
130
  expect {
125
131
  context.live(page)
126
132
  }.to raise_error(StandardError)
133
+
134
+ expect(strategy).not_to have_received(:destroy)
127
135
  end
128
136
  end
129
137
  end
130
138
 
131
139
  describe "#renew" do
132
- it "destroys" do
133
- expect(strategy).to receive(:destroy).with(instance)
140
+ specify do
134
141
  context.renew
142
+ expect(strategy).to have_received(:destroy).with(instance)
135
143
  end
136
144
  end
137
145
 
138
146
  describe "#instance" do
139
- it "creates an instance" do
140
- expect(strategy).to receive(:create).and_return(instance)
147
+ specify do
141
148
  expect(context.instance).to be(instance)
149
+ expect(strategy).to have_received(:create)
142
150
  end
143
151
  end
144
152
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+ require_relative "strategy"
5
+
6
+ describe Wayfarer::Networking::Ferrum, :ferrum do
7
+ it_behaves_like "Network strategy", strategy: described_class,
8
+ browser: true,
9
+ request_headers: true,
10
+ response_headers: true,
11
+ status_code: true,
12
+ raises_on_error_response: true
13
+ end
@@ -3,28 +3,33 @@
3
3
  require "spec_helpers"
4
4
 
5
5
  describe Wayfarer::Networking::Follow do
6
+ subject(:outer) { described_class.new(inner) }
7
+
6
8
  let(:page) { build(:page) }
7
9
  let(:url) { test_app_path("/foo") }
8
10
  let(:redirect_url) { test_app_path("/redirect") }
9
11
  let(:success) { Wayfarer::Networking::Result::Success.new(page) }
10
12
  let(:redirect) { Wayfarer::Networking::Result::Redirect.new(redirect_url) }
11
13
  let(:inner) { spy }
12
- subject(:outer) { described_class.new(inner) }
13
14
 
14
15
  describe "#fetch" do
15
16
  context "when context returns Success" do
16
17
  before { allow(inner).to receive(:fetch).and_return(success) }
17
18
 
18
19
  it "returns the page" do
19
- expect(outer.fetch(url)).to be(page)
20
+ expect(outer.fetch(url, follow: 3)).to be(page)
20
21
  end
21
22
  end
22
23
 
23
24
  context "when context returns Redirect" do
24
- it "follows the redirect" do
25
- expect(inner).to receive(:fetch).with(url).and_return(redirect).ordered
26
- expect(inner).to receive(:fetch).with(redirect_url).and_return(success).ordered
25
+ it "follows redirect URL" do
26
+ allow(inner).to receive(:fetch).with(url).and_return(redirect)
27
+ allow(inner).to receive(:fetch).with(redirect_url).and_return(success)
28
+
27
29
  outer.fetch(url, follow: 2)
30
+
31
+ expect(inner).to have_received(:fetch).with(url).ordered
32
+ expect(inner).to have_received(:fetch).with(redirect_url).ordered
28
33
  end
29
34
  end
30
35
 
@@ -34,7 +39,7 @@ describe Wayfarer::Networking::Follow do
34
39
 
35
40
  expect {
36
41
  outer.fetch(url, follow: 0)
37
- }.to raise_error(Wayfarer::Networking::RedirectsExhaustedError)
42
+ }.to raise_error(described_class::RedirectsExhaustedError)
38
43
  end
39
44
  end
40
45
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+ require_relative "strategy"
5
+
6
+ describe Wayfarer::Networking::HTTP do
7
+ it_behaves_like "Network strategy", strategy: described_class,
8
+ browser: false,
9
+ request_headers: true,
10
+ response_headers: true,
11
+ status_code: true
12
+ end
@@ -3,12 +3,12 @@
3
3
  require "spec_helpers"
4
4
 
5
5
  describe Wayfarer::Networking::Pool do
6
- subject(:pool) { Wayfarer::Networking::Pool.send(:new) }
6
+ subject(:pool) { described_class.send(:new) }
7
7
 
8
8
  after { pool.free }
9
9
 
10
10
  describe "#with" do
11
- context "by default" do
11
+ context "with default" do
12
12
  it "yields HTTP" do
13
13
  pool.with do |context|
14
14
  expect(context.strategy).to be_a(Wayfarer::Networking::HTTP)
@@ -16,8 +16,8 @@ describe Wayfarer::Networking::Pool do
16
16
  end
17
17
  end
18
18
 
19
- context "when using Ferrum", ferrum: true do
20
- before { Wayfarer.config.network.agent = :ferrum }
19
+ context "when using Ferrum", :ferrum do
20
+ before { Wayfarer.config[:network][:agent] = :ferrum }
21
21
 
22
22
  it "yields Ferrum" do
23
23
  pool.with do |context|
@@ -26,8 +26,8 @@ describe Wayfarer::Networking::Pool do
26
26
  end
27
27
  end
28
28
 
29
- context "when using Selenium", selenium: true do
30
- before { Wayfarer.config.network.agent = :selenium }
29
+ context "when using Selenium", :selenium do
30
+ before { Wayfarer.config[:network][:agent] = :selenium }
31
31
 
32
32
  it "yields Selenium" do
33
33
  pool.with do |context|
@@ -36,10 +36,10 @@ describe Wayfarer::Networking::Pool do
36
36
  end
37
37
  end
38
38
 
39
- context "when using Capybara", ferrum: true do
39
+ context "when using Capybara", :ferrum do
40
40
  before do
41
- Wayfarer.config.network.agent = :capybara
42
- Wayfarer.config.capybara.driver = :cuprite
41
+ Wayfarer.config[:network][:agent] = :capybara
42
+ Wayfarer.config[:capybara][:driver] = :cuprite
43
43
  end
44
44
 
45
45
  it "yields Capybara" do
@@ -51,17 +51,19 @@ describe Wayfarer::Networking::Pool do
51
51
  end
52
52
 
53
53
  describe "#free" do
54
- let(:strategy) { double(create: spy) }
54
+ let(:strategy) { double(create: nil, destroy: nil) } # rubocop:disable RSpec/VerifiedDoubles
55
55
 
56
56
  before do
57
- pool.class.registry[:foobar] = double(new: strategy)
58
- Wayfarer.config.network.agent = :foobar
57
+ pool.class.registry[:foobar] = double(new: strategy) # rubocop:disable RSpec/VerifiedDoubles
58
+ pool.class.finalizer = ->(pool) { pool.reload(&:renew) }
59
+
60
+ Wayfarer.config[:network][:agent] = :foobar
59
61
  end
60
62
 
61
63
  it "destroys the strategy" do
62
- expect(strategy).to receive(:destroy)
63
- pool.with {}
64
+ pool.with {} # rubocop:disable Lint/EmptyBlock
64
65
  pool.free
66
+ expect(strategy).to have_received(:destroy)
65
67
  end
66
68
  end
67
69
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+ require_relative "strategy"
5
+
6
+ describe Wayfarer::Networking::Selenium, :selenium do
7
+ it_behaves_like "Network strategy", strategy: described_class,
8
+ browser: true,
9
+ request_headers: false,
10
+ response_headers: false,
11
+ status_code: false
12
+ end
@@ -5,13 +5,15 @@ require "spec_helpers"
5
5
  RSpec.shared_examples "Network strategy" do |options|
6
6
  attr_accessor :context
7
7
 
8
- before(:all) do
8
+ # rubocop:disable RSpec/BeforeAfterAll
9
+ before :all do
9
10
  self.context = Wayfarer::Networking::Context.new(options[:strategy].new)
10
11
  end
11
12
 
12
- after(:all) do
13
+ after :all do
13
14
  context.renew
14
15
  end
16
+ # rubocop:enable RSpec/BeforeAfterAll
15
17
 
16
18
  describe "#renew_on" do
17
19
  it "returns an Array" do
@@ -21,17 +23,21 @@ RSpec.shared_examples "Network strategy" do |options|
21
23
 
22
24
  describe "Context" do
23
25
  describe "#fetch" do
24
- it "returns Success" do
25
- url = test_app_path("/hello_world")
26
+ it "returns Success", :aggregate_failures do
27
+ url = test_app_path("/status/200")
26
28
  result = context.fetch(url)
27
29
  expect(result).to be_a(Wayfarer::Networking::Result::Success)
28
30
  expect(result.page).to be_a(Wayfarer::Page)
29
31
  end
30
32
 
31
- it "sets the URL" do
32
- url = test_app_path("/status_code/404")
33
- page = context.fetch(url).page
34
- expect(page.url).to eq test_app_path("/status_code/404")
33
+ context "with 4xx response code" do
34
+ skip if options[:raises_on_error_response]
35
+
36
+ it "sets the URL" do
37
+ url = test_app_path("hello_world")
38
+ page = context.fetch(url).page
39
+ expect(page.url).to eq test_app_path("hello_world")
40
+ end
35
41
  end
36
42
 
37
43
  it "sets the response body" do
@@ -40,23 +46,26 @@ RSpec.shared_examples "Network strategy" do |options|
40
46
  expect(page.body).to match(/Hello world!/)
41
47
  end
42
48
 
43
- it "sets the status code" do
44
- skip unless options[:status_code]
49
+ context "with error responses" do
50
+ it "sets the status code" do
51
+ skip unless options[:status_code]
52
+ skip if options[:raises_on_error_response]
45
53
 
46
- url = test_app_path("/status_code/418")
47
- page = context.fetch(url).page
48
- expect(page.status_code).to be(418)
54
+ url = test_app_path("status_code/404")
55
+ page = context.fetch(url).page
56
+ expect(page.status_code).to be(404)
57
+ end
49
58
  end
50
59
 
51
60
  it "sets response headers" do
52
61
  skip unless options[:response_headers]
53
62
 
54
- url = test_app_path("/hello_world")
63
+ url = test_app_path("hello_world")
55
64
  page = context.fetch(url).page
56
65
  expect(page.headers["hello"]).to eq("world")
57
66
  end
58
67
 
59
- context "Selenium" do
68
+ context "with Selenium" do
60
69
  before { skip unless context.strategy.is_a?(Wayfarer::Networking::Selenium) }
61
70
 
62
71
  it "sets a mock status code" do
@@ -74,21 +83,6 @@ RSpec.shared_examples "Network strategy" do |options|
74
83
  end
75
84
  end
76
85
 
77
- describe "HTTP headers" do
78
- before do
79
- Wayfarer.config.network.http_headers = { "User-Agent" => "Foobar" }
80
- context.renew
81
- end
82
-
83
- it "uses configured HTTP headers" do
84
- skip unless options[:request_headers]
85
-
86
- url = test_app_path("/headers/HTTP_USER_AGENT")
87
- page = context.fetch(url).page
88
- expect(page.body).to match(/Foobar/)
89
- end
90
- end
91
-
92
86
  context "when encountering a redirect" do
93
87
  it "returns a Redirect" do
94
88
  skip if options[:browser]
@@ -103,29 +97,29 @@ RSpec.shared_examples "Network strategy" do |options|
103
97
 
104
98
  describe "#live" do
105
99
  context "when automating a browser" do
106
- let(:url) { test_app_path("/body/foobar") }
100
+ subject(:page) { context.live.page }
101
+
102
+ let(:url) { test_app_path("hello_world") }
107
103
 
108
104
  before do
109
105
  skip unless options[:browser]
110
106
 
111
- context.fetch(test_app_path("/hello_world"))
107
+ context.fetch(url)
112
108
  context.strategy.navigate(context.instance, url)
113
109
  end
114
110
 
115
- subject(:page) { context.live.page }
116
-
117
111
  it "sets the URL" do
118
112
  expect(page.url).to eq(url)
119
113
  end
120
114
 
121
115
  it "sets the response body" do
122
- expect(page.body).to match(/foobar/)
116
+ expect(page.body).to match(/Hello world/)
123
117
  end
124
118
 
125
119
  it "sets response headers" do
126
120
  skip unless options[:response_headers]
127
121
 
128
- expect(page.headers["content-length"]).to eq("6")
122
+ expect(page.headers["content-length"]).to eq("12")
129
123
  end
130
124
 
131
125
  it "sets the status code" do
@@ -139,31 +133,16 @@ RSpec.shared_examples "Network strategy" do |options|
139
133
  it "returns nil" do
140
134
  skip if options[:browser]
141
135
 
142
- expect(context.live).to be(nil)
136
+ expect(context.live).to be_nil
143
137
  end
144
138
  end
145
139
  end
146
140
 
147
141
  describe "#renew" do
148
- it "replaces the instance", foo: true do
142
+ it "replaces the instance" do
149
143
  expect {
150
144
  context.renew
151
- }.to(change { context.instance })
152
- end
153
- end
154
- end
155
-
156
- describe "Selenium" do
157
- before { skip unless context.strategy.is_a?(Wayfarer::Networking::Selenium) }
158
-
159
- describe "Client timeout" do
160
- before do
161
- Wayfarer.config.selenium.client_timeout = 42
162
- context.renew
163
- end
164
-
165
- it "sets the client timeout" do
166
- expect(context.instance.send(:bridge).send(:http).read_timeout).to be(42)
145
+ }.to(change(context, :instance))
167
146
  end
168
147
  end
169
148
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe Wayfarer::Page do
6
+ describe "#mime_type" do
7
+ subject { build(:page, headers: headers).mime_type }
8
+
9
+ let(:headers) { { "Content-Type" => "text/html; charset=UTF-8" } }
10
+
11
+ it { is_expected.to eq("text/html") }
12
+ end
13
+
14
+ describe "#doc" do
15
+ context "when Content-Type is absent" do
16
+ subject { build(:page, :html, headers: {}).doc }
17
+
18
+ it { is_expected.to be_nil }
19
+ end
20
+
21
+ context "when Content-Type is HTML" do
22
+ subject(:page) { build(:page, :html).doc }
23
+
24
+ it { is_expected.to be_a(Nokogiri::HTML::Document) }
25
+ end
26
+
27
+ context "when Content-Type is XML" do
28
+ subject(:page) { build(:page, :xml).doc }
29
+
30
+ it { is_expected.to be_a(Nokogiri::XML::Document) }
31
+ end
32
+
33
+ context "when Content-Type is JSON" do
34
+ subject(:page) { build(:page, :json).doc }
35
+
36
+ it { is_expected.to be_a(Hash) }
37
+ end
38
+
39
+ context "with Content-Type parameters" do
40
+ subject(:page) { build(:page, headers: { "content-type" => "text/html; charset=UTF-8" }).doc }
41
+
42
+ it { is_expected.to be_a(Nokogiri::HTML::Document) }
43
+ end
44
+
45
+ context "when Content-Type is unsupported" do
46
+ subject(:page) { build(:page, headers: { "Content-Type" => "foo/bar" }).doc }
47
+
48
+ it { is_expected.to be_nil }
49
+ end
50
+ end
51
+
52
+ describe "#headers" do
53
+ subject(:headers) { build(:page, headers: { "Content-Type" => "text/html" }).headers }
54
+
55
+ it "downcases keys" do
56
+ expect(headers).to eq("content-type" => "text/html")
57
+ end
58
+
59
+ it "is case-sensitive" do
60
+ expect(headers["Content-Type"]).to be_nil
61
+ end
62
+ end
63
+
64
+ describe "#meta" do
65
+ subject(:page) { build(:page).meta }
66
+
67
+ it { is_expected.to be_a(MetaInspector::Document) }
68
+ end
69
+ end
@@ -3,7 +3,7 @@
3
3
  require "spec_helpers"
4
4
 
5
5
  describe Wayfarer::Parsing::JSON do
6
- subject(:parser) { Wayfarer::Parsing::JSON }
6
+ subject(:parser) { described_class }
7
7
 
8
8
  describe ".parse" do
9
9
  it "returns a Hash" do
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe Wayfarer::Parsing::XML, ".parse" do
6
+ subject(:doc) { described_class.parse(xml, variant) }
7
+
8
+ let(:xml) { "<span>Foobar</span>" }
9
+
10
+ context "with HTML" do
11
+ let(:variant) { :html }
12
+
13
+ specify do
14
+ expect(doc).to be_a(Nokogiri::HTML::Document)
15
+ end
16
+ end
17
+
18
+ context "with XML" do
19
+ let(:variant) { :xml }
20
+
21
+ specify do
22
+ expect(doc).to be_a(Nokogiri::XML::Document)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe Wayfarer::Redis::Barrier, :redis do
6
+ subject(:barrier) { build(:barrier, task: task) }
7
+
8
+ let(:task) { build(:task, :redis_pool) }
9
+
10
+ describe "#redis_key" do
11
+ it "returns the expected Redis key" do
12
+ expect(barrier.redis_key).to eq("wayfarer-barrier-batch")
13
+ end
14
+ end
15
+
16
+ describe "#reset!" do
17
+ it "resets seen URLs" do
18
+ barrier.check!(task.url)
19
+ barrier.reset!
20
+ expect(barrier.check!(task.url)).to be(false)
21
+ end
22
+ end
23
+
24
+ describe "#check!" do
25
+ context "with seen URL" do
26
+ before { barrier.check!(task.url) }
27
+
28
+ specify do
29
+ expect(barrier.check!(task.url)).to be(true)
30
+ end
31
+ end
32
+
33
+ context "with unseen URL" do
34
+ specify do
35
+ expect(barrier.check!(task.url)).to be(false)
36
+ end
37
+ end
38
+ end
39
+ end