ghostbuster 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +17 -1
- data/ghost/config.ru +4 -0
- data/ghost/test_ghostmore.coffee +14 -1
- data/ghost/views/slow.erb +12 -0
- data/lib/ghostbuster.coffee +38 -24
- data/lib/ghostbuster/version.rb +1 -1
- metadata +16 -15
data/README.md
CHANGED
@@ -50,4 +50,20 @@ Look inside `ghost` to see some examples of what actual tests would look like. L
|
|
50
50
|
|
51
51
|
~~~~
|
52
52
|
|
53
|
-
To use this within rake, just put `require 'ghostbuster/install_rake'` in your Rakefile.
|
53
|
+
To use this within rake, just put `require 'ghostbuster/install_rake'` in your Rakefile.
|
54
|
+
|
55
|
+
## Assertions
|
56
|
+
|
57
|
+
Assertions are run in order, and only one assertion at a time can run. An assertion will have at most one second to complete. If you want to change the total amount of time an assertion will take, you can supply that time.
|
58
|
+
|
59
|
+
~~~~
|
60
|
+
@body.assertFirst 'p', total: 3, (p) -> # this asserts the first paragraph's inner text
|
61
|
+
~~~~
|
62
|
+
|
63
|
+
The available assertions are:
|
64
|
+
|
65
|
+
* _assertFirst_ : This asserts for the first matching DOM element
|
66
|
+
* _assertAll_ : This asserts for the each matching DOM element
|
67
|
+
* _assertLocation_ : This asserts the current browser location
|
68
|
+
|
69
|
+
The closures passed for matching have access to the real DOM node, however, they do not have any access to the outside context. They must return true if the assertion is passed, anything else will be interpreted as failure.
|
data/ghost/config.ru
CHANGED
data/ghost/test_ghostmore.coffee
CHANGED
@@ -5,4 +5,17 @@ phantom.test.add "Simple form", ->
|
|
5
5
|
@succeed()
|
6
6
|
|
7
7
|
phantom.test.addPending "Form should do more things", ->
|
8
|
-
console.log "some thing here.."
|
8
|
+
console.log "some thing here.."
|
9
|
+
|
10
|
+
phantom.test.add "Simple form with wait", ->
|
11
|
+
@get '/form', ->
|
12
|
+
@wait 1, ->
|
13
|
+
@succeed()
|
14
|
+
|
15
|
+
phantom.test.add "Slow form", ->
|
16
|
+
@get '/slow', ->
|
17
|
+
@body.input "#in", "this is my input"
|
18
|
+
@body.click "#btn"
|
19
|
+
@body.assertFirst '#out', total: 3, (out) ->
|
20
|
+
out.innerHTML == 'this is my input'
|
21
|
+
@succeed()
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>This is my index</title>
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
<form>
|
7
|
+
<input type="text" id="in">
|
8
|
+
<input type="button" id="btn" onclick="setTimeout( function() { document.getElementById('out').innerHTML = document.getElementById('in').value;}, 2000);">
|
9
|
+
</form>
|
10
|
+
<p id="out"></p>
|
11
|
+
</body>
|
12
|
+
</html>
|
data/lib/ghostbuster.coffee
CHANGED
@@ -3,12 +3,14 @@ class Test
|
|
3
3
|
@page = new WebPage()
|
4
4
|
@page.onConsoleMessage = (msg) ->
|
5
5
|
console.log "PAGE CONSOLE: #{msg}"
|
6
|
-
|
7
|
-
@page.onAlert = (msg) =>
|
8
|
-
@runner.lastErrors[testName] = msg
|
6
|
+
@page.onAlert = (msg) => @setLastError(msg)
|
9
7
|
@lastError = null
|
10
8
|
@assertions = []
|
11
9
|
@seenCallbacks = []
|
10
|
+
getLastError: -> @runner.lastErrors[@name]
|
11
|
+
resetLastError: -> delete @runner.lastErrors[@name]
|
12
|
+
setLastError: (error) ->
|
13
|
+
@runner.lastErrors[@name] = error
|
12
14
|
waitForAssertions: (whenDone) ->
|
13
15
|
if @assertions.length == 0
|
14
16
|
whenDone.call(this)
|
@@ -24,7 +26,7 @@ class Test
|
|
24
26
|
test = this
|
25
27
|
loadedCallback = (status) ->
|
26
28
|
return if test.seenCallbacks.indexOf(getCallback) != -1
|
27
|
-
test.seenCallbacks.push getCallback #traversing links causes this to get re-fired.
|
29
|
+
test.seenCallbacks.push getCallback # traversing links causes this to get re-fired.
|
28
30
|
switch status
|
29
31
|
when 'success'
|
30
32
|
test.body = new Body(test)
|
@@ -37,13 +39,18 @@ class Test
|
|
37
39
|
@callback(true)
|
38
40
|
fail: (msg) ->
|
39
41
|
@callback(false, msg)
|
40
|
-
assert: (valueFetcher) ->
|
41
|
-
@assertions.push(new Assertion(this, valueFetcher))
|
42
|
+
assert: (opts, valueFetcher) ->
|
43
|
+
@assertions.push(new Assertion(this, opts, valueFetcher))
|
42
44
|
@assertions[0].start() if @assertions.length == 1
|
45
|
+
wait: (time, callback) ->
|
46
|
+
test = this
|
47
|
+
setTimeout (-> callback.call(test)), time * 1000
|
43
48
|
|
44
49
|
class Assertion
|
45
|
-
constructor: (@test, @fetcher) ->
|
50
|
+
constructor: (@test, @opts, @fetcher) ->
|
46
51
|
@count = 0
|
52
|
+
@totalTime = if @opts['total'] then @opts['total'] * 1000 else 1000
|
53
|
+
@everyTime = if @opts['every'] then @opts['every'] else 75
|
47
54
|
start: ->
|
48
55
|
test = @test
|
49
56
|
assertion = this
|
@@ -51,21 +58,18 @@ class Assertion
|
|
51
58
|
assertion.start()
|
52
59
|
if @count == 0
|
53
60
|
fatalCallback = ->
|
54
|
-
test.fail(test.
|
55
|
-
@fatal = setTimeout(fatalCallback,
|
61
|
+
test.fail(test.getLastError() || "This assertion failed to complete.")
|
62
|
+
@fatal = setTimeout(fatalCallback, assertion.totalTime)
|
56
63
|
@fetcher.call test, (val) ->
|
57
64
|
assertion.count++
|
58
65
|
if val == true
|
59
|
-
|
66
|
+
test.resetLastError()
|
60
67
|
test.assertions.splice(test.assertions.indexOf(assertion), 1)
|
61
68
|
clearTimeout assertion.fatal
|
62
69
|
if test.assertions.length > 0
|
63
70
|
test.assertions[0].start()
|
64
|
-
else if assertion.count > 10
|
65
|
-
clearTimeout assertion.fatal
|
66
|
-
test.fail(test.lastError)
|
67
71
|
else
|
68
|
-
setTimeout(failedCallback,
|
72
|
+
setTimeout(failedCallback, test.everyTime)
|
69
73
|
|
70
74
|
class Body
|
71
75
|
constructor: (@test) ->
|
@@ -96,11 +100,12 @@ class Body
|
|
96
100
|
"
|
97
101
|
@test.page.evaluate(fn)
|
98
102
|
|
99
|
-
assertLocation: (path) ->
|
103
|
+
assertLocation: (path, opts) ->
|
104
|
+
opts ||= {}
|
100
105
|
test = @test
|
101
106
|
location = @test.runner.normalizePath(path)
|
102
|
-
@test.assert (withValue) ->
|
103
|
-
alerter = if test.
|
107
|
+
@test.assert opts, (withValue) ->
|
108
|
+
alerter = if test.getLastError()? then "" else "alert('Assert location failed: Excepted #{location}, got '+currentLocation);"
|
104
109
|
eval "
|
105
110
|
var fn = function() {
|
106
111
|
var currentLocation = window.location.href;
|
@@ -114,10 +119,13 @@ class Body
|
|
114
119
|
"
|
115
120
|
withValue @page.evaluate(fn)
|
116
121
|
|
117
|
-
assertFirst: (selector, assertionCallback) ->
|
122
|
+
assertFirst: (selector, opts, assertionCallback) ->
|
123
|
+
unless assertionCallback?
|
124
|
+
assertionCallback = opts
|
125
|
+
opts = {}
|
118
126
|
test = @test
|
119
|
-
@test.assert (withValue) ->
|
120
|
-
alerter = if test.
|
127
|
+
@test.assert opts, (withValue) ->
|
128
|
+
alerter = if test.getLastError()? then "" else "alert('Assert first for selector #{selector} did not meet expectations');"
|
121
129
|
eval "
|
122
130
|
var evaluator = function() {
|
123
131
|
try {
|
@@ -139,8 +147,11 @@ class Body
|
|
139
147
|
"
|
140
148
|
withValue @page.evaluate(evaluator)
|
141
149
|
|
142
|
-
assertAll: (selector, assertionCallback) ->
|
143
|
-
|
150
|
+
assertAll: (selector, opts, assertionCallback) ->
|
151
|
+
unless assertionCallback?
|
152
|
+
assertionCallback = opts
|
153
|
+
opts = {}
|
154
|
+
@test.assert opts, (withValue) ->
|
144
155
|
eval "
|
145
156
|
var evaluator = function() {
|
146
157
|
try {
|
@@ -172,7 +183,10 @@ class TestFile
|
|
172
183
|
@lastErrors = {}
|
173
184
|
normalizePath: (path) -> if path.match(/^http/) then path else "#{@root}#{path}"
|
174
185
|
addPending: (name, body) -> @tests.push new PendingTest(this, name)
|
175
|
-
add: (name, body) ->
|
186
|
+
add: (name, body) ->
|
187
|
+
for test in @tests
|
188
|
+
throw("Identically named test already exists for name #{name} in #{@name}") if test.name == name
|
189
|
+
@tests.push new Test(this, name, body)
|
176
190
|
run: (callback) ->
|
177
191
|
throw "No root is defined" unless @root?
|
178
192
|
count = 0
|
@@ -199,7 +213,7 @@ class TestFile
|
|
199
213
|
console.log " \033[32m\u2713\033[0m #{name}"
|
200
214
|
else if state == 'pending'
|
201
215
|
pending++
|
202
|
-
console.log " \033[33m\
|
216
|
+
console.log " \033[33m\u25d0\033[0m #{name}"
|
203
217
|
else
|
204
218
|
failure++
|
205
219
|
console.log " \033[31m\u2717\033[0m #{name}\n #{@lastErrors[name] || "There was a problem"}"
|
data/lib/ghostbuster/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ghostbuster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Josh Hull
|
@@ -19,8 +19,9 @@ date: 2011-08-26 00:00:00 -07:00
|
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
+
name: thin
|
22
23
|
prerelease: false
|
23
|
-
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
25
|
none: false
|
25
26
|
requirements:
|
26
27
|
- - ~>
|
@@ -31,12 +32,12 @@ dependencies:
|
|
31
32
|
- 2
|
32
33
|
- 11
|
33
34
|
version: 1.2.11
|
34
|
-
requirement: *id001
|
35
|
-
name: thin
|
36
35
|
type: :development
|
36
|
+
version_requirements: *id001
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
|
+
name: rake
|
38
39
|
prerelease: false
|
39
|
-
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
41
|
none: false
|
41
42
|
requirements:
|
42
43
|
- - ~>
|
@@ -47,12 +48,12 @@ dependencies:
|
|
47
48
|
- 8
|
48
49
|
- 7
|
49
50
|
version: 0.8.7
|
50
|
-
requirement: *id002
|
51
|
-
name: rake
|
52
51
|
type: :development
|
52
|
+
version_requirements: *id002
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
|
+
name: bundler
|
54
55
|
prerelease: false
|
55
|
-
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
57
|
none: false
|
57
58
|
requirements:
|
58
59
|
- - ~>
|
@@ -63,12 +64,12 @@ dependencies:
|
|
63
64
|
- 0
|
64
65
|
- 14
|
65
66
|
version: 1.0.14
|
66
|
-
requirement: *id003
|
67
|
-
name: bundler
|
68
67
|
type: :development
|
68
|
+
version_requirements: *id003
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
+
name: sinatra
|
70
71
|
prerelease: false
|
71
|
-
|
72
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
72
73
|
none: false
|
73
74
|
requirements:
|
74
75
|
- - ">="
|
@@ -77,9 +78,8 @@ dependencies:
|
|
77
78
|
segments:
|
78
79
|
- 0
|
79
80
|
version: "0"
|
80
|
-
requirement: *id004
|
81
|
-
name: sinatra
|
82
81
|
type: :development
|
82
|
+
version_requirements: *id004
|
83
83
|
description: Integration testing ftw.
|
84
84
|
email:
|
85
85
|
- joshbuddy@gmail.com
|
@@ -104,6 +104,7 @@ files:
|
|
104
104
|
- ghost/test_ghostmore.coffee
|
105
105
|
- ghost/views/form.erb
|
106
106
|
- ghost/views/index.erb
|
107
|
+
- ghost/views/slow.erb
|
107
108
|
- ghostbuster.gemspec
|
108
109
|
- lib/ghostbuster.coffee
|
109
110
|
- lib/ghostbuster.rb
|