red 4.1.0 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)`
|