symbiont 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.md CHANGED
@@ -1,6 +1,12 @@
1
1
  Change Log and History
2
2
  ======================
3
3
 
4
+ Version 0.1.6 / 2012-09-30
5
+ --------------------------
6
+
7
+ This releases provides two bits of functionality. One is an ability to wait for pending Ajax requests. Currently this is very specific to jQuery only. The other ability is that of providing workflows. The idea behind this feature is that you can specify a workflow that starts with an action (method) on a particular definition (class). That workflow may have a series of steps that are required in order to allow the action to take place. This new logic will attempt to execute all of those steps. The rationale behind this addition is to make it easier to specify output-driven logic.
8
+
9
+
4
10
  Version 0.1.5 / 2012-09-12
5
11
  --------------------------
6
12
 
data/app/app.rb CHANGED
@@ -175,7 +175,6 @@ module Symbiont
175
175
  end
176
176
  redirect '/db_users'
177
177
  end
178
-
179
178
  end # class: TestApp
180
179
  end # module: Symbiont
181
180
 
@@ -1,28 +1,28 @@
1
1
  <script type="text/javascript">
2
- function unhide() {
3
- document.getElementById("conditional").style.display="block";
4
- }
2
+ function unhide() {
3
+ document.getElementById("conditional").style.display="block";
4
+ }
5
5
 
6
- function hide() {
7
- document.getElementById("conditional").style.display="none";
8
- }
6
+ function hide() {
7
+ document.getElementById("conditional").style.display="none";
8
+ }
9
9
 
10
- function addDiv() {
11
- var button = document.createElement("input");
12
- button.setAttribute("type", "button");
13
- button.setAttribute("value", "Newly Created Button");
14
- button.setAttribute("id", "new_button");
15
- //document.body.appendChild(button);
16
- var sectional = document.getElementById("created")
17
- sectional.appendChild(button);
18
- }
10
+ function addDiv() {
11
+ var button = document.createElement("input");
12
+ button.setAttribute("type", "button");
13
+ button.setAttribute("value", "Newly Created Button");
14
+ button.setAttribute("id", "new_button");
15
+ //document.body.appendChild(button);
16
+ var sectional = document.getElementById("created")
17
+ sectional.appendChild(button);
18
+ }
19
19
 
20
- function removeDiv() {
21
- var button = document.getElementById("new_button");
22
- //document.body.removeChild(button);
23
- var sectional = document.getElementById("created")
24
- sectional.removeChild(button);
25
- }
20
+ function removeDiv() {
21
+ var button = document.getElementById("new_button");
22
+ //document.body.removeChild(button);
23
+ var sectional = document.getElementById("created")
24
+ sectional.removeChild(button);
25
+ }
26
26
  </script>
27
27
 
28
28
  <section id="test_events">
@@ -35,8 +35,8 @@ module Symbiont
35
35
  # @page.wait_for(5, 'page with expected title not found') do
36
36
  # @page.title.should == "Test App"
37
37
  # end
38
- def wait_for(timeout=10, message=nil, &block)
39
- @platform.wait_for(timeout, message, &block)
38
+ def wait_for(message=nil, timeout=10, &block)
39
+ @platform.wait_for(message, timeout, &block)
40
40
  end
41
41
 
42
42
  # Provides a context for an action that will generate a JavaScript alert
@@ -51,5 +51,20 @@ module Symbiont
51
51
 
52
52
  alias :execute_script :run_script
53
53
 
54
+ # Provides an evaluator that attempts to wait for any pending AJAX
55
+ # requests from the jQuery library.
56
+ #
57
+ # @param [Numeric] timeout amount of time to wait
58
+ # @param [String] message text to print if timeout period is exceeded
59
+ def wait_for_pending_requests(timeout=30, message=nil)
60
+ end_time = ::Time.now + timeout
61
+ until ::Time.now > end_time
62
+ return if @browser.run_script('return jQuery.active') == 0
63
+ sleep 0.5
64
+ end
65
+ message = "Pending requests never indicated completion" unless message
66
+ raise message
67
+ end
68
+
54
69
  end # module: Evaluators
