Skip to content
This repository
Browse code

initial import

  • Loading branch information...
commit 22d9b0facb4658f58b553bb68b918439dad4cf22 0 parents
Ryan Bates authored June 29, 2008

Showing 124 changed files with 28,733 additions and 0 deletions. Show diff stats Hide diff stats

  1. 1  .gitignore
  2. 125  CHANGELOG
  3. 202  LICENSE-2.0.txt
  4. 193  README
  5. 27  Rakefile
  6. 33  config.yml.example
  7. 19  generators/selenium/USAGE
  8. 50  generators/selenium/selenium_generator.rb
  9. 16  generators/selenium/templates/rhtml.rhtml
  10. 14  generators/selenium/templates/rselenese.rhtml
  11. 11  generators/selenium/templates/selenese.rhtml
  12. 19  init.rb
  13. 119  lib/controllers/selenium_controller.rb
  14. 9  lib/selenium_helper.rb
  15. 11  lib/selenium_on_rails.rb
  16. 212  lib/selenium_on_rails/acceptance_test_runner.rb
  17. 55  lib/selenium_on_rails/fixture_loader.rb
  18. 38  lib/selenium_on_rails/partials_support.rb
  19. 57  lib/selenium_on_rails/paths.rb
  20. 17  lib/selenium_on_rails/renderer.rb
  21. 35  lib/selenium_on_rails/rselenese.rb
  22. 81  lib/selenium_on_rails/selenese.rb
  23. 51  lib/selenium_on_rails/suite_renderer.rb
  24. 113  lib/selenium_on_rails/test_builder.rb
  25. 1,002  lib/selenium_on_rails/test_builder_accessors.rb
  26. 515  lib/selenium_on_rails/test_builder_actions.rb
  27. 91  lib/selenium_on_rails/test_builder_user_accessors.rb.example
  28. 24  lib/selenium_on_rails/test_builder_user_actions.rb.example
  29. 22  lib/selenium_on_rails_config.rb
  30. 18  lib/views/layout.rhtml
  31. 5  lib/views/record.rhtml
  32. 67  lib/views/setup.rhtml
  33. 26  lib/views/test_suite.rhtml
  34. 23  routes.rb
  35. 8  selenium-core/Blank.html
  36. 8  selenium-core/InjectedRemoteRunner.html
  37. 109  selenium-core/RemoteRunner.html
  38. 74  selenium-core/SeleniumLog.html
  39. 123  selenium-core/TestPrompt.html
  40. 55  selenium-core/TestRunner-splash.html
  41. 175  selenium-core/TestRunner.hta
  42. 175  selenium-core/TestRunner.html
  43. BIN  selenium-core/domviewer/butmin.gif
  44. BIN  selenium-core/domviewer/butplus.gif
  45. 298  selenium-core/domviewer/domviewer.css
  46. 16  selenium-core/domviewer/domviewer.html
  47. 205  selenium-core/domviewer/selenium-domviewer.js
  48. BIN  selenium-core/icons/all.png
  49. BIN  selenium-core/icons/continue.png
  50. BIN  selenium-core/icons/continue_disabled.png
  51. BIN  selenium-core/icons/pause.png
  52. BIN  selenium-core/icons/pause_disabled.png
  53. BIN  selenium-core/icons/selected.png
  54. BIN  selenium-core/icons/step.png
  55. BIN  selenium-core/icons/step_disabled.png
  56. 1,431  selenium-core/iedoc-core.xml
  57. 1,368  selenium-core/iedoc.xml
  58. 6  selenium-core/lib/cssQuery/cssQuery-p.js
  59. 142  selenium-core/lib/cssQuery/src/cssQuery-level2.js
  60. 150  selenium-core/lib/cssQuery/src/cssQuery-level3.js
  61. 53  selenium-core/lib/cssQuery/src/cssQuery-standard.js
  62. 356  selenium-core/lib/cssQuery/src/cssQuery.js
  63. 2,006  selenium-core/lib/prototype.js
  64. 101  selenium-core/lib/scriptaculous/builder.js
  65. 815  selenium-core/lib/scriptaculous/controls.js
  66. 915  selenium-core/lib/scriptaculous/dragdrop.js
  67. 958  selenium-core/lib/scriptaculous/effects.js
  68. 47  selenium-core/lib/scriptaculous/scriptaculous.js
  69. 283  selenium-core/lib/scriptaculous/slider.js
  70. 383  selenium-core/lib/scriptaculous/unittest.js
  71. 69  selenium-core/scripts/find_matching_child.js
  72. 842  selenium-core/scripts/htmlutils.js
  73. 79  selenium-core/scripts/injection.html
  74. 7  selenium-core/scripts/injection_iframe.html
  75. 70  selenium-core/scripts/js2html.js
  76. 175  selenium-core/scripts/narcissus-defs.js
  77. 1,054  selenium-core/scripts/narcissus-exec.js
  78. 1,003  selenium-core/scripts/narcissus-parse.js
  79. 63  selenium-core/scripts/se2html.js
  80. 2,329  selenium-core/scripts/selenium-api.js
  81. 1,946  selenium-core/scripts/selenium-browserbot.js
  82. 142  selenium-core/scripts/selenium-browserdetect.js
  83. 375  selenium-core/scripts/selenium-commandhandlers.js
  84. 177  selenium-core/scripts/selenium-executionloop.js
  85. 139  selenium-core/scripts/selenium-logging.js
  86. 466  selenium-core/scripts/selenium-remoterunner.js
  87. 1,281  selenium-core/scripts/selenium-testrunner.js
  88. 5  selenium-core/scripts/selenium-version.js
  89. 75  selenium-core/scripts/user-extensions.js.sample
  90. 153  selenium-core/scripts/xmlextras.js
  91. BIN  selenium-core/selenium-logo.png
  92. 43  selenium-core/selenium-test.css
  93. 299  selenium-core/selenium.css
  94. 428  selenium-core/xpath/dom.js
  95. 255  selenium-core/xpath/misc.js
  96. 2,182  selenium-core/xpath/xpath.js
  97. 20  switch_environment/init.rb
  98. 16  switch_environment/switch_environment_controller.rb
  99. 8  tasks/test_acceptance.rake
  100. 147  test/renderer_test.rb
  101. 672  test/rselenese_test.rb
  102. 229  test/selenese_test.rb
  103. 48  test/selenium_controller_test.rb
  104. 33  test/selenium_support_test.rb
  105. 29  test/setup_test.rb
  106. 173  test/suite_renderer_test.rb
  107. 70  test/test_helper.rb
  108. 0  test_data/.hidden.html
  109. 1  test_data/_partial.rsel
  110. 6  test_data/html.html
  111. 12  test_data/own_layout.html
  112. 6  test_data/partials/_html.html
  113. 2  test_data/partials/_nesting.rsel
  114. 6  test_data/partials/_rhtml.rhtml
  115. 1  test_data/partials/_rsel.rsel
  116. 5  test_data/partials/_sel.sel
  117. 5  test_data/partials/all_partials.rsel
  118. 7  test_data/rhtml.rhtml
  119. 8  test_data/rselenese.rsel
  120. 7  test_data/selenese.sel
  121. 1  test_data/suite_one/subsuite/suite_one_subsuite_testcase.sel
  122. 1  test_data/suite_one/suite_one_testcase1.sel
  123. 1  test_data/suite_one/suite_one_testcase2.sel
  124. 1  test_data/suite_two/suite_two_testcase.sel
