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.
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