with_form 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +196 -0
- data/db/migrate/20200310042146_create_widget_records.rb +1 -1
- data/lib/with_form/engine.rb +18 -0
- data/lib/with_form/model_form.rb +8 -0
- data/lib/with_form/scope_form.rb +39 -3
- data/lib/with_form/translation_helpers.rb +11 -0
- data/lib/with_form/version.rb +1 -1
- metadata +20 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a78f39980ba03659bd61b33c94e65e8987dc590647ba8870271141a879eafca
|
4
|
+
data.tar.gz: ad43310ff4fd4a42ddb3f154af5c9e799f1a25c82dafdd46c9d18a6f41f48304
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a300ce3b20953400496bc7b7cf09e0bb9206870526c8d63cfb6987db7537ffe702788cd1543ad9eb28f83b99ac44bb39063b628be3677eac73069874a0bdbd6
|
7
|
+
data.tar.gz: b596e4300be6ac53de36e9e81e85514722d1763f3c877ed82aa1b5b38a04adb8d02995d625d89eb800a07938f42343a76d565aa62c0523e338e16845aa675e95
|
data/README.md
CHANGED
@@ -7,6 +7,8 @@ Your System Test's counterpart to `form_with`
|
|
7
7
|
Leverage Rails-generated `<label>` values to submit `<form>` elements in System
|
8
8
|
Tests.
|
9
9
|
|
10
|
+
### The `with_form` test helper
|
11
|
+
|
10
12
|
To add coverage to a form's fields that are generated by ActionView's
|
11
13
|
`form_with` helper, fill them using `with_form`:
|
12
14
|
|
@@ -60,6 +62,29 @@ The `with_form` helper method accepts two styles of options:
|
|
60
62
|
|
61
63
|
* `scope:` - the internationalization scope key to use when translating Capybara's
|
62
64
|
locator values
|
65
|
+
|
66
|
+
When submitting a `<form>` through a call to `form.click_button`, you can pass
|
67
|
+
an `action` as the translation scope. A `with_form(scope:)` call will default
|
68
|
+
to the `submit` key when one is not specified. For instance:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
form_with(scope: :post) do |form|
|
72
|
+
form.click_button
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
This call will search for an `<input type="text">` or `<button>` whose `value`
|
77
|
+
or text content is the String translated by the `helpers.submit.post.submit`
|
78
|
+
key.
|
79
|
+
|
80
|
+
That action can be overridden:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
form_with(scope: :post) do |form|
|
84
|
+
form.click_button :create
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
63
88
|
* `model:` - an instance of an `ActiveModel::Model` or `ActiveRecord::Base` to
|
64
89
|
be used to translate Capybara's locator values, and to populate the fields
|
65
90
|
with an attribute's value.
|
@@ -97,9 +122,65 @@ The `with_form` helper method accepts two styles of options:
|
|
97
122
|
`"New Title"`) will take precedence over the `post.title` attribute's value
|
98
123
|
(in this case, `"Old Title"`).
|
99
124
|
|
125
|
+
When submitting a `<form>` through a call to `form.click_button`, you can pass
|
126
|
+
an `action` as the translation scope. A `with_form(model:)` call will
|
127
|
+
determine the translation key based on [the `model`
|
128
|
+
argument's persistence state][persisted].
|
129
|
+
|
130
|
+
When a `model` instance is a new record, the key will use `create`. For
|
131
|
+
instance:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
post = Post.new
|
135
|
+
|
136
|
+
form_with(model: post) do |form|
|
137
|
+
form.click_button
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
This call will search for an `<input type="text">` or `<button>` whose `value`
|
142
|
+
or text content is the String translated by the `helpers.submit.post.create`
|
143
|
+
key.
|
144
|
+
|
145
|
+
That action can be overridden:
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
post = Post.new
|
149
|
+
|
150
|
+
form_with(model: post) do |form|
|
151
|
+
form.click_button :submit
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
155
|
+
When a `model` instance is an existing persisted record, the key will use
|
156
|
+
`update`. For instance:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
post = Post.last
|
160
|
+
|
161
|
+
form_with(model: post) do |form|
|
162
|
+
form.click_button
|
163
|
+
end
|
164
|
+
```
|
165
|
+
|
166
|
+
This call will search for an `<input type="text">` or `<button>` whose `value`
|
167
|
+
or text content is the String translated by the `helpers.submit.post.update`
|
168
|
+
key.
|
169
|
+
|
170
|
+
That action can be overridden:
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
post = Post.last
|
174
|
+
|
175
|
+
form_with(model: post) do |form|
|
176
|
+
form.click_button :submit
|
177
|
+
end
|
178
|
+
```
|
179
|
+
|
100
180
|
[label]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label
|
101
181
|
[input]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
|
102
182
|
[textarea]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
|
183
|
+
[persisted]: https://api.rubyonrails.org/classes/ActiveModel/Model.html#method-i-persisted-3F
|
103
184
|
|
104
185
|
With the exception of `#click_link` and `#click_link_or_button`, the argument
|
105
186
|
yielded to `with_form` supports [all helper methods made available by
|
@@ -118,6 +199,117 @@ Those include:
|
|
118
199
|
|
119
200
|
[actions]: https://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Actions
|
120
201
|
|
202
|
+
#### ActionText `rich_text_area` support
|
203
|
+
|
204
|
+
When [`ActionText`][actiontext] is available, `with_form` provides a
|
205
|
+
`#fill_in_rich_text_area` helper method.
|
206
|
+
|
207
|
+
The current implementation is inspired by
|
208
|
+
`ActionText::SystemTestHelper#fill_in_rich_text_area` that is currently declared
|
209
|
+
on the current [`rails@master` branch][fill_in_rich_text_area].
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
class UserInteractsWithRichTextAreasTest < ApplicationSystemTestCase
|
213
|
+
include WithForm::TestHelpers
|
214
|
+
|
215
|
+
test "makes a post with a scope: argument" do
|
216
|
+
visit new_post_path
|
217
|
+
with_form(scope: :post) do |form|
|
218
|
+
form.fill_in_rich_text_area :body, with: "My First Post"
|
219
|
+
form.click_button
|
220
|
+
end
|
221
|
+
|
222
|
+
assert_text "My First Post"
|
223
|
+
end
|
224
|
+
|
225
|
+
test "user makes a post with a model: argument" do
|
226
|
+
post = Post.new(body: "My First Post")
|
227
|
+
|
228
|
+
visit new_post_path
|
229
|
+
with_form(model: post) do |form|
|
230
|
+
form.fill_in_rich_text_area :body
|
231
|
+
form.click_button
|
232
|
+
end
|
233
|
+
|
234
|
+
assert_text "My First Post"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
There is a current limitation in how the [`rails@master`-inspired
|
240
|
+
`#fill_in_rich_text_area` implementation][fill_in_rich_text_area] resolves the
|
241
|
+
`locator` argument. Since the underlying `<trix-editor>` element is not a
|
242
|
+
default field provided by the browser, focussing on its corresponding `<label>`
|
243
|
+
element won't focus the `<trix-editor>`. To resolve that shortcoming, the
|
244
|
+
`#fill_in_rich_text_area` uses the `<trix-editor aria-label="...">` attribute as
|
245
|
+
the label text.
|
246
|
+
|
247
|
+
This is a helpful, but incomplete solution to the problem. This requires that
|
248
|
+
instead of declaring a `<label for="my_rich_text_field">` element
|
249
|
+
referencing the `<trix-editor id="my_rich_text_field">` element, the `<label>`
|
250
|
+
element's text (or rather, the text that _would be_ in the `<label>` element)
|
251
|
+
must be passed to the `<trix-editor aria-label="...">` attribute.
|
252
|
+
|
253
|
+
For example:
|
254
|
+
|
255
|
+
```html+erb
|
256
|
+
<%= form_with(model: Post.new) do |form %>
|
257
|
+
<%= form.label :my_rich_text_field %>
|
258
|
+
<%= form.rich_text_area :my_rich_text_field, "aria-label": translate(:my_rich_text_field, scope: "helpers.label.post") %>
|
259
|
+
<% end %>
|
260
|
+
```
|
261
|
+
|
262
|
+
[actiontext]: https://edgeguides.rubyonrails.org/action_text_overview.html#examples
|
263
|
+
[fill_in_rich_text_area]: https://github.com/rails/rails/blob/339be65d669c83fd4c64541a9e82086dc5e64682/actiontext/lib/action_text/system_test_helper.rb
|
264
|
+
|
265
|
+
### The `label` and `submit` test helpers
|
266
|
+
|
267
|
+
While `with_form` can simplify `<form>` element interactions with multiple
|
268
|
+
steps, there are times when a single line of instructions is more convenient.
|
269
|
+
|
270
|
+
Behind the scenes, `with_form` utilize the `#label` and `#submit` helper
|
271
|
+
methods to translate `<label>` and `<button>` text, along with `<input
|
272
|
+
type="submit">` values.
|
273
|
+
|
274
|
+
To put the same helpers to use within your test, include the
|
275
|
+
`WithForm::TranslationHelpers` module and invoke either:
|
276
|
+
|
277
|
+
* `label(model_name, attribute)`
|
278
|
+
|
279
|
+
* `submit(model_name, action = :submit)`
|
280
|
+
|
281
|
+
For example when clicking an `<input type="checkbox">` labelled by a translation
|
282
|
+
declared at `helpers.label.session.ready`:
|
283
|
+
|
284
|
+
```ruby
|
285
|
+
class UserInteractsWithFormsTest < ApplicationSystemTestCase
|
286
|
+
include WithForm::TranslationHelpers
|
287
|
+
|
288
|
+
test "user ticks a box" do
|
289
|
+
visit new_session_path
|
290
|
+
check label(:session, :ready)
|
291
|
+
|
292
|
+
assert_text "We're glad you're ready, user@example.com."
|
293
|
+
end
|
294
|
+
end
|
295
|
+
```
|
296
|
+
|
297
|
+
Or, to destroy a Post by clicking a button labelled by a translation declared at
|
298
|
+
`helpers.submit.post.destroy`:
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
class UserInteractsWithFormsTest < ApplicationSystemTestCase
|
302
|
+
include WithForm::TranslationHelpers
|
303
|
+
|
304
|
+
test "user deletes a post" do
|
305
|
+
visit new_post_path
|
306
|
+
click_on submit(:post, :destroy)
|
307
|
+
|
308
|
+
assert_text "Deleted Post."
|
309
|
+
end
|
310
|
+
end
|
311
|
+
```
|
312
|
+
|
121
313
|
## Installation
|
122
314
|
|
123
315
|
Add this line to your application's Gemfile:
|
@@ -186,6 +378,10 @@ I've used the [`formulaic` gem][formulaic] before. How is this gem different?
|
|
186
378
|
[form_with]: https://guides.rubyonrails.org/form_helpers.html#dealing-with-basic-forms
|
187
379
|
[rails-i18n]: https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-label
|
188
380
|
|
381
|
+
## Contributing
|
382
|
+
|
383
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
384
|
+
|
189
385
|
## License
|
190
386
|
|
191
387
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/with_form/engine.rb
CHANGED
@@ -1,4 +1,22 @@
|
|
1
1
|
module WithForm
|
2
2
|
class Engine < ::Rails::Engine
|
3
|
+
ActiveSupport.on_load :action_dispatch_system_test_case do
|
4
|
+
Capybara.add_selector :rich_text_area do
|
5
|
+
label "rich-text area"
|
6
|
+
xpath do |locator|
|
7
|
+
if locator.nil?
|
8
|
+
XPath.descendant(:"trix-editor")
|
9
|
+
else
|
10
|
+
input_located_by_name = XPath.anywhere(:input).where(XPath.attr(:name) == locator).attr(:id)
|
11
|
+
|
12
|
+
XPath.descendant(:"trix-editor").where \
|
13
|
+
XPath.attr(:id).equals(locator) |
|
14
|
+
XPath.attr(:placeholder).equals(locator) |
|
15
|
+
XPath.attr(:"aria-label").equals(locator) |
|
16
|
+
XPath.attr(:input).equals(input_located_by_name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
3
21
|
end
|
4
22
|
end
|
data/lib/with_form/model_form.rb
CHANGED
@@ -15,6 +15,14 @@ module WithForm
|
|
15
15
|
)
|
16
16
|
end
|
17
17
|
|
18
|
+
def fill_in_rich_text_area(attribute, with: nil, **options)
|
19
|
+
scope_form.fill_in_rich_text_area(
|
20
|
+
attribute,
|
21
|
+
with: with || @model.public_send(attribute),
|
22
|
+
**options,
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
18
26
|
def attach_file(attribute, path = nil, **options)
|
19
27
|
scope_form.attach_file(
|
20
28
|
attribute,
|
data/lib/with_form/scope_form.rb
CHANGED
@@ -1,18 +1,54 @@
|
|
1
|
+
require "with_form/translation_helpers"
|
2
|
+
|
1
3
|
module WithForm
|
2
4
|
class ScopeForm
|
3
5
|
include ActionView::Helpers::TranslationHelper
|
6
|
+
include WithForm::TranslationHelpers
|
4
7
|
|
5
|
-
delegate :
|
8
|
+
delegate :choose, to: :@page
|
6
9
|
|
7
10
|
def initialize(scope:, page:)
|
8
11
|
@page = page
|
9
12
|
@scope = scope
|
10
13
|
end
|
11
14
|
|
15
|
+
def check(attribute, **options)
|
16
|
+
case attribute
|
17
|
+
when Symbol
|
18
|
+
value = label(attribute)
|
19
|
+
else
|
20
|
+
value = attribute
|
21
|
+
end
|
22
|
+
|
23
|
+
@page.check value, **options
|
24
|
+
end
|
25
|
+
|
26
|
+
def uncheck(attribute, **options)
|
27
|
+
case attribute
|
28
|
+
when Symbol
|
29
|
+
value = label(attribute)
|
30
|
+
else
|
31
|
+
value = attribute
|
32
|
+
end
|
33
|
+
|
34
|
+
@page.uncheck value, **options
|
35
|
+
end
|
36
|
+
|
12
37
|
def fill_in(attribute, with:, **options)
|
13
38
|
@page.fill_in label(attribute), with: with, **options
|
14
39
|
end
|
15
40
|
|
41
|
+
def fill_in_rich_text_area(locator = nil, with:)
|
42
|
+
fill_in_script = <<~JS
|
43
|
+
this.editor.loadHTML(arguments[0])
|
44
|
+
JS
|
45
|
+
|
46
|
+
@page.find(:rich_text_area, label(locator)).execute_script(
|
47
|
+
fill_in_script,
|
48
|
+
with.to_s,
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
16
52
|
def select(value, from:, **options)
|
17
53
|
@page.select value, from: label(from), **options
|
18
54
|
end
|
@@ -30,11 +66,11 @@ module WithForm
|
|
30
66
|
end
|
31
67
|
|
32
68
|
def submit(action = nil)
|
33
|
-
|
69
|
+
super(@scope, action || :submit)
|
34
70
|
end
|
35
71
|
|
36
72
|
def label(attribute)
|
37
|
-
|
73
|
+
super(@scope, attribute)
|
38
74
|
end
|
39
75
|
end
|
40
76
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module WithForm
|
2
|
+
module TranslationHelpers
|
3
|
+
def submit(model_name, action = :submit)
|
4
|
+
translate(action, scope: [:helpers, :submit, model_name])
|
5
|
+
end
|
6
|
+
|
7
|
+
def label(model_name, attribute)
|
8
|
+
translate(attribute, scope: [:helpers, :label, model_name])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/with_form/version.rb
CHANGED
metadata
CHANGED
@@ -1,35 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: with_form
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Doyle
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: railties
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 6.0.2
|
20
17
|
- - ">="
|
21
18
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
19
|
+
version: 5.2.0
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 6.0.2
|
30
24
|
- - ">="
|
31
25
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
26
|
+
version: 5.2.0
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: capybara
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,6 +52,20 @@ dependencies:
|
|
58
52
|
- - ">="
|
59
53
|
- !ruby/object:Gem::Version
|
60
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activerecord
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 5.2.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 5.2.0
|
61
69
|
- !ruby/object:Gem::Dependency
|
62
70
|
name: selenium-webdriver
|
63
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,6 +112,7 @@ files:
|
|
104
112
|
- lib/with_form/model_form.rb
|
105
113
|
- lib/with_form/scope_form.rb
|
106
114
|
- lib/with_form/test_helpers.rb
|
115
|
+
- lib/with_form/translation_helpers.rb
|
107
116
|
- lib/with_form/version.rb
|
108
117
|
homepage: https://github.com/seanpdoyle/with_form
|
109
118
|
licenses:
|