symbiont 1.0.0 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9cfaf815aa4e5d2e137a959e075c008951d41982
4
- data.tar.gz: 42e72aa8b6a3f1cc15ddfbb549de23e93b223da2
3
+ metadata.gz: 2f501abc5dee4a79e9327a94d825ebc19b821636
4
+ data.tar.gz: 7f3030071dfa29ec97fb617ee7038ee33870139f
5
5
  SHA512:
6
- metadata.gz: ed69a62157cfe29f2ba6cb9512778959bca07147f663453e8be8a2923b83a6c963d6350dae35938ec960e22705347dcfa9d905b76f37c90d804f8dffcd8482a4
7
- data.tar.gz: 29cd1a724214ee35954490f305a31446412840bf1fe70d1328944d060efe135777f8d7cd66e0b06771e804759838196e4749a3534b6fdfd7b39718e3c311f24a
6
+ metadata.gz: 070eb7b9e03d9a070b6a82d31561f32bede1a0a17b474f19e602f2035f230e23315aabbfd47c8dc554b45842f3e1a6ada8e371c01929f1815ff5f6ceee1de0de
7
+ data.tar.gz: 16f45a9497ed0d2c3f224fb1b1edb7f3788c1c9d5c49b63ba81f3fabbcc9aa1041b2efe7472ed5c99c93535f7ec832af5be21d52ea74be57c450edbad2a51e36
data/.gitignore CHANGED
@@ -16,6 +16,7 @@ spec/reports
16
16
  spec/examples.txt
17
17
  test/tmp
18
18
  test/version_tmp
19
+ test/symbiont-script.rb
19
20
  tmp
20
21
  *.bundle
21
22
  *.so
data/Rakefile CHANGED
@@ -6,10 +6,19 @@ require 'rspec/core/rake_task'
6
6
 
7
7
  RuboCop::RakeTask.new
8
8
 
9
- namespace :test do
10
- desc 'Run the Symbiont script.'
11
- task :script do
12
- system('ruby ./test/symbiont-script.rb')
9
+ namespace :scripts do
10
+ desc 'Run the Symbiont Watir script.'
11
+ task :watir do
12
+ system('ruby ./test/symbiont-with-watir.rb')
13
+ end
14
+
15
+ desc 'Run the Symbiont Capybara script.'
16
+ task :capybara do
17
+ system('ruby ./test/symbiont-with-capybara.rb')
18
+ end
19
+
20
+ desc 'Run all Symbiont scripts'
21
+ task all: [:watir, :capybara] do
13
22
  end
14
23
  end
15
24
 
data/lib/symbiont.rb CHANGED
@@ -20,12 +20,15 @@ require 'symbiont/data_builder'
20
20
 
21
21
  require 'symbiont/service_objects'
22
22
 
23
+ require 'symbiont/capybara/page'
24
+ require 'symbiont/capybara/region'
25
+
23
26
  module Symbiont
24
27
  # @param caller [Class] the class including the framework
25
28
  def self.included(caller)
26
29
  caller.extend Symbiont::Assertion
27
- caller.extend Symbiont::Element
28
- caller.send :include, Symbiont::Page
30
+ caller.extend Symbiont::Elements
31
+ caller.send :include, Symbiont::Pages
29
32
  caller.send :include, Symbiont::Accessor
30
33
  caller.send :include, Symbiont::DataSetter
31
34
  caller.send :include, Symbiont::DataBuilder
@@ -49,6 +52,7 @@ module Symbiont
49
52
  Symbiont v#{Symbiont::VERSION}
50
53
  Watir-WebDriver: #{Gem.loaded_specs['watir-webdriver'].version}
51
54
  Selenium-WebDriver: #{Gem.loaded_specs['selenium-webdriver'].version}
