simple_bootstrap_form 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/Gemfile +9 -0
- data/Guardfile +9 -0
- data/README.md +84 -1
- data/Rakefile +9 -0
- data/circle.yml +5 -0
- data/lib/simple_bootstrap_form/action_view_extensions.rb +5 -5
- data/lib/simple_bootstrap_form/css_class_list.rb +1 -1
- data/lib/simple_bootstrap_form/field_factory.rb +58 -0
- data/lib/simple_bootstrap_form/horizontal_form/fields/base_field.rb +118 -0
- data/lib/simple_bootstrap_form/horizontal_form/fields/boolean_field.rb +16 -0
- data/lib/simple_bootstrap_form/horizontal_form/fields/datetime_field.rb +55 -0
- data/lib/simple_bootstrap_form/horizontal_form/fields/email_field.rb +10 -0
- data/lib/simple_bootstrap_form/horizontal_form/fields/password_field.rb +10 -0
- data/lib/simple_bootstrap_form/horizontal_form/fields/text_field.rb +10 -0
- data/lib/simple_bootstrap_form/horizontal_form/fields/textarea_field.rb +14 -0
- data/lib/simple_bootstrap_form/horizontal_form/form_builder.rb +59 -0
- data/lib/simple_bootstrap_form/version.rb +1 -1
- data/lib/simple_bootstrap_form.rb +9 -8
- data/simple_bootstrap_form.gemspec +1 -1
- data/spec/field_factory_spec.rb +65 -0
- data/spec/simple_bootstrap_form_spec.rb +360 -83
- data/spec/spec_helper.rb +3 -0
- data/spec/support/have_element.rb +109 -0
- metadata +19 -13
- data/lib/simple_bootstrap_form/fields/base_field.rb +0 -103
- data/lib/simple_bootstrap_form/fields/boolean_field.rb +0 -14
- data/lib/simple_bootstrap_form/fields/datetime_field.rb +0 -53
- data/lib/simple_bootstrap_form/fields/email_field.rb +0 -8
- data/lib/simple_bootstrap_form/fields/password_field.rb +0 -8
- data/lib/simple_bootstrap_form/fields/text_field.rb +0 -8
- data/lib/simple_bootstrap_form/fields/textarea_field.rb +0 -12
- data/lib/simple_bootstrap_form/form_builder.rb +0 -51
- data/spec/support/input_matchers.rb +0 -72
@@ -1,5 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
def pretty_print(html)
|
4
|
+
Nokogiri::XML(html, &:noblanks).to_xhtml
|
5
|
+
end
|
6
|
+
|
3
7
|
describe SimpleBootstrapForm, type: :helper do
|
4
8
|
|
5
9
|
def account_form
|
@@ -23,133 +27,406 @@ describe SimpleBootstrapForm, type: :helper do
|
|
23
27
|
let(:model) { Account.new }
|
24
28
|
let(:form_id) { 'new_account' }
|
25
29
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
#it "should generate a form" do
|
31
|
-
# expect(subject).to eq(
|
32
|
-
# '<form accept-charset="UTF-8" action="/accounts" class="form-horizontal" id="new_account" method="post">' +
|
33
|
-
# '<div style="margin:0;padding:0;display:inline">'+
|
34
|
-
# '<input name="utf8" type="hidden" value="✓" />'+
|
35
|
-
# '</div>'+
|
36
|
-
# '<div class="form-group">'+
|
37
|
-
# '<label class="control-label col-sm-3" for="account_email"><abbr title="required">*</abbr> Email</label>'+
|
38
|
-
# '<div class="col-sm-6">'+
|
39
|
-
# '<input class="form-control" id="account_email" name="account[email]" placeholder="Email" required="required" type="email" />'+
|
40
|
-
# '</div>'+
|
41
|
-
# '</div>'+
|
42
|
-
# '</form>'
|
43
|
-
# )
|
44
|
-
#end
|
45
|
-
|
46
|
-
describe "the form" do
|
47
|
-
it "should have and ID" do
|
48
|
-
should have_selector %(form##{form_id}[action="/accounts"])
|
30
|
+
describe "all forms" do
|
31
|
+
subject do
|
32
|
+
account_form
|
49
33
|
end
|
50
34
|
|
51
|
-
it "should
|
52
|
-
should
|
35
|
+
it "should have an ID" do
|
36
|
+
should have_element %(form##{form_id}[action="/accounts"])
|
53
37
|
end
|
54
38
|
|
55
39
|
it "should have role 'form'" do
|
56
|
-
should
|
40
|
+
should have_element "form##{form_id}[role=form]"
|
57
41
|
end
|
58
|
-
end
|
59
42
|
|
60
|
-
|
61
|
-
|
43
|
+
describe "f.input" do
|
44
|
+
let(:field_id) { 'account_email' }
|
45
|
+
|
46
|
+
describe "form-group" do
|
47
|
+
it "should add a class describing the form group" do
|
48
|
+
should have_element '.form-group.account_email_group'
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when a :group_class option is provided" do
|
52
|
+
subject {
|
53
|
+
helper.bootstrap_form_for model do |f|
|
54
|
+
f.input :email, group_class: "my_class"
|
55
|
+
end
|
56
|
+
}
|
57
|
+
|
58
|
+
it "should add that value as a class to the group" do
|
59
|
+
should have_element '.form-group.my_class'
|
60
|
+
end
|
61
|
+
end
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
context "when :group_class is set to false on the input" do
|
64
|
+
subject {
|
65
|
+
helper.bootstrap_form_for model do |f|
|
66
|
+
f.input :email, group_class: false
|
67
|
+
end
|
68
|
+
}
|
69
|
+
|
70
|
+
it "should not add a field-specific class to that group" do
|
71
|
+
should have_element('.form-group').with_only_classes('form-group')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "when :group_class is set to false on the form" do
|
76
|
+
subject {
|
77
|
+
helper.bootstrap_form_for model, group_class: false do |f|
|
78
|
+
f.input :email
|
79
|
+
end
|
80
|
+
}
|
81
|
+
|
82
|
+
it "should not add a field-specific class to the groups" do
|
83
|
+
should have_element('.form-group').with_only_classes('form-group')
|
84
|
+
end
|
85
|
+
end
|
66
86
|
end
|
67
|
-
end
|
68
87
|
|
69
|
-
|
70
|
-
|
88
|
+
describe "label" do
|
89
|
+
it { should have_element "form##{form_id} > .form-group " +
|
90
|
+
"> label.control-label[for=#{field_id}]" }
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "string field" do
|
94
|
+
let(:field_id) { 'account_first_name' }
|
71
95
|
|
72
|
-
|
73
|
-
|
96
|
+
it "should give the input an ID, and class form-control" do
|
97
|
+
should have_element %(input##{field_id}.form-control[name="account[first_name]"])
|
98
|
+
end
|
99
|
+
|
100
|
+
it { should have_element("input##{field_id}").with_type('text') }
|
101
|
+
it { should have_element("input##{field_id}").with_placeholder('First name') }
|
74
102
|
end
|
75
|
-
end
|
76
103
|
|
77
|
-
|
78
|
-
|
104
|
+
describe "integer field" do
|
105
|
+
let(:field_id) { "account_id" }
|
106
|
+
subject do
|
107
|
+
helper.bootstrap_form_for model do |f|
|
108
|
+
f.input :id
|
109
|
+
end
|
110
|
+
end
|
111
|
+
it { should have_element("input##{field_id}").with_type('text') }
|
112
|
+
end
|
79
113
|
|
80
|
-
|
81
|
-
|
114
|
+
describe "email field (required)" do
|
115
|
+
let(:field_id) { "account_email" }
|
116
|
+
|
117
|
+
it { should have_element("input##{field_id}").with_type('email') }
|
118
|
+
it { should have_element("input##{field_id}").with_placeholder('Email') }
|
119
|
+
it { should have_element("input##{field_id}").with_attr_value(:required, 'required') }
|
82
120
|
end
|
83
121
|
|
84
|
-
|
85
|
-
|
122
|
+
describe "option :as =>" do
|
123
|
+
let(:field_id) { "account_email" }
|
124
|
+
subject do
|
125
|
+
helper.bootstrap_form_for model do |f|
|
126
|
+
f.input :email, as: :text
|
127
|
+
end
|
128
|
+
end
|
129
|
+
it "should override the type" do
|
130
|
+
should have_element("input##{field_id}").with_type('text')
|
131
|
+
end
|
86
132
|
end
|
87
133
|
|
88
|
-
|
89
|
-
|
90
|
-
|
134
|
+
describe "password field" do
|
135
|
+
let(:field_id) { "account_password" }
|
136
|
+
|
137
|
+
it { should have_element("input##{field_id}").with_type('password') }
|
138
|
+
end
|
139
|
+
|
140
|
+
context "Using the Article form" do
|
141
|
+
let(:model) { Article.new }
|
142
|
+
subject { article_form }
|
143
|
+
|
144
|
+
describe "text field (optional)" do
|
145
|
+
let(:field_id) { 'article_body' }
|
146
|
+
|
147
|
+
it { should have_element(:textarea).with_id(field_id) }
|
148
|
+
it { should have_element(:textarea).with_id(field_id)
|
149
|
+
.with_placeholder('Body') }
|
150
|
+
it { should_not have_element(:textarea).with_id(field_id)
|
151
|
+
.with_attr_value(:required, 'required') }
|
152
|
+
end
|
91
153
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
154
|
+
describe "datetime field" do
|
155
|
+
let(:field_id) { "article_published_at" }
|
156
|
+
|
157
|
+
it { should have_element("input##{field_id}").with_type('datetime') }
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "boolean field" do
|
161
|
+
let(:field_id) { 'article_visible' }
|
162
|
+
|
163
|
+
it { should have_element("input##{field_id}").with_type('checkbox') }
|
97
164
|
end
|
98
165
|
end
|
99
|
-
it { should have_input("##{field_id}").with_type('text') }
|
100
166
|
end
|
167
|
+
end
|
101
168
|
|
102
|
-
|
103
|
-
|
169
|
+
#describe "for vertical forms" do
|
170
|
+
#end
|
171
|
+
|
172
|
+
#describe "for inline forms" do
|
173
|
+
# subject {
|
174
|
+
# helper.bootstrap_form_for model, layout: 'inline' do |f|
|
175
|
+
# f.input(:email)
|
176
|
+
# end
|
177
|
+
# }
|
178
|
+
# it { should have_element "form.form-inline" }
|
179
|
+
#end
|
104
180
|
|
105
|
-
|
106
|
-
|
107
|
-
|
181
|
+
describe "horizontal forms" do
|
182
|
+
subject {
|
183
|
+
helper.bootstrap_form_for(model, layout: 'horizontal') {}
|
184
|
+
}
|
185
|
+
|
186
|
+
describe "the form" do
|
187
|
+
it { should have_element "form.form-horizontal" }
|
108
188
|
end
|
109
189
|
|
110
|
-
describe "
|
190
|
+
describe "f.input" do
|
111
191
|
let(:field_id) { "account_email" }
|
112
|
-
|
113
|
-
|
114
|
-
|
192
|
+
|
193
|
+
context "using size defaults" do
|
194
|
+
subject {
|
195
|
+
helper.bootstrap_form_for model, layout: 'horizontal' do |f|
|
196
|
+
f.input(:email)
|
197
|
+
end
|
198
|
+
}
|
199
|
+
|
200
|
+
it "should make the label col-sm-3 wide" do
|
201
|
+
should have_element "label.col-sm-3[for=#{field_id}]"
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should place the input inside a col-sm-6" do
|
205
|
+
should have_element "form##{form_id} > .form-group > .col-sm-6 > input##{field_id}"
|
115
206
|
end
|
116
207
|
end
|
117
|
-
|
118
|
-
|
208
|
+
|
209
|
+
context "when sizes are supplied to the form" do
|
210
|
+
subject {
|
211
|
+
helper.bootstrap_form_for model, layout: 'horizontal',
|
212
|
+
label_size: 'col-md-3',
|
213
|
+
input_size: 'col-md-6' do |f|
|
214
|
+
f.input :email
|
215
|
+
end
|
216
|
+
}
|
217
|
+
|
218
|
+
it "should use the form sizes for label and input" do
|
219
|
+
should have_element "label.col-md-3[for=#{field_id}]"
|
220
|
+
should have_element ".form-group > .col-md-6 > input##{field_id}"
|
221
|
+
end
|
222
|
+
|
223
|
+
context "when sizes are supplied to the input" do
|
224
|
+
subject {
|
225
|
+
helper.bootstrap_form_for model, layout: 'horizontal' do |f|
|
226
|
+
f.input :email, label_size: 'col-xs-2', input_size: 'col-xs-4'
|
227
|
+
end
|
228
|
+
}
|
229
|
+
|
230
|
+
it "input sizes should override the form sizes" do
|
231
|
+
should have_element "label.col-xs-2[for=#{field_id}]"
|
232
|
+
should have_element ".form-group > .col-xs-4 > input##{field_id}"
|
233
|
+
end
|
234
|
+
end
|
119
235
|
end
|
120
236
|
end
|
237
|
+
end
|
238
|
+
end
|
121
239
|
|
122
|
-
|
123
|
-
|
240
|
+
describe "getbootstrap.com examples" do
|
241
|
+
describe "Basic example" do
|
242
|
+
class Model1
|
243
|
+
include ActiveModel::Validations
|
244
|
+
include ActiveModel::Conversion
|
245
|
+
include ActiveModel::Naming
|
124
246
|
|
125
|
-
|
247
|
+
def self.model_path
|
248
|
+
"foo"
|
249
|
+
end
|
250
|
+
|
251
|
+
attr_accessor :exampleInputEmail1
|
252
|
+
attr_accessor :exampleInputPassword1
|
253
|
+
attr_accessor :exampleInputFile
|
254
|
+
attr_accessor :check_me_out
|
126
255
|
end
|
127
256
|
|
128
|
-
|
129
|
-
|
130
|
-
|
257
|
+
let!(:model) do
|
258
|
+
Model1.new
|
259
|
+
end
|
131
260
|
|
132
|
-
|
133
|
-
|
261
|
+
let(:basic_example_output_from_getbootstrap_dot_com) {
|
262
|
+
<<-BASIC_EXAMPLE
|
263
|
+
<form role="form">
|
264
|
+
<div class="form-group">
|
265
|
+
<label for="exampleInputEmail1">Email address</label>
|
266
|
+
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
|
267
|
+
</div>
|
268
|
+
<div class="form-group">
|
269
|
+
<label for="exampleInputPassword1">Password</label>
|
270
|
+
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
|
271
|
+
</div>
|
272
|
+
<div class="form-group">
|
273
|
+
<label for="exampleInputFile">File input</label>
|
274
|
+
<input type="file" id="exampleInputFile">
|
275
|
+
<p class="help-block">Example block-level help text here.</p>
|
276
|
+
</div>
|
277
|
+
<div class="checkbox">
|
278
|
+
<label>
|
279
|
+
<input type="checkbox"> Check me out
|
280
|
+
</label>
|
281
|
+
</div>
|
282
|
+
<button type="submit" class="btn btn-default">Submit</button>
|
283
|
+
</form>
|
284
|
+
BASIC_EXAMPLE
|
285
|
+
}
|
134
286
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
287
|
+
subject {
|
288
|
+
helper.bootstrap_form_for model, url: '/foo' do |f|
|
289
|
+
f.input(:exampleInputEmail1) +
|
290
|
+
f.input(:exampleInputPassword1) +
|
291
|
+
f.input(:exampleInputFile, help: "Example block-level help text here.") +
|
292
|
+
f.input(:check_me_out, as: :boolean)
|
140
293
|
end
|
294
|
+
}
|
141
295
|
|
142
|
-
|
143
|
-
|
296
|
+
it "should generate the correct output"
|
297
|
+
end
|
144
298
|
|
145
|
-
|
299
|
+
describe "Inline form" do
|
300
|
+
let(:inline_form_from_getbootstrap_dot_com) {
|
301
|
+
<<-INLINE_FORM
|
302
|
+
<form class="form-inline" role="form">
|
303
|
+
<div class="form-group">
|
304
|
+
<label class="sr-only" for="exampleInputEmail2">Email address</label>
|
305
|
+
<input type="email" class="form-control" id="exampleInputEmail2" placeholder="Enter email">
|
306
|
+
</div>
|
307
|
+
<div class="form-group">
|
308
|
+
<label class="sr-only" for="exampleInputPassword2">Password</label>
|
309
|
+
<input type="password" class="form-control" id="exampleInputPassword2" placeholder="Password">
|
310
|
+
</div>
|
311
|
+
<div class="checkbox">
|
312
|
+
<label>
|
313
|
+
<input type="checkbox"> Remember me
|
314
|
+
</label>
|
315
|
+
</div>
|
316
|
+
<button type="submit" class="btn btn-default">Sign in</button>
|
317
|
+
</form>
|
318
|
+
INLINE_FORM
|
319
|
+
}
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "Horizontal form" do
|
323
|
+
class Model3
|
324
|
+
include ActiveModel::Validations
|
325
|
+
include ActiveModel::Conversion
|
326
|
+
include ActiveModel::Naming
|
327
|
+
|
328
|
+
def self.model_path
|
329
|
+
"foo"
|
146
330
|
end
|
147
331
|
|
148
|
-
|
149
|
-
|
332
|
+
attr_accessor :inputEmail3
|
333
|
+
attr_accessor :inputPassword3
|
334
|
+
attr_accessor :remember_me
|
335
|
+
end
|
336
|
+
|
337
|
+
let!(:model) do
|
338
|
+
Model3.new
|
339
|
+
end
|
340
|
+
|
341
|
+
let(:horizontal_form_output) {
|
342
|
+
# Original copy from getbootstrap.com
|
343
|
+
#<form class="form-horizontal" role="form">
|
344
|
+
# <div class="form-group">
|
345
|
+
# <label for="inputEmail3" class="col-sm-2 control-label">Email</label>
|
346
|
+
# <div class="col-sm-10">
|
347
|
+
# <input type="email" class="form-control" id="inputEmail3" placeholder="Email">
|
348
|
+
# </div>
|
349
|
+
# </div>
|
350
|
+
# <div class="form-group">
|
351
|
+
# <label for="inputPassword3" class="col-sm-2 control-label">Password</label>
|
352
|
+
# <div class="col-sm-10">
|
353
|
+
# <input type="password" class="form-control" id="inputPassword3" placeholder="Password">
|
354
|
+
# </div>
|
355
|
+
# </div>
|
356
|
+
# <div class="form-group">
|
357
|
+
# <div class="col-sm-offset-2 col-sm-10">
|
358
|
+
# <div class="checkbox">
|
359
|
+
# <label>
|
360
|
+
# <input type="checkbox"> Remember me
|
361
|
+
# </label>
|
362
|
+
# </div>
|
363
|
+
# </div>
|
364
|
+
# </div>
|
365
|
+
# <div class="form-group">
|
366
|
+
# <div class="col-sm-offset-2 col-sm-10">
|
367
|
+
# <button type="submit" class="btn btn-default">Sign in</button>
|
368
|
+
# </div>
|
369
|
+
# </div>
|
370
|
+
#</form>
|
150
371
|
|
151
|
-
|
372
|
+
# Railsified version
|
373
|
+
# <form>
|
374
|
+
# add accept-charset, action, id, method, model-specific class
|
375
|
+
# <label>
|
376
|
+
# changed for= to model_field
|
377
|
+
# <input>
|
378
|
+
# reorder input attributes to match Rails' order
|
379
|
+
# add name=
|
380
|
+
<<-HORIZONTAL_FORM
|
381
|
+
<form accept-charset="UTF-8" action="/foo" class="new_model3 form-horizontal" id="new_model3" method="post" role="form">
|
382
|
+
<div style=\"margin:0;padding:0;display:inline\">
|
383
|
+
<input name="utf8" type="hidden" value="✓" />
|
384
|
+
</div>
|
385
|
+
<div class="form-group">
|
386
|
+
<label class="col-sm-2 control-label" for="model3_inputEmail3">Email</label>
|
387
|
+
<div class="col-sm-10">
|
388
|
+
<input class="form-control" id="model3_inputEmail3" name="model3[inputEmail3]" placeholder="Email" type="email" />
|
389
|
+
</div>
|
390
|
+
</div>
|
391
|
+
<div class="form-group">
|
392
|
+
<label class="col-sm-2 control-label" for="model3_inputPassword3">Password</label>
|
393
|
+
<div class="col-sm-10">
|
394
|
+
<input class="form-control" id="model3_inputPassword3" name="model3[inputPassword3]" placeholder="Password" type="password" />
|
395
|
+
</div>
|
396
|
+
</div>
|
397
|
+
<div class="form-group">
|
398
|
+
<div class="col-sm-offset-2 col-sm-10">
|
399
|
+
<div class="checkbox">
|
400
|
+
<label>
|
401
|
+
<input type="checkbox"> Remember me
|
402
|
+
</label>
|
403
|
+
</div>
|
404
|
+
</div>
|
405
|
+
</div>
|
406
|
+
<div class="form-group">
|
407
|
+
<div class="col-sm-offset-2 col-sm-10">
|
408
|
+
<button type="submit" class="btn btn-default">Sign in</button>
|
409
|
+
</div>
|
410
|
+
</div>
|
411
|
+
</form>
|
412
|
+
HORIZONTAL_FORM
|
413
|
+
}
|
414
|
+
|
415
|
+
subject {
|
416
|
+
helper.bootstrap_form_for model,
|
417
|
+
layout: :horizontal,
|
418
|
+
label_size: 'col-sm-2',
|
419
|
+
input_size: 'col-sm-10',
|
420
|
+
group_class: false,
|
421
|
+
url: '/foo' do |f|
|
422
|
+
f.input(:inputEmail3, label: "Email", placeholder: "Email") +
|
423
|
+
f.input(:inputPassword3, label: "Password", placeholder: "Password") +
|
424
|
+
f.input(:remember_me, as: :boolean, label_size: 'col-sm-offset-2 col-sm-10')
|
152
425
|
end
|
426
|
+
}
|
427
|
+
|
428
|
+
it "should generate the correct output" do
|
429
|
+
#expect(pretty_print subject).to eq horizontal_form_output
|
153
430
|
end
|
154
431
|
end
|
155
432
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
RSpec::Matchers.define :have_element do |selector|
|
4
|
+
match_for_should do |markup|
|
5
|
+
@selector = selector
|
6
|
+
@markup = markup
|
7
|
+
element_is_present && classes_match
|
8
|
+
end
|
9
|
+
|
10
|
+
match_for_should_not do |markup|
|
11
|
+
@selector = selector
|
12
|
+
@markup = markup
|
13
|
+
!element_is_present || !classes_match
|
14
|
+
end
|
15
|
+
|
16
|
+
failure_message_for_should do |markup|
|
17
|
+
if the_element.nil?
|
18
|
+
"expected to find an element matching #{selector} in #{markup}"
|
19
|
+
elsif @expected_classes
|
20
|
+
actual_classes = @element['class'].split(' ')
|
21
|
+
"expected #{inspect_the_element} to have classes \"#{@expected_classes.sort.join(' ')}\" but it has classes \"#{actual_classes.sort.join(' ')}\""
|
22
|
+
else
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
failure_message_for_should_not do |markup|
|
27
|
+
"expected #{inspect_the_element} not to have classes \"#{@expected_classes.sort.join(' ')}\" in #{markup}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def element_is_present
|
31
|
+
the_element.is_a? Nokogiri::XML::Element
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_element(element)
|
35
|
+
if @expected_classes
|
36
|
+
else
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
########## Chain assertions that will affect the selector
|
42
|
+
|
43
|
+
chain :with_id do |id|
|
44
|
+
@id = id
|
45
|
+
end
|
46
|
+
|
47
|
+
chain :with_class do |css_class|
|
48
|
+
@class = css_class
|
49
|
+
end
|
50
|
+
|
51
|
+
def attrs
|
52
|
+
@attrs ||= {}
|
53
|
+
end
|
54
|
+
|
55
|
+
chain :with_attr_value do |attr, value|
|
56
|
+
attrs[attr] = value
|
57
|
+
end
|
58
|
+
|
59
|
+
chain :with_type do |type|
|
60
|
+
attrs['type'] = type
|
61
|
+
end
|
62
|
+
|
63
|
+
chain :with_placeholder do |placeholder|
|
64
|
+
attrs['placeholder'] = placeholder
|
65
|
+
end
|
66
|
+
|
67
|
+
def actual_selector
|
68
|
+
@actual_selector ||= begin
|
69
|
+
s = @selector.to_s.dup
|
70
|
+
s << "##{@id}" if @id
|
71
|
+
s << ".#{@class}" if @class
|
72
|
+
attrs.each do |attr, value|
|
73
|
+
s << "[#{attr}=\"#{value}\"]"
|
74
|
+
end
|
75
|
+
s
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
########## Chain assertions that are run once the tag has been recovered
|
80
|
+
|
81
|
+
chain :with_only_classes do |classes|
|
82
|
+
@expected_classes = classes.split ' '
|
83
|
+
end
|
84
|
+
|
85
|
+
def actual_classes
|
86
|
+
the_element['class'].split ' '
|
87
|
+
end
|
88
|
+
|
89
|
+
def classes_match
|
90
|
+
return true unless @expected_classes
|
91
|
+
actual_classes.sort == @expected_classes.sort
|
92
|
+
end
|
93
|
+
|
94
|
+
########## Utility methods
|
95
|
+
|
96
|
+
def the_element
|
97
|
+
@element ||= begin
|
98
|
+
doc = Nokogiri::XML @markup
|
99
|
+
elements = doc.css actual_selector
|
100
|
+
raise "found multiple elements matching \"#{actual_selector}\"" if elements.count > 1
|
101
|
+
elements.first
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def inspect_the_element
|
106
|
+
the_element.children = ""
|
107
|
+
the_element
|
108
|
+
end
|
109
|
+
end
|