fracture 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.md +186 -0
- data/Rakefile +1 -0
- data/fracture.gemspec +25 -0
- data/lib/fracture.rb +4 -0
- data/lib/fracture/fracture.rb +112 -0
- data/lib/fracture/matchers/matcher.rb +113 -0
- data/lib/fracture/version.rb +3 -0
- data/spec/fracture_spec.rb +75 -0
- data/spec/matcher_spec.rb +350 -0
- metadata +109 -0
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
# Fracture
|
2
|
+
Unified view testing for your view or controller specs.
|
3
|
+
|
4
|
+
Fracture allows you to define text or selector once at the top of a spec file. It also allows grouping of multiple text or selectors snippets using one label.
|
5
|
+
|
6
|
+
Defining what you are looking for in one place prevents issues when a name (or selector) you are searching for is changed on a view which would only result in one failing spec, the other spec checking for the non exisitence would not fail so you would not find this 'always' passing spec.
|
7
|
+
|
8
|
+
|
9
|
+
### Example
|
10
|
+
|
11
|
+
A simple example why would you use the fracture gem, assume you have the following tests (without Fracture)
|
12
|
+
|
13
|
+
context "admin"
|
14
|
+
```ruby
|
15
|
+
response.body.should have_text("Edit")
|
16
|
+
```
|
17
|
+
...
|
18
|
+
|
19
|
+
(Somewhere further down in your spec file)
|
20
|
+
|
21
|
+
...
|
22
|
+
|
23
|
+
context "user"
|
24
|
+
```ruby
|
25
|
+
response.body.should_not have_text("Edit")
|
26
|
+
```
|
27
|
+
If the word 'Edit' was changed in your view to 'Modify' the first test would fail although the second test would not fail. In a small spec this may be obvious to see although in a large file it might not be found. This would leave you with a never failing spec and if the logic controlling the display of this text broke and allowed for it to display when you are a user this would never be detected.
|
28
|
+
|
29
|
+
####With Fracture:
|
30
|
+
You define the text "Edit" once at the top of your spec and now it can be used multiple times within the spec. If you change the text in the view, you only need to change the Fracture.define_text(:show_edit_button, "Modify") and all test using that definition will change.
|
31
|
+
```ruby
|
32
|
+
Fracture.define_text(:show_edit_button, "Edit")
|
33
|
+
```
|
34
|
+
context "admin"
|
35
|
+
```ruby
|
36
|
+
response.body.should have_fracture(:show_edit_button)
|
37
|
+
```
|
38
|
+
context "user"
|
39
|
+
```ruby
|
40
|
+
response.body.should_not have_fracture(:show_edit_button)
|
41
|
+
```
|
42
|
+
|
43
|
+
## Installation:
|
44
|
+
Gemfile
|
45
|
+
```
|
46
|
+
gem "fracture"
|
47
|
+
```
|
48
|
+
|
49
|
+
## Usage:
|
50
|
+
spec_helper.rb
|
51
|
+
```ruby
|
52
|
+
config.after :all do
|
53
|
+
Fracture.clear
|
54
|
+
end
|
55
|
+
```
|
56
|
+
This is to clear the set Fractures between each spec file
|
57
|
+
|
58
|
+
|
59
|
+
#### In your spec
|
60
|
+
If you want to test views from the controller spec you will need to add *render_views*, fracture will also work within view specs.
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
require 'spec_helper'
|
64
|
+
|
65
|
+
describe ContactsController do
|
66
|
+
render_views
|
67
|
+
|
68
|
+
Fracture.define_text(:add, "New")
|
69
|
+
|
70
|
+
context "as admin" do
|
71
|
+
describe "as an admin" do
|
72
|
+
it "index" do
|
73
|
+
login_as :admin # psuedo code for example
|
74
|
+
get :index
|
75
|
+
response.body.should have_fracture(:add)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "as user" do
|
81
|
+
describe "as an user" do
|
82
|
+
it "index" do
|
83
|
+
login_as :user # psuedo code for example
|
84
|
+
get :index
|
85
|
+
response.body.should have_fracture(:add)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
## Definitions
|
93
|
+
### Text
|
94
|
+
Single
|
95
|
+
```ruby
|
96
|
+
Fracture.define_text(:edits, "Edit")
|
97
|
+
```
|
98
|
+
Multiple
|
99
|
+
```ruby
|
100
|
+
Fracture.define_text(:edits, "Edit", "Edit All")
|
101
|
+
```
|
102
|
+
### Selector
|
103
|
+
```ruby
|
104
|
+
Fracture.define_selector(:label_1, "#an_id", ".a_class", ".another_class")
|
105
|
+
```
|
106
|
+
|
107
|
+
Currently there is no way to build text and selectors into one definition (future feature). Another future feature will be to support 'within'.
|
108
|
+
|
109
|
+
## Matchers
|
110
|
+
Example Definitions
|
111
|
+
```ruby
|
112
|
+
Fracture.define_text(:label_1, "Fred")
|
113
|
+
Fracture.define_text(:label_2, "Barney", "Betty")
|
114
|
+
Fracture.define_text(:label_3, "Wilma")
|
115
|
+
```
|
116
|
+
|
117
|
+
Page should contain "Barney" and "Betty". Ignores any other definitions
|
118
|
+
```ruby
|
119
|
+
response.body.should have_fracture(:label_2)
|
120
|
+
```
|
121
|
+
|
122
|
+
Page should contain "Barney", "Betty", "Fred" and "Wilma"
|
123
|
+
```ruby
|
124
|
+
response.body.should have_fracture(:label_1, :label_2, :label_3)
|
125
|
+
```
|
126
|
+
or
|
127
|
+
```ruby
|
128
|
+
response.body.should have_all_fractures
|
129
|
+
```
|
130
|
+
|
131
|
+
Page should contain "Barney" and "Betty" and not "Fred" or "Wilma"
|
132
|
+
```ruby
|
133
|
+
response.body.should have_only_fractures(:label_2)
|
134
|
+
```
|
135
|
+
|
136
|
+
Page should contain "Barney", "Betty", "Fred" and not "Wilma"
|
137
|
+
```ruby
|
138
|
+
response.body.should have_all_fractures_except(:label_3)
|
139
|
+
```
|
140
|
+
|
141
|
+
### Forms
|
142
|
+
Check to see if there is a form
|
143
|
+
```ruby
|
144
|
+
response.body.should have_a_form
|
145
|
+
```
|
146
|
+
Check to see if its a new form or editing (checks method is POST or PUT)
|
147
|
+
```ruby
|
148
|
+
response.body.should have_a_form.that_is_new
|
149
|
+
response.body.should have_a_form.that_is_edit
|
150
|
+
```
|
151
|
+
Check to path form posts to
|
152
|
+
```ruby
|
153
|
+
response.body.should have_a_form.that_is_new.with_path_of("/tickets")
|
154
|
+
response.body.should have_a_form.with_path_of(tickets_path)
|
155
|
+
```
|
156
|
+
|
157
|
+
|
158
|
+
## All Methods:
|
159
|
+
|
160
|
+
* have_fracture(*labels)
|
161
|
+
* have_all_fractures
|
162
|
+
* have_all_fractures_except(*labels)
|
163
|
+
* have_only_fractures(*labels)
|
164
|
+
* have_a_form
|
165
|
+
- that_is_new
|
166
|
+
- that_is_edit
|
167
|
+
- with_path_of(path)
|
168
|
+
|
169
|
+
# TODO
|
170
|
+
|
171
|
+
* Support text and selector in one fracture
|
172
|
+
|
173
|
+
## Contributing
|
174
|
+
|
175
|
+
1. Fork it
|
176
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
177
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
178
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
179
|
+
5. Create new Pull Request
|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/fracture.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "fracture/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "fracture"
|
7
|
+
s.version = FractureVersion::VERSION
|
8
|
+
s.authors = ["Nigel Rausch"]
|
9
|
+
s.email = ["nigelr@brisbanerails.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Unified View testing within Views or Controllers for RSpec}
|
12
|
+
s.description = %q{Fracture allows you to define and group view text or selectors in one place (at the top of a spec) and then refer to them with labels. This prevents issues when checking for existence and non existence of text/selectors if the views value changes only one spec will fail, using fracture you will update both instances}
|
13
|
+
|
14
|
+
s.rubyforge_project = "fracture"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_runtime_dependency "nokogiri"
|
22
|
+
s.add_runtime_dependency "rspec"
|
23
|
+
|
24
|
+
s.add_development_dependency "rake"
|
25
|
+
end
|
data/lib/fracture.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
class Fracture
|
2
|
+
attr_accessor :label, :items, :is_text
|
3
|
+
|
4
|
+
def initialize label, items, is_text
|
5
|
+
self.label = label
|
6
|
+
self.items = Array(items)
|
7
|
+
self.is_text = is_text
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.define_text label, *items
|
11
|
+
@all ||= {}
|
12
|
+
raise "#{label} has already been defined" if @all[label.to_s]
|
13
|
+
@all[label.to_s] = self.new(label, items.flatten, true)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.define_selector label, *items
|
17
|
+
@all ||= {}
|
18
|
+
raise "#{label} has already been defined" if @all[label.to_s]
|
19
|
+
@all[label.to_s] = self.new(label, items.flatten, false)
|
20
|
+
end
|
21
|
+
|
22
|
+
def text?
|
23
|
+
!!is_text
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.find label
|
27
|
+
#if labels.is_a? Array
|
28
|
+
# ret = []
|
29
|
+
# labels.map do |label|
|
30
|
+
# p label
|
31
|
+
# ret = all[label.to_s]
|
32
|
+
# raise "Fracture with Label of '#{label}' was not found" unless ret
|
33
|
+
# end
|
34
|
+
# p ret
|
35
|
+
#else
|
36
|
+
raise "No Fractures have been defined" if all.empty?
|
37
|
+
ret = all[label.to_s]
|
38
|
+
raise "Fracture with Label of '#{label}' was not found" unless ret
|
39
|
+
#end
|
40
|
+
ret
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.all
|
44
|
+
@all || {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.clear
|
48
|
+
@all = {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.list_to_s items
|
52
|
+
items.map { |item| item.to_s }
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.have_only_test page, is_not, only_fractures
|
56
|
+
test_fractures page, is_not, only_fractures, all_keys_less(only_fractures)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.have_all_except_test page, is_not, except_fractures
|
60
|
+
test_fractures page, is_not, all_keys_less(except_fractures), except_fractures
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.all_keys_less fractures
|
64
|
+
all.keys - list_to_s(Array(fractures).flatten)
|
65
|
+
end
|
66
|
+
|
67
|
+
def do_check page, label
|
68
|
+
#page = page.response.body if page.is_a? CompaniesController
|
69
|
+
page = Nokogiri::HTML.parse(page)
|
70
|
+
if text?
|
71
|
+
page.text.include?(label)
|
72
|
+
else
|
73
|
+
page.at label
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.test_fractures(page, is_not, fracture_labels, reverse_fracture_labels=[])
|
78
|
+
failures = {}
|
79
|
+
failures[:should] = []
|
80
|
+
failures[:should_not] = []
|
81
|
+
Array(fracture_labels).flatten.each do |fracture_label|
|
82
|
+
fracture = Fracture.find(fracture_label)
|
83
|
+
fracture.items.each do |label|
|
84
|
+
if is_not
|
85
|
+
if fracture.do_check(page, label)
|
86
|
+
failures[:should_not] << {fracture_label: fracture_label, label: label}
|
87
|
+
end
|
88
|
+
else
|
89
|
+
unless fracture.do_check(page, label)
|
90
|
+
failures[:should] << {fracture_label: fracture_label, label: label}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
Array(reverse_fracture_labels).flatten.each do |fracture_label|
|
96
|
+
fracture = Fracture.find(fracture_label)
|
97
|
+
fracture.items.each do |label|
|
98
|
+
unless is_not
|
99
|
+
if fracture.do_check(page, label)
|
100
|
+
failures[:should_not] << {fracture_label: fracture_label, label: label}
|
101
|
+
end
|
102
|
+
else
|
103
|
+
unless fracture.do_check(page, label)
|
104
|
+
failures[:should] << {fracture_label: fracture_label, label: label}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
failures.merge!(passed: (failures[:should].empty? && failures[:should_not].empty?))
|
110
|
+
failures
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
RSpec::Matchers.define :have_fracture do |*fracture_labels|
|
2
|
+
match do |page|
|
3
|
+
@results = Fracture.test_fractures page, false, fracture_labels, nil
|
4
|
+
@results[:passed]
|
5
|
+
end
|
6
|
+
|
7
|
+
match_for_should_not do |page|
|
8
|
+
@results = Fracture.test_fractures page, true, fracture_labels, nil
|
9
|
+
@results[:passed]
|
10
|
+
end
|
11
|
+
|
12
|
+
failure_message_for_should { |actual| common_error(actual, @results) }
|
13
|
+
failure_message_for_should_not { |actual| common_error(actual, @results) }
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec::Matchers.define :have_all_fractures do
|
17
|
+
match do |page|
|
18
|
+
@results = Fracture.test_fractures page, false, Fracture.all.keys, nil
|
19
|
+
@results[:passed]
|
20
|
+
end
|
21
|
+
|
22
|
+
match_for_should_not do |page|
|
23
|
+
@results = Fracture.test_fractures page, true, Fracture.all.keys, nil
|
24
|
+
@results[:passed]
|
25
|
+
end
|
26
|
+
|
27
|
+
failure_message_for_should { |actual| common_error(actual, @results) }
|
28
|
+
failure_message_for_should_not { |actual| common_error(actual, @results) }
|
29
|
+
end
|
30
|
+
|
31
|
+
RSpec::Matchers.define :have_all_fractures_except do |*fracture_labels|
|
32
|
+
match do |page|
|
33
|
+
@results = Fracture.have_all_except_test(page, false, fracture_labels)
|
34
|
+
@results[:passed]
|
35
|
+
end
|
36
|
+
|
37
|
+
match_for_should_not do |page|
|
38
|
+
@results = Fracture.have_all_except_test(page, true, fracture_labels)
|
39
|
+
@results[:passed]
|
40
|
+
end
|
41
|
+
|
42
|
+
failure_message_for_should { |actual| common_error(actual, @results) }
|
43
|
+
failure_message_for_should_not { |actual| common_error(actual, @results) }
|
44
|
+
end
|
45
|
+
|
46
|
+
RSpec::Matchers.define :have_only_fractures do |*fracture_labels|
|
47
|
+
match do |page|
|
48
|
+
@results = Fracture.have_only_test(page, false, fracture_labels)
|
49
|
+
@results[:passed]
|
50
|
+
end
|
51
|
+
|
52
|
+
match_for_should_not do |page|
|
53
|
+
@results = Fracture.have_only_test(page, true, fracture_labels)
|
54
|
+
@results[:passed]
|
55
|
+
end
|
56
|
+
|
57
|
+
failure_message_for_should { |actual| common_error(actual, @results) }
|
58
|
+
failure_message_for_should_not { |actual| common_error(actual, @results) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def common_error(actual, results)
|
62
|
+
errors = ""
|
63
|
+
unless results[:should].empty?
|
64
|
+
errors += "expected to find '#{results[:should].map { |i| i[:label] }.join(", ")}'"
|
65
|
+
end
|
66
|
+
unless results[:should_not].empty?
|
67
|
+
errors += "expected not to find '#{results[:should_not].map { |i| i[:label] }.join(", ")}'"
|
68
|
+
end
|
69
|
+
errors += "\non page of\n #{actual}"
|
70
|
+
end
|
71
|
+
|
72
|
+
RSpec::Matchers.define :have_a_form do
|
73
|
+
match do |page|
|
74
|
+
page = Nokogiri::HTML.parse(page)
|
75
|
+
@edit_found = page.at("input[type='hidden'][name='_method'][value='put']")
|
76
|
+
@has_form = page.at("form[method='post']")
|
77
|
+
#TODO refactor this
|
78
|
+
#@found_action = page.at("form[action]").try(:attributes).try(:fetch, "action", nil).try(:value)
|
79
|
+
@found_action = page.at("form[action]") &&
|
80
|
+
page.at("form[action]").attributes &&
|
81
|
+
page.at("form[action]").attributes.fetch("action", nil) &&
|
82
|
+
page.at("form[action]").attributes.fetch("action", nil).value
|
83
|
+
@has_form && !(@new_form && @edit_found) && (!@edit_form || @edit_found) && (!@expected_path || (@found_action == @expected_path))
|
84
|
+
end
|
85
|
+
|
86
|
+
match_for_should_not do |page|
|
87
|
+
raise "Cannot use should_not chained with .is_for, .that_is_edit or .with_path_of " if @new_form || @edit_form || @expected_path
|
88
|
+
page = Nokogiri::HTML.parse(page)
|
89
|
+
!page.at("form[method='post']")
|
90
|
+
end
|
91
|
+
|
92
|
+
#chain(:for_action) { |action #new:edit| @new_form = true }
|
93
|
+
chain(:that_is_new) { @new_form = true }
|
94
|
+
chain(:that_is_edit) { @edit_form = true }
|
95
|
+
#chain(:with_path) { |path| @expected_path = path }
|
96
|
+
chain(:with_path_of) { |path| @expected_path = path }
|
97
|
+
failure_message_for_should do
|
98
|
+
ret = case
|
99
|
+
when !@has_form
|
100
|
+
"expected to find a form on the page\n"
|
101
|
+
when @new_form && @edit_found
|
102
|
+
'Form is an edit'
|
103
|
+
when @edit_form && !@edit_found
|
104
|
+
'Form is not an edit'
|
105
|
+
when @expected_path
|
106
|
+
"Expected to find forms action of '/#{@expected_path}' but found '/#@found_action'"
|
107
|
+
else
|
108
|
+
raise "Unexpected have_form state."
|
109
|
+
end
|
110
|
+
ret
|
111
|
+
end
|
112
|
+
failure_message_for_should_not { "expected not to find a form on the page" }
|
113
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "fracture/fracture"
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
|
6
|
+
describe Fracture do
|
7
|
+
|
8
|
+
before { Fracture.clear }
|
9
|
+
|
10
|
+
context "without data" do
|
11
|
+
it("should be empty before use") { Fracture.all.should == {} }
|
12
|
+
it "should not fail when no data set" do
|
13
|
+
expect {Fracture.find(:nothing) }.to raise_error(RuntimeError, /No Fractures have been defined/)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "with data" do
|
18
|
+
before do
|
19
|
+
@first = Fracture.define_text(:a, "a")
|
20
|
+
Fracture.define_text(:bc, "b", "c")
|
21
|
+
Fracture.define_selector(:x, "x")
|
22
|
+
Fracture.define_selector(:yz, "y", "z")
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#clear" do
|
26
|
+
before { Fracture.clear }
|
27
|
+
it("should clear all") { Fracture.all.should == {} }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe ".text?" do
|
31
|
+
it("should be text search") { Fracture.find(:a).text?.should be_true }
|
32
|
+
it("should not be text search") { Fracture.find(:x).text?.should be_false }
|
33
|
+
end
|
34
|
+
|
35
|
+
context "reuse" do
|
36
|
+
context "of same text label" do
|
37
|
+
it("should raise error if a label is reused") { expect { Fracture.define_text(:bc, "reused") }.to raise_error(RuntimeError, /bc has already been defined/) }
|
38
|
+
end
|
39
|
+
context "of same selector label" do
|
40
|
+
it("should raise error if a label is reused") { expect { Fracture.define_selector(:x, "reused") }.to raise_error(RuntimeError, /x has already been defined/) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "reuse of same text or selector" do
|
45
|
+
it "should display warning when same text is defined"
|
46
|
+
it "should display warning when same label is defined"
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#find" do
|
50
|
+
context "existing" do
|
51
|
+
it("should find label using symbol") { Fracture.find(:a).items == ["a"] }
|
52
|
+
it("should find label using string") { Fracture.find("a").items == ["a"] }
|
53
|
+
end
|
54
|
+
context "should raise error if label does not exist" do
|
55
|
+
it("single") { expect { Fracture.find(:ab) }.to raise_error(RuntimeError, /Fracture with Label of 'ab' was not found/) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#all" do
|
60
|
+
context "should return all Fractures" do
|
61
|
+
subject {Fracture.all }
|
62
|
+
its(:length) {should == 4}
|
63
|
+
its(:keys) {should =~ ["a", "bc", "x", "yz"]}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
#TODO move from matcher_spec
|
68
|
+
describe "test_fracture"
|
69
|
+
|
70
|
+
describe ".do_check" do
|
71
|
+
it("should find it") { @first.do_check("z a b", "a").should be_true }
|
72
|
+
it("should not find it") { @first.do_check("z b", "a").should be_false }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,350 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'nokogiri'
|
3
|
+
require "fracture/fracture"
|
4
|
+
require "fracture/matchers/matcher"
|
5
|
+
|
6
|
+
describe Fracture do
|
7
|
+
context "form" do
|
8
|
+
context "when no form exists" do
|
9
|
+
before { @page = "<p>not a form</p>" }
|
10
|
+
it("should not have a form") { @page.should_not have_a_form }
|
11
|
+
it("should have a form") { expect { @page.should have_a_form }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected to find a form on the page/) }
|
12
|
+
end
|
13
|
+
context "when form exists" do
|
14
|
+
before { @page = "<form method='post' action='/companies'>" }
|
15
|
+
it("should have a form") { @page.should have_a_form }
|
16
|
+
it("should not have a form") { expect { @page.should_not have_a_form }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected not to find a form on the page/) }
|
17
|
+
context "that_is_new" do
|
18
|
+
it("should be a new form") { @page.should have_a_form.that_is_new }
|
19
|
+
it("should not be an edit") { expect { @page.should have_a_form.that_is_edit }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /Form is not an edit/) }
|
20
|
+
end
|
21
|
+
context "that_is_edit" do
|
22
|
+
before { @page += "<input type='hidden' name='_method' value='put'>" }
|
23
|
+
it "should not be a new form" do
|
24
|
+
expect { @page.should have_a_form.that_is_new }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /Form is an edit/)
|
25
|
+
end
|
26
|
+
it("should be an edit form") { @page.should have_a_form.that_is_edit }
|
27
|
+
it("should have a form") { @page.should have_a_form }
|
28
|
+
end
|
29
|
+
context "with_path_of" do
|
30
|
+
it "should match path" do
|
31
|
+
@page.should have_a_form.with_path_of("/companies")
|
32
|
+
end
|
33
|
+
it "should not match path" do
|
34
|
+
expect { @page.should have_a_form.with_path_of("/fred") }.to raise_error(RSpec::Expectations::ExpectationNotMetError, "Expected to find forms action of '//fred' but found '//companies'")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
context "not support should_not when chained" do
|
39
|
+
it "should raise error if that_is_edit" do
|
40
|
+
expect { @page.should_not have_a_form.that_is_edit }.to raise_error(RuntimeError, "Cannot use should_not chained with .is_for, .that_is_edit or .with_path_of ")
|
41
|
+
end
|
42
|
+
it "should raise error if that_is_new" do
|
43
|
+
expect { @page.should_not have_a_form.that_is_new }.to raise_error(RuntimeError, "Cannot use should_not chained with .is_for, .that_is_edit or .with_path_of ")
|
44
|
+
end
|
45
|
+
it "should raise error if with_path_of" do
|
46
|
+
expect { @page.should_not have_a_form.with_path_of("/abc") }.to raise_error(RuntimeError, "Cannot use should_not chained with .is_for, .that_is_edit or .with_path_of ")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "Fracture" do
|
52
|
+
it "non existent fracture label" do
|
53
|
+
expect { @page.should have_fracture(:dont_exist) }.to raise_error(RuntimeError, "Fracture with Label of 'dont_exist' was not found")
|
54
|
+
end
|
55
|
+
|
56
|
+
before do
|
57
|
+
Fracture.clear
|
58
|
+
@page = <<sample
|
59
|
+
<h1>Opening</h1>
|
60
|
+
<table>
|
61
|
+
<tr>
|
62
|
+
<th>abc</th>
|
63
|
+
<th>def</th>
|
64
|
+
</tr>
|
65
|
+
<tr>
|
66
|
+
<td class='left'>123</td>
|
67
|
+
<td id='second'>456</td>
|
68
|
+
</tr>
|
69
|
+
</table>
|
70
|
+
<p class='big'>Title 1</p>
|
71
|
+
The Main Body
|
72
|
+
sample
|
73
|
+
|
74
|
+
Fracture.define_text(:text_1, "Title 1")
|
75
|
+
Fracture.define_text(:text_2, "Main", "Opening")
|
76
|
+
end
|
77
|
+
|
78
|
+
let(:nsel_1) { Fracture.define_selector(:nsel_1, "table > td") }
|
79
|
+
let(:ntext_1) { Fracture.define_text(:ntext_1, "sex") }
|
80
|
+
let(:b11) { Fracture.define_text(:b11, "please") }
|
81
|
+
let(:bb1) { Fracture.define_text(:bb1, "Main", "sex") }
|
82
|
+
let(:bb2) { Fracture.define_text(:bb2, "Sex", "Main") }
|
83
|
+
let(:bb3) { Fracture.define_text(:bb3, "Sex", "please") }
|
84
|
+
|
85
|
+
context "when selector" do
|
86
|
+
describe "Fracture" do
|
87
|
+
before do
|
88
|
+
Fracture.define_selector(:sel_1, "tr>td:contains('123')")
|
89
|
+
Fracture.define_selector(:sel_2, "tr>th:contains('abc')", "tr>td:contains('456')")
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should find sel_1" do
|
93
|
+
Fracture.test_fractures(@page, false, :sel_1).should == {passed: true, should: [], should_not: []}
|
94
|
+
end
|
95
|
+
it 'should find sel_2' do
|
96
|
+
Fracture.test_fractures(@page, false, :sel_2).should == {passed: true, should: [], should_not: []}
|
97
|
+
end
|
98
|
+
it "should not have sel_1 present" do
|
99
|
+
Fracture.test_fractures(@page, true, :sel_1).should == {passed: false,
|
100
|
+
should: [],
|
101
|
+
should_not: [{fracture_label: :sel_1, label: "tr>td:contains('123')"}]}
|
102
|
+
end
|
103
|
+
it "cant find nsel_1 on page" do
|
104
|
+
nsel_1
|
105
|
+
Fracture.test_fractures(@page, false, :nsel_1).should == {passed: false,
|
106
|
+
should: [{fracture_label: :nsel_1, :label => "table > td"}],
|
107
|
+
should_not: []}
|
108
|
+
end
|
109
|
+
it "should not find nsel_1 on page" do
|
110
|
+
nsel_1
|
111
|
+
Fracture.test_fractures(@page, true, :nsel_1).should == {passed: true,
|
112
|
+
should: [],
|
113
|
+
should_not: []}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "have_fracture" do
|
118
|
+
it "should find fracture of :class_1" do
|
119
|
+
Fracture.define_selector(:class_1, "td.left")
|
120
|
+
@page.should have_fracture :class_1
|
121
|
+
end
|
122
|
+
it "should find fracture of :id_1" do
|
123
|
+
Fracture.define_selector(:id_1, "td#second")
|
124
|
+
@page.should have_fracture :id_1
|
125
|
+
end
|
126
|
+
it "should not find missing fracture" do
|
127
|
+
Fracture.define_selector(:id_2, "th#second")
|
128
|
+
@page.should_not have_fracture :id_2
|
129
|
+
end
|
130
|
+
it "should fail to find a fracture" do
|
131
|
+
Fracture.define_selector(:id_3, "th#second")
|
132
|
+
expect { @page.should have_fracture(:id_3) }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected to find 'th#second'/)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "when text" do
|
138
|
+
describe "Fracture" do
|
139
|
+
context "when passing only one fracture list" do
|
140
|
+
context "should" do
|
141
|
+
context "when 1 fracture" do
|
142
|
+
it "1 found" do
|
143
|
+
Fracture.test_fractures(@page, false, :text_1).should == {passed: true, should: [], should_not: []}
|
144
|
+
end
|
145
|
+
it "2 found" do
|
146
|
+
Fracture.test_fractures(@page, false, :text_2).should == {passed: true, should: [], should_not: []}
|
147
|
+
end
|
148
|
+
it "1 not found" do
|
149
|
+
ntext_1
|
150
|
+
Fracture.test_fractures(@page, false, :ntext_1).should == {passed: false,
|
151
|
+
should: [{fracture_label: :ntext_1, label: "sex"}],
|
152
|
+
should_not: []}
|
153
|
+
end
|
154
|
+
it "2 not found" do
|
155
|
+
bb3
|
156
|
+
Fracture.test_fractures(@page, false, :bb3).should == {passed: false,
|
157
|
+
should: [{fracture_label: :bb3, label: "Sex"}, {fracture_label: :bb3, label: "please"}],
|
158
|
+
should_not: []}
|
159
|
+
end
|
160
|
+
it "1 not found and 1 found" do
|
161
|
+
bb1
|
162
|
+
Fracture.test_fractures(@page, false, :bb1).should == {passed: false,
|
163
|
+
should: [{fracture_label: :bb1, label: "sex"}],
|
164
|
+
should_not: []}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
context "when list of 2 fractures" do
|
168
|
+
it "3 found" do
|
169
|
+
Fracture.test_fractures(@page, false, [:text_1, :text_2]).should == {passed: true, should: [], should_not: []}
|
170
|
+
end
|
171
|
+
it "2 not found" do
|
172
|
+
ntext_1
|
173
|
+
b11
|
174
|
+
Fracture.test_fractures(@page, false, [:ntext_1, :b11]).should == {passed: false,
|
175
|
+
should: [{:fracture_label => :ntext_1, :label => "sex"}, {:fracture_label => :b11, :label => "please"}],
|
176
|
+
should_not: []}
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
context "should_not" do
|
181
|
+
context "when 1 fracture" do
|
182
|
+
it "1 found (not)" do
|
183
|
+
Fracture.test_fractures(@page, true, :text_1).should == {passed: false,
|
184
|
+
should_not: [{fracture_label: :text_1, label: "Title 1"}],
|
185
|
+
should: []}
|
186
|
+
end
|
187
|
+
it "not found" do
|
188
|
+
ntext_1
|
189
|
+
Fracture.test_fractures(@page, true, :ntext_1).should == {passed: true, should: [], should_not: []}
|
190
|
+
end
|
191
|
+
it "not found multi" do
|
192
|
+
bb3
|
193
|
+
Fracture.test_fractures(@page, true, :bb3).should == {passed: true, should: [], should_not: []}
|
194
|
+
end
|
195
|
+
end
|
196
|
+
context "when list of 2 fractures" do
|
197
|
+
it "3 found" do
|
198
|
+
Fracture.test_fractures(@page, true, [:text_1, :text_2]).should == {passed: false,
|
199
|
+
should_not: [{:fracture_label => :text_1, :label => "Title 1"},
|
200
|
+
{:fracture_label => :text_2, :label => "Main"},
|
201
|
+
{:fracture_label => :text_2, :label => "Opening"}],
|
202
|
+
should: []}
|
203
|
+
end
|
204
|
+
it "2 not found" do
|
205
|
+
ntext_1
|
206
|
+
b11
|
207
|
+
Fracture.test_fractures(@page, true, [:ntext_1, :b11]).should == {passed: true, should: [], should_not: []}
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
context "when passing 2 fracture lists (should find and should not find)" do
|
213
|
+
context "should" do
|
214
|
+
it "exist 1 found and not exist 1 not found" do
|
215
|
+
ntext_1
|
216
|
+
Fracture.test_fractures(@page, false, [:text_1], [:ntext_1]).should == {passed: true, should: [], should_not: []}
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should not find text_2" do
|
220
|
+
Fracture.test_fractures(@page, false, [:text_1], [:text_2]).should == {passed: false, should: [],
|
221
|
+
should_not: [{:fracture_label => :text_2, :label => "Main"}, {:fracture_label => :text_2, :label => "Opening"}]}
|
222
|
+
end
|
223
|
+
it "should not find text_1" do
|
224
|
+
ntext_1
|
225
|
+
Fracture.test_fractures(@page, false, [:ntext_1], [:text_1]).should == {passed: false, should:
|
226
|
+
[{:fracture_label => :ntext_1, :label => "sex"}], should_not: [{fracture_label: :text_1, label: "Title 1"}]}
|
227
|
+
end
|
228
|
+
end
|
229
|
+
context "when should_not" do
|
230
|
+
it "should not find ntext_1 and should find text_1 " do
|
231
|
+
ntext_1
|
232
|
+
Fracture.test_fractures(@page, true, [:ntext_1], [:text_1]).should == {passed: true, should: [], should_not: []}
|
233
|
+
end
|
234
|
+
|
235
|
+
it "exist 1 found and not exist 1 not found" do
|
236
|
+
ntext_1
|
237
|
+
Fracture.test_fractures(@page, true, [:text_1], [:ntext_1]).should == {passed: false,
|
238
|
+
should: [{:fracture_label => :ntext_1, :label => "sex"}],
|
239
|
+
should_not: [{fracture_label: :text_1, label: "Title 1"}]}
|
240
|
+
end
|
241
|
+
it "text_1 should_not appear on the page and text_2 should" do
|
242
|
+
Fracture.test_fractures(@page, true, [:text_1], [:text_2]).should == {passed: false,
|
243
|
+
should_not: [{fracture_label: :text_1, label: "Title 1"}],
|
244
|
+
should: []}
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
context "have_fracture" do
|
249
|
+
context "should" do
|
250
|
+
it "match single" do
|
251
|
+
@page.should have_fracture(:text_1)
|
252
|
+
end
|
253
|
+
it "should match multiple" do
|
254
|
+
@page.should have_fracture(:text_2)
|
255
|
+
end
|
256
|
+
it "should not match multiple when 2nd fracture item does not match" do
|
257
|
+
bb1
|
258
|
+
expect { @page.should have_fracture(:bb1) }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected to find 'sex'/)
|
259
|
+
end
|
260
|
+
it "should match with multiple arguments" do
|
261
|
+
@page.should have_fracture(:text_2, :text_1)
|
262
|
+
end
|
263
|
+
it "should not match with multiple argument when last item does not match" do
|
264
|
+
ntext_1
|
265
|
+
expect { @page.should have_fracture(:text_2, :text_1, :ntext_1) }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected to find 'sex'/)
|
266
|
+
end
|
267
|
+
it "should fail with missing element" do
|
268
|
+
ntext_1
|
269
|
+
expect { @page.should have_fracture(:ntext_1) }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected to find 'sex'/)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
context "should not" do
|
273
|
+
it "fails not match single" do
|
274
|
+
expect { @page.should_not have_fracture(:text_1) }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected not to find 'Title 1'/)
|
275
|
+
end
|
276
|
+
it "should not match multiple when 2nd fracture item does exist" do
|
277
|
+
bb2
|
278
|
+
expect { @page.should_not have_fracture(:bb2) }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected not to find 'Main'/)
|
279
|
+
end
|
280
|
+
it "should fail when last fracture has items that exist on pag" do
|
281
|
+
bb2
|
282
|
+
bb3
|
283
|
+
expect { @page.should_not have_fracture(:bb3, :bb2) }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected not to find 'Main'/)
|
284
|
+
end
|
285
|
+
it "should fail when first fracture has items that exist on pag" do
|
286
|
+
bb2
|
287
|
+
bb3
|
288
|
+
expect { @page.should_not have_fracture([:bb2, :bb3]) }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected not to find 'Main'/)
|
289
|
+
end
|
290
|
+
it "should pass when no items exist" do
|
291
|
+
bb3
|
292
|
+
@page.should_not have_fracture(:bb3)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
describe "have_all_fractures" do
|
300
|
+
it "all" do
|
301
|
+
@page.should have_all_fractures
|
302
|
+
end
|
303
|
+
it "not have :ntext_1" do
|
304
|
+
ntext_1
|
305
|
+
expect { @page.should have_all_fractures }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected to find 'sex'/)
|
306
|
+
end
|
307
|
+
it "not have any fractures" do
|
308
|
+
Fracture.clear
|
309
|
+
bb3
|
310
|
+
@page.should_not have_all_fractures
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
describe "have_all_fractures_except" do
|
315
|
+
it "should have all except ntext_1" do
|
316
|
+
ntext_1
|
317
|
+
@page.should have_all_fractures_except :ntext_1
|
318
|
+
end
|
319
|
+
it "fails when find text_2 on page" do
|
320
|
+
expect { @page.should have_all_fractures_except :text_2 }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected not to find 'Main, Opening'/)
|
321
|
+
end
|
322
|
+
|
323
|
+
it "fails when should_not finds text_1 on the page" do
|
324
|
+
expect { @page.should_not have_all_fractures_except :text_2 }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected not to find 'Title 1'/)
|
325
|
+
end
|
326
|
+
|
327
|
+
it "none" do
|
328
|
+
Fracture.clear
|
329
|
+
Fracture.define_text(:text_1, "Title 1")
|
330
|
+
@page.should_not have_all_fractures_except :text_1
|
331
|
+
end
|
332
|
+
end
|
333
|
+
describe "have_only_fractures" do
|
334
|
+
it "should have only text_1 and text_2" do
|
335
|
+
@page.should have_only_fractures :text_1, :text_2
|
336
|
+
end
|
337
|
+
it "should have only text_1 and text_2 and ignore ntext_1" do
|
338
|
+
ntext_1
|
339
|
+
@page.should have_only_fractures :text_1, :text_2
|
340
|
+
end
|
341
|
+
it "should raise error when one exists" do
|
342
|
+
expect { @page.should have_only_fractures :text_2 }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected not to find 'Title 1'/)
|
343
|
+
end
|
344
|
+
it "should raise error when expected item to exist" do
|
345
|
+
ntext_1
|
346
|
+
expect { @page.should have_only_fractures :text_1, :text_2, :ntext_1 }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected to find 'sex'/)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fracture
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nigel Rausch
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Fracture allows you to define and group view text or selectors in one
|
63
|
+
place (at the top of a spec) and then refer to them with labels. This prevents issues
|
64
|
+
when checking for existence and non existence of text/selectors if the views value
|
65
|
+
changes only one spec will fail, using fracture you will update both instances
|
66
|
+
email:
|
67
|
+
- nigelr@brisbanerails.com
|
68
|
+
executables: []
|
69
|
+
extensions: []
|
70
|
+
extra_rdoc_files: []
|
71
|
+
files:
|
72
|
+
- .gitignore
|
73
|
+
- Gemfile
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- fracture.gemspec
|
77
|
+
- lib/fracture.rb
|
78
|
+
- lib/fracture/fracture.rb
|
79
|
+
- lib/fracture/matchers/matcher.rb
|
80
|
+
- lib/fracture/version.rb
|
81
|
+
- spec/fracture_spec.rb
|
82
|
+
- spec/matcher_spec.rb
|
83
|
+
homepage: ''
|
84
|
+
licenses: []
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project: fracture
|
103
|
+
rubygems_version: 1.8.24
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: Unified View testing within Views or Controllers for RSpec
|
107
|
+
test_files:
|
108
|
+
- spec/fracture_spec.rb
|
109
|
+
- spec/matcher_spec.rb
|