55
+ Capybara: #{Gem.loaded_specs['capybara'].version}
52
56
  """
53
57
  end
54
58
 
@@ -70,6 +74,17 @@ Selenium-WebDriver: #{Gem.loaded_specs['selenium-webdriver'].version}
70
74
  @browser = Watir::Browser.new(app, *args)
71
75
  Symbiont.browser = @browser
72
76
  end
77
+
78
+ # Configure mechanism for Capybara
79
+ class << self
80
+ attr_accessor :use_implicit_waits
81
+
82
+ def configure
83
+ yield self
84
+ end
85
+ end
86
+
87
+ @use_implicit_waits = false
73
88
  end
74
89
 
75
90
  def attach(mod = Symbiont)
@@ -0,0 +1,142 @@
1
+ require 'timeout'
2
+
3
+ module Symbiont
4
+ module Element
5
+ def element(name, *identifier)
6
+ build(name, *identifier) do
7
+ define_method(name.to_s) do |*options|
8
+ find_first(*identifier, *options)
9
+ end
10
+ end
11
+ end
12
+
13
+ def elements(name, *identifier)
14
+ build(name, *identifier) do
15
+ define_method(name.to_s) do |*options|
16
+ find_all(*identifier, *options)
17
+ end
18
+ end
19
+ end
20
+
21
+ def region(name, *identifier, &block)
22
+ region_class, region_args = extract_region_details(identifier, &block)
23
+
24
+ build(name, *region_args) do
25
+ define_method(name) do |*options|
26
+ region_class.new(self, find_first(*region_args, *options))
27
+ end
28
+ end
29
+ end
30
+
31
+ def regions(name, *identifier, &block)
32
+ region_class, region_args = extract_region_details(identifier, &block)
33
+
34
+ build(name, *region_args) do
35
+ define_method(name) do |*options|
36
+ find_all(*region_args, *options).map do |element|
37
+ region_class.new(self, element)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def build(name, *identifier)
46
+ add_to_mapped_elements(name)
47
+ yield
48
+ add_element_methods(name, *identifier)
49
+ end
50
+
51
+ def add_to_mapped_elements(name)
52
+ @mapped_elements ||= []
53
+ @mapped_elements << name.to_s
54
+ end
55
+
56
+ def add_element_methods(name, *identifier)
57
+ create_existence_check(name, *identifier)
58
+ create_nonexistence_check(name, *identifier)
59
+ create_wait_check(name, *identifier)
60
+ create_visible_check(name, *identifier)
61
+ create_invisible_check(name, *identifier)
62
+ end
63
+
64
+ def create_element_method(_name, *_identifier)
65
+ yield
66
+ end
67
+
68
+ def create_existence_check(name, *identifier)
69
+ method_name = "has_#{name}?"
70
+ create_element_method(method_name, *identifier) do
71
+ define_method(method_name) do |*args|
72
+ wait_time = Symbiont.use_implicit_waits ? Capybara.default_max_wait_time : 0
73
+ Capybara.using_wait_time(wait_time) do
74
+ element_exists?(*identifier, *args)
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ def create_nonexistence_check(name, *identifier)
81
+ method_name = "has_no_#{name}?"
82
+ create_element_method(method_name, *identifier) do
83
+ define_method(method_name) do |*args|
84
+ wait_time = Symbiont.use_implicit_waits ? Capybara.default_max_wait_time : 0
85
+ Capybara.using_wait_time(wait_time) do
86
+ element_does_not_exist?(*identifier, *args)
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ def create_wait_check(name, *identifier)
93
+ method_name = "wait_for_#{name}"
94
+ create_element_method(method_name, *identifier) do
95
+ define_method(method_name) do |timeout = nil, *args|
96
+ timeout = timeout.nil? ? Capybara.default_max_wait_time : timeout
97
+ Capybara.using_wait_time(timeout) do
98
+ element_exists?(*identifier, *args)
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ def create_visible_check(name, *identifier)
105
+ method_name = "wait_until_#{name}_visible"
106
+ create_element_method(method_name, *identifier) do
107
+ define_method(method_name) do |timeout = Capybara.default_max_wait_time, *args|
108
+ Timeout.timeout(timeout, Symbiont::Errors::ElementVisibleTimeout) do
109
+ Capybara.using_wait_time(0) do
110
+ sleep(0.05) until element_exists?(*identifier, *args, visible: true)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ def create_invisible_check(name, *identifier)
118
+ method_name = "wait_until_#{name}_invisible"
119
+ create_element_method(name, *identifier) do
120
+ define_method(method_name) do |timeout = Capybara.default_max_wait_time, *args|
121
+ Timeout.timeout(timeout, Symbiont::Errors::ElementNonVisibleTimeout) do
122
+ Capybara.using_wait_time(0) do
123
+ sleep(0.05) while element_exists?(*identifier, *args, visible: true)
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ def extract_region_details(identifier, &block)
131
+ if identifier.first.is_a?(Class)
132
+ region_class = identifier.shift
133
+ elsif block_given?
134
+ region_class = Class.new(Symbiont::Region, &block)
135
+ else
136
+ fail(ArgumentError, 'Provide a region class either as a block or as the second argument.')
137
+ end
138
+
139
+ [region_class, identifier]
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,95 @@
1
+ require 'capybara'
2
+
3
+ require 'symbiont/capybara/element'
4
+ require 'symbiont/capybara/ready'
5
+
6
+ module Symbiont
7
+ class Page
8
+ include Capybara::DSL
9
+ include Ready
10
+ extend Element
11
+
12
+ class << self
13
+ attr_reader :url
14
+
15
+ def url_is(url)
16
+ @url = url.to_s
17
+ end
18
+
19
+ def url_matches(url)
20
+ @url_matcher = url
21
+ end
22
+
23
+ def url_matcher
24
+ @url_matcher || url
25
+ end
26
+ end
27
+
28
+ def initialize(&block)
29
+ super
30
+ instance_eval(&block) if block
31
+ end
32
+
33
+ page_ready do
34
+ [displayed?, "Expected #{current_url} to match #{url_matcher} but it did not."]
35
+ end
36
+
37
+ def view(content = {}, &block)
38
+ self.ready = false
39
+
40
+ if content.is_a?(String)
41
+ @page = Capybara.string(content)
42
+ else
43
+ location = url
44
+ fail Symbiont::Errors::NoUrlForDefinition if location.nil?
45
+ visit url
46
+ end
47
+
48
+ when_ready(&block) if block_given?
49
+ end
50
+
51
+ alias_method :load, :view
52
+ alias_method :markup, :html
53
+ alias_method :run_script, :execute_script
54
+
55
+ def perform(*args)
56
+ view(*args)
57
+ self
58
+ end
59
+
60
+ def url
61
+ self.class.url
62
+ end
63
+
64
+ def url_matcher
65
+ self.class.url_matcher
66
+ end
67
+
68
+ def displayed?
69
+ fail Symbiont::Errors::NoUrlMatchForDefinition if url_matcher.nil?
70
+ true
71
+ end
72
+
73
+ def secure?
74
+ !current_url.match(/^https/).nil?
75
+ end
76
+
77
+ private
78
+
79
+ def find_first(*identifier)
80
+ find(*identifier)
81
+ end
82
+
83
+ def find_all(*identifier)
84
+ all(*identifier)
85
+ end
86
+
87
+ def element_exists?(*identifier)
88
+ has_selector?(*identifier)
89
+ end
90
+
91
+ def element_does_not_exist?(*identifier)
92
+ has_no_selector?(*identifier)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,57 @@
1
+ module Symbiont
2
+ module Ready
3
+ module ClassMethods
4
+ def ready_validations
5
+ if superclass.respond_to?(:ready_validations)
6
+ superclass.ready_validations + _ready_validations
7
+ else
8
+ _ready_validations
9
+ end
10
+ end
11
+
12
+ def page_ready(&block)
13
+ _ready_validations << block
14
+ end
15
+
16
+ alias_method :page_ready_when, :page_ready
17
+
18
+ def _ready_validations
19
+ @_ready_validations ||= []
20
+ end
21
+ end
22
+
23
+ attr_accessor :ready, :ready_error
24
+
25
+ def self.included(caller)
26
+ caller.extend(ClassMethods)
27
+ end
28
+
29
+ def when_ready(&block)
30
+ already_marked_ready = ready
31
+
32
+ fail(ArgumentError, 'A block is required for a when_ready action.') unless block_given?
33
+
34
+ unless self.ready = ready?
35
+ message = "Failed to validate because: #{ready_error || 'no reason provided'}"
36
+ fail(::Symbiont::Errors::PageNotValidatedError, message)
37
+ end
38
+ block.call self
39
+ ensure
40
+ self.ready = already_marked_ready
41
+ end
42
+
43
+ def ready?
44
+ self.ready_error = nil
45
+ return true if ready
46
+ ready_validations_pass?
47
+ end
48
+
49
+ def ready_validations_pass?
50
+ self.class.ready_validations.all? do |validation|
51
+ passed, message = instance_eval(&validation)
52
+ self.ready_error = message if message && !passed
53
+ passed
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,25 @@
1
+ require 'capybara'
2
+
3
+ require 'symbiont/capybara/element'
4
+ require 'symbiont/capybara/region'
5
+
6
+ module Symbiont
7
+ class Region
8
+ include Capybara::DSL
9
+ include Ready
10
+ extend Element
11
+
12
+ attr_reader :region_element, :region_parent
13
+
14
+ def initialize(region_parent, region_element)
15
+ @region_parent = region_parent
16
+ @region_element = region_element
17
+ end
18
+
19
+ private
20
+
21
+ def find_first(*identifier)
22
+ region_element.find(*identifier)
23
+ end
24
+ end
25
+ end
@@ -31,7 +31,7 @@ module Symbiont
31
31
  end
32
32
  end
33
33
 
34
- module Element
34
+ module Elements
35
35
  # Iterates through Watir factory methods. Each method is defined
36
36
  # as a method that can be called on a page class. This is what
37
37
  # allows element definitions to be created.
@@ -3,6 +3,9 @@ module Symbiont
3
3
  class NoUrlForDefinition < StandardError; end
4
4
  class NoUrlMatchForDefinition < StandardError; end
5
5
  class NoTitleForDefinition < StandardError; end
6
+ class ElementVisibleTimeout < StandardError; end
7
+ class ElementNonVisibleTimeout < StandardError; end
8
+ class PageNotValidatedError < StandardError; end
6
9
 
7
10
  class PageURLFromFactoryNotVerified < StandardError
8
11
  def message
@@ -8,20 +8,12 @@ module Symbiont
8
8
  # @param block [Proc] logic to execute in the context of the definition
9
9
  # @return [Object] instance of the definition
10
10
  def on(definition, visit = false, &block)
11
- if @page.is_a?(definition)
12
- block.call @page if block
13
- return @page
11
+ unless @page.is_a?(definition)
12
+ @page = definition.new(@browser) if @browser
13
+ @page = definition.new unless @browser
14
+ @page.view if visit
14
15
  end
15
16
 
16
- if @context.is_a?(definition)
17
- block.call @context if block
18
- @page = @context
19
- return @context
20
- end
21
-
22
- @page = definition.new(@browser)
23
- @page.view if visit
24
-
25
17
  if @page.class.instance_variable_get(:@url_match)
26
18
  raise Symbiont::Errors::PageURLFromFactoryNotVerified unless @page.has_correct_url?
27
19
  end
@@ -30,10 +22,7 @@ module Symbiont
30
22
  raise Symbiont::Errors::PageTitleFromFactoryNotVerified unless @page.has_correct_title?
31
23
  end
32
24
 
33
- @model = @page
34
-
35
25
  block.call @page if block
36
-
37
26
  @page
38
27
  end
39
28
 
@@ -61,23 +50,7 @@ module Symbiont
61
50
  # @return [Object] instance of the definition
62
51
  def on_new(definition, &block)
63
52
  @page = nil
64
- @model = nil
65
-
66
- @context = nil if @context.is_a?(definition)
67
- on(definition, &block)
68
- end
69
-
70
- # Creates a definition context for actions. If an existing context
71
- # exists, that context will be re-used. This also sets a context that
72
- # will be used for that definition even if the active definition
73
- # changes.
74
- #
75
- # @param definition [Class] the name of a definition class
76
- # @param block [Proc] logic to execute within the context of the definition
77
- # @return [Object] instance of the definition
78
- def on_set(definition, &block)
79
53
  on(definition, &block)
80
- @context = @page
81
54
  end
82
55
  end
83
56
  end
@@ -1,5 +1,5 @@
1
1
  module Symbiont
2
- module Page
2
+ module Pages
3
3
  include Helpers
4
4
 
5
5
  def view
@@ -1,3 +1,3 @@
1
1
  module Symbiont
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
data/symbiont.gemspec CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.bindir = 'exe'
31
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
32
  spec.require_paths = ['lib']
33
- spec.requirements << 'Watir-WebDriver, Savon'
33
+ spec.requirements << 'Watir-WebDriver, Capybara, Savon'
34
34
 
35
35
  spec.required_ruby_version = '>= 2.0'
36
36
  spec.required_rubygems_version = '>= 1.8.29'
@@ -47,6 +47,7 @@ Gem::Specification.new do |spec|
47
47
  spec.add_runtime_dependency 'watir-dom-wait'
48
48
  spec.add_runtime_dependency 'watir-scroll'
49
49
  spec.add_runtime_dependency 'savon'
50
+ spec.add_runtime_dependency 'capybara', ['>= 2.1', '< 3.0']
50
51
 
51
52
  spec.post_install_message = %{
52
53
  (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: symbiont
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Nyman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-14 00:00:00.000000000 Z
11
+ date: 2015-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -164,6 +164,26 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: capybara
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '2.1'
174
+ - - "<"
175
+ - !ruby/object:Gem::Version
176
+ version: '3.0'
177
+ type: :runtime
178
+ prerelease: false
179
+ version_requirements: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: '2.1'
184
+ - - "<"
185
+ - !ruby/object:Gem::Version
186
+ version: '3.0'
167
187
  description: "\n Symbiont is a framework that allows you to describe your application
168
188
  in\n terms of activity and page definitions. Those definitions can then be\n
169
189
  \ referenced by test libraries using the DSL that Symbiont provides. The\n DSL
@@ -194,6 +214,10 @@ files:
194
214
  - lib/symbiont.rb
195
215
  - lib/symbiont/accessor.rb
196
216
  - lib/symbiont/assertions.rb
217
+ - lib/symbiont/capybara/element.rb
218
+ - lib/symbiont/capybara/page.rb
219
+ - lib/symbiont/capybara/ready.rb
220
+ - lib/symbiont/capybara/region.rb
197
221
  - lib/symbiont/data_builder.rb
198
222
  - lib/symbiont/data_reader.rb
199
223
  - lib/symbiont/data_setter.rb
@@ -211,7 +235,7 @@ licenses:
211
235
  - MIT
212
236
  metadata: {}
213
237
  post_install_message: "\n(::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)\n\n
214
- \ Symbiont 1.0.0 has been installed.\n\n(::) (::) (::) (::) (::) (::) (::) (::)
238
+ \ Symbiont 1.1.0 has been installed.\n\n(::) (::) (::) (::) (::) (::) (::) (::)
215
239
  (::) (::) (::) (::)\n "
216
240
  rdoc_options: []
217
241
  require_paths:
@@ -227,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
251
  - !ruby/object:Gem::Version
228
252
  version: 1.8.29
229
253
  requirements:
230
- - Watir-WebDriver, Savon
254
+ - Watir-WebDriver, Capybara, Savon
231
255
  rubyforge_project:
232
256
  rubygems_version: 2.4.5.1
233
257
  signing_key: