page_magic 1.2.9 → 2.0.0.alpha1
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.
- checksums.yaml +5 -5
- data/.rubocop.yml +3 -3
- data/.simplecov +4 -2
- data/.zsh_config +6 -0
- data/Dockerfile +10 -0
- data/Gemfile +10 -11
- data/Gemfile.lock +120 -133
- data/Makefile +13 -0
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/lib/page_magic.rb +5 -3
- data/lib/page_magic/class_methods.rb +4 -1
- data/lib/page_magic/driver.rb +3 -0
- data/lib/page_magic/drivers.rb +3 -1
- data/lib/page_magic/drivers/poltergeist.rb +2 -0
- data/lib/page_magic/drivers/rack_test.rb +3 -1
- data/lib/page_magic/drivers/selenium.rb +4 -2
- data/lib/page_magic/element.rb +8 -5
- data/lib/page_magic/element/locators.rb +4 -1
- data/lib/page_magic/element/query.rb +11 -2
- data/lib/page_magic/element/query_builder.rb +15 -2
- data/lib/page_magic/element/selector.rb +3 -0
- data/lib/page_magic/element/selector_methods.rb +3 -0
- data/lib/page_magic/element_context.rb +2 -0
- data/lib/page_magic/element_definition_builder.rb +4 -1
- data/lib/page_magic/elements.rb +42 -6
- data/lib/page_magic/exceptions.rb +3 -1
- data/lib/page_magic/instance_methods.rb +2 -0
- data/lib/page_magic/matcher.rb +10 -1
- data/lib/page_magic/session.rb +7 -5
- data/lib/page_magic/session_methods.rb +2 -0
- data/lib/page_magic/utils/string.rb +2 -0
- data/lib/page_magic/wait_methods.rb +3 -0
- data/lib/page_magic/watcher.rb +2 -0
- data/lib/page_magic/watchers.rb +4 -1
- data/spec/element_spec.rb +2 -0
- data/spec/page_magic/class_methods_spec.rb +2 -0
- data/spec/page_magic/driver_spec.rb +2 -0
- data/spec/page_magic/drivers/poltergeist_spec.rb +2 -0
- data/spec/page_magic/drivers/rack_test_spec.rb +2 -0
- data/spec/page_magic/drivers/selenium_spec.rb +2 -0
- data/spec/page_magic/drivers_spec.rb +2 -0
- data/spec/page_magic/element/locators_spec.rb +2 -0
- data/spec/page_magic/element/query_builder_spec.rb +7 -5
- data/spec/page_magic/element/query_spec.rb +6 -4
- data/spec/page_magic/element/selector_spec.rb +7 -5
- data/spec/page_magic/element_context_spec.rb +3 -1
- data/spec/page_magic/element_definition_builder_spec.rb +2 -0
- data/spec/page_magic/elements_spec.rb +9 -0
- data/spec/page_magic/instance_methods_spec.rb +2 -0
- data/spec/page_magic/matcher_spec.rb +3 -1
- data/spec/page_magic/session_methods_spec.rb +2 -0
- data/spec/page_magic/session_spec.rb +1 -1
- data/spec/page_magic/utils/string_spec.rb +2 -0
- data/spec/page_magic/wait_methods_spec.rb +5 -3
- data/spec/page_magic/watchers_spec.rb +2 -0
- data/spec/page_magic_spec.rb +5 -7
- data/spec/spec_helper.rb +3 -0
- data/spec/support/shared_contexts.rb +3 -1
- data/spec/support/shared_contexts/files_context.rb +2 -0
- data/spec/support/shared_contexts/nested_elements_html_context.rb +2 -0
- data/spec/support/shared_contexts/rack_application_context.rb +2 -0
- data/spec/support/shared_contexts/webapp_fixture_context.rb +2 -0
- data/spec/support/shared_examples.rb +2 -0
- data/spec/watcher_spec.rb +3 -0
- metadata +45 -29
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PageMagic
|
2
4
|
# module ClassMethods - contains class level methods for PageObjects
|
3
5
|
module ClassMethods
|
@@ -15,6 +17,7 @@ module PageMagic
|
|
15
17
|
# if one has not been set on the page object class it will return a default block that does nothing
|
16
18
|
def on_load(&block)
|
17
19
|
return @on_load || DEFAULT_ON_LOAD unless block
|
20
|
+
|
18
21
|
@on_load = block
|
19
22
|
end
|
20
23
|
|
@@ -34,7 +37,7 @@ module PageMagic
|
|
34
37
|
session_options = { browser: browser, options: options, url: url }
|
35
38
|
session_options[:application] = application if application
|
36
39
|
|
37
|
-
PageMagic.session(session_options).tap do |session|
|
40
|
+
PageMagic.session(**session_options).tap do |session|
|
38
41
|
session.visit(self, url: url)
|
39
42
|
end
|
40
43
|
end
|
data/lib/page_magic/driver.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PageMagic
|
2
4
|
# class Driver - instances are factories for drivers used by PageMagic
|
3
5
|
class Driver
|
4
6
|
attr_reader :supported_browsers, :handler
|
7
|
+
|
5
8
|
# Creates a driver definition
|
6
9
|
# @example
|
7
10
|
# Driver.new do |rack_application, options|
|
data/lib/page_magic/drivers.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'page_magic/driver'
|
2
4
|
require 'page_magic/utils/string'
|
3
5
|
module PageMagic
|
@@ -17,7 +19,7 @@ module PageMagic
|
|
17
19
|
# Loads drivers defined in files at the given path
|
18
20
|
# @param [String] path where the drivers are located
|
19
21
|
def load(path = "#{__dir__}/drivers")
|
20
|
-
Dir["#{path}/*.rb"].each do |driver_file|
|
22
|
+
Dir["#{path}/*.rb"].sort.each do |driver_file|
|
21
23
|
require driver_file
|
22
24
|
driver_name = File.basename(driver_file)[/(.*)\.rb$/, 1]
|
23
25
|
register self.class.const_get(Utils::String.classify(driver_name))
|
@@ -1,4 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
PageMagic::Drivers::Selenium = PageMagic::Driver.new(:chrome, :firefox) do |app, options, browser|
|
2
|
-
require 'watir
|
3
|
-
Capybara::Selenium::Driver.new(app, options.dup.merge(browser: browser))
|
4
|
+
require 'watir'
|
5
|
+
Capybara::Selenium::Driver.new(app, **options.dup.merge(browser: browser))
|
4
6
|
end
|
data/lib/page_magic/element.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
2
4
|
require 'page_magic/element/selector_methods'
|
3
5
|
require 'page_magic/element/locators'
|
@@ -8,7 +10,7 @@ module PageMagic
|
|
8
10
|
class Element
|
9
11
|
EVENT_TYPES = %i[set select select_option unselect_option click].freeze
|
10
12
|
DEFAULT_HOOK = proc {}.freeze
|
11
|
-
EVENT_NOT_SUPPORTED_MSG = '%s event not supported'
|
13
|
+
EVENT_NOT_SUPPORTED_MSG = '%s event not supported'
|
12
14
|
|
13
15
|
include Locators
|
14
16
|
include WaitMethods
|
@@ -44,6 +46,7 @@ module PageMagic
|
|
44
46
|
# @return [Element]
|
45
47
|
def parent_element(page_element = nil)
|
46
48
|
return @parent_page_element unless page_element
|
49
|
+
|
47
50
|
@parent_page_element = page_element
|
48
51
|
end
|
49
52
|
|
@@ -84,9 +87,7 @@ module PageMagic
|
|
84
87
|
# @raise [NotSupportedException] if the wrapped Capybara element does not support the method
|
85
88
|
EVENT_TYPES.each do |method|
|
86
89
|
define_method method do |*args|
|
87
|
-
unless browser_element.respond_to?(method)
|
88
|
-
raise NotSupportedException, EVENT_NOT_SUPPORTED_MSG % method
|
89
|
-
end
|
90
|
+
raise NotSupportedException, EVENT_NOT_SUPPORTED_MSG % method unless browser_element.respond_to?(method)
|
90
91
|
|
91
92
|
browser_element.send(method, *args)
|
92
93
|
end
|
@@ -97,7 +98,8 @@ module PageMagic
|
|
97
98
|
rescue ElementMissingException
|
98
99
|
begin
|
99
100
|
return browser_element.send(method, *args, &block) if browser_element.respond_to?(method)
|
100
|
-
|
101
|
+
|
102
|
+
parent_element.send(method, *args, &block)
|
101
103
|
rescue NoMethodError
|
102
104
|
super
|
103
105
|
end
|
@@ -137,6 +139,7 @@ module PageMagic
|
|
137
139
|
def wrap_events(raw_element)
|
138
140
|
EVENT_TYPES.each do |action_method|
|
139
141
|
next unless raw_element.respond_to?(action_method)
|
142
|
+
|
140
143
|
apply_hooks(raw_element: raw_element,
|
141
144
|
capybara_method: action_method,
|
142
145
|
before_events: before_events,
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PageMagic
|
2
4
|
# for the benefit of pull review :@
|
3
5
|
class Element
|
4
6
|
# contains method for finding element definitions
|
5
7
|
module Locators
|
6
8
|
# message used when raising {ElementMissingException} from methods within this module
|
7
|
-
ELEMENT_NOT_DEFINED_MSG = 'Element not defined: %s'
|
9
|
+
ELEMENT_NOT_DEFINED_MSG = 'Element not defined: %s'
|
8
10
|
|
9
11
|
# find an element definition based on its name
|
10
12
|
# @param [Symbol] name name of the element
|
@@ -13,6 +15,7 @@ module PageMagic
|
|
13
15
|
def element_by_name(name, *args)
|
14
16
|
defintion = element_definitions[name]
|
15
17
|
raise ElementMissingException, (ELEMENT_NOT_DEFINED_MSG % name) unless defintion
|
18
|
+
|
16
19
|
defintion.call(self, *args)
|
17
20
|
end
|
18
21
|
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PageMagic
|
2
4
|
class Element
|
3
5
|
# class Query - executes query on capybara driver
|
4
6
|
class Query
|
5
7
|
# Message template for execptions raised as a result of calling method_missing
|
6
|
-
ELEMENT_NOT_FOUND_MSG = 'Unable to find %s'
|
8
|
+
ELEMENT_NOT_FOUND_MSG = 'Unable to find %s'
|
7
9
|
|
8
10
|
attr_reader :args, :multiple_results
|
9
11
|
|
@@ -20,7 +22,14 @@ module PageMagic
|
|
20
22
|
raise Capybara::ElementNotFound if result.empty?
|
21
23
|
end
|
22
24
|
else
|
23
|
-
|
25
|
+
# TODO - make sure there is a test around this.
|
26
|
+
if args.last.is_a?(Hash)
|
27
|
+
capybara_element.find(*args[0...-1], **args.last)
|
28
|
+
else
|
29
|
+
capybara_element.find(*args)
|
30
|
+
end
|
31
|
+
|
32
|
+
|
24
33
|
end
|
25
34
|
rescue Capybara::Ambiguous => e
|
26
35
|
raise AmbiguousQueryException, e.message
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'page_magic/element/query'
|
3
4
|
module PageMagic
|
4
5
|
class Element
|
@@ -14,6 +15,7 @@ module PageMagic
|
|
14
15
|
def find(type)
|
15
16
|
query = constants.find { |constant| constant.to_s.casecmp(type.to_s).zero? }
|
16
17
|
return ELEMENT unless query
|
18
|
+
|
17
19
|
const_get(query)
|
18
20
|
end
|
19
21
|
end
|
@@ -40,8 +42,19 @@ module PageMagic
|
|
40
42
|
end
|
41
43
|
|
42
44
|
ELEMENT = QueryBuilder.new
|
43
|
-
TEXT_FIELD =
|
45
|
+
TEXT_FIELD =
|
46
|
+
CHECKBOX =
|
47
|
+
SELECT_LIST =
|
48
|
+
RADIO =
|
49
|
+
TEXTAREA =
|
50
|
+
FIELD =
|
51
|
+
FILE_FIELD =
|
52
|
+
FILLABLE_FIELD =
|
53
|
+
RADIO_BUTTON =
|
54
|
+
SELECT = QueryBuilder.new(:field)
|
55
|
+
|
44
56
|
LINK = QueryBuilder.new(:link)
|
57
|
+
LABEL = QueryBuilder.new(:label)
|
45
58
|
BUTTON = QueryBuilder.new(:button)
|
46
59
|
end
|
47
60
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PageMagic
|
2
4
|
class Element
|
3
5
|
# class Selector - models the selection criteria understood by Capybara
|
@@ -10,6 +12,7 @@ module PageMagic
|
|
10
12
|
def find(name)
|
11
13
|
selector = constants.find { |constant| constant.to_s.casecmp(name.to_s).zero? }
|
12
14
|
raise UnsupportedCriteriaException unless selector
|
15
|
+
|
13
16
|
const_get(selector)
|
14
17
|
end
|
15
18
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PageMagic
|
2
4
|
class Element
|
3
5
|
# module SelectorMethods - adds method for getting and setting an element selector
|
@@ -6,6 +8,7 @@ module PageMagic
|
|
6
8
|
# @param [Hash] selector method for locating the browser element. E.g. text: 'the text'
|
7
9
|
def selector(selector = nil)
|
8
10
|
return @selector unless selector
|
11
|
+
|
9
12
|
@selector = selector
|
10
13
|
end
|
11
14
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PageMagic
|
2
4
|
# Builder for creating ElementDefinitions
|
3
5
|
class ElementDefinitionBuilder
|
4
|
-
INVALID_SELECTOR_MSG = 'Pass a locator/define one on the class'
|
6
|
+
INVALID_SELECTOR_MSG = 'Pass a locator/define one on the class'
|
5
7
|
attr_reader :definition_class, :options, :selector, :type, :element, :query_builder
|
6
8
|
|
7
9
|
def initialize(definition_class:, selector:, type:, options: {}, element: nil)
|
@@ -34,6 +36,7 @@ module PageMagic
|
|
34
36
|
|
35
37
|
def ==(other)
|
36
38
|
return false unless other.is_a?(ElementDefinitionBuilder)
|
39
|
+
|
37
40
|
this = [options, selector, type, element, definition_class]
|
38
41
|
this == [other.options, other.selector, other.type, other.element, other.definition_class]
|
39
42
|
end
|
data/lib/page_magic/elements.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/inflector'
|
2
4
|
require 'page_magic/element_definition_builder'
|
3
5
|
module PageMagic
|
@@ -12,11 +14,44 @@ module PageMagic
|
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
15
|
-
INVALID_METHOD_NAME_MSG = 'a method already exists with this method name'
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
INVALID_METHOD_NAME_MSG = 'a method already exists with this method name'
|
18
|
+
|
19
|
+
# css
|
20
|
+
# datalist_input
|
21
|
+
# datalist_option
|
22
|
+
# field
|
23
|
+
# fieldset
|
24
|
+
# file_field
|
25
|
+
# fillable_field
|
26
|
+
# frame
|
27
|
+
# link_or_button
|
28
|
+
# option
|
29
|
+
# radio_button
|
30
|
+
# select
|
31
|
+
# table
|
32
|
+
# table_row
|
33
|
+
# xpath
|
34
|
+
#
|
35
|
+
|
36
|
+
TYPES = %i[field
|
37
|
+
fieldset
|
38
|
+
file_field
|
39
|
+
fillable_field
|
40
|
+
frame
|
41
|
+
link_or_button
|
42
|
+
option
|
43
|
+
radio_button
|
44
|
+
select
|
45
|
+
table
|
46
|
+
table_row
|
47
|
+
text_field
|
48
|
+
button
|
49
|
+
link
|
50
|
+
checkbox
|
51
|
+
select_list
|
52
|
+
radio
|
53
|
+
textarea
|
54
|
+
label].collect{ |type| [type, :"#{type}s"]}.flatten.freeze
|
20
55
|
|
21
56
|
class << self
|
22
57
|
def extended(clazz)
|
@@ -63,7 +98,8 @@ module PageMagic
|
|
63
98
|
parent_element(parent_element)
|
64
99
|
class_exec(*e_args, &block)
|
65
100
|
end
|
66
|
-
|
101
|
+
|
102
|
+
ElementDefinitionBuilder.new(**options.merge(definition_class: definition_class))
|
67
103
|
end
|
68
104
|
end
|
69
105
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PageMagic
|
2
4
|
class ElementMissingException < RuntimeError
|
3
5
|
end
|
@@ -20,7 +22,7 @@ module PageMagic
|
|
20
22
|
class TimeoutException < RuntimeError
|
21
23
|
end
|
22
24
|
|
23
|
-
class
|
25
|
+
class UnsupportedBrowserException < RuntimeError
|
24
26
|
end
|
25
27
|
|
26
28
|
class UnsupportedCriteriaException < RuntimeError
|
data/lib/page_magic/matcher.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/core_ext/object/to_query'
|
2
4
|
module PageMagic
|
3
5
|
# models mapping used to relate pages to uris
|
@@ -10,6 +12,7 @@ module PageMagic
|
|
10
12
|
# @raise [MatcherInvalidException] if at least one component is not specified
|
11
13
|
def initialize(path = nil, parameters: nil, fragment: nil)
|
12
14
|
raise MatcherInvalidException unless path || parameters || fragment
|
15
|
+
|
13
16
|
@path = path
|
14
17
|
@parameters = parameters
|
15
18
|
@fragment = fragment
|
@@ -22,7 +25,7 @@ module PageMagic
|
|
22
25
|
|
23
26
|
# @return [String] uri represented by this mapping
|
24
27
|
def compute_uri
|
25
|
-
path.to_s.tap do |uri|
|
28
|
+
path.to_s.dup.tap do |uri|
|
26
29
|
uri << "?#{parameters.to_query}" if parameters
|
27
30
|
uri << "##{fragment}" if fragment
|
28
31
|
end
|
@@ -55,6 +58,7 @@ module PageMagic
|
|
55
58
|
# @return [Boolean]
|
56
59
|
def ==(other)
|
57
60
|
return false unless other.is_a?(Matcher)
|
61
|
+
|
58
62
|
path == other.path && parameters == other.parameters && fragment == other.fragment
|
59
63
|
end
|
60
64
|
|
@@ -64,11 +68,13 @@ module PageMagic
|
|
64
68
|
|
65
69
|
def compare(this, other)
|
66
70
|
return presence_comparison(this, other) unless this && other
|
71
|
+
|
67
72
|
fuzzy_comparison(this, other)
|
68
73
|
end
|
69
74
|
|
70
75
|
def compatible?(string, comparitor)
|
71
76
|
return true if comparitor.nil?
|
77
|
+
|
72
78
|
if fuzzy?(comparitor)
|
73
79
|
string =~ comparitor ? true : false
|
74
80
|
else
|
@@ -82,6 +88,7 @@ module PageMagic
|
|
82
88
|
|
83
89
|
def fuzzy?(component)
|
84
90
|
return false unless component
|
91
|
+
|
85
92
|
if component.is_a?(Hash)
|
86
93
|
component.values.any? { |o| fuzzy?(o) }
|
87
94
|
else
|
@@ -108,11 +115,13 @@ module PageMagic
|
|
108
115
|
def presence_comparison(this, other)
|
109
116
|
return 0 if this.nil? && other.nil?
|
110
117
|
return 1 if this.nil? && other
|
118
|
+
|
111
119
|
-1
|
112
120
|
end
|
113
121
|
|
114
122
|
def query_string_valid?(string)
|
115
123
|
return true unless parameters
|
124
|
+
|
116
125
|
parameters.none? do |key, value|
|
117
126
|
!compatible?(parameters_hash(string)[key.downcase.to_s], value)
|
118
127
|
end
|
data/lib/page_magic/session.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
2
4
|
require 'page_magic/matcher'
|
3
5
|
module PageMagic
|
4
6
|
# class Session - coordinates access to the browser though page objects.
|
5
7
|
class Session
|
6
|
-
URL_MISSING_MSG = 'a path must be mapped or a url supplied'
|
7
|
-
REGEXP_MAPPING_MSG = 'URL could not be derived because mapping contains Regexps'
|
8
|
-
INVALID_MAPPING_MSG = 'mapping must be a string or regexp'
|
9
|
-
UNSUPPORTED_OPERATION_MSG = 'execute_script not supported by driver'
|
8
|
+
URL_MISSING_MSG = 'a path must be mapped or a url supplied'
|
9
|
+
REGEXP_MAPPING_MSG = 'URL could not be derived because mapping contains Regexps'
|
10
|
+
INVALID_MAPPING_MSG = 'mapping must be a string or regexp'
|
11
|
+
UNSUPPORTED_OPERATION_MSG = 'execute_script not supported by driver'
|
10
12
|
|
11
13
|
extend Forwardable
|
12
14
|
|
@@ -18,7 +20,6 @@ module PageMagic
|
|
18
20
|
def initialize(capybara_session, base_url = nil)
|
19
21
|
@raw_session = capybara_session
|
20
22
|
@base_url = base_url
|
21
|
-
visit(url: base_url) if base_url
|
22
23
|
@transitions = {}
|
23
24
|
end
|
24
25
|
|
@@ -94,6 +95,7 @@ module PageMagic
|
|
94
95
|
target_url = url || begin
|
95
96
|
if (mapping = transitions.key(page))
|
96
97
|
raise InvalidURLException, REGEXP_MAPPING_MSG unless mapping.can_compute_uri?
|
98
|
+
|
97
99
|
url(base_url, mapping.compute_uri)
|
98
100
|
end
|
99
101
|
end
|