1  .gitignore
... ...
@@ -0,0 +1 @@
  1
+doc
125  CHANGELOG
... ...
@@ -0,0 +1,125 @@
  1
+== REVISION 38[http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=38]
  2
+
  3
+=== change made by Flanagan
  4
+
  5
+* SOR-13[http://jira.openqa.org/browse/SOR-13] Corrected an omission of require statements.
  6
+
  7
+== REVISION 37
  8
+
  9
+=== change made by Flanagan
  10
+
  11
+* Undone an unwanted commit of modified Rakefile.
  12
+
  13
+== REVISION 36[http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=36]
  14
+
  15
+=== change made by Flanagan
  16
+
  17
+* SOR-13[http://jira.openqa.org/browse/SOR-13] Added (experimental) support for user-extensions.js.
  18
+
  19
+== REVISION 35[http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=35]
  20
+
  21
+=== all changes made by Jonas
  22
+
  23
+* SOR-12[http://jira.openqa.org/browse/SOR-12] removed all support for selenium gem
  24
+* Selenium Core 0.8.2 is now bundled with Selenium on Rails. If you want to use other version set the 'selenium_path' in config.yml
  25
+* Updated installation instructions for Windows
  26
+
  27
+== REVISION 34[http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=34]
  28
+
  29
+=== all changes made by Flanagan
  30
+
  31
+* SOR-11[http://jira.openqa.org/browse/SOR-11] Fixed related assertions for store_checked to use only locator parameter
  32
+
  33
+Warning: Users must change tests that pass two parameters (locator, pattern) to +verify_checked+, +verify_not_checked+, +assert_checked+, +assert_not_checked+, +wait_for_checked+, or +wait_for_not_checked+.
  34
+
  35
+Test scripts that continue to use two parameters will be broken, only one parameter, the locator, should be passed.
  36
+
  37
+For example, <tt>|verify_checked|my_checkbox|true|</tt> will be interpreted as <tt>|verify_checked|my_checkboxtrue||</tt> so change the test to <tt>|verify_checked|my_checkbox||</tt>
  38
+
  39
+* SOR-9[http://jira.openqa.org/browse/SOR-9] Added Mac OS X browsers to config.yml.example
  40
+* SOR-10[http://jira.openqa.org/browse/SOR-10] Added support for baseUrl to acceptance_test_runner.rb as added to selenium-core 0.8.2
  41
+* Added 'webrick' to SERVER_COMMAND in acceptance_test_runner.rb as parameters do not work with lighttpd
  42
+* Reversed expected query string in test/renderer_testrb to make tests pass
  43
+
  44
+Note: On Mac OS X, at least, clear_tables comes before fixtures in the query string; this may be an environment-specific issue if the test now fails on other OSes.
  45
+
  46
+* Added this CHANGELOG file and amended the rake rdoc task to include it
  47
+
  48
+* Added support in rselenese for a long list of actions and accessors that are included in selenium-core (0.8.2 and possibly earlier) but were previously missing in selenium-on-rails.
  49
+
  50
+Here are the newly supported actions:
  51
+
  52
+Useful for debugging:
  53
+* <tt>brake</tt> (alias for selenium-core's break, a reserved word in Ruby)
  54
+* <tt>echo, :string</tt>
  55
+* <tt>highlight, :locator</tt>
  56
+
  57
+Keyboard events:
  58
+* <tt>alt_key_down</tt>
  59
+* <tt>alt_key_up</tt>
  60
+* <tt>control_key_down</tt>
  61
+* <tt>control_key_up</tt>
  62
+* <tt>meta_key_down</tt>
  63
+* <tt>meta_key_up</tt>
  64
+* <tt>shift_key_down</tt>
  65
+* <tt>shift_key_up</tt>
  66
+* <tt>type_keys, :locator, :string</tt>
  67
+
  68
+Mouse events:
  69
+* <tt>click_at, :locator, :coord_string</tt>
  70
+* <tt>double_click, :locator</tt>
  71
+* <tt>double_click_at, :locator, :coord_string</tt>
  72
+* <tt>drag_and_drop, :locator, :movements_string</tt>
  73
+* <tt>drag_and_drop_to_object, :locator, :locator</tt>
  74
+* <tt>mouse_down_at, :locator, :coord_string</tt>
  75
+* <tt>mouse_move, :locator</tt>
  76
+* <tt>mouse_move_at, :locator, :coord_string</tt>
  77
+* <tt>mouse_out, :locator</tt>
  78
+* <tt>mouse_up, :locator</tt>
  79
+* <tt>mouse_up_at, :locator, :coord_string</tt>
  80
+* <tt>set_mouse_speed, :integer</tt>
  81
+
  82
+Other actions:
  83
+* <tt>create_cookie, :name_value_pair, :options_string</tt>
  84
+* <tt>delete_cookie, :string, :string</tt>
  85
+* <tt>open_window, :url, :integer</tt>
  86
+* <tt>pause, :timeout</tt>
  87
+* <tt>remove_all_selections, :locator</tt>
  88
+* <tt>select_frame, :locator</tt>
  89
+* <tt>set_cursor_position, :locator, :integer</tt>
  90
+* <tt>store, :script, :variable</tt>
  91
+* <tt>window_focus, :window_name</tt>
  92
+* <tt>window_maximize, :window_name</tt>
  93
+
  94
+Here are the newly supported accessors:
  95
+
  96
+The following store_* accessors and their associated assert, verify and wait_for brethren are fully supported:
  97
+* <tt>store_selected_id, :locator, :variable</tt>
  98
+* <tt>store_selected_ids, :locator, :variable</tt>
  99
+* <tt>store_selected_index, :locator, :variable</tt>
  100
+* <tt>store_selected_indexes, :locator, :variable</tt>
  101
+* <tt>store_selected_label, :locator, :variable</tt>
  102
+* <tt>store_selected_labels, :locator, :variable</tt>
  103
+* <tt>store_selected_value, :locator, :variable</tt>
  104
+* <tt>store_selected_values, :locator, :variable</tt>
  105
+* <tt>store_something_selected, :locator, :variable</tt>
  106
+* <tt>store_all_window_ids, :variable</tt>
  107
+* <tt>store_all_window_names, :variable</tt>
  108
+* <tt>store_all_window_titles, :variable</tt>
  109
+* <tt>store_cookie, :variable</tt>
  110
+* <tt>store_log_messages, :variable</tt>
  111
+* <tt>store_mouse_speed, :variable</tt>
  112
+* <tt>store_cursor_position, :locator, :variable</tt>
  113
+* <tt>store_attribute_from_all_windows, :attribute_name, :variable</tt>
  114
+* <tt>store_element_height, :locator, :variable</tt>
  115
+* <tt>store_element_index, :locator, :variable</tt>
  116
+* <tt>store_element_width, :locator, :variable</tt>
  117
+* <tt>store_element_position_left, :locator, :variable</tt>
  118
+* <tt>store_element_position_top, :locator, :variable</tt>
  119
+
  120
+Only the associated assert, verify and wait_for brethren of the following store_* accessors are supported by the selenium-core, so these store_* accessors create exceptions in SOR:
  121
+* <tt>store_ordered, :locator, :locator, :variable</tt>
  122
+* <tt>store_error_on_next, :string</tt>
  123
+* <tt>store_failure_on_next, :string</tt>
  124
+* <tt>store_whether_this_frame_match_frame_expression, :string, :string, :variable</tt>
  125
+* <tt>store_whether_this_window_match_window_expression, :string, :string, :variable</tt>
202  LICENSE-2.0.txt
... ...
@@ -0,0 +1,202 @@
  1
+
  2
+                                 Apache License
  3
+                           Version 2.0, January 2004
  4
+                        http://www.apache.org/licenses/
  5
+
  6
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
  7
+
  8
+   1. Definitions.
  9
+
  10
+      "License" shall mean the terms and conditions for use, reproduction,
  11
+      and distribution as defined by Sections 1 through 9 of this document.
  12
+
  13
+      "Licensor" shall mean the copyright owner or entity authorized by
  14
+      the copyright owner that is granting the License.
  15
+
  16
+      "Legal Entity" shall mean the union of the acting entity and all
  17
+      other entities that control, are controlled by, or are under common
  18
+      control with that entity. For the purposes of this definition,
  19
+      "control" means (i) the power, direct or indirect, to cause the
  20
+      direction or management of such entity, whether by contract or
  21
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
  22
+      outstanding shares, or (iii) beneficial ownership of such entity.
  23
+
  24
+      "You" (or "Your") shall mean an individual or Legal Entity
  25
+      exercising permissions granted by this License.
  26
+
  27
+      "Source" form shall mean the preferred form for making modifications,
  28
+      including but not limited to software source code, documentation
  29
+      source, and configuration files.
  30
+
  31
+      "Object" form shall mean any form resulting from mechanical
  32
+      transformation or translation of a Source form, including but
  33
+      not limited to compiled object code, generated documentation,
  34
+      and conversions to other media types.
  35
+
  36
+      "Work" shall mean the work of authorship, whether in Source or
  37
+      Object form, made available under the License, as indicated by a
  38
+      copyright notice that is included in or attached to the work
  39
+      (an example is provided in the Appendix below).
  40
+
  41
+      "Derivative Works" shall mean any work, whether in Source or Object
  42
+      form, that is based on (or derived from) the Work and for which the
  43
+      editorial revisions, annotations, elaborations, or other modifications
  44
+      represent, as a whole, an original work of authorship. For the purposes
  45
+      of this License, Derivative Works shall not include works that remain
  46
+      separable from, or merely link (or bind by name) to the interfaces of,
  47
+      the Work and Derivative Works thereof.
  48
+
  49
+      "Contribution" shall mean any work of authorship, including
  50
+      the original version of the Work and any modifications or additions
  51
+      to that Work or Derivative Works thereof, that is intentionally
  52
+      submitted to Licensor for inclusion in the Work by the copyright owner
  53
+      or by an individual or Legal Entity authorized to submit on behalf of
  54
+      the copyright owner. For the purposes of this definition, "submitted"
  55
+      means any form of electronic, verbal, or written communication sent
  56
+      to the Licensor or its representatives, including but not limited to
  57
+      communication on electronic mailing lists, source code control systems,
  58
+      and issue tracking systems that are managed by, or on behalf of, the
  59
+      Licensor for the purpose of discussing and improving the Work, but
  60
+      excluding communication that is conspicuously marked or otherwise
  61
+      designated in writing by the copyright owner as "Not a Contribution."
  62
+
  63
+      "Contributor" shall mean Licensor and any individual or Legal Entity
  64
+      on behalf of whom a Contribution has been received by Licensor and
  65
+      subsequently incorporated within the Work.
  66
+
  67
+   2. Grant of Copyright License. Subject to the terms and conditions of
  68
+      this License, each Contributor hereby grants to You a perpetual,
  69
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
  70
+      copyright license to reproduce, prepare Derivative Works of,
  71
+      publicly display, publicly perform, sublicense, and distribute the
  72
+      Work and such Derivative Works in Source or Object form.
  73
+
  74
+   3. Grant of Patent License. Subject to the terms and conditions of
  75
+      this License, each Contributor hereby grants to You a perpetual,
  76
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
  77
+      (except as stated in this section) patent license to make, have made,
  78
+      use, offer to sell, sell, import, and otherwise transfer the Work,
  79
+      where such license applies only to those patent claims licensable
  80
+      by such Contributor that are necessarily infringed by their
  81
+      Contribution(s) alone or by combination of their Contribution(s)
  82
+      with the Work to which such Contribution(s) was submitted. If You
  83
+      institute patent litigation against any entity (including a
  84
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
  85
+      or a Contribution incorporated within the Work constitutes direct
  86
+      or contributory patent infringement, then any patent licenses
  87
+      granted to You under this License for that Work shall terminate
  88
+      as of the date such litigation is filed.
  89
+
  90
+   4. Redistribution. You may reproduce and distribute copies of the
  91
+      Work or Derivative Works thereof in any medium, with or without
  92
+      modifications, and in Source or Object form, provided that You
  93
+      meet the following conditions:
  94
+
  95
+      (a) You must give any other recipients of the Work or
  96
+          Derivative Works a copy of this License; and
  97
+
  98
+      (b) You must cause any modified files to carry prominent notices
  99
+          stating that You changed the files; and
  100
+
  101
+      (c) You must retain, in the Source form of any Derivative Works
  102
+          that You distribute, all copyright, patent, trademark, and
  103
+          attribution notices from the Source form of the Work,
  104
+          excluding those notices that do not pertain to any part of
  105
+          the Derivative Works; and
  106
+
  107
+      (d) If the Work includes a "NOTICE" text file as part of its
  108
+          distribution, then any Derivative Works that You distribute must
  109
+          include a readable copy of the attribution notices contained
  110
+          within such NOTICE file, excluding those notices that do not
  111
+          pertain to any part of the Derivative Works, in at least one
  112
+          of the following places: within a NOTICE text file distributed
  113
+          as part of the Derivative Works; within the Source form or
  114
+          documentation, if provided along with the Derivative Works; or,
  115
+          within a display generated by the Derivative Works, if and
  116
+          wherever such third-party notices normally appear. The contents
  117
+          of the NOTICE file are for informational purposes only and
  118
+          do not modify the License. You may add Your own attribution
  119
+          notices within Derivative Works that You distribute, alongside
  120
+          or as an addendum to the NOTICE text from the Work, provided
  121
+          that such additional attribution notices cannot be construed
  122
+          as modifying the License.
  123
+
  124
+      You may add Your own copyright statement to Your modifications and
  125
+      may provide additional or different license terms and conditions
  126
+      for use, reproduction, or distribution of Your modifications, or
  127
+      for any such Derivative Works as a whole, provided Your use,
  128
+      reproduction, and distribution of the Work otherwise complies with
  129
+      the conditions stated in this License.
  130
+
  131
+   5. Submission of Contributions. Unless You explicitly state otherwise,
  132
+      any Contribution intentionally submitted for inclusion in the Work
  133
+      by You to the Licensor shall be under the terms and conditions of
  134
+      this License, without any additional terms or conditions.
  135
+      Notwithstanding the above, nothing herein shall supersede or modify
  136
+      the terms of any separate license agreement you may have executed
  137
+      with Licensor regarding such Contributions.
  138
+
  139
+   6. Trademarks. This License does not grant permission to use the trade
  140
+      names, trademarks, service marks, or product names of the Licensor,
  141
+      except as required for reasonable and customary use in describing the
  142
+      origin of the Work and reproducing the content of the NOTICE file.
  143
+
  144
+   7. Disclaimer of Warranty. Unless required by applicable law or
  145
+      agreed to in writing, Licensor provides the Work (and each
  146
+      Contributor provides its Contributions) on an "AS IS" BASIS,
  147
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  148
+      implied, including, without limitation, any warranties or conditions
  149
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
  150
+      PARTICULAR PURPOSE. You are solely responsible for determining the
  151
+      appropriateness of using or redistributing the Work and assume any
  152
+      risks associated with Your exercise of permissions under this License.
  153
+
  154
+   8. Limitation of Liability. In no event and under no legal theory,
  155
+      whether in tort (including negligence), contract, or otherwise,
  156
+      unless required by applicable law (such as deliberate and grossly
  157
+      negligent acts) or agreed to in writing, shall any Contributor be
  158
+      liable to You for damages, including any direct, indirect, special,
  159
+      incidental, or consequential damages of any character arising as a
  160
+      result of this License or out of the use or inability to use the
  161
+      Work (including but not limited to damages for loss of goodwill,
  162
+      work stoppage, computer failure or malfunction, or any and all
  163
+      other commercial damages or losses), even if such Contributor
  164
+      has been advised of the possibility of such damages.
  165
+
  166
+   9. Accepting Warranty or Additional Liability. While redistributing
  167
+      the Work or Derivative Works thereof, You may choose to offer,
  168
+      and charge a fee for, acceptance of support, warranty, indemnity,
  169
+      or other liability obligations and/or rights consistent with this
  170
+      License. However, in accepting such obligations, You may act only
  171
+      on Your own behalf and on Your sole responsibility, not on behalf
  172
+      of any other Contributor, and only if You agree to indemnify,
  173
+      defend, and hold each Contributor harmless for any liability
  174
+      incurred by, or claims asserted against, such Contributor by reason
  175
+      of your accepting any such warranty or additional liability.
  176
+
  177
+   END OF TERMS AND CONDITIONS
  178
+
  179
+   APPENDIX: How to apply the Apache License to your work.
  180
+
  181
+      To apply the Apache License to your work, attach the following
  182
+      boilerplate notice, with the fields enclosed by brackets "[]"
  183
+      replaced with your own identifying information. (Don't include
  184
+      the brackets!)  The text should be enclosed in the appropriate
  185
+      comment syntax for the file format. We also recommend that a
  186
+      file or class name and description of purpose be included on the
  187
+      same "printed page" as the copyright notice for easier
  188
+      identification within third-party archives.
  189
+
  190
+   Copyright [yyyy] [name of copyright owner]
  191
+
  192
+   Licensed under the Apache License, Version 2.0 (the "License");
  193
+   you may not use this file except in compliance with the License.
  194
+   You may obtain a copy of the License at
  195
+
  196
+       http://www.apache.org/licenses/LICENSE-2.0
  197
+
  198
+   Unless required by applicable law or agreed to in writing, software
  199
+   distributed under the License is distributed on an "AS IS" BASIS,
  200
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  201
+   See the License for the specific language governing permissions and
  202
+   limitations under the License.
193  README
... ...
@@ -0,0 +1,193 @@
  1
+= Selenium on Rails
  2
+
  3
+== Overview
  4
+
  5
+Selenium on Rails provides an easy way to test Rails application with 
  6
+SeleniumCore[http://www.openqa.org/selenium-core/].
  7
+
  8
+This plugin does four things:
  9
+1. The Selenium Core files don't have to pollute <tt>/public</tt>.
  10
+2. No need to create suite files, they are generated on the fly -- one suite per directory in <tt>/test/selenium</tt> (suites can be nested).
  11
+3. Instead of writing the test cases in HTML you can use a number of better formats (see <tt>Formats</tt>).
  12
+4. Loading of fixtures and wiping of session (<tt>/selenium/setup</tt>).
  13
+
  14
+== Installation
  15
+
  16
+1. Install Selenium on Rails: <tt>script/plugin install http://svn.openqa.org/svn/selenium-on-rails/selenium-on-rails</tt>
  17
+2. If you're on Windows, <tt>gem install win32-open3</tt>
  18
+3. <i>If the RedCloth gem is available the Selenese test cases can use it for better markup.</i>
  19
+4. Run the Rakefile in the plugin's directory to run the tests in order to see that everything works. (If RedCloth isn't installed a few tests will fail since they assume RedCloth is installed.)
  20
+5. Create a test case: <tt>script/generate selenium login</tt>
  21
+6. Start the server: <tt>script/server -e test</tt>
  22
+7. Point your browser to <tt>http://localhost:3000/selenium</tt>
  23
+8. If everything works as expected you should see the Selenium test runner. The north east frame contains all your test cases (just one for now), and the north frame contains your test case.
  24
+
  25
+== Formats
  26
+
  27
+The test cases can be written in a number of formats. Which one you choose is a 
  28
+matter of taste. You can generate your test files by running 
  29
+<tt>script/generate selenium</tt> or by creating them manually in your 
  30
+<tt>/test/selenium</tt> directory.
  31
+
  32
+=== Selenese, .sel
  33
+
  34
+Selenese is the dumbest format (in a good way). You just write your commands
  35
+delimited by | characters.
  36
+
  37
+ |open|/selenium/setup|
  38
+ |open|/|
  39
+ |goBack|
  40
+
  41
+If you don't want to write Selenese tests by hand you can use
  42
+SeleniumIDE[http://www.openqa.org/selenium-ide/] which has 
  43
+support[http://wiki.openqa.org/display/SIDE/SeleniumOnRails] for Selenese.
  44
+
  45
+SeleniumIDE makes it super easy to record test and edit them.
  46
+
  47
+=== RSelenese, .rsel
  48
+
  49
+RSelenese enable you to write your tests in Ruby.
  50
+
  51
+ setup :fixtures => :all
  52
+ open '/'
  53
+ assert_title 'Home'
  54
+ ('a'..'z').each {|c| open :controller => 'user', :action => 'create', :name => c }
  55
+
  56
+See SeleniumOnRails::TestBuilder for available commands.
  57
+
  58
+=== HTML/RHTML
  59
+
  60
+You can write your tests in HTML/RHTML but that's mostly useful if you have 
  61
+existing tests you want to reuse.
  62
+
  63
+=== Partial test cases
  64
+
  65
+If you have some common actions you want to do in several test cases you can put
  66
+them in a separate partial test case and include them in your other test cases.
  67
+
  68
+A partial test case is just like a normal test case besides that its filename
  69
+has to start with _:
  70
+
  71
+ #_login.rsel
  72
+ open '/login'
  73
+ type 'name', name
  74
+ type 'password', password
  75
+ click 'submit', :wait=>true
  76
+
  77
+To include a partial test case you write like this in a Selenese test case:
  78
+
  79
+ |includePartial|login|name=John Doe|password=eoD nhoJ|
  80
+
  81
+in a RSelenese test case:
  82
+ 
  83
+ include_partial 'login', :name => 'Jane Doe', :password => 'Jane Doe'.reverse
  84
+
  85
+and in a RHTML test case:
  86
+
  87
+ <%= render :partial => 'login', :locals => {:name = 'Joe Schmo', :password => 'Joe Schmo'.reverse} %>
  88
+
  89
+== Configuration
  90
+
  91
+There are a number of settings available. You make them by renaming 
  92
+<tt>config.yml.example</tt> to <tt>config.yml</tt> and make your changes in that
  93
+file.
  94
+
  95
+=== Environments
  96
+
  97
+Per default this plugin is only available in test environment. You can change 
  98
+this by setting <tt>environments</tt>, such as:
  99
+
  100
+ #config.yml
  101
+ environments:
  102
+   - test
  103
+   - development
  104
+
  105
+=== Selenium Core path
  106
+
  107
+If you don't want to use the bundled Selenium Core version you can set 
  108
+<tt>selenium_path</tt> to the directory where Selenium Core is stored.
  109
+
  110
+ #config.yml
  111
+ selenium_path: 'c:\selenium'
  112
+
  113
+== <tt>test:acceptance</tt>
  114
+
  115
+You can run all your Selenium tests as a Rake task.
  116
+
  117
+First, if you're on Windows, you have to make sure win32-open3 is installed. 
  118
+Then you have to configure which browsers you want to run, like this:
  119
+ 
  120
+ #config.yml
  121
+ browsers:
  122
+   firefox: 'c:\Program Files\Mozilla Firefox\firefox.exe'
  123
+   ie: 'c:\Program Files\Internet Explorer\iexplore.exe'
  124
+
  125
+Now you're all set. First start a server:
  126
+
  127
+ script/server -e test
  128
+
  129
+Then run the tests:
  130
+
  131
+ rake test:acceptance
  132
+
  133
+Now it should work, otherwise let me know!
  134
+
  135
+=== Store results
  136
+
  137
+If you want to store the results from a <tt>test:acceptance</tt> you just need
  138
+to set in which directory they should be stored:
  139
+
  140
+ #config.yml
  141
+ result_dir: 'c:\result'
  142
+
  143
+So when you run <tt>rake test:acceptance</tt> the tables with the results will
  144
+be stored as <tt>.html</tt> files in that directory.
  145
+
  146
+This can be useful especially for continous integration.
  147
+
  148
+=== user_extension.js
  149
+
  150
+Selenium has support for <tt>user_extension.js</tt> which is a way to extend the 
  151
+functionality of Selenium Core. Selenium on Rails now provides the means for you
  152
+to extend it's functionality to match.
  153
+
  154
+To get you started, we've included the example files 
  155
+<tt>lib/test_builder_user_accessors.rb.example</tt> and 
  156
+<tt>lib/test_builder_user_actions.rb.example</tt> that replicate the sample
  157
+extensions in Selenium Core's <tt>user-extensions.js.sample</tt>
  158
+
  159
+To get these examples running, simply remove the .example and .sample extensions 
  160
+from the files and restart your server.
  161
+
  162
+== Todo
  163
+
  164
+=== Standalone mode
  165
+
  166
+More work is needed on <tt>test:acceptance</tt> on Windows to be able to start 
  167
+the server when needed.
  168
+
  169
+=== More setup/teardown support?
  170
+
  171
+Currently there is only support to load fixtures and to wipe the session in
  172
+<tt>/selenium/setup</tt>. Is there a need for more kinds of setups or teardowns?
  173
+
  174
+=== More documentation
  175
+
  176
+
  177
+== Not todo
  178
+
  179
+=== Editor
  180
+
  181
+Creating an editor for the test cases is currently considered out of scope for 
  182
+this plugin. SeleniumIDE[http://www.openqa.org/selenium-ide/] does such a good 
  183
+job and has support[http://wiki.openqa.org/display/SIDE/SeleniumOnRails] for 
  184
+the Selenese format.
  185
+
  186
+== Credits
  187
+
  188
+* Jon Tirsen, http://jutopia.tirsen.com -- initial inspiration[http://wiki.rubyonrails.com/rails/pages/SeleniumIntegration]
  189
+* Eric Kidd, http://www.randomhacks.net -- contribution of RSelenese
  190
+
  191
+== Information
  192
+
  193
+For more information, check out the website[http://www.openqa.org/selenium-on-rails/].
27  Rakefile
... ...
@@ -0,0 +1,27 @@
  1
+require 'rake'
  2
+require 'rake/testtask'
  3
+require 'rdoc/rdoc'
  4
+
  5
+desc 'Default: run unit tests.'
  6
+task :default => :test
  7
+
  8
+desc 'Test the Selenium on Rails plugin.'
  9
+Rake::TestTask.new(:test) do |t|
  10
+  t.libs << 'lib'
  11
+  t.pattern = 'test/**/*_test.rb'
  12
+  t.verbose = true
  13
+end
  14
+
  15
+desc 'Generate documentation for the Selenium on Rails plugin.'
  16
+task :rdoc do
  17
+  rm_rf 'doc'
  18
+  RDoc::RDoc.new.document(%w(--line-numbers --inline-source --title SeleniumOnRails README CHANGELOG lib))
  19
+end
  20
+
  21
+begin
  22
+  require 'rcov/rcovtask'
  23
+  Rcov::RcovTask.new do |t|
  24
+    t.test_files = FileList['test/*_test.rb']
  25
+  end
  26
+rescue LoadError #if rcov isn't available, ignore
  27
+end
33  config.yml.example
... ...
@@ -0,0 +1,33 @@
  1
+# Rename this file to config.yml in order to configure the plugin
  2
+
  3
+#
  4
+# General settings
  5
+#
  6
+
  7
+environments:
  8
+  - test
  9
+#  - development # Uncomment this line to enable in development environment. N.B. your development database will likely be altered/destroyed/abducted
  10
+
  11
+#selenium_path: 'c:\selenium' #path to selenium installation. only needed if you for some reason don't want to use the bundled version of selenium core
  12
+
  13
+#
  14
+# rake test:acceptance settings
  15
+#
  16
+
  17
+browsers:
  18
+  # Windows
  19
+  firefox: 'c:\Program Files\Mozilla Firefox\firefox.exe'
  20
+  ie: 'c:\Program Files\Internet Explorer\iexplore.exe'
  21
+
  22
+  # Mac OS X
  23
+  #firefox: '/Applications/Firefox.app/Contents/MacOS/firefox-bin'
  24
+  #safari: '/Applications/Safari.app/Contents/MacOS/Safari'
  25
+
  26
+#host: 'localhost'
  27
+#port_start: 3000
  28
+#port_end: 3005
  29
+#base_url_path: '/'
  30
+#max_browser_duration: 120
  31
+#multi_window: false
  32
+  
  33
+#result_dir: 'c:\result' # the directory where the results will be stored after a test:acceptance run
19  generators/selenium/USAGE
... ...
@@ -0,0 +1,19 @@
  1
+Description:
  2
+    Generates a stub Selenium test case.
  3
+
  4
+Examples:
  5
+    ./script/generate selenium login
  6
+    will create:
  7
+        /test/selenium/login.sel
  8
+    
  9
+    ./script/generate selenium user/create
  10
+    will create:
  11
+        /test/selenium/user/create.sel
  12
+
  13
+    ./script/generate selenium login.rsel
  14
+    will create:
  15
+        /test/selenium/login.rsel
  16
+        
  17
+    ./script/generate selenium logout.rhtml
  18
+    will create:
  19
+        /test/selenium/logout.rhtml
50  generators/selenium/selenium_generator.rb
... ...
@@ -0,0 +1,50 @@
  1
+class SeleniumGenerator < Rails::Generator::Base
  2
+  def initialize runtime_args, runtime_options = {}
  3
+    super
  4
+    usage if @args.empty?
  5
+  end
  6
+
  7
+  def banner
  8
+    "Usage: #{$0} #{spec.name} testname [options]"
  9
+  end
  10
+
  11
+  def manifest
  12
+    record do |m|
  13
+      path = 'test/selenium'
  14
+      path = File.join(path, suite_path) unless suite_path.empty?
  15
+      m.directory path
  16
+
  17
+      template = case File.extname(filename)
  18
+                   when '.rhtml' then 'rhtml.rhtml'
  19
+                   when '.rsel' then 'rselenese.rhtml'
  20
+                   else 'selenese.rhtml'
  21
+                 end
  22
+      m.template template, File.join(path, filename)
  23
+    end
  24
+  end
  25
+
  26
+  def filename
  27
+    name = File.basename args[0]
  28
+    extensions = ['.sel', '.rhtml', '.rsel']
  29
+    name =  "#{name}.sel" unless extensions.include? File.extname(name)
  30
+    name
  31
+  end
  32
+
  33
+  def suite_path
  34
+    sp = File.dirname args[0]
  35
+    sp = '' if sp == '.'
  36
+    sp
  37
+  end
  38
+
  39
+  def testcase_link
  40
+    l = "http://localhost:3000/selenium/tests/"
  41
+    l = "#{l}#{suite_path}/" unless suite_path.empty?
  42
+    l + filename
  43
+  end
  44
+
  45
+  def suite_link
  46
+    l = "http://localhost:3000/selenium"
  47
+    l = "#{l}/TestRunner.html?test=tests/#{suite_path}" unless suite_path.empty?
  48
+    l
  49
+  end
  50
+end
16  generators/selenium/templates/rhtml.rhtml
... ...
@@ -0,0 +1,16 @@
  1
+<p>It's often a good idea to start the test with opening <tt>/selenium/setup</tt> (see <%%= link_to 'here', :controller => 'selenium', :action => 'setup' %> for more info).</p>
  2
+
  3
+<table>
  4
+	<tr><th colspan="3"><%%= @page_title %></th></tr>
  5
+	<tr><td>open</td><td>/selenium/setup</td><td>&nbsp;</td></tr>
  6
+<%% for page in ['/', '/home'] -%>
  7
+	<tr><td>open</td><td><%%= page %></td><td>&nbsp;</td></tr>
  8
+	<tr><td>assertTitle</td><td>Home</td><td>&nbsp;</td></tr>
  9
+<%% end -%>
  10
+</table>
  11
+
  12
+<p>More information about the commands is available <a href="http://release.openqa.org/selenium-core/nightly/reference.html">here</a>.</p>
  13
+
  14
+<p>You can write comments above and below the commands, but you can only have one set of commands, i.e. one table, per test.</p>
  15
+
  16
+<p>Point the browser to <a href="<%= testcase_link %>"><%= testcase_link %></a> to see how this test is rendered, or to <a href="<%= suite_link %>"><%= suite_link %></a> to run the suite.</p>
14  generators/selenium/templates/rselenese.rhtml
... ...
@@ -0,0 +1,14 @@
  1
+# It's often a good idea to start the test with 'setup'.
  2
+# See /selenium/setup for more info.
  3
+
  4
+setup
  5
+open '/'
  6
+assert_title 'Home'
  7
+
  8
+# More information about the commands is available at:
  9
+#   http://release.openqa.org/selenium-core/nightly/reference.html
  10
+# See also the RDoc for SeleniumOnRails::TestBuilder.
  11
+#
  12
+# Point the browser to <%= testcase_link %> to see
  13
+# how this test is rendered, or to <%= suite_link %> to
  14
+# run the suite.
11  generators/selenium/templates/selenese.rhtml
... ...
@@ -0,0 +1,11 @@
  1
+It's often a good idea to start the test with opening <tt>/selenium/setup</tt> (see "here":/selenium/setup for more info).
  2
+
  3
+|open|/selenium/setup|
  4
+|open|/|
  5
+|assertTitle|Home|
  6
+
  7
+More information about the commands is available "here":http://release.openqa.org/selenium-core/nightly/reference.html.
  8
+
  9
+You can write comments above and below the commands, but you can only have one set of commands, i.e. one table, per test. "RedCloth":http://www.whytheluckystiff.net/ruby/redcloth/ is used for formatting if installed.
  10
+
  11
+Point the browser to "<%= testcase_link %>":<%= testcase_link %> to see how this test is rendered, or to "<%= suite_link %>":<%= suite_link %> to run the suite.
19  init.rb
... ...
@@ -0,0 +1,19 @@
  1
+require 'selenium_on_rails_config'
  2
+envs = SeleniumOnRailsConfig.get :environments
  3
+
  4
+if envs.include? RAILS_ENV
  5
+  #initialize the plugin
  6
+  $LOAD_PATH << File.dirname(__FILE__) + "/lib/controllers"
  7
+  require 'selenium_controller'
  8
+  require File.dirname(__FILE__) + '/routes'
  9
+
  10
+else
  11
+  #erase all traces
  12
+  $LOAD_PATH.delete lib_path
  13
+  
  14
+  #but help user figure out what to do
  15
+  unless RAILS_ENV == 'production' # don't pollute production
  16
+    require File.dirname(__FILE__) + '/switch_environment/init'
  17
+  end
  18
+end
  19
+
119  lib/controllers/selenium_controller.rb
... ...
@@ -0,0 +1,119 @@
  1
+require 'webrick/httputils'
  2
+
  3
+class SeleniumController < ActionController::Base
  4
+  include SeleniumOnRails::FixtureLoader
  5
+  include SeleniumOnRails::Renderer
  6
+
  7
+  def setup
  8
+    unless params.has_key? :keep_session
  9
+      reset_session
  10
+      @session_wiped = true
  11
+    end
  12
+    @cleared_tables = clear_tables params[:clear_tables].to_s
  13
+    @loaded_fixtures = load_fixtures params[:fixtures].to_s
  14
+    render :file => view_path('setup.rhtml'), :layout => layout_path
  15
+  end
  16
+
  17
+  def test_file
  18
+    params[:testname] = '' if params[:testname].to_s == 'TestSuite.html'
  19
+    filename = File.join selenium_tests_path, params[:testname]
  20
+    if File.directory? filename
  21
+      @suite_path = filename
  22
+      render :file => view_path('test_suite.rhtml'), :layout => layout_path
  23
+    elsif File.readable? filename
  24
+      render_test_case filename
  25
+    else
  26
+      if File.directory? selenium_tests_path
  27
+        render :text => 'Not found', :status => 404
  28
+      else
  29
+        render :text => "Did not find the Selenium tests path (#{selenium_tests_path}). Run script/generate selenium", :status => 404
  30
+      end
  31
+    end
  32
+  end
  33
+
  34
+  def support_file
  35
+    if params[:filename].empty?
  36
+      redirect_to :filename => 'TestRunner.html', :test => 'tests'
  37
+      return
  38
+    end
  39
+
  40
+    filename = File.join selenium_path, params[:filename]
  41
+    if File.file? filename
  42
+      type = WEBrick::HTTPUtils::DefaultMimeTypes[$1.downcase] if filename =~ /\.(\w+)$/
  43
+      type ||= 'text/html'
  44
+      send_file filename, :type => type, :disposition => 'inline', :stream => false
  45
+    else
  46
+      render :text => 'Not found', :status => 404
  47
+    end
  48
+  end
  49
+
  50
+  def record
  51
+    dir = record_table
  52
+
  53
+    @result = {'resultDir' => dir}
  54
+    for p in ['result', 'numTestFailures', 'numTestPasses', 'numCommandFailures', 'numCommandPasses', 'numCommandErrors', 'totalTime']
  55
+      @result[p] = params[p]
  56
+    end
  57
+    File.open(log_path(params[:logFile] || 'default.yml'), 'w') {|f| YAML.dump(@result, f)}
  58
+    
  59
+    render :file => view_path('record.rhtml'), :layout => layout_path
  60
+  end
  61
+
  62
+  def record_table
  63
+    return nil unless result_dir = SeleniumOnRailsConfig.get(:result_dir)
  64
+
  65
+    cur_result_dir = File.join(result_dir, (params[:logFile] || "default").sub(/\.yml$/, ''))
  66
+    FileUtils.mkdir_p(cur_result_dir)
  67
+    File.open("#{cur_result_dir}/index.html", "wb") do |f|
  68
+      f.write <<EOS
  69
+<html>
  70
+<head><title>Selenium Test Result</title></head>
  71
+<frameset cols="30%,*">
  72
+<frame name="suite" src="suite.html">
  73
+<frame name="testcase" src="blank.html">
  74
+</frameset>
  75
+</html>
  76
+EOS
  77
+    end
  78
+    html_header = <<EOS
  79
+<html>
  80
+<head>
  81
+<link rel="stylesheet" type="text/css" href="selenium-test.css">
  82
+</head>
  83
+<body>
  84
+EOS
  85
+    html_footer = "</body></html>\n"
  86
+    if selenium_path
  87
+      css_file = File.join selenium_path, "selenium-test.css"
  88
+      if File.exist?(css_file)
  89
+        FileUtils.cp css_file, cur_result_dir
  90
+      end
  91
+    end
  92
+    File.open("#{cur_result_dir}/blank.html", "wb") do |f|
  93
+      f.write "<html><body></body></html>"
  94
+    end
  95
+    File.open("#{cur_result_dir}/suite.html", "wb") do |f|
  96
+      suite = params[:suite]
  97
+      suite.sub!(/^.*(<table[\s>])/im, '\1')
  98
+      i = 1
  99
+      suite.gsub!(/(\shref=)"[^"]*"/i) do |m|
  100
+        link = "#{$1}\"test#{i}.html\" target=\"testcase\""
  101
+        File.open("#{cur_result_dir}/test#{i}.html", "wb") do |testcase|
  102
+          testcase.write html_header
  103
+          testcase.write(params["testTable.#{i}"])
  104
+          testcase.write html_footer
  105
+        end
  106
+        i += 1
  107
+        link
  108
+      end
  109
+      f.write html_header
  110
+      f.write suite
  111
+      f.write html_footer
  112
+    end
  113
+    cur_result_dir
  114
+  end
  115
+  
  116
+  private :record_table
  117
+  
  118
+
  119
+end
9  lib/selenium_helper.rb
... ...
@@ -0,0 +1,9 @@
  1
+module SeleniumHelper
  2
+  include SeleniumOnRails::SuiteRenderer
  3
+  include SeleniumOnRails::FixtureLoader
  4
+
  5
+  def test_case_name filename
  6
+    File.basename(filename).sub(/\..*/,'').humanize
  7
+  end
  8
+
  9
+end
11  lib/selenium_on_rails.rb
... ...
@@ -0,0 +1,11 @@
  1
+module SeleniumOnRails # :nodoc
  2
+end
  3
+
  4
+require 'selenium_on_rails/selenese'
  5
+require 'selenium_on_rails/test_builder'
  6
+require 'selenium_on_rails/rselenese'
  7
+require 'selenium_on_rails/suite_renderer'
  8
+require 'selenium_on_rails/paths'
  9
+require 'selenium_on_rails/fixture_loader'
  10
+require 'selenium_on_rails/partials_support'
  11
+require 'selenium_on_rails/renderer'
212  lib/selenium_on_rails/acceptance_test_runner.rb
... ...
@@ -0,0 +1,212 @@
  1
+require File.dirname(__FILE__) + '/paths'
  2
+require File.dirname(__FILE__) + '/../selenium_on_rails_config'
  3
+require 'net/http'
  4
+require 'tempfile'
  5
+
  6
+
  7
+def c(var, default = nil) SeleniumOnRailsConfig.get var, default end
  8
+def c_b(var, default = nil) SeleniumOnRailsConfig.get(var, default) { yield } end
  9
+
  10
+BROWSERS =              c :browsers, {}
  11
+REUSE_EXISTING_SERVER = c :reuse_existing_server, true
  12
+START_SERVER =          c :start_server, false  #TODO can't get it to work reliably on Windows, perhaps it's just on my computer, but I leave it off by default for now
  13
+HOST =                  c :host, 'localhost'
  14
+PORTS =                 c(:port_start, 3000)..c(:port_end, 3005)
  15
+BASE_URL_PATH =         c :base_url_path, '/'
  16
+TEST_RUNNER_URL =       c :test_runner_url, '/selenium/TestRunner.html'
  17
+MAX_BROWSER_DURATION =  c :max_browser_duration, 2*60
  18
+MULTI_WINDOW =          c :multi_window, false
  19
+SERVER_COMMAND =      c_b :server_command do
  20
+  server_path = File.expand_path(File.dirname(__FILE__) + '/../../../../../script/server')
  21
+  if RUBY_PLATFORM =~ /mswin/
  22
+    "ruby #{server_path} webrick -p %d -e test > NUL 2>&1"
  23
+  else
  24
+    # don't use redirects to /dev/nul since it makes the fork return wrong pid
  25
+    # see UnixSubProcess
  26
+    "#{server_path} webrick -p %d -e test"
  27
+  end
  28
+end
  29
+
  30
+module SeleniumOnRails
  31
+  class AcceptanceTestRunner
  32
+    include SeleniumOnRails::Paths
  33
+  
  34
+    def run
  35
+      raise 'no browser specified, edit/create config.yml' if BROWSERS.empty?
  36
+      start_server
  37
+      has_error = false
  38
+      begin
  39
+        BROWSERS.each_pair do |browser, path|
  40
+          log_file = start_browser browser, path
  41
+          wait_for_completion log_file
  42
+          stop_browser
  43
+          result = YAML::load_file log_file
  44
+          print_result result
  45
+          has_error ||= result['numTestFailures'].to_i > 0
  46
+          File.delete log_file unless has_error
  47
+        end
  48
+      rescue
  49
+        stop_server
  50
+        raise
  51
+      end
  52
+      stop_server
  53
+      raise 'Test failures' if has_error
  54
+    end
  55
+    
  56
+    private
  57
+      def start_server
  58
+        PORTS.each do |p|
  59
+          @port = p
  60
+          case server_check
  61
+            when :success
  62
+              return if REUSE_EXISTING_SERVER
  63
+              next
  64
+            when Fixnum
  65
+              next
  66
+            when :no_response
  67
+              next unless START_SERVER
  68
+              do_start_server
  69
+              return
  70
+          end
  71
+        end
  72
+        raise START_SERVER ? 'failed to start server': 'failed to find existing server, run script/server -e test'
  73
+      end
  74
+      
  75
+      def do_start_server
  76
+        puts 'Starting server'
  77
+        @server = start_subprocess(format(SERVER_COMMAND, @port))
  78
+        while true
  79
+          print '.'
  80
+          r = server_check
  81
+          if r == :success
  82
+            puts
  83
+            return
  84
+          end
  85
+          raise "server returned error: #{r}" if r.instance_of? Fixnum
  86
+          sleep 3
  87
+        end
  88
+      end
  89
+    
  90
+      def server_check
  91
+        begin
  92
+          res = Net::HTTP.get_response HOST, TEST_RUNNER_URL, @port
  93
+          return :success if (200..399).include? res.code.to_i
  94
+          return res.code.to_i
  95
+        rescue Errno::ECONNREFUSED
  96
+          return :no_response
  97
+        end
  98
+      end
  99
+    
  100
+      def stop_server
  101
+        return unless defined? @server
  102
+        puts
  103
+        @server.stop 'server'
  104
+      end
  105
+    
  106
+      def start_browser browser, path
  107
+        puts
  108
+        puts "Starting #{browser}"
  109
+        base_url = "http://#{HOST}:#{@port}#{BASE_URL_PATH}"
  110
+        log = log_file browser
  111
+        command = "\"#{path}\" \"http://#{HOST}:#{@port}#{TEST_RUNNER_URL}?test=tests&auto=true&baseUrl=#{base_url}&resultsUrl=postResults/#{log}&multiWindow=#{MULTI_WINDOW}\""
  112
+        @browser = start_subprocess command    
  113
+        log_path log
  114
+      end
  115
+      
  116
+      def stop_browser
  117
+        @browser.stop 'browser'
  118
+      end
  119
+      
  120
+      def start_subprocess command
  121
+        if RUBY_PLATFORM =~ /mswin/
  122
+          SeleniumOnRails::AcceptanceTestRunner::Win32SubProcess.new command
  123
+        elsif RUBY_PLATFORM =~ /darwin/i && command =~ /safari/i
  124
+          SeleniumOnRails::AcceptanceTestRunner::SafariSubProcess.new command
  125
+        else
  126
+          SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess.new command
  127
+        end
  128
+      end
  129
+      
  130
+      def log_file browser
  131
+        (0..100).each do |i|
  132
+          name = browser + (i==0 ? '' : "(#{i})") + '.yml'
  133
+          return name unless File.exist?(log_path(name))
  134
+        end
  135
+        raise 'there are way too many files in the log directory...'
  136
+      end
  137
+    
  138
+      def wait_for_completion log_file
  139
+        duration = 0
  140
+        while true
  141
+          raise 'browser takes too long' if duration > MAX_BROWSER_DURATION
  142
+          print '.'
  143
+          break if File.exist? log_file
  144
+          sleep 5
  145
+          duration += 5
  146
+        end
  147
+        puts
  148
+      end
  149
+    
  150
+      def print_result result
  151
+        puts "Finished in #{result['totalTime']} seconds."
  152
+        puts
  153
+        puts "#{result['numTestPasses']} tests passed, #{result['numTestFailures']} tests failed"
  154
+        puts "(Results stored in '#{result['resultDir']}')" if result['resultDir']
  155
+      end
  156
+        
  157
+  end
  158
+end
  159
+
  160
+class SeleniumOnRails::AcceptanceTestRunner::SubProcess
  161
+  def stop what
  162
+    begin
  163
+      puts "Stopping #{what} (pid=#{@pid}) ..."
  164
+      Process.kill 9, @pid
  165
+    rescue Errno::EPERM #such as the process is already closed (tabbed browser)
  166
+    end
  167
+  end
  168
+end
  169
+
  170
+class SeleniumOnRails::AcceptanceTestRunner::Win32SubProcess < SeleniumOnRails::AcceptanceTestRunner::SubProcess
  171
+  def initialize command
  172
+    require 'win32/open3' #win32-open3 http://raa.ruby-lang.org/project/win32-open3/
  173
+
  174
+    puts command
  175
+    input, output, error, @pid = Open4.popen4 command, 't', true
  176
+  end
  177
+end
  178
+
  179
+class SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess < SeleniumOnRails::AcceptanceTestRunner::SubProcess
  180
+  def initialize command
  181
+    puts command
  182
+    @pid = fork do
  183
+      # Since we can't use shell redirects without screwing 
  184
+      # up the pid, we'll reopen stdin and stdout instead
  185
+      # to get the same effect.
  186
+      [STDOUT,STDERR].each {|f| f.reopen '/dev/null', 'w' }
  187
+      exec command
  188
+    end
  189
+  end
  190
+end
  191
+
  192
+# The path to Safari should look like this: /Applications/Safari.app/Contents/MacOS/Safari
  193
+class SeleniumOnRails::AcceptanceTestRunner::SafariSubProcess < SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess
  194
+  def initialize command
  195
+    f = File.open(Tempfile.new('selenium-on-rails').path, 'w')
  196
+    f.puts <<-HTML
  197
+      <html>
  198
+        <head>
  199
+          <script type="text/javascript" charset="utf-8">
  200
+            window.location.href = #{command.split.last};
  201
+          </script>
  202
+        </head>
  203
+        <body></body>
  204
+      </html>
  205
+    HTML
  206
+    f.close
  207
+    
  208
+    super "#{command.split.first} #{f.path}"
  209
+   end
  210
+  
  211
+end
  212
+  
55  lib/selenium_on_rails/fixture_loader.rb
... ...
@@ -0,0 +1,55 @@
  1
+require 'test/unit'
  2
+require 'active_record/fixtures'
  3
+
  4
+module SeleniumOnRails::FixtureLoader
  5
+  include SeleniumOnRails::Paths
  6
+  
  7
+  def available_fixtures
  8
+    fixtures = {}
  9
+    path = fixtures_path + '/'
  10
+    files = Dir["#{path}**/*.{yml,csv}"]
  11
+    files.each do |file|
  12
+      rel_path = file.sub(path, '')