watirsome 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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