napybara 0.4.1 → 0.5.0
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/.travis.yml +0 -1
- data/CHANGELOG.md +6 -0
- data/README.md +41 -17
- data/lib/napybara.rb +2 -0
- data/lib/napybara/element.rb +20 -24
- data/lib/napybara/element_array.rb +14 -0
- data/lib/napybara/selector.rb +20 -0
- data/lib/napybara/version.rb +1 -1
- data/spec/integration/readme_spec.rb +40 -7
- data/spec/napybara/element_spec.rb +76 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7b2cbbf480b100b3a1adc606cfa57b05868f860
|
4
|
+
data.tar.gz: 2a4ec7daa20873ffb807f49eba6302d4aa9171d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5661e2643515c2fa34eacef4702e1aa577f17f84ee4f02a9d0cf7d7929f544613ad183cc6c1ecf1ef6b78a584958376d634997d415819aa3b85a89794901e5f
|
7
|
+
data.tar.gz: 7eff003cfac47e53c8f476679e123630913f7eb289dc59bf71fbe48063bee022b049b0ddfa805ac35eeaaa05b2ec7d3f72b56735a512eddec629dce7842ca2f6
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Napybara
|
2
2
|
|
3
|
+
[](https://travis-ci.org/gsmendoza/napybara)
|
4
|
+
|
3
5
|
So you're writing an integration test for the following page:
|
4
6
|
|
5
7
|
```html
|
@@ -19,12 +21,13 @@ So you're writing an integration test for the following page:
|
|
19
21
|
</html>
|
20
22
|
```
|
21
23
|
|
22
|
-
Wouldn't it be nice if
|
24
|
+
Wouldn't it be nice if you can write test helpers that followed the page's
|
25
|
+
structure?
|
23
26
|
|
24
27
|
```ruby
|
25
28
|
messages_page.visit!
|
26
29
|
|
27
|
-
messages_page.form.message_row.text_field.
|
30
|
+
messages_page.form.message_row.text_field.node.set 'Hello World!'
|
28
31
|
messages_page.form.submit!
|
29
32
|
|
30
33
|
expect(messages_page.message(Message.find(1))).to have_content('Hello world!')
|
@@ -36,7 +39,7 @@ expect(messages_page.messages[1]).to have_content('Kamusta mundo!')
|
|
36
39
|
|
37
40
|
With Napybara, now you can!
|
38
41
|
|
39
|
-
## Napybara::Element.new and #
|
42
|
+
## Napybara::Element.new and #node
|
40
43
|
|
41
44
|
First off, let's wrap the Capybara session in a Napybara element:
|
42
45
|
|
@@ -49,10 +52,10 @@ end
|
|
49
52
|
In Rails integration tests which use Capybara, `self` is usually the Capybara session.
|
50
53
|
|
51
54
|
You can get the Capybara element wrapped by the Napybara element with
|
52
|
-
`Napybara::Element#
|
55
|
+
`Napybara::Element#node`:
|
53
56
|
|
54
57
|
```ruby
|
55
|
-
expect(messages_page.
|
58
|
+
expect(messages_page.node).to eq(self)
|
56
59
|
```
|
57
60
|
|
58
61
|
## Finding by selector
|
@@ -68,7 +71,7 @@ end
|
|
68
71
|
|
69
72
|
# ...
|
70
73
|
|
71
|
-
expect(messages_page.form.
|
74
|
+
expect(messages_page.form.node['class']).to eq('new-message')
|
72
75
|
```
|
73
76
|
|
74
77
|
## Finding by object
|
@@ -89,7 +92,7 @@ end
|
|
89
92
|
|
90
93
|
# ...
|
91
94
|
|
92
|
-
expect(messages_page.message(some_message).
|
95
|
+
expect(messages_page.message(some_message).node['id'])
|
93
96
|
.to eq("message-#{some_message.id}")
|
94
97
|
|
95
98
|
```
|
@@ -106,7 +109,7 @@ If the ruby object is identified by a method other than the object's id, you can
|
|
106
109
|
`Napybara::Element#finder` also adds `has_` and `has_no_` methods to the element.
|
107
110
|
With the Napybara elements above, you can call:
|
108
111
|
|
109
|
-
```
|
112
|
+
```ruby
|
110
113
|
expect(messages_page.has_form?).to be_true
|
111
114
|
expect(messages_page).to have_form
|
112
115
|
|
@@ -136,8 +139,8 @@ end
|
|
136
139
|
|
137
140
|
# ...
|
138
141
|
|
139
|
-
expect(messages_page.messages[0].
|
140
|
-
expect(messages_page.messages[1].
|
142
|
+
expect(messages_page.messages[0].node.text).to eq("Hello world!")
|
143
|
+
expect(messages_page.messages[1].node.text).to eq("Kamusta mundo!")
|
141
144
|
```
|
142
145
|
|
143
146
|
Napybara uses ActiveSupport to get the plural version of the finder name.
|
@@ -150,7 +153,7 @@ You can add new methods to a Napybara element with plain Ruby:
|
|
150
153
|
let(:messages_page) do
|
151
154
|
Napybara::Element.new(self) do |page|
|
152
155
|
def page.visit!
|
153
|
-
|
156
|
+
node.visit node.messages_path
|
154
157
|
end
|
155
158
|
end
|
156
159
|
end
|
@@ -167,7 +170,7 @@ Adding the same methods to multiple Napybara elements? You can share the methods
|
|
167
170
|
```ruby
|
168
171
|
module PageExtensions
|
169
172
|
def visit!
|
170
|
-
|
173
|
+
node.visit node.messages_path
|
171
174
|
@visited = true
|
172
175
|
end
|
173
176
|
|
@@ -192,10 +195,10 @@ expect(messages_page).to be_visited
|
|
192
195
|
|
193
196
|
And what if you want to share a module with finders? Again, with plain Ruby:
|
194
197
|
|
195
|
-
```
|
198
|
+
```ruby
|
196
199
|
module IsAForm
|
197
200
|
def submit!
|
198
|
-
submit_button.
|
201
|
+
submit_button.node.click
|
199
202
|
end
|
200
203
|
|
201
204
|
def self.add_to(form)
|
@@ -222,7 +225,7 @@ helpers at the start of this README:
|
|
222
225
|
|
223
226
|
module PageExtensions
|
224
227
|
def visit!
|
225
|
-
|
228
|
+
node.visit node.messages_path
|
226
229
|
@visited = true
|
227
230
|
end
|
228
231
|
|
@@ -233,7 +236,7 @@ end
|
|
233
236
|
|
234
237
|
module IsAForm
|
235
238
|
def submit!
|
236
|
-
submit_button.
|
239
|
+
submit_button.node.click
|
237
240
|
end
|
238
241
|
|
239
242
|
def self.add_to(form)
|
@@ -243,7 +246,7 @@ module IsAForm
|
|
243
246
|
end
|
244
247
|
|
245
248
|
let(:messages_page) do
|
246
|
-
Napybara::Element.new(
|
249
|
+
Napybara::Element.new(self) do |page|
|
247
250
|
page.extend PageExtensions
|
248
251
|
|
249
252
|
page.finder :form, 'form.new-message' do |form|
|
@@ -259,6 +262,27 @@ let(:messages_page) do
|
|
259
262
|
end
|
260
263
|
```
|
261
264
|
|
265
|
+
## And a few more things: getting the selector of a finder
|
266
|
+
|
267
|
+
`Napybara::Element#selector` returns a selector that can be used to find the element:
|
268
|
+
|
269
|
+
```ruby
|
270
|
+
expect(messages_page.form.message_row.text_field.selector)
|
271
|
+
.to eq('form.new-message .message-row input[type=text]')
|
272
|
+
|
273
|
+
expect(messages_page.message(Message.find(2)).selector)
|
274
|
+
.to eq('#message-2')
|
275
|
+
|
276
|
+
expect(messages_page.messages.selector)
|
277
|
+
.to eq('.message-list .message')
|
278
|
+
|
279
|
+
expect(messages_page.messages[1].selector)
|
280
|
+
.to eq('.message-list .message')
|
281
|
+
|
282
|
+
```
|
283
|
+
|
284
|
+
Take note that with `messages_page.messages[1]`, it's currently not possible to get the ith match of a selector. We'll have to wait until [`nth-match`](http://www.w3.org/TR/selectors4/#nth-match-pseudo) becomes mainstream.
|
285
|
+
|
262
286
|
## Installation
|
263
287
|
|
264
288
|
```
|
data/lib/napybara.rb
CHANGED
data/lib/napybara/element.rb
CHANGED
@@ -2,18 +2,24 @@ require 'napybara'
|
|
2
2
|
|
3
3
|
module Napybara
|
4
4
|
class Element
|
5
|
-
attr_reader :
|
6
|
-
|
5
|
+
attr_reader :node, :parent, :selector_string
|
6
|
+
|
7
|
+
alias_method :get, :node
|
8
|
+
|
9
|
+
def initialize(node, parent = nil, selector_string = nil, &block)
|
10
|
+
@node = node
|
11
|
+
@parent = parent
|
12
|
+
@selector_string = selector_string
|
7
13
|
|
8
|
-
def initialize(capybara_element, &block)
|
9
|
-
@capybara_element = capybara_element
|
10
14
|
block.call(self) if block_given?
|
11
15
|
end
|
12
16
|
|
13
17
|
def finder(child_element_name, child_element_selector, record_selector = nil, &block)
|
14
18
|
self.define_singleton_method(child_element_name) do |record = nil|
|
15
19
|
selector = Selector.new(child_element_selector, record_selector, record)
|
16
|
-
|
20
|
+
selector_string = selector.to_s
|
21
|
+
|
22
|
+
self.class.new(self.get.find(selector_string), self, selector_string, &block)
|
17
23
|
end
|
18
24
|
|
19
25
|
self.define_singleton_method("has_#{child_element_name}?") do |record = nil|
|
@@ -27,29 +33,19 @@ module Napybara
|
|
27
33
|
end
|
28
34
|
|
29
35
|
self.define_singleton_method(child_element_name.to_s.pluralize) do
|
30
|
-
self.get.all(child_element_selector)
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
36
|
+
elements = self.get.all(child_element_selector)
|
37
|
+
.map.with_index do |child_element, i|
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
def method_name
|
39
|
-
record_selector.match(METHOD_NAME_REGEX)[1]
|
40
|
-
end
|
39
|
+
self.class.new(child_element, self, child_element_selector, &block)
|
40
|
+
end
|
41
41
|
|
42
|
-
|
43
|
-
record && record.public_send(method_name)
|
42
|
+
ElementArray.new(elements, self, child_element_selector)
|
44
43
|
end
|
44
|
+
end
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
else
|
50
|
-
child_element_selector
|
51
|
-
end
|
52
|
-
end
|
46
|
+
def selector
|
47
|
+
parent_selector = parent.try(:selector)
|
48
|
+
parent_selector ? "#{parent_selector} #{selector_string}" : selector_string
|
53
49
|
end
|
54
50
|
end
|
55
51
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Napybara
|
2
|
+
class ElementArray < Array
|
3
|
+
def initialize(elements, parent, selector_string = '')
|
4
|
+
@parent = parent
|
5
|
+
@selector_string = selector_string
|
6
|
+
super(elements)
|
7
|
+
end
|
8
|
+
|
9
|
+
def selector
|
10
|
+
parent_selector = @parent.try(:selector)
|
11
|
+
parent_selector ? "#{@parent.selector} #{@selector_string}" : @selector_string
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Napybara
|
2
|
+
class Selector < Struct.new(:child_element_selector, :record_selector, :record)
|
3
|
+
METHOD_NAME_REGEX = /\{(\w+)\}/
|
4
|
+
def method_name
|
5
|
+
record_selector.match(METHOD_NAME_REGEX)[1]
|
6
|
+
end
|
7
|
+
|
8
|
+
def record_id
|
9
|
+
record && record.public_send(method_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
if record
|
14
|
+
record_selector.gsub(METHOD_NAME_REGEX, record_id.to_s)
|
15
|
+
else
|
16
|
+
child_element_selector
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/napybara/version.rb
CHANGED
@@ -11,7 +11,7 @@ describe 'Readme example:' do
|
|
11
11
|
<li class="message" id="message-2">Kamusta mundo!</li>
|
12
12
|
</ul>
|
13
13
|
<form class='new-message'>
|
14
|
-
<div class="message-row"
|
14
|
+
<div class="message-row">
|
15
15
|
<label for='message'>Message</label>
|
16
16
|
<input id='message' type='text' name='message'>
|
17
17
|
</div>
|
@@ -30,8 +30,8 @@ describe 'Readme example:' do
|
|
30
30
|
@messages_page = Napybara::Element.new(capybara_page)
|
31
31
|
end
|
32
32
|
|
33
|
-
And "I call #
|
34
|
-
@get_result = @messages_page.
|
33
|
+
And "I call #node on the Napybara page" do
|
34
|
+
@get_result = @messages_page.node
|
35
35
|
end
|
36
36
|
|
37
37
|
Then "I should get the capybara page" do
|
@@ -52,7 +52,7 @@ describe 'Readme example:' do
|
|
52
52
|
|
53
53
|
Then "the finder should be able to find the element matching the selector" do
|
54
54
|
|
55
|
-
expect(@messages_page.form.
|
55
|
+
expect(@messages_page.form.node['class']).to eq('new-message')
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -70,7 +70,7 @@ describe 'Readme example:' do
|
|
70
70
|
Then "the finder should be able to find the element matching a given object" do
|
71
71
|
id = 1
|
72
72
|
message = OpenStruct.new(id: id)
|
73
|
-
expect(@messages_page.message(message).
|
73
|
+
expect(@messages_page.message(message).node['id']).to eq("message-#{id}")
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
@@ -114,8 +114,8 @@ describe 'Readme example:' do
|
|
114
114
|
Then "I should be able to find all the elements matching the selector with
|
115
115
|
a plural version of the finder name" do
|
116
116
|
|
117
|
-
expect(@messages_page.message_items[0].
|
118
|
-
expect(@messages_page.message_items[1].
|
117
|
+
expect(@messages_page.message_items[0].node.text).to eq("Hello world!")
|
118
|
+
expect(@messages_page.message_items[1].node.text).to eq("Kamusta mundo!")
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
@@ -169,4 +169,37 @@ describe 'Readme example:' do
|
|
169
169
|
expect(@messages_page).to be_visited
|
170
170
|
end
|
171
171
|
end
|
172
|
+
|
173
|
+
Steps "Getting the selector of a finder" do
|
174
|
+
Given "I have a a capybara page" do
|
175
|
+
capybara_page
|
176
|
+
end
|
177
|
+
|
178
|
+
When "I wrap the page in a Napybara element" do
|
179
|
+
@messages_page = Napybara::Element.new(capybara_page) do |page|
|
180
|
+
page.finder :form, 'form.new-message' do |form|
|
181
|
+
|
182
|
+
form.finder :message_row, '.message-row' do |row|
|
183
|
+
row.finder :text_field, 'input[type=text]'
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
page.finder :message, '.messages-list .message', '#message-{id}'
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
Then "I can get the selectors of the Napybara finder results" do
|
192
|
+
expect(@messages_page.form.message_row.text_field.selector)
|
193
|
+
.to eq('form.new-message .message-row input[type=text]')
|
194
|
+
|
195
|
+
expect(@messages_page.message(OpenStruct.new(id: 2)).selector)
|
196
|
+
.to eq('#message-2')
|
197
|
+
|
198
|
+
expect(@messages_page.messages.selector)
|
199
|
+
.to eq('.messages-list .message')
|
200
|
+
|
201
|
+
expect(@messages_page.messages[1].selector)
|
202
|
+
.to eq('.messages-list .message')
|
203
|
+
end
|
204
|
+
end
|
172
205
|
end
|
@@ -104,4 +104,80 @@ describe Napybara::Element do
|
|
104
104
|
expect(page.has_no_form?(object)).to be_false
|
105
105
|
end
|
106
106
|
end
|
107
|
+
|
108
|
+
describe "#selector" do
|
109
|
+
it "can return the selector for a single element" do
|
110
|
+
napybara_page = described_class.new(capybara_page) do |page|
|
111
|
+
page.finder :form, '.some-form'
|
112
|
+
end
|
113
|
+
|
114
|
+
expect(napybara_page.form.selector).to eq('.some-form')
|
115
|
+
end
|
116
|
+
|
117
|
+
it "can return the selector for an element nested one layer" do
|
118
|
+
napybara_page = described_class.new(capybara_page) do |page|
|
119
|
+
page.finder :form, '.some-form' do |form|
|
120
|
+
form.finder :some_button, '.some-button'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
expect(napybara_page.form.some_button.selector).to eq('.some-form .some-button')
|
125
|
+
end
|
126
|
+
|
127
|
+
it "can return the selector for an element nested more than one layer" do
|
128
|
+
napybara_page = described_class.new(capybara_page) do |page|
|
129
|
+
page.finder :form, '.some-form' do |form|
|
130
|
+
form.finder :some_button, '.some-button' do |button|
|
131
|
+
button.finder :img, 'img'
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
expect(napybara_page.form.some_button.img.selector)
|
137
|
+
.to eq('.some-form .some-button img')
|
138
|
+
end
|
139
|
+
|
140
|
+
it "can return the selector for an element array" do
|
141
|
+
napybara_page = described_class.new(capybara_page) do |page|
|
142
|
+
page.finder :button, 'button'
|
143
|
+
end
|
144
|
+
|
145
|
+
expect(napybara_page.buttons.selector).to eq('button')
|
146
|
+
end
|
147
|
+
|
148
|
+
context "where the items of the element array are not adjacent" do
|
149
|
+
let(:capybara_page) do
|
150
|
+
Capybara.string <<-HTML
|
151
|
+
<form class='some-form', id='form-1'>
|
152
|
+
<button class='recognized-button some-button' />
|
153
|
+
<button class='ignored-button' />
|
154
|
+
<button class='recognized-button another-button' />
|
155
|
+
</form>
|
156
|
+
HTML
|
157
|
+
end
|
158
|
+
|
159
|
+
it "can return the selector of the ith item of an element array" do
|
160
|
+
napybara_page = described_class.new(capybara_page) do |page|
|
161
|
+
page.finder :button, '.recognized-button'
|
162
|
+
end
|
163
|
+
|
164
|
+
first_button = napybara_page.buttons[1]
|
165
|
+
|
166
|
+
expect(first_button.selector).to eq('.recognized-button')
|
167
|
+
|
168
|
+
expect(napybara_page.node.all(first_button.selector)[1]['class'])
|
169
|
+
.to eq('recognized-button another-button')
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
it "can return the selector of an child of an element array item" do
|
174
|
+
napybara_page = described_class.new(capybara_page) do |page|
|
175
|
+
page.finder :button, 'button' do |button|
|
176
|
+
button.finder :image, 'img'
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
expect(napybara_page.buttons[0].image.selector).to eq('button img')
|
181
|
+
end
|
182
|
+
end
|
107
183
|
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.
|
4
|
+
version: 0.5.0
|
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-
|
11
|
+
date: 2014-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -198,6 +198,8 @@ files:
|
|
198
198
|
- Rakefile
|
199
199
|
- lib/napybara.rb
|
200
200
|
- lib/napybara/element.rb
|
201
|
+
- lib/napybara/element_array.rb
|
202
|
+
- lib/napybara/selector.rb
|
201
203
|
- lib/napybara/version.rb
|
202
204
|
- napybara.gemspec
|
203
205
|
- spec/dummy_app/config.ru
|