guard-jasmine 1.19.2 → 2.0.0beta1
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.
- checksums.yaml +4 -4
- data/README.md +31 -234
- data/lib/generators/guard_jasmine/install_generator.rb +17 -0
- data/lib/generators/guard_jasmine/templates/Guardfile +9 -0
- data/lib/guard/jasmine.rb +18 -15
- data/lib/guard/jasmine/cli.rb +5 -5
- data/lib/guard/jasmine/formatter.rb +10 -0
- data/lib/guard/jasmine/inspector.rb +1 -2
- data/lib/guard/jasmine/phantomjs/guard-jasmine.js +54 -180
- data/lib/guard/jasmine/phantomjs/guard-reporter.js +187 -0
- data/lib/guard/jasmine/phantomjs/src/guard-jasmine.coffee +101 -0
- data/lib/guard/jasmine/phantomjs/src/guard-reporter.coffee +109 -0
- data/lib/guard/jasmine/phantomjs/test/guard-reporter_spec.coffee +41 -0
- data/lib/guard/jasmine/runner.rb +178 -268
- data/lib/guard/jasmine/server.rb +17 -3
- data/lib/guard/jasmine/util.rb +1 -7
- data/lib/guard/jasmine/version.rb +1 -1
- metadata +135 -26
- data/lib/guard/jasmine/phantomjs/guard-jasmine.coffee +0 -193
- data/lib/guard/jasmine/phantomjs/lib/console.js +0 -188
- data/lib/guard/jasmine/phantomjs/lib/junit_reporter.js +0 -224
- data/lib/guard/jasmine/phantomjs/lib/reporter.js +0 -144
- data/lib/guard/jasmine/phantomjs/lib/result.js +0 -155
- data/lib/guard/jasmine/phantomjs/src/console.coffee +0 -149
- data/lib/guard/jasmine/phantomjs/src/reporter.coffee +0 -139
- data/lib/guard/jasmine/phantomjs/src/result.coffee +0 -95
- data/lib/guard/jasmine/phantomjs/test/console_spec.coffee +0 -125
- data/lib/guard/jasmine/phantomjs/test/reporter_spec.coffee +0 -0
- data/lib/guard/jasmine/phantomjs/test/result_spec.coffee +0 -311
@@ -0,0 +1,101 @@
|
|
1
|
+
|
2
|
+
# Set default values
|
3
|
+
options =
|
4
|
+
url: phantom.args[0] || 'http://127.0.0.1:3000/jasmine'
|
5
|
+
timeout: parseInt(phantom.args[1] || 10000)
|
6
|
+
|
7
|
+
# Create the web page.
|
8
|
+
page = require('webpage').create()
|
9
|
+
|
10
|
+
# Catch JavaScript errors
|
11
|
+
# abort the request and return the error
|
12
|
+
page.onError = (message, trace) ->
|
13
|
+
reportError "Javascript error encountered on Jasmine test page: #{ message }", trace
|
14
|
+
|
15
|
+
# Once the page is initialized, setup the script for
|
16
|
+
# the GuardReporter class
|
17
|
+
page.onInitialized = ->
|
18
|
+
page.injectJs 'guard-reporter.js'
|
19
|
+
page.evaluate ->
|
20
|
+
window.onload = ->
|
21
|
+
window.reporter = new GuardReporter()
|
22
|
+
window.jasmine.getEnv().addReporter(window.reporter) if window.jasmine
|
23
|
+
|
24
|
+
# Once the page is finished loading
|
25
|
+
page.onLoadFinished = (status)->
|
26
|
+
if status isnt 'success'
|
27
|
+
reportError "Unable to access Jasmine specs at #{ options.url }, page returned status: #{status}"
|
28
|
+
else
|
29
|
+
waitFor reporterReady, jasmineAvailable, options.timeout, reporterMissing
|
30
|
+
|
31
|
+
# Open web page, which will kick off the Jasmine test runner
|
32
|
+
page.open options.url
|
33
|
+
|
34
|
+
# Test if Jasmine and guard has been loaded
|
35
|
+
reporterReady = ->
|
36
|
+
page.evaluate ->
|
37
|
+
window.jasmine && window.reporter
|
38
|
+
|
39
|
+
# Start specs after they are have been loaded
|
40
|
+
jasmineAvailable = ->
|
41
|
+
waitFor specsDone, exitSuccessfully, options.timeout, specsTimedout
|
42
|
+
|
43
|
+
# Error message for when jasmine never loaded asynchronously
|
44
|
+
reporterMissing = ->
|
45
|
+
text = page.evaluate -> document.getElementsByTagName('body')[0]?.innerText
|
46
|
+
reportError """
|
47
|
+
The reporter is not available!
|
48
|
+
Perhaps the url ( #{ options.url } ) is incorrect?
|
49
|
+
|
50
|
+
#{ text }
|
51
|
+
"""
|
52
|
+
|
53
|
+
# tests if the resultComplete flag is set on the reporter
|
54
|
+
specsDone = ->
|
55
|
+
result = page.evaluate ->
|
56
|
+
window.reporter.resultComplete
|
57
|
+
|
58
|
+
# We should end up here. Logs the results as JSON and exits
|
59
|
+
exitSuccessfully = ->
|
60
|
+
results = page.evaluate -> window.reporter.results()
|
61
|
+
console.log JSON.stringify( results )
|
62
|
+
phantom.exit()
|
63
|
+
|
64
|
+
|
65
|
+
# Error message for when specs time out
|
66
|
+
specsTimedout = ->
|
67
|
+
text = page.evaluate -> document.getElementsByTagName('body')[0]?.innerText
|
68
|
+
reportError """
|
69
|
+
Timeout waiting for the Jasmine test results!
|
70
|
+
|
71
|
+
#{ text }
|
72
|
+
"""
|
73
|
+
|
74
|
+
# Wait until the test condition is true or a timeout occurs.
|
75
|
+
#
|
76
|
+
# @param [Function] test the test that returns true if condition is met
|
77
|
+
# @param [Function] ready the action when the condition is fulfilled
|
78
|
+
# @param [Number] timeout the max amount of time to wait in milliseconds
|
79
|
+
#
|
80
|
+
waitFor = (test, ready, timeout = 10000, timeoutFunction)->
|
81
|
+
condition = false
|
82
|
+
interval = undefined
|
83
|
+
start = Date.now(0)
|
84
|
+
wait = ->
|
85
|
+
if !condition && (Date.now() - start < timeout)
|
86
|
+
condition = test()
|
87
|
+
else
|
88
|
+
clearInterval interval
|
89
|
+
if condition
|
90
|
+
ready()
|
91
|
+
else
|
92
|
+
timeoutFunction()
|
93
|
+
interval = setInterval( wait, 250 )
|
94
|
+
|
95
|
+
# Logs the error to the console as JSON and exits with status '1'
|
96
|
+
reportError = (msg, trace=[])->
|
97
|
+
if 0 == trace.length
|
98
|
+
err = new Error();
|
99
|
+
trace = err.stack
|
100
|
+
console.log JSON.stringify({ error: msg, trace: trace })
|
101
|
+
phantom.exit(1)
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# Capture statements that were logged to the console
|
2
|
+
# during spec execution.
|
3
|
+
#
|
4
|
+
# To do so it substitues it's own functions for the console.<levels>
|
5
|
+
#
|
6
|
+
extendObject = (a, b)->
|
7
|
+
for key,value of b
|
8
|
+
a[key] = value if b.hasOwnProperty(key)
|
9
|
+
return a
|
10
|
+
|
11
|
+
|
12
|
+
class ConsoleCapture
|
13
|
+
# Instead of attempting to de-activate the console dot reporter in hacky ways,
|
14
|
+
# just ignore it's output
|
15
|
+
@DOT_REPORTER_MATCH = /\[\d+m[F.]..0m/
|
16
|
+
@levels: ['log','info','warn','error','debug' ]
|
17
|
+
@original = console
|
18
|
+
|
19
|
+
@original_levels = {}
|
20
|
+
@original_levels[level] = console[level] for level in ConsoleCapture.levels
|
21
|
+
|
22
|
+
constructor:->
|
23
|
+
@original = {}
|
24
|
+
@captured = []
|
25
|
+
this._reassign_level( level ) for level in ConsoleCapture.levels
|
26
|
+
|
27
|
+
revert: ->
|
28
|
+
for level in ConsoleCapture.levels
|
29
|
+
ConsoleCapture.original[level] = ConsoleCapture.original_levels[level]
|
30
|
+
|
31
|
+
_reassign_level: ( level )->
|
32
|
+
my = this
|
33
|
+
console[level] = ->
|
34
|
+
args = Array.prototype.slice.call(arguments, 0)
|
35
|
+
return if args[0] && args[0].toString && args[0].toString().match( ConsoleCapture.DOT_REPORTER_MATCH )
|
36
|
+
my.captured.push( [ level ].concat( args ) )
|
37
|
+
ConsoleCapture.original_levels[ level ].apply( ConsoleCapture.original, arguments )
|
38
|
+
|
39
|
+
|
40
|
+
# Implements a Jasmine reporter
|
41
|
+
class GuardReporter
|
42
|
+
@STACK_MATCHER=new RegExp("__spec__\/(.*):([0-9]+)","g")
|
43
|
+
|
44
|
+
jasmineStarted: ->
|
45
|
+
@console = new ConsoleCapture();
|
46
|
+
@startedAt = Date.now()
|
47
|
+
@currentSuite = { suites: [] }
|
48
|
+
@stack = [ @currentSuite ]
|
49
|
+
|
50
|
+
suiteStarted: (suite)->
|
51
|
+
suite = extendObject({ specs: [], suites: [] }, suite )
|
52
|
+
@currentSuite.suites.push( suite )
|
53
|
+
@currentSuite = suite
|
54
|
+
@stack.push(suite)
|
55
|
+
|
56
|
+
suiteDone: (Suite)->
|
57
|
+
@stack.pop()
|
58
|
+
@currentSuite = @stack[@stack.length-1]
|
59
|
+
|
60
|
+
jasmineDone: ->
|
61
|
+
@resultComplete = true
|
62
|
+
|
63
|
+
specDone: (spec)->
|
64
|
+
@resultReceived = true
|
65
|
+
spec = extendObject({ logs: @console.captured, errors: [] }, spec )
|
66
|
+
for failure in spec.failedExpectations
|
67
|
+
error = extendObject({trace:[]}, failure )
|
68
|
+
while match = GuardReporter.STACK_MATCHER.exec( failure.stack )
|
69
|
+
error.trace.push({ file: match[1], line: parseInt(match[2]) })
|
70
|
+
delete error.stack
|
71
|
+
spec.errors.push( error )
|
72
|
+
delete spec.failedExpectations
|
73
|
+
@currentSuite.specs.push( spec )
|
74
|
+
|
75
|
+
this.resetConsoleLog()
|
76
|
+
spec
|
77
|
+
|
78
|
+
resetConsoleLog: ->
|
79
|
+
@console.revert()
|
80
|
+
@console = new ConsoleCapture
|
81
|
+
|
82
|
+
eachSuite: (suite)->
|
83
|
+
suites = [].concat( suite.suites )
|
84
|
+
for suite in suite.suites
|
85
|
+
suites = suites.concat( this.eachSuite(suite) )
|
86
|
+
suites
|
87
|
+
|
88
|
+
results: ->
|
89
|
+
stats = {
|
90
|
+
time : ( Date.now() - @startedAt ) / 1000
|
91
|
+
specs : 0
|
92
|
+
failed : 0
|
93
|
+
pending : 0
|
94
|
+
disabled : 0
|
95
|
+
}
|
96
|
+
for suite in this.eachSuite(@stack[0])
|
97
|
+
stats.specs += suite.specs.length
|
98
|
+
for spec in suite.specs
|
99
|
+
stats[spec.status] += 1 unless undefined == stats[spec.status]
|
100
|
+
{
|
101
|
+
jasmine_version: jasmine?.version
|
102
|
+
stats: stats
|
103
|
+
suites: @stack[0].suites
|
104
|
+
}
|
105
|
+
|
106
|
+
if typeof module isnt 'undefined' and module.exports
|
107
|
+
module.exports = GuardReporter
|
108
|
+
else
|
109
|
+
window.GuardReporter = GuardReporter
|
@@ -0,0 +1,41 @@
|
|
1
|
+
sinon = require 'sinon'
|
2
|
+
{expect} = require 'chai'
|
3
|
+
|
4
|
+
GuardReporter = require '../src/guard-reporter'
|
5
|
+
|
6
|
+
describe 'Reporter', ->
|
7
|
+
beforeEach ->
|
8
|
+
@reporter = new GuardReporter
|
9
|
+
@reporter.jasmineStarted()
|
10
|
+
|
11
|
+
it 'captures the console', ->
|
12
|
+
@reporter.suiteStarted({name:'Blank'})
|
13
|
+
console.log("A %s Logging", "Test")
|
14
|
+
console.warn("This is your last warning")
|
15
|
+
@reporter.specDone( { failedExpectations: [] } )
|
16
|
+
expect( @reporter.results() )
|
17
|
+
.to.have.deep.property('.suites[0].specs[0].logs')
|
18
|
+
.and.equal([
|
19
|
+
[ 'log', 'A %s Logging', "Test" ],
|
20
|
+
[ 'warn', 'This is your last warning' ]
|
21
|
+
])
|
22
|
+
|
23
|
+
it "reports counts", ->
|
24
|
+
@reporter.suiteStarted({name:'Blank'})
|
25
|
+
console.log("A %s Logging", "Test")
|
26
|
+
console.warn("This is your last warning")
|
27
|
+
@reporter.specDone( { status: 'passed', failedExpectations: [] } )
|
28
|
+
@reporter.specDone( { status: 'failed', failedExpectations: [{
|
29
|
+
matcherName:"toEqual",
|
30
|
+
message: "Expected 2 to equal 5"
|
31
|
+
}] })
|
32
|
+
@reporter.specDone( { status: 'passed', failedExpectations: [] } )
|
33
|
+
@reporter.specDone( { status: 'pending', failedExpectations: [] } )
|
34
|
+
results = @reporter.results()
|
35
|
+
expect( results ).to.have.property('stats')
|
36
|
+
expect( results.stats )
|
37
|
+
.to.have.property('specs').and.equal(4)
|
38
|
+
expect( results.stats )
|
39
|
+
.to.have.property('failed').and.equal(1)
|
40
|
+
expect( results.stats )
|
41
|
+
.to.have.property('pending').and.equal(1)
|
data/lib/guard/jasmine/runner.rb
CHANGED
@@ -11,53 +11,68 @@ module Guard
|
|
11
11
|
# evaluates the JSON response from the PhantomJS Script `guard_jasmine.coffee`,
|
12
12
|
# writes the result to the console and triggers optional system notifications.
|
13
13
|
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
14
|
+
class Runner
|
15
|
+
include ::Guard::Jasmine::Util
|
16
|
+
|
17
|
+
attr_reader :options
|
18
|
+
|
19
|
+
# Name of the coverage threshold options
|
20
|
+
THRESHOLDS = [:statements_threshold, :functions_threshold, :branches_threshold, :lines_threshold]
|
21
|
+
|
22
|
+
# Run the supplied specs.
|
23
|
+
#
|
24
|
+
# @param [Hash] options the options for the execution
|
25
|
+
# @option options [String] :jasmine_url the url of the Jasmine test runner
|
26
|
+
# @option options [String] :phantomjs_bin the location of the PhantomJS binary
|
27
|
+
# @option options [Integer] :timeout the maximum time in seconds to wait for the spec runner to finish
|
28
|
+
# @option options [String] :rackup_config custom rackup config to use
|
29
|
+
# @option options [Boolean] :notification show notifications
|
30
|
+
# @option options [Boolean] :hide_success hide success message notification
|
31
|
+
# @option options [Integer] :max_error_notify maximum error notifications to show
|
32
|
+
# @option options [Symbol] :specdoc options for the specdoc output, either :always, :never
|
33
|
+
# @option options [Symbol] :console options for the console.log output, either :always, :never or :failure
|
34
|
+
# @option options [String] :spec_dir the directory with the Jasmine specs
|
35
|
+
# @option options [Hash] :query_params Parameters to pass along with the request
|
36
|
+
# @option options [Boolean] :debug display raw JSON output from the runner
|
37
|
+
#
|
38
|
+
def initialize(options)
|
39
|
+
@options = options
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
+
# @param [Array<String>] paths the spec files or directories
|
43
|
+
# @return [Hash<String,Array>] keys for the spec_file, value is array of failure messages.
|
44
|
+
# Only specs with failures will be returned. Therefore an empty? return hash indicates success.
|
45
|
+
def run(paths, per_run_options = {})
|
46
|
+
previous_options = @options
|
47
|
+
@options.merge!( per_run_options )
|
42
48
|
|
43
|
-
|
44
|
-
results << evaluate_response(run_jasmine_spec(file, options), file, options) if File.exist?(file_and_line_number_parts(file)[0])
|
49
|
+
return {} if paths.empty?
|
45
50
|
|
46
|
-
|
47
|
-
end.compact
|
51
|
+
notify_start_message(paths)
|
48
52
|
|
49
|
-
|
53
|
+
run_results = paths.each_with_object({}) do |file, results|
|
54
|
+
if File.exist?(file_and_line_number_parts(file)[0])
|
55
|
+
results[file] = evaluate_response(run_jasmine_spec(file), file)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
# return the errors
|
59
|
+
return run_results.each_with_object({}) do | spec_run, hash |
|
60
|
+
file, r = spec_run
|
61
|
+
errors = collect_spec_errors(r['suites']||[])
|
62
|
+
errors.push( r['error'] ) if r.has_key? 'error'
|
63
|
+
hash[file] = errors unless errors.empty?
|
50
64
|
end
|
65
|
+
ensure
|
66
|
+
@options=previous_options
|
67
|
+
end
|
51
68
|
|
52
|
-
|
69
|
+
private
|
53
70
|
|
54
|
-
|
55
|
-
|
71
|
+
# Shows a notification in the console that the runner starts.
|
72
|
+
#
|
56
73
|
# @param [Array<String>] paths the spec files or directories
|
57
|
-
# @param [Hash] options the options for the execution
|
58
|
-
# @option options [String] :spec_dir the directory with the Jasmine specs
|
59
74
|
#
|
60
|
-
def notify_start_message(paths
|
75
|
+
def notify_start_message(paths)
|
61
76
|
message = if paths == [options[:spec_dir]]
|
62
77
|
'Run all Jasmine suites'
|
63
78
|
else
|
@@ -67,33 +82,12 @@ module Guard
|
|
67
82
|
Formatter.info(message, reset: true)
|
68
83
|
end
|
69
84
|
|
70
|
-
# Returns the failed spec file names.
|
71
|
-
#
|
72
|
-
# @param [Array<Object>] results the spec runner results
|
73
|
-
# @return [Array<String>] the list of failed spec files
|
74
|
-
#
|
75
|
-
def failed_paths_from(results)
|
76
|
-
results.map { |r| !r['passed'] ? r['file'] : nil }.compact
|
77
|
-
end
|
78
|
-
|
79
|
-
# Returns the response status for the given result set.
|
80
|
-
#
|
81
|
-
# @param [Array<Object>] results the spec runner results
|
82
|
-
# @return [Boolean] whether it has passed or not
|
83
|
-
#
|
84
|
-
def response_status_for(results)
|
85
|
-
results.none? { |r| r.has_key?('error') || !r['passed'] }
|
86
|
-
end
|
87
|
-
|
88
85
|
# Run the Jasmine spec by executing the PhantomJS script.
|
89
86
|
#
|
90
87
|
# @param [String] file the path of the spec
|
91
|
-
# @param [Hash] options the options for the execution
|
92
|
-
# @option options [Integer] :timeout the maximum time in seconds to wait for the spec runner to finish
|
93
88
|
#
|
94
|
-
def run_jasmine_spec(file
|
95
|
-
suite = jasmine_suite(file
|
96
|
-
Formatter.info("Run Jasmine suite at #{ suite }")
|
89
|
+
def run_jasmine_spec(file)
|
90
|
+
suite = jasmine_suite(file)
|
97
91
|
|
98
92
|
arguments = [
|
99
93
|
options[:timeout] * 1000,
|
@@ -105,30 +99,27 @@ module Guard
|
|
105
99
|
options[:junit_consolidate],
|
106
100
|
"'#{ options[:junit_save_path] }'"
|
107
101
|
]
|
108
|
-
|
109
|
-
IO.popen(
|
102
|
+
cmd = "#{ phantomjs_command } \"#{ suite }\" #{ arguments.collect { |i| i.to_s }.join(' ')}"
|
103
|
+
IO.popen(cmd, 'r:UTF-8')
|
110
104
|
end
|
111
105
|
|
112
106
|
# Get the PhantomJS binary and script to execute.
|
113
107
|
#
|
114
|
-
# @param [Hash] options the options for the execution
|
115
|
-
# @option options [String] :phantomjs_bin the location of the PhantomJS binary
|
116
108
|
# @return [String] the command
|
117
109
|
#
|
118
|
-
def phantomjs_command
|
110
|
+
def phantomjs_command
|
119
111
|
options[:phantomjs_bin] + ' ' + phantomjs_script
|
112
|
+
#options[:phantomjs_bin] + ' --remote-debugger-port=9000 ' + phantomjs_script
|
120
113
|
end
|
121
114
|
|
122
115
|
# Get the Jasmine test runner URL with the appended suite name
|
123
116
|
# that acts as the spec filter.
|
124
117
|
#
|
125
118
|
# @param [String] file the spec file
|
126
|
-
# @param [Hash] options the options for the execution
|
127
|
-
# @option options [String] :jasmine_url the url of the Jasmine test runner
|
128
119
|
# @return [String] the Jasmine url
|
129
120
|
#
|
130
|
-
def jasmine_suite(file
|
131
|
-
options[:jasmine_url] + query_string_for_suite(file
|
121
|
+
def jasmine_suite(file)
|
122
|
+
options[:jasmine_url] + query_string_for_suite(file)
|
132
123
|
end
|
133
124
|
|
134
125
|
# Get the PhantomJS script that executes the spec and extracts
|
@@ -144,22 +135,17 @@ module Guard
|
|
144
135
|
# will be run.
|
145
136
|
#
|
146
137
|
# @param [String] file the spec file
|
147
|
-
# @param [Hash] options the options for the execution
|
148
|
-
# @option options [String] :spec_dir the directory with the Jasmine specs
|
149
138
|
# @return [String] the suite name
|
150
139
|
#
|
151
|
-
def query_string_for_suite(file
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
unless query_string
|
157
|
-
query_string = query_string_for_suite_from_first_describe(file, options)
|
140
|
+
def query_string_for_suite(file)
|
141
|
+
params = {}
|
142
|
+
if options[:query_params]
|
143
|
+
params.merge!(options[:query_params])
|
158
144
|
end
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
URI.
|
145
|
+
if file != options[:spec_dir]
|
146
|
+
params[:spec] = suite_from_line_number(file) || suite_from_first_describe(file)
|
147
|
+
end
|
148
|
+
params.empty? ? "" : "?"+URI.encode_www_form(params)
|
163
149
|
end
|
164
150
|
|
165
151
|
# When providing a line number by either the option or by
|
@@ -167,11 +153,9 @@ module Guard
|
|
167
153
|
# fromt the corresponding line number in the file.
|
168
154
|
#
|
169
155
|
# @param [String] file the spec file
|
170
|
-
# @param [Hash] options the options for the execution
|
171
|
-
# @option options [Fixnum] :line_number the line number to run
|
172
156
|
# @return [String] the suite name
|
173
157
|
#
|
174
|
-
def
|
158
|
+
def suite_from_line_number(file)
|
175
159
|
file_name, line_number = file_and_line_number_parts(file)
|
176
160
|
line_number ||= options[:line_number]
|
177
161
|
|
@@ -196,12 +180,11 @@ module Guard
|
|
196
180
|
# found.
|
197
181
|
#
|
198
182
|
# @param [String] file the spec file
|
199
|
-
# @param [Hash] options the options for the execution
|
200
183
|
# @return [String] the suite name
|
201
184
|
#
|
202
|
-
def
|
185
|
+
def suite_from_first_describe(file)
|
203
186
|
File.foreach(file) do |line|
|
204
|
-
if line =~ /describe\s*[("']+(.*?)["')]+/
|
187
|
+
if line =~ /describe\s*[("']+(.*?)["')]+/ #'
|
205
188
|
return $1
|
206
189
|
end
|
207
190
|
end
|
@@ -241,7 +224,7 @@ module Guard
|
|
241
224
|
# @return [String] the extracted title
|
242
225
|
#
|
243
226
|
def spec_title(line)
|
244
|
-
line[/['"](.+?)['
|
227
|
+
line[/['"](.+?)["']/, 1]
|
245
228
|
end
|
246
229
|
|
247
230
|
# Evaluates the JSON response that the PhantomJS script
|
@@ -250,33 +233,31 @@ module Guard
|
|
250
233
|
#
|
251
234
|
# @param [String] output the JSON output the spec run
|
252
235
|
# @param [String] file the file name of the spec
|
253
|
-
# @
|
254
|
-
# @return [Hash] the suite result
|
236
|
+
# @return [Hash] results of the suite's specs
|
255
237
|
#
|
256
|
-
def evaluate_response(output, file
|
238
|
+
def evaluate_response(output, file)
|
257
239
|
json = output.read
|
258
240
|
json = json.encode('UTF-8') if json.respond_to?(:encode)
|
259
|
-
|
260
241
|
begin
|
261
242
|
result = MultiJson.decode(json, { max_nesting: false })
|
262
243
|
raise 'No response from Jasmine runner' if !result && options[:is_cli]
|
263
|
-
|
244
|
+
pp result if options[:debug]
|
264
245
|
if result['error']
|
265
246
|
if options[:is_cli]
|
266
247
|
raise 'An error occurred in the Jasmine runner'
|
267
248
|
else
|
268
|
-
notify_runtime_error(result
|
249
|
+
notify_runtime_error(result)
|
269
250
|
end
|
270
251
|
elsif result
|
271
252
|
result['file'] = file
|
272
|
-
notify_spec_result(result
|
253
|
+
notify_spec_result(result)
|
273
254
|
end
|
274
255
|
|
275
256
|
if result && result['coverage'] && options[:coverage]
|
276
|
-
notify_coverage_result(result['coverage'], file
|
257
|
+
notify_coverage_result(result['coverage'], file)
|
277
258
|
end
|
278
259
|
|
279
|
-
result
|
260
|
+
return result
|
280
261
|
|
281
262
|
rescue MultiJson::DecodeError => e
|
282
263
|
if e.data == ''
|
@@ -287,10 +268,11 @@ module Guard
|
|
287
268
|
end
|
288
269
|
else
|
289
270
|
if options[:is_cli]
|
290
|
-
raise
|
271
|
+
raise "Cannot decode JSON from PhantomJS runner, message received was:\n#{json}"
|
291
272
|
else
|
292
273
|
Formatter.error("Cannot decode JSON from PhantomJS runner: #{ e.message }")
|
293
274
|
Formatter.error("JSON response: #{ e.data }")
|
275
|
+
Formatter.error("message received was:\n#{json}")
|
294
276
|
end
|
295
277
|
end
|
296
278
|
ensure
|
@@ -302,12 +284,11 @@ module Guard
|
|
302
284
|
# prohibits the execution of the Jasmine spec.
|
303
285
|
#
|
304
286
|
# @param [Hash] result the suite result
|
305
|
-
# @param [Hash] options the options for the execution
|
306
|
-
# @option options [Boolean] :notification show notifications
|
307
287
|
#
|
308
|
-
def notify_runtime_error(result
|
288
|
+
def notify_runtime_error(result)
|
309
289
|
message = "An error occurred: #{ result['error'] }"
|
310
|
-
Formatter.error(message)
|
290
|
+
Formatter.error(message )
|
291
|
+
Formatter.error( result['trace'] ) if result['trace']
|
311
292
|
Formatter.notify(message, title: 'Jasmine error', image: :failed, priority: 2) if options[:notification]
|
312
293
|
end
|
313
294
|
|
@@ -315,62 +296,59 @@ module Guard
|
|
315
296
|
# and some stats.
|
316
297
|
#
|
317
298
|
# @param [Hash] result the suite result
|
318
|
-
# @param [Hash] options the options for the execution
|
319
|
-
# @option options [Boolean] :notification show notifications
|
320
|
-
# @option options [Boolean] :hide_success hide success message notification
|
321
299
|
#
|
322
|
-
def notify_spec_result(result
|
323
|
-
specs
|
324
|
-
|
325
|
-
time
|
326
|
-
specs_plural
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
message = "#{ specs } spec#{ specs_plural }, #{ failures } failure#{ failures_plural }"
|
300
|
+
def notify_spec_result(result)
|
301
|
+
specs = result['stats']['specs'] - result['stats']['disabled']
|
302
|
+
failed = result['stats']['failed']
|
303
|
+
time = sprintf( '%0.2f', result['stats']['time'] )
|
304
|
+
specs_plural = specs == 1 ? '' : 's'
|
305
|
+
failed_plural = failed == 1 ? '' : 's'
|
306
|
+
Formatter.info("Finished in #{ time } seconds")
|
307
|
+
pending = result['stats']['pending'].to_i > 0 ? " #{result['stats']['pending']} pending," : ""
|
308
|
+
message = "#{ specs } spec#{ specs_plural },#{pending} #{ failed } failure#{ failed_plural }"
|
332
309
|
full_message = "#{ message }\nin #{ time } seconds"
|
333
|
-
passed =
|
310
|
+
passed = failed == 0
|
311
|
+
|
312
|
+
report_specdoc(result, passed) if specdoc_shown?(passed)
|
334
313
|
|
335
314
|
if passed
|
336
|
-
report_specdoc(result, passed, options)
|
337
315
|
Formatter.success(message)
|
338
316
|
Formatter.notify(full_message, title: 'Jasmine suite passed') if options[:notification] && !options[:hide_success]
|
339
317
|
else
|
340
|
-
|
318
|
+
errors = collect_spec_errors(result['suites'])
|
319
|
+
error_message = errors[0..options[:max_error_notify]].join("\n")
|
320
|
+
|
341
321
|
Formatter.error(message)
|
342
|
-
|
343
|
-
|
322
|
+
if options[:notification]
|
323
|
+
Formatter.notify( "#{error_message}\n#{full_message}",
|
324
|
+
title: 'Jasmine suite failed', image: :failed, priority: 2)
|
325
|
+
end
|
344
326
|
end
|
345
327
|
|
346
|
-
Formatter.info("Done.\n")
|
347
328
|
end
|
348
329
|
|
349
|
-
# Notification about the coverage of a spec run, success or
|
330
|
+
# Notification about the coverage of a spec run, success or failed,
|
350
331
|
# and some stats.
|
351
332
|
#
|
352
333
|
# @param [Hash] coverage the coverage hash from the JSON
|
353
334
|
# @param [String] file the file name of the spec
|
354
|
-
# @param [Hash] options the options for the execution
|
355
|
-
# @option options [Boolean] :notification show notifications
|
356
|
-
# @option options [Boolean] :hide_success hide success message notification
|
357
335
|
#
|
358
|
-
def notify_coverage_result(coverage, file
|
336
|
+
def notify_coverage_result(coverage, file)
|
359
337
|
if coverage_bin
|
360
338
|
FileUtils.mkdir_p(coverage_root) unless File.exist?(coverage_root)
|
361
339
|
|
362
|
-
update_coverage(coverage, file
|
340
|
+
update_coverage(coverage, file)
|
363
341
|
|
364
342
|
if options[:coverage_summary]
|
365
343
|
generate_summary_report
|
366
344
|
else
|
367
|
-
generate_text_report(file
|
345
|
+
generate_text_report(file)
|
368
346
|
end
|
369
347
|
|
370
|
-
check_coverage
|
348
|
+
check_coverage
|
371
349
|
|
372
350
|
if options[:coverage_html]
|
373
|
-
generate_html_report
|
351
|
+
generate_html_report
|
374
352
|
end
|
375
353
|
else
|
376
354
|
Formatter.error('Skipping coverage report: unable to locate istanbul in your PATH')
|
@@ -381,9 +359,8 @@ module Guard
|
|
381
359
|
# last coverage run.
|
382
360
|
#
|
383
361
|
# @param [String] file the file name of the spec
|
384
|
-
# @param [Hash] options the options for the execution
|
385
362
|
#
|
386
|
-
def generate_text_report(file
|
363
|
+
def generate_text_report(file)
|
387
364
|
Formatter.info 'Spec coverage details:'
|
388
365
|
|
389
366
|
if file == options[:spec_dir]
|
@@ -405,11 +382,9 @@ module Guard
|
|
405
382
|
# Uses the Istanbul text reported to output the result of the
|
406
383
|
# last coverage run.
|
407
384
|
#
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
if any_coverage_threshold?(options)
|
412
|
-
coverage = `#{coverage_bin} check-coverage #{ istanbul_coverage_options(options) } #{ coverage_file } 2>&1`
|
385
|
+
def check_coverage
|
386
|
+
if any_coverage_threshold?
|
387
|
+
coverage = `#{coverage_bin} check-coverage #{ istanbul_coverage_options } #{ coverage_file } 2>&1`
|
413
388
|
coverage = coverage.split("\n").grep(/ERROR/).join.sub('ERROR:', '')
|
414
389
|
failed = $? && $?.exitstatus != 0
|
415
390
|
|
@@ -426,10 +401,8 @@ module Guard
|
|
426
401
|
# Uses the Istanbul text reported to output the result of the
|
427
402
|
# last coverage run.
|
428
403
|
#
|
429
|
-
|
430
|
-
|
431
|
-
def generate_html_report(options)
|
432
|
-
report_directory = coverage_report_directory(options)
|
404
|
+
def generate_html_report
|
405
|
+
report_directory = coverage_report_directory
|
433
406
|
`#{coverage_bin} report --dir #{ report_directory } --root #{ coverage_root } html #{ coverage_file }`
|
434
407
|
Formatter.info "Updated HTML report available at: #{ report_directory }/index.html"
|
435
408
|
end
|
@@ -453,12 +426,10 @@ module Guard
|
|
453
426
|
#
|
454
427
|
# @param [Hash] result the suite result
|
455
428
|
# @param [Boolean] passed status
|
456
|
-
# @param [Hash] options the options
|
457
|
-
# @option options [Symbol] :console options for the console.log output, either :always, :never or :failure
|
458
429
|
#
|
459
|
-
def report_specdoc(result, passed
|
430
|
+
def report_specdoc(result, passed)
|
460
431
|
result['suites'].each do |suite|
|
461
|
-
report_specdoc_suite(suite, passed
|
432
|
+
report_specdoc_suite(suite, passed)
|
462
433
|
end
|
463
434
|
end
|
464
435
|
|
@@ -466,128 +437,78 @@ module Guard
|
|
466
437
|
#
|
467
438
|
# @param [Hash] suite the suite
|
468
439
|
# @param [Boolean] passed status
|
469
|
-
# @param [Hash] options the options
|
470
|
-
# @option options [Symbol] :console options for the console.log output, either :always, :never or :failure
|
471
|
-
# @option options [Symbol] :focus options for focus on failures in the specdoc
|
472
440
|
# @param [Number] level the indention level
|
473
441
|
#
|
474
|
-
def report_specdoc_suite(suite,
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
end
|
442
|
+
def report_specdoc_suite(suite, run_passed, level = 0)
|
443
|
+
|
444
|
+
# Print the suite description when the specdoc is shown or there are logs to display
|
445
|
+
Formatter.suite_name((' ' * level) + suite['description'])
|
479
446
|
|
480
447
|
suite['specs'].each do |spec|
|
481
|
-
if
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
448
|
+
# Specs are shown if they failed, or if they passed and the "focus" option is falsey
|
449
|
+
# If specs are going to be shown, then pending are also shown
|
450
|
+
# If the focus option is set, then only failing tests are shown
|
451
|
+
next unless :always==options[:specdoc] || spec['status'] == 'failed' || ( !run_passed && !options[:focus] )
|
452
|
+
if spec['status'] == 'passed'
|
453
|
+
Formatter.success(indent(" ✔ #{ spec['description'] }", level))
|
454
|
+
elsif spec['status'] == 'failed'
|
455
|
+
Formatter.spec_failed(indent(" ✘ #{ spec['description'] }", level))
|
487
456
|
else
|
488
|
-
Formatter.
|
489
|
-
spec['messages'].each do |message|
|
490
|
-
Formatter.spec_failed(indent(" ➤ #{ format_message(message, false) }", level)) if specdoc_shown?(passed, options)
|
491
|
-
end
|
492
|
-
report_specdoc_errors(spec, options, level)
|
493
|
-
report_specdoc_logs(spec, options, level)
|
457
|
+
Formatter.spec_pending(indent(" ○ #{ spec['description'] }", level))
|
494
458
|
end
|
459
|
+
report_specdoc_errors(spec, level)
|
460
|
+
report_specdoc_logs(spec, level)
|
495
461
|
end
|
496
462
|
|
497
|
-
suite['suites'].each { |s| report_specdoc_suite(s,
|
463
|
+
suite['suites'].each { |s| report_specdoc_suite(s, run_passed, level + 2) } if suite['suites']
|
498
464
|
end
|
499
465
|
|
500
466
|
# Is the specdoc shown for this suite?
|
501
467
|
#
|
502
468
|
# @param [Boolean] passed the spec status
|
503
|
-
# @param [Hash] options the options
|
504
469
|
#
|
505
|
-
def specdoc_shown?(passed
|
470
|
+
def specdoc_shown?(passed)
|
506
471
|
options[:specdoc] == :always || (options[:specdoc] == :failure && !passed)
|
507
472
|
end
|
508
473
|
|
509
|
-
# Are console logs shown for this suite?
|
510
|
-
#
|
511
|
-
# @param [Hash] suite the suite
|
512
|
-
# @param [Boolean] passed the spec status
|
513
|
-
# @param [Hash] options the options
|
514
|
-
#
|
515
|
-
def console_logs_shown?(suite, passed, options = { })
|
516
|
-
# Are console messages displayed?
|
517
|
-
console_enabled = options[:console] == :always || (options[:console] == :failure && !passed)
|
518
|
-
|
519
|
-
# Are there any logs to display at all for this suite?
|
520
|
-
logs_for_current_options = suite['specs'].select do |spec|
|
521
|
-
spec['logs'] && (options[:console] == :always || (options[:console] == :failure && !spec['passed']))
|
522
|
-
end
|
523
|
-
|
524
|
-
any_logs_present = !logs_for_current_options.empty?
|
525
|
-
|
526
|
-
console_enabled && any_logs_present
|
527
|
-
end
|
528
474
|
|
529
475
|
# Are console logs shown for this spec?
|
530
476
|
#
|
531
477
|
# @param [Hash] spec the spec
|
532
|
-
# @param [Hash] options the options
|
533
478
|
#
|
534
|
-
def console_for_spec?(spec
|
535
|
-
spec['logs'] && ((spec['
|
536
|
-
(
|
479
|
+
def console_for_spec?(spec)
|
480
|
+
spec['logs'] && (( spec['status'] == 'passed' && options[:console] == :always) ||
|
481
|
+
(spec['status'] == 'failed' && options[:console] != :never) )
|
537
482
|
end
|
538
483
|
|
539
|
-
# Are error logs shown for this suite?
|
540
|
-
#
|
541
|
-
# @param [Hash] suite the suite
|
542
|
-
# @param [Boolean] passed the spec status
|
543
|
-
# @param [Hash] options the options
|
544
|
-
#
|
545
|
-
def error_logs_shown?(suite, passed, options = { })
|
546
|
-
# Are error messages displayed?
|
547
|
-
errors_enabled = options[:errors] == :always || (options[:errors] == :failure && !passed)
|
548
|
-
|
549
|
-
# Are there any errors to display at all for this suite?
|
550
|
-
errors_for_current_options = suite['specs'].select do |spec|
|
551
|
-
spec['errors'] && (options[:errors] == :always || (options[:errors] == :failure && !spec['passed']))
|
552
|
-
end
|
553
|
-
|
554
|
-
any_errors_present= !errors_for_current_options.empty?
|
555
|
-
|
556
|
-
errors_enabled && any_errors_present
|
557
|
-
end
|
558
484
|
|
559
485
|
# Are errors shown for this spec?
|
560
486
|
#
|
561
487
|
# @param [Hash] spec the spec
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
(!spec['passed'] && options[:errors] != :never))
|
488
|
+
def errors_for_spec?(spec)
|
489
|
+
spec['errors'] && ((spec['status']=='passed' && options[:errors] == :always) ||
|
490
|
+
(spec['status']=='failed' && options[:errors] != :never))
|
566
491
|
end
|
567
492
|
|
568
493
|
# Is the description shown for this spec?
|
569
494
|
#
|
570
495
|
# @param [Boolean] passed the spec status
|
571
496
|
# @param [Hash] spec the spec
|
572
|
-
# @param [Hash] options the options
|
573
497
|
#
|
574
|
-
def description_shown?(passed, spec
|
575
|
-
specdoc_shown?(passed
|
498
|
+
def description_shown?(passed, spec)
|
499
|
+
specdoc_shown?(passed) || console_for_spec?(spec) || errors_for_spec?(spec)
|
576
500
|
end
|
577
501
|
|
578
502
|
# Shows the logs for a given spec.
|
579
503
|
#
|
580
504
|
# @param [Hash] spec the spec result
|
581
|
-
# @param [Hash] options the options
|
582
|
-
# @option options [Symbol] :console options for the console.log output, either :always, :never or :failure
|
583
505
|
# @param [Number] level the indention level
|
584
506
|
#
|
585
|
-
def report_specdoc_logs(spec,
|
586
|
-
if
|
587
|
-
spec['logs'].each do |
|
588
|
-
log
|
589
|
-
|
590
|
-
end
|
507
|
+
def report_specdoc_logs(spec, level)
|
508
|
+
if console_for_spec?(spec)
|
509
|
+
spec['logs'].each do |log_level, message|
|
510
|
+
log_level = log_level == 'log' ? '' : "#{log_level.upcase}: "
|
511
|
+
Formatter.info(indent(" • #{log_level}#{ message }", level))
|
591
512
|
end
|
592
513
|
end
|
593
514
|
end
|
@@ -595,19 +516,16 @@ module Guard
|
|
595
516
|
# Shows the errors for a given spec.
|
596
517
|
#
|
597
518
|
# @param [Hash] spec the spec result
|
598
|
-
# @param [Hash] options the options
|
599
|
-
# @option options [Symbol] :errors options for the errors output, either :always, :never or :failure
|
600
519
|
# @param [Number] level the indention level
|
601
520
|
#
|
602
|
-
def report_specdoc_errors(spec,
|
603
|
-
if spec['errors'] && (options[:errors] == :always || (options[:errors] == :failure &&
|
521
|
+
def report_specdoc_errors(spec, level)
|
522
|
+
if spec['errors'] && (options[:errors] == :always || (options[:errors] == :failure && spec['status']=='failed'))
|
604
523
|
spec['errors'].each do |error|
|
524
|
+
Formatter.spec_failed(indent(" ➤ #{ format_error(error,true) }", level))
|
605
525
|
if error['trace']
|
606
526
|
error['trace'].each do |trace|
|
607
|
-
Formatter.spec_failed(indent(" ➜
|
527
|
+
Formatter.spec_failed(indent(" ➜ #{ trace['file'] } on line #{ trace['line'] }", level+2))
|
608
528
|
end
|
609
|
-
else
|
610
|
-
Formatter.spec_failed(indent(" ➜ Exception: #{ error['msg'] }", level))
|
611
529
|
end
|
612
530
|
end
|
613
531
|
end
|
@@ -622,24 +540,6 @@ module Guard
|
|
622
540
|
(' ' * level) + message
|
623
541
|
end
|
624
542
|
|
625
|
-
# Show system notifications about the occurred errors.
|
626
|
-
#
|
627
|
-
# @param [Hash] result the suite result
|
628
|
-
# @param [Hash] options the options
|
629
|
-
# @option options [Integer] :max_error_notify maximum error notifications to show
|
630
|
-
# @option options [Boolean] :notification show notifications
|
631
|
-
#
|
632
|
-
def notify_errors(result, options)
|
633
|
-
collect_specs(result['suites']).each_with_index do |spec, index|
|
634
|
-
if !spec['passed'] && options[:max_error_notify] > index
|
635
|
-
msg = spec['messages'].map { |message| format_message(message, true) }.join(', ')
|
636
|
-
Formatter.notify("#{ spec['description'] }: #{ msg }",
|
637
|
-
title: 'Jasmine spec failed',
|
638
|
-
image: :failed,
|
639
|
-
priority: 2) if options[:notification]
|
640
|
-
end
|
641
|
-
end
|
642
|
-
end
|
643
543
|
|
644
544
|
# Tests if the given suite has a failing spec underneath.
|
645
545
|
#
|
@@ -647,7 +547,19 @@ module Guard
|
|
647
547
|
# @return [Boolean] the search result
|
648
548
|
#
|
649
549
|
def contains_failed_spec?(suite)
|
650
|
-
collect_specs([suite]).any? { |spec|
|
550
|
+
collect_specs([suite]).any? { |spec| spec['status'] == 'failed' }
|
551
|
+
end
|
552
|
+
|
553
|
+
|
554
|
+
# Get all failed specs from the suites and its nested suites.
|
555
|
+
#
|
556
|
+
# @param suites [Array<Hash>] the suites results
|
557
|
+
# @return [Array<Hash>] all failed
|
558
|
+
#
|
559
|
+
def collect_spec_errors(suites)
|
560
|
+
collect_specs(suites).map { |spec|
|
561
|
+
(spec['errors']||[]).map { |error| format_error(error,false) }
|
562
|
+
}.flatten
|
651
563
|
end
|
652
564
|
|
653
565
|
# Get all specs from the suites and its nested suites.
|
@@ -656,10 +568,9 @@ module Guard
|
|
656
568
|
# @return [Array<Hash>] all specs
|
657
569
|
#
|
658
570
|
def collect_specs(suites)
|
659
|
-
suites.
|
660
|
-
specs
|
661
|
-
specs
|
662
|
-
specs
|
571
|
+
suites.each_with_object([]) do |suite, specs|
|
572
|
+
specs.concat( suite['specs'] )
|
573
|
+
specs.concat( collect_specs(suite['suites']) ) if suite['suites']
|
663
574
|
end
|
664
575
|
end
|
665
576
|
|
@@ -669,9 +580,11 @@ module Guard
|
|
669
580
|
# @param [Boolean] short show a short version of the message
|
670
581
|
# @return [String] the cleaned error message
|
671
582
|
#
|
672
|
-
def
|
673
|
-
|
674
|
-
|
583
|
+
def format_error(error, short)
|
584
|
+
message = error['message'].gsub(%r{ in http.*\(line \d+\)$},'')
|
585
|
+
if !short && error['trace'] && error['trace'].length > 0
|
586
|
+
location = error['trace'][0]
|
587
|
+
"#{message} in #{location['file']}:#{location['line']}"
|
675
588
|
else
|
676
589
|
message
|
677
590
|
end
|
@@ -682,9 +595,8 @@ module Guard
|
|
682
595
|
#
|
683
596
|
# @param [Hash] coverage the last run coverage data
|
684
597
|
# @param [String] file the file name of the spec
|
685
|
-
# @param [Hash] options the options for the execution
|
686
598
|
#
|
687
|
-
def update_coverage(coverage, file
|
599
|
+
def update_coverage(coverage, file)
|
688
600
|
if file == options[:spec_dir]
|
689
601
|
File.write(coverage_file, MultiJson.encode(coverage, { max_nesting: false }))
|
690
602
|
else
|
@@ -707,16 +619,15 @@ module Guard
|
|
707
619
|
#
|
708
620
|
# @return [Boolean] true if any coverage threshold is set
|
709
621
|
#
|
710
|
-
def any_coverage_threshold?
|
622
|
+
def any_coverage_threshold?
|
711
623
|
THRESHOLDS.any? { |threshold| options[threshold] != 0 }
|
712
624
|
end
|
713
625
|
|
714
626
|
# Converts the options to Istanbul recognized options
|
715
627
|
#
|
716
|
-
# @param [Hash] options the options for the coverage
|
717
628
|
# @return [String] the command line options
|
718
629
|
#
|
719
|
-
def istanbul_coverage_options
|
630
|
+
def istanbul_coverage_options
|
720
631
|
THRESHOLDS.inject([]) do |coverage, name|
|
721
632
|
threshold = options[name]
|
722
633
|
coverage << (threshold != 0 ? "--#{ name.to_s.sub('_threshold', '') } #{ threshold }" : '')
|
@@ -750,13 +661,12 @@ module Guard
|
|
750
661
|
|
751
662
|
# Creates and returns the coverage report directory.
|
752
663
|
#
|
753
|
-
# @param [Hash] options for the coverage report directory
|
754
664
|
# @return [String] the coverage report directory
|
755
665
|
#
|
756
|
-
def coverage_report_directory
|
666
|
+
def coverage_report_directory
|
757
667
|
File.expand_path(options[:coverage_html_dir])
|
758
668
|
end
|
759
|
-
end
|
760
669
|
end
|
761
670
|
end
|
762
671
|
end
|
672
|
+
|