seaweed 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/seaweed +23 -50
- data/lib/Spec/ObjectExtensions.coffee +53 -0
- data/lib/Spec/WindowExtensions.coffee +252 -0
- data/lib/Spec.coffee +127 -239
- data/lib/seaweed/runner.rb +31 -0
- data/lib/seaweed/server.rb +33 -0
- data/lib/seaweed/version.rb +3 -0
- data/lib/seaweed.rb +121 -0
- data/public/ie.js +5 -0
- data/{server/public/jquery-1.5.js → public/jquery-1.5.2.js} +771 -573
- data/public/jsdiff.js +161 -0
- data/public/spec.css +29 -0
- data/views/index.slim +15 -0
- metadata +113 -113
- data/lib/required_files.rb +0 -62
- data/server/public/spec.css +0 -9
- data/server/server.rb +0 -88
- data/server/views/index.slim +0 -11
data/bin/seaweed
CHANGED
@@ -1,55 +1,28 @@
|
|
1
|
-
#!/usr/bin/env
|
2
|
-
|
3
|
-
require 'bundler'
|
4
|
-
require 'celerity'
|
5
|
-
require 'watchr'
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
6
3
|
|
7
|
-
require File.
|
8
|
-
require
|
9
|
-
require 'net/http'
|
4
|
+
require "#{File.dirname(__FILE__)}/../lib/seaweed/runner.rb"
|
5
|
+
require 'optparse'
|
10
6
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
'auto'
|
24
|
-
else
|
25
|
-
'auto'
|
26
|
-
end
|
27
|
-
|
28
|
-
if mode == 'server'
|
29
|
-
Rack::Handler.default.run app, :Port => PORT
|
30
|
-
else
|
31
|
-
Thread.new do
|
32
|
-
Rack::Handler.default.run app, :Port => PORT
|
33
|
-
end
|
34
|
-
|
35
|
-
begin
|
36
|
-
page = Net::HTTP.get URI.parse("http://localhost:#{PORT}/")
|
37
|
-
rescue Errno::ECONNREFUSED
|
38
|
-
sleep 1
|
39
|
-
retry
|
7
|
+
options = {}
|
8
|
+
parser = OptionParser.new do |o|
|
9
|
+
o.banner = "Usage: #{$0} [options] mode\nPossible modes: server, terminal, auto"
|
10
|
+
|
11
|
+
options[:port] = nil
|
12
|
+
o.on '-p', '--port PORT', 'Override server port' do |port|
|
13
|
+
options[:port] = port
|
14
|
+
end
|
15
|
+
|
16
|
+
options[:version] = false
|
17
|
+
o.on '-v', '--version', 'Show version' do
|
18
|
+
options[:version] = true
|
40
19
|
end
|
41
|
-
|
42
|
-
browser = Celerity::Browser.new
|
43
|
-
browser.goto "http://localhost:#{PORT}/#terminal"
|
44
|
-
puts browser.text
|
45
20
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
browser.refresh
|
50
|
-
puts browser.text
|
51
|
-
end
|
52
|
-
controller = Watchr::Controller.new(script, Watchr.handler.new)
|
53
|
-
controller.run
|
21
|
+
o.on_tail '-h', '--help', 'Display this screen' do
|
22
|
+
puts o
|
23
|
+
exit
|
54
24
|
end
|
55
|
-
end
|
25
|
+
end
|
26
|
+
parser.parse!
|
27
|
+
|
28
|
+
Seaweed::Runner.new ARGV.first, options, parser
|
@@ -0,0 +1,53 @@
|
|
1
|
+
window.Spec ||= {}
|
2
|
+
window.Spec.ObjectExtensions = {
|
3
|
+
# Tests for a positive match
|
4
|
+
should: (matcher) ->
|
5
|
+
result = Spec.findMatcher(matcher)(this)
|
6
|
+
Spec.fail "expected #{result[1]}" unless result[0]
|
7
|
+
|
8
|
+
# Tests for a negative match
|
9
|
+
shouldNot: (matcher) ->
|
10
|
+
result = Spec.findMatcher(matcher)(this)
|
11
|
+
Spec.fail "expected not #{result[1]}" if result[0]
|
12
|
+
|
13
|
+
# Creates a stub method, with an expectation of no calls
|
14
|
+
shouldNotReceive: (name) ->
|
15
|
+
@shouldReceive(name).exactly(0).times
|
16
|
+
|
17
|
+
# Creates a stub method with an expectation
|
18
|
+
shouldReceive: (name) ->
|
19
|
+
object = this
|
20
|
+
|
21
|
+
received = expectation "to receive “#{name}”"
|
22
|
+
|
23
|
+
passthrough = object[name]
|
24
|
+
object[name] = -> received.meet()
|
25
|
+
|
26
|
+
received.with = (expectArgs...) ->
|
27
|
+
object[name] = (args...) ->
|
28
|
+
received.meet()
|
29
|
+
correct = true
|
30
|
+
correct = false if expectArgs.length != args.length
|
31
|
+
if correct
|
32
|
+
for i in [0..args.length]
|
33
|
+
correct = false unless String(expectArgs[i]) == String(args[i])
|
34
|
+
unless correct
|
35
|
+
Spec.fail "expected ##{name} to be called with arguments “#{expectArgs.join ', '}”, actual arguments: “#{args.join ', '}”"
|
36
|
+
received
|
37
|
+
|
38
|
+
received.andReturn = (returnValue) ->
|
39
|
+
fn = object[name]
|
40
|
+
object[name] = ->
|
41
|
+
fn.apply this, arguments
|
42
|
+
returnValue
|
43
|
+
received
|
44
|
+
|
45
|
+
received.andPassthrough = ->
|
46
|
+
fn = object[name]
|
47
|
+
object[name] = ->
|
48
|
+
fn.apply this, arguments
|
49
|
+
passthrough.apply this, arguments
|
50
|
+
received
|
51
|
+
|
52
|
+
received
|
53
|
+
}
|
@@ -0,0 +1,252 @@
|
|
1
|
+
window.Spec ||= {}
|
2
|
+
window.Spec.WindowExtensions = {
|
3
|
+
SpecObject: (object) ->
|
4
|
+
$.extend this, object if object
|
5
|
+
this
|
6
|
+
|
7
|
+
# Tests if matched value === expected value
|
8
|
+
be: (expected) ->
|
9
|
+
(value) ->
|
10
|
+
[value is expected, "to be #{Spec.inspect expected}, actual #{Spec.inspect value}"]
|
11
|
+
|
12
|
+
# Tests if matched value is a boolean
|
13
|
+
beABoolean: (value) ->
|
14
|
+
[typeof value is 'boolean', "to have type “boolean”, actual “#{typeof value}”"]
|
15
|
+
|
16
|
+
# Tests if matched value is a function
|
17
|
+
beAFunction: (value) ->
|
18
|
+
[typeof value is 'function', "to have type “function”, actual “#{typeof value}”"]
|
19
|
+
|
20
|
+
# Tests if matched value is a number
|
21
|
+
beANumber: (value) ->
|
22
|
+
[typeof value is 'number', "to have type “number”, actual “#{typeof value}”"]
|
23
|
+
|
24
|
+
# Tests if matched value is a string
|
25
|
+
beAString: (value) ->
|
26
|
+
[typeof value is 'string', "to have type “string”, actual “#{typeof value}”"]
|
27
|
+
|
28
|
+
# Tests if matched value is an instance of class
|
29
|
+
beAnInstanceOf: (klass) ->
|
30
|
+
(value) ->
|
31
|
+
[value instanceof klass, "to be an instance of “#{klass}”"]
|
32
|
+
|
33
|
+
# Tests if matched value is an object
|
34
|
+
beAnObject: (value) ->
|
35
|
+
[typeof value is 'object', "to have type “object”, actual “#{typeof value}”"]
|
36
|
+
|
37
|
+
# Tests if given attribute is true
|
38
|
+
beAttribute: (attribute) ->
|
39
|
+
(value) ->
|
40
|
+
result = value[attribute]
|
41
|
+
result = result.call value if typeof result is 'function'
|
42
|
+
[!!result, "to be #{attribute}"]
|
43
|
+
|
44
|
+
# Tests if matched value is boolean false
|
45
|
+
beFalse: (value) ->
|
46
|
+
[String(value) == 'false', "to be false, got #{Spec.inspect value}"]
|
47
|
+
|
48
|
+
# Adds a setup step to the current test case
|
49
|
+
before: (action) ->
|
50
|
+
test = Spec.testStack[Spec.testStack.length - 1]
|
51
|
+
test.before.push action
|
52
|
+
|
53
|
+
# Tests if matched value is boolean true
|
54
|
+
beTrue: (value) ->
|
55
|
+
[String(value) == 'true', "to be true, got #{Spec.inspect value}"]
|
56
|
+
|
57
|
+
context: () ->
|
58
|
+
describe.apply this, arguments
|
59
|
+
|
60
|
+
# Prepares a sub-test of the current test case
|
61
|
+
describe: (title, definition) ->
|
62
|
+
parent = Spec.testStack[Spec.testStack.length - 1]
|
63
|
+
|
64
|
+
ul = $('<ul></ul>')
|
65
|
+
switch Spec.Format
|
66
|
+
when 'ul'
|
67
|
+
parent.ul.append($('<li>' + title + '</li>').append(ul))
|
68
|
+
when 'terminal'
|
69
|
+
$('.results').append(Spec.pad(title, parent.ul.depth) + "<br>")
|
70
|
+
ul.depth = parent.ul.depth + 2
|
71
|
+
|
72
|
+
Spec.testStack.push {
|
73
|
+
title: title
|
74
|
+
ul: ul
|
75
|
+
before: []
|
76
|
+
}
|
77
|
+
definition()
|
78
|
+
Spec.testStack.pop()
|
79
|
+
|
80
|
+
# Tests if matched value == expected value
|
81
|
+
equal: (expected) ->
|
82
|
+
(value) ->
|
83
|
+
[String(value) == String(expected), "to match “#{$.trim diffString(String(value), String(expected))}”"]
|
84
|
+
|
85
|
+
# Allows an assertion on a non-object value
|
86
|
+
expect: (object) ->
|
87
|
+
{
|
88
|
+
to: (matcher) ->
|
89
|
+
result = Spec.findMatcher(matcher)(object)
|
90
|
+
Spec.fail "expected #{result[1]}" unless result[0]
|
91
|
+
notTo: (matcher) ->
|
92
|
+
result = Spec.findMatcher(matcher)(object)
|
93
|
+
Spec.fail "expected not #{result[1]}" if result[0]
|
94
|
+
}
|
95
|
+
|
96
|
+
# Sets up an expectation
|
97
|
+
expectation: (message) ->
|
98
|
+
exp = {
|
99
|
+
message: message
|
100
|
+
meet: -> @met++
|
101
|
+
met: 0
|
102
|
+
desired: 1
|
103
|
+
twice: ->
|
104
|
+
@desired = 2
|
105
|
+
this
|
106
|
+
exactly: (times) ->
|
107
|
+
@desired = times
|
108
|
+
{times: this}
|
109
|
+
timesString: (times) ->
|
110
|
+
switch times
|
111
|
+
when 0
|
112
|
+
'not at all'
|
113
|
+
when 1
|
114
|
+
'once'
|
115
|
+
when 2
|
116
|
+
'twice'
|
117
|
+
else
|
118
|
+
"#{times} times"
|
119
|
+
check: ->
|
120
|
+
if @met != @desired
|
121
|
+
Spec.fail "expected #{message} #{@timesString @desired}, actually received #{@timesString @met}"
|
122
|
+
}
|
123
|
+
Spec.expectations.push exp
|
124
|
+
exp
|
125
|
+
|
126
|
+
finishTest: ->
|
127
|
+
for expectation in Spec.expectations
|
128
|
+
expectation.check()
|
129
|
+
|
130
|
+
reportTestResult(if Spec.passed then "passed" else "failed")
|
131
|
+
|
132
|
+
delete Spec.expectations
|
133
|
+
delete Spec.testTitle
|
134
|
+
window.onerror = -> null
|
135
|
+
|
136
|
+
Spec.env.sandbox.empty().remove()
|
137
|
+
|
138
|
+
# Syntactic sugar to create a before method that prepares a variable
|
139
|
+
#
|
140
|
+
# Example:
|
141
|
+
# given 'dog', -> new Dog()
|
142
|
+
given: (name, definition) ->
|
143
|
+
before ->
|
144
|
+
@[name] = definition.call Spec.env
|
145
|
+
|
146
|
+
haveHtml: (expected) ->
|
147
|
+
(value) ->
|
148
|
+
div = $(document.createElement 'div')
|
149
|
+
div.html expected
|
150
|
+
normalized = div.html()
|
151
|
+
actual = value.html()
|
152
|
+
[actual == normalized, "to have html “#{$.trim diffString(actual, normalized)}”"]
|
153
|
+
|
154
|
+
# All-purpose inclusion matcher
|
155
|
+
include: (expected) ->
|
156
|
+
if expected instanceof Array
|
157
|
+
(value) ->
|
158
|
+
match = true
|
159
|
+
for test in expected
|
160
|
+
match = false unless (value.indexOf && value.indexOf(test) >= 0) || value[test]?
|
161
|
+
[match, "to include #{Spec.inspect expected}, actual #{Spec.inspect value}"]
|
162
|
+
else if typeof expected == 'object'
|
163
|
+
(value) ->
|
164
|
+
missing = {}
|
165
|
+
match = true
|
166
|
+
for test of expected
|
167
|
+
if expected.hasOwnProperty test
|
168
|
+
unless value[test] isnt undefined && String(value[test]) == String(expected[test])
|
169
|
+
match = false
|
170
|
+
missing[test] = expected[test]
|
171
|
+
[match, "to include #{Spec.inspect expected}, actual #{Spec.inspect value}, missing #{Spec.inspect missing}"]
|
172
|
+
else
|
173
|
+
include([expected])
|
174
|
+
|
175
|
+
# Creates a specificaition
|
176
|
+
it: (title, definition) ->
|
177
|
+
# Automatically choose a title when only definition supplied
|
178
|
+
if typeof title is 'function'
|
179
|
+
definition = title
|
180
|
+
title = Spec.descriptionize title
|
181
|
+
|
182
|
+
test = Spec.testStack[Spec.testStack.length - 1]
|
183
|
+
if definition?
|
184
|
+
Spec.env = {sandbox: $('<div/>').appendTo document.body}
|
185
|
+
for aTest in Spec.testStack
|
186
|
+
for action in aTest.before
|
187
|
+
action.call Spec.env
|
188
|
+
|
189
|
+
Spec.expectations = []
|
190
|
+
Spec.testTitle = title
|
191
|
+
|
192
|
+
window.onerror = (message, url, line) ->
|
193
|
+
Spec.fail message, "#{url.replace(document.location, '')}:#{line}"
|
194
|
+
Spec.passed = false
|
195
|
+
finishTest()
|
196
|
+
|
197
|
+
Spec.passed = true
|
198
|
+
definition.call Spec.env
|
199
|
+
finishTest()
|
200
|
+
else
|
201
|
+
reportTestResult "pending"
|
202
|
+
|
203
|
+
# Creates a specification that tests an attribute of subject
|
204
|
+
#
|
205
|
+
# Example:
|
206
|
+
# subject -> new Employee('Fred')
|
207
|
+
# its 'name', -> should equal('Fred')
|
208
|
+
its: (attribute, definition) ->
|
209
|
+
it "#{attribute} #{Spec.descriptionize definition}", ->
|
210
|
+
value = @subject[attribute]
|
211
|
+
value = value.call @subject if typeof value is 'function'
|
212
|
+
@subject = value
|
213
|
+
definition.call Spec.env
|
214
|
+
|
215
|
+
reportTestResult: (status) ->
|
216
|
+
test = Spec.testStack[Spec.testStack.length - 1]
|
217
|
+
|
218
|
+
switch Spec.Format
|
219
|
+
when 'ul'
|
220
|
+
test.ul.append '<li class="' + status + '">' + Spec.testTitle + '</li>'
|
221
|
+
when 'terminal'
|
222
|
+
s = Spec.testTitle
|
223
|
+
color = switch status
|
224
|
+
when 'passed' then 32
|
225
|
+
when 'failed' then 31
|
226
|
+
when 'pending' then 33
|
227
|
+
$('.results').append Spec.pad("[#{color}m#{s}[0m<br>", test.ul.depth)
|
228
|
+
|
229
|
+
Spec.counts[status]++
|
230
|
+
Spec.counts.total++
|
231
|
+
|
232
|
+
# Runs a test against @subject
|
233
|
+
#
|
234
|
+
# Example
|
235
|
+
# subject -> new Employee()
|
236
|
+
# it -> should beAnInstanceOf(Employee)
|
237
|
+
should: (matcher) ->
|
238
|
+
expect(Spec.env.subject).to matcher
|
239
|
+
|
240
|
+
# Runs a negative test against @subject
|
241
|
+
#
|
242
|
+
# Example
|
243
|
+
# subject -> new Employee()
|
244
|
+
# it -> shouldNot be(null)
|
245
|
+
shouldNot: (matcher) ->
|
246
|
+
expect(Spec.env.subject).notTo matcher
|
247
|
+
|
248
|
+
# Creates a before method to prepare the @subject variable
|
249
|
+
subject: (definition) ->
|
250
|
+
given 'subject', definition
|
251
|
+
|
252
|
+
}
|