seaweed 0.1.1 → 0.1.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/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
|
+
}
|