red 4.1.0 → 4.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +25 -0
- data/lib/red/version.rb +1 -1
- data/lib/source/redshift/accessors.rb +580 -0
- data/lib/source/redshift/browser.rb +150 -0
- data/lib/source/redshift/chainable.rb +75 -0
- data/lib/source/redshift/code_events.rb +204 -0
- data/lib/source/redshift/cookie.rb +142 -0
- data/lib/source/redshift/document.rb +216 -0
- data/lib/source/redshift/element.rb +417 -0
- data/lib/source/redshift/event.rb +312 -0
- data/lib/source/redshift/redshift.red +5 -0
- data/lib/source/redshift/request.rb +276 -0
- data/lib/source/redshift/selectors.rb +374 -0
- data/lib/source/redshift/situated.rb +328 -0
- data/lib/source/redshift/store.rb +48 -0
- data/lib/source/redshift/transform.rb +199 -0
- data/lib/source/redshift/tween.rb +66 -0
- data/lib/source/redshift/user_events.rb +215 -0
- data/lib/source/redshift/validator.rb +21 -0
- data/lib/source/redshift/window.rb +11 -0
- data/lib/source/redspec/index.html +11 -0
- data/lib/source/redspec/lib/red_spec/red_spec.red +525 -0
- data/lib/source/redspec/lib/stylesheets/specs.sass +290 -0
- metadata +27 -2
@@ -0,0 +1,525 @@
|
|
1
|
+
# Spec::DSL (module)
|
2
|
+
# should_fail
|
3
|
+
# should_be
|
4
|
+
# should_not_be
|
5
|
+
# should_be_empty
|
6
|
+
# should_not_be_empty
|
7
|
+
# should_be_true
|
8
|
+
# should_not_be_true
|
9
|
+
# should_be_false
|
10
|
+
# should_not_be_false
|
11
|
+
# should_be_nil
|
12
|
+
# should_not_be_nil
|
13
|
+
# should_have
|
14
|
+
# should_not_have
|
15
|
+
# should_have_exactly
|
16
|
+
# should_have_at_least
|
17
|
+
# should_have_at_most
|
18
|
+
# should_include
|
19
|
+
# should_not_include
|
20
|
+
# should_match
|
21
|
+
# should_not_match
|
22
|
+
#
|
23
|
+
|
24
|
+
# RedSpec is a BDD library designed for Red (url)
|
25
|
+
# RedSpec draws inspiration from both Ruby RSpec and Javascript JSSpec
|
26
|
+
# Using:
|
27
|
+
# RedSpec is intended for use with Red Herring, the framework-independant Red runner (url)
|
28
|
+
|
29
|
+
|
30
|
+
module DSL
|
31
|
+
# +DSL::Base+ represents the basic syntax that all Red objects should have to
|
32
|
+
# work properly with RedSpec. It also includes stub methods for methods that
|
33
|
+
# only object of a specific type should have. These methods will raise Specs::Failure when
|
34
|
+
# called because calling them on any object that does not include their
|
35
|
+
# fully implemented versions implies a specification that behaves
|
36
|
+
# differently than expected.
|
37
|
+
#
|
38
|
+
module Base
|
39
|
+
def should_equal(other)
|
40
|
+
raise ::Specs::Failure unless self == other
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
def should_be(other)
|
45
|
+
raise ::Specs::Failure unless self === other
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
def should_not_be(other)
|
50
|
+
raise ::Specs::Failure if self === other
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
def should_not_equal(other)
|
55
|
+
raise ::Specs::Failure if self == other
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
def should_not_be_nil
|
60
|
+
raise ::Specs::Failure if self == nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# here for polymorphic purposes. all objects will need to respond
|
64
|
+
# to these but having these methods called implies you are
|
65
|
+
# are not getting a object you intended.
|
66
|
+
#
|
67
|
+
# For example, calling .should_be_true on an object that is
|
68
|
+
# not _true_ implies a specification failure by defintaiton
|
69
|
+
# and will raise Specs::Failure
|
70
|
+
def should_be_nil; raise ::Specs::Failure; end
|
71
|
+
def should_be_true; raise ::Specs::Failure; end
|
72
|
+
def should_be_false; raise ::Specs::Failure; end
|
73
|
+
def should_have(n); raise ::Specs::Failure; end
|
74
|
+
def items; raise ::Specs::Failure; end
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
module Nil
|
79
|
+
def should_be_nil
|
80
|
+
raise ::Specs::Failure unless self == nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def should_not_be_nil
|
84
|
+
raise ::Specs::Failure if self == nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module Boolean
|
89
|
+
def should_be_true
|
90
|
+
raise ::Specs::Failure unless `this.valueOf()`
|
91
|
+
end
|
92
|
+
|
93
|
+
def should_be_false
|
94
|
+
raise ::Specs::Failure if `this.valueOf()`
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
module Proc
|
99
|
+
def should_raise(specific_exception = nil)
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def should_not_raise(specific_exception = nil)
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
module Array
|
109
|
+
def should_have(n)
|
110
|
+
raise ::Specs::Failure unless self.size == n
|
111
|
+
end
|
112
|
+
|
113
|
+
# just for looks to allow sugary syntax like
|
114
|
+
# @foo.bar.should_have(2).items
|
115
|
+
def items
|
116
|
+
true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
String.include(DSL::Base)
|
122
|
+
Array.include(DSL::Base)
|
123
|
+
Hash.include(DSL::Base)
|
124
|
+
Numeric.include(DSL::Base)
|
125
|
+
Class.include(DSL::Base)
|
126
|
+
nil.extend(DSL::Base)
|
127
|
+
nil.extend(DSL::Nil)
|
128
|
+
|
129
|
+
`Red.donateMethodsToClass(#{DSL::Boolean}.prototype, Boolean.prototype)`
|
130
|
+
|
131
|
+
Array.include(DSL::Array)
|
132
|
+
Proc.include(DSL::Proc)
|
133
|
+
|
134
|
+
|
135
|
+
# Just stores the @@spec_list class variables. @@spec_list is an array of
|
136
|
+
# all the specs created with Spec.describe. This might go away with everthing nested inside
|
137
|
+
# of class Spec
|
138
|
+
class RedSpec
|
139
|
+
@@specs_list = []
|
140
|
+
def self.specs
|
141
|
+
@@specs_list
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.escape_tags(string)
|
145
|
+
return string
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class Spec
|
150
|
+
attr_accessor :name, :block, :examples, :runner
|
151
|
+
|
152
|
+
def self.describe(name, &block)
|
153
|
+
s = Spec.new(name, &block)
|
154
|
+
RedSpec.specs << s
|
155
|
+
block.call(s)
|
156
|
+
end
|
157
|
+
|
158
|
+
def initialize(name, &block)
|
159
|
+
@name = name.to_s
|
160
|
+
@block = block
|
161
|
+
@examples = []
|
162
|
+
end
|
163
|
+
|
164
|
+
# the meat of the verb calls on 'it' ('can', 'has', 'does', 'wants', etc).
|
165
|
+
# allows us to add new verbs and stay DRY.
|
166
|
+
def verb(display_verb, description, &block)
|
167
|
+
self.examples << ::Specs::Example.new((display_verb + " " + description), self, &block)
|
168
|
+
end
|
169
|
+
|
170
|
+
def can(description, &block)
|
171
|
+
self.verb("can", description, &block)
|
172
|
+
end
|
173
|
+
|
174
|
+
def returns(description, &block)
|
175
|
+
self.verb("returns", description, &block)
|
176
|
+
end
|
177
|
+
|
178
|
+
def has(description, &block)
|
179
|
+
self.verb("has", description, &block)
|
180
|
+
end
|
181
|
+
|
182
|
+
def does_not(description, &block)
|
183
|
+
self.verb("does not", description, &block)
|
184
|
+
end
|
185
|
+
|
186
|
+
def to_heading_html
|
187
|
+
"<li id=\"spec_#{self.object_id.to_s}_list\"><h3><a href=\"#spec_#{self.object_id.to_s}\"> #{RedSpec.escape_tags(self.name)}</a> [<a href=\"?rerun=#{self.name}\">rerun</a>]</h3></li>"
|
188
|
+
end
|
189
|
+
|
190
|
+
def examples_to_html
|
191
|
+
examples_as_text = []
|
192
|
+
self.examples.each do |example|
|
193
|
+
examples_as_text << example.to_html
|
194
|
+
end
|
195
|
+
examples_as_text.join('')
|
196
|
+
end
|
197
|
+
|
198
|
+
def to_html_with_examples
|
199
|
+
"<li id=\"spec_#{self.object_id.to_s}\">
|
200
|
+
<h3>#{RedSpec.escape_tags(self.name)} [<a href=\"?rerun=#{self.name}\">rerun</a>]</h3>
|
201
|
+
<ul id=\"spec_#{self.object_id.to_s}_examples\" class=\"examples\">
|
202
|
+
#{self.examples_to_html}
|
203
|
+
</ul>
|
204
|
+
</li>
|
205
|
+
"
|
206
|
+
end
|
207
|
+
|
208
|
+
def executor
|
209
|
+
::Specs::Executor.new(self)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
module Specs
|
214
|
+
# class +Failure+ is raise when an +Example+ fails to behave as intended.
|
215
|
+
# +Failure+ is rescued by the +Runner+ which notes the failure and
|
216
|
+
# continues to run subsequent Examples.
|
217
|
+
class Failure < Exception; end
|
218
|
+
|
219
|
+
# class +Error+ is raise when an +Example+ throws an error. Typically this
|
220
|
+
# is caused by errors of javascript syntax, missing variables, etc.
|
221
|
+
# Many Ruby syntax errors will be discovered by Red at compile time when
|
222
|
+
# ParseTree cannot parse the file.
|
223
|
+
# +Error+ is rescued by the +Runner+ which notes the error and
|
224
|
+
# continues to run subsequent Examples.
|
225
|
+
class Error < Exception; end
|
226
|
+
|
227
|
+
# each block within a spec is an example. typicall referenced with 'it' and one
|
228
|
+
# of the action verb methods ('should', 'can', 'has', etc)
|
229
|
+
#
|
230
|
+
# for example:
|
231
|
+
# Spec.describe Foo do |it|
|
232
|
+
#
|
233
|
+
# it.has 'pretty damn awesome bars' do
|
234
|
+
# # I am an Example object and will be called by the Runner
|
235
|
+
# end
|
236
|
+
#
|
237
|
+
# end
|
238
|
+
#
|
239
|
+
class Example
|
240
|
+
attr_accessor :block, :name, :result, :spec
|
241
|
+
def initialize(name, spec, &block)
|
242
|
+
|
243
|
+
# Examples without blocks will be listed as 'pending'
|
244
|
+
# and will not be executed by the Runner.
|
245
|
+
self.result = "pending" if block.nil?
|
246
|
+
@name = name
|
247
|
+
@spec = spec
|
248
|
+
@block = block
|
249
|
+
end
|
250
|
+
|
251
|
+
def to_html
|
252
|
+
"<li id=\"example_#{self.object_id.to_s}\">
|
253
|
+
<h4>#{RedSpec.escape_tags(self.name)}</h4>
|
254
|
+
</li>
|
255
|
+
"
|
256
|
+
end
|
257
|
+
|
258
|
+
def executor
|
259
|
+
::Specs::Executor.new(self)
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
# responsible for gathering all specs from RedSpec.specs (or a subset if you're rerunning
|
265
|
+
# a particual spec) into one place and running them.
|
266
|
+
class Runner
|
267
|
+
attr_accessor :specs, :specs_map, :total_examples, :logger, :ordered_executor, :total_failures, :total_errors, :total_pending
|
268
|
+
def initialize(arg_specs, logger)
|
269
|
+
logger.runner = self
|
270
|
+
@logger = logger
|
271
|
+
|
272
|
+
@specs = []
|
273
|
+
@specs_map = {}
|
274
|
+
|
275
|
+
self.total_examples = 0
|
276
|
+
self.total_pending = 0
|
277
|
+
self.total_failures = 0
|
278
|
+
self.add_all_specs(arg_specs)
|
279
|
+
end
|
280
|
+
|
281
|
+
def add_all_specs(specs)
|
282
|
+
specs.each {|spec| self.add_spec(spec)}
|
283
|
+
end
|
284
|
+
|
285
|
+
def add_spec(spec)
|
286
|
+
spec.runner = self
|
287
|
+
self.specs << spec
|
288
|
+
# self.specs_map[spec.object_id] = spec
|
289
|
+
self.total_examples += spec.examples.size
|
290
|
+
end
|
291
|
+
|
292
|
+
def run
|
293
|
+
self.logger.on_runner_start
|
294
|
+
self.ordered_executor = Specs::OrderedExecutor.new
|
295
|
+
self.specs.each do |spec|
|
296
|
+
spec.examples.each do |example|
|
297
|
+
self.ordered_executor.add_executor(example.executor)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
self.ordered_executor.run
|
302
|
+
self.logger.on_runner_end
|
303
|
+
end
|
304
|
+
|
305
|
+
# def get_spec_by_id ; end
|
306
|
+
# def get_spec_by_context ; end
|
307
|
+
# def has_exception ; end
|
308
|
+
# def total_failures ; end
|
309
|
+
# def total_errors ; end
|
310
|
+
# def rerun ; end
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
# executes the code of the examples in each spec
|
315
|
+
# and stores their state (success/failure) and any
|
316
|
+
# failure messages, normalized for browser differences
|
317
|
+
class Executor
|
318
|
+
attr_accessor :example, :type, :containing_ordered_executor, :on_start
|
319
|
+
|
320
|
+
def initialize(example)
|
321
|
+
self.example = example
|
322
|
+
end
|
323
|
+
|
324
|
+
def run
|
325
|
+
::Specs::Logger.on_example_start(self.example)
|
326
|
+
|
327
|
+
begin
|
328
|
+
if self.example.result # result was set to pending on Example#initialize
|
329
|
+
self.type = 'pending'
|
330
|
+
self.example.spec.runner.total_pending += 1
|
331
|
+
else
|
332
|
+
self.example.block.call
|
333
|
+
end
|
334
|
+
|
335
|
+
self.type = 'success'
|
336
|
+
self.example.result = 'success' unless self.example.result
|
337
|
+
|
338
|
+
rescue ::Specs::Failure
|
339
|
+
self.type = 'failure'
|
340
|
+
self.example.result = 'failure'
|
341
|
+
self.example.spec.runner.total_failures += 1
|
342
|
+
rescue Exception
|
343
|
+
self.example.rescue = 'exception'
|
344
|
+
self.example.spec.runner.total_errors += 1
|
345
|
+
end
|
346
|
+
|
347
|
+
::Specs::Logger.on_example_end(self.example)
|
348
|
+
|
349
|
+
self.containing_ordered_executor.next
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
|
354
|
+
class OrderedExecutor
|
355
|
+
attr_accessor :queue, :at
|
356
|
+
|
357
|
+
def initialize
|
358
|
+
@queue = []
|
359
|
+
self.at = 0
|
360
|
+
end
|
361
|
+
|
362
|
+
def add_executor(executor)
|
363
|
+
# some other stuff with callbacks? no idea
|
364
|
+
executor.containing_ordered_executor = self
|
365
|
+
self.queue << executor
|
366
|
+
end
|
367
|
+
|
368
|
+
# Runs the next Executor in the queue.
|
369
|
+
def next
|
370
|
+
self.at += 1
|
371
|
+
self.queue[self.at].run unless self.at >= self.queue.size
|
372
|
+
end
|
373
|
+
|
374
|
+
def run
|
375
|
+
if self.queue.size > 0
|
376
|
+
self.queue[0].run
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
# Logger writes the pretty to the screen
|
382
|
+
class Logger
|
383
|
+
attr_accessor :runner, :started_at, :ended_at
|
384
|
+
|
385
|
+
# on_runner_start is called just before the specs are run and writes the general logging
|
386
|
+
# structure to the page for later manipulation
|
387
|
+
def on_runner_start
|
388
|
+
title = `document.title`
|
389
|
+
self.started_at = Time.now
|
390
|
+
# self.runnetotal_failures = 0
|
391
|
+
|
392
|
+
# if container already exists it implies we are rerunning the
|
393
|
+
# specs and the contents of the div should be cleared.
|
394
|
+
# Otherwise we added a containing div to the page
|
395
|
+
# to hold our Logger printout.
|
396
|
+
container = `document.getElementById('redspec_container')`
|
397
|
+
if container
|
398
|
+
`container.innerHTML = ""`
|
399
|
+
else
|
400
|
+
`container = document.createElement("DIV")`
|
401
|
+
`container.id = "redspec_container"`
|
402
|
+
`document.body.appendChild(container)`
|
403
|
+
end
|
404
|
+
|
405
|
+
# The dashboard contains at-a-glace information about the running/competed specs
|
406
|
+
# allowing a tester to see see a summary of
|
407
|
+
`dashboard = document.createElement("DIV")`
|
408
|
+
`dashboard.id = "dashboard"`
|
409
|
+
`dashboard.innerHTML = [
|
410
|
+
'<h1>RedSpec</h1>',
|
411
|
+
'<ul>',
|
412
|
+
// JSSpec.options.rerun ? '<li>[<a href="?" title="rerun all specs">X</a>] ' + JSSpec.util.escapeTags(decodeURIComponent(JSSpec.options.rerun)) + '</li>' : '',
|
413
|
+
' <li><span id="total_examples">' + #{self.runner.total_examples} + '</span> examples</li>',
|
414
|
+
' <li><span id="total_failures">0</span> failures</li>',
|
415
|
+
' <li><span id="total_errors">0</span> errors</li>',
|
416
|
+
' <li><span id="total_pending">0</span> pending</li>',
|
417
|
+
' <li><span id="progress">0</span>% done</li>',
|
418
|
+
' <li><span id="total_elapsed">0</span> secs</li>',
|
419
|
+
'</ul>',
|
420
|
+
'<p><a href="">RedSpec documentation</a></p>',
|
421
|
+
].join("");`
|
422
|
+
|
423
|
+
`container.appendChild(dashboard);`
|
424
|
+
|
425
|
+
# convert all of the specs for this runner into native js strings for writing
|
426
|
+
all_runner_specs = []
|
427
|
+
self.runner.specs.each do |spec|
|
428
|
+
all_runner_specs << spec.to_heading_html
|
429
|
+
end
|
430
|
+
`all_runner_specs_as_list_items = #{all_runner_specs.join("")}.__value__`
|
431
|
+
|
432
|
+
# List the Specs by name to act as a table of contents
|
433
|
+
`list = document.createElement("DIV")`
|
434
|
+
`list.id = "list"`
|
435
|
+
`list.innerHTML = [
|
436
|
+
'<h2>Specs</h2>',
|
437
|
+
'<ul class="specs">',
|
438
|
+
all_runner_specs_as_list_items,
|
439
|
+
'</ul>'
|
440
|
+
].join("")`
|
441
|
+
`container.appendChild(list)`
|
442
|
+
|
443
|
+
|
444
|
+
# List all the examples, nested within their Spec name
|
445
|
+
# so we can later manipulate their element to display
|
446
|
+
# results of running a particular example.
|
447
|
+
`log = document.createElement("DIV")`
|
448
|
+
`log.id = "log"`
|
449
|
+
|
450
|
+
all_runner_specs_with_examples = []
|
451
|
+
self.runner.specs.each do |spec|
|
452
|
+
all_runner_specs_with_examples << spec.to_html_with_examples
|
453
|
+
end
|
454
|
+
`all_runner_specs_as_list_items_with_examples = #{all_runner_specs_with_examples.join("")}.__value__`
|
455
|
+
|
456
|
+
`log.innerHTML = [
|
457
|
+
'<h2>Log</h2>',
|
458
|
+
'<ul class="specs">',
|
459
|
+
all_runner_specs_as_list_items_with_examples,
|
460
|
+
'</ul>'
|
461
|
+
].join("")`
|
462
|
+
|
463
|
+
`container.appendChild(log)`
|
464
|
+
|
465
|
+
# add event click handler to each spec for toggling
|
466
|
+
self.runner.specs.each do |spec|
|
467
|
+
# `spec_div = document.getElementById('spec_' + #{spec.object_id})`
|
468
|
+
# `title = spec_div.getElementsByTagName("H3")[0]`
|
469
|
+
# `title.onclick = function(e){
|
470
|
+
# var target = document.getElementById(this.parentNode.id + "_examples")
|
471
|
+
# target.style.display = target.style.display == 'none' ? 'block' : 'none'
|
472
|
+
# return true
|
473
|
+
# }`
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
# called automatically when a runner ends, updating the dashboard with result information for
|
478
|
+
# the entire spec suite.
|
479
|
+
def on_runner_end
|
480
|
+
`document.getElementById("total_elapsed").innerHTML = (#{Time.now - self.started_at })`
|
481
|
+
`document.getElementById("total_failures").innerHTML = #{self.runner.total_errors}`
|
482
|
+
`document.getElementById("total_failures").innerHTML = #{self.runner.total_failures}`
|
483
|
+
`document.getElementById("total_pending").innerHTML = #{self.runner.total_pending}`
|
484
|
+
end
|
485
|
+
|
486
|
+
def self.on_spec_start(spec)
|
487
|
+
`spec_list = document.getElementById("spec_" + spec.id + "_list")`
|
488
|
+
`spec_log = document.getElementById("spec_" + spec.id)`
|
489
|
+
|
490
|
+
`spec_list.className = "ongoing"`
|
491
|
+
`spec_log.className = "ongoing"`
|
492
|
+
end
|
493
|
+
|
494
|
+
def self.on_spec_end(spec)
|
495
|
+
|
496
|
+
end
|
497
|
+
|
498
|
+
# called before an example runs
|
499
|
+
def self.on_example_start(example)
|
500
|
+
`li = document.getElementById("example_" + #{example.object_id.to_s})`
|
501
|
+
`li.className = "ongoing"`
|
502
|
+
end
|
503
|
+
|
504
|
+
# called after an example runs, manipulating the examples representation on the page
|
505
|
+
# to reflect the result of the execution.
|
506
|
+
def self.on_example_end(example)
|
507
|
+
`li = document.getElementById("example_" + #{example.object_id.to_s})`
|
508
|
+
`li.className = #{example.result}.__value__`
|
509
|
+
end
|
510
|
+
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
|
515
|
+
main = lambda {
|
516
|
+
if RedSpec.specs.size > 0
|
517
|
+
r = Specs::Runner.new(RedSpec.specs, Specs::Logger.new)
|
518
|
+
r.run
|
519
|
+
end
|
520
|
+
}
|
521
|
+
|
522
|
+
# Wait for the window to load and then determing run the specs
|
523
|
+
# `window.onload = #{main}.__block__`
|
524
|
+
|
525
|
+
`document.addEventListener('DOMContentLoaded', function(){document.__loaded__=true;#{main.call};}.m$(this), false)`
|