formulary 0.0.1 → 0.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.
- data/README.md +50 -6
- data/formulary.gemspec +1 -0
- data/lib/formulary.rb +13 -0
- data/lib/formulary/html_form.rb +39 -58
- data/lib/formulary/html_form/fields.rb +21 -0
- data/lib/formulary/html_form/fields/checkbox_group.rb +43 -0
- data/lib/formulary/html_form/fields/email_input.rb +23 -0
- data/lib/formulary/html_form/fields/field.rb +45 -0
- data/lib/formulary/html_form/fields/field_group.rb +26 -0
- data/lib/formulary/html_form/fields/hidden_input.rb +7 -0
- data/lib/formulary/html_form/fields/input.rb +32 -0
- data/lib/formulary/html_form/fields/radio_button_group.rb +29 -0
- data/lib/formulary/html_form/fields/select.rb +24 -0
- data/lib/formulary/html_form/fields/tel_input.rb +7 -0
- data/lib/formulary/html_form/fields/text_input.rb +7 -0
- data/lib/formulary/html_form/fields/textarea.rb +12 -0
- data/lib/formulary/version.rb +1 -1
- data/spec/html_form/fields/checkbox_group_spec.rb +141 -0
- data/spec/html_form/fields/email_input_spec.rb +55 -0
- data/spec/html_form/fields/field_spec.rb +10 -0
- data/spec/html_form/fields/hidden_input_spec.rb +37 -0
- data/spec/html_form/fields/input_spec.rb +17 -0
- data/spec/html_form/fields/radio_button_group_spec.rb +94 -0
- data/spec/html_form/fields/select_spec.rb +62 -0
- data/spec/html_form/fields/tel_input_spec.rb +29 -0
- data/spec/html_form/fields/text_input_spec.rb +29 -0
- data/spec/html_form/fields/textarea_spec.rb +28 -0
- data/spec/html_form_spec.rb +53 -109
- data/spec/spec_helper.rb +5 -10
- data/spec/support/element_helper.rb +15 -0
- data/spec/support/shared_examples_for_pattern.rb +15 -0
- data/spec/support/shared_examples_for_required.rb +35 -0
- metadata +149 -94
- checksums.yaml +0 -7
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Formulary::HtmlForm::Fields::Select do
|
4
|
+
describe ".compatible_with?" do
|
5
|
+
subject { Formulary::HtmlForm::Fields::Select.compatible_with?(element) }
|
6
|
+
|
7
|
+
context "with a select" do
|
8
|
+
let(:markup) { %{<select name="name"></select>} }
|
9
|
+
it { should be_true }
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with a textarea" do
|
13
|
+
let(:markup) { %{<textarea name="name"></textarea>} }
|
14
|
+
it { should be_false }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "with an input type" do
|
18
|
+
let(:markup) { %{<input type="text" name="name" />} }
|
19
|
+
it { should be_false }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "validations" do
|
24
|
+
subject(:input) { Formulary::HtmlForm::Fields::Select.new(element) }
|
25
|
+
let(:markup) do
|
26
|
+
<<-EOS
|
27
|
+
<select name="name">
|
28
|
+
<option>First Text</option>
|
29
|
+
<option value="second_value">Second Text</option>
|
30
|
+
</select>
|
31
|
+
EOS
|
32
|
+
end
|
33
|
+
|
34
|
+
context "passed the text from a valueless option" do
|
35
|
+
before { input.set_value("First Text") }
|
36
|
+
|
37
|
+
it { should be_valid }
|
38
|
+
its(:error) { should be_blank }
|
39
|
+
end
|
40
|
+
|
41
|
+
context "passed the value from an option with a value" do
|
42
|
+
before { input.set_value("second_value") }
|
43
|
+
|
44
|
+
it { should be_valid }
|
45
|
+
its(:error) { should be_blank }
|
46
|
+
end
|
47
|
+
|
48
|
+
context "passed the text from a value with an option" do
|
49
|
+
before { input.set_value("Second Text") }
|
50
|
+
|
51
|
+
it { should_not be_valid }
|
52
|
+
its(:error) { should include("choose") }
|
53
|
+
end
|
54
|
+
|
55
|
+
context "passed a value that is not in the options" do
|
56
|
+
before { input.set_value("unknown") }
|
57
|
+
|
58
|
+
it { should_not be_valid }
|
59
|
+
its(:error) { should include("choose") }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Formulary::HtmlForm::Fields::TelInput do
|
4
|
+
describe ".compatible_with?" do
|
5
|
+
subject { Formulary::HtmlForm::Fields::TelInput.compatible_with?(element) }
|
6
|
+
let(:markup) { %{<input type="#{type}" name="name" />} }
|
7
|
+
|
8
|
+
context "text type" do
|
9
|
+
let(:type) { "text" }
|
10
|
+
it { should be_false }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "tel type" do
|
14
|
+
let(:type) { "tel" }
|
15
|
+
it { should be_true }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it_should_behave_like "a field that allows the required attribute" do
|
20
|
+
let(:markup_with_required) { %{<input type="tel" name="field" required />} }
|
21
|
+
let(:markup_without_required) { %{<input type="tel" name="field" />} }
|
22
|
+
let(:valid_value) { "123-123-1234" }
|
23
|
+
end
|
24
|
+
|
25
|
+
it_should_behave_like "a field that allows the pattern attribute" do
|
26
|
+
let(:markup) { '<input type="tel" name="field" pattern="\d{3}-\d{3}-\d{4}" />' }
|
27
|
+
let(:valid_value) { "123-123-1234" }
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Formulary::HtmlForm::Fields::TextInput do
|
4
|
+
describe ".compatible_with?" do
|
5
|
+
subject { Formulary::HtmlForm::Fields::TextInput.compatible_with?(element) }
|
6
|
+
let(:markup) { %{<input type="#{type}" name="name" />} }
|
7
|
+
|
8
|
+
context "text type" do
|
9
|
+
let(:type) { "text" }
|
10
|
+
it { should be_true }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "email type" do
|
14
|
+
let(:type) { "email" }
|
15
|
+
it { should be_false }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it_should_behave_like "a field that allows the required attribute" do
|
20
|
+
let(:markup_with_required) { %{<input type="text" name="field" required />} }
|
21
|
+
let(:markup_without_required) { %{<input type="text" name="field" />} }
|
22
|
+
let(:valid_value) { "test" }
|
23
|
+
end
|
24
|
+
|
25
|
+
it_should_behave_like "a field that allows the pattern attribute" do
|
26
|
+
let(:markup) { %{<input type="text" name="field" pattern="^test$" />} }
|
27
|
+
let(:valid_value) { "test" }
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Formulary::HtmlForm::Fields::Textarea do
|
4
|
+
describe ".compatible_with?" do
|
5
|
+
subject { Formulary::HtmlForm::Fields::Textarea.compatible_with?(element) }
|
6
|
+
|
7
|
+
context "with a textarea" do
|
8
|
+
let(:markup) { %{<textarea name="name"></textarea>} }
|
9
|
+
it { should be_true }
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with a select" do
|
13
|
+
let(:markup) { %{<select name="name"></select>} }
|
14
|
+
it { should be_false }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "with an input type" do
|
18
|
+
let(:markup) { %{<input type="text" name="name" />} }
|
19
|
+
it { should be_false }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it_should_behave_like "a field that allows the required attribute" do
|
24
|
+
let(:markup_with_required) { %{<textarea name="field" required></textarea>} }
|
25
|
+
let(:markup_without_required) { %{<textarea name="field"></textarea>} }
|
26
|
+
let(:valid_value) { "test" }
|
27
|
+
end
|
28
|
+
end
|
data/spec/html_form_spec.rb
CHANGED
@@ -35,152 +35,96 @@ describe Formulary::HtmlForm do
|
|
35
35
|
</div>
|
36
36
|
|
37
37
|
<div class="field">
|
38
|
-
<label for="
|
39
|
-
<
|
38
|
+
<label for="message">Message</label>
|
39
|
+
<textarea name="message"></textarea>
|
40
40
|
</div>
|
41
41
|
|
42
42
|
<div class="field">
|
43
|
-
<label for="
|
44
|
-
<
|
43
|
+
<label for="unit">Unit</label>
|
44
|
+
<select name="unit">
|
45
|
+
<option>5x5</option>
|
46
|
+
<option value="5x10">Five By Ten</option>
|
47
|
+
</select>
|
45
48
|
</div>
|
46
49
|
|
47
|
-
<
|
48
|
-
|
49
|
-
<input type="text" name="state" />
|
50
|
-
</div>
|
50
|
+
<input type="radio" name="foods" value="bacon">Bacon<br>
|
51
|
+
<input type="radio" name="foods" value="butter" checked>Butter<br>
|
51
52
|
|
52
|
-
<
|
53
|
-
<label for="zip">Zip</label>
|
54
|
-
<input type="text" name="zip" />
|
55
|
-
</div>
|
53
|
+
<input type="radio" name="beverages" value="water">Water<br>
|
56
54
|
|
57
|
-
<
|
58
|
-
<label for="message">Message</label>
|
59
|
-
<textarea name="message"></textarea>
|
60
|
-
</div>
|
55
|
+
<input type="hidden" name="syndication_url" value="example.com" />
|
61
56
|
|
62
|
-
<input type="
|
57
|
+
<input type="checkbox" name="terms">
|
63
58
|
|
59
|
+
<input type="submit" value="Apply" />
|
64
60
|
</form>
|
65
61
|
</div>
|
66
62
|
EOS
|
67
63
|
end
|
68
64
|
|
69
|
-
def valid_params(hash = {})
|
70
|
-
{
|
71
|
-
first_name: "First",
|
72
|
-
last_name: "Last",
|
73
|
-
email: "test@test.com",
|
74
|
-
g5_email: "test@getg5.com"
|
75
|
-
}.merge(hash)
|
76
|
-
end
|
77
|
-
|
78
65
|
let(:html_form) { Formulary::HtmlForm.new(markup) }
|
79
66
|
|
80
|
-
|
81
|
-
let(:
|
82
|
-
subject { fields }
|
83
|
-
|
84
|
-
its(:length) { should eq(10) }
|
85
|
-
|
86
|
-
describe "a required text input" do
|
87
|
-
subject { fields.first }
|
88
|
-
|
89
|
-
its(:name) { should eq("first_name") }
|
90
|
-
its(:type) { should eq("text") }
|
91
|
-
its(:required) { should be_true }
|
92
|
-
end
|
93
|
-
|
94
|
-
describe "a textarea that is not required" do
|
95
|
-
subject { fields[9] }
|
96
|
-
|
97
|
-
its(:name) { should eq("message") }
|
98
|
-
its(:type) { should eq("textarea") }
|
99
|
-
its(:required) { should be_false }
|
100
|
-
end
|
101
|
-
|
102
|
-
describe "an input with a pattern attribute" do
|
103
|
-
subject { fields[6] }
|
67
|
+
context "unsupported field type" do
|
68
|
+
let(:markup) { %{<input type="bacon" name="delicious" />} }
|
104
69
|
|
105
|
-
|
70
|
+
it "explodes" do
|
71
|
+
expect { html_form }.to raise_error(Formulary::UnsupportedFieldType, /bacon/)
|
106
72
|
end
|
107
73
|
end
|
108
74
|
|
109
|
-
describe "
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
75
|
+
describe "validations" do
|
76
|
+
let(:valid_params) do
|
77
|
+
{
|
78
|
+
first_name: "First",
|
79
|
+
last_name: "Last",
|
80
|
+
email: "test@test.com",
|
81
|
+
g5_email: "test@getg5.com",
|
82
|
+
unit: "5x5"
|
83
|
+
}
|
116
84
|
end
|
117
85
|
|
118
|
-
|
119
|
-
|
120
|
-
|
86
|
+
describe "#valid?" do
|
87
|
+
subject(:valid) { html_form.valid?(params) }
|
88
|
+
|
89
|
+
context "with a valid submission" do
|
90
|
+
let(:params) { valid_params }
|
121
91
|
it { should be_true }
|
122
92
|
end
|
123
|
-
end
|
124
|
-
|
125
|
-
context "with invalid parameters" do
|
126
|
-
context "due to missing parameters" do
|
127
|
-
let(:params) { { last_name: "" } }
|
128
93
|
|
94
|
+
context "with an invalid submission" do
|
95
|
+
let(:params) { {} }
|
129
96
|
it { should be_false }
|
130
|
-
|
131
|
-
it "has an error for an omitted field" do
|
132
|
-
html_form.errors.keys.should include("first_name")
|
133
|
-
html_form.errors["first_name"].should include("required")
|
134
|
-
end
|
135
|
-
|
136
|
-
it "has an error for a blank field" do
|
137
|
-
html_form.errors.keys.should include("last_name")
|
138
|
-
html_form.errors["last_name"].should include("required")
|
139
|
-
end
|
140
97
|
end
|
141
98
|
|
142
|
-
context "due to
|
143
|
-
let(:params) { valid_params(
|
144
|
-
|
145
|
-
it { should be_false }
|
99
|
+
context "due to unexpected parameters" do
|
100
|
+
let(:params) { valid_params.merge(extra: "test") }
|
146
101
|
|
147
|
-
it "
|
148
|
-
valid
|
149
|
-
html_form.errors.keys.should include("city")
|
150
|
-
html_form.errors["city"].should include("format")
|
102
|
+
it "raises a Formulary::UnexpectedParameter exception" do
|
103
|
+
expect { valid }.to raise_error(Formulary::UnexpectedParameter, /extra/)
|
151
104
|
end
|
152
105
|
end
|
106
|
+
end
|
153
107
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
it { should be_false }
|
108
|
+
describe "#errors" do
|
109
|
+
before { html_form.valid?(params) }
|
110
|
+
subject { html_form.errors }
|
158
111
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
html_form.errors["email"].should include("not a valid email")
|
163
|
-
end
|
112
|
+
context "with a valid submission" do
|
113
|
+
let(:params) { valid_params }
|
114
|
+
it { should be_empty }
|
164
115
|
end
|
165
116
|
|
166
|
-
context "
|
167
|
-
let(:params)
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
it "has an error for the g5 email field" do
|
172
|
-
valid
|
173
|
-
html_form.errors.keys.should include("g5_email")
|
174
|
-
html_form.errors["g5_email"].should include("format")
|
117
|
+
context "with an invalid submission" do
|
118
|
+
let(:params) do
|
119
|
+
{
|
120
|
+
email: "invalid", g5_email: "test@example.com", foods: "water"
|
121
|
+
}
|
175
122
|
end
|
176
|
-
end
|
177
|
-
|
178
|
-
context "due to unexpected parameters" do
|
179
|
-
let(:params) { valid_params(extra: "test") }
|
180
123
|
|
181
|
-
|
182
|
-
|
183
|
-
|
124
|
+
its(["first_name"]) { should include("required") }
|
125
|
+
its(["email"]) { should include("email") }
|
126
|
+
its(["g5_email"]) { should include("format") }
|
127
|
+
its(["foods"]) { should include("choose") }
|
184
128
|
end
|
185
129
|
end
|
186
130
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,18 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
1
|
+
require 'pry'
|
2
|
+
require 'support/shared_examples_for_pattern'
|
3
|
+
require 'support/shared_examples_for_required'
|
4
|
+
require 'support/element_helper'
|
5
|
+
|
7
6
|
RSpec.configure do |config|
|
8
7
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
8
|
config.run_all_when_everything_filtered = true
|
10
9
|
config.filter_run :focus
|
11
10
|
|
12
|
-
# Run specs in random order to surface order dependencies. If you find an
|
13
|
-
# order dependency and want to debug it, you can fix the order by providing
|
14
|
-
# the seed, which is printed after each run.
|
15
|
-
# --seed 1234
|
16
11
|
config.order = 'random'
|
17
12
|
end
|
18
13
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ElementHelper
|
2
|
+
def element
|
3
|
+
@element ||= elements.first
|
4
|
+
end
|
5
|
+
|
6
|
+
def elements
|
7
|
+
@elements ||= \
|
8
|
+
Nokogiri::HTML("<html><body>#{markup}</body></html>").
|
9
|
+
css("body > *")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.include ElementHelper
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
shared_examples_for "a field that allows the pattern attribute" do
|
2
|
+
subject(:input) { described_class.new(element) }
|
3
|
+
|
4
|
+
context "with a matching value" do
|
5
|
+
before { input.set_value(valid_value) }
|
6
|
+
it { should be_valid }
|
7
|
+
its(:error) { should be_blank }
|
8
|
+
end
|
9
|
+
|
10
|
+
context "without a matching value" do
|
11
|
+
before { input.set_value("z") }
|
12
|
+
it { should_not be_valid }
|
13
|
+
its(:error) { should include("format") }
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
shared_examples_for "a field that allows the required attribute" do
|
2
|
+
subject(:input) { described_class.new(element) }
|
3
|
+
|
4
|
+
context "required" do
|
5
|
+
let(:markup) { markup_with_required }
|
6
|
+
|
7
|
+
context "with a submitted value" do
|
8
|
+
before { input.set_value(valid_value) }
|
9
|
+
it { should be_valid }
|
10
|
+
its(:error) { should be_blank }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "submitted a blank value" do
|
14
|
+
before { input.set_value("") }
|
15
|
+
it { should_not be_valid }
|
16
|
+
its(:error) { should include("required") }
|
17
|
+
end
|
18
|
+
|
19
|
+
context "submitted a nil value" do
|
20
|
+
before { input.set_value(nil) }
|
21
|
+
it { should_not be_valid }
|
22
|
+
its(:error) { should include("required") }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "not required" do
|
27
|
+
let(:markup) { markup_without_required }
|
28
|
+
|
29
|
+
context "without a submitted value" do
|
30
|
+
before { input.set_value("") }
|
31
|
+
it { should be_valid }
|
32
|
+
its(:error) { should be_blank }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|