guard-jasmine 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{LICENSE.MIT → LICENSE} +0 -0
- data/README.md +24 -0
- data/bin/guard-jasmine +1 -1
- data/lib/guard/jasmine.rb +39 -11
- data/lib/guard/jasmine/phantomjs/run-jasmine.coffee +184 -62
- data/lib/guard/jasmine/runner.rb +111 -38
- data/lib/guard/jasmine/version.rb +1 -1
- metadata +48 -16
- data/LICENSE.BSD +0 -22
data/{LICENSE.MIT → LICENSE}
RENAMED
File without changes
|
data/README.md
CHANGED
@@ -154,10 +154,34 @@ be shown in the console:
|
|
154
154
|
:specdoc => :always # Specdoc output options, either :always, :never or :failure
|
155
155
|
# default: :failure
|
156
156
|
|
157
|
+
:focus => false # Specdoc focus to hide successful specs when at least one spec fails.
|
158
|
+
# default: true
|
159
|
+
|
160
|
+
:console => :always # Console.log output options, either :always, :never or :failure
|
161
|
+
# default: :failure
|
162
|
+
|
157
163
|
With the option set to `:always`, the specdoc is shown with and without errors in your spec, whereas on with the option
|
158
164
|
set to `:never`, there is no output at all, instead just a summary of the spec run is shown. The default option
|
159
165
|
`:failure` shows the specdoc when at least one spec failed.
|
160
166
|
|
167
|
+
When `:focus` is enabled, only the failing specs are shown in the specdoc when at least one spec is failing.
|
168
|
+
|
169
|
+
The `:console` options adds captured console logs from the spec runner and adds them to the specdoc. Please note
|
170
|
+
that PhantomJS only support capturing of `console.log`, so the other log functions like `debug`, `warn`, `info` and
|
171
|
+
`error` are missing. Please vote on [Issue 232](http://code.google.com/p/phantomjs/issues/detail?id=232) if you like
|
172
|
+
to see support for more console methods coming to PhantomJS.
|
173
|
+
|
174
|
+
Another restriction on console logging is that currently only the first log parameter is passed. So instead of writing
|
175
|
+
|
176
|
+
console.log('Debug of %o with %s', object, string)
|
177
|
+
|
178
|
+
your should write
|
179
|
+
|
180
|
+
console.log('Debug of ' + object.toString() + ' width ' + string)
|
181
|
+
|
182
|
+
You can also give your vote on [Issue 36](http://code.google.com/p/phantomjs/issues/detail?id=36) to see support for
|
183
|
+
multiple console arguments.
|
184
|
+
|
161
185
|
### System notifications options
|
162
186
|
|
163
187
|
These options affects what system notifications (growl, libnotify or notifu) are shown after a spec run:
|
data/bin/guard-jasmine
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
url = ARGV[
|
3
|
+
url = ARGV[0] || 'http://127.0.0.1:3000/jasmine'
|
4
4
|
script = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'guard', 'jasmine', 'phantomjs', 'run-jasmine.coffee'))
|
5
5
|
|
6
6
|
puts "Run Jasmine at #{ url }"
|
data/lib/guard/jasmine.rb
CHANGED
@@ -2,6 +2,7 @@ require 'guard'
|
|
2
2
|
require 'guard/guard'
|
3
3
|
require 'guard/watcher'
|
4
4
|
require 'net/http'
|
5
|
+
require 'version'
|
5
6
|
|
6
7
|
module Guard
|
7
8
|
|
@@ -25,7 +26,9 @@ module Guard
|
|
25
26
|
:keep_failed => true,
|
26
27
|
:all_after_pass => true,
|
27
28
|
:max_error_notify => 3,
|
28
|
-
:specdoc => :failure
|
29
|
+
:specdoc => :failure,
|
30
|
+
:console => :failure,
|
31
|
+
:focus => true
|
29
32
|
}
|
30
33
|
|
31
34
|
# Initialize Guard::Jasmine.
|
@@ -41,6 +44,8 @@ module Guard
|
|
41
44
|
# @option options [Boolean] :keep_failed keep failed suites and add them to the next run again
|
42
45
|
# @option options [Boolean] :all_after_pass run all suites after a suite has passed again after failing
|
43
46
|
# @option options [Symbol] :specdoc options for the specdoc output, either :always, :never or :failure
|
47
|
+
# @option options [Symbol] :console options for the console.log output, either :always, :never or :failure
|
48
|
+
# @option options [Symbol] :focus options for focus on failures in the specdoc
|
44
49
|
#
|
45
50
|
def initialize(watchers = [], options = { })
|
46
51
|
options = DEFAULT_OPTIONS.merge(options)
|
@@ -57,8 +62,12 @@ module Guard
|
|
57
62
|
# @raise [:task_has_failed] when run_on_change has failed
|
58
63
|
#
|
59
64
|
def start
|
60
|
-
if
|
61
|
-
|
65
|
+
if phantomjs_bin_valid?(options[:phantomjs_bin])
|
66
|
+
if jasmine_runner_available?(options[:jasmine_url])
|
67
|
+
run_all if options[:all_on_start]
|
68
|
+
end
|
69
|
+
else
|
70
|
+
throw :task_has_failed
|
62
71
|
end
|
63
72
|
end
|
64
73
|
|
@@ -126,30 +135,49 @@ module Guard
|
|
126
135
|
if response.code.to_i == 200
|
127
136
|
Formatter.info("Jasmine test runner is available at #{ url }")
|
128
137
|
else
|
129
|
-
|
138
|
+
notify_failure("Jasmine test runner isn't available", "Jasmine test runner isn't available at #{ url }")
|
130
139
|
end
|
131
140
|
|
132
141
|
response.code.to_i == 200
|
133
142
|
end
|
134
143
|
|
135
144
|
rescue Errno::ECONNREFUSED => e
|
136
|
-
|
145
|
+
notify_failure("Jasmine test runner isn't available", "Jasmine test runner isn't available at #{ url }")
|
137
146
|
|
138
147
|
false
|
139
148
|
end
|
140
149
|
end
|
141
150
|
|
142
|
-
#
|
151
|
+
# Verifies that the phantomjs bin is available and the
|
152
|
+
# right version is installed.
|
153
|
+
#
|
154
|
+
# @param [String] bin the location of the phantomjs bin
|
155
|
+
# @return [Boolean] when the runner is available
|
156
|
+
#
|
157
|
+
def phantomjs_bin_valid?(bin)
|
158
|
+
version = `#{ bin } --version`
|
159
|
+
|
160
|
+
if !version
|
161
|
+
notify_failure('PhantomJS binary missing', "PhantomJS binary doesn't exist at #{ bin }")
|
162
|
+
elsif version.to_version < '1.3.0'.to_version
|
163
|
+
notify_failure('Wrong PhantomJS version', "PhantomJS binary at #{ bin } must be at least version 1.3.0")
|
164
|
+
else
|
165
|
+
true
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Notify a failure.
|
143
170
|
#
|
144
|
-
# @param [String]
|
171
|
+
# @param title [String] the failure title
|
172
|
+
# @param message [String] the failure message
|
145
173
|
#
|
146
|
-
def
|
147
|
-
message = "Jasmine test runner not available at #{ url }"
|
174
|
+
def notify_failure(title, message)
|
148
175
|
Formatter.error(message)
|
149
176
|
Formatter.notify(message,
|
150
|
-
:title =>
|
177
|
+
:title => title,
|
151
178
|
:image => :failed,
|
152
|
-
:priority => 2)
|
179
|
+
:priority => 2) if options[:notification]
|
180
|
+
false
|
153
181
|
end
|
154
182
|
|
155
183
|
end
|
@@ -1,13 +1,5 @@
|
|
1
|
-
# This file is the script that runs within PhantomJS
|
2
|
-
# waits until they are ready
|
3
|
-
# structure that is the parsed by Guard::Jasmine.
|
4
|
-
#
|
5
|
-
# This scripts needs the TrivialReporter to report the results.
|
6
|
-
#
|
7
|
-
# This file is inspired by the Jasmine runner that comes with the PhantomJS examples:
|
8
|
-
# https://github.com/ariya/phantomjs/blob/master/examples/run-jasmine.coffee, by https://github.com/Roejames12
|
9
|
-
#
|
10
|
-
# This file is licensed under the BSD license.
|
1
|
+
# This file is the script that runs within PhantomJS, requests the Jasmine specs
|
2
|
+
# and waits until they are ready.
|
11
3
|
|
12
4
|
# Wait until the test condition is true or a timeout occurs.
|
13
5
|
#
|
@@ -15,11 +7,11 @@
|
|
15
7
|
# @param [Function] ready the action when the condition is fulfilled
|
16
8
|
# @param [Number] timeout the max amount of time to wait
|
17
9
|
#
|
18
|
-
waitFor = (condition, ready, timeout =
|
10
|
+
waitFor = (condition, ready, timeout = 5000) ->
|
19
11
|
start = new Date().getTime()
|
20
12
|
wait = ->
|
21
13
|
if new Date().getTime() - start > timeout
|
22
|
-
console.log JSON.stringify({ error:
|
14
|
+
console.log JSON.stringify({ error: 'Timeout requesting Jasmine test runner!' })
|
23
15
|
phantom.exit(1)
|
24
16
|
else
|
25
17
|
if condition()
|
@@ -33,71 +25,201 @@ waitFor = (condition, ready, timeout = 3000) ->
|
|
33
25
|
specsReady = ->
|
34
26
|
page.evaluate -> if document.body.querySelector('.finished-at') then true else false
|
35
27
|
|
36
|
-
#
|
28
|
+
# Check arguments of the script.
|
29
|
+
#
|
30
|
+
if phantom.args.length isnt 1
|
31
|
+
console.log JSON.stringify({ error: 'Wrong usage of PhantomJS script!' })
|
32
|
+
phantom.exit()
|
33
|
+
else
|
34
|
+
url = phantom.args[0]
|
35
|
+
|
36
|
+
# Create the web page.
|
37
|
+
#
|
38
|
+
page = require('webpage').create()
|
39
|
+
|
40
|
+
# Used to collect log messages for later assignment to the spec
|
41
|
+
#
|
42
|
+
currentSpecId = 0
|
43
|
+
logs = {}
|
44
|
+
|
45
|
+
# Add logs to the given suite
|
37
46
|
#
|
38
|
-
|
47
|
+
# @param suite [Object} the suite result
|
48
|
+
#
|
49
|
+
page.addLogs = (suite) ->
|
50
|
+
for s in suite.suites
|
51
|
+
arguments.callee(s) if s
|
52
|
+
|
53
|
+
for spec in suite.specs
|
54
|
+
id = Number(spec['id'])
|
55
|
+
spec['logs'] = logs[id] if logs[id] && logs[id].length isnt 0
|
56
|
+
delete spec['id']
|
57
|
+
|
58
|
+
delete suite['id']
|
59
|
+
delete suite['parent']
|
60
|
+
|
61
|
+
# Capture console.log output to add it to
|
62
|
+
# the result when specs have finished.
|
63
|
+
#
|
64
|
+
page.onConsoleMessage = (msg, line, source) ->
|
65
|
+
if /^RUNNER_RESULT: ([\s\S]*)$/.test(msg)
|
66
|
+
result = JSON.parse(RegExp.$1)
|
67
|
+
|
68
|
+
for suite in result.suites
|
69
|
+
page.addLogs(suite)
|
70
|
+
|
71
|
+
console.log JSON.stringify(result, undefined, 2)
|
72
|
+
|
73
|
+
else if /^SPEC_START: (\d+)$/.test(msg)
|
74
|
+
currentSpecId = Number(RegExp.$1)
|
75
|
+
logs[currentSpecId] = []
|
76
|
+
|
77
|
+
else
|
78
|
+
logs[currentSpecId].push "#{ msg } in #{ source } (line #{ line })"
|
79
|
+
|
80
|
+
# Initialize the page before the JavaScript is run.
|
81
|
+
#
|
82
|
+
page.onInitialized = ->
|
39
83
|
page.evaluate ->
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
}
|
55
|
-
|
56
|
-
for suite in document.body.querySelectorAll('div.jasmine_reporter > div.suite')
|
57
|
-
description = suite.querySelector('a.description')
|
58
|
-
suite_ = {
|
59
|
-
description: description.innerText
|
60
|
-
specs: []
|
84
|
+
|
85
|
+
# Jasmine Reporter that logs reporter steps
|
86
|
+
# and results to the console.
|
87
|
+
#
|
88
|
+
class ConsoleReporter
|
89
|
+
|
90
|
+
runnerResult: {
|
91
|
+
passed: false
|
92
|
+
stats: {
|
93
|
+
specs: 0
|
94
|
+
failures: 0
|
95
|
+
time: 0.0
|
96
|
+
}
|
97
|
+
suites: []
|
61
98
|
}
|
62
99
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
100
|
+
currentSpecs: []
|
101
|
+
nestedSuiteResults: {}
|
102
|
+
|
103
|
+
# Report the start of a spec.
|
104
|
+
#
|
105
|
+
# @param spec [jasmine.Spec] the spec
|
106
|
+
#
|
107
|
+
reportSpecStarting: (spec) ->
|
108
|
+
console.log "SPEC_START: #{ spec.id }"
|
109
|
+
|
110
|
+
# Report results from a spec.
|
111
|
+
#
|
112
|
+
# @param spec [jasmine.Spec] the spec
|
113
|
+
#
|
114
|
+
reportSpecResults: (spec) ->
|
115
|
+
unless spec.results().skipped
|
116
|
+
specResult = {
|
117
|
+
id: spec.id
|
118
|
+
description: spec.description
|
119
|
+
passed: spec.results().failedCount is 0
|
70
120
|
}
|
71
|
-
spec_['error_message'] = spec.querySelector('div.resultMessage').innerText if not passed
|
72
|
-
suite_['specs'].push spec_
|
73
121
|
|
74
|
-
|
122
|
+
if spec.results().failedCount isnt 0
|
123
|
+
messages = []
|
124
|
+
messages.push result.message for result in spec.results().getItems()
|
125
|
+
specResult['messages'] = messages if messages.length isnt 0
|
75
126
|
|
76
|
-
|
127
|
+
@currentSpecs.push specResult
|
77
128
|
|
78
|
-
|
129
|
+
# Report results from a suite.
|
130
|
+
#
|
131
|
+
# @param suite [jasmine.Suite] the suite
|
132
|
+
#
|
133
|
+
reportSuiteResults: (suite) ->
|
134
|
+
unless suite.results().skipped
|
135
|
+
suiteResult = {
|
136
|
+
id: suite.id
|
137
|
+
parent: suite.parentSuite?.id
|
138
|
+
description: suite.description
|
139
|
+
passed: suite.results().failedCount is 0
|
140
|
+
specs: @currentSpecs
|
141
|
+
suites: []
|
142
|
+
}
|
79
143
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
144
|
+
if suite.parentSuite?
|
145
|
+
parent = suite.parentSuite.id
|
146
|
+
@nestedSuiteResults[parent] = [] unless @nestedSuiteResults[parent]
|
147
|
+
@nestedSuiteResults[parent].push suiteResult
|
148
|
+
else
|
149
|
+
@addNestedSuites suiteResult
|
150
|
+
@removeEmptySuites suiteResult
|
87
151
|
|
88
|
-
|
152
|
+
if suiteResult.specs.length isnt 0 || suiteResult.suites.length isnt 0
|
153
|
+
@runnerResult.suites.push suiteResult
|
89
154
|
|
90
|
-
|
91
|
-
|
92
|
-
#
|
93
|
-
|
94
|
-
|
155
|
+
@currentSpecs = []
|
156
|
+
|
157
|
+
# Report results from the runner.
|
158
|
+
#
|
159
|
+
# @param runner [jasmine.Runner] the runner
|
160
|
+
#
|
161
|
+
reportRunnerResults: (runner) ->
|
162
|
+
runtime = (new Date().getTime() - @startTime) / 1000
|
163
|
+
|
164
|
+
@runnerResult['passed'] = runner.results().failedCount is 0
|
165
|
+
|
166
|
+
@runnerResult['stats'] = {
|
167
|
+
specs: runner.results().totalCount
|
168
|
+
failures: runner.results().failedCount
|
169
|
+
time: runtime
|
170
|
+
}
|
171
|
+
|
172
|
+
console.log "RUNNER_RESULT: #{ JSON.stringify(@runnerResult) }"
|
173
|
+
|
174
|
+
# Report the start of the runner
|
175
|
+
#
|
176
|
+
# @param runner [jasmine.Runner] the runner
|
177
|
+
#
|
178
|
+
reportRunnerStarting: (runner) ->
|
179
|
+
@startTime = new Date().getTime()
|
180
|
+
|
181
|
+
# Add all nested suites that have previously
|
182
|
+
# been processed.
|
183
|
+
#
|
184
|
+
# @param suiteResult [Object] the suite result
|
185
|
+
#
|
186
|
+
addNestedSuites: (suiteResult) ->
|
187
|
+
if @nestedSuiteResults[suiteResult.id]
|
188
|
+
for suite in @nestedSuiteResults[suiteResult.id]
|
189
|
+
@addNestedSuites suite
|
190
|
+
suiteResult.suites.push suite
|
191
|
+
|
192
|
+
# Removes suites without child suites or specs.
|
193
|
+
#
|
194
|
+
# @param suiteResult [Object] the suite result
|
195
|
+
#
|
196
|
+
removeEmptySuites: (suiteResult) ->
|
197
|
+
suites = []
|
198
|
+
|
199
|
+
for suite in suiteResult.suites
|
200
|
+
@removeEmptySuites suite
|
201
|
+
|
202
|
+
suites.push suite if suite.suites.length isnt 0 || suite.specs.length isnt 0
|
203
|
+
|
204
|
+
suiteResult.suites = suites
|
205
|
+
|
206
|
+
# Log a message
|
207
|
+
#
|
208
|
+
# @param message [String] the log message
|
209
|
+
#
|
210
|
+
log: (message) ->
|
211
|
+
|
212
|
+
# Attach the console reporter when the document is ready.
|
213
|
+
#
|
214
|
+
window.onload = ->
|
215
|
+
jasmine.getEnv().addReporter(new ConsoleReporter())
|
95
216
|
|
96
217
|
# Open web page and run the Jasmine test runner
|
97
218
|
#
|
98
219
|
page.open url, (status) ->
|
99
220
|
if status isnt 'success'
|
100
|
-
console.log
|
221
|
+
console.log JSON.stringify({ error: "Unable to access Jasmine specs at #{ url }" })
|
101
222
|
phantom.exit()
|
102
223
|
else
|
103
|
-
waitFor specsReady,
|
224
|
+
waitFor specsReady, -> phantom.exit()
|
225
|
+
|
data/lib/guard/jasmine/runner.rb
CHANGED
@@ -22,6 +22,7 @@ module Guard
|
|
22
22
|
# @option options [Boolean] :hide_success hide success message notification
|
23
23
|
# @option options [Integer] :max_error_notify maximum error notifications to show
|
24
24
|
# @option options [Symbol] :specdoc options for the specdoc output, either :always, :never
|
25
|
+
# @option options [Symbol] :console options for the console.log output, either :always, :never or :failure
|
25
26
|
# @return [Boolean, Array<String>] the status of the run and the failed files
|
26
27
|
#
|
27
28
|
def run(paths, options = { })
|
@@ -144,25 +145,26 @@ module Guard
|
|
144
145
|
#
|
145
146
|
def evaluate_response(output, file, options)
|
146
147
|
json = output.read
|
148
|
+
result = {}
|
147
149
|
|
148
150
|
begin
|
149
151
|
result = MultiJson.decode(json)
|
150
|
-
output.close
|
151
|
-
|
152
|
-
if result['error']
|
153
|
-
notify_runtime_error(result, options)
|
154
|
-
else
|
155
|
-
result['file'] = file
|
156
|
-
notify_spec_result(result, options)
|
157
|
-
end
|
158
|
-
|
159
|
-
result
|
160
|
-
|
161
152
|
rescue Exception => e
|
162
153
|
Formatter.error("Cannot decode JSON from PhantomJS runner: #{ e.message }")
|
163
154
|
Formatter.error('Please report an issue at: https://github.com/netzpirat/guard-jasmine/issues')
|
164
155
|
Formatter.error(json)
|
156
|
+
ensure
|
157
|
+
output.close
|
165
158
|
end
|
159
|
+
|
160
|
+
if result['error']
|
161
|
+
notify_runtime_error(result, options)
|
162
|
+
else
|
163
|
+
result['file'] = file
|
164
|
+
notify_spec_result(result, options)
|
165
|
+
end
|
166
|
+
|
167
|
+
result
|
166
168
|
end
|
167
169
|
|
168
170
|
# Notification when a system error happens that
|
@@ -193,58 +195,129 @@ module Guard
|
|
193
195
|
plural = failures == 1 ? '' : 's'
|
194
196
|
|
195
197
|
message = "#{ specs } specs, #{ failures } failure#{ plural }\nin #{ time } seconds"
|
198
|
+
passed = failures == 0
|
196
199
|
|
197
|
-
if
|
198
|
-
|
200
|
+
if passed
|
201
|
+
report_specdoc(result, passed, options) if options[:specdoc] == :always
|
202
|
+
Formatter.success(message)
|
203
|
+
Formatter.notify(message, :title => 'Jasmine suite passed') if options[:notification] && !options[:hide_success]
|
204
|
+
else
|
205
|
+
report_specdoc(result, passed, options) if options[:specdoc] != :never
|
199
206
|
Formatter.error(message)
|
200
207
|
notify_errors(result, options)
|
201
208
|
Formatter.notify(message, :title => 'Jasmine suite failed', :image => :failed, :priority => 2) if options[:notification]
|
202
|
-
else
|
203
|
-
show_specdoc(result) if options[:specdoc] == :always
|
204
|
-
Formatter.success(message)
|
205
|
-
Formatter.notify(message, :title => 'Jasmine suite passed') if options[:notification] && !options[:hide_success]
|
206
209
|
end
|
207
210
|
end
|
208
211
|
|
209
212
|
# Specdoc like formatting of the result.
|
210
213
|
#
|
211
214
|
# @param [Hash] result the suite result
|
215
|
+
# @param [Boolean] passed status
|
216
|
+
# @param [Hash] options the options
|
217
|
+
# @option options [Symbol] :console options for the console.log output, either :always, :never or :failure
|
212
218
|
#
|
213
|
-
def
|
219
|
+
def report_specdoc(result, passed, options)
|
214
220
|
result['suites'].each do |suite|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
221
|
+
report_specdoc_suite(suite, passed, options)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Show the suite result.
|
226
|
+
#
|
227
|
+
# @param [Hash] suite the suite
|
228
|
+
# @param [Boolean] passed status
|
229
|
+
# @param [Hash] options the options
|
230
|
+
# @option options [Symbol] :console options for the console.log output, either :always, :never or :failure
|
231
|
+
# @option options [Symbol] :focus options for focus on failures in the specdoc
|
232
|
+
# @param [Number] level the indention level
|
233
|
+
#
|
234
|
+
def report_specdoc_suite(suite, passed, options, level = 0)
|
235
|
+
Formatter.suite_name((' ' * level) + suite['description']) if passed || options[:focus] && contains_failed_spec?(suite)
|
236
|
+
|
237
|
+
suite['specs'].each do |spec|
|
238
|
+
if spec['passed']
|
239
|
+
if passed || !options[:focus]
|
240
|
+
Formatter.success(indent(" ✔ #{ spec['description'] }", level))
|
241
|
+
report_specdoc_logs(spec, options, level)
|
242
|
+
end
|
243
|
+
else
|
244
|
+
Formatter.spec_failed(indent(" ✘ #{ spec['description'] }", level))
|
245
|
+
spec['messages'].each do |message|
|
246
|
+
Formatter.spec_failed(indent(" ➤ #{ format_message(message, false) }", level))
|
223
247
|
end
|
248
|
+
report_specdoc_logs(spec, options, level)
|
224
249
|
end
|
225
250
|
end
|
251
|
+
|
252
|
+
suite['suites'].each { |suite| report_specdoc_suite(suite, passed, options, level + 2) } if suite['suites']
|
226
253
|
end
|
227
254
|
|
228
|
-
#
|
255
|
+
# Shows the logs for a given spec.
|
256
|
+
#
|
257
|
+
# @param [Hash] spec the spec result
|
258
|
+
# @param [Hash] options the options
|
259
|
+
# @option options [Symbol] :console options for the console.log output, either :always, :never or :failure
|
260
|
+
# @param [Number] level the indention level
|
261
|
+
#
|
262
|
+
def report_specdoc_logs(spec, options, level)
|
263
|
+
if spec['logs'] && (options[:console] == :always || (options[:console] == :failure && !spec['passed']))
|
264
|
+
spec['logs'].each do |log|
|
265
|
+
Formatter.info(indent(" • #{ format_message(log, true) }", level))
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# Indent a message.
|
271
|
+
#
|
272
|
+
# @param [String] message the message
|
273
|
+
# @param [Number] level the indention level
|
274
|
+
#
|
275
|
+
def indent(message, level)
|
276
|
+
(' ' * level) + message
|
277
|
+
end
|
278
|
+
|
279
|
+
# Show system notifications about the occurred errors.
|
229
280
|
#
|
230
281
|
# @param [Hash] result the suite result
|
282
|
+
# @param [Hash] options the options
|
231
283
|
# @option options [Integer] :max_error_notify maximum error notifications to show
|
232
|
-
# @option options [Boolean] :
|
284
|
+
# @option options [Boolean] :notification show notifications
|
233
285
|
#
|
234
286
|
def notify_errors(result, options)
|
235
|
-
result['suites'].
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
end
|
287
|
+
collect_specs(result['suites']).each_with_index do |spec, index|
|
288
|
+
if !spec['passed'] && options[:max_error_notify] > index
|
289
|
+
msg = spec['messages'].map { |message| format_message(message, true) }.join(', ')
|
290
|
+
Formatter.notify("#{ spec['description'] }: #{ msg }",
|
291
|
+
:title => 'Jasmine spec failed',
|
292
|
+
:image => :failed,
|
293
|
+
:priority => 2) if options[:notification]
|
243
294
|
end
|
244
295
|
end
|
245
296
|
end
|
246
297
|
|
247
|
-
#
|
298
|
+
# Tests if the given suite has a failing spec underneath.
|
299
|
+
#
|
300
|
+
# @param [Hash] suite the suite result
|
301
|
+
# @return [Boolean] the search result
|
302
|
+
#
|
303
|
+
def contains_failed_spec?(suite)
|
304
|
+
collect_specs([suite]).any? { |spec| !spec['passed'] }
|
305
|
+
end
|
306
|
+
|
307
|
+
# Get all specs from the suites and its nested suites.
|
308
|
+
#
|
309
|
+
# @param suites [Array<Hash>] the suites results
|
310
|
+
# @param [Array<Hash>] all specs
|
311
|
+
#
|
312
|
+
def collect_specs(suites)
|
313
|
+
suites.inject([]) do |specs, suite|
|
314
|
+
specs = (specs | suite['specs']) if suite['specs']
|
315
|
+
specs = (specs | collect_specs(suite['suites'])) if suite['suites']
|
316
|
+
specs
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
# Formats a message.
|
248
321
|
#
|
249
322
|
# Known message styles:
|
250
323
|
#
|
@@ -254,7 +327,7 @@ module Guard
|
|
254
327
|
# @param [Boolean] short show a short version of the message
|
255
328
|
# @return [String] the cleaned error message
|
256
329
|
#
|
257
|
-
def
|
330
|
+
def format_message(message, short)
|
258
331
|
if message =~ /(.*?) in http.+?assets\/(.*)\?body=\d+\s\((line\s\d+)/
|
259
332
|
short ? $1 : "#{ $1 } in #{ $2 } on #{ $3 }"
|
260
333
|
else
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 7
|
9
|
+
- 0
|
10
|
+
version: 0.7.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Michael Kessler
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-10-
|
18
|
+
date: 2011-10-10 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: guard
|
@@ -50,9 +50,25 @@ dependencies:
|
|
50
50
|
type: :runtime
|
51
51
|
version_requirements: *id002
|
52
52
|
- !ruby/object:Gem::Dependency
|
53
|
-
name:
|
53
|
+
name: version
|
54
54
|
prerelease: false
|
55
55
|
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 23
|
61
|
+
segments:
|
62
|
+
- 1
|
63
|
+
- 0
|
64
|
+
- 0
|
65
|
+
version: 1.0.0
|
66
|
+
type: :runtime
|
67
|
+
version_requirements: *id003
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: bundler
|
70
|
+
prerelease: false
|
71
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
56
72
|
none: false
|
57
73
|
requirements:
|
58
74
|
- - ~>
|
@@ -63,11 +79,11 @@ dependencies:
|
|
63
79
|
- 0
|
64
80
|
version: "1.0"
|
65
81
|
type: :development
|
66
|
-
version_requirements: *
|
82
|
+
version_requirements: *id004
|
67
83
|
- !ruby/object:Gem::Dependency
|
68
84
|
name: guard-rspec
|
69
85
|
prerelease: false
|
70
|
-
requirement: &
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
71
87
|
none: false
|
72
88
|
requirements:
|
73
89
|
- - ~>
|
@@ -78,11 +94,11 @@ dependencies:
|
|
78
94
|
- 4
|
79
95
|
version: "0.4"
|
80
96
|
type: :development
|
81
|
-
version_requirements: *
|
97
|
+
version_requirements: *id005
|
82
98
|
- !ruby/object:Gem::Dependency
|
83
99
|
name: rspec
|
84
100
|
prerelease: false
|
85
|
-
requirement: &
|
101
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
86
102
|
none: false
|
87
103
|
requirements:
|
88
104
|
- - ~>
|
@@ -93,11 +109,11 @@ dependencies:
|
|
93
109
|
- 6
|
94
110
|
version: "2.6"
|
95
111
|
type: :development
|
96
|
-
version_requirements: *
|
112
|
+
version_requirements: *id006
|
97
113
|
- !ruby/object:Gem::Dependency
|
98
114
|
name: yard
|
99
115
|
prerelease: false
|
100
|
-
requirement: &
|
116
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
101
117
|
none: false
|
102
118
|
requirements:
|
103
119
|
- - ~>
|
@@ -109,11 +125,11 @@ dependencies:
|
|
109
125
|
- 2
|
110
126
|
version: 0.7.2
|
111
127
|
type: :development
|
112
|
-
version_requirements: *
|
128
|
+
version_requirements: *id007
|
113
129
|
- !ruby/object:Gem::Dependency
|
114
130
|
name: kramdown
|
115
131
|
prerelease: false
|
116
|
-
requirement: &
|
132
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
117
133
|
none: false
|
118
134
|
requirements:
|
119
135
|
- - ~>
|
@@ -125,7 +141,24 @@ dependencies:
|
|
125
141
|
- 3
|
126
142
|
version: 0.13.3
|
127
143
|
type: :development
|
128
|
-
version_requirements: *
|
144
|
+
version_requirements: *id008
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: pry
|
147
|
+
prerelease: false
|
148
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ~>
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
hash: 27
|
154
|
+
segments:
|
155
|
+
- 0
|
156
|
+
- 9
|
157
|
+
- 6
|
158
|
+
- 2
|
159
|
+
version: 0.9.6.2
|
160
|
+
type: :development
|
161
|
+
version_requirements: *id009
|
129
162
|
description: Guard::Jasmine automatically tests your Jasmine specs on PhantomJS
|
130
163
|
email:
|
131
164
|
- michi@netzpiraten.ch
|
@@ -149,8 +182,7 @@ files:
|
|
149
182
|
- lib/guard/jasmine/version.rbc
|
150
183
|
- lib/guard/jasmine.rb
|
151
184
|
- lib/guard/jasmine.rbc
|
152
|
-
- LICENSE
|
153
|
-
- LICENSE.BSD
|
185
|
+
- LICENSE
|
154
186
|
- README.md
|
155
187
|
homepage: http://github.com/netzpirat/guard-jasmine
|
156
188
|
licenses: []
|
data/LICENSE.BSD
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
Redistribution and use in source and binary forms, with or without
|
2
|
-
modification, are permitted provided that the following conditions are met:
|
3
|
-
|
4
|
-
* Redistributions of source code must retain the above copyright
|
5
|
-
notice, this list of conditions and the following disclaimer.
|
6
|
-
* Redistributions in binary form must reproduce the above copyright
|
7
|
-
notice, this list of conditions and the following disclaimer in the
|
8
|
-
documentation and/or other materials provided with the distribution.
|
9
|
-
* Neither the name of the <organization> nor the
|
10
|
-
names of its contributors may be used to endorse or promote products
|
11
|
-
derived from this software without specific prior written permission.
|
12
|
-
|
13
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
14
|
-
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
15
|
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
16
|
-
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
17
|
-
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
-
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
-
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
-
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
-
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
22
|
-
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|