symbiont 1.0.0 → 1.1.0

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