capybara_test_helpers 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e4f6226edd7ecb46f2d8376f129d26e8ee0156ed0df1fd1083881a224489da8
4
- data.tar.gz: da483ed245cd972f66b291e31c5345bf9b451c8f26c866284d7f35892043a4b6
3
+ metadata.gz: b44cf8eaed214e39d9bd3078cf7d5144d8664df13619b95686dcfe77c9c44fa1
4
+ data.tar.gz: eba61f25b74ffd67e04e45504d7479ff10910b6a155428f94d7ed13aa70456d0
5
5
  SHA512:
6
- metadata.gz: 66ee90ceda7582b79b2ffc905f875422ad7122a3a9a29c589b9df2bd63417ee81c94f6fa66c2d26568ff8cb01e835c8dcc30e4e7970e6ece174376941f07ac39
7
- data.tar.gz: c75546cc4a3ea671b22ccf685fba84a2767f3d0ac2e652b214f144eb28ea0a284b8f38198596b03c487f81d49bea0e447ea608b0deeaf42bf2f19d46a3fcae5a
6
+ metadata.gz: d01e4d56cb7cf5fa40ab2f383ff902b6d343c02741fc4be0ac2217d12b22c0a882dc665f291f6988e9b1abd3fdd663f842aa57be250778c6140f65235527fb96
7
+ data.tar.gz: fc19367420ea452a08aaf2505cd85b74830823902a0de8696f77f6aec0a6cb9a77ea897ee11522b754f777f1c7e4590f3b3134b0094159801429472e562ef73e
@@ -1,4 +1,8 @@
1
- ## Upcoming Changes
1
+ ## Capybara Test Helpers 1.0.2 (2020-11-23) ##
2
+
3
+ * Add `aliases` DSL to define `SELECTORS`.
4
+
5
+ ## Capybara Test Helpers 1.0.1 (2020-11-19) ##
2
6
 
3
7
  * Add `has?` alias for `has_selector?`.
4
8
  * Delegate `have` to the RSpec collection matcher when passing an Integer.
data/README.md CHANGED
@@ -1,21 +1,6 @@
1
- <h1 align="center">
2
- Capybara Test Helpers
3
- <p align="center">
4
- <a href="https://github.com/ElMassimo/capybara_test_helpers/actions"><img alt="Build Status" src="https://github.com/ElMassimo/capybara_test_helpers/workflows/build/badge.svg"/></a>
5
- <a href="https://codeclimate.com/github/ElMassimo/capybara_test_helpers"><img alt="Maintainability" src="https://codeclimate.com/github/ElMassimo/capybara_test_helpers/badges/gpa.svg"/></a>
6
- <a href="https://codeclimate.com/github/ElMassimo/capybara_test_helpers"><img alt="Test Coverage" src="https://codeclimate.com/github/ElMassimo/capybara_test_helpers/badges/coverage.svg"/></a>
7
- <a href="https://rubygems.org/gems/capybara_test_helpers"><img alt="Gem Version" src="https://img.shields.io/gem/v/capybara_test_helpers.svg?colorB=e9573f"/></a>
8
- <a href="https://github.com/ElMassimo/capybara_test_helpers/blob/master/LICENSE.txt"><img alt="License" src="https://img.shields.io/badge/license-MIT-428F7E.svg"/></a>
9
- </p>
10
- </h1>
11
-
12
- [__Capybara Test Helpers__](https://github.com/ElMassimo/capybara_test_helpers) is
13
- an opinionated library built on top of [capybara], that encourages good testing
14
- practices based on encapsulation and reuse.
15
-
16
- Write tests that everyone can understand, and leverage your Ruby skills to keep them __easy to read and easy to change__.
17
-
18
1
  [docs]: https://capybara-test-helpers.netlify.app/
2
+ [design patterns]: https://capybara-test-helpers.netlify.app/guide/advanced/design-patterns
3
+ [installation]: https://capybara-test-helpers.netlify.app/installation
19
4
  [capybara]: https://github.com/teamcapybara/capybara
20
5
  [capybara dsl]: https://github.com/teamcapybara/capybara#the-dsl
21
6
  [capybara querying]: https://github.com/teamcapybara/capybara#querying
@@ -37,38 +22,36 @@ Write tests that everyone can understand, and leverage your Ruby skills to keep
37
22
  [rails_integration]: https://github.com/ElMassimo/capybara_test_helpers/commit/c512e39987215e30227dad45e775480bc1348325
38
23
  [cucumber_integration]: https://github.com/ElMassimo/capybara_test_helpers/commit/68e20cb40ba409c50f88f8b745eb908fb067a0aa
39
24
 
40
- Check out the [documentation site][docs] for more information.
41
-
42
- ## Why? 🤔
43
-
44
- [`capybara`][capybara] is a great library for integration tests in Ruby,
45
- commonly used in combination with [RSpec] or [cucumber].
46
-
47
- Although [cucumber] encourages good practices such as writing steps at a high
48
- level, thinking in terms of the user rather than the interactions required, it
49
- __doesn't scale well__ in a large project. Steps are available for all tests,
50
- and there's no way to partition or isolate them.
51
-
52
- At the same time, Gherkin is very limited as a language, it can be very awkward
53
- to use when steps require parameters, and it's hard to find and detect duplicate
54
- steps, and very __time consuming__ to refactor them.
25
+ <h1 align="center">
26
+ Capybara Test Helpers
27
+ <p align="center">
28
+ <a href="https://github.com/ElMassimo/capybara_test_helpers/actions">
29
+ <img alt="Build Status" src="https://github.com/ElMassimo/capybara_test_helpers/workflows/build/badge.svg"/>
30
+ </a>
31
+ <a href="https://codeclimate.com/github/ElMassimo/capybara_test_helpers">
32
+ <img alt="Maintainability" src="https://codeclimate.com/github/ElMassimo/capybara_test_helpers/badges/gpa.svg"/>
33
+ </a>
34
+ <a href="https://codeclimate.com/github/ElMassimo/capybara_test_helpers">
35
+ <img alt="Test Coverage" src="https://codeclimate.com/github/ElMassimo/capybara_test_helpers/badges/coverage.svg"/>
36
+ </a>
37
+ <a href="https://rubygems.org/gems/capybara_test_helpers">
38
+ <img alt="Gem Version" src="https://img.shields.io/gem/v/capybara_test_helpers.svg?colorB=e9573f"/>
39
+ </a>
40
+ <a href="https://github.com/ElMassimo/capybara_test_helpers/blob/master/LICENSE.txt">
41
+ <img alt="License" src="https://img.shields.io/badge/license-MIT-428F7E.svg"/>
42
+ </a>
43
+ </p>
44
+ </h1>
55
45
 
56
- In contrast, writing tests in [RSpec] has a very low barrier since Ruby is a joy
57
- to work with, but you are on your own to encapsulate code to avoid coupling
58
- tests to the current UI. Small changes to the UI should not require rewriting
59
- dozens of tests, but __without clear guidelines__ it's hard to achieve good tests.
46
+ [__Capybara Test Helpers__](https://github.com/ElMassimo/capybara_test_helpers) is
47
+ an opinionated library built on top of [capybara], that encourages good testing
48
+ practices based on encapsulation and reuse.
60
49
 
61
- This library provides __a solid foundation__ of simple and repeatable patterns
62
- that can be used to write better tests.
50
+ Write tests that everyone can understand, and leverage your Ruby skills to keep them __easy to read and easy to change__.
63
51
 
64
- ## Features ⚡️
52
+ ## Documentation 📖
65
53
 
66
- - Leverage your __Ruby__ skills for keeping tests in good shape
67
- - Powerful syntax for __assertions__ (without monkey patching)
68
- - __Aliases__ for element locators to avoid repetition
69
- - __Composability__: define interactions with your UI once, and [focus on the tests][testing robots] many times
70
- - Dependency injection to make tests __predictable and robust__
71
- - Full access to the __[Capybara DSL]__
54
+ [Visit the documentation website][docs] to check out the guides, API reference, and examples.
72
55
 
73
56
  ## Installation 💿
74
57
 
@@ -78,325 +61,66 @@ Add this line to your application's Gemfile:
78
61
  gem 'capybara_test_helpers'
79
62
  ```
80
63
 
81
- And then run:
82
-
83
- $ bundle install
84
-
85
- ### RSpec
86
-
87
- To use with [RSpec], require the following in `spec_helper.rb`:
64
+ To use with [RSpec], add the following to your `spec_helper.rb`:
88
65
 
89
66
  ```ruby
90
67
  require 'capybara_test_helpers/rspec'
91
68
  ```
92
69
 
93
- #### In Rails
94
-
95
- If using Rails, make sure you [follow the setup in `rspec-rails`][rspec-rails] first.
96
-
97
- You can run `rails g test_helper base` to create a base test helper and require
98
- it as well so that other test helpers can extend it without manually requiring.
99
-
100
- ```ruby
101
- # spec/rails_helper.rb
102
- require 'capybara_test_helpers/rspec'
103
- require Rails.root.join('test_helpers/base_test_helper')
104
- ```
105
-
106
- [Check this example][rails_integration] to see how you can get started.
107
-
108
- ### Cucumber
109
-
110
- To use with [Cucumber], require the following in `env.rb`:
70
+ To use with [Cucumber], add the following to your `support/env.rb`:
111
71
 
112
72
  ```ruby
113
73
  require 'capybara_test_helpers/cucumber'
114
- require Rails.root.join('test_helpers/base_test_helper')
115
74
  ```
116
75
 
117
- Have in mind that RSpec is a much better fit, as Gherkin is very limited.
118
-
119
- That said, test helpers do provide [a nice way to share code](https://github.com/ElMassimo/capybara_test_helpers/blob/master/examples/rails_app/features/step_definitions/city_steps.rb) if you are migrating
120
- from Cucumber to RSpec.
121
-
122
- [Check this example][cucumber_integration] to see how you can get started.
76
+ Additional installation instructions are available in the [documentation website][installation].
123
77
 
124
- ## Usage 🚀
78
+ ## Quick Tour ⚡️
125
79
 
126
- You can define a test helper by subclassing `Capybara::TestHelper`, which has
127
- full access to the Capybara DSL.
80
+ Let's say we have a list of cities, and we want to test the _Edit_ functionality using [Capybara].
128
81
 
129
82
  ```ruby
130
- class CitiesTestHelper < Capybara::TestHelper
131
- use_test_helpers(:form, :table)
83
+ scenario 'editing a city' do
84
+ visit('/cities')
132
85
 
133
- # Selectors: Semantic aliases for elements, a useful abstraction.
134
- SELECTORS = {
135
- el: 'table.cities',
86
+ within('.cities') {
87
+ find(:table_row, { 'Name' => 'NYC' }).click_on('Edit')
136
88
  }
89
+ fill_in 'Name', with: 'New York City'
90
+ click_on('Update City')
137
91
 
138
- # Getters: A convenient way to get related data or nested elements.
139
- def row_for(city)
140
- within { table.row_for(city.name) }
141
- end
142
-
143
- # Actions: Encapsulate complex actions to provide a cleaner interface.
144
- def add(**args)
145
- click_on('New City')
146
- save_city(**args)
147
- yield(form) if block_given?
148
- end
149
-
150
- def edit(city, with:)
151
- row_for(city).click_on('Edit')
152
- save_city(**with)
153
- end
154
-
155
- def delete(city)
156
- accept_confirm { row_for(city).click_on('Destroy') }
157
- end
158
-
159
- private \
160
- def save_city(name:)
161
- form.within {
162
- fill_in 'Name', with: name
163
- form.save
164
- }
165
- end
166
-
167
- # Assertions: Check on element properties, used with `should` and `should_not`.
168
- def have_city(name)
169
- within { have(:table_row, { 'Name' => name }) }
170
- end
171
-
172
- # Background: Helpers to add/modify/delete data in the database or session.
173
- def given_there_is_a_city(name)
174
- City.create!(name: name)
175
- end
176
- end
177
- ```
178
-
179
- When using Rails, you can generate a test helper by running:
180
-
181
- $ rails g test_helper users
182
-
183
- ### Writing a Test with Helpers ✅
184
-
185
- You can find [this working example](https://github.com/ElMassimo/capybara_test_helpers/blob/master/examples/rails_app/spec/system/cities_spec.rb) and more in the [example app] and the [Capybara tests][capybara_test_helpers_tests].
186
-
187
- ```ruby
188
- require 'rails_helper'
189
-
190
- RSpec.describe 'Cities', test_helpers: [:cities] do
191
- let!(:nyc) { cities.given_there_is_a_city('NYC') }
192
-
193
- before { cities.visit_page }
194
-
195
- scenario 'valid inputs' do
196
- cities.add(name: 'Minneapolis')
197
- cities.should.have_city('Minneapolis')
198
- end
199
-
200
- scenario 'invalid inputs' do
201
- cities.add(name: '') { |form|
202
- form.should.have_error("Name can't be blank")
203
- }
204
- end
205
-
206
- scenario 'editing a city' do
207
- cities.edit(nyc, with: { name: 'New York City' })
208
- cities.should_no_longer.have_city('NYC')
209
- cities.should_now.have_city('New York City')
210
- end
211
-
212
- scenario 'deleting a city', screen_size: :phone do
213
- cities.delete(nyc)
214
- cities.should_no_longer.have_city('NYC')
215
- end
216
- end
217
- ```
218
-
219
- To make the test helper available you can use the [`test_helpers` option][rspec_injection]
220
- in a `describe`, `context` or `scenario` as seen above.
221
-
222
- When using Cucumber, you may call [`use_test_helpers`][cucumber_injection] in the step definitions.
223
-
224
- Finally, for test helpers that you expect to use very often, you can [`use_test_helpers`][rspec_global_injection] in an RSpec helper module to make them available globally.
225
-
226
- ## DSL 🛠
227
-
228
- A [documentation website][docs] with the full API and examples is [now available][docs] :shipit:
229
-
230
- Every single method in the [Capybara DSL] is available inside test helpers, as
231
- well as the [built-in RSpec matchers][rspec matchers].
232
-
233
- ### Selectors 🔍
234
-
235
- You can encapsulate locators for commonly used elements to avoid hardcoding them
236
- in different tests.
237
-
238
- As a result, if the UI changes there are less places that need to be updated in
239
- the tests 😃
240
-
241
- ```ruby
242
- class FormTestHelper < BaseTestHelper
243
- SELECTORS = {
244
- el: '.form',
245
- error_summary: ['#error_explanation', visible: true],
246
- name_input: [:fillable_field, 'Name'],
247
- save_button: [:button, type: 'submit'],
92
+ within('.cities') {
93
+ expect(page).not_to have_selector(:table_row, { 'Name' => 'NYC' })
94
+ expect(page).to have_selector(:table_row, { 'Name' => 'New York City' })
248
95
  }
96
+ end
249
97
  ```
250
98
 
251
- You can then leverage these aliases on any Capybara method:
252
-
253
- ```ruby
254
- # Finding an element
255
- form.find(:save_button, visible: false)
256
-
257
- # Interacting with an element
258
- form.fill_in(:name_input, with: 'Jane')
259
-
260
- # Making an assertion
261
- form.has_selector?(:error_summary, text: "Can't be blank")
262
- ```
263
-
264
- #### Syntax Sugar
265
-
266
- To avoid repetition, getters are available for every selector alias:
267
-
268
- ```ruby
269
- form.find(:name_input)
270
- # same as
271
- form.name_input
272
-
273
- form.find(:error_summary, text: "Can't be blank")
274
- # same as
275
- form.error_summary(text: "Can't be blank")
276
- ```
277
-
278
- #### `:el` convention
279
-
280
- By convention, `:el` is the top-level element of the component or page the test
281
- helper is encapsulating, which will be used automatically when calling a
282
- Capybara operation that requires a node, such as `click` or `value`.
283
-
284
- ```ruby
285
- form.within { save_button.click }
286
- # same as
287
- form.within(:el) { save_button.click }
288
- # same as
289
- form.el.within { save_button.click }
290
- ```
291
-
292
- ### Assertions ☑️
293
-
294
- You can use any of the [RSpec matchers provided by Capybara][capybara querying],
295
- but the way to use them in test helpers is slightly different.
296
-
297
- Before using an assertion, you must call [`should`][should] or [`should_not`][should_not], and then
298
- chain the RSpec matcher or your own custom assertion.
299
-
300
- ```ruby
301
- users.find(:table)
302
- .should.have_selector(:table_row, ['Jane', 'Doe']
303
- .should_not.have_selector(:table_row, ['John', 'Doe'])
304
- ```
305
-
306
- #### Custom Assertions 🎩
99
+ Even though it gets the job done, it takes a while to understand what the test is trying to do.
307
100
 
308
- The example above becomes a lot nicer if we define a more semantic assertion,
309
- which can be easily done by leveraging an existing assertion:
310
-
311
- ```ruby
312
- class UsersTestHelper < BaseTestHelper
313
- SELECTORS = {
314
- list: 'table.users',
315
- }
101
+ Without discipline these tests can become __hard to manage__ and require __frequent updating__.
316
102
 
317
- # Assertions: Check on element properties, used with `should` and `should_not`.
318
- def have_user(*names)
319
- have(:table_row, names)
320
- end
321
- ```
103
+ ### Using Test Helpers
322
104
 
323
- and then use it as:
105
+ We can avoid the duplication and keep the [focus on the test][design patterns] instead of its
106
+ implementation by using [__test helpers__][docs].
324
107
 
325
108
  ```ruby
326
- users.list
327
- .should.have_user('Jane', 'Doe')
328
- .should_not.have_user('John', 'Doe')
329
- ```
330
-
331
- Notice that you don't need to define both the [positive and negative assertions],
332
- they are both available because we are using an existing assertion.
333
-
334
- #### Advanced Assertions ⚙️
109
+ scenario 'editing a city', test_helpers: [:cities] do
110
+ cities.visit_page
335
111
 
336
- Sometimes built-in assertions are not enough, and you need to use an expectation
337
- directly. Test helpers provide [`to_or` and `not_to` methods][positive and negative assertions] that you
338
- can use to implement an assertion that you can use with `should` or `should_not`.
112
+ cities.edit('NYC', with: { name: 'New York City' })
339
113
 
340
- ```ruby
341
- class CurrentPageTestHelper < BaseTestHelper
342
- # Getters: A convenient way to get related data or nested elements.
343
- def fullscreen?
344
- evaluate_script('!!(document.mozFullScreenElement || document.webkitFullscreenElement)')
345
- end
346
-
347
- # Assertions: Allow to check on element properties while keeping it DRY.
348
- def be_fullscreen
349
- expect(fullscreen?).to_or not_to, eq(true)
350
- end
114
+ cities.should_no_longer.have_city('NYC')
115
+ cities.should_now.have_city('New York City')
351
116
  end
352
-
353
- current_page.should.be_fullscreen
354
- current_page.should_not.be_fullscreen
355
- ```
356
-
357
- You can make the assertion retry automatically until the Capybara timeout by
358
- using `synchronize_expectation`:
359
-
360
- ```ruby
361
- def be_fullscreen
362
- synchronize_expectation {
363
- expect(fullscreen?).to_or not_to, eq(true)
364
- }
365
- end
366
- ```
367
-
368
- ## Design 📐
369
-
370
- This library is loosely based on the concepts of [Page Objects][page_objects] and [Testing Robots][testing_robots], with a healthy dose of [dependency injection](https://martinfowler.com/articles/injection.html).
371
-
372
- Capybara has a great DSL, so the focus of this library is to build upon it, by
373
- allowing you to create your own actions and assertions and call them just as
374
- fluidly as you would call `find` or `has_content?`.
375
-
376
- This library works best when encapsulating common UI patterns in separate helpers,
377
- such as a `FormTestHelper` or a `DropdownTestHelper`, and then reusing them in
378
- page-specific test helpers to make the test read more semantically.
379
-
380
- ## Formatting 📏
381
-
382
- Regarding selectors, I highly recommend writing one attribute per line, sorting
383
- them alphabetically (most editors can do it for you), and
384
- [always using a trailing comma][trailing_commas].
385
-
386
- ```ruby
387
- class DropdownTestHelper < BaseTestHelper
388
- # Selectors: Semantic aliases for elements, a useful abstraction.
389
- SELECTORS = {
390
- el: '.dropdown',
391
- toggle: '.dropdown-toggle',
392
- }
393
117
  ```
394
118
 
395
- It will minimize the amount of git conflicts, and keep the history a lot cleaner and more meaningful when using `git blame`.
119
+ Learn more about it in the [documentation website][docs].
396
120
 
397
121
  ## Special Thanks 🙏
398
122
 
399
- This library wouldn't be the same without the early validation from my colleagues, and numerous improvements and bugfixes they contributed to it. Thanks for the support 😃
123
+ This library wouldn't be the same without early validation from my colleagues, and numerous improvements and bugfixes they contributed to it. Thanks for the support 😃
400
124
 
401
125
  - [capybara]: Solid library to write integration tests in Ruby.
402
126
 
@@ -40,6 +40,11 @@ module CapybaraTestHelpers::Selectors
40
40
  end
41
41
 
42
42
  module ClassMethods
43
+ # Public: Light wrapper as syntax sugar for defining SELECTORS.
44
+ def aliases(selectors = {})
45
+ const_set('SELECTORS', selectors)
46
+ end
47
+
43
48
  # Public: Returns the available selectors for the test helper, or an empty
44
49
  # Hash if selectors are not defined.
45
50
  def selectors
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Easily write fluent Page Objects for Capybara in Ruby.
4
4
  module CapybaraTestHelpers
5
- VERSION = '1.0.1'
5
+ VERSION = '1.0.2'
6
6
  end
@@ -5,16 +5,22 @@ require 'rails/generators/named_base'
5
5
 
6
6
  # Internal: Generates a new test helper file in the appropriate directory.
7
7
  class TestHelperGenerator < Rails::Generators::NamedBase
8
+ def base_helper?
9
+ file_name.to_s == 'base'
10
+ end
11
+
8
12
  def create_helper_file
9
13
  create_file("#{ CapybaraTestHelpers.config.helpers_paths.first }/#{ file_name }_test_helper.rb") {
10
14
  <<~CAPYBARA_TEST_HELPER
11
15
  # frozen_string_literal: true
12
16
 
13
- class #{ file_name.camelize }TestHelper < #{ file_name.to_s == 'base' ? 'Capybara::TestHelper' : 'BaseTestHelper' }
14
- # Selectors: Semantic aliases for elements, a useful abstraction.
15
- SELECTORS = {}
17
+ class #{ file_name.camelize }TestHelper < #{ base_helper? ? 'Capybara::TestHelper' : 'BaseTestHelper' }
18
+ # Aliases: Semantic aliases for locators, can be used in most DSL methods.
19
+ aliases(
20
+ #{ base_helper? ? '# Avoid defining :el here since it will be inherited by all helpers.' : "# el: '.#{ file_name.tr('_', '-') }'," }
21
+ )
16
22
 
17
- # Getters: A convenient way to get related data or nested elements.
23
+ # Finders: A convenient way to get related data or nested elements.
18
24
 
19
25
  # Actions: Encapsulate complex actions to provide a cleaner interface.
20
26
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara_test_helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maximo Mussini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-19 00:00:00.000000000 Z
11
+ date: 2020-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport