symbiont 0.1.0 → 0.1.1

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.
Files changed (56) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +14 -0
  3. data/HISTORY.md +6 -0
  4. data/README.md +1 -1
  5. data/app/Gemfile +4 -0
  6. data/app/app.rb +167 -0
  7. data/app/config/database.rb +9 -0
  8. data/app/models/plan.rb +10 -0
  9. data/app/models/product.rb +10 -0
  10. data/app/models/study.rb +11 -0
  11. data/app/models/user.rb +13 -0
  12. data/app/public/css/style.css +138 -0
  13. data/app/views/create_plan.erb +21 -0
  14. data/app/views/create_product.erb +15 -0
  15. data/app/views/create_study.erb +24 -0
  16. data/app/views/create_user.erb +60 -0
  17. data/app/views/db_plans.erb +31 -0
  18. data/app/views/db_products.erb +29 -0
  19. data/app/views/db_studies.erb +33 -0
  20. data/app/views/db_users.erb +23 -0
  21. data/app/views/entity_list.erb +10 -0
  22. data/app/views/index.erb +7 -0
  23. data/app/views/layout.erb +39 -0
  24. data/app/views/login_page.erb +17 -0
  25. data/app/views/success_1.erb +2 -0
  26. data/app/views/success_2.erb +2 -0
  27. data/app/views/test_database.erb +13 -0
  28. data/app/views/test_events.erb +44 -0
  29. data/app/views/test_page.erb +164 -0
  30. data/lib/symbiont.rb +3 -0
  31. data/lib/symbiont/enclosers.rb +17 -0
  32. data/lib/symbiont/evaluators.rb +17 -0
  33. data/lib/symbiont/platform_watir/platform_object.rb +22 -2
  34. data/lib/symbiont/version.rb +1 -1
  35. data/lib/symbiont/web_objects/_common.rb +36 -1
  36. data/lib/symbiont/web_objects/table.rb +9 -0
  37. data/lib/symbiont/web_objects/table_row.rb +9 -0
  38. data/spec/symbiont/enclosers_spec.rb +5 -0
  39. data/spec/symbiont/evaluators_spec.rb +24 -0
  40. data/spec/symbiont/web_object_spec.rb +60 -2
  41. data/spec/symbiont/web_objects/table_row_spec.rb +9 -0
  42. data/spec/symbiont/web_objects/table_spec.rb +8 -0
  43. data/specs/button.feature +2 -0
  44. data/specs/definitions/pages.rb +17 -0
  45. data/specs/evaluators.feature +5 -0
  46. data/specs/events.feature +19 -0
  47. data/specs/link.feature +2 -0
  48. data/specs/support/test_steps/action_steps_buttons.rb +2 -0
  49. data/specs/support/test_steps/action_steps_evaluators.rb +3 -0
  50. data/specs/support/test_steps/action_steps_events.rb +40 -0
  51. data/specs/support/test_steps/action_steps_links.rb +2 -0
  52. data/specs/support/test_steps/action_steps_navigate.rb +4 -0
  53. data/specs/support/test_steps/action_steps_webobjects.rb +25 -0
  54. data/specs/web_object.feature +11 -0
  55. data/symbiont.gemspec +3 -3
  56. metadata +47 -13
@@ -3,9 +3,12 @@ require 'symbiont/logger'
3
3
  require 'symbiont/platforms'
4
4
  require 'symbiont/generators'
5
5
  require 'symbiont/enclosers'
6
+ require 'symbiont/evaluators'
6
7
 
7
8
  module Symbiont
8
9
  include Platforms
10
+ include Enclosers
11
+ include Evaluators
9
12
 
10
13
  # Used to make a platform object accessible. Will hold object
11
14
  # references like these:
@@ -22,5 +22,22 @@ module Symbiont
22
22
  block.call(encloser)
23
23
  end
24
24
 
25
+ # Provides a context for an action that must succeed within a given time period.
26
+ # The logic here is simply that the result of the action will be true (meaning
27
+ # the action was carried out) or false, which means the action did not succeed
28
+ # in the time allotted.
29
+ #
30
+ # @param [Integer] timeout the amount of time in seconds to wait
31
+ # @param [String] message the text to return if the action did not occur in time
32
+ # @param [Proc] block the code that calls the desired action
33
+ #
34
+ # @example
35
+ # @page.wait_for(5, 'page with expected title not found') do
36
+ # @page.title.should == "Test App"
37
+ # end
38
+ def wait_for(timeout=10, message=nil, &block)
39
+ @platform.wait_for(timeout, message, &block)
40
+ end
41
+
25
42
  end # module: Enclosers
26
43
  end # module: Symbiont
@@ -0,0 +1,17 @@
1
+ module Symbiont
2
+ module Evaluators
3
+
4
+ # Visits a page via a specified URL. The URL can be specified as a domain
5
+ # address or as a file-based link.
6
+ # @param [String] url the full URL to navigate to
7
+ def visit(url)
8
+ @platform.visit(url)
9
+ end
10
+
11
+ # Returns the text of the current page.
12
+ def text
13
+ @platform.text
14
+ end
15
+
16
+ end # module: Evaluators
17
+ end # module: Symbiont
@@ -7,13 +7,33 @@ module Symbiont
7
7
  def initialize(browser)
8
8
  @browser = browser
9
9
  end
10
-
10
+
11
+ ## Browser-Level Actions ##
12
+
11
13
  # Platform method to make a call to a specified URL.
12
- # See Symbiont::Generators#url_is
14
+ # See Symbiont#visit
13
15
  def visit(url)
14
16
  @browser.goto(url)
15
17
  end
16
18
 
19
+ ## Page-Level Actions ##
20
+
21
+ # Platform method to retrieve text from the current page.
22
+ # See Symbiont#text
23
+ def text
24
+ @browser.text
25
+ end
26
+
27
+ ## Encloser Methods ##
28
+
29
+ # Platform method to wait for an action to complete in a given time.
30
+ # @see Symbiont::Enclosers#wait_for
31
+ def wait_for(timeout, message=nil, &block)
32
+ @browser.wait_until(timeout, message, &block)
33
+ end
34
+
35
+ ## Generator Methods ##
36
+
17
37
  # Platform method to return a link object.
18
38
  # Link objects are of type: Symbiont::WebObjects::Link
19
39
  # @see Symbiont::Generators#link
@@ -1,3 +1,3 @@
1
1
  module Symbiont
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -31,10 +31,45 @@ module Symbiont
31
31
  @web_object.text
32
32
  end
33
33
 
34
- def when_actionable(timeout)
34
+ def click
35
+ @web_object.click
36
+ end
37
+
38
+ def attribute(name)
39
+ @web_object.attribute_value(name)
40
+ end
41
+
42
+ def style(property)
43
+ @web_object.style(property)
44
+ end
45
+
46
+ def when_actionable(timeout=5)
35
47
  @web_object.wait_until_present(timeout)
36
48
  self
37
49
  end
50
+
51
+ alias :when_present :when_actionable
52
+
53
+ def when_visible(timeout=5)
54
+ Object::Watir::Wait.until(timeout, "object not visible within #{timeout} seconds.") do
55
+ visible?
56
+ end
57
+ self
58
+ end
59
+
60
+ def when_not_visible(timeout=5)
61
+ Object::Watir::Wait.while(timeout, "object still visible after #{timeout} seconds.") do
62
+ visible?
63
+ end
64
+ self
65
+ end
66
+
67
+ alias :must_be_visible :when_visible
68
+ alias :must_not_be_visible :when_not_visible
69
+
70
+ def wait_until(timeout, message=nil, &block)
71
+ Object::Watir::Wait.until(timeout, message, &block)
72
+ end
38
73
  end # class: WebObject
39
74
 
40
75
  end # module: WebObjects
@@ -9,6 +9,15 @@ module Symbiont
9
9
  Object::Symbiont::WebObjects::TableRow.new(@web_object[index])
10
10
  end
11
11
 
12
+ # This method is an iterator that returns a TableRow object each time through
13
+ # the loop.
14
+ # @return [Symbiont::WebObjects::TableRow]
15
+ def each
16
+ for index in 1..self.rows do
17
+ yield self[index - 1]
18
+ end
19
+ end
20
+
12
21
  # This method will return the number of rows in a table.
13
22
  def rows
14
23
  @web_object.wd.find_elements(:xpath, row_xpath).size
@@ -9,6 +9,15 @@ module Symbiont
9
9
  Object::Symbiont::WebObjects::TableCell.new(@web_object[index])
10
10
  end
11
11
 
12
+ # This method is an iterator that returns a TableCell object each time through
13
+ # the loop.
14
+ # @return [Symbiont::WebObjects::TableCell]
15
+ def each
16
+ for index in 1..self.columns do
17
+ yield self[index - 1]
18
+ end
19
+ end
20
+
12
21
  # This method returns the number of columns in a table object.
13
22
  def columns
14
23
  @web_object.wd.find_elements(:xpath, cell_xpath).size
@@ -12,5 +12,10 @@ describe Symbiont::Enclosers do
12
12
  web_object.should_not be_nil
13
13
  web_object.should be_instance_of Symbiont::WebObjects::TextField
14
14
  end
15
+
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")
19
+ end
15
20
  end
16
21
  end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Symbiont::Enclosers do
4
+ let(:watir_browser) { mock_browser_for_watir }
5
+ let(:watir_definition) { DefinitionTest.new(watir_browser) }
6
+
7
+ describe "browser-level actions" do
8
+ context "a definition using watir-webdriver" do
9
+ it "should visit a page" do
10
+ watir_browser.should_receive(:goto).with("http://localhost:4567")
11
+ watir_definition.visit("http://localhost:4567")
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "page-level actions" do
17
+ context "a definition using watir-webdriver" do
18
+ it "should return all the text on a page" do
19
+ watir_browser.should_receive(:text).and_return("page text")
20
+ watir_definition.text.should == "page text"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,6 +4,16 @@ describe "Web Objects" do
4
4
  let(:watir_browser) { mock_browser_for_watir }
5
5
  let(:watir_definition) { ::Symbiont::WebObjects::WebObject.new(watir_browser) }
6
6
 
7
+ it "should retrieve the value of an attribute" do
8
+ watir_browser.should_receive(:attribute_value).and_return(true)
9
+ watir_definition.attribute("readonly").should be_true
10
+ end
11
+
12
+ it "should retrieve the style of a web object" do
13
+ watir_browser.should_receive(:style).with('display').and_return("none")
14
+ watir_definition.style('display').should == 'none'
15
+ end
16
+
7
17
  it "should determine if a web object is enabled" do
8
18
  watir_browser.should_receive(:enabled?).and_return(true)
9
19
  watir_definition.enabled?.should == true
@@ -19,19 +29,67 @@ describe "Web Objects" do
19
29
  watir_definition.exists?.should == true
20
30
  end
21
31
 
32
+ it "should determine if a web object does not exist" do
33
+ watir_browser.should_receive(:exists?).and_return(false)
34
+ watir_definition.exists?.should == false
35
+ end
36
+
22
37
  it "should determine if a web object is visible" do
23
38
  watir_browser.should_receive(:visible?).and_return(true)
24
39
  watir_definition.visible?.should == true
25
40
  end
26
41
 
42
+ it "should determine if a web object is not visible" do
43
+ watir_browser.should_receive(:visible?).and_return(false)
44
+ watir_definition.visible?.should == false
45
+ end
46
+
27
47
  it "should return the text contained by a web object" do
28
48
  watir_browser.should_receive(:text).and_return("testing")
29
49
  watir_definition.text.should == "testing"
30
50
  end
31
51
 
32
- it "should wait for web object to be actionable" do
33
- watir_browser.stub(:wait_until_present).with(5)
52
+ it "should simulate a click event on a web object" do
53
+ watir_browser.should_receive(:click)
54
+ watir_definition.click
55
+ end
56
+
57
+ it "should wait for a web object to be actionable" do
58
+ watir_browser.should_receive(:wait_until_present).twice.with(5)
59
+ watir_definition.when_actionable(5)
60
+ watir_definition.when_present(5)
61
+ end
62
+
63
+ it "should reference a web object when it is actionable" do
64
+ watir_browser.should_receive(:wait_until_present).with(5)
34
65
  web_object = watir_definition.when_actionable(5)
35
66
  web_object.should === watir_definition
36
67
  end
68
+
69
+ it "should wait for a web object to become visible" do
70
+ watir_browser.should_receive(:visible?).and_return(true)
71
+ watir_definition.when_visible(5)
72
+ end
73
+
74
+ it "should reference a web object when it is visible" do
75
+ watir_browser.should_receive(:visible?).and_return(true)
76
+ web_object = watir_definition.when_visible(5)
77
+ web_object.should === watir_definition
78
+ end
79
+
80
+ it "should wait for a web object to become invisible" do
81
+ watir_browser.should_receive(:visible?).and_return(false)
82
+ watir_definition.when_not_visible(5)
83
+ end
84
+
85
+ it "should reference a web object when it is not visible" do
86
+ watir_browser.stub(:visible?).and_return(false)
87
+ web_object = watir_definition.when_not_visible(5)
88
+ web_object.should === watir_definition
89
+ end
90
+
91
+ it "should wait until a specific condition occurs" do
92
+ Object::Watir::Wait.stub(:until).with(5, "Condition occurred.")
93
+ watir_definition.wait_until(5, "Condition occurred.") { true }
94
+ end
37
95
  end
@@ -19,6 +19,15 @@ describe Symbiont::WebObjects::TableRow do
19
19
  table_row_object.should_receive(:size).and_return(3)
20
20
  table_row.columns.should == 3
21
21
  end
22
+
23
+ it "should iterate over the table columns" do
24
+ table_row = Symbiont::WebObjects::TableRow.new(table_row_object)
25
+ table_row.should_receive(:columns).and_return(2)
26
+ table_row.stub(:[]).and_return(table_row_object)
27
+ count = 0
28
+ table_row.each { |e| count += 1 }
29
+ count.should == 2
30
+ end
22
31
  end
23
32
  end
24
33
  end
@@ -28,6 +28,14 @@ describe Symbiont::WebObjects::Table do
28
28
  table_object.should_receive(:size).and_return(2)
29
29
  watir_table.rows.should == 2
30
30
  end
31
+
32
+ it "should iterate over the table rows" do
33
+ watir_table.should_receive(:rows).and_return(2)
34
+ table_object.stub(:[]).and_return(table_object)
35
+ count = 0
36
+ watir_table.each { |e| count += 1 }
37
+ count.should == 2
38
+ end
31
39
  end
32
40
  end
33
41
  end
@@ -39,3 +39,5 @@ Feature: Ability to Support Button Web Objects
39
39
  | class |
40
40
  | xpath |
41
41
  | index |
42
+ | value |
43
+ | text |
@@ -21,12 +21,16 @@ class SimpleObjectPage
21
21
  link :avengersClass, class: "avengersClass"
22
22
  link :avengersXPath, xpath: "id('avengersID')"
23
23
  link :avengersIndex, {id: "avengersID", index: 0}
24
+ link :avengersText, text: "Avengers Assemble"
25
+ link :avengersHref, href: "success_1"
24
26
 
25
27
  button :clickmeID, id: "clickmeID"
26
28
  button :clickmeName, name: "clickmeName"
27
29
  button :clickmeClass, class: "clickmeClass"
28
30
  button :clickmeXPath, xpath: "//input[@id='clickmeID']"
29
31
  button :clickmeIndex, {id: "clickmeID", index: 0}
32
+ button :clickmeValue, value: "Click Me"
33
+ button :clickmeText, text: "Click Me"
30
34
 
31
35
  button :cantClickMeID, id: "cantclickmeID"
32
36
 
@@ -38,6 +42,7 @@ class SimpleObjectPage
38
42
  text_field :bookTitleXPath, xpath: "//input[@id='bookTitleID']"
39
43
  text_field :bookTitleIndex, {id: "bookTitleID", index: 0}
40
44
 
45
+ text_field :bookRefID, id: "bookRefID"
41
46
  text_field :bookPubID, id: "bookPubID"
42
47
  text_field :fake_text_field, id: "fake_text_field"
43
48
 
@@ -91,6 +96,18 @@ class SimpleObjectPage
91
96
  span :spanTextClass, class: "spanTextClass"
92
97
  end
93
98
 
99
+ class SimpleEventsPage
100
+ include Symbiont
101
+
102
+ url_is "http://localhost:4567/test_events"
103
+
104
+ button :conditional, id: "conditional"
105
+ button :hideButton, value: "Hide Button"
106
+ button :revealButton, value: "Reveal Button"
107
+ button :createButton, value: "Create Button"
108
+ button :removeButton, value: "Remove Button"
109
+ end
110
+
94
111
  class LoggingIn
95
112
  include Symbiont
96
113
  begin_at "http://localhost:4567/test_database"
@@ -0,0 +1,5 @@
1
+ Feature: Ability to handle browser and page actions.
2
+
3
+ Scenario: Getting web page text
4
+ When on the object test page
5
+ Then the page should contain the text "Multiphasic Temporal Convergence"
@@ -0,0 +1,19 @@
1
+ Feature: Ability to Handle Events or Time-Based Situations
2
+
3
+ Scenario: Waiting for a general condition
4
+ When performing a successful action on the object test page
5
+ Then the test should wait for a success page
6
+
7
+ Scenario: Waiting for an object to be invisible
8
+ When on the events test page
9
+ Then the conditional button can be clicked
10
+ When the conditional button is hidden
11
+ Then the test will wait until the conditional button is invisible
12
+ And after that time the conditional button should not be visible
13
+
14
+ Scenario: Waiting for an object to be visible
15
+ When the conditional button on the events test page is invisible
16
+ And the conditional button is revealed
17
+ Then the test will wait until the conditional button is visible before clicking it
18
+
19
+
@@ -30,3 +30,5 @@ Feature: Ability to Support Link Web Objects
30
30
  | class |
31
31
  | xpath |
32
32
  | index |
33
+ | text |
34
+ | href |
@@ -10,6 +10,8 @@ When (/^the click me button on the object test page is clicked by "([^"]*)"$/) d
10
10
  @page.clickmeClass if locator == "class"
11
11
  @page.clickmeXPath if locator == "xpath"
12
12
  @page.clickmeIndex if locator == "index"
13
+ @page.clickmeValue if locator == "value"
14
+ @page.clickmeText if locator == "text"
13
15
  end
14
16
 
15
17
  Then (/^the click me button should exist$/) do
@@ -0,0 +1,3 @@
1
+ Then (/^the page should contain the text "([^"]*)"$/) do |text|
2
+ @page.text.include? text
3
+ end
@@ -0,0 +1,40 @@
1
+ When (/^performing a successful action on the object test page$/) do
2
+ step %{on the object test page}
3
+ @page.clickmeID
4
+ end
5
+
6
+ When (/^the conditional button is hidden$/) do
7
+ @page.hideButton
8
+ end
9
+
10
+ When (/^the conditional button is revealed$/) do
11
+ @page.revealButton
12
+ end
13
+
14
+ When (/^the conditional button on the events test page is invisible$/) do
15
+ step %{on the events test page}
16
+ step %{the conditional button is hidden}
17
+ end
18
+
19
+ Then (/^the test should wait for a success page$/) do
20
+ @page.wait_for(10, "success page did not come up in time") do
21
+ @page.text.include? 'Success'
22
+ end
23
+ end
24
+
25
+ Then (/^the conditional button can be clicked$/) do
26
+ @page.conditional
27
+ end
28
+
29
+ Then (/^the test will wait until the conditional button is invisible$/) do
30
+ @page.conditional_button.when_not_visible
31
+ end
32
+
33
+ Then (/^after that time the conditional button should not be visible$/) do
34
+ @page.conditional_visible?.should == false
35
+ end
36
+
37
+ Then (/^the test will wait until the conditional button is visible before clicking it$/) do
38
+ @page.conditional_button.when_visible
39
+ @page.conditional
40
+ end