watirsome 0.1.0

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/watirsome.rb ADDED
@@ -0,0 +1,155 @@
1
+ module Watirsome
2
+ class << self
3
+
4
+ # @attr [Regexp] region_matcher
5
+ attr_accessor :region_matcher
6
+
7
+ # @attr [Array<Symbol>] readable
8
+ attr_accessor :readable
9
+
10
+ # @attr [Array<Symbol>] clickable
11
+ attr_accessor :clickable
12
+
13
+ # @attr [Array<Symbol>] settable
14
+ attr_accessor :settable
15
+
16
+ # @attr [Array<Symbol>] selectable
17
+ attr_accessor :selectable
18
+
19
+ #
20
+ # Returns regular expression for region module names.
21
+ # @return [Regexp]
22
+ #
23
+ def region_matcher
24
+ @region_matcher ||= /^.+(Region)$/
25
+ end
26
+
27
+ #
28
+ # Returns array of readable elements.
29
+ # @return [Array<Symbol>]
30
+ #
31
+ def readable
32
+ @readable ||= [:div, :span, :p, :h1, :h2, :h3, :h4, :h5, :h6, :select_list, :text_field, :textarea]
33
+ end
34
+
35
+ #
36
+ # Returns array of clickable elements.
37
+ # @return [Array<Symbol>]
38
+ #
39
+ def clickable
40
+ @clickable ||= [:a, :link, :button]
41
+ end
42
+
43
+ #
44
+ # Returns array of settable elements.
45
+ # @return [Array<Symbol>]
46
+ #
47
+ def settable
48
+ @settable ||= [:text_field, :file_field, :textarea, :checkbox]
49
+ end
50
+
51
+ #
52
+ # Returns array of selectable elements.
53
+ # @return [Array<Symbol>]
54
+ #
55
+ def selectable
56
+ @selectable ||= [:select_list]
57
+ end
58
+
59
+ #
60
+ # Returns true if tag can have click accessor.
61
+ #
62
+ # @param [Symbol, String] method
63
+ # @return [Boolean]
64
+ #
65
+ def clickable?(tag)
66
+ clickable.include? tag.to_sym
67
+ end
68
+
69
+ #
70
+ # Returns true if tag can have set accessor.
71
+ #
72
+ # @param [Symbol, String] method
73
+ # @return [Boolean]
74
+ #
75
+ def settable?(tag)
76
+ settable.include? tag.to_sym
77
+ end
78
+
79
+ #
80
+ # Returns true if tag can have select accessor.
81
+ #
82
+ # @param [Symbol, String] method
83
+ # @return [Boolean]
84
+ #
85
+ def selectable?(tag)
86
+ selectable.include? tag.to_sym
87
+ end
88
+
89
+ #
90
+ # Returns true if tag can have text accessor.
91
+ #
92
+ # @param [Symbol, String] method
93
+ # @return [Boolean]
94
+ #
95
+ def readable?(tag)
96
+ readable.include? tag.to_sym
97
+ end
98
+
99
+ #
100
+ # Returns array of Watir element methods.
101
+ # @return [Array<Sybmol>]
102
+ #
103
+ def watir_methods
104
+ unless @watir_methods
105
+ @watir_methods = Watir::Container.instance_methods
106
+ @watir_methods.delete(:extract_selector)
107
+ end
108
+
109
+ @watir_methods
110
+ end
111
+
112
+ #
113
+ # Return true if method can be proxied to Watir, false otherwise.
114
+ #
115
+ # @param [Symbol] method
116
+ # @return [Boolean]
117
+ #
118
+ def watirsome?(method)
119
+ Watirsome.watir_methods.include? method.to_sym
120
+ end
121
+
122
+ #
123
+ # Returns true if method is element accessor in plural form.
124
+ #
125
+ # @example
126
+ # Watirsome::Accessors.plural? :div #=> false
127
+ # Watirsome::Accessors.plural? :divs #=> true
128
+ #
129
+ # @param [Symbol, String] method
130
+ # @return [Boolean]
131
+ # @api private
132
+ #
133
+ def plural?(method)
134
+ str = method.to_s
135
+ sym = method.to_sym
136
+ sgl = str.sub(/s$/, '').to_sym
137
+
138
+ /s$/ === str && Watirsome.watir_methods.include?(sym) && Watirsome.watir_methods.include?(sgl)
139
+ end
140
+
141
+ end # self
142
+
143
+
144
+ def self.included(kls)
145
+ kls.extend Watirsome::Accessors::ClassMethods
146
+ kls.send :include, Watirsome::Accessors::InstanceMethods
147
+ kls.send :include, Watirsome::Initializers
148
+ end
149
+
150
+ end # Watirsome
151
+
152
+
153
+ require 'watir-webdriver'
154
+ require 'watirsome/accessors'
155
+ require 'watirsome/initializers'
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Watirsome::Accessors do
4
+ include_context :page
5
+ include_context :element
6
+
7
+ it_defines :element_accessor, %w(div a text_field select_list)
8
+ it_defines :read_accessor, %w(div text_field select_list)
9
+ it_defines :click_accessor, %w(a)
10
+ it_defines :set_accessor, %w(text_field)
11
+ it_defines :select_accessor, %w(select_list)
12
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Watirsome::Initializers do
4
+ include_context :page
5
+
6
+ describe '#initialze' do
7
+ it 'does not initalize page if there is no constructor defined' do
8
+ page = Page.dup
9
+ page.class_eval { remove_method :initialize_page }
10
+ page.should_not_receive :initialize_page
11
+ page.new(watir)
12
+ end
13
+
14
+ it 'initializes page if there is constructor defined' do
15
+ page.instance_variable_get(:@initialized).should == true
16
+ end
17
+
18
+ it 'initalizes regions' do
19
+ Page.any_instance.should_receive :initialize_regions
20
+ Page.new(watir)
21
+ end
22
+ end
23
+
24
+ describe '#initialize_regions' do
25
+ it 'initalizes included regions' do
26
+ page.instance_variable_get(:@included_initialized).should == 1
27
+ end
28
+
29
+ it 'initalizes extended regions' do
30
+ page.instance_variable_get(:@extended_initialized).should == 1
31
+ end
32
+
33
+ it 'does not initalize modules with incorrect name' do
34
+ page.instance_variable_get(:@helper_initialized).should == nil
35
+ end
36
+
37
+ it 'uses Watirsome.region_matcher to match module name' do
38
+ Watirsome.should_receive(:region_matcher).and_return ''
39
+ page
40
+ end
41
+
42
+ it 'caches initalized regions' do
43
+ page.initialize_regions
44
+ page.instance_variable_get(:@included_initialized).should == 1
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe Watirsome do
4
+ describe '.region_matcher' do
5
+ it 'returns region matcher regexp' do
6
+ described_class.region_matcher.should be_a(Regexp)
7
+ end
8
+ end
9
+
10
+ %w(readable clickable settable selectable).each do |method|
11
+ describe ".#{method}" do
12
+ it 'returns array of accessors' do
13
+ accessors = described_class.send(method)
14
+ accessors.should be_an(Array)
15
+ accessors.each do |accessor|
16
+ accessor.should be_a(Symbol)
17
+ end
18
+ end
19
+
20
+ it 'allows to add custom accessors' do
21
+ described_class.send(method) << :custom
22
+ described_class.send(method).should include(:custom)
23
+ end
24
+ end
25
+
26
+ describe ".#{method}?" do
27
+ let(:tag) do
28
+ case method
29
+ when 'readable' then :div
30
+ when 'clickable' then :button
31
+ when 'settable' then :text_field
32
+ when 'selectable' then :select_list
33
+ end
34
+ end
35
+
36
+ it "returns true if element is #{method}" do
37
+ described_class.send(:"#{method}?", tag).should == true
38
+ end
39
+
40
+ it "returns false if element is not #{method}" do
41
+ described_class.send(:"#{method}?", :foo).should == false
42
+ end
43
+ end
44
+ end
45
+
46
+
47
+ describe '.watir_methods' do
48
+ it 'returns array of watir container methods' do
49
+ described_class.watir_methods.each do |method|
50
+ Watir::Container.instance_methods.should include(method)
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '.watirsome?' do
56
+ it 'returns true if method is watir-contained' do
57
+ described_class.watirsome?(:div).should == true
58
+ end
59
+
60
+ it 'returns false if method is not watir-contained' do
61
+ described_class.watirsome?(:foo).should == false
62
+ end
63
+ end
64
+
65
+ describe '.plural?' do
66
+ it 'returns true if watir-contained method is plural' do
67
+ described_class.plural?(:divs).should == true
68
+ end
69
+
70
+ it 'returns false if watir-contained method is singular' do
71
+ described_class.plural?(:div).should == false
72
+ end
73
+
74
+ it 'returns false if method is not watir-contained' do
75
+ described_class.plural?(:foo).should == false
76
+ end
77
+ end
78
+
79
+ context 'when included' do
80
+ include_context :page
81
+
82
+ it 'adds accessor class methods' do
83
+ page.class.should respond_to(:div)
84
+ end
85
+
86
+ it 'does not add #extract_selector' do
87
+ page.class.should_not respond_to(:extract_selector)
88
+ end
89
+
90
+ it 'adds accessor instance methods' do
91
+ page.private_methods.should include(:grab_elements)
92
+ end
93
+
94
+ it 'adds regions initializer' do
95
+ page.should respond_to(:initialize_regions)
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,31 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ]
8
+ SimpleCov.start do
9
+ add_filter "/spec/"
10
+ add_filter "/vendor/"
11
+ end
12
+
13
+ require 'watir-webdriver'
14
+ require 'watirsome'
15
+
16
+ Dir['spec/support/**/*.rb'].each do |file|
17
+ require file.sub(/spec\//, '')
18
+ end
19
+
20
+ RSpec.configure do |spec|
21
+ spec.alias_it_should_behave_like_to :it_defines, 'it defines'
22
+
23
+ shared_context :page do
24
+ let(:watir) { stub('watir') }
25
+ let(:page) { Page.new(watir) }
26
+ end
27
+
28
+ shared_context :element do
29
+ let(:element) { stub('element', visible?: true) }
30
+ end
31
+ end
@@ -0,0 +1,49 @@
1
+ module IncludedRegion
2
+ def initialize_region
3
+ @included_initialized ||= 0
4
+ @included_initialized += 1
5
+ end
6
+ end # IncludedRegion
7
+
8
+
9
+ module ExtendedRegion
10
+ def initialize_region
11
+ @extended_initialized = 1
12
+ end
13
+ end # ExtendedRegion
14
+
15
+
16
+ module Helper
17
+ def initialize_region
18
+ @helper_initialized = 1
19
+ end
20
+ end # Helper
21
+
22
+
23
+ class Page
24
+ include Watirsome
25
+ include IncludedRegion
26
+ include Helper
27
+
28
+ def initialize_page
29
+ extend ExtendedRegion
30
+ @initialized = true
31
+ end
32
+
33
+ %w(div a text_field select_list).each do |tag|
34
+ send tag, :"#{tag}1"
35
+ send tag, :"#{tag}2", id: tag
36
+ send tag, :"#{tag}3", id: tag, class: /#{tag}/
37
+ send tag, :"#{tag}4", id: tag, class: tag, visible: true
38
+ send tag, :"#{tag}5", proc { @browser.send(tag, id: tag) }
39
+ send tag, :"#{tag}6", -> { @browser.send(tag, id: tag) }
40
+ # set/select accessor cannot have block arguments
41
+ case tag
42
+ when 'div', 'a'
43
+ send(tag, :"#{tag}7") { |id| @browser.send(tag, id: id) }
44
+ when 'text_field', 'select_list'
45
+ send(tag, :"#{tag}7") { @browser.send(tag, id: tag) }
46
+ end
47
+ end
48
+
49
+ end # Page
@@ -0,0 +1,52 @@
1
+ shared_examples_for :click_accessor do |tags|
2
+ tags.each do |tag|
3
+ context tag do
4
+ def accessor(tag, index, *args)
5
+ page.send :"#{tag}#{index}", *args
6
+ end
7
+
8
+ it 'clicks element with no locators' do
9
+ watir.should_receive(tag).with(no_args).and_return(element)
10
+ element.should_receive(:click).with(any_args)
11
+ accessor(tag, 1)
12
+ end
13
+
14
+ it 'clicks element with single watir locator' do
15
+ watir.should_receive(tag).with(id: tag).and_return(element)
16
+ element.should_receive(:click).with(any_args)
17
+ accessor(tag, 2)
18
+ end
19
+
20
+ it 'clicks element with multiple watir locator' do
21
+ watir.should_receive(tag).with(id: tag, class: /#{tag}/).and_return(element)
22
+ element.should_receive(:click).with(any_args)
23
+ accessor(tag, 3)
24
+ end
25
+
26
+ it 'clicks element with custom locator' do
27
+ element2 = stub('element', visible?: false)
28
+ watir.should_receive(:"#{tag}s").with(id: tag, class: tag).and_return([element, element2])
29
+ element.should_receive(:click).with(any_args)
30
+ accessor(tag, 4)
31
+ end
32
+
33
+ it 'clicks element with proc' do
34
+ watir.should_receive(tag).with(id: tag).and_return(element)
35
+ element.should_receive(:click).with(any_args)
36
+ accessor(tag, 5)
37
+ end
38
+
39
+ it 'clicks element with lambda' do
40
+ watir.should_receive(tag).with(id: tag).and_return(element)
41
+ element.should_receive(:click).with(any_args)
42
+ accessor(tag, 6)
43
+ end
44
+
45
+ it 'clicks element with block and custom arguments' do
46
+ watir.should_receive(tag).with(id: tag).and_return(element)
47
+ element.should_receive(:click).with(any_args)
48
+ accessor(tag, 7, tag)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,47 @@
1
+ shared_examples_for :element_accessor do |tags|
2
+ tags.each do |tag|
3
+ context tag do
4
+ def accessor(tag, index, *args)
5
+ page.send :"#{tag}#{index}_#{tag}", *args
6
+ end
7
+
8
+ it 'finds element with no locators' do
9
+ watir.should_receive(tag).with(no_args).and_return(element)
10
+ accessor(tag, 1).should == element
11
+ end
12
+
13
+ it 'finds element with single watir locator' do
14
+ watir.should_receive(tag).with(id: tag).and_return(element)
15
+ accessor(tag, 2).should == element
16
+ end
17
+
18
+ it 'finds element with multiple watir locator' do
19
+ watir.should_receive(tag).with(id: tag, class: /#{tag}/).and_return(element)
20
+ accessor(tag, 3).should == element
21
+ end
22
+
23
+ it 'finds element with custom locator' do
24
+ element2 = stub('element')
25
+ watir.should_receive(:"#{tag}s").with(id: tag, class: tag).and_return([element, element2])
26
+ element.should_receive(:visible?).with(no_args).and_return(true)
27
+ element2.should_receive(:visible?).with(no_args).and_return(false)
28
+ accessor(tag, 4).should == element
29
+ end
30
+
31
+ it 'finds element with proc' do
32
+ watir.should_receive(tag).with(id: tag).and_return(element)
33
+ accessor(tag, 5).should == element
34
+ end
35
+
36
+ it 'finds element with lambda' do
37
+ watir.should_receive(tag).with(id: tag).and_return(element)
38
+ accessor(tag, 6).should == element
39
+ end
40
+
41
+ it 'finds element with block and custom arguments' do
42
+ watir.should_receive(tag).with(id: tag).and_return(element)
43
+ accessor(tag, 7, tag).should == element
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,67 @@
1
+ shared_examples_for :read_accessor do |tags|
2
+ tags.each do |tag|
3
+ context tag do
4
+ def accessor(tag, index, *args)
5
+ page.send :"#{tag}#{index}", *args
6
+ end
7
+
8
+ def read_expectation(tag)
9
+ case tag
10
+ when 'text_field'
11
+ element.should_receive(:value).and_return('text')
12
+ when 'select_list'
13
+ option1 = stub('option1', selected?: true)
14
+ option2 = stub('option2', selected?: false)
15
+ element.should_receive(:options).and_return([option1, option2])
16
+ option1.should_receive(:text).and_return('text')
17
+ option2.should_not_receive(:text)
18
+ else
19
+ element.should_receive(:text).and_return('text')
20
+ end
21
+ end
22
+
23
+ it 'gets text from element with no locators' do
24
+ watir.should_receive(tag).with(no_args).and_return(element)
25
+ read_expectation(tag)
26
+ accessor(tag, 1).should == 'text'
27
+ end
28
+
29
+ it 'gets text from element with single watir locator' do
30
+ watir.should_receive(tag).with(id: tag).and_return(element)
31
+ read_expectation(tag)
32
+ accessor(tag, 2).should == 'text'
33
+ end
34
+
35
+ it 'gets text from element with multiple watir locator' do
36
+ watir.should_receive(tag).with(id: tag, class: /#{tag}/).and_return(element)
37
+ read_expectation(tag)
38
+ accessor(tag, 3).should == 'text'
39
+ end
40
+
41
+ it 'gets text from element with custom locator' do
42
+ element2 = stub('element', visible?: false)
43
+ watir.should_receive(:"#{tag}s").with(id: tag, class: tag).and_return([element, element2])
44
+ read_expectation(tag)
45
+ accessor(tag, 4).should == 'text'
46
+ end
47
+
48
+ it 'gets text from element with proc' do
49
+ watir.should_receive(tag).with(id: tag).and_return(element)
50
+ read_expectation(tag)
51
+ accessor(tag, 5).should == 'text'
52
+ end
53
+
54
+ it 'gets text from element with lambda' do
55
+ watir.should_receive(tag).with(id: tag).and_return(element)
56
+ read_expectation(tag)
57
+ accessor(tag, 6).should == 'text'
58
+ end
59
+
60
+ it 'gets text from element with block and custom arguments' do
61
+ watir.should_receive(tag).with(id: tag).and_return(element)
62
+ read_expectation(tag)
63
+ accessor(tag, 7, tag).should == 'text'
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,46 @@
1
+ shared_examples_for :select_accessor do |tags|
2
+ tags.each do |tag|
3
+ context tag do
4
+ def accessor(tag, index, *args)
5
+ page.send :"#{tag}#{index}=", *args
6
+ end
7
+
8
+ it 'selects option for element with no locators' do
9
+ watir.should_receive(tag).with(no_args).and_return(element)
10
+ element.should_receive(:select).with('value')
11
+ accessor(tag, 1, 'value')
12
+ end
13
+
14
+ it 'selects option for element with single watir locator' do
15
+ watir.should_receive(tag).with(id: tag).and_return(element)
16
+ element.should_receive(:select).with('value')
17
+ accessor(tag, 2, 'value')
18
+ end
19
+
20
+ it 'selects option for element with multiple watir locator' do
21
+ watir.should_receive(tag).with(id: tag, class: /#{tag}/).and_return(element)
22
+ element.should_receive(:select).with('value')
23
+ accessor(tag, 3, 'value')
24
+ end
25
+
26
+ it 'selects option for element with custom locator' do
27
+ element2 = stub('element', visible?: false)
28
+ watir.should_receive(:"#{tag}s").with(id: tag, class: tag).and_return([element, element2])
29
+ element.should_receive(:select).with('value')
30
+ accessor(tag, 4, 'value')
31
+ end
32
+
33
+ it 'selects option for element with proc' do
34
+ watir.should_receive(tag).with(id: tag).and_return(element)
35
+ element.should_receive(:select).with('value')
36
+ accessor(tag, 5, 'value')
37
+ end
38
+
39
+ it 'selects option for element with lambda' do
40
+ watir.should_receive(tag).with(id: tag).and_return(element)
41
+ element.should_receive(:select).with('value')
42
+ accessor(tag, 6, 'value')
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,53 @@
1
+ shared_examples_for :set_accessor do |tags|
2
+ tags.each do |tag|
3
+ context tag do
4
+ def accessor(tag, index, *args)
5
+ page.send :"#{tag}#{index}=", *args
6
+ end
7
+
8
+ it 'sets value on element with no locators' do
9
+ watir.should_receive(tag).with(no_args).and_return(element)
10
+ element.should_receive(:set).with('value')
11
+ accessor(tag, 1, 'value')
12
+ end
13
+
14
+ it 'sets value on element with single watir locator' do
15
+ watir.should_receive(tag).with(id: tag).and_return(element)
16
+ element.should_receive(:set).with('value')
17
+ accessor(tag, 2, 'value')
18
+ end
19
+
20
+ it 'sets value on element with multiple watir locator' do
21
+ watir.should_receive(tag).with(id: tag, class: /#{tag}/).and_return(element)
22
+ element.should_receive(:set).with('value')
23
+ accessor(tag, 3, 'value')
24
+ end
25
+
26
+ it 'sets value on element with custom locator' do
27
+ element2 = stub('element', visible?: false)
28
+ watir.should_receive(:"#{tag}s").with(id: tag, class: tag).and_return([element, element2])
29
+ element.should_receive(:set).with('value')
30
+ accessor(tag, 4, 'value')
31
+ end
32
+
33
+ it 'sets value on element with proc' do
34
+ watir.should_receive(tag).with(id: tag).and_return(element)
35
+ element.should_receive(:set).with('value')
36
+ accessor(tag, 5, 'value')
37
+ end
38
+
39
+ it 'sets value on element with lambda' do
40
+ watir.should_receive(tag).with(id: tag).and_return(element)
41
+ element.should_receive(:set).with('value')
42
+ accessor(tag, 6, 'value')
43
+ end
44
+
45
+ it 'sends keys if element cannot be set' do
46
+ watir.should_receive(tag).with(no_args).and_return(element)
47
+ element.stub(:respond_to?).with(:set).and_return(false)
48
+ element.should_receive(:send_keys).with('value')
49
+ accessor(tag, 1, 'value')
50
+ end
51
+ end
52
+ end
53
+ end
data/watirsome.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+ require 'watirsome/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'watirsome'
6
+ s.version = Watirsome::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.author = 'Alex Rodionov'
9
+ s.email = 'p0deje@gmail.com'
10
+ s.homepage = 'http://github.com/p0deje/watirsome'
11
+ s.summary = 'Awesome page objects with Watir'
12
+ s.description = 'Pure dynamic Watir-based page object DSL'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = %w(lib)
18
+
19
+ s.add_dependency 'watir-webdriver'
20
+
21
+ s.add_development_dependency 'rspec'
22
+ s.add_development_dependency 'rake'
23
+ s.add_development_dependency 'fuubar'
24
+ s.add_development_dependency 'simplecov'
25
+ s.add_development_dependency 'coveralls'
26
+ end