guard-jasmine 0.6.2 → 0.7.0
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/{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.
|