55
70
  end # module: Symbiont
@@ -8,6 +8,7 @@ module Symbiont
8
8
  # definition
9
9
  # @return [Object] instance of the definition
10
10
  def on(definition, &block)
11
+ return @active if @active.class == definition
11
12
  @active = definition.new(@browser)
12
13
  block.call @active if block
13
14
  @active
@@ -29,5 +30,73 @@ module Symbiont
29
30
  alias :during :on
30
31
  alias :start_activity :on_view
31
32
 
33
+ # Starts a workflow, which is a set of predefined actions. You can use
34
+ # this to navigate through a set of actions (and thus a set of
35
+ # definitions). This is done by calling an action that is specified as
36
+ # part of the workflow path. This action will be called on the relevant
37
+ # definition at each point of the workflow.
38
+ #
39
+ # @param [Class] definition an instance of the definition; note this
40
+ # instance must have the workflow action defined on it.
41
+ # @param [Hash] elements a hash that contains an element with the
42
+ # key :using. This is used to lookup the actions for the workflow.
43
+ # @param [optional] block Logic to execute within the context of the
44
+ # workflow.
45
+ # @return [Object] the definition being used at that point of the
46
+ # workflow.
47
+ def start_workflow(definition, elements = {:using => :default}, &block)
48
+ path = workflow_path_for(elements)
49
+ to_element = find_element_for(path, definition) - 1
50
+ go_through_definitions(path[0..to_element])
51
+ on(definition, &block)
52
+ end
53
+
54
+ # This provides a way to start a workflow from somewhere other than the
55
+ # start of the workflow. Specifically, the workflow will start from whatever
56
+ # the active definition is.
57
+ #
58
+ # @param [Class] definition an instance of the definition; note this
59
+ # instance must have the workflow action defined on it.
60
+ # @param [Hash] elements a hash that contains an element with the
61
+ # key :using. This is used to lookup the actions for the workflow.
62
+ # @param [optional] block Logic to execute within the context of the
63
+ # workflow.
64
+ # @return [Object] the definition being used at that point of the
65
+ # workflow.
66
+ def continue_workflow(definition, elements = {:using => :default}, &block)
67
+ path = workflow_path_for(elements)
68
+ from_element = find_element_for(path, @active.class) + 1
69
+ to_element = find_element_for(path, definition) - 1
70
+ go_through_definitions(path[from_element..to_element])
71
+ on(definition, &block)
72
+ end
73
+
74
+ def workflow_path_for(elements)
75
+ path = Symbiont::Factory.symbiont_workflow[elements[:using]]
76
+ fail("Factory workflow :#{elements[:using].to_s} does not exist.") if path.nil?
77
+ path
78
+ end
79
+
80
+ def find_element_for(path, definition)
81
+ path.each_with_index { |each, index| return index if each[0] == definition }
82
+ end
83
+
84
+ def go_through_definitions(elements)
85
+ elements.each do |definition, action|
86
+ element = on(definition)
87
+ fail("Action called #{action} not specified on #{definition}.") unless element.respond_to? action
88
+ element.send action
89
+ end
90
+ end
91
+
92
+ class << self
93
+ attr_accessor :symbiont_workflow
94
+
95
+ def workflow=(path)
96
+ raise("A default workflow path for a Factory workflow must exist.") unless path[:default]
97
+ @symbiont_workflow = path
98
+ end
99
+ end
100
+
32
101
  end # module: Factory
33
102
  end # module: Symbiont
@@ -67,7 +67,7 @@ module Symbiont
67
67
 
68
68
  # Platform method to wait for an action to complete in a given time.
69
69
  # @see Symbiont::Enclosers#wait_for
70
- def wait_for(timeout, message=nil, &block)
70
+ def wait_for(message="wait condition not found", timeout, &block)
71
71
  @browser.wait_until(timeout, message, &block)
72
72
  end
73
73
 
@@ -1,3 +1,3 @@
1
1
  module Symbiont
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
data/lib/symbiont.rb CHANGED
@@ -2,6 +2,7 @@ require 'symbiont/version'
2
2
  require 'symbiont/logger'
