waw 0.2.2

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 (199) hide show
  1. data/LICENCE.rdoc +25 -0
  2. data/README.rdoc +32 -0
  3. data/bin/waw +32 -0
  4. data/bin/waw-profile +26 -0
  5. data/bin/waw-start +26 -0
  6. data/bin/wspec +33 -0
  7. data/layouts/empty/Rakefile +14 -0
  8. data/layouts/empty/config.ru +5 -0
  9. data/layouts/empty/config/commons.cfg +31 -0
  10. data/layouts/empty/config/devel.cfg +21 -0
  11. data/layouts/empty/ignore +7 -0
  12. data/layouts/empty/logs/dontforgetme +0 -0
  13. data/layouts/empty/resources/messages.rs +1 -0
  14. data/layouts/empty/test/wspec/site_respond.wspec +3 -0
  15. data/layouts/empty/test/wspec/test_all.rb +13 -0
  16. data/layouts/empty/waw.deploy +1 -0
  17. data/layouts/empty/waw.routing +6 -0
  18. data/layouts/static/dependencies +1 -0
  19. data/layouts/static/public/.wawaccess +18 -0
  20. data/layouts/static/public/css/style.css +0 -0
  21. data/layouts/static/public/images/dontforgetme +0 -0
  22. data/layouts/static/public/js/project.js +0 -0
  23. data/layouts/static/public/pages/.wawaccess +30 -0
  24. data/layouts/static/public/pages/404.wtpl +1 -0
  25. data/layouts/static/public/pages/index.wtpl +5 -0
  26. data/layouts/static/public/templates/.wawaccess +9 -0
  27. data/layouts/static/public/templates/layout.wtpl +17 -0
  28. data/layouts/static/test/wspec/static_pages_are_served.wspec +21 -0
  29. data/layouts/static/waw.routing +8 -0
  30. data/lib/waw.rb +99 -0
  31. data/lib/waw/commands/command.rb +115 -0
  32. data/lib/waw/commands/profile_command.rb +66 -0
  33. data/lib/waw/commands/start_command.rb +59 -0
  34. data/lib/waw/config.rb +110 -0
  35. data/lib/waw/controller.rb +25 -0
  36. data/lib/waw/controllers/action/action.rb +91 -0
  37. data/lib/waw/controllers/action/action_utils.rb +30 -0
  38. data/lib/waw/controllers/action/js_generation.rb +116 -0
  39. data/lib/waw/controllers/action_controller.rb +133 -0
  40. data/lib/waw/controllers/error/backtrace.rb +54 -0
  41. data/lib/waw/controllers/error_handler.rb +62 -0
  42. data/lib/waw/controllers/json_controller.rb +31 -0
  43. data/lib/waw/controllers/no_cache.rb +22 -0
  44. data/lib/waw/controllers/static/match.rb +80 -0
  45. data/lib/waw/controllers/static/waw_access.rb +235 -0
  46. data/lib/waw/controllers/static/waw_access_dsl.rb +48 -0
  47. data/lib/waw/controllers/static_controller.rb +37 -0
  48. data/lib/waw/default_config.cfg +14 -0
  49. data/lib/waw/environment_utils.rb +57 -0
  50. data/lib/waw/errors.rb +4 -0
  51. data/lib/waw/ext.rb +3 -0
  52. data/lib/waw/ext/core.rb +4 -0
  53. data/lib/waw/ext/core/hash.rb +47 -0
  54. data/lib/waw/ext/core/logger.rb +10 -0
  55. data/lib/waw/ext/core/module.rb +20 -0
  56. data/lib/waw/ext/core/object.rb +29 -0
  57. data/lib/waw/ext/rack.rb +19 -0
  58. data/lib/waw/ext/rack/builder.rb +43 -0
  59. data/lib/waw/ext/rack/delegator.rb +51 -0
  60. data/lib/waw/ext/rack/urlmap.rb +55 -0
  61. data/lib/waw/ext/wlang.rb +1 -0
  62. data/lib/waw/ext/wlang/hosted_language.rb +21 -0
  63. data/lib/waw/fullstate.rb +8 -0
  64. data/lib/waw/fullstate/on_class.rb +37 -0
  65. data/lib/waw/fullstate/on_instance.rb +27 -0
  66. data/lib/waw/fullstate/variable.rb +36 -0
  67. data/lib/waw/kern.rb +6 -0
  68. data/lib/waw/kern/app.rb +48 -0
  69. data/lib/waw/kern/empty/waw.deploy +0 -0
  70. data/lib/waw/kern/empty/waw.routing +1 -0
  71. data/lib/waw/kern/freezed_state.rb +32 -0
  72. data/lib/waw/kern/hooks.rb +53 -0
  73. data/lib/waw/kern/lifecycle.rb +248 -0
  74. data/lib/waw/kern/living_state.rb +87 -0
  75. data/lib/waw/kern/utils.rb +27 -0
  76. data/lib/waw/resource_collection.rb +100 -0
  77. data/lib/waw/restart.rb +32 -0
  78. data/lib/waw/routing.rb +43 -0
  79. data/lib/waw/routing/action_routing.rb +78 -0
  80. data/lib/waw/routing/dsl.rb +45 -0
  81. data/lib/waw/routing/feedback.rb +23 -0
  82. data/lib/waw/routing/form_validation_feedback.rb +36 -0
  83. data/lib/waw/routing/javascript.rb +17 -0
  84. data/lib/waw/routing/redirect.rb +26 -0
  85. data/lib/waw/routing/refresh.rb +17 -0
  86. data/lib/waw/routing/routing_rule.rb +16 -0
  87. data/lib/waw/scope_utils.rb +69 -0
  88. data/lib/waw/session.rb +51 -0
  89. data/lib/waw/testing.rb +1 -0
  90. data/lib/waw/tools/mail.rb +4 -0
  91. data/lib/waw/tools/mail/mail.rb +119 -0
  92. data/lib/waw/tools/mail/mail_agent.rb +123 -0
  93. data/lib/waw/tools/mail/mailbox.rb +62 -0
  94. data/lib/waw/tools/mail/template.rb +38 -0
  95. data/lib/waw/utils/dsl_helper.rb +116 -0
  96. data/lib/waw/validation.rb +175 -0
  97. data/lib/waw/validation/and_validator.rb +27 -0
  98. data/lib/waw/validation/array_validations.rb +38 -0
  99. data/lib/waw/validation/boolean_validator.rb +32 -0
  100. data/lib/waw/validation/comparison_validations.rb +45 -0
  101. data/lib/waw/validation/date_validator.rb +31 -0
  102. data/lib/waw/validation/default_validator.rb +30 -0
  103. data/lib/waw/validation/dsl_ruby_extensions.rb +11 -0
  104. data/lib/waw/validation/errors.rb +17 -0
  105. data/lib/waw/validation/ext.rb +3 -0
  106. data/lib/waw/validation/file_validator.rb +30 -0
  107. data/lib/waw/validation/float_validator.rb +19 -0
  108. data/lib/waw/validation/helpers.rb +67 -0
  109. data/lib/waw/validation/integer_validator.rb +16 -0
  110. data/lib/waw/validation/isin_validator.rb +24 -0
  111. data/lib/waw/validation/mandatory_validator.rb +17 -0
  112. data/lib/waw/validation/missing_validator.rb +17 -0
  113. data/lib/waw/validation/not_validator.rb +20 -0
  114. data/lib/waw/validation/or_validator.rb +34 -0
  115. data/lib/waw/validation/regexp_validator.rb +29 -0
  116. data/lib/waw/validation/same_validator.rb +16 -0
  117. data/lib/waw/validation/signature.rb +157 -0
  118. data/lib/waw/validation/size_validations.rb +44 -0
  119. data/lib/waw/validation/string_validator.rb +15 -0
  120. data/lib/waw/validation/validator.rb +48 -0
  121. data/lib/waw/wawgen.rb +2 -0
  122. data/lib/waw/wawgen/create.rb +166 -0
  123. data/lib/waw/wawgen/project.rb +25 -0
  124. data/lib/waw/wspec.rb +5 -0
  125. data/lib/waw/wspec/browser.rb +240 -0
  126. data/lib/waw/wspec/dsl.rb +201 -0
  127. data/lib/waw/wspec/html_analysis.rb +136 -0
  128. data/lib/waw/wspec/html_analysis/tag.rb +56 -0
  129. data/lib/waw/wspec/runner.rb +70 -0
  130. data/lib/waw/wspec/scenario.rb +35 -0
  131. data/lib/waw/wspec/suite.rb +54 -0
  132. data/test/bricks/error_handler/config/test.cfg +2 -0
  133. data/test/bricks/error_handler/logs/webapp.log +1411 -0
  134. data/test/bricks/error_handler/test/error_handler.wspec +16 -0
  135. data/test/bricks/error_handler/waw.deploy +1 -0
  136. data/test/bricks/error_handler/waw.routing +27 -0
  137. data/test/integration/waw_create_integration_test.rb +24 -0
  138. data/test/spec/assumptions_spec.rb +30 -0
  139. data/test/spec/controllers/action_controller_spec.rb +14 -0
  140. data/test/spec/controllers/static/waw_access_spec.rb +112 -0
  141. data/test/spec/environment_utils_spec.rb +15 -0
  142. data/test/spec/ext/core/hash_spec.rb +58 -0
  143. data/test/spec/fixtures.rb +41 -0
  144. data/test/spec/fixtures/action/config/default.cfg +2 -0
  145. data/test/spec/fixtures/action/lib/action_controller_test.rb +12 -0
  146. data/test/spec/fixtures/action/waw.deploy +1 -0
  147. data/test/spec/fixtures/action/waw.routing +6 -0
  148. data/test/spec/fixtures/empty/waw.deploy +0 -0
  149. data/test/spec/fixtures/empty/waw.routing +0 -0
  150. data/test/spec/fullstate/on_class_spec.rb +59 -0
  151. data/test/spec/fullstate/on_instance_spec.rb +59 -0
  152. data/test/spec/fullstate/session_spec.rb +43 -0
  153. data/test/spec/fullstate/variable_spec.rb +55 -0
  154. data/test/spec/resource_collection_spec.rb +50 -0
  155. data/test/spec/test_all.rb +9 -0
  156. data/test/spec/tools/mail/mail_agent_spec.rb +116 -0
  157. data/test/spec/tools/mail/mail_spec.rb +56 -0
  158. data/test/spec/tools/mail/mailbox_spec.rb +57 -0
  159. data/test/spec/tools/mail/template_spec.rb +47 -0
  160. data/test/spec/validation/array_validation_spec.rb +63 -0
  161. data/test/spec/validation/array_validator_spec.rb +17 -0
  162. data/test/spec/validation/date_validation_spec.rb +35 -0
  163. data/test/spec/validation/default_validation_spec.rb +37 -0
  164. data/test/spec/validation/disjuctive_validation_spec.rb +33 -0
  165. data/test/spec/validation/errors_spec.rb +37 -0
  166. data/test/spec/validation/file_validator_spec.rb +34 -0
  167. data/test/spec/validation/mail_validation_spec.rb +51 -0
  168. data/test/spec/validation/missing_validation_spec.rb +43 -0
  169. data/test/spec/validation/same_validation_spec.rb +24 -0
  170. data/test/spec/validation/signature_intuition_spec.rb +37 -0
  171. data/test/spec/validation/signature_spec.rb +164 -0
  172. data/test/spec/validation/validation_spec.rb +28 -0
  173. data/test/spec/wspec/html_analysis/tag_spec.rb +38 -0
  174. data/test/spec/wspec/html_analysis_spec.rb +170 -0
  175. data/test/unit/test_all.rb +8 -0
  176. data/test/unit/waw/app_test.rb +126 -0
  177. data/test/unit/waw/app_test/config/commons.cfg +2 -0
  178. data/test/unit/waw/app_test/config/devel.cfg +1 -0
  179. data/test/unit/waw/config_test.rb +54 -0
  180. data/test/unit/waw/controllers/action_controller_test.rb +76 -0
  181. data/test/unit/waw/controllers/action_test.rb +35 -0
  182. data/test/unit/waw/controllers/example_action_controller_test.rb +24 -0
  183. data/test/unit/waw/controllers/multiple_action_controller_test.rb +78 -0
  184. data/test/unit/waw/controllers/static/example/css/example.css +1 -0
  185. data/test/unit/waw/controllers/static/example/index.html +1 -0
  186. data/test/unit/waw/controllers/static/example/js/example.js +1 -0
  187. data/test/unit/waw/controllers/static/example/pages/hello.wtpl +1 -0
  188. data/test/unit/waw/controllers/static/waw_access_test.rb +76 -0
  189. data/test/unit/waw/ext/rack_test.rb +74 -0
  190. data/test/unit/waw/resource_collection_test.rb +49 -0
  191. data/test/unit/waw/resources.txt +4 -0
  192. data/test/unit/waw/routing/routing_test.rb +26 -0
  193. data/test/unit/waw/utils/dsl_helper_test.rb +79 -0
  194. data/test/unit/waw/utils/dsl_helper_test_extensions1.rb +4 -0
  195. data/test/unit/waw/validation/signature_test.rb +193 -0
  196. data/test/unit/waw/validation_test.rb +319 -0
  197. data/test/unit/waw/wspec/html_analysis_test.html +81 -0
  198. data/test/unit/waw/wspec/html_analysis_test.rb +26 -0
  199. metadata +272 -0
@@ -0,0 +1,201 @@
1
+ require 'test/unit/assertions'
2
+ module Waw
3
+ module WSpec
4
+ #
5
+ # Provides the DSL of the .wspec scenario language.
6
+ #
7
+ class DSL
8
+ include ::Waw::ScopeUtils
9
+ include ::Test::Unit::Assertions
10
+ include HTMLAnalysis
11
+
12
+ # Creates a DSL instance for a given scenario
13
+ def initialize(waw_kernel, scenario)
14
+ @waw_kernel = waw_kernel
15
+ @scenario = scenario
16
+ @browser = Browser.new
17
+ end
18
+
19
+ # Returns waw kernel
20
+ def waw_kernel
21
+ @waw_kernel
22
+ end
23
+
24
+ #################################################################### Semi-private utilities
25
+
26
+ # Executes some code
27
+ def __execute(&block)
28
+ self.instance_eval(&block)
29
+ end
30
+ alias :by_the_way :__execute
31
+
32
+ # A stack of execution context
33
+ def __stack
34
+ @stack ||= []
35
+ end
36
+
37
+ # Returns the last because clause
38
+ def __last_because
39
+ __stack.last || @scenario.name
40
+ end
41
+
42
+ # Adds an assertion
43
+ def add_assertion
44
+ @scenario.add_assertion
45
+ end
46
+
47
+ #################################################################### About scoping
48
+
49
+ # Delegates to waw ressources
50
+ def method_missing(name, *args, &block)
51
+ if args.empty? and resources and resources.has_resource?(name)
52
+ resources[name]
53
+ else
54
+ super(name, *args, &block)
55
+ end
56
+ end
57
+
58
+ #################################################################### About browser
59
+
60
+ # Returns the current browser instance
61
+ def browser
62
+ @browser
63
+ end
64
+
65
+ # Returns current browser contents (used by HTMLAnalysis)
66
+ def browser_contents
67
+ browser.contents
68
+ end
69
+ alias :contents :browser_contents
70
+
71
+ # Returns the URL of the index page (the web_base actually)
72
+ # This method returns nil unless the Waw application has been loaded
73
+ def index_page
74
+ config && config.web_base
75
+ end
76
+
77
+ # Goes to a given location and returns the HTTPResponse object
78
+ def go(location)
79
+ browser.location = location
80
+ browser.response
81
+ end
82
+
83
+ # Simply returns args
84
+ def with(args = {})
85
+ args
86
+ end
87
+
88
+ #################################################################### About scenario execution
89
+
90
+ # Because some condition holds...
91
+ def because(msg="Unknown cause", &block)
92
+ raise ArgumentError, "WSpec because/therefore expects a block" unless block
93
+ __stack.push(msg)
94
+ yield(browser)
95
+ __stack.pop
96
+ end
97
+ alias :therefore :because
98
+
99
+ #################################################################### About reaching pages
100
+
101
+ # Asserts that a page can be reached, leading to a Net::HTTPSuccess result
102
+ def i_reach(which_page)
103
+ result = go(which_page)
104
+ assert Net::HTTPSuccess===result, __last_because + " (cannot actually reach #{which_page}: #{result})"
105
+ end
106
+
107
+ # Asserts that a page could be reached (requesting headers leads to a Net::HTTPSucess result)
108
+ def i_could_reach(which_page)
109
+ return if which_page.nil? or '#'==which_page
110
+ case which_page
111
+ when Tag
112
+ i_could_reach(which_page[:href])
113
+ when Array
114
+ which_page.each{|link| i_could_reach(link)}
115
+ when String
116
+ result = browser.headers_fetch(which_page)
117
+ assert Net::HTTPSuccess===result, __last_because + " (could not reach #{which_page}: #{result})"
118
+ else
119
+ raise ArgumentError, "Unable to use #{which_page} for i_could_reach"
120
+ end
121
+ end
122
+
123
+ # Asserts that a page cannot be reached, leading to a Net::HTTPNotFound or a Net::HTTPForbidden (403)
124
+ # result
125
+ def i_dont_reach(which_page)
126
+ result = go(which_page)
127
+ assert (Net::HTTPNotFound===result or Net::HTTPForbidden===result), __last_because + " (can reach #{which_page}: #{result})"
128
+ end
129
+
130
+ # Asserts that a page may not be reached, leading to a Net::HTTPForbidden (403) result.
131
+ def i_may_not_reach(which_page)
132
+ result = go(which_page)
133
+ assert (Net::HTTPForbidden===result or Net::HTTPBadRequest===result), __last_because + " (may actually reach #{which_page}: #{result})"
134
+ end
135
+
136
+ #################################################################### About seeing something on the page
137
+
138
+ # Asserts that something can be seen on the current page
139
+ def i_see(what)
140
+ assert i_see?(what), __last_because + " (don't see #{what})"
141
+ end
142
+
143
+ # Asserts that something is not present on the current page
144
+ def i_dont_see(what)
145
+ assert !i_see?(what), __last_because + " (actually see #{what})"
146
+ end
147
+
148
+ # Asserts that I see a particular tag (see HTMLAnalysis.tag)
149
+ def i_see_tag(name, opts = nil)
150
+ assert has_tag?(name, opts), __last_because + " (don't see tag <#{name} #{opts.inspect})"
151
+ end
152
+
153
+ # Asserts that I see a particular link (see HTMLAnalysis.link)
154
+ def i_see_link(opts = nil)
155
+ assert has_link?(opts), __last_because + " (dont see link <a #{opts.inspect})"
156
+ end
157
+
158
+ #################################################################### About link-based navigation
159
+
160
+ # Following a link
161
+ def i_follow(link)
162
+ link = case link
163
+ when String
164
+ link
165
+ when Tag
166
+ link[:href]
167
+ when ::Waw::ActionController::Action
168
+ link.href
169
+ else
170
+ raise ArgumentError, "Unable to apply i_follow to #{link.inspect}"
171
+ end
172
+ i_reach(link)
173
+ end
174
+
175
+ #################################################################### About forms and action
176
+
177
+ # Submits some form with optional arguments
178
+ def i_submit(form, args = {})
179
+ assert_not_nil form, __last_because + "(form has not been found)"
180
+ raise ArgumentError, "i_submit requires a Tag instance, #{form.inspect} received" unless Tag===form
181
+ i_invoke(form[:action], args)
182
+ end
183
+
184
+ # Directly invoke an action or service server side, bypassing
185
+ # form lookup and so on.
186
+ def i_invoke(action, args = {})
187
+ result = case action
188
+ when String
189
+ browser.invoke_service(action, args)
190
+ when ::Waw::ActionController::Action
191
+ browser.invoke_action(action, args)
192
+ else
193
+ raise ArgumentError, "Unable to apply i_invoke on #{action.inspect}, unable to catch the associated action"
194
+ end
195
+ assert Net::HTTPSuccess===result, __last_because + " (invoking #{action.inspect} led to: #{result})"
196
+ result
197
+ end
198
+
199
+ end # class DSL
200
+ end # module WSpec
201
+ end # module Waw
@@ -0,0 +1,136 @@
1
+ require 'waw/wspec/html_analysis/tag'
2
+ module Waw
3
+ module WSpec
4
+ #
5
+ # Provides utility methods for analysis of XML/HTML contents.
6
+ #
7
+ # This module expects an accessor to a browser instance. Otherwise,
8
+ # the browser_contents method may be overrided.
9
+ #
10
+ module HTMLAnalysis
11
+
12
+ # Yields the block passing browser contents as first argument
13
+ def browser_contents
14
+ browser.contents
15
+ end
16
+
17
+ # Decodes a string of HTML attributes as a hash with symbols as keys
18
+ def decode_attributes_string(str)
19
+ attrs = {}
20
+ str.scan(/([a-z]+)=["'](.*?)["']/) do |match|
21
+ attrs[match[0].to_sym] = match[1]
22
+ end
23
+ attrs
24
+ end
25
+
26
+ #################################################################### Tag helpers
27
+
28
+ # Find tags inside the browser contents. If a block is given, yield it with
29
+ # each tag information. Otherwise, returns an array of found tags, that can be
30
+ # empty.
31
+ def all_tags(name, opts = nil, contents = browser_contents)
32
+ found = [] unless block_given?
33
+ contents.scan(/(<\s*#{name}\s*(.*?)\/?>)/) do |match|
34
+ tag = Tag.new(match[0], name, decode_attributes_string(match[1]))
35
+ next unless tag.matches?(opts)
36
+ block_given? ? yield(tag) : (found << tag)
37
+ end
38
+ found
39
+ end
40
+ alias :tags :all_tags
41
+
42
+ # Iterates over a tag specification
43
+ def each_tag(name, opts = nil, contents = browser_contents, &block)
44
+ tags(name, opts, contents, &block)
45
+ end
46
+
47
+ # Shortcut for <code>tags(name, opts, contents)[0]</code>. Returns nil if no such
48
+ # tag can be found
49
+ def first_tag(name, opts = nil, contents = browser_contents)
50
+ tags(name, opts, contents)[0]
51
+ end
52
+ alias :tag :first_tag
53
+
54
+ # Look for some html tag
55
+ def has_tag?(name, opts = nil, contents = browser_contents)
56
+ return tags(name, opts, contents).size != 0
57
+ end
58
+
59
+ #################################################################### Links helpers
60
+
61
+ # Shortcut for <code>tags('a', {:href => /^(.*?)$/}.merge(opts), contents, &block)</code>
62
+ def all_links(opts = nil, contents = browser_contents, &block)
63
+ tags('a', {:href => /^(.*?)$/}.merge(opts || {}), contents, &block)
64
+ end
65
+ alias :links :all_links
66
+
67
+ # Same as all_links, but retains internal links only (i.e. <code>not(URI::Generic.absolute?)</code>)
68
+ def all_internal_links(opts = nil, contents = browser_contents, &block)
69
+ if block
70
+ all_links(opts, contents).each do |link|
71
+ yield(link) unless URI.parse(link[:href]).absolute?
72
+ end
73
+ else
74
+ all_links(opts, contents).reject{|link| URI.parse(link[:href]).absolute?}
75
+ end
76
+ end
77
+ alias :internal_links :all_internal_links
78
+
79
+ # Same as all_links, but retains external links only (i.e. <code>URI::Generic.absolute?</code>)
80
+ def all_external_links(opts = nil, contents = browser_contents, &block)
81
+ if block
82
+ all_links(opts, contents).each do |link|
83
+ yield(link) if URI.parse(link[:href]).absolute?
84
+ end
85
+ else
86
+ all_links(opts, contents).select{|link| URI.parse(link[:href]).absolute?}
87
+ end
88
+ end
89
+ alias :external_links :all_external_links
90
+
91
+ # Shortcut for <code>links(name, opts, contents)[0]</code>. Returns nil if no such
92
+ # link can be found
93
+ def first_link(opts = nil, contents = browser_contents)
94
+ links(opts, contents)[0]
95
+ end
96
+ alias :link :first_link
97
+
98
+ # Checks if some link can be found
99
+ def has_link?(opts = nil, contents = browser_contents)
100
+ return links(opts, contents).size != 0
101
+ end
102
+
103
+ #################################################################### Form helpers
104
+
105
+ # Shortcut for <code>tag('form', opts, contents)</code>
106
+ def form(opts = nil, contents = browser_contents)
107
+ if opts[:action] and ::Waw::ActionController::Action===opts[:action]
108
+ action = opts[:action]
109
+ opts = {:id => action.id}.merge(opts || {}).forget(:action)
110
+ form = tag('form', opts, contents)
111
+ form[:action] = action if form
112
+ form
113
+ else
114
+ tag('form', opts, contents)
115
+ end
116
+ end
117
+
118
+ #################################################################### Text helpers
119
+
120
+ # Assert that the user sees something in the browser contents
121
+ def i_see?(what, contents = browser_contents)
122
+ case what
123
+ when NilClass
124
+ false
125
+ when String, Regexp
126
+ not(contents.index(what).nil?)
127
+ when Tag
128
+ true
129
+ else
130
+ raise ArgumentError, "Unable to see #{what}, not understood"
131
+ end
132
+ end
133
+
134
+ end # module HTMLAnalysis
135
+ end # module WSpec
136
+ end # module Waw
@@ -0,0 +1,56 @@
1
+ module Waw
2
+ module WSpec
3
+ module HTMLAnalysis
4
+
5
+ # A tag helper class
6
+ class Tag
7
+
8
+ # Result of the regexp matching applied to get this tag
9
+ attr_reader :match
10
+
11
+ # Name of the tag
12
+ attr_reader :name
13
+
14
+ # Tag attributes
15
+ attr_reader :attributes
16
+
17
+ # Creates a Tag instance
18
+ def initialize(match, name, attributes)
19
+ @match, @name, @attributes = match, name, attributes
20
+ end
21
+
22
+ # Returns the value of an attribute
23
+ def [](key)
24
+ attributes[key]
25
+ end
26
+
27
+ # Forces the value of an attribute
28
+ def []=(key, value)
29
+ attributes[key] = value
30
+ end
31
+
32
+ # Checks if this tags has a given attribute
33
+ def has_attribute?(name)
34
+ attributes.has_key?(name)
35
+ end
36
+
37
+ # Checks if this tag matches a given attributes specification
38
+ def matches?(opts = {})
39
+ return true if (opts.nil? or opts.empty?)
40
+ opts.each_pair do |name, value|
41
+ return false unless self.has_attribute?(name)
42
+ case value
43
+ when Regexp
44
+ return false unless value =~ self[name]
45
+ else
46
+ return false unless value.to_s == self[name]
47
+ end
48
+ end
49
+ true
50
+ end
51
+
52
+ end # class Tag
53
+
54
+ end # module HTMLAnalysis
55
+ end # module WSpec
56
+ end # module Waw
@@ -0,0 +1,70 @@
1
+ require 'waw'
2
+ require 'waw/wspec'
3
+
4
+ if RUBY_VERSION >= "1.9"
5
+ # These classes don't seem to exist in some Ruby 1.9 installations
6
+ module Test
7
+ module Unit
8
+ class AssertionFailedError < StandardError
9
+ end
10
+ end
11
+ end
12
+ else
13
+ # These classes don't seem to exist in some Ruby 1.8 installations
14
+ module MiniTest
15
+ class Assertion < StandardError
16
+ end
17
+ end
18
+ end
19
+
20
+ # The autoloaded scenarios
21
+ $scenarios = []
22
+ def scenario(name, &block)
23
+ $scenarios << Waw::WSpec::Scenario.new(name, &block)
24
+ end
25
+ alias :requirement :scenario
26
+
27
+ # We run the whole suite at end
28
+ at_exit {
29
+ begin
30
+ puts "Running wspec test suite now"
31
+
32
+ # Load waw through rack in a different thread
33
+ puts "Loading waw application and web server"
34
+ t = Thread.new(Waw.kernel) do |app|
35
+ begin
36
+ server = Rack::Handler::Mongrel
37
+ rescue LoadError => e
38
+ server = Rack::Handler::WEBrick
39
+ end
40
+ options = {:Port => Waw.config.web_port, :Host => "0.0.0.0", :AccessLog => []}
41
+ server.run app, options
42
+ end
43
+
44
+ # Wait until the server is loaded
45
+ try, ok = 0, false
46
+ begin
47
+ puts "Attempting to reach the web server..."
48
+ Net::HTTP.get(URI.parse(Waw.config.web_base))
49
+ ok = true
50
+ rescue Errno::ECONNREFUSED => ex
51
+ sleep 0.1
52
+ end until (ok or (try += 1)>10)
53
+
54
+ # Create the suite and run it
55
+ if ok
56
+ s = ::Waw::WSpec::Suite.new($scenarios)
57
+ t1 = Time.now
58
+ s.run(Waw.kernel)
59
+ t2 = Time.now
60
+ puts "\nFinished in #{Time.now - t1} seconds.\n"
61
+ puts "#{s.scenario_count} high-level requirements, #{s.assertion_count} assertions, #{s.failure_count} failures, #{s.error_count} errors"
62
+ else
63
+ raise WawError, "Unable to reach the local web server... sorry!"
64
+ end
65
+
66
+ ensure
67
+ # Kill the web server thread
68
+ t.kill if t
69
+ end
70
+ }