kameleon 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/lib/kameleon/dsl/act.rb +73 -22
  2. data/lib/kameleon/dsl/see.rb +101 -20
  3. data/lib/kameleon/session/capybara.rb +11 -0
  4. data/lib/kameleon/user/abstract.rb +78 -6
  5. data/spec/sample_rack_app/hey.rb +11 -4
  6. data/spec/spec_helper.rb +12 -0
  7. data/spec/support/deferred_garbage_collection.rb +20 -0
  8. data/spec/unit/act/click_spec.rb +52 -0
  9. data/spec/unit/act/fill_in/attach_file_spec.rb +27 -0
  10. data/spec/unit/act/fill_in/checkbox_spec.rb +87 -0
  11. data/spec/unit/act/fill_in/date_ranges_spec.rb +24 -0
  12. data/spec/unit/act/fill_in/multiple_select_spec.rb +42 -0
  13. data/spec/unit/act/fill_in/radio_button_spec.rb +35 -0
  14. data/spec/unit/act/fill_in/select_spec.rb +35 -0
  15. data/spec/unit/act/fill_in/text_area_spec.rb +52 -0
  16. data/spec/unit/act/fill_in/text_input_spec.rb +52 -0
  17. data/spec/unit/act/on_hover_spec.rb +34 -0
  18. data/spec/unit/dsl/not_see/form_elements/fields/empty_spec.rb +38 -0
  19. data/spec/unit/dsl/not_see/form_elements/fields/readonly_spec.rb +38 -0
  20. data/spec/unit/dsl/not_see/form_elements/fields_spec.rb +24 -0
  21. data/spec/unit/dsl/not_see/form_elements/textareas_spec.rb +25 -0
  22. data/spec/unit/dsl/not_see/form_elements/texts_spec.rb +26 -0
  23. data/spec/unit/dsl/not_see/in_scopes_spec.rb +61 -0
  24. data/spec/unit/dsl/not_see/special_elements/buttons_spec.rb +24 -0
  25. data/spec/unit/dsl/not_see/special_elements/error_message_for_spec.rb +24 -0
  26. data/spec/unit/dsl/not_see/special_elements/images_spec.rb +24 -0
  27. data/spec/unit/dsl/not_see/special_elements/links_spec.rb +46 -0
  28. data/spec/unit/dsl/not_see/special_elements/ordered_texts_spec.rb +21 -0
  29. data/spec/unit/dsl/not_see/special_selectors_spec.rb +35 -0
  30. data/spec/unit/dsl/not_see/texts_spec.rb +24 -0
  31. data/spec/unit/dsl/see/counted_elements_spec.rb +26 -0
  32. data/spec/unit/dsl/see/form_elements/checkboxes_spec.rb +45 -0
  33. data/spec/unit/dsl/see/form_elements/fields/disabled_spec.rb +30 -0
  34. data/spec/unit/dsl/see/form_elements/fields/empty_spec.rb +28 -0
  35. data/spec/unit/dsl/see/form_elements/fields/readonly_spec.rb +38 -0
  36. data/spec/unit/dsl/see/form_elements/fields_spec.rb +28 -0
  37. data/spec/unit/dsl/see/form_elements/multiple_selects_spec.rb +47 -0
  38. data/spec/unit/dsl/see/form_elements/radio_buttons_spec.rb +35 -0
  39. data/spec/unit/dsl/see/form_elements/selects_spec.rb +40 -0
  40. data/spec/unit/dsl/see/form_elements/textareas_spec.rb +29 -0
  41. data/spec/unit/dsl/see/form_elements/texts_spec.rb +29 -0
  42. data/spec/unit/dsl/see/in_scopes_spec.rb +83 -0
  43. data/spec/unit/dsl/see/special_elements/buttons_spec.rb +28 -0
  44. data/spec/unit/dsl/see/special_elements/error_message_for_spec.rb +24 -0
  45. data/spec/unit/dsl/see/special_elements/images_spec.rb +28 -0
  46. data/spec/unit/dsl/see/special_elements/links_spec.rb +55 -0
  47. data/spec/unit/dsl/see/special_elements/ordered_texts_spec.rb +21 -0
  48. data/spec/unit/dsl/see/special_selectors_spec.rb +53 -0
  49. data/spec/unit/dsl/see/texts_spec.rb +24 -0
  50. data/spec/unit/guest_spec.rb +24 -45
  51. data/spec/unit/user_base_spec.rb +1 -1
  52. metadata +78 -13
  53. data/spec/unit/act_spec.rb +0 -99
  54. data/spec/unit/see_spec.rb +0 -242
@@ -4,41 +4,92 @@ module Kameleon
4
4
 
5
5
  def click(*links)
6
6
  links.each do |link|
7
- session.click_on(link)
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(fields)
12
- fields.each_pair do |value, selector|
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.check locator
50
+ session.send(value, locator)
17
51
  end
18
- when :uncheck
19
- one_or_all(selector).each do |locator|
20
- session.uncheck locator
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
- session.fill_in selector, :with => value
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
- # def click(link_text, options={:within => DEFAULT_AREA})
29
- # yield if block_given?
30
- # rspec_world.within(options[:within]) do
31
- # begin
32
- # rspec_world.click_on(self_or_translation_for(link_text))
33
- # rescue Capybara::ElementNotFound => e
34
- # attr_value, attr_type = within_value_and_type(options[:within])
35
- # xpath = attr_type ? "//*[@#{attr_type}='#{attr_value}']//*[*='%s']/*" : "//*[#{attr_type}]//*[*='%s']/*"
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
@@ -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
- session.should rspec_world.have_content(content_part)
12
+ see(content_part)
13
13
  end
14
14
  when 'Hash'
15
15
  options.each_pair do |value, locator|
16
- case value
17
- when :empty
18
- one_or_all(locator).each do |selector|
19
- session.should rspec_world.have_field(selector)
20
- session.find_field(selector).value.should == ""
21
- end
22
- when :checked, :selected
23
- one_or_all(locator).each do |selector|
24
- session.should rspec_world.have_checked_field(selector)
25
- end
26
- when :unchecked, :unselected
27
- one_or_all(locator).each do |selector|
28
- session.should rspec_world.have_unchecked_field(selector)
29
- end
30
- when :link, :links
31
- locator.each_pair do |link_text, url|
32
- session.should rspec_world.have_link(link_text, :href => url)
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, locator|
55
- session.should_not rspec_world.have_field(locator, :with => value)
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?(Symbol) ? page_areas[selector] : selector
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
@@ -1,10 +1,17 @@
1
1
  class Hey
2
-
3
- def initialize(body)
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
- end
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