capybara_test_helpers 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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