3
3
  require 'symbiont/platforms'
4
4
  require 'symbiont/generators'
5
+ require 'symbiont/factory'
5
6
  require 'symbiont/enclosers'
6
7
  require 'symbiont/evaluators'
7
8
  require 'symbiont/locators'
@@ -12,7 +13,7 @@ module Symbiont
12
13
  include Enclosers
13
14
  include Evaluators
14
15
  include Locators
15
- include DataSetter
16
+ include DataSetter
16
17
 
17
18
  # Used to make a platform object accessible. Will hold object
18
19
  # references like these:
@@ -14,10 +14,10 @@ describe Symbiont::Enclosers do
14
14
  end
15
15
 
16
16
  it "should wait for a condition to be true" do
17
- watir_browser.should_receive(:wait_until).with(5, "not quick enough")
18
- watir_definition.wait_for(5, "not quick enough")
17
+ watir_browser.should_receive(:wait_until).with(5, "some condition")
18
+ watir_definition.wait_for("some condition", 5)
19
19
  end
20
-
20
+
21
21
  it "should handle alert message boxes" do
22
22
  watir_browser.should_receive(:wd).twice.and_return(watir_browser)
23
23
  watir_browser.should_receive(:execute_script).twice
@@ -54,6 +54,17 @@ describe Symbiont::Enclosers do
54
54
  watir_browser.should_receive(:type).and_return(:submit)
55
55
  watir_definition.focus.class.should == Symbiont::WebObjects::Button
56
56
  end
57
+
58
+ it "should wait for jquery pending requests to finish" do
59
+ watir_browser.should_receive(:run_script).with('return jQuery.active').and_return(0)
60
+ watir_definition.wait_for_pending_requests
61
+ end
62
+
63
+ it "should return an exception if pending requests did not finish" do
64
+ watir_browser.should_receive(:run_script).with('return jQuery.active')
65
+ watir_browser.should_receive(:run_script).with('return jQuery.active').and_return(1)
66
+ expect { watir_definition.wait_for_pending_requests(1) }.to raise_error
67
+ end
57
68
  end
58
69
  end
59
70
  end
@@ -5,31 +5,118 @@ class TestFactory
5
5
  include Symbiont::Factory
6
6
 
7
7
  attr_accessor :browser
8
+ attr_accessor :active
9
+ end
10
+
11
+ class TestFactorySecond
12
+ include Symbiont
13
+ end
14
+
15
+ class TestFactoryThird
16
+ include Symbiont
8
17
  end
9
18
 
10
19
  describe Symbiont::Factory do
20
+ #let(:watir_browser) { mock_browser_for_watir }
21
+ #let(:factory) { TestFactory.new(watir_browser) }
22
+
11
23
  before(:each) do
12
24
  @factory = TestFactory.new
13
25
  @factory.browser = mock_browser_for_watir
14
26
  end
15
27
 
16
- it "should create a new definition object" do
28
+ it "should create a new definition object, using on" do
17
29
  @factory.on DefinitionTest do |page|
18
30
  page.should be_instance_of DefinitionTest
19
31
  end
20
32
  end
21
33
 
22
- it "should create a new definition object and view it" do
34
+ it "should create a new definition object, using during" do
35
+ @factory.during DefinitionTest do |page|
36
+ page.should be_instance_of DefinitionTest
37
+ end
38
+ end
39
+
40
+ it "should create a new definition object and view it, using on_view" do
23
41
  @factory.browser.should_receive(:goto).twice
24
42
  @factory.on_view DefinitionTest do |page|
25
43
  page.should be_instance_of DefinitionTest
26
44
  end
27
45
  end
28
46
 
47
+ it "should create a new definition object and view it, using start_activity" do
48
+ @factory.browser.should_receive(:goto).twice
49
+ @factory.start_activity DefinitionTest do |page|
50
+ page.should be_instance_of DefinitionTest
51
+ end
52
+ end
53
+
29
54
  it "should set a reference to be used outside the factory" do
30
55
  active = @factory.on DefinitionTest
31
56
  current = @factory.instance_variable_get "@active"
