napybara 0.3.0 → 0.3.1
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 +4 -4
- data/README.md +179 -45
- data/lib/napybara/element.rb +2 -2
- data/lib/napybara/version.rb +1 -1
- data/napybara.gemspec +1 -1
- data/spec/integration/readme_spec.rb +172 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c60bfd33a34b3c9225ede612cd2ceaecb644b235
|
4
|
+
data.tar.gz: ed872c87a98a39850a887a9f66e5fdcf5884e143
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 745db690753460d0e8b058f176463fac216f5a335b3abf4409e2229f3f6c3f8c75ea79b5b84f6d8ce204b2134cf7172f6dfc0caef95ad11207df7b1dfdbe245f
|
7
|
+
data.tar.gz: dcde1d036cedd78c9894b01110d6536db00e66a954cd82cd977ac8bcdd4961b535810e5ffb7b51b40c159bacffe8619412266289c486193c19468807d299248c
|
data/README.md
CHANGED
@@ -5,12 +5,12 @@ So you're writing an integration test for the following page:
|
|
5
5
|
```html
|
6
6
|
<html>
|
7
7
|
<body>
|
8
|
-
<ul class='
|
9
|
-
<li class="message">Hello world!</li>
|
10
|
-
<li class="message">Kamusta mundo!</li>
|
8
|
+
<ul class='message-list'>
|
9
|
+
<li class="message" id="message-1">Hello world!</li>
|
10
|
+
<li class="message" id="message-2">Kamusta mundo!</li>
|
11
11
|
</ul>
|
12
12
|
<form class='new-message'>
|
13
|
-
<div class="message" />
|
13
|
+
<div class="message-row" />
|
14
14
|
<label for='message'>Message</label>
|
15
15
|
<input id='message' type='text' name='message'>
|
16
16
|
</div>
|
@@ -19,87 +19,221 @@ So you're writing an integration test for the following page:
|
|
19
19
|
</html>
|
20
20
|
```
|
21
21
|
|
22
|
-
Wouldn't it be nice if
|
22
|
+
Wouldn't it be nice if you can write test helpers so that they followed the page structure?
|
23
23
|
|
24
24
|
```ruby
|
25
25
|
messages_page.visit!
|
26
|
-
|
26
|
+
|
27
|
+
messages_page.form.message_row.text_field.get.set 'Hello World!'
|
27
28
|
messages_page.form.submit!
|
28
|
-
|
29
|
-
expect(messages_page.
|
29
|
+
|
30
|
+
expect(messages_page.message(Message.find(1))).to have_content('Hello world!')
|
31
|
+
expect(messages_page.message(Message.find(2))).to have_content('Kamusta mundo!')
|
32
|
+
|
33
|
+
expect(messages_page.message_items[0]).to have_content('Hello world!')
|
34
|
+
expect(messages_page.message_items[1]).to have_content('Kamusta mundo!')
|
35
|
+
```
|
36
|
+
|
37
|
+
With Napybara, now you can!
|
38
|
+
|
39
|
+
## Napybara::Element.new and #get
|
40
|
+
|
41
|
+
First off, let's wrap the Capybara session in a Napybara element:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
let(:messages_page) do
|
45
|
+
Napybara::Element.new(self)
|
46
|
+
end
|
30
47
|
```
|
31
48
|
|
32
|
-
|
49
|
+
In Rails integration tests which use Capybara, `self` usually is the Capybara session.
|
50
|
+
|
51
|
+
You can get the capybara element wrapped by the Napybara element with
|
52
|
+
`Napybara::Element#get`:
|
33
53
|
|
34
54
|
```ruby
|
35
|
-
|
55
|
+
expect(messages_page.get).to eq(self)
|
56
|
+
```
|
57
|
+
|
58
|
+
## Finding by selector
|
36
59
|
|
37
|
-
|
60
|
+
You can add finders to the Napybara page with `Napybara::Element#finder`:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
let(:messages_page) do
|
38
64
|
Napybara::Element.new(self) do |page|
|
39
|
-
page.finder :
|
65
|
+
page.finder :form, 'form.new-message'
|
66
|
+
end
|
67
|
+
end
|
40
68
|
|
41
|
-
|
42
|
-
form.finder :message, '.message' do |row|
|
43
|
-
row.finder :text_field, 'input#message'
|
44
|
-
end
|
69
|
+
# ...
|
45
70
|
|
46
|
-
|
47
|
-
|
71
|
+
expect(messages_page.form.get['class']).to eq('new-message')
|
72
|
+
```
|
73
|
+
|
74
|
+
## Finding by object
|
75
|
+
|
76
|
+
In Rails, dom elements usually have ids which end with object ids, the objects
|
77
|
+
usually being active records. The method generated by `Napybara::Element#finder`
|
78
|
+
can also accept an object when searching for the object's matching element:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
let(:messages_page) do
|
82
|
+
Napybara::Element.new(self) do |page|
|
83
|
+
page.finder :message, '#message-'
|
48
84
|
end
|
49
85
|
end
|
86
|
+
|
87
|
+
let(:some_message) do
|
88
|
+
Message.find(1)
|
89
|
+
end
|
90
|
+
|
91
|
+
# ...
|
92
|
+
|
93
|
+
expect(messages_page.message(some_message).get['id'])
|
94
|
+
.to eq("messages-#{some_message.id}")
|
95
|
+
|
96
|
+
```
|
97
|
+
|
98
|
+
In the above example, the `message` finder looks for an element matching the
|
99
|
+
given selector (`#message-`) with `some_message`'s id (`1`). So it ends up
|
100
|
+
looking for "#message-1".
|
101
|
+
|
102
|
+
## Calling the finder with or without an object argument
|
103
|
+
|
104
|
+
As you may have observed, the finder added by `Napybara::Element#finder`
|
105
|
+
can be called with or without an object argument. Usually, you only want to use
|
106
|
+
just one of these two options; the selector you declare will determine what
|
107
|
+
option you want to use. For example, `#message-` only makes sense with an object
|
108
|
+
id at the end of the selector, so you want to call the `messages_page.message()`
|
109
|
+
finder with an object. On the other hand, `form.new-message` does not make sense
|
110
|
+
with an object id at the end of the selector, so you want to call the
|
111
|
+
`messages_page.form()` finder without an object argument.
|
112
|
+
|
113
|
+
## Checking if an element exists
|
114
|
+
|
115
|
+
`Napybara::Element#finder` also adds `has_` and `has_no_` methods to the element.
|
116
|
+
With the Napybara elements above, you can call:
|
117
|
+
|
50
118
|
```
|
119
|
+
expect(messages_page.has_form?).to be_true
|
120
|
+
expect(messages_page).to have_form
|
51
121
|
|
52
|
-
|
122
|
+
expect(messages_page.has_message?(some_message).to be_true
|
123
|
+
expect(messages_page).to have_message(some_message)
|
53
124
|
|
54
|
-
|
125
|
+
non_existent_message = Message.find(3)
|
126
|
+
expect(messages_page.has_no_message?(non_existent_message)).to be_true
|
127
|
+
expect(messages_page).to have_no_message(non_existent_message)
|
128
|
+
```
|
129
|
+
|
130
|
+
Due to the magic that Capybara does when finding elements in a Ajaxified page,
|
131
|
+
it's recommended to call `expect(element).to have_no_...` instead of
|
132
|
+
`expect(element).to_not have...`, since the former relies on Capybara's Ajax-
|
133
|
+
friendly `has_no_css?` method.
|
134
|
+
|
135
|
+
## Finding all elements matching a selector
|
136
|
+
|
137
|
+
Finally, `Napybara::Element#finder` adds a pluralized version of the finder. For example,
|
55
138
|
|
56
139
|
```ruby
|
57
|
-
|
58
|
-
|
59
|
-
|
140
|
+
let(:messages_page) do
|
141
|
+
Napybara::Element.new(self) do |page|
|
142
|
+
page.finder :message_item, '.message'
|
60
143
|
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# ...
|
147
|
+
|
148
|
+
expect(messages_page.message_items[0].get.text).to eq("Hello world!")
|
149
|
+
expect(messages_page.message_items[1].get.text).to eq("Kamusta mundo!")
|
150
|
+
```
|
151
|
+
|
152
|
+
Napybara uses ActiveSupport to get the plural version of the finder name.
|
153
|
+
|
154
|
+
## Adding custom methods to a Napybara element
|
61
155
|
|
62
|
-
|
156
|
+
We can add new methods to a Napybara element with plain Ruby:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
let(:messages_page) do
|
160
|
+
Napybara::Element.new(self) do |page|
|
161
|
+
def page.visit!
|
162
|
+
get.visit get.messages_path
|
163
|
+
end
|
164
|
+
end
|
63
165
|
end
|
166
|
+
|
167
|
+
# ...
|
168
|
+
|
169
|
+
messages_page.visit!
|
64
170
|
```
|
65
171
|
|
66
|
-
|
172
|
+
## Extending a Napybara element with a module
|
67
173
|
|
68
|
-
|
174
|
+
Adding the same methods to multiple Napybara elements? You can share the methods in a module:
|
69
175
|
|
70
176
|
```ruby
|
71
|
-
module
|
72
|
-
def
|
73
|
-
|
177
|
+
module PageExtensions
|
178
|
+
def visit!
|
179
|
+
get.visit get.messages_path
|
180
|
+
@visited = true
|
181
|
+
end
|
182
|
+
|
183
|
+
def visited?
|
184
|
+
!! @visited
|
74
185
|
end
|
75
186
|
end
|
76
187
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
# ...
|
188
|
+
let(:messages_page) do
|
189
|
+
Napybara::Element.new(capybara_page) do |page|
|
190
|
+
page.extend PageExtensions
|
81
191
|
end
|
82
192
|
end
|
193
|
+
|
194
|
+
# ...
|
195
|
+
|
196
|
+
messages_page.visit!
|
197
|
+
expect(messages_page).to be_visited
|
83
198
|
```
|
84
199
|
|
85
|
-
##
|
200
|
+
## Putting it all together
|
86
201
|
|
87
|
-
|
202
|
+
Oh yeah, the "N" in Napybara stands for nesting. Here's how you can define the
|
203
|
+
helpers at the start of this README:
|
88
204
|
|
89
|
-
|
205
|
+
```ruby
|
206
|
+
let(:messages_page) do
|
207
|
+
Napybara::Element.new(capybara_page) do |page|
|
208
|
+
def page.visit!
|
209
|
+
get.visit get.messages_path
|
210
|
+
end
|
90
211
|
|
91
|
-
|
212
|
+
page.finder :form, 'form.new-message' do |form|
|
213
|
+
def form.submit!
|
214
|
+
submit_button.get.click
|
215
|
+
end
|
92
216
|
|
93
|
-
|
217
|
+
form.finder :message_row, '.message-row' do |row|
|
218
|
+
row.finder :text_field, 'input[type=text]'
|
219
|
+
end
|
94
220
|
|
95
|
-
|
221
|
+
form.finder :submit_button, 'input[type=submit]'
|
222
|
+
end
|
223
|
+
|
224
|
+
page.finder :message, '.message-list #message-'
|
225
|
+
page.finder :message_item, '.message-list .message'
|
226
|
+
end
|
227
|
+
end
|
228
|
+
```
|
96
229
|
|
97
|
-
|
230
|
+
## Installation
|
231
|
+
|
232
|
+
```
|
233
|
+
$ gem install Napybara
|
234
|
+
```
|
98
235
|
|
99
236
|
## Contributing
|
100
237
|
|
101
|
-
|
102
|
-
|
103
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
104
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
105
|
-
5. Create new Pull Request
|
238
|
+
I'm still looking for ways to improve Napybara's DSL. If you have an idea, a
|
239
|
+
pull request would be awesome :)
|
data/lib/napybara/element.rb
CHANGED
@@ -16,12 +16,12 @@ module Napybara
|
|
16
16
|
self.class.new(self.get.find(selector.to_s), &block)
|
17
17
|
end
|
18
18
|
|
19
|
-
self.define_singleton_method("has_#{child_element_name}?") do |record|
|
19
|
+
self.define_singleton_method("has_#{child_element_name}?") do |record = nil|
|
20
20
|
selector = Selector.new(child_element_selector, method_name, record)
|
21
21
|
self.get.has_css?(selector.to_s)
|
22
22
|
end
|
23
23
|
|
24
|
-
self.define_singleton_method("has_no_#{child_element_name}?") do |record|
|
24
|
+
self.define_singleton_method("has_no_#{child_element_name}?") do |record = nil|
|
25
25
|
selector = Selector.new(child_element_selector, method_name, record)
|
26
26
|
self.get.has_no_css?(selector.to_s)
|
27
27
|
end
|
data/lib/napybara/version.rb
CHANGED
data/napybara.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["gsmendoza@gmail.com"]
|
11
11
|
spec.summary = %q{napybara == nested capybara}
|
12
12
|
spec.description = %q{DSL for nesting capybara helpers}
|
13
|
-
spec.homepage = ""
|
13
|
+
spec.homepage = "https://github.com/gsmendoza/napybara"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dummy_app/dummy_app'
|
3
|
+
|
4
|
+
describe 'Readme example:' do
|
5
|
+
let(:capybara_page) do
|
6
|
+
Capybara.string <<-HTML
|
7
|
+
<html>
|
8
|
+
<body>
|
9
|
+
<ul class='messages-list'>
|
10
|
+
<li class="message" id="message-1">Hello world!</li>
|
11
|
+
<li class="message" id="message-2">Kamusta mundo!</li>
|
12
|
+
</ul>
|
13
|
+
<form class='new-message'>
|
14
|
+
<div class="message-row" />
|
15
|
+
<label for='message'>Message</label>
|
16
|
+
<input id='message' type='text' name='message'>
|
17
|
+
</div>
|
18
|
+
<input type='submit' value='Send'/>
|
19
|
+
</form>
|
20
|
+
</html>
|
21
|
+
HTML
|
22
|
+
end
|
23
|
+
|
24
|
+
Steps "Wrapping a page in a Napybara element" do
|
25
|
+
Given "I have a capybara page" do
|
26
|
+
capybara_page
|
27
|
+
end
|
28
|
+
|
29
|
+
When "I wrap that capybara page in a Napybara page" do
|
30
|
+
@messages_page = Napybara::Element.new(capybara_page)
|
31
|
+
end
|
32
|
+
|
33
|
+
And "I call #get on the Napybara page" do
|
34
|
+
@get_result = @messages_page.get
|
35
|
+
end
|
36
|
+
|
37
|
+
Then "I should get the capybara page" do
|
38
|
+
expect(@get_result).to eq(capybara_page)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Steps 'Find by selector' do
|
43
|
+
Given "I have a capybara page" do
|
44
|
+
capybara_page
|
45
|
+
end
|
46
|
+
|
47
|
+
When "I add a finder to the Napybara page wrapping the capybara page" do
|
48
|
+
@messages_page = Napybara::Element.new(capybara_page) do |page|
|
49
|
+
page.finder :form, 'form.new-message'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Then "the finder should be able to find the element matching the selector" do
|
54
|
+
|
55
|
+
expect(@messages_page.form.get['class']).to eq('new-message')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Steps 'Find by object' do
|
60
|
+
Given "I have a capybara page" do
|
61
|
+
capybara_page
|
62
|
+
end
|
63
|
+
|
64
|
+
When "I add an object finder to the Napybara page wrapping the capybara page" do
|
65
|
+
@messages_page = Napybara::Element.new(capybara_page) do |page|
|
66
|
+
page.finder :message, '#message-'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
Then "the finder should be able to find the element matching a given object" do
|
71
|
+
id = 1
|
72
|
+
message = OpenStruct.new(id: id)
|
73
|
+
expect(@messages_page.message(message).get['id']).to eq("message-#{id}")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Steps 'Existence finders' do
|
78
|
+
Given "I have a capybara page" do
|
79
|
+
capybara_page
|
80
|
+
end
|
81
|
+
|
82
|
+
When "I add finders to the Napybara page wrapping the capybara page" do
|
83
|
+
@messages_page = Napybara::Element.new(capybara_page) do |page|
|
84
|
+
page.finder :form, 'form.new-message'
|
85
|
+
page.finder :message, '#message-'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Then "I can check for the existence of elements" do
|
90
|
+
expect(@messages_page.has_form?).to be_true
|
91
|
+
expect(@messages_page).to have_form
|
92
|
+
|
93
|
+
some_message = OpenStruct.new(id: 1)
|
94
|
+
expect(@messages_page.has_message?(some_message)).to be_true
|
95
|
+
expect(@messages_page).to have_message(some_message)
|
96
|
+
|
97
|
+
non_existent_message = OpenStruct.new(id: 3)
|
98
|
+
expect(@messages_page.has_no_message?(non_existent_message)).to be_true
|
99
|
+
expect(@messages_page).to have_no_message(non_existent_message)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
Steps 'Find all by selector' do
|
104
|
+
Given "I have a capybara page" do
|
105
|
+
capybara_page
|
106
|
+
end
|
107
|
+
|
108
|
+
When "I add a plain finder to the Napybara page wrapping the capybara page" do
|
109
|
+
@messages_page = Napybara::Element.new(capybara_page) do |page|
|
110
|
+
page.finder :message_item, '.message'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
Then "I should be able to find all the elements matching the selector with
|
115
|
+
a plural version of the finder name" do
|
116
|
+
|
117
|
+
expect(@messages_page.message_items[0].get.text).to eq("Hello world!")
|
118
|
+
expect(@messages_page.message_items[1].get.text).to eq("Kamusta mundo!")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
Steps "Adding a custom method to the Napybara element" do
|
123
|
+
Given "I have a capybara page" do
|
124
|
+
capybara_page
|
125
|
+
end
|
126
|
+
|
127
|
+
When "I add a custom method to the Napybara element wrapping the capybara
|
128
|
+
element" do
|
129
|
+
@messages_page = Napybara::Element.new(capybara_page) do |page|
|
130
|
+
def page.visit!
|
131
|
+
@visited = true
|
132
|
+
end
|
133
|
+
|
134
|
+
def page.visited?
|
135
|
+
!! @visited
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
Then "I can call the custom method on the Napybara element" do
|
141
|
+
@messages_page.visit!
|
142
|
+
expect(@messages_page).to be_visited
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
Steps "Extending the Napybara element with a module" do
|
147
|
+
Given "I have a capybara page" do
|
148
|
+
capybara_page
|
149
|
+
end
|
150
|
+
|
151
|
+
When "I extend the Napybara element with a module" do
|
152
|
+
module PageExtensions
|
153
|
+
def visit!
|
154
|
+
@visited = true
|
155
|
+
end
|
156
|
+
|
157
|
+
def visited?
|
158
|
+
!! @visited
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
@messages_page = Napybara::Element.new(capybara_page) do |page|
|
163
|
+
page.extend PageExtensions
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
Then "I can call the custom methods in the module on the Napybara element" do
|
168
|
+
@messages_page.visit!
|
169
|
+
expect(@messages_page).to be_visited
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: napybara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- George Mendoza
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -205,9 +205,10 @@ files:
|
|
205
205
|
- spec/dummy_app/public/new_content.html
|
206
206
|
- spec/dummy_app/public/test.html
|
207
207
|
- spec/integration/napybara_spec.rb
|
208
|
+
- spec/integration/readme_spec.rb
|
208
209
|
- spec/napybara/element_spec.rb
|
209
210
|
- spec/spec_helper.rb
|
210
|
-
homepage:
|
211
|
+
homepage: https://github.com/gsmendoza/napybara
|
211
212
|
licenses:
|
212
213
|
- MIT
|
213
214
|
metadata: {}
|
@@ -238,5 +239,6 @@ test_files:
|
|
238
239
|
- spec/dummy_app/public/new_content.html
|
239
240
|
- spec/dummy_app/public/test.html
|
240
241
|
- spec/integration/napybara_spec.rb
|
242
|
+
- spec/integration/readme_spec.rb
|
241
243
|
- spec/napybara/element_spec.rb
|
242
244
|
- spec/spec_helper.rb
|