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.
- data/LICENCE.rdoc +25 -0
- data/README.rdoc +32 -0
- data/bin/waw +32 -0
- data/bin/waw-profile +26 -0
- data/bin/waw-start +26 -0
- data/bin/wspec +33 -0
- data/layouts/empty/Rakefile +14 -0
- data/layouts/empty/config.ru +5 -0
- data/layouts/empty/config/commons.cfg +31 -0
- data/layouts/empty/config/devel.cfg +21 -0
- data/layouts/empty/ignore +7 -0
- data/layouts/empty/logs/dontforgetme +0 -0
- data/layouts/empty/resources/messages.rs +1 -0
- data/layouts/empty/test/wspec/site_respond.wspec +3 -0
- data/layouts/empty/test/wspec/test_all.rb +13 -0
- data/layouts/empty/waw.deploy +1 -0
- data/layouts/empty/waw.routing +6 -0
- data/layouts/static/dependencies +1 -0
- data/layouts/static/public/.wawaccess +18 -0
- data/layouts/static/public/css/style.css +0 -0
- data/layouts/static/public/images/dontforgetme +0 -0
- data/layouts/static/public/js/project.js +0 -0
- data/layouts/static/public/pages/.wawaccess +30 -0
- data/layouts/static/public/pages/404.wtpl +1 -0
- data/layouts/static/public/pages/index.wtpl +5 -0
- data/layouts/static/public/templates/.wawaccess +9 -0
- data/layouts/static/public/templates/layout.wtpl +17 -0
- data/layouts/static/test/wspec/static_pages_are_served.wspec +21 -0
- data/layouts/static/waw.routing +8 -0
- data/lib/waw.rb +99 -0
- data/lib/waw/commands/command.rb +115 -0
- data/lib/waw/commands/profile_command.rb +66 -0
- data/lib/waw/commands/start_command.rb +59 -0
- data/lib/waw/config.rb +110 -0
- data/lib/waw/controller.rb +25 -0
- data/lib/waw/controllers/action/action.rb +91 -0
- data/lib/waw/controllers/action/action_utils.rb +30 -0
- data/lib/waw/controllers/action/js_generation.rb +116 -0
- data/lib/waw/controllers/action_controller.rb +133 -0
- data/lib/waw/controllers/error/backtrace.rb +54 -0
- data/lib/waw/controllers/error_handler.rb +62 -0
- data/lib/waw/controllers/json_controller.rb +31 -0
- data/lib/waw/controllers/no_cache.rb +22 -0
- data/lib/waw/controllers/static/match.rb +80 -0
- data/lib/waw/controllers/static/waw_access.rb +235 -0
- data/lib/waw/controllers/static/waw_access_dsl.rb +48 -0
- data/lib/waw/controllers/static_controller.rb +37 -0
- data/lib/waw/default_config.cfg +14 -0
- data/lib/waw/environment_utils.rb +57 -0
- data/lib/waw/errors.rb +4 -0
- data/lib/waw/ext.rb +3 -0
- data/lib/waw/ext/core.rb +4 -0
- data/lib/waw/ext/core/hash.rb +47 -0
- data/lib/waw/ext/core/logger.rb +10 -0
- data/lib/waw/ext/core/module.rb +20 -0
- data/lib/waw/ext/core/object.rb +29 -0
- data/lib/waw/ext/rack.rb +19 -0
- data/lib/waw/ext/rack/builder.rb +43 -0
- data/lib/waw/ext/rack/delegator.rb +51 -0
- data/lib/waw/ext/rack/urlmap.rb +55 -0
- data/lib/waw/ext/wlang.rb +1 -0
- data/lib/waw/ext/wlang/hosted_language.rb +21 -0
- data/lib/waw/fullstate.rb +8 -0
- data/lib/waw/fullstate/on_class.rb +37 -0
- data/lib/waw/fullstate/on_instance.rb +27 -0
- data/lib/waw/fullstate/variable.rb +36 -0
- data/lib/waw/kern.rb +6 -0
- data/lib/waw/kern/app.rb +48 -0
- data/lib/waw/kern/empty/waw.deploy +0 -0
- data/lib/waw/kern/empty/waw.routing +1 -0
- data/lib/waw/kern/freezed_state.rb +32 -0
- data/lib/waw/kern/hooks.rb +53 -0
- data/lib/waw/kern/lifecycle.rb +248 -0
- data/lib/waw/kern/living_state.rb +87 -0
- data/lib/waw/kern/utils.rb +27 -0
- data/lib/waw/resource_collection.rb +100 -0
- data/lib/waw/restart.rb +32 -0
- data/lib/waw/routing.rb +43 -0
- data/lib/waw/routing/action_routing.rb +78 -0
- data/lib/waw/routing/dsl.rb +45 -0
- data/lib/waw/routing/feedback.rb +23 -0
- data/lib/waw/routing/form_validation_feedback.rb +36 -0
- data/lib/waw/routing/javascript.rb +17 -0
- data/lib/waw/routing/redirect.rb +26 -0
- data/lib/waw/routing/refresh.rb +17 -0
- data/lib/waw/routing/routing_rule.rb +16 -0
- data/lib/waw/scope_utils.rb +69 -0
- data/lib/waw/session.rb +51 -0
- data/lib/waw/testing.rb +1 -0
- data/lib/waw/tools/mail.rb +4 -0
- data/lib/waw/tools/mail/mail.rb +119 -0
- data/lib/waw/tools/mail/mail_agent.rb +123 -0
- data/lib/waw/tools/mail/mailbox.rb +62 -0
- data/lib/waw/tools/mail/template.rb +38 -0
- data/lib/waw/utils/dsl_helper.rb +116 -0
- data/lib/waw/validation.rb +175 -0
- data/lib/waw/validation/and_validator.rb +27 -0
- data/lib/waw/validation/array_validations.rb +38 -0
- data/lib/waw/validation/boolean_validator.rb +32 -0
- data/lib/waw/validation/comparison_validations.rb +45 -0
- data/lib/waw/validation/date_validator.rb +31 -0
- data/lib/waw/validation/default_validator.rb +30 -0
- data/lib/waw/validation/dsl_ruby_extensions.rb +11 -0
- data/lib/waw/validation/errors.rb +17 -0
- data/lib/waw/validation/ext.rb +3 -0
- data/lib/waw/validation/file_validator.rb +30 -0
- data/lib/waw/validation/float_validator.rb +19 -0
- data/lib/waw/validation/helpers.rb +67 -0
- data/lib/waw/validation/integer_validator.rb +16 -0
- data/lib/waw/validation/isin_validator.rb +24 -0
- data/lib/waw/validation/mandatory_validator.rb +17 -0
- data/lib/waw/validation/missing_validator.rb +17 -0
- data/lib/waw/validation/not_validator.rb +20 -0
- data/lib/waw/validation/or_validator.rb +34 -0
- data/lib/waw/validation/regexp_validator.rb +29 -0
- data/lib/waw/validation/same_validator.rb +16 -0
- data/lib/waw/validation/signature.rb +157 -0
- data/lib/waw/validation/size_validations.rb +44 -0
- data/lib/waw/validation/string_validator.rb +15 -0
- data/lib/waw/validation/validator.rb +48 -0
- data/lib/waw/wawgen.rb +2 -0
- data/lib/waw/wawgen/create.rb +166 -0
- data/lib/waw/wawgen/project.rb +25 -0
- data/lib/waw/wspec.rb +5 -0
- data/lib/waw/wspec/browser.rb +240 -0
- data/lib/waw/wspec/dsl.rb +201 -0
- data/lib/waw/wspec/html_analysis.rb +136 -0
- data/lib/waw/wspec/html_analysis/tag.rb +56 -0
- data/lib/waw/wspec/runner.rb +70 -0
- data/lib/waw/wspec/scenario.rb +35 -0
- data/lib/waw/wspec/suite.rb +54 -0
- data/test/bricks/error_handler/config/test.cfg +2 -0
- data/test/bricks/error_handler/logs/webapp.log +1411 -0
- data/test/bricks/error_handler/test/error_handler.wspec +16 -0
- data/test/bricks/error_handler/waw.deploy +1 -0
- data/test/bricks/error_handler/waw.routing +27 -0
- data/test/integration/waw_create_integration_test.rb +24 -0
- data/test/spec/assumptions_spec.rb +30 -0
- data/test/spec/controllers/action_controller_spec.rb +14 -0
- data/test/spec/controllers/static/waw_access_spec.rb +112 -0
- data/test/spec/environment_utils_spec.rb +15 -0
- data/test/spec/ext/core/hash_spec.rb +58 -0
- data/test/spec/fixtures.rb +41 -0
- data/test/spec/fixtures/action/config/default.cfg +2 -0
- data/test/spec/fixtures/action/lib/action_controller_test.rb +12 -0
- data/test/spec/fixtures/action/waw.deploy +1 -0
- data/test/spec/fixtures/action/waw.routing +6 -0
- data/test/spec/fixtures/empty/waw.deploy +0 -0
- data/test/spec/fixtures/empty/waw.routing +0 -0
- data/test/spec/fullstate/on_class_spec.rb +59 -0
- data/test/spec/fullstate/on_instance_spec.rb +59 -0
- data/test/spec/fullstate/session_spec.rb +43 -0
- data/test/spec/fullstate/variable_spec.rb +55 -0
- data/test/spec/resource_collection_spec.rb +50 -0
- data/test/spec/test_all.rb +9 -0
- data/test/spec/tools/mail/mail_agent_spec.rb +116 -0
- data/test/spec/tools/mail/mail_spec.rb +56 -0
- data/test/spec/tools/mail/mailbox_spec.rb +57 -0
- data/test/spec/tools/mail/template_spec.rb +47 -0
- data/test/spec/validation/array_validation_spec.rb +63 -0
- data/test/spec/validation/array_validator_spec.rb +17 -0
- data/test/spec/validation/date_validation_spec.rb +35 -0
- data/test/spec/validation/default_validation_spec.rb +37 -0
- data/test/spec/validation/disjuctive_validation_spec.rb +33 -0
- data/test/spec/validation/errors_spec.rb +37 -0
- data/test/spec/validation/file_validator_spec.rb +34 -0
- data/test/spec/validation/mail_validation_spec.rb +51 -0
- data/test/spec/validation/missing_validation_spec.rb +43 -0
- data/test/spec/validation/same_validation_spec.rb +24 -0
- data/test/spec/validation/signature_intuition_spec.rb +37 -0
- data/test/spec/validation/signature_spec.rb +164 -0
- data/test/spec/validation/validation_spec.rb +28 -0
- data/test/spec/wspec/html_analysis/tag_spec.rb +38 -0
- data/test/spec/wspec/html_analysis_spec.rb +170 -0
- data/test/unit/test_all.rb +8 -0
- data/test/unit/waw/app_test.rb +126 -0
- data/test/unit/waw/app_test/config/commons.cfg +2 -0
- data/test/unit/waw/app_test/config/devel.cfg +1 -0
- data/test/unit/waw/config_test.rb +54 -0
- data/test/unit/waw/controllers/action_controller_test.rb +76 -0
- data/test/unit/waw/controllers/action_test.rb +35 -0
- data/test/unit/waw/controllers/example_action_controller_test.rb +24 -0
- data/test/unit/waw/controllers/multiple_action_controller_test.rb +78 -0
- data/test/unit/waw/controllers/static/example/css/example.css +1 -0
- data/test/unit/waw/controllers/static/example/index.html +1 -0
- data/test/unit/waw/controllers/static/example/js/example.js +1 -0
- data/test/unit/waw/controllers/static/example/pages/hello.wtpl +1 -0
- data/test/unit/waw/controllers/static/waw_access_test.rb +76 -0
- data/test/unit/waw/ext/rack_test.rb +74 -0
- data/test/unit/waw/resource_collection_test.rb +49 -0
- data/test/unit/waw/resources.txt +4 -0
- data/test/unit/waw/routing/routing_test.rb +26 -0
- data/test/unit/waw/utils/dsl_helper_test.rb +79 -0
- data/test/unit/waw/utils/dsl_helper_test_extensions1.rb +4 -0
- data/test/unit/waw/validation/signature_test.rb +193 -0
- data/test/unit/waw/validation_test.rb +319 -0
- data/test/unit/waw/wspec/html_analysis_test.html +81 -0
- data/test/unit/waw/wspec/html_analysis_test.rb +26 -0
- 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
|
+
}
|