32
57
  current.should === active
33
58
  end
34
59
 
60
+ it "should use an existing definition when that definition is already active" do
61
+ @factory.instance_variable_set "@active", TestFactorySecond.new(@factory.browser)
62
+ @factory.on(TestFactorySecond) do |page|
63
+ page.should be_instance_of TestFactorySecond
64
+ end
65
+ end
66
+
67
+ it "should not execute block if definition is not the active definition" do
68
+ @factory.instance_variable_set "@active", TestFactorySecond.new(@factory.browser)
69
+ @factory.on(TestFactoryThird) do |page|
70
+ page.should_not be_instance_of TestFactorySecond
71
+ page.should be_instance_of TestFactoryThird
72
+ end
73
+ end
74
+
75
+ it "should store a workflow path" do
76
+ workflow = ['stage1', 'stage2', 'stage3']
77
+ Symbiont::Factory.workflow = {default: workflow}
78
+ Symbiont::Factory.symbiont_workflow[:default].should == workflow
79
+ end
80
+
81
+ it "should be unable to work without a default worfklow path" do
82
+ expect { Symbiont::Factory.workflow = {another: []} }.to raise_error
83
+ end
84
+
85
+ it "should start a workflow path by using the default path" do
86
+ paths = [[TestFactory, :first_action], [TestFactorySecond, :second_action]]
87
+ Symbiont::Factory.workflow = {:default => paths}
88
+ mock_page = double("mock_page")
89
+ TestFactory.should_receive(:new).and_return(mock_page)
90
+ mock_page.should_receive(:first_action)
91
+ @factory.start_workflow(TestFactorySecond).class.should == TestFactorySecond
92
+ end
93
+
94
+ it "should not start a workflow when there is no proper path" do
95
+ Symbiont::Factory.workflow = {:default => ['default'], :standard => ['standard']}
96
+ expect { @factory.start_workflow(TestFactory, :using => :invalid_path) }.to raise_error
97
+ end
98
+
99
+ it "should not use a workflow when an action is not specified" do
100
+ Symbiont::Factory.workflow = {:default => [[TestFactory, :action_1], [TestFactorySecond, :action_2]]}
101
+ mock_page = double("mock_page")
102
+ TestFactory.should_receive(:new).and_return(mock_page)
103
+ mock_page.should_receive(:respond_to?).with(:action_1).and_return(false)
104
+ expect { @factory.start_workflow(TestFactorySecond) }.to raise_error
105
+ end
106
+
107
+ it "should be able to continue along a workflow" do
108
+ Symbiont::Factory.workflow = {
109
+ :default => [[TestFactory, :action_1],
110
+ [TestFactorySecond, :action_2],
111
+ [TestFactoryThird, :action_3]]
112
+ }
113
+ mock_page = double("mock_page")
114
+ TestFactorySecond.should_receive(:new).and_return(mock_page)
115
+ mock_page.should_receive(:respond_to?).with(:action_2).and_return(true)
116
+ mock_page.should_receive(:action_2)
117
+ @factory.active = TestFactory.new()
118
+ TestFactory.should_not_receive(:new)
119
+ @factory.continue_workflow(TestFactoryThird).class.should == TestFactoryThird
120
+ end
121
+
35
122
  end
@@ -15,13 +15,13 @@ end
15
15
  Then (/^the reference ID text field should have a black background$/) do
16
16
  @web_object = @page.bookRefID_object
17
17
  @style = @web_object.style('background-color')
18
- @style.should == "rgba(0,0,0,1)"
18
+ @style.should == "rgba(0, 0, 0, 1)"
19
19
  end
20
20
 
21
21
  Then (/^the reference ID text field should have yellow text$/) do
22
22
  @web_object = @page.bookRefID_object
23
23
  @style = @web_object.style('color')
24
- @style.should == "rgba(255,255,0,1)"
24
+ @style.should == "rgba(255, 255, 0, 1)"
25
25
  end
26
26
 
27
27
  Then (/^the book title text field should be an input field$/) do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: symbiont
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-12 00:00:00.000000000 Z
12
+ date: 2012-09-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec