page_magic 0.8.8

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/page_magic.rb ADDED
@@ -0,0 +1,55 @@
1
+ $LOAD_PATH.unshift("#{File.dirname(__FILE__)}")
2
+ require 'capybara'
3
+ require 'wait'
4
+ require 'page_magic/wait'
5
+ require 'page_magic/browser'
6
+ require 'page_magic/session'
7
+ require 'page_magic/ajax_support'
8
+ require 'page_magic/page_elements'
9
+ require 'page_magic/element_context'
10
+ require 'page_magic/page_element'
11
+ require 'page_magic/page_magic'
12
+ require 'page_magic/page_section'
13
+
14
+ module PageMagic
15
+ class << self
16
+ def session browser=nil, options = {}
17
+ if browser
18
+ Capybara.register_driver browser do |app|
19
+ options[:browser] = browser
20
+ Capybara::Selenium::Driver.new(app, options)
21
+ end
22
+ Session.new(Capybara::Session.new(browser, nil))
23
+ else
24
+ Capybara.reset!
25
+ Session.new(Capybara.current_session)
26
+ end
27
+ end
28
+
29
+ def included clazz
30
+ clazz.extend ClassMethods, PageElements
31
+ pages << clazz if clazz.is_a? Class
32
+
33
+ def clazz.url url=nil
34
+ @url = url if url
35
+ @url
36
+ end
37
+ end
38
+
39
+ def pages
40
+ @pages||=[]
41
+ end
42
+ end
43
+
44
+ module ClassMethods
45
+ def included clazz
46
+ clazz.instance_eval { include PageMagic }
47
+ clazz.element_definitions.merge!(element_definitions)
48
+ end
49
+
50
+ def method_missing method_name, *args
51
+ raise "You can only instantiate child pages" if method_name == :new
52
+ super
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,80 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "page_magic"
8
+ s.version = "0.8.8"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Leon Davis"]
12
+ s.date = "2013-11-10"
13
+ s.description = "Framework for modeling and interacting with webpages which wraps capybara"
14
+ s.email = "info@lad-tech.com"
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".ruby-gemset",
20
+ ".ruby-version",
21
+ ".travis.yml",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "README.md",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/page_magic.rb",
28
+ "lib/page_magic/ajax_support.rb",
29
+ "lib/page_magic/browser.rb",
30
+ "lib/page_magic/element_context.rb",
31
+ "lib/page_magic/page_element.rb",
32
+ "lib/page_magic/page_elements.rb",
33
+ "lib/page_magic/page_magic.rb",
34
+ "lib/page_magic/page_section.rb",
35
+ "lib/page_magic/session.rb",
36
+ "lib/page_magic/wait.rb",
37
+ "page_magic.gemspec",
38
+ "spec/browser_spec.rb",
39
+ "spec/element_context_spec.rb",
40
+ "spec/helpers.rb",
41
+ "spec/helpers/capybara.rb",
42
+ "spec/member_methods_spec.rb",
43
+ "spec/page_element_spec.rb",
44
+ "spec/page_elements_spec.rb",
45
+ "spec/page_magic_spec.rb",
46
+ "spec/page_section_spec.rb",
47
+ "spec/session_spec.rb",
48
+ "spec/spec_helper.rb"
49
+ ]
50
+ s.homepage = "https://github.com/ladtech/page_magic"
51
+ s.licenses = ["ruby"]
52
+ s.require_paths = ["lib"]
53
+ s.rubygems_version = "1.8.25"
54
+ s.summary = "Framework for modeling and interacting with webpages"
55
+
56
+ if s.respond_to? :specification_version then
57
+ s.specification_version = 3
58
+
59
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
60
+ s.add_runtime_dependency(%q<watir-webdriver>, [">= 0"])
61
+ s.add_runtime_dependency(%q<capybara>, [">= 0"])
62
+ s.add_runtime_dependency(%q<wait>, [">= 0"])
63
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
64
+ s.add_runtime_dependency(%q<watir-webdriver>, [">= 0"])
65
+ else
66
+ s.add_dependency(%q<watir-webdriver>, [">= 0"])
67
+ s.add_dependency(%q<capybara>, [">= 0"])
68
+ s.add_dependency(%q<wait>, [">= 0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
70
+ s.add_dependency(%q<watir-webdriver>, [">= 0"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<watir-webdriver>, [">= 0"])
74
+ s.add_dependency(%q<capybara>, [">= 0"])
75
+ s.add_dependency(%q<wait>, [">= 0"])
76
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
77
+ s.add_dependency(%q<watir-webdriver>, [">= 0"])
78
+ end
79
+ end
80
+
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe PageMagic::Browser do
4
+ let(:app) { Object.new }
5
+
6
+ before do
7
+ PageMagic::Browser.session = nil
8
+ app.extend PageMagic::Browser
9
+ end
10
+
11
+ describe 'page' do
12
+ it 'should return the existing session' do
13
+ session = double(:session)
14
+ PageMagic::Browser.session = session
15
+
16
+ app.browser.should == session
17
+ end
18
+
19
+ it 'should create a session if not already set' do
20
+ new_session = double(:new_session)
21
+
22
+ PageMagic.should_receive(:session).with(:chrome).and_return new_session
23
+ app.browser.should == new_session
24
+ end
25
+
26
+ it 'should use custom browser' do
27
+ PageMagic::Browser.use :firefox
28
+
29
+ PageMagic.should_receive(:session).with(:firefox)
30
+ app.browser
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,123 @@
1
+ require 'spec_helper'
2
+ require 'page_magic'
3
+
4
+ describe 'Element Context' do
5
+
6
+ include_context :webapp
7
+
8
+ let!(:page1) do
9
+ Class.new do
10
+ include PageMagic
11
+ url '/page1'
12
+ link(:next, :text => "next page")
13
+ end
14
+ end
15
+
16
+ let!(:elements_page) do
17
+ Class.new do
18
+ include PageMagic
19
+ url '/elements'
20
+ link(:a_link, :text => "a link")
21
+ end
22
+ end
23
+
24
+ let!(:session) do
25
+ double('session', browser: double('browser'))
26
+ end
27
+
28
+ describe 'resolving field definitions' do
29
+
30
+ it 'should only evaluate the targeted field definition' do
31
+ page1.class_eval do
32
+ link(:link, :selector) do
33
+ fail("should not have been evaluated")
34
+ end
35
+ end
36
+ page = page1.new
37
+ page.visit
38
+
39
+ PageMagic::ElementContext.new(page, page.browser, self).next
40
+ end
41
+ end
42
+
43
+ it 'should raise an error if an element is not found' do
44
+ expect { PageMagic::ElementContext.new(page1.new(session), session, self).missing_thing }.to raise_error PageMagic::ElementMissingException
45
+ end
46
+
47
+ it 'should attempt to execute method on page object it is defined' do
48
+ page1.class_eval do
49
+ def page_method
50
+ :called
51
+ end
52
+ end
53
+
54
+ PageMagic::ElementContext.new(page1.new(session), session, self).page_method.should == :called
55
+ end
56
+
57
+ describe 'retrieving elements' do
58
+ it 'should give the capybara object' do
59
+ page = elements_page.new
60
+ page.visit
61
+
62
+ element = PageMagic::ElementContext.new(page, page.browser, self).a_link
63
+ element.text.should == 'a link'
64
+ end
65
+ end
66
+
67
+ describe 'actions' do
68
+ it 'should click the element' do
69
+ page = page1.new
70
+ page.visit
71
+
72
+ PageMagic::ElementContext.new(page, page.browser, self).click_next
73
+ page.current_path.should == '/page2'
74
+ page.text.should == 'page 2 content'
75
+ end
76
+ end
77
+
78
+
79
+ describe 'accessing page sections' do
80
+ it 'should go through page sections' do
81
+
82
+ elements_page.class_eval do
83
+ section :form do
84
+ selector css: '.form'
85
+ end
86
+ end
87
+
88
+ page = elements_page.new
89
+ page.visit
90
+
91
+ PageMagic::ElementContext.new(page, page.browser, self).form('a', 'b')
92
+ end
93
+ end
94
+
95
+ describe 'hooks' do
96
+
97
+ it 'should execute a before and after action that gives access to the browser' do
98
+
99
+ page = elements_page.new
100
+ page.visit
101
+
102
+ selector = {text: 'a link'}
103
+ browser = page.browser
104
+ browser.should_receive(:call_in_before_hook)
105
+ browser.should_receive(:call_in_after_before_hook)
106
+
107
+
108
+ elements_page.link(:create, selector) do
109
+ before do |page_browser|
110
+ page_browser.call_in_before_hook
111
+ end
112
+
113
+ after do |page_browser|
114
+ page_browser.call_in_after_before_hook
115
+ end
116
+ end
117
+
118
+ PageMagic::ElementContext.new(page, page.browser, self).create.click
119
+ end
120
+
121
+ end
122
+
123
+ end
@@ -0,0 +1,10 @@
1
+ module Capybara
2
+ module Selenium
3
+ class Driver
4
+ def == driver
5
+ driver.respond_to?(:options) && self.options == driver.options &&
6
+ driver.respond_to?(:app) && self.app == driver.app
7
+ end
8
+ end
9
+ end
10
+ end
data/spec/helpers.rb ADDED
@@ -0,0 +1 @@
1
+ require 'helpers/capybara'
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'page_magic'
3
+
4
+ describe 'member methods' do
5
+
6
+ let(:page_object_class) do
7
+ Class.new do
8
+ extend PageMagic::PageElements
9
+ end
10
+ end
11
+
12
+ it 'should say you have fields when you do' do
13
+ page_object_class.elements?.should == false
14
+ page_object_class.link(:link, :text => "text")
15
+ page_object_class.elements?.should == true
16
+ end
17
+
18
+
19
+ describe 'the element types that you can define' do
20
+ PageMagic::PageElements::ELEMENT_TYPES.each do |element_type|
21
+
22
+ it "can have a #{element_type}" do
23
+ parent_page_element = double('parent_page_object', browser_element: double('browser_element'))
24
+ friendly_name = "#{element_type}_name".to_sym
25
+
26
+ page_object_class.send(element_type, friendly_name,{})
27
+
28
+
29
+ expected_element = PageMagic::PageElement.new(friendly_name,parent_page_element, element_type, {})
30
+ page_object_class.element_definitions[friendly_name].call(parent_page_element) == expected_element
31
+ end
32
+ end
33
+ end
34
+
35
+
36
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+ require 'sinatra'
3
+
4
+
5
+ describe 'Page elements' do
6
+
7
+ before :each do
8
+ Capybara.app = Class.new(Sinatra::Base) do
9
+ get '/' do
10
+ <<-HTML
11
+ <label>enter text
12
+ <input id='field_id' name='field_name' class='input_class' type='text' value='filled in'/>
13
+ </label>
14
+ <a id=my_link href='#'>my link</a>
15
+ HTML
16
+ end
17
+ end
18
+
19
+ Capybara.current_session.visit('/')
20
+ end
21
+
22
+ describe 'location' do
23
+ let!(:browser) { double('browser') }
24
+ let!(:page) do
25
+ page_class = Class.new do
26
+ include PageMagic
27
+ end
28
+ page_class.new
29
+ end
30
+
31
+ it 'should locate an element using its id' do
32
+ element = PageMagic::PageElement.new(:my_input,page, :text_field, id:'field_id').locate
33
+ element.value == 'filled in'
34
+ end
35
+
36
+ it 'should locate an element using its name' do
37
+ element = PageMagic::PageElement.new(:my_input,page, :text_field, name:'field_name').locate
38
+ element.value == 'filled in'
39
+ end
40
+
41
+ it 'should locate a link using its text' do
42
+ element = PageMagic::PageElement.new(:my_link,page, :link, text: 'my link').locate
43
+ element[:id].should == 'my_link'
44
+ end
45
+
46
+ it 'should locate an element using its label' do
47
+ element = PageMagic::PageElement.new(:my_link,page, :link, label: 'enter text').locate
48
+ element[:id].should == 'field_id'
49
+ end
50
+
51
+ it 'should raise an exception when finding another element using its text' do
52
+ expect{PageMagic::PageElement.new(:my_link,page, :text_field, text: 'my link').locate}.to raise_error(PageMagic::UnsupportedSelectorException)
53
+ end
54
+
55
+ it 'should locate an element using css' do
56
+ element = PageMagic::PageElement.new(:my_link,page, :link, css: "input[name='field_name']").locate
57
+ element[:id].should == 'field_id'
58
+ end
59
+
60
+ it 'should raise errors for unsupported selectors' do
61
+ expect{PageMagic::PageElement.new(:my_link,page, :link, unsupported:"").locate}.to raise_error(PageMagic::UnsupportedSelectorException)
62
+ end
63
+
64
+
65
+
66
+ it 'should return the browser element if a selector was not specified' do
67
+ PageMagic::PageElement.new(:help, browser, :link, nil).locate.should == browser
68
+ end
69
+
70
+ #TODO - Bug here, parent element reference is not available
71
+ it 'should return a prefetched value' do
72
+ PageMagic::PageElement.new(:help, "prefetched text", :link ).locate.should == "prefetched text"
73
+ end
74
+
75
+ it 'should have a handle to the session' do
76
+ PageMagic::PageElement.new(:help, page, :link, :selector ).session.should == page.session
77
+ end
78
+ end
79
+
80
+ end
@@ -0,0 +1,202 @@
1
+ require 'spec_helper'
2
+ require 'page_magic'
3
+
4
+ describe PageMagic::PageElements do
5
+
6
+
7
+ let(:page_elements) do
8
+ page_element = Class.new do
9
+ extend(PageMagic::PageElements)
10
+ end
11
+ end
12
+
13
+ let(:selector) { {id: 'id'} }
14
+ let(:browser_element) { double('browser_element', find: :browser_element) }
15
+ let(:parent_page_element) do
16
+ double('parent_page_element', browser_element: browser_element)
17
+ end
18
+
19
+
20
+ describe 'adding elements' do
21
+
22
+ context 'using a selector' do
23
+ it 'should add an element' do
24
+ page_elements.text_field :name, selector
25
+ page_elements.element_definitions[:name].call(parent_page_element).should == PageMagic::PageElement.new(:name, parent_page_element, :text_field, selector)
26
+ end
27
+
28
+ it 'should return your a copy of the core definition' do
29
+ page_elements.text_field :name, selector
30
+ first = page_elements.element_definitions[:name].call(parent_page_element)
31
+ second = page_elements.element_definitions[:name].call(parent_page_element)
32
+ first.should_not equal(second)
33
+ end
34
+ end
35
+
36
+ context 'passing in a prefetched watir object' do
37
+ it 'should create a page element with the prefetched watir object as the core browser object' do
38
+ watir_element = double('watir_element')
39
+ page_elements.text_field :name, watir_element
40
+ page_elements.elements(browser_element).first.locate.should == watir_element
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ context 'section' do
47
+
48
+ let!(:section_class) do
49
+ Class.new do
50
+ extend PageMagic::PageSection
51
+
52
+ def == object
53
+ object.class.is_a?(PageMagic::PageSection) &&
54
+ object.name == self.name
55
+ end
56
+ end
57
+ end
58
+
59
+ context 'session handle' do
60
+ it 'should be on instances created from a class' do
61
+
62
+ browser_element = double(:browser_element, find: :browser_element)
63
+ parent = double('parent', session: :current_session, browser_element: browser_element)
64
+ page_elements.section section_class, :page_section, selector
65
+
66
+ section = page_elements.element_definitions[:page_section].call(parent)
67
+
68
+ section.session.should == :current_session
69
+
70
+ end
71
+
72
+ it 'should be on instances created dynamically using the section method' do
73
+
74
+ browser_element = double('browser_element')
75
+ browser_element.stub(:find)
76
+ parent = double('parent', session: :current_session, browser_element: browser_element)
77
+
78
+ page_elements.section :page_section, css: :selector do
79
+
80
+ end
81
+
82
+ section = page_elements.element_definitions[:page_section].call(parent)
83
+ section.session.should == :current_session
84
+ end
85
+ end
86
+
87
+ context 'using a class as a definition' do
88
+ it 'should add a section' do
89
+ page_elements.section section_class, :page_section, selector
90
+ page_elements.elements(parent_page_element).first.should == section_class.new(parent_page_element, :page_section, selector)
91
+ end
92
+ end
93
+
94
+ context 'using a block to define a section inline' do
95
+
96
+ context 'browser_element' do
97
+ before :each do
98
+
99
+ @browser, @element, @parent_page_element = double('browser'), double('element'), double('parent_page_element')
100
+ @parent_page_element.stub(:browser_element).and_return(@browser)
101
+ @browser.should_receive(:find).with(:css, :selector).twice.and_return(@element)
102
+ end
103
+
104
+ it 'should be assigned when selector is passed to section method' do
105
+ element = @element
106
+
107
+ page_elements.section :page_section, css: :selector do
108
+ browser_element.should == element
109
+ end
110
+
111
+ page_elements.element_definitions[:page_section].call(@parent_page_element)
112
+ end
113
+
114
+ it 'should be assigned when selector is defined in the block passed to the section method' do
115
+ element = @element
116
+
117
+ page_elements.section :page_section do
118
+ browser_element.should == nil
119
+ selector css: :selector
120
+ browser_element.should == element
121
+ end
122
+
123
+ page_elements.elements(@parent_page_element, nil)
124
+ end
125
+ end
126
+
127
+ it 'should raise an exception if the selector is not passed' do
128
+
129
+ arg, browser, element = {}, double('browser'), double('element')
130
+ parent_page_element = double('parent_browser_element', browser_element: browser)
131
+
132
+ page_elements.section :page_section, nil do
133
+ end
134
+
135
+ expect { page_elements.elements(parent_page_element, arg) }.to raise_error(PageMagic::PageSection::UndefinedSelectorException)
136
+ end
137
+
138
+
139
+
140
+ it 'should pass args through to the block' do
141
+ page_elements.section :page_section, css: '.blah' do |arg|
142
+ arg[:passed_through] = true
143
+ end
144
+
145
+ arg, browser = {}, double('browser', find: :browser_element)
146
+ parent_page_element = double('parent_browser_element', browser_element: browser)
147
+ page_elements.elements(parent_page_element, arg)
148
+ arg[:passed_through].should be_true
149
+ end
150
+
151
+ end
152
+
153
+ it 'should return your a copy of the core definition' do
154
+ page_elements.section section_class, :page_section, selector
155
+ first = page_elements.element_definitions[:page_section].call(parent_page_element)
156
+ second = page_elements.element_definitions[:page_section].call(parent_page_element)
157
+ first.should_not equal(second)
158
+ end
159
+ end
160
+
161
+ describe 'restrictions' do
162
+ it 'should not allow method names that match element names' do
163
+ expect do
164
+ page_elements.class_eval do
165
+ link(:hello, text: 'world')
166
+
167
+ def hello;
168
+ end
169
+ end
170
+ end.to raise_error(PageMagic::PageElements::InvalidMethodNameException)
171
+ end
172
+
173
+ it 'should not allow element names that match method names' do
174
+ expect do
175
+ page_elements.class_eval do
176
+ def hello;
177
+ end
178
+
179
+ link(:hello, text: 'world')
180
+ end
181
+ end.to raise_error(PageMagic::PageElements::InvalidElementNameException)
182
+ end
183
+
184
+ it 'should not allow duplicate element names' do
185
+ expect do
186
+ page_elements.class_eval do
187
+ link(:hello, text: 'world')
188
+ link(:hello, text: 'world')
189
+ end
190
+ end.to raise_error(PageMagic::PageElements::InvalidElementNameException)
191
+ end
192
+
193
+ it 'should not evaluate the elements when applying naming checks' do
194
+ page_elements.class_eval do
195
+ link(:link1, :selector) do
196
+ fail("should not have been evaluated")
197
+ end
198
+ link(:link2, :selector)
199
+ end
200
+ end
201
+ end
202
+ end