kameleon 0.0.5 → 0.0.6
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/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
|