kameleon 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/kameleon/dsl/act.rb +73 -22
- data/lib/kameleon/dsl/see.rb +101 -20
- data/lib/kameleon/session/capybara.rb +11 -0
- data/lib/kameleon/user/abstract.rb +78 -6
- data/spec/sample_rack_app/hey.rb +11 -4
- data/spec/spec_helper.rb +12 -0
- data/spec/support/deferred_garbage_collection.rb +20 -0
- data/spec/unit/act/click_spec.rb +52 -0
- data/spec/unit/act/fill_in/attach_file_spec.rb +27 -0
- data/spec/unit/act/fill_in/checkbox_spec.rb +87 -0
- data/spec/unit/act/fill_in/date_ranges_spec.rb +24 -0
- data/spec/unit/act/fill_in/multiple_select_spec.rb +42 -0
- data/spec/unit/act/fill_in/radio_button_spec.rb +35 -0
- data/spec/unit/act/fill_in/select_spec.rb +35 -0
- data/spec/unit/act/fill_in/text_area_spec.rb +52 -0
- data/spec/unit/act/fill_in/text_input_spec.rb +52 -0
- data/spec/unit/act/on_hover_spec.rb +34 -0
- data/spec/unit/dsl/not_see/form_elements/fields/empty_spec.rb +38 -0
- data/spec/unit/dsl/not_see/form_elements/fields/readonly_spec.rb +38 -0
- data/spec/unit/dsl/not_see/form_elements/fields_spec.rb +24 -0
- data/spec/unit/dsl/not_see/form_elements/textareas_spec.rb +25 -0
- data/spec/unit/dsl/not_see/form_elements/texts_spec.rb +26 -0
- data/spec/unit/dsl/not_see/in_scopes_spec.rb +61 -0
- data/spec/unit/dsl/not_see/special_elements/buttons_spec.rb +24 -0
- data/spec/unit/dsl/not_see/special_elements/error_message_for_spec.rb +24 -0
- data/spec/unit/dsl/not_see/special_elements/images_spec.rb +24 -0
- data/spec/unit/dsl/not_see/special_elements/links_spec.rb +46 -0
- data/spec/unit/dsl/not_see/special_elements/ordered_texts_spec.rb +21 -0
- data/spec/unit/dsl/not_see/special_selectors_spec.rb +35 -0
- data/spec/unit/dsl/not_see/texts_spec.rb +24 -0
- data/spec/unit/dsl/see/counted_elements_spec.rb +26 -0
- data/spec/unit/dsl/see/form_elements/checkboxes_spec.rb +45 -0
- data/spec/unit/dsl/see/form_elements/fields/disabled_spec.rb +30 -0
- data/spec/unit/dsl/see/form_elements/fields/empty_spec.rb +28 -0
- data/spec/unit/dsl/see/form_elements/fields/readonly_spec.rb +38 -0
- data/spec/unit/dsl/see/form_elements/fields_spec.rb +28 -0
- data/spec/unit/dsl/see/form_elements/multiple_selects_spec.rb +47 -0
- data/spec/unit/dsl/see/form_elements/radio_buttons_spec.rb +35 -0
- data/spec/unit/dsl/see/form_elements/selects_spec.rb +40 -0
- data/spec/unit/dsl/see/form_elements/textareas_spec.rb +29 -0
- data/spec/unit/dsl/see/form_elements/texts_spec.rb +29 -0
- data/spec/unit/dsl/see/in_scopes_spec.rb +83 -0
- data/spec/unit/dsl/see/special_elements/buttons_spec.rb +28 -0
- data/spec/unit/dsl/see/special_elements/error_message_for_spec.rb +24 -0
- data/spec/unit/dsl/see/special_elements/images_spec.rb +28 -0
- data/spec/unit/dsl/see/special_elements/links_spec.rb +55 -0
- data/spec/unit/dsl/see/special_elements/ordered_texts_spec.rb +21 -0
- data/spec/unit/dsl/see/special_selectors_spec.rb +53 -0
- data/spec/unit/dsl/see/texts_spec.rb +24 -0
- data/spec/unit/guest_spec.rb +24 -45
- data/spec/unit/user_base_spec.rb +1 -1
- metadata +78 -13
- data/spec/unit/act_spec.rb +0 -99
- data/spec/unit/see_spec.rb +0 -242
data/lib/kameleon/dsl/act.rb
CHANGED
@@ -4,41 +4,92 @@ module Kameleon
|
|
4
4
|
|
5
5
|
def click(*links)
|
6
6
|
links.each do |link|
|
7
|
-
|
7
|
+
case link.class.name
|
8
|
+
when 'String'
|
9
|
+
session.click_on(link)
|
10
|
+
when 'Hash'
|
11
|
+
link.each_pair do |what, locator|
|
12
|
+
case what
|
13
|
+
when :image
|
14
|
+
session.find(:xpath, "//img[@alt=\"#{locator}\"").click
|
15
|
+
when :and_accept
|
16
|
+
if session.driver.is_a?(Capybara::Selenium::Driver)
|
17
|
+
#! js hack - problem with selenium native alerts usage
|
18
|
+
#! it switch to allert but no reaction on accept or dismiss
|
19
|
+
session.evaluate_script("window.alert = function(msg) { return true; }")
|
20
|
+
session.evaluate_script("window.confirm = function(msg) { return true; }")
|
21
|
+
end
|
22
|
+
click(locator)
|
23
|
+
# session.driver.browser.switch_to.alert.accept if session.driver.is_a?(Capybara::Selenium::Driver)
|
24
|
+
when :and_dismiss
|
25
|
+
if session.driver.is_a?(Capybara::Selenium::Driver)
|
26
|
+
session.evaluate_script("window.alert = function(msg) { return true; }")
|
27
|
+
session.evaluate_script("window.confirm = function(msg) { return false; }")
|
28
|
+
end
|
29
|
+
click(locator)
|
30
|
+
# session.driver.browser.switch_to.alert.dismiss if session.driver.is_a?(Capybara::Selenium::Driver)
|
31
|
+
else
|
32
|
+
raise("User do not know how to click #{what} - you need to teach him how")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
8
36
|
end
|
9
37
|
end
|
10
38
|
|
11
|
-
def fill_in(
|
12
|
-
|
39
|
+
def fill_in(locators)
|
40
|
+
fill(locators) if can_fill?(locators)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def fill(locators)
|
46
|
+
locators.each_pair do |value, selector|
|
13
47
|
case value
|
14
|
-
when :check
|
48
|
+
when :check, :choose, :uncheck
|
15
49
|
one_or_all(selector).each do |locator|
|
16
|
-
session.
|
50
|
+
session.send(value, locator)
|
17
51
|
end
|
18
|
-
when :
|
19
|
-
|
20
|
-
|
52
|
+
when :select, :unselect
|
53
|
+
selector.each_pair do |select_value, select_locator|
|
54
|
+
one_or_all(select_locator).each do |locator|
|
55
|
+
session.send(value, select_value, :from => locator)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
when :attach
|
59
|
+
selector.each_pair do |file_path, locator|
|
60
|
+
session.attach_file(locator, get_full_test_asset_path(file_path))
|
21
61
|
end
|
22
62
|
else
|
23
|
-
|
63
|
+
one_or_all(selector).each do |locator|
|
64
|
+
session.fill_in(locator, :with => value)
|
65
|
+
end
|
24
66
|
end
|
25
67
|
end
|
26
68
|
end
|
27
69
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
# rspec_world.find(:xpath, xpath % self_or_translation_for(link_text)).click
|
37
|
-
# end
|
38
|
-
# end
|
39
|
-
#end
|
70
|
+
def can_fill?(locators)
|
71
|
+
locators.values.each do |loc|
|
72
|
+
locators = loc.respond_to?(:values) ? loc.values : loc
|
73
|
+
one_or_all(locators).each do |locator|
|
74
|
+
return false if unmodifiable?(locator)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
40
78
|
|
79
|
+
def get_full_test_asset_path(file_path)
|
80
|
+
if File.file?(file_path)
|
81
|
+
file_path
|
82
|
+
elsif File.file?(default_files_path.join(file_path))
|
83
|
+
default_files_path.join(file_path)
|
84
|
+
else
|
85
|
+
raise "Sorry but we didn't found that file in: #{file_path}, neither #{default_files_path.join(file_path)}"
|
86
|
+
end
|
87
|
+
end
|
41
88
|
|
89
|
+
def unmodifiable?(locator)
|
90
|
+
field = session.find_field(locator)
|
91
|
+
field[:readonly] || field[:disabled]
|
92
|
+
end
|
42
93
|
end
|
43
94
|
end
|
44
|
-
end
|
95
|
+
end
|
data/lib/kameleon/dsl/see.rb
CHANGED
@@ -9,28 +9,67 @@ module Kameleon
|
|
9
9
|
session.should rspec_world.have_content(options)
|
10
10
|
when 'Array'
|
11
11
|
options.each do |content_part|
|
12
|
-
|
12
|
+
see(content_part)
|
13
13
|
end
|
14
14
|
when 'Hash'
|
15
15
|
options.each_pair do |value, locator|
|
16
|
-
case value
|
17
|
-
when
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
16
|
+
case value.class.name
|
17
|
+
when 'Symbol'
|
18
|
+
case value
|
19
|
+
when :button, :buttons
|
20
|
+
one_or_all(locator).each do |selector|
|
21
|
+
session.should rspec_world.have_button(selector)
|
22
|
+
end
|
23
|
+
when :checked, :unchecked
|
24
|
+
one_or_all(locator).each do |selector|
|
25
|
+
session.should rspec_world.send("have_#{value.to_s}_field", selector)
|
26
|
+
end
|
27
|
+
when :disabled, :readonly
|
28
|
+
one_or_all(locator).each do |selector|
|
29
|
+
see :field => selector
|
30
|
+
session.find_field(selector)[value].should ==(value.to_s)
|
31
|
+
end
|
32
|
+
when :empty
|
33
|
+
one_or_all(locator).each do |selector|
|
34
|
+
see :field => selector
|
35
|
+
session.find_field(selector).value.to_s.should == ''
|
36
|
+
end
|
37
|
+
when :error_message_for, :error_messages_for
|
38
|
+
one_or_all(locator).each do |selector|
|
39
|
+
session.find(:xpath, '//div[@id="error_explanation"]').should rspec_world.have_content(selector.capitalize)
|
40
|
+
end
|
41
|
+
when :field, :fields
|
42
|
+
one_or_all(locator).each do |selector|
|
43
|
+
session.should rspec_world.have_field(selector)
|
44
|
+
end
|
45
|
+
when :image, :images
|
46
|
+
one_or_all(locator).each do |selector|
|
47
|
+
session.should rspec_world.have_xpath("//img[@alt=\"#{selector}\"] | //img[@src=\"#{selector}\"]")
|
48
|
+
end
|
49
|
+
when :selected
|
50
|
+
locator.each_pair do |selected_value, selected_locator|
|
51
|
+
session.should rspec_world.have_select(selected_locator, :selected => selected_value)
|
52
|
+
end
|
53
|
+
when :unselected
|
54
|
+
locator.each_pair do |selected_value, selected_locator|
|
55
|
+
session.should rspec_world.have_no_select(selected_locator, :selected => selected_value)
|
56
|
+
end
|
57
|
+
when :link, :links
|
58
|
+
if locator.respond_to?(:each_pair)
|
59
|
+
locator.each_pair do |link_text, url|
|
60
|
+
session.should rspec_world.have_link(link_text, :href => url)
|
61
|
+
end
|
62
|
+
else
|
63
|
+
one_or_all(locator).each { |text| session.should rspec_world.have_link(text) }
|
64
|
+
end
|
65
|
+
when :ordered
|
66
|
+
nodes = session.all(:xpath, locator.collect { |n| "//node()[text()= \"#{n}\"]" }.join(' | '))
|
67
|
+
nodes.map(&:text).should == locator
|
68
|
+
else
|
69
|
+
raise("User can not see #{value} - you need to teach him how")
|
33
70
|
end
|
71
|
+
when 'Fixnum'
|
72
|
+
session.should ::Capybara::RSpecMatchers::HaveMatcher.new(*get_selector(locator), :count => value)
|
34
73
|
else
|
35
74
|
session.should rspec_world.have_field(locator, :with => value)
|
36
75
|
end
|
@@ -51,8 +90,50 @@ module Kameleon
|
|
51
90
|
session.should_not rspec_world.have_content(content_part)
|
52
91
|
end
|
53
92
|
when 'Hash'
|
54
|
-
options.each_pair do |value,
|
55
|
-
|
93
|
+
options.each_pair do |value, locators|
|
94
|
+
case value
|
95
|
+
when :button, :buttons
|
96
|
+
one_or_all(locators).each do |selector|
|
97
|
+
session.should_not rspec_world.have_button(selector)
|
98
|
+
end
|
99
|
+
when :error_message_for, :error_messages_for
|
100
|
+
one_or_all(locators).each do |selector|
|
101
|
+
session.find(:xpath, '//div[@id="error_explanation"]').should_not rspec_world.have_content(selector.capitalize)
|
102
|
+
end
|
103
|
+
when :image, :images
|
104
|
+
one_or_all(locators).each do |selector|
|
105
|
+
session.should_not rspec_world.have_xpath("//img[@alt=\"#{selector}\"] | //img[@src=\"#{selector}\"]")
|
106
|
+
end
|
107
|
+
when :field, :fields
|
108
|
+
one_or_all(locators).each do |locator|
|
109
|
+
session.should_not rspec_world.have_field(locator)
|
110
|
+
end
|
111
|
+
when :link, :links
|
112
|
+
if locators.respond_to?(:each_pair)
|
113
|
+
locators.each_pair do |link_text, url|
|
114
|
+
session.should_not rspec_world.have_link(link_text, :href => url)
|
115
|
+
end
|
116
|
+
else
|
117
|
+
one_or_all(locators).each { |text| session.should_not rspec_world.have_link(text) }
|
118
|
+
end
|
119
|
+
when :ordered
|
120
|
+
nodes = session.all(:xpath, locators.collect { |n| "//node()[text()= \"#{n}\"]" }.join(' | '))
|
121
|
+
nodes.map(&:text).should_not == locators
|
122
|
+
when :readonly
|
123
|
+
one_or_all(locators).each do |selector|
|
124
|
+
see :field => selector
|
125
|
+
session.find_field(selector)[value].should rspec_world.be_nil
|
126
|
+
end
|
127
|
+
when :empty
|
128
|
+
one_or_all(locators).each do |locator|
|
129
|
+
see :field => locator
|
130
|
+
session.find_field(locator).value.to_s.should_not == ''
|
131
|
+
end
|
132
|
+
else
|
133
|
+
one_or_all(locators).each do |locator|
|
134
|
+
session.should_not rspec_world.have_field(locator, :with => value)
|
135
|
+
end
|
136
|
+
end
|
56
137
|
end
|
57
138
|
else
|
58
139
|
raise "Not Implemented Structure #{options} :: #{options.class}"
|
@@ -10,6 +10,17 @@ module Kameleon
|
|
10
10
|
current_session
|
11
11
|
end
|
12
12
|
|
13
|
+
def refresh_page
|
14
|
+
case session.driver.class.name
|
15
|
+
when 'Capybara::Selenium::Driver', 'Capybara::RackTest::Driver'
|
16
|
+
visit session.driver.browser.current_url
|
17
|
+
when 'Capybara::Culerity::Driver'
|
18
|
+
session.driver.browser.refresh
|
19
|
+
else
|
20
|
+
raise 'unsupported driver'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
13
24
|
private
|
14
25
|
|
15
26
|
def find_or_create_session
|
@@ -3,7 +3,6 @@ module Kameleon
|
|
3
3
|
class Abstract
|
4
4
|
attr_accessor :options
|
5
5
|
attr_accessor :rspec_world
|
6
|
-
attr_accessor :session
|
7
6
|
|
8
7
|
include Kameleon::Session::Capybara
|
9
8
|
include Kameleon::Dsl::See
|
@@ -15,6 +14,31 @@ module Kameleon
|
|
15
14
|
@session_name = options.delete(:session_name)
|
16
15
|
@options = options
|
17
16
|
set_session
|
17
|
+
session.instance_eval do
|
18
|
+
def within(*args)
|
19
|
+
new_scope = if args.size == 1 && Capybara::Node::Base === args.first
|
20
|
+
args.first
|
21
|
+
else
|
22
|
+
if args.last == :select_multiple
|
23
|
+
node = find(*args)
|
24
|
+
native = Nokogiri::HTML.parse(all(*args[0..-2]).map(&:native).map(&:to_s).join)
|
25
|
+
base = Capybara::RackTest::Node.new(driver, native)
|
26
|
+
::Capybara::Node::Element.new(self,
|
27
|
+
base,
|
28
|
+
node.parent,
|
29
|
+
node.instance_variable_get(:@selector))
|
30
|
+
else
|
31
|
+
find(*args)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
begin
|
35
|
+
scopes.push(new_scope)
|
36
|
+
yield
|
37
|
+
ensure
|
38
|
+
scopes.pop
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
18
42
|
yield if block_given?
|
19
43
|
after_initialization
|
20
44
|
end
|
@@ -25,12 +49,12 @@ module Kameleon
|
|
25
49
|
|
26
50
|
def will(&block)
|
27
51
|
default_selector ?
|
28
|
-
within(default_selector, &block) :
|
52
|
+
within(*default_selector, &block) :
|
29
53
|
instance_eval(&block)
|
30
54
|
end
|
31
55
|
|
32
|
-
def within(selector, &block)
|
33
|
-
session.within(get_selector(selector)) do
|
56
|
+
def within(*selector, &block)
|
57
|
+
session.within(*get_selector(selector)) do
|
34
58
|
instance_eval(&block)
|
35
59
|
end
|
36
60
|
end
|
@@ -39,12 +63,29 @@ module Kameleon
|
|
39
63
|
{}
|
40
64
|
end
|
41
65
|
|
66
|
+
def debug
|
67
|
+
session
|
68
|
+
end
|
69
|
+
|
70
|
+
#! it should be package into raw module
|
71
|
+
def page_element(selector)
|
72
|
+
session.find(*get_selector(selector))
|
73
|
+
end
|
74
|
+
|
75
|
+
def page_elements(selector)
|
76
|
+
session.all(*get_selector(selector))
|
77
|
+
end
|
78
|
+
|
42
79
|
private
|
43
80
|
|
44
81
|
def load_homepage?
|
45
82
|
!options[:skip_page_autoload]
|
46
83
|
end
|
47
84
|
|
85
|
+
def session
|
86
|
+
@session
|
87
|
+
end
|
88
|
+
|
48
89
|
def extract_options(opts)
|
49
90
|
if opts.size == 1
|
50
91
|
opts.first
|
@@ -58,16 +99,47 @@ module Kameleon
|
|
58
99
|
end
|
59
100
|
|
60
101
|
def get_selector(selector)
|
61
|
-
selector.is_a?(
|
102
|
+
if (selector.is_a?(Array) && selector.size == 1)
|
103
|
+
selector = selector.first
|
104
|
+
end
|
105
|
+
case selector.class.name
|
106
|
+
when 'Hash'
|
107
|
+
selector.each_pair do |key, value|
|
108
|
+
case key
|
109
|
+
when :row
|
110
|
+
return [:xpath, "//tr[*='#{value}'][1]"]
|
111
|
+
when :column
|
112
|
+
position =
|
113
|
+
session.all(:xpath, "//table//th").index { |n| n.text =~ /#{value}/ }
|
114
|
+
return [:xpath, "//table//th[#{position + 1}] | //table//td[#{position + 1}]", :select_multiple]
|
115
|
+
else
|
116
|
+
raise "not supported selectors"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
when 'Symbol'
|
120
|
+
page_areas[selector].is_a?(Array) ?
|
121
|
+
page_areas[selector] :
|
122
|
+
[Capybara.default_selector, page_areas[selector]]
|
123
|
+
when 'Array'
|
124
|
+
selector
|
125
|
+
else
|
126
|
+
[Capybara.default_selector, selector]
|
127
|
+
end
|
62
128
|
end
|
63
129
|
|
64
130
|
def default_selector
|
65
131
|
page_areas[:main]
|
66
132
|
end
|
67
133
|
|
134
|
+
#! rails dependency
|
135
|
+
def default_files_path
|
136
|
+
::Rails.root.join('spec')
|
137
|
+
end
|
138
|
+
|
68
139
|
def one_or_all(elements)
|
69
140
|
elements.is_a?(Array) ? elements : [elements]
|
70
141
|
end
|
142
|
+
|
71
143
|
end
|
72
144
|
end
|
73
|
-
end
|
145
|
+
end
|
data/spec/sample_rack_app/hey.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
class Hey
|
2
|
-
|
3
|
-
|
4
|
-
@body = body
|
2
|
+
def initialize(filename = 'default')
|
3
|
+
@body = get_body(filename)
|
5
4
|
end
|
6
5
|
|
7
6
|
def call(env)
|
8
7
|
[200, {"Content-Type" => "text/plain"}, [@body]]
|
9
8
|
end
|
10
|
-
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def get_body(filename)
|
13
|
+
File.open(File.dirname(__FILE__) + "/../dummy/#{filename}").read
|
14
|
+
rescue
|
15
|
+
filename
|
16
|
+
end
|
17
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,16 @@
|
|
1
1
|
require 'kameleon'
|
2
2
|
require 'capybara/dsl'
|
3
|
+
require 'capybara/rspec/matchers'
|
4
|
+
|
5
|
+
Dir["#{File.expand_path("../", __FILE__)}/support/**/*.rb"].each { |f| require f }
|
3
6
|
|
4
7
|
require 'sample_rack_app/hey'
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.before(:all) do
|
11
|
+
DeferredGarbageCollection.start
|
12
|
+
end
|
13
|
+
config.after(:all) do
|
14
|
+
DeferredGarbageCollection.reconsider
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# https://makandracards.com/makandra/950-speed-up-rspec-by-deferring-garbage-collection
|
2
|
+
class DeferredGarbageCollection
|
3
|
+
|
4
|
+
DEFERRED_GC_THRESHOLD = (ENV['DEFER_GC'] || 10.0).to_f
|
5
|
+
|
6
|
+
@@last_gc_run = Time.now
|
7
|
+
|
8
|
+
def self.start
|
9
|
+
GC.disable if DEFERRED_GC_THRESHOLD > 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.reconsider
|
13
|
+
if DEFERRED_GC_THRESHOLD > 0 && Time.now - @@last_gc_run >= DEFERRED_GC_THRESHOLD
|
14
|
+
GC.enable
|
15
|
+
GC.start
|
16
|
+
GC.disable
|
17
|
+
@@last_gc_run = Time.now
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|