link_thumbnailer 1.1.2 → 2.0.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.
Files changed (104) hide show
  1. checksums.yaml +5 -13
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +117 -104
  4. data/Gemfile +1 -1
  5. data/{LICENSE → LICENSE.txt} +21 -21
  6. data/README.md +153 -184
  7. data/lib/generators/link_thumbnailer/install_generator.rb +0 -4
  8. data/lib/generators/templates/initializer.rb +63 -41
  9. data/lib/link_thumbnailer/configuration.rb +52 -10
  10. data/lib/link_thumbnailer/exceptions.rb +6 -0
  11. data/lib/link_thumbnailer/grader.rb +37 -0
  12. data/lib/link_thumbnailer/graders/base.rb +32 -0
  13. data/lib/link_thumbnailer/graders/html_attribute.rb +49 -0
  14. data/lib/link_thumbnailer/graders/length.rb +19 -0
  15. data/lib/link_thumbnailer/graders/link_density.rb +21 -0
  16. data/lib/link_thumbnailer/graders/position.rb +11 -0
  17. data/lib/link_thumbnailer/image_comparator.rb +24 -0
  18. data/lib/link_thumbnailer/image_comparators/base.rb +17 -0
  19. data/lib/link_thumbnailer/image_comparators/size.rb +11 -0
  20. data/lib/link_thumbnailer/image_parser.rb +18 -0
  21. data/lib/link_thumbnailer/image_parsers/size.rb +15 -0
  22. data/lib/link_thumbnailer/image_parsers/type.rb +15 -0
  23. data/lib/link_thumbnailer/image_validator.rb +30 -0
  24. data/lib/link_thumbnailer/model.rb +16 -0
  25. data/lib/link_thumbnailer/models/description.rb +34 -0
  26. data/lib/link_thumbnailer/models/image.rb +54 -0
  27. data/lib/link_thumbnailer/models/title.rb +20 -0
  28. data/lib/link_thumbnailer/models/website.rb +39 -0
  29. data/lib/link_thumbnailer/page.rb +40 -0
  30. data/lib/link_thumbnailer/parser.rb +13 -0
  31. data/lib/link_thumbnailer/processor.rb +94 -0
  32. data/lib/link_thumbnailer/railtie.rb +9 -9
  33. data/lib/link_thumbnailer/scraper.rb +64 -0
  34. data/lib/link_thumbnailer/scrapers/base.rb +63 -0
  35. data/lib/link_thumbnailer/scrapers/default/base.rb +10 -0
  36. data/lib/link_thumbnailer/scrapers/default/description.rb +47 -0
  37. data/lib/link_thumbnailer/scrapers/default/images.rb +64 -0
  38. data/lib/link_thumbnailer/scrapers/default/title.rb +25 -0
  39. data/lib/link_thumbnailer/scrapers/opengraph/base.rb +43 -0
  40. data/lib/link_thumbnailer/scrapers/opengraph/description.rb +10 -0
  41. data/lib/link_thumbnailer/scrapers/opengraph/image.rb +30 -0
  42. data/lib/link_thumbnailer/scrapers/opengraph/images.rb +16 -0
  43. data/lib/link_thumbnailer/scrapers/opengraph/title.rb +10 -0
  44. data/lib/link_thumbnailer/version.rb +3 -3
  45. data/lib/link_thumbnailer.rb +36 -119
  46. data/link_thumbnailer.gemspec +26 -28
  47. data/spec/configuration_spec.rb +51 -0
  48. data/spec/examples/empty_og_image_example.html +9 -0
  49. data/spec/fixture_spec.rb +88 -0
  50. data/spec/fixtures/bar.png +2907 -0
  51. data/spec/fixtures/default_from_body.html +12 -0
  52. data/spec/fixtures/default_from_meta.html +11 -0
  53. data/spec/{examples → fixtures}/example.html +53 -53
  54. data/spec/fixtures/foo.png +0 -0
  55. data/spec/fixtures/og_not_valid_example.html +12 -0
  56. data/spec/fixtures/og_valid_example.html +12 -0
  57. data/spec/fixtures/og_valid_multi_image_example.html +13 -0
  58. data/spec/grader_spec.rb +24 -0
  59. data/spec/graders/base_spec.rb +12 -0
  60. data/spec/graders/html_attribute_spec.rb +48 -0
  61. data/spec/graders/length_spec.rb +81 -0
  62. data/spec/graders/link_density_spec.rb +22 -0
  63. data/spec/image_comparators/size_spec.rb +39 -0
  64. data/spec/image_parsers/size_spec.rb +34 -0
  65. data/spec/image_parsers/type_spec.rb +34 -0
  66. data/spec/image_validator_spec.rb +35 -0
  67. data/spec/model_spec.rb +17 -0
  68. data/spec/models/description_spec.rb +64 -0
  69. data/spec/models/image_spec.rb +71 -0
  70. data/spec/models/title_spec.rb +24 -0
  71. data/spec/models/website_spec.rb +49 -0
  72. data/spec/page_spec.rb +26 -0
  73. data/spec/processor_spec.rb +349 -0
  74. data/spec/scraper_spec.rb +95 -0
  75. data/spec/scrapers/base_spec.rb +67 -0
  76. data/spec/scrapers/opengraph/base_spec.rb +94 -0
  77. data/spec/spec_helper.rb +15 -13
  78. metadata +126 -120
  79. data/app/controllers/link_thumbnailer/application_controller.rb +0 -4
  80. data/app/controllers/link_thumbnailer/previews_controller.rb +0 -11
  81. data/lib/link_thumbnailer/doc.rb +0 -65
  82. data/lib/link_thumbnailer/doc_parser.rb +0 -15
  83. data/lib/link_thumbnailer/engine.rb +0 -4
  84. data/lib/link_thumbnailer/fetcher.rb +0 -34
  85. data/lib/link_thumbnailer/img_comparator.rb +0 -17
  86. data/lib/link_thumbnailer/img_parser.rb +0 -41
  87. data/lib/link_thumbnailer/img_url_filter.rb +0 -13
  88. data/lib/link_thumbnailer/object.rb +0 -41
  89. data/lib/link_thumbnailer/opengraph.rb +0 -20
  90. data/lib/link_thumbnailer/rails/routes/mapper.rb +0 -30
  91. data/lib/link_thumbnailer/rails/routes/mapping.rb +0 -33
  92. data/lib/link_thumbnailer/rails/routes.rb +0 -47
  93. data/lib/link_thumbnailer/web_image.rb +0 -19
  94. data/spec/doc_parser_spec.rb +0 -25
  95. data/spec/doc_spec.rb +0 -23
  96. data/spec/examples/empty_example.html +0 -11
  97. data/spec/examples/og_example.html +0 -12
  98. data/spec/fetcher_spec.rb +0 -97
  99. data/spec/img_comparator_spec.rb +0 -16
  100. data/spec/img_url_filter_spec.rb +0 -31
  101. data/spec/link_thumbnailer_spec.rb +0 -205
  102. data/spec/object_spec.rb +0 -130
  103. data/spec/opengraph_spec.rb +0 -7
  104. data/spec/web_image_spec.rb +0 -57
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe LinkThumbnailer::Models::Description do
4
+
5
+ let(:text) { 'bar' }
6
+ let(:grader) { double(call: 0) }
7
+ let(:node) { double(text: 'bar') }
8
+ let(:instance) { described_class.new(node, text) }
9
+
10
+ before do
11
+ ::LinkThumbnailer::Grader.should_receive(:new).at_least(1).and_return(grader)
12
+ end
13
+
14
+ describe '#to_s' do
15
+
16
+ let(:action) { instance.to_s }
17
+
18
+ it { expect(action).to eq(text) }
19
+
20
+ end
21
+
22
+ describe '#<=>' do
23
+
24
+ let(:another_instance) { described_class.new(node, text) }
25
+ let(:score) { 5 }
26
+ let(:action) { instance <=> another_instance }
27
+
28
+ before do
29
+ another_instance.score = score
30
+ end
31
+
32
+ context 'when instance score is lower' do
33
+
34
+ before do
35
+ instance.score = score - 1
36
+ end
37
+
38
+ it { expect(action).to eq(-1) }
39
+
40
+ end
41
+
42
+ context 'when instance score is equal' do
43
+
44
+ before do
45
+ instance.score = score
46
+ end
47
+
48
+ it { expect(action).to eq(0) }
49
+
50
+ end
51
+
52
+ context 'when instance score is greater' do
53
+
54
+ before do
55
+ instance.score = score + 1
56
+ end
57
+
58
+ it { expect(action).to eq(1) }
59
+
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe LinkThumbnailer::Models::Image do
4
+
5
+ let(:src) { 'http://foo.com' }
6
+ let(:instance) { described_class.new(src) }
7
+
8
+ before do
9
+ stub_request(:get, src).to_return(status: 200, body: '', headers: {})
10
+ end
11
+
12
+ describe '#to_s' do
13
+
14
+ let(:action) { instance.to_s }
15
+
16
+ it { expect(action).to eq(src) }
17
+
18
+ end
19
+
20
+ describe '#<=>' do
21
+
22
+ let(:other) { double(size: other_size) }
23
+ let(:action) { instance <=> other }
24
+
25
+ before do
26
+ instance.stub(:size).and_return([20, 20])
27
+ end
28
+
29
+ context 'when other has a smaller image' do
30
+
31
+ let(:other_size) { [10, 10] }
32
+
33
+ it { expect(action).to eq(-1) }
34
+
35
+ end
36
+
37
+ context 'when other as identical image size' do
38
+
39
+ let(:other_size) { [20, 20] }
40
+
41
+ it { expect(action).to eq(0) }
42
+
43
+ end
44
+
45
+ context 'when other as a bigger image' do
46
+
47
+ let(:other_size) { [30, 30] }
48
+
49
+ it { expect(action).to eq(1) }
50
+
51
+ end
52
+
53
+ end
54
+
55
+ describe '#valid?' do
56
+
57
+ let(:validator) { double }
58
+ let(:action) { instance.valid? }
59
+
60
+ before do
61
+ instance.stub(:validator).and_return(validator)
62
+ end
63
+
64
+ it 'calls validator public method' do
65
+ expect(validator).to receive(:call)
66
+ action
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe LinkThumbnailer::Models::Title do
4
+
5
+ let(:node) { double(text: 'bar') }
6
+ let(:instance) { described_class.new(node, text) }
7
+
8
+ context 'when text provided' do
9
+
10
+ let(:text) { 'foo' }
11
+
12
+ it { expect(instance.to_s).to eq(text) }
13
+
14
+ end
15
+
16
+ context 'when text not provided' do
17
+
18
+ let(:text) { nil }
19
+
20
+ it { expect(instance.to_s).to eq(node.text) }
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe LinkThumbnailer::Models::Website do
4
+
5
+ let(:instance) { described_class.new }
6
+
7
+ it { expect(instance.images).to be_empty }
8
+
9
+ describe '#image=' do
10
+
11
+ let(:image) { double }
12
+ let(:action) { instance.image = image }
13
+
14
+ before do
15
+ image.stub(:valid?).and_return(true)
16
+ end
17
+
18
+ it { expect { action }.to change { instance.images.size }.by(1) }
19
+
20
+ end
21
+
22
+ describe '#images=' do
23
+
24
+ let(:image) { double }
25
+ let(:action) { instance.images = image }
26
+
27
+ context 'when image is valid' do
28
+
29
+ before do
30
+ image.stub(:valid?).and_return(true)
31
+ end
32
+
33
+ it { expect { action }.to change { instance.images.size }.by(1) }
34
+
35
+ end
36
+
37
+ context 'when image is not valid' do
38
+
39
+ before do
40
+ image.stub(:valid?).and_return(false)
41
+ end
42
+
43
+ it { expect { action }.to_not change { instance.images.size }.by(1) }
44
+
45
+ end
46
+
47
+ end
48
+
49
+ end
data/spec/page_spec.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe LinkThumbnailer::Page do
4
+
5
+ let(:url) { 'http://foo.com' }
6
+ let(:instance) { described_class.new(url, options) }
7
+
8
+ context 'with inline options' do
9
+
10
+ let(:options) { { image_limit: 2 } }
11
+
12
+ it { expect(instance.config.image_limit).to eq(2) }
13
+ it { expect(instance.config.user_agent).to eq(LinkThumbnailer.config.user_agent) }
14
+
15
+ end
16
+
17
+ context 'without inline options' do
18
+
19
+ let(:options) { {} }
20
+
21
+ it { expect(instance.config.image_limit).to eq(LinkThumbnailer.config.image_limit) }
22
+ it { expect(instance.config.user_agent).to eq(LinkThumbnailer.config.user_agent) }
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,349 @@
1
+ require 'spec_helper'
2
+
3
+ describe LinkThumbnailer::Processor do
4
+
5
+ let(:instance) { described_class.new }
6
+ let(:url) { 'http://foo.com' }
7
+
8
+ describe '#call' do
9
+
10
+ let(:action) { instance.call(url) }
11
+
12
+ context 'when redirect_count is greater than config' do
13
+
14
+ it { expect { instance.call(url, 10) } .to raise_error(LinkThumbnailer::RedirectLimit) }
15
+
16
+ end
17
+
18
+ context 'on no http error' do
19
+
20
+ let(:body) { 'foo' }
21
+
22
+ before do
23
+ stub_request(:get, url).to_return(status: 200, body: body, headers: {})
24
+ end
25
+
26
+ it { expect(action).to eq(body) }
27
+
28
+ end
29
+
30
+ context 'on http error' do
31
+
32
+ before do
33
+ stub_request(:get, url).to_return(status: 500, body: '', headers: {})
34
+ end
35
+
36
+ it { expect { action }.to raise_error(Net::HTTPFatalError) }
37
+
38
+ end
39
+
40
+ context 'on http redirection' do
41
+
42
+ let(:body) { 'foo' }
43
+
44
+ context 'with relative uri' do
45
+
46
+ let(:another_url) { '/bar' }
47
+
48
+ before do
49
+ stub_request(:get, url).to_return(status: 300, body: '', headers: { 'Location' => another_url })
50
+ stub_request(:get, url + another_url).to_return(status: 200, body: body, headers: {})
51
+ end
52
+
53
+ it { expect(action).to eq(body) }
54
+
55
+ end
56
+
57
+ context 'with absolute uri' do
58
+
59
+ let(:another_url) { 'http://bar.com' }
60
+
61
+ before do
62
+ stub_request(:get, url).to_return(status: 300, body: '', headers: { 'Location' => another_url })
63
+ stub_request(:get, another_url).to_return(status: 200, body: body, headers: {})
64
+ end
65
+
66
+ it { expect(action).to eq(body) }
67
+
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+
74
+ describe '#with_valid_url' do
75
+
76
+ context 'when valid' do
77
+
78
+ before do
79
+ instance.stub(:valid_url_format?).and_return(true)
80
+ end
81
+
82
+ it 'yields' do
83
+ expect(instance).to receive(:with_valid_url).and_yield
84
+ instance.send(:with_valid_url) {}
85
+ end
86
+
87
+ end
88
+
89
+ context 'when not valid' do
90
+
91
+ before do
92
+ instance.stub(:valid_url_format?).and_return(false)
93
+ end
94
+
95
+ it { expect { instance.send(:with_valid_url) }.to raise_error(LinkThumbnailer::BadUriFormat) }
96
+
97
+ end
98
+
99
+ end
100
+
101
+ describe '#set_http_headers' do
102
+
103
+ let(:user_agent) { 'foo' }
104
+ let(:headers) { instance.send(:http).headers }
105
+ let(:action) { instance.send(:set_http_headers) }
106
+
107
+ before do
108
+ instance.stub(:user_agent).and_return(user_agent)
109
+ action
110
+ end
111
+
112
+ it { expect(headers['User-Agent']).to eq(user_agent) }
113
+
114
+ end
115
+
116
+ describe '#set_http_options' do
117
+
118
+ let(:http) { instance.send(:http) }
119
+ let(:action) { instance.send(:set_http_options) }
120
+
121
+ describe 'verify_mode' do
122
+
123
+ context 'when verify_ssl is true' do
124
+
125
+ before do
126
+ instance.stub(:ssl_required?).and_return(true)
127
+ action
128
+ end
129
+
130
+ it { expect(http.verify_mode).to_not eq(::OpenSSL::SSL::VERIFY_NONE) }
131
+
132
+ end
133
+
134
+ context 'when verify_ssl is not true' do
135
+
136
+ before do
137
+ instance.stub(:ssl_required?).and_return(false)
138
+ action
139
+ end
140
+
141
+ it { expect(http.verify_mode).to eq(::OpenSSL::SSL::VERIFY_NONE) }
142
+
143
+ end
144
+
145
+ end
146
+
147
+ describe 'open_timeout' do
148
+
149
+ let(:http_timeout) { 1 }
150
+
151
+ before do
152
+ instance.stub(:http_timeout).and_return(http_timeout)
153
+ action
154
+ end
155
+
156
+ it { expect(http.open_timeout).to eq(http_timeout) }
157
+
158
+ end
159
+
160
+ end
161
+
162
+ describe '#perform_request' do
163
+
164
+ let(:action) { instance.send(:perform_request) }
165
+
166
+ before do
167
+ instance.stub_chain(:http, :request).and_return(response)
168
+ end
169
+
170
+ context 'when http success' do
171
+
172
+ let(:code) { 200 }
173
+ let(:body) { 'body' }
174
+ let(:response) { ::Net::HTTPSuccess.new('', code, body) }
175
+
176
+ before do
177
+ response.stub(:body).and_return(body)
178
+ end
179
+
180
+ it { expect(action).to eq(body) }
181
+
182
+ end
183
+
184
+ context 'when http redirection' do
185
+
186
+ let(:code) { 200 }
187
+ let(:body) { 'body' }
188
+ let(:response) { ::Net::HTTPRedirection.new('', code, body) }
189
+ let(:new_url) { 'http://foo.com/bar' }
190
+
191
+ before do
192
+ instance.stub(:redirect_count).and_return(0)
193
+ instance.stub(:resolve_relative_url).and_return(new_url)
194
+ end
195
+
196
+ it 'calls call method' do
197
+ expect(instance).to receive(:resolve_relative_url)
198
+ expect(instance).to receive(:call).with(new_url, instance.redirect_count + 1)
199
+ action
200
+ end
201
+
202
+ end
203
+
204
+ end
205
+
206
+ describe '#build_absolute_url_for' do
207
+
208
+ let(:scheme) { 'https' }
209
+ let(:host) { 'foo.com' }
210
+ let(:url) { URI("#{scheme}://#{host}") }
211
+ let(:relative_url) { '/bar' }
212
+ let(:action) { instance.send(:build_absolute_url_for, relative_url).to_s }
213
+
214
+ before do
215
+ instance.stub(:url).and_return(url)
216
+ end
217
+
218
+ it { expect(action).to eq("#{scheme}://#{host}#{relative_url}") }
219
+
220
+ end
221
+
222
+ describe '#redirect_limit' do
223
+
224
+ let(:redirect_limit) { 1 }
225
+ let(:action) { instance.send(:redirect_limit) }
226
+
227
+ before do
228
+ instance.config.redirect_limit = redirect_limit
229
+ end
230
+
231
+ it { expect(action).to eq(redirect_limit) }
232
+
233
+ end
234
+
235
+ describe '#user_agent' do
236
+
237
+ let(:user_agent) { 'foo' }
238
+ let(:action) { instance.send(:user_agent) }
239
+
240
+ before do
241
+ instance.config.user_agent = user_agent
242
+ end
243
+
244
+ it { expect(action).to eq(user_agent) }
245
+
246
+ end
247
+
248
+ describe '#http_timeout' do
249
+
250
+ let(:http_timeout) { 1 }
251
+ let(:action) { instance.send(:http_timeout) }
252
+
253
+ before do
254
+ instance.config.http_timeout = http_timeout
255
+ end
256
+
257
+ it { expect(action).to eq(http_timeout) }
258
+
259
+ end
260
+
261
+ describe '#ssl_required?' do
262
+
263
+ let(:verify_ssl) { true }
264
+ let(:action) { instance.send(:ssl_required?) }
265
+
266
+ before do
267
+ instance.config.verify_ssl = verify_ssl
268
+ end
269
+
270
+ it { expect(action).to eq(verify_ssl) }
271
+
272
+ end
273
+
274
+ describe '#valid_url_format?' do
275
+
276
+ let(:action) { instance.send(:valid_url_format?) }
277
+
278
+ context 'when bad format' do
279
+
280
+ before do
281
+ instance.stub(:url).and_return("http://foo.com")
282
+ end
283
+
284
+ it { expect(action).to be_false }
285
+
286
+ end
287
+
288
+ context 'when valid format' do
289
+
290
+ before do
291
+ instance.stub(:url).and_return(URI("http://foo.com"))
292
+ end
293
+
294
+ it { expect(action).to be_true }
295
+
296
+ end
297
+
298
+ end
299
+
300
+ describe '#too_many_redirections?' do
301
+
302
+ let(:action) { instance.send(:too_many_redirections?) }
303
+
304
+ context 'when redirect count is greater than redirect limit' do
305
+
306
+ before do
307
+ instance.stub(:redirect_count).and_return(5)
308
+ instance.stub(:redirect_limit).and_return(4)
309
+ end
310
+
311
+ it { expect(action).to be_true }
312
+
313
+ end
314
+
315
+ context 'when redirect count is less than redirect limit' do
316
+
317
+ before do
318
+ instance.stub(:redirect_count).and_return(4)
319
+ instance.stub(:redirect_limit).and_return(5)
320
+ end
321
+
322
+ it { expect(action).to be_false }
323
+
324
+ end
325
+
326
+ context 'when redirect count is equal to redirect limit' do
327
+
328
+ before do
329
+ instance.stub(:redirect_count).and_return(5)
330
+ instance.stub(:redirect_limit).and_return(5)
331
+ end
332
+
333
+ it { expect(action).to be_false }
334
+
335
+ end
336
+
337
+ end
338
+
339
+ describe '#url=' do
340
+
341
+ before do
342
+ instance.send(:url=, url)
343
+ end
344
+
345
+ it { expect(instance.url).to be_a(URI) }
346
+
347
+ end
348
+
349
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe LinkThumbnailer::Scraper do
4
+
5
+ let(:source) { '' }
6
+ let(:url) { 'http://foo.com' }
7
+ let(:document) { double('document') }
8
+ let(:website) { double('website') }
9
+ let(:instance) { described_class.new(source, url) }
10
+
11
+ before do
12
+ instance.stub(:document).and_return(document)
13
+ instance.stub(:website).and_return(website)
14
+ end
15
+
16
+ describe '#call' do
17
+
18
+ let(:prefix_1) { 'prefix_1' }
19
+ let(:prefix_2) { 'prefix_2' }
20
+ let(:scraper_class) { double('scraper_class') }
21
+ let(:applicable_scraper) { double(applicable?: true) }
22
+ let(:not_applicable_scraper) { double(applicable?: false) }
23
+ let(:attributes) { [:bar] }
24
+ let(:scrapers) { [prefix_1, prefix_2] }
25
+ let(:action) { instance.call }
26
+
27
+ before do
28
+ instance.stub_chain(:config, :attributes).and_return(attributes)
29
+ instance.stub(:scrapers).and_return(scrapers)
30
+ end
31
+
32
+ context 'when first scraper not applicable' do
33
+
34
+ before do
35
+ expect(website).to receive(:bar).and_return('bar')
36
+ expect(applicable_scraper).to receive(:call).with(website, 'bar')
37
+ expect(scraper_class).to receive(:new).with(document).and_return(applicable_scraper)
38
+ expect(instance).to receive(:scraper_class).with(prefix_1, :bar).and_return(scraper_class)
39
+ end
40
+
41
+ it { expect(action).to eq(website) }
42
+
43
+ end
44
+
45
+ context 'when first scraper applicable' do
46
+
47
+ before do
48
+ expect(website).to receive(:bar).and_return('bar')
49
+ expect(not_applicable_scraper).to_not receive(:call).with(website, 'bar')
50
+ expect(scraper_class).to receive(:new).with(document).and_return(not_applicable_scraper)
51
+ expect(instance).to receive(:scraper_class).with(prefix_1, :bar).and_return(scraper_class)
52
+ end
53
+
54
+ it { expect(action).to eq(website) }
55
+
56
+ end
57
+
58
+ context 'when all scrapers applicable and first one return a result' do
59
+
60
+ let(:valid_scraper) { double('scraper', applicable?: true) }
61
+ let(:not_valid_scraper) { double('scraper', applicable?: true) }
62
+
63
+ before do
64
+ expect(website).to receive(:bar).once.and_return('bar')
65
+ expect(valid_scraper).to receive(:call).once.with(website, 'bar')
66
+ expect(not_valid_scraper).to_not receive(:call).with(website, 'bar')
67
+ expect(scraper_class).to receive(:new).with(document).once.and_return(valid_scraper)
68
+ expect(instance).to receive(:scraper_class).with(prefix_1, :bar).and_return(scraper_class)
69
+ end
70
+
71
+ it { expect(action).to eq(website) }
72
+
73
+ end
74
+
75
+ context 'when all scrapers applicable but first one do not return any result' do
76
+
77
+ let(:valid_scraper) { double('scraper', applicable?: true) }
78
+ let(:not_valid_scraper) { double('scraper', applicable?: true) }
79
+
80
+ before do
81
+ expect(website).to receive(:bar).and_return('', 'bar')
82
+ expect(valid_scraper).to receive(:call).once.with(website, 'bar')
83
+ expect(not_valid_scraper).to receive(:call).once.with(website, 'bar')
84
+ expect(scraper_class).to receive(:new).with(document).and_return(not_valid_scraper, valid_scraper)
85
+ expect(instance).to receive(:scraper_class).with(prefix_1, :bar).and_return(scraper_class)
86
+ expect(instance).to receive(:scraper_class).with(prefix_2, :bar).and_return(scraper_class)
87
+ end
88
+
89
+ it { expect(action).to eq(website) }
90
+
91
+ end
92
+
93
+ end
94
+
95
+ end