site_prism.vcr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +12 -0
  5. data/Gemfile +17 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +381 -0
  8. data/Rakefile +1 -0
  9. data/TODO.md +71 -0
  10. data/lib/site_prism.vcr.rb +1 -0
  11. data/lib/site_prism_vcr/applier.rb +54 -0
  12. data/lib/site_prism_vcr/dsl/adjuster.rb +82 -0
  13. data/lib/site_prism_vcr/dsl/initial_adjuster.rb +97 -0
  14. data/lib/site_prism_vcr/element.rb +18 -0
  15. data/lib/site_prism_vcr/fixture.rb +29 -0
  16. data/lib/site_prism_vcr/fixtures/converter.rb +17 -0
  17. data/lib/site_prism_vcr/fixtures/handler.rb +31 -0
  18. data/lib/site_prism_vcr/fixtures/manager.rb +38 -0
  19. data/lib/site_prism_vcr/fixtures/modifiers/home_path.rb +27 -0
  20. data/lib/site_prism_vcr/fixtures/modifiers/path.rb +30 -0
  21. data/lib/site_prism_vcr/fixtures/tmp_keeper.rb +21 -0
  22. data/lib/site_prism_vcr/fixtures.rb +41 -0
  23. data/lib/site_prism_vcr/options.rb +22 -0
  24. data/lib/site_prism_vcr/options_with_path.rb +7 -0
  25. data/lib/site_prism_vcr/patches/element_container.rb +15 -0
  26. data/lib/site_prism_vcr/patches/page.rb +41 -0
  27. data/lib/site_prism_vcr/vcr_helpers.rb +18 -0
  28. data/lib/site_prism_vcr/version.rb +3 -0
  29. data/lib/site_prism_vcr/waiter.rb +23 -0
  30. data/lib/site_prism_vcr.rb +24 -0
  31. data/site_prism.vcr.gemspec +24 -0
  32. data/spec/fixtures/arya_stark.yml +44 -0
  33. data/spec/fixtures/custom/blank.yml +44 -0
  34. data/spec/fixtures/custom/bran_stark.yml +44 -0
  35. data/spec/fixtures/custom/daenerys_targaryen.yml +44 -0
  36. data/spec/fixtures/jon_snow.yml +44 -0
  37. data/spec/fixtures/ned_stark.yml +44 -0
  38. data/spec/fixtures/robb_stark.yml +44 -0
  39. data/spec/integration/http_interactions_on_even/click_spec.rb +75 -0
  40. data/spec/integration/immediate_http_interactions/page_load_on_click_spec.rb +18 -0
  41. data/spec/integration/immediate_http_interactions/page_load_spec.rb +56 -0
  42. data/spec/spec_helper.rb +18 -0
  43. data/spec/spec_integration_helper.rb +27 -0
  44. data/spec/support/shared/integration/custom_fixtures.rb +32 -0
  45. data/spec/support/shared/integration/exchange.rb +42 -0
  46. data/spec/support/shared/integration/home_path.rb +49 -0
  47. data/spec/support/shared/integration/waiter.rb +75 -0
  48. data/spec/support/site_prism/pages/base.rb +18 -0
  49. data/spec/support/site_prism/pages/home.rb +44 -0
  50. data/spec/support/site_prism/pages/immediate_http_interactions/home_path.rb +15 -0
  51. data/spec/support/site_prism/pages/immediate_http_interactions/one_request.rb +13 -0
  52. data/spec/support/site_prism/pages/immediate_http_interactions/subpage.rb +7 -0
  53. data/spec/support/site_prism/pages/immediate_http_interactions/two_requests.rb +12 -0
  54. data/spec/support/site_prism/pages/immediate_http_interactions/waiter_without_fixtures_ejection.rb +12 -0
  55. data/spec/support/site_prism/sections/console_block.rb +8 -0
  56. data/spec/support/test_app/public/jquery.min.js +5 -0
  57. data/spec/support/test_app/public/test.js +44 -0
  58. data/spec/support/test_app/test_app.rb +46 -0
  59. data/spec/support/test_app/views/index.erb +26 -0
  60. data/spec/unit/applier_spec.rb +134 -0
  61. data/spec/unit/dsl/adjuster_spec.rb +141 -0
  62. data/spec/unit/dsl/initial_adjuster_spec.rb +166 -0
  63. data/spec/unit/element_container_spec.rb +48 -0
  64. data/spec/unit/element_spec.rb +47 -0
  65. data/spec/unit/fixture_spec.rb +45 -0
  66. data/spec/unit/fixtures/converter_spec.rb +36 -0
  67. data/spec/unit/fixtures/handler_spec.rb +72 -0
  68. data/spec/unit/fixtures/manager_spec.rb +58 -0
  69. data/spec/unit/fixtures/modifiers/home_path_spec.rb +47 -0
  70. data/spec/unit/fixtures/modifiers/path_spec.rb +45 -0
  71. data/spec/unit/fixtures/tmp_keeper_spec.rb +17 -0
  72. data/spec/unit/fixtures_spec.rb +76 -0
  73. data/spec/unit/options_spec.rb +41 -0
  74. data/spec/unit/patches/element_container_spec.rb +48 -0
  75. data/spec/unit/patches/page_spec.rb +57 -0
  76. data/spec/unit/vcr_helpers_spec.rb +18 -0
  77. data/spec/unit/waiter_spec.rb +67 -0
  78. metadata +213 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Y2YwODQ0Y2JlYTZlMTI2YzIyMjA2Y2VhNmNiNDE5YTgwMmY4Y2E1ZQ==
5
+ data.tar.gz: !binary |-
6
+ YTU3ZWMxMGVkZWIyODA2MmQzZTcxZjZkMmZlNGQzMGI4MWVlNzhiZQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ N2FmY2YxNGYyMTUwZmUzZjg4NDVlNWJhYmZiOWE1OGQyYjgxZDljOGZjNWFh
10
+ NTI2MDIyOGNkMjgyZjg1ZDJhODM2ZGMxNjA5M2RjMjc0NjVmNzQwOWNiY2Y0
11
+ ZTI4NTA5OThkY2JmOTFhYzliM2IwOTRmYjAxNjJlODA1YjI3NWQ=
12
+ data.tar.gz: !binary |-
13
+ YjE4MTFlYjE2MmIwOGM5YzJmZGQxMTg5M2RlOTI2ZjQyYjZjYjAyMWNiMDYz
14
+ OTlhM2ZhMDgwYzBkYzQ2NzQ3ZDY3YTA5YWI0YzkxOWQ0Njc3ZDU5OTljZDhm
15
+ Mjk3MmNlMmY3Y2Q3ZmIyZWMxMTA5NTIxMWNlMWJkMjE4MzY2ZmQ=
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --profile
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ matrix:
6
+ allow_failures:
7
+ - rvm: jruby-19mode
8
+ - rvm: rbx-19mode
9
+ before_install:
10
+ - "export DISPLAY=:99.0"
11
+ - "sh -e /etc/init.d/xvfb start"
12
+ script: bundle exec rspec spec
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in site_prism.vcr.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'rspec', '~> 2.14.1'
8
+ gem 'sinatra'
9
+ gem 'httpi'
10
+ gem 'capybara-firebug'
11
+ end
12
+
13
+ group :test do
14
+ gem 'selenium-webdriver'
15
+ gem 'coveralls', require: false
16
+ end
17
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Dmitriy Nesteryuk
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,381 @@
1
+ # SitePrism.Vcr
2
+
3
+ [![Code Climate](https://codeclimate.com/github/nestd/site_prism.vcr.png)](https://codeclimate.com/github/nestd/site_prism.vcr)
4
+ [![Build Status](https://secure.travis-ci.org/nestd/site_prism.vcr.png?branch=master)](https://travis-ci.org/nestd/site_prism.vcr)
5
+ [![Coverage Status](https://coveralls.io/repos/nestd/site_prism.vcr/badge.png)](https://coveralls.io/r/nestd/site_prism.vcr)
6
+ [![Dependency Status](https://gemnasium.com/nestd/site_prism.vcr.png)](https://gemnasium.com/nestd/site_prism.vcr)
7
+
8
+ The purpose of this gem is to give an easy way for integrating [SitePrism](https://github.com/natritmeyer/site_prism) (it is Page Object Model DSL for Capybara) and [VCR](https://github.com/vcr/vcr) (it is a powerful tool for recording and stubbing HTTP interactions).
9
+
10
+ Such integration allows you to write acceptance tests more easily since you receive handy tool for managing VCR cassettes. Those cassettes can be easily linked with SitePrism elements (in fact, Capybara elements since SitePrism doesn't have own elements). Afterwards those linked cassettes can be used for stubbing external API responses while clicking on an element that cassettes are defined for.
11
+
12
+ ## Features
13
+
14
+ * Links VCR cassettes with SitePrism elements.
15
+ * Links VCR cassettes with SitePrism pages.
16
+ * Applies VCR cassettes while clicking on an element.
17
+ * Applies VCR cassettes while loading a page.
18
+ * Defines a waiter which will be used for waiting until an expected element is on a page or until an expected element has disappeared from a page (It is very helpful when a few external API requests are being executed after clicking on an element).
19
+ * Allows to redefine default VCR cassettes (cassettes which were specified while describing a SitePrism element or a SitePrism page).
20
+ * Allows to redefine a default waiter (a waiter which was specified while describing a SitePrism element or a SitePrism page).
21
+
22
+ ## Installation
23
+
24
+ Add this line to your application's Gemfile:
25
+
26
+ gem 'site_prism.vcr'
27
+
28
+ And then execute:
29
+
30
+ $ bundle install
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install site_prism.vcr
35
+
36
+ ## Usage
37
+
38
+ ### Linking VCR cassettes with SitePrism elements
39
+
40
+ To link VCR cassettes with SitePrism elements, you have to use `element_with_vcr` instead of `element` method of SitePrism for specifying elements:
41
+
42
+ ```ruby
43
+ class ProductsPage < SitePrism::Page
44
+ element_with_vcr \
45
+ :car_details_link,
46
+ '#car_details' do
47
+ fixtures ['ford', 'cars/ford_features']
48
+ end
49
+ end
50
+ ```
51
+
52
+ `fixtures` helper method is used for defining VCR cassettes. All cassettes are taken from a path which you have defined in `cassette_library_dir` configuration option of VCR. Please, refer to [documentation](https://relishapp.com/vcr/vcr/v/2-5-0/docs/configuration/cassette-library-dir) of VCR to get more info about configuration options.
53
+
54
+ #### Path helper method
55
+
56
+ In case you have a lot of cassettes which are stored in some subdirectory, there is more better way for defining cassettes:
57
+
58
+ ```ruby
59
+ class ProductsPage < SitePrism::Page
60
+ element_with_vcr \
61
+ :car_details_link,
62
+ '#car_details' do
63
+ path 'cars/small', ['ford', 'ford_features', 'prices']
64
+ path 'offerings', ['used_cars', 'new_cars']
65
+ end
66
+ end
67
+ ```
68
+
69
+ The `path` helper method can be used a few times in a block to define cassettes. The code above is identical to:
70
+
71
+ ```ruby
72
+ class ProductsPage < SitePrism::Page
73
+ element_with_vcr \
74
+ :car_details_link,
75
+ '#car_details' do
76
+ fixtures [
77
+ 'cars/small/ford',
78
+ 'cars/small/ford_features',
79
+ 'cars/small/prices',
80
+ 'offerings/used_cars',
81
+ 'offerings/new_cars'
82
+ ]
83
+ end
84
+ end
85
+ ```
86
+
87
+ #### Home path helper method
88
+
89
+ There is a possibility to define a home path to cassettes which are applied for a particular element:
90
+
91
+ ```ruby
92
+ class ProductsPage < SitePrism::Page
93
+ element_with_vcr \
94
+ :car_details_link,
95
+ '#car_details' do
96
+ home_path 'cars/small'
97
+
98
+ fixtures ['~/ford', '~/ford_features', '~/prices']
99
+ end
100
+ end
101
+ ```
102
+
103
+ If some fixture name begins with `~/`, it means that a defined home path will be applied to find such fixture. The previous example is identical to this one:
104
+
105
+ ```ruby
106
+ class ProductsPage < SitePrism::Page
107
+ element_with_vcr \
108
+ :car_details_link,
109
+ '#car_details' do
110
+ fixtures [
111
+ 'cars/small/ford',
112
+ 'cars/small/ford_features',
113
+ 'cars/small/prices'
114
+ ]
115
+ end
116
+ end
117
+ ```
118
+
119
+ Home path is a very useful while redefining default cassettes (It is described below).
120
+
121
+ Also, you can use a defined home path with the `path` helper method:
122
+
123
+ ```ruby
124
+ class ProductsPage < SitePrism::Page
125
+ element_with_vcr \
126
+ :car_details_link,
127
+ '#car_details' do
128
+ home_path 'cars/small'
129
+
130
+ path '~/', ['ford', 'ford_features', 'prices']
131
+ end
132
+ end
133
+ ```
134
+
135
+ ### Applying VCR cassettes on click
136
+
137
+ Now cassettes can be applied only on a click event:
138
+
139
+ ```ruby
140
+ @products_page.car_details_link.click_and_apply_vcr
141
+ ```
142
+
143
+ This code applies VCR cassettes which were specified while defining a SitePrism element. But, there is also possibility to override them:
144
+
145
+ ```ruby
146
+ @products_page.car_details_link.click_and_apply_vcr do
147
+ fixtures ['cars/volvo']
148
+ end
149
+ ```
150
+
151
+ This code completely overrides default cassettes, but only for this one particular click action. If you want to apply default cassettes again after this code, just use code without specifying custom cassettes:
152
+
153
+ ```ruby
154
+ @products_page.car_details_link.click_and_apply_vcr do # overrides all default cassettes
155
+ fixtures ['cars/volvo']
156
+ end
157
+
158
+ @products_page.car_details_link.click_and_apply_vcr # uses default cassettes again
159
+ ```
160
+
161
+ Also, there is possibility to add new cassettes instead of overriding default one:
162
+
163
+ ```ruby
164
+ @products_page.car_details_link.click_and_apply_vcr do
165
+ fixtures ['cars/volvo']
166
+ union # makes this library add new cassettes to a list with default cassettes
167
+ end
168
+ ```
169
+
170
+ Similar to defining SitePrism elements with VCR cassettes, you can use `path` helper method while applying fixtures:
171
+
172
+ ```ruby
173
+ @products_page.car_details_link.click_and_apply_vcr do
174
+ path 'cars/small', ['volvo', 'volvo_features', 'prices']
175
+ end
176
+ ```
177
+
178
+ Also, if you have specified a home path while defining a SitePrism element, you can use it here:
179
+
180
+ ```ruby
181
+ @products_page.car_details_link.click_and_apply_vcr do
182
+ fixtures ['~/volvo', '~/volvo_features', '~/prices']
183
+ end
184
+ ```
185
+
186
+ or
187
+
188
+ ```ruby
189
+ @products_page.car_details_link.click_and_apply_vcr do
190
+ path '~/', ['volvo', 'volvo_features', 'prices']
191
+ end
192
+ ```
193
+
194
+ Home path can be defined while applying Vcr:
195
+
196
+ ```ruby
197
+ @products_page.car_details_link.click_and_apply_vcr do
198
+ home_path 'cars/volvo'
199
+
200
+ path '~/', ['volvo', 'volvo_features', 'prices']
201
+ end
202
+ ```
203
+
204
+ #### Exchange default fixtures
205
+
206
+ There may be a situation when you need to exchange some default cassette for one specific test. It is a very easy to do:
207
+
208
+ ```ruby
209
+ @products_page.car_details_link.click_and_apply_vcr do
210
+ exchange 'volvo', 'ford'
211
+ end
212
+ ```
213
+
214
+ When you use a home path:
215
+
216
+ ```ruby
217
+ @products_page.car_details_link.click_and_apply_vcr do
218
+ exchange '~/volvo', '~/ford'
219
+ end
220
+ ```
221
+
222
+ Also, multiple cassettes can be exchanged:
223
+
224
+ ```ruby
225
+ @products_page.car_details_link.click_and_apply_vcr do
226
+ exchange ['~/volvo', '~/ford'], ['~/mazda', '~/toyota']
227
+ end
228
+ ```
229
+
230
+ ### Waiters
231
+
232
+ Waiters are very important part of this gem (actually, waiters are part of SitePrism gem, but they are used widely here). When we do some action and that action causes a few HTTP interactions we have to wait for a result of them, before expecting something on a page. The good approach is to wait for some visibility or invisibility of an element. For example, you have a list of products when you click on a button to show details of some product, you may wait until loading indicator which may be shown on a details page of a product disappears. Capybara already waits for an element to appear, but it hasn't any possibility to wait for invisibility of an element, SitePrism has this capability and it is very useful.
233
+
234
+ There is reason why you should use them when you use SitePrism.Vcr. If you specify a waiter while describing SitePrism elements or applying VCR cassettes, SitePrism.Vcr will know when the inserted cassettes should be ejected from Vcr to avoid a situation when some unexpected cassette is applied.
235
+
236
+ There are 2 ways for defining a waiter. When you define SitePrism elements:
237
+
238
+ ```ruby
239
+ class ProductsPage < SitePrism::Page
240
+ element_with_vcr \
241
+ :car_details_link,
242
+ '#car_details' do
243
+ fixtures ['ford', 'cars/ford_features']
244
+ waiter &:wait_until_loading_indicator_invisible # our code will wait until the loading indicator has disappeared from a page
245
+ end
246
+ end
247
+ ```
248
+
249
+ The second way is to set it while applying Vcr cassettes:
250
+
251
+ ```ruby
252
+ @products_page.car_details_link.click_and_apply_vcr do
253
+ fixtures ['cars/volvo']
254
+ waiter &:wait_until_loading_indicator_invisible
255
+ end
256
+ ```
257
+
258
+ *Note:* Using the second way, you can override a default waiter which was specified while defining SitePrism element.
259
+
260
+ In this case once we meet an expectation defined in a waiter, Vcr cassettes will be ejected and you will avoid issues with mixing unexpected cassettes. If you don't specify a waiter, you have to eject them manually:
261
+
262
+ ```ruby
263
+ after do
264
+ SPV::Helpers.eject_all_cassettes
265
+ end
266
+ ```
267
+
268
+ or directly in the test:
269
+
270
+ ```ruby
271
+ it 'displays details of a product' do
272
+ products_page.products.first.show_details_btn.click_and_apply_vcr
273
+ products_page.details.should have_content('Volvo')
274
+
275
+ SPV::Helpers.eject_all_cassettes
276
+
277
+ products_page.products.second.show_details_btn.click_and_apply_vcr
278
+ products_page.details.should have_content('Ford')
279
+ end
280
+ ```
281
+
282
+ *Note:* Waiters must be defined in a block. In a block you have access to an instance of class where you define elements.
283
+
284
+ There may be situation when you don't need a waiter to eject all cassettes. In this case you can pass an additional option to a waiter to disable ejecting all cassettes:
285
+
286
+ ```ruby
287
+ @products_page.car_details_link.click_and_apply_vcr do
288
+ fixtures ['cars/volvo']
289
+ waiter(eject_cassettes: false) { self.wait_until_loading_indicator_invisible }
290
+ end
291
+ ```
292
+
293
+ The same thing can be defined for a default waiter.
294
+
295
+ ### Linking and applying VCR cassettes with SitePrism pages
296
+
297
+ External HTTP interactions may be done on page loading as well. This gem supports capability to apply Vcr cassettes on page loading. To define default cassettes you have to use `vcr_options_for_load` class method:
298
+
299
+ ```ruby
300
+ class ProductsPage < SitePrism::Page
301
+ vcr_options_for_load do
302
+ fixtures ['max']
303
+ end
304
+ end
305
+ ```
306
+
307
+ Everything described above about defining cassettes for SitePrism elements is true for defining cassettes for pages.
308
+
309
+ Applying cassettes is almost the same as we saw for a click event:
310
+
311
+ ```ruby
312
+ page.load_and_apply_vcr do
313
+ fixtures ['max', 'felix']
314
+
315
+ waiter &:wait_for_max_and_felix
316
+ end
317
+ ```
318
+
319
+ All arguments passed to `load_and_apply_vcr` method will be passed to `load` method of SitePrism. It allows you to change an url of the being loaded page.
320
+
321
+ ```ruby
322
+ page.load_and_apply_vcr(cat: 'tom') do
323
+ fixtures ['max', 'felix']
324
+
325
+ waiter &:wait_for_max_and_felix
326
+ end
327
+ ```
328
+
329
+ In this case, SitePrism will alter an url and it will look like:
330
+
331
+ ```ruby
332
+ http://localhost/cats/tom
333
+ ```
334
+
335
+ There may be situation when we need to apply fixtures for page loading when an user clicks on a link (an user moves from one page to another one). In this case you can use `apply_vcr` method of a page object:
336
+
337
+ ```ruby
338
+ @cars = CarsPage.new
339
+
340
+ @cars.apply_vcr(-> { page.find('#cars').click }) do
341
+ fixtures ['cars']
342
+ end
343
+ ```
344
+
345
+ The first argument passed to this method should be a proc object which will do an action. As you can see while applying fixtures without actual loading a page you can use everything what is described for `load_and_apply_vcr` method.
346
+
347
+ ### Using Vcr options for cassettes
348
+
349
+ Vcr provides number of options which can be used for cassettes. For example, you may [pass ERB into cassettes](https://relishapp.com/vcr/vcr/v/2-5-0/docs/cassettes/dynamic-erb-cassettes). This gem doesn't bother you use any options for Vcr cassettes. If you want to do so, you have to use a hash instead of a cassette name:
350
+
351
+ ```ruby
352
+ class ProductsPage < SitePrism::Page
353
+ element_with_vcr \
354
+ :car_details_link,
355
+ '#car_details' do
356
+ home_path 'cars/small'
357
+
358
+ path '~/', [{fixture: 'ford', options: {erb: {amount: 109} } }, 'ford_features', 'prices']
359
+ end
360
+ end
361
+ ```
362
+
363
+ It works with any kind of helper methods where you list names of cassettes, even with the `exchange` helper method:
364
+
365
+ ```ruby
366
+ @products_page.car_details_link.click_and_apply_vcr do
367
+ exchange '~/volvo', {fixture: '~/toyota', options: {erb: {amount: 1000} } }
368
+ end
369
+ ```
370
+
371
+ ## Contributing
372
+
373
+ 1. Fork it
374
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
375
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
376
+ 4. Push to the branch (`git push origin my-new-feature`)
377
+ 5. Create new Pull Request
378
+
379
+
380
+ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/nestd/site_prism.vcr/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
381
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/TODO.md ADDED
@@ -0,0 +1,71 @@
1
+ # TODO
2
+
3
+ ## Release 0.0.1
4
+
5
+ 1. Add comments to code and review existing comments.
6
+
7
+ ## Release 0.0.2
8
+
9
+ 1. Think about adding more integration tests
10
+ 2. Pages and elements should inherit fixtures defined for their parents
11
+ 3. Add possibility to add fixtures for existing elements, it will be helpful in case they are inherited
12
+ 4. Think about applying fixtures for any kind of events, for example, for a change event of select boxes
13
+ 5. Think how to manage the situation when a method name and a block is passed to the `waiter` helper method
14
+ 6. When we eject fixtures from Vcr we should eject only fixtures inserted into Vcr by one specific fixtures manager (See SPV#eject)
15
+ 7. Make this gem working on JRuby
16
+ 8. Give possibility to define options for a waiter instead of redefining a whole waiter in a subclass
17
+ 9. Turn this code:
18
+
19
+ ```ruby
20
+ @cars.apply_vcr(-> { page.find('#cars').click }) do
21
+ fixtures ['cars']
22
+ end
23
+ ```
24
+
25
+ into
26
+
27
+ ```ruby
28
+ @cars.shift_event{ page.find('#cars').click }.apply_vcr do
29
+ fixtures ['cars']
30
+ end
31
+ ```
32
+
33
+ 10. Think about creating set of fixtures which can be exchanged by a name of set. It will be very helpful when you have to exchange a set of fixtures.
34
+ 11. Think how to avoid monkey patching to add stuffs to SitePrism
35
+
36
+ ## Should be implemented?
37
+
38
+ 1. Create possibility to define fixtures without the click action:
39
+
40
+ ```ruby
41
+ self.confirm_btn.vcr do
42
+ path 'products', ['tomato', 'fruit/apple']
43
+ path 'goods', 'cars'
44
+
45
+ replace
46
+ end
47
+ ```
48
+
49
+ and then
50
+
51
+ ```ruby
52
+ self.confirm_btn.click_and_apply_vcr
53
+ ```
54
+
55
+ will use previously defined fixtures
56
+
57
+ 2. There should be possibility to change default fixtures:
58
+
59
+ ```ruby
60
+ self.confirm_btn.vcr do
61
+ path 'products', ['tomato', 'fruit/apple']
62
+ path 'goods', 'cars'
63
+
64
+ force_replace
65
+ end
66
+ ```
67
+
68
+ ## Things to think over
69
+
70
+ 1. Should we add the integration tests for page load to make sure 2 HTTP requests will be handled properly?
71
+ 2. Should we add own integration tests to test the path helper method?
@@ -0,0 +1 @@
1
+ require 'site_prism_vcr'
@@ -0,0 +1,54 @@
1
+ module SPV
2
+ # This class manages defining default fixtures
3
+ # and applying them on an event.
4
+ class Applier
5
+ def initialize(node, &block)
6
+ @node, @options = node, Options.new
7
+ adjuster = DSL::InitialAdjuster.new(@options)
8
+
9
+ if block_given?
10
+ adjuster.instance_eval &block
11
+ end
12
+
13
+ @fixtures = adjuster.prepared_fixtures
14
+
15
+ @fixtures_manager = Fixtures::Manager.new(@options)
16
+ end
17
+
18
+ # Applies fixtures to be used for stubbing HTTP interactions
19
+ # caused by an event (click on an element or page loading).
20
+ #
21
+ # Makes a defined waiter to meet expectation before ejecting
22
+ # fixtures from VCR.
23
+ #
24
+ # @param adjusting_block [nil, Proc] If an adjusting block is given,
25
+ # it allows to change fixtures through DSL (@see SPV::DSL::InitialAdjuster
26
+ # and @see SPV::DSL::Adjuster)
27
+ #
28
+ # @return [void]
29
+ def apply(adjusting_block = nil)
30
+ options = @options.clone_options
31
+
32
+ adjuster = DSL::Adjuster.new(
33
+ options,
34
+ @fixtures
35
+ )
36
+
37
+ if adjusting_block
38
+ adjuster.instance_eval &adjusting_block
39
+ end
40
+
41
+ @fixtures_manager.inject(adjuster.prepared_fixtures)
42
+
43
+ yield
44
+
45
+ @waiter = Waiter.new(
46
+ @node,
47
+ @fixtures_manager,
48
+ options
49
+ )
50
+
51
+ @waiter.wait
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,82 @@
1
+ module SPV
2
+ module DSL
3
+ # This class extends SPV::DSL::InitialAdjuster with new methods
4
+ # which can be used in a block for manipulating fixtures before applying them.
5
+ class Adjuster < InitialAdjuster
6
+ def initialize(options, fixtures)
7
+ super options
8
+
9
+ @options, @fixtures = options, fixtures
10
+ end
11
+
12
+ # Replaces default fixtures with a set of fixtures
13
+ # defined in a block passed while applying fixtures.
14
+ #
15
+ # @return [void]
16
+ #
17
+ # @api public
18
+ def replace
19
+ change_fixtures :replace
20
+ end
21
+
22
+ # Joins default fixtures with a set of fixtures
23
+ # defined in a block passed while applying fixtures.
24
+ #
25
+ # @return [void]
26
+ #
27
+ # @api public
28
+ def union
29
+ change_fixtures :union
30
+ end
31
+
32
+ # Exchanges certain default fixtures with another fixtures.
33
+ #
34
+ # @param old_fixtures [String, Array<String>] List of fixtures which should be removed.
35
+ # If string is passed instead of an array, it will be converted to an array.
36
+ # @param new_fixtures [String, Array<String>] List of fixtures which should added.
37
+ # If string is passed instead of an array, it will be converted to an array.
38
+ #
39
+ # @return [void]
40
+ #
41
+ # @api public
42
+ def exchange(old_fixtures, new_fixtures)
43
+ home_path_modifier = Fixtures::Modifiers::HomePath.new(@options)
44
+
45
+ old_fixtures = [old_fixtures] unless old_fixtures.is_a?(Array)
46
+ new_fixtures = [new_fixtures] unless new_fixtures.is_a?(Array)
47
+
48
+ old_fixtures, new_fixtures = @fixtures_handler.handle_set_raws(
49
+ old_fixtures,
50
+ new_fixtures,
51
+ [home_path_modifier]
52
+ )
53
+
54
+ @fixtures = @fixtures.exchange(
55
+ old_fixtures,
56
+ new_fixtures
57
+ )
58
+ end
59
+
60
+ # Performs the replace action when no explicit action is defined
61
+ # in a block for manipulating fixtures before applying them.
62
+ #
63
+ # @return [SPV::Fixtures] A set of prepared fixtures.
64
+ #
65
+ # @api public
66
+ def prepared_fixtures
67
+ # If no action has been performed,
68
+ # it should be performed manually, before allowing
69
+ # to get prepared fixtures.
70
+ replace unless @is_action_done # TODO: do something with this logic, it looks ugly
71
+ @fixtures
72
+ end
73
+
74
+ private
75
+ def change_fixtures(action)
76
+ @fixtures = @fixtures.public_send(action, @tmp_keeper.fixtures)
77
+ @tmp_keeper.clean_fixtures
78
+ @is_action_done = true
79
+ end
80
+ end # class Adjuster
81
+ end # module DSL
82
+ end # module SPV