guard-jasmine 1.11.1 → 1.12.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/README.md +97 -12
- data/lib/guard/jasmine.rb +41 -25
- data/lib/guard/jasmine/cli.rb +47 -20
- data/lib/guard/jasmine/coverage.rb +73 -0
- data/lib/guard/jasmine/phantomjs/lib/reporter.js +3 -0
- data/lib/guard/jasmine/phantomjs/src/reporter.coffee +4 -0
- data/lib/guard/jasmine/phantomjs/src/result.coffee +2 -1
- data/lib/guard/jasmine/runner.rb +171 -2
- data/lib/guard/jasmine/server.rb +6 -2
- data/lib/guard/jasmine/version.rb +1 -1
- metadata +106 -67
data/README.md
CHANGED
@@ -18,6 +18,9 @@ various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.
|
|
18
18
|
* Runs the standard Jasmine test runner, so you can use [Jasminerice][] for integrating [Jasmine][] into the
|
19
19
|
[Rails asset pipeline][] and write your specs in [CoffeeScript][].
|
20
20
|
|
21
|
+
* Integrates [Istanbul](https://github.com/gotwarlost/istanbul) to instrument your code in the asset pipeline and
|
22
|
+
generate coverage reports.
|
23
|
+
|
21
24
|
* Custom console logger implementation for pretty printing JavaScript objects and DOM elements.
|
22
25
|
|
23
26
|
* Can be used to run [Jasmine-species](http://rudylattae.github.com/jasmine-species/) acceptance tests provided by
|
@@ -167,7 +170,7 @@ Now you can access `/jasmine-stories` when you start your Rails server normally.
|
|
167
170
|
accordingly:
|
168
171
|
|
169
172
|
```ruby
|
170
|
-
guard :jasmine, :jasmine_url => 'http://127.0.0.1:8888/jasmine-stories' do
|
173
|
+
guard :jasmine, :port => 8888, :jasmine_url => 'http://127.0.0.1:8888/jasmine-stories' do
|
171
174
|
...
|
172
175
|
end
|
173
176
|
```
|
@@ -205,13 +208,7 @@ group :development, :test do
|
|
205
208
|
end
|
206
209
|
```
|
207
210
|
|
208
|
-
and generate the configuration files
|
209
|
-
|
210
|
-
```ruby
|
211
|
-
guard :jasmine, :jasmine_url => 'http://localhost:8888/' do
|
212
|
-
...
|
213
|
-
end
|
214
|
-
```
|
211
|
+
and generate the configuration files.
|
215
212
|
|
216
213
|
#### Rails 3 without the asset pipeline
|
217
214
|
|
@@ -276,6 +273,7 @@ create a Rack configuration to spin up a mini-Rails app for testing:
|
|
276
273
|
```Ruby
|
277
274
|
require 'action_controller/railtie'
|
278
275
|
require 'jasminerice'
|
276
|
+
require 'guard/jasmine'
|
279
277
|
require 'sprockets/railtie'
|
280
278
|
require 'jquery-rails'
|
281
279
|
|
@@ -489,9 +487,85 @@ You can further customize the log output by implement one of these methods:
|
|
489
487
|
In addition, the console can log jQuery collections and outputs the HTML representation of the element by using the
|
490
488
|
jQuery `html()` method.
|
491
489
|
|
490
|
+
### Coverage options
|
491
|
+
|
492
|
+
Guard::Jasmine supports coverage reports generated by [Istanbul](https://github.com/gotwarlost/istanbul). You need to
|
493
|
+
have `istanbul` in your path in order to make this feature work. You can install it with NPM
|
494
|
+
|
495
|
+
```ruby
|
496
|
+
$ npm install istanbul
|
497
|
+
```
|
498
|
+
|
499
|
+
You also need to explicit enable the coverage support in the options:
|
500
|
+
|
501
|
+
```ruby
|
502
|
+
:coverage => :true # Enable/disable JavaScript coverage support
|
503
|
+
# default: :false
|
504
|
+
```
|
505
|
+
|
506
|
+
### Instrumentation
|
507
|
+
|
508
|
+
Istanbul needs to instrument the implementation files so that the execution path can be detected. Guard::Jasmine comes
|
509
|
+
with a tilt template that generates instrumented implementation files when using in the asset pipeline. If you do not
|
510
|
+
use asset pipeline, than you need to instrument your files on your own, either manually or by using something like
|
511
|
+
[Guard::Process](https://github.com/socialreferral/guard-process). You can get more information about the
|
512
|
+
instrumentation with `instanbul help instrument`.
|
513
|
+
|
514
|
+
**Important**: You need to clear the asset cache when you change this setting, so that already compiled assets will be
|
515
|
+
recompiled. Just use the Sprockets supplied Rake task:
|
516
|
+
|
517
|
+
```ruby
|
518
|
+
$ rake assets:clean
|
519
|
+
```
|
520
|
+
|
521
|
+
#### Check coverage
|
522
|
+
|
523
|
+
By default Guard::Jasmine just outputs the coverage when enable without any effect on the spec run result. You can
|
524
|
+
make Guard::Jasmine fail the spec run when a given threshold is not met. You can set the following thresholds:
|
525
|
+
|
526
|
+
```ruby
|
527
|
+
:statements_threshold => 95 # Statements coverage threshold
|
528
|
+
# default: 0
|
529
|
+
|
530
|
+
:functions_threshold => 85 # Functions coverage threshold
|
531
|
+
# default: 0
|
532
|
+
|
533
|
+
:branches_threshold => -10 # Branches coverage threshold
|
534
|
+
# default: 0
|
535
|
+
|
536
|
+
:lines_threshold => -15 # Lines coverage threshold
|
537
|
+
# default: 0
|
538
|
+
```
|
539
|
+
|
540
|
+
A positive threshold is taken to be the minimum percentage required, a negative threshold represents the maximum number
|
541
|
+
of uncovered entities allowed.
|
542
|
+
|
543
|
+
#### Coverage report
|
544
|
+
|
545
|
+
Guard::Jasmine always shows the Istanbul text report after a spec run that contains the coverage results per file. You
|
546
|
+
can also enable two more reports:
|
547
|
+
|
548
|
+
```ruby
|
549
|
+
:coverage_html => :true # Enable Istanbul HTML coverage report
|
550
|
+
# default: :false
|
551
|
+
|
552
|
+
:coverage_summary => :true # Enable Istanbul summary coverage report
|
553
|
+
# default: :false
|
554
|
+
```
|
555
|
+
|
556
|
+
The `:coverage_summary` options disables the detailed file based coverage report by a small summary coverage report.
|
557
|
+
|
558
|
+
Both of these results are more useful if they are run against the coverage data from a full spec run, so it's strongly
|
559
|
+
advised to enable the `:all_on_start` option.
|
560
|
+
|
561
|
+
With Jasmine in the asset pipeline all instrumented implementation files are available in the runtime and when you
|
562
|
+
execute a partial spec run it reports a lower coverage for the excluded files, since their associated specs aren't run.
|
563
|
+
Guard::Jasmine tries to work around this by merge only the coverage data for the changed files (Istanbul knows the file
|
564
|
+
name in opposite to Jasmine).
|
565
|
+
|
492
566
|
### System notifications options
|
493
567
|
|
494
|
-
These options affects what system notifications
|
568
|
+
These options affects what system notifications are shown after a spec run:
|
495
569
|
|
496
570
|
```ruby
|
497
571
|
:notifications => false # Show success and error notifications.
|
@@ -564,7 +638,15 @@ Options:
|
|
564
638
|
# Default: true
|
565
639
|
[--specdoc=SPECDOC] # Whether to show successes in the spec runner, either `always`, `never` or `failure`
|
566
640
|
# Default: always
|
567
|
-
|
641
|
+
[--coverage] # Whether to enable the coverage support or not
|
642
|
+
[--statements-threshold=N] # Statements coverage threshold
|
643
|
+
# Default: 0
|
644
|
+
[--functions-threshold=N] # Functions coverage threshold
|
645
|
+
# Default: 0
|
646
|
+
[--branches-threshold=N] # Branches coverage threshold
|
647
|
+
# Default: 0
|
648
|
+
[--lines-threshold=N] # Lines coverage threshold
|
649
|
+
# Default: 0
|
568
650
|
Run the Jasmine spec runner
|
569
651
|
```
|
570
652
|
|
@@ -617,14 +699,14 @@ With the given `guard-jasmine` script you're able to configure [Travis CI](http:
|
|
617
699
|
Simply use the `script` setting in your `.travis.yml`:
|
618
700
|
|
619
701
|
```yaml
|
620
|
-
script: 'bundle exec guard-jasmine'
|
702
|
+
script: 'bundle exec guard-jasmine --server-timeout=60'
|
621
703
|
```
|
622
704
|
|
623
705
|
You can also run your Guard::Jasmine specs after your specs that are ran with `rake` by using `after_script`:
|
624
706
|
|
625
707
|
```yaml
|
626
708
|
script: 'rake spec'
|
627
|
-
after_script: 'bundle exec guard-jasmine'
|
709
|
+
after_script: 'bundle exec guard-jasmine --server-timeout=60'
|
628
710
|
```
|
629
711
|
|
630
712
|
When using a PhantomJS version prior to 1.5, you need to start `xvfb` before running the specs:
|
@@ -635,6 +717,9 @@ before_script:
|
|
635
717
|
- "sh -e /etc/init.d/xvfb start"
|
636
718
|
```
|
637
719
|
|
720
|
+
**Tip**: It's highly recommended the have a server timeout of at least 60 seconds, since the performance of the Travis VMs seems to
|
721
|
+
vary quite a bit; sometimes the Jasmine server starts in 5 seconds, sometimes it takes as long as 50 seconds.
|
722
|
+
|
638
723
|
## How to test a Rails engine with Jasmine Gem
|
639
724
|
|
640
725
|
When building an engine, your code lives at the root but the dummy Rails app is in another folder (like `test/dummy` or `spec/dummy`).
|
data/lib/guard/jasmine.rb
CHANGED
@@ -11,35 +11,43 @@ module Guard
|
|
11
11
|
#
|
12
12
|
class Jasmine < Guard
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
require 'guard/jasmine/coverage'
|
15
|
+
require 'guard/jasmine/inspector'
|
16
|
+
require 'guard/jasmine/runner'
|
17
|
+
require 'guard/jasmine/server'
|
18
|
+
require 'guard/jasmine/util'
|
18
19
|
|
19
|
-
extend Util
|
20
|
+
extend ::Guard::Jasmine::Util
|
20
21
|
|
21
22
|
attr_accessor :last_run_failed, :last_failed_paths, :run_all_options
|
22
23
|
|
23
24
|
DEFAULT_OPTIONS = {
|
24
|
-
:server
|
25
|
-
:server_env
|
26
|
-
:server_timeout
|
27
|
-
:port
|
28
|
-
:rackup_config
|
29
|
-
:jasmine_url
|
30
|
-
:timeout
|
31
|
-
:spec_dir
|
32
|
-
:notification
|
33
|
-
:hide_success
|
34
|
-
:all_on_start
|
35
|
-
:keep_failed
|
36
|
-
:clean
|
37
|
-
:all_after_pass
|
38
|
-
:max_error_notify
|
39
|
-
:specdoc
|
40
|
-
:console
|
41
|
-
:errors
|
42
|
-
:focus
|
25
|
+
:server => :auto,
|
26
|
+
:server_env => ENV['RAILS_ENV'] || 'development',
|
27
|
+
:server_timeout => 15,
|
28
|
+
:port => nil,
|
29
|
+
:rackup_config => nil,
|
30
|
+
:jasmine_url => nil,
|
31
|
+
:timeout => 10,
|
32
|
+
:spec_dir => 'spec/javascripts',
|
33
|
+
:notification => true,
|
34
|
+
:hide_success => false,
|
35
|
+
:all_on_start => true,
|
36
|
+
:keep_failed => true,
|
37
|
+
:clean => true,
|
38
|
+
:all_after_pass => true,
|
39
|
+
:max_error_notify => 3,
|
40
|
+
:specdoc => :failure,
|
41
|
+
:console => :failure,
|
42
|
+
:errors => :failure,
|
43
|
+
:focus => true,
|
44
|
+
:coverage => false,
|
45
|
+
:coverage_html => false,
|
46
|
+
:coverage_summary => false,
|
47
|
+
:statements_threshold => 0,
|
48
|
+
:functions_threshold => 0,
|
49
|
+
:branches_threshold => 0,
|
50
|
+
:lines_threshold => 0
|
43
51
|
}
|
44
52
|
|
45
53
|
# Initialize Guard::Jasmine.
|
@@ -66,11 +74,18 @@ module Guard
|
|
66
74
|
# @option options [Symbol] :console options for the console.log output, either :always, :never or :failure
|
67
75
|
# @option options [Symbol] :errors options for the errors output, either :always, :never or :failure
|
68
76
|
# @option options [Symbol] :focus options for focus on failures in the specdoc
|
77
|
+
# @option options [Symbol] :coverage options for enable coverage support
|
78
|
+
# @option options [Symbol] :coverage_html options for enable coverage html support
|
79
|
+
# @option options [Symbol] :coverage_summary options for enable coverage summary support
|
80
|
+
# @option options [Symbol] :statements_threshold options for the statement coverage threshold
|
81
|
+
# @option options [Symbol] :functions_threshold options for the statement function threshold
|
82
|
+
# @option options [Symbol] :branches_threshold options for the statement branch threshold
|
83
|
+
# @option options [Symbol] :lines_threshold options for the statement lines threshold
|
69
84
|
# @option options [Hash] :run_all options overwrite options when run all specs
|
70
85
|
#
|
71
86
|
def initialize(watchers = [], options = { })
|
72
87
|
options[:port] ||= Jasmine.find_free_server_port
|
73
|
-
options[:jasmine_url] = "http://localhost:#{ options[:port] }/jasmine" unless options[:jasmine_url]
|
88
|
+
options[:jasmine_url] = "http://localhost:#{ options[:port] }#{ options[:server] == :jasmine_gem ? '/' : '/jasmine' }" unless options[:jasmine_url]
|
74
89
|
options = DEFAULT_OPTIONS.merge(options)
|
75
90
|
options[:specdoc] = :failure if ![:always, :never, :failure].include? options[:specdoc]
|
76
91
|
options[:server] ||= :auto
|
@@ -157,3 +172,4 @@ module Guard
|
|
157
172
|
|
158
173
|
end
|
159
174
|
end
|
175
|
+
|
data/lib/guard/jasmine/cli.rb
CHANGED
@@ -92,6 +92,31 @@ module Guard
|
|
92
92
|
:default => :always,
|
93
93
|
:desc => 'Whether to show successes in the spec runner, either `always`, `never` or `failure`'
|
94
94
|
|
95
|
+
method_option :coverage,
|
96
|
+
:type => :boolean,
|
97
|
+
:default => false,
|
98
|
+
:desc => 'Whether to enable the coverage support or not'
|
99
|
+
|
100
|
+
method_option :statements_threshold,
|
101
|
+
:type => :numeric,
|
102
|
+
:default => 0,
|
103
|
+
:desc => 'Statements coverage threshold'
|
104
|
+
|
105
|
+
method_option :functions_threshold,
|
106
|
+
:type => :numeric,
|
107
|
+
:default => 0,
|
108
|
+
:desc => 'Functions coverage threshold'
|
109
|
+
|
110
|
+
method_option :branches_threshold,
|
111
|
+
:type => :numeric,
|
112
|
+
:default => 0,
|
113
|
+
:desc => 'Branches coverage threshold'
|
114
|
+
|
115
|
+
method_option :lines_threshold,
|
116
|
+
:type => :numeric,
|
117
|
+
:default => 0,
|
118
|
+
:desc => 'Lines coverage threshold'
|
119
|
+
|
95
120
|
# Run the Guard::Jasmine::Runner with options from
|
96
121
|
# the command line.
|
97
122
|
#
|
@@ -100,26 +125,28 @@ module Guard
|
|
100
125
|
def spec(*paths)
|
101
126
|
paths = [options.spec_dir] if paths.empty?
|
102
127
|
|
103
|
-
runner_options
|
104
|
-
runner_options[:port]
|
105
|
-
runner_options[:jasmine_url]
|
106
|
-
runner_options[:phantomjs_bin]
|
107
|
-
runner_options[:timeout]
|
108
|
-
runner_options[:server]
|
109
|
-
runner_options[:server_env]
|
110
|
-
runner_options[:server_timeout]
|
111
|
-
runner_options[:rackup_config]
|
112
|
-
runner_options[:spec_dir]
|
113
|
-
runner_options[:console]
|
114
|
-
runner_options[:errors]
|
115
|
-
runner_options[:specdoc]
|
116
|
-
runner_options[:focus]
|
117
|
-
|
118
|
-
|
119
|
-
runner_options[:
|
120
|
-
runner_options[:
|
121
|
-
|
122
|
-
runner_options[:
|
128
|
+
runner_options = { }
|
129
|
+
runner_options[:port] = options.port || CLI.find_free_server_port
|
130
|
+
runner_options[:jasmine_url] = options.url || "http://localhost:#{ runner_options[:port] }#{ options.server.to_sym == :jasmine_gem ? '/' : '/jasmine' }"
|
131
|
+
runner_options[:phantomjs_bin] = options.bin || CLI.which('phantomjs')
|
132
|
+
runner_options[:timeout] = options.timeout
|
133
|
+
runner_options[:server] = options.server.to_sym
|
134
|
+
runner_options[:server_env] = options.server_env
|
135
|
+
runner_options[:server_timeout] = options.server_timeout
|
136
|
+
runner_options[:rackup_config] = options.rackup_config
|
137
|
+
runner_options[:spec_dir] = options.spec_dir
|
138
|
+
runner_options[:console] = [:always, :never, :failure].include?(options.console.to_sym) ? options.console.to_sym : :failure
|
139
|
+
runner_options[:errors] = [:always, :never, :failure].include?(options.errors.to_sym) ? options.errors.to_sym : :failure
|
140
|
+
runner_options[:specdoc] = [:always, :never, :failure].include?(options.specdoc.to_sym) ? options.specdoc.to_sym : :always
|
141
|
+
runner_options[:focus] = options.focus
|
142
|
+
runner_options[:coverage] = options.coverage
|
143
|
+
runner_options[:statements_threshold] = options.statements_threshold
|
144
|
+
runner_options[:functions_threshold] = options.functions_threshold
|
145
|
+
runner_options[:branches_threshold] = options.branches_threshold
|
146
|
+
runner_options[:lines_threshold] = options.lines_threshold
|
147
|
+
runner_options[:notification] = false
|
148
|
+
runner_options[:hide_success] = true
|
149
|
+
runner_options[:max_error_notify] = 0
|
123
150
|
|
124
151
|
if CLI.phantomjs_bin_valid?(runner_options[:phantomjs_bin])
|
125
152
|
catch(:task_has_failed) do
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'tilt'
|
3
|
+
require 'childprocess'
|
4
|
+
require 'guard/jasmine/util'
|
5
|
+
|
6
|
+
# Tilt template to generate coverage instrumented
|
7
|
+
# Jasmine specs files.
|
8
|
+
#
|
9
|
+
class JasmineCoverage < Tilt::Template
|
10
|
+
extend ::Guard::Jasmine::Util
|
11
|
+
|
12
|
+
def prepare
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns a coverage instrumented JavaScript file
|
16
|
+
# when the environment variable `JSCOVERAGE` is `true`
|
17
|
+
# and the `jscoverage` binary is in the `$PATH`.
|
18
|
+
#
|
19
|
+
def evaluate(context, locals)
|
20
|
+
return data unless JasmineCoverage.coverage_bin
|
21
|
+
return data unless file.include?(JasmineCoverage.app_asset_path)
|
22
|
+
|
23
|
+
Dir.mktmpdir do |path|
|
24
|
+
filename = File.basename(file)
|
25
|
+
input = File.join(path, filename).sub /\.js.+/, '.js'
|
26
|
+
|
27
|
+
File.write input, data
|
28
|
+
|
29
|
+
r, w = IO.pipe
|
30
|
+
proc = ChildProcess.build(JasmineCoverage.coverage_bin, 'instrument', '--embed-source', input)
|
31
|
+
proc.io.stdout = proc.io.stderr = w
|
32
|
+
proc.start
|
33
|
+
proc.wait
|
34
|
+
w.close
|
35
|
+
|
36
|
+
raise "Could not generate coverage instrumented file for #{ file }" unless proc.exit_code == 0
|
37
|
+
|
38
|
+
r.read.gsub input, file
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Get the absolute path to the projects assets path `/app/assets`.
|
45
|
+
#
|
46
|
+
# @return [String] the path to the Rails assets
|
47
|
+
#
|
48
|
+
def self.app_asset_path
|
49
|
+
@app_asset_path ||= File.join(Rails.root, 'app', 'assets')
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the coverage executable path.
|
53
|
+
#
|
54
|
+
# @return [String] the path
|
55
|
+
#
|
56
|
+
def self.coverage_bin
|
57
|
+
@coverage_bin ||= which 'istanbul'
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
if ENV['COVERAGE'] == 'true' and defined?(Rails)
|
63
|
+
|
64
|
+
# Guard::Jasmine engine to register coverage instrumented
|
65
|
+
# Jasmine spec files.
|
66
|
+
#
|
67
|
+
class GuardJasmineCoverageEngine < ::Rails::Engine
|
68
|
+
config.after_initialize do |app|
|
69
|
+
app.assets.register_postprocessor 'application/javascript', JasmineCoverage
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -86,6 +86,10 @@ class ConsoleReporter
|
|
86
86
|
time: runtime
|
87
87
|
}
|
88
88
|
|
89
|
+
# Report coverage results if data present
|
90
|
+
if window.__coverage__
|
91
|
+
@runnerResult['coverage'] = window.__coverage__
|
92
|
+
|
89
93
|
# Delay the end runner message, so that logs and errors can be retreived in between
|
90
94
|
end = -> console.log "RUNNER_END"
|
91
95
|
setTimeout end, 10
|
data/lib/guard/jasmine/runner.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
require 'multi_json'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'guard/jasmine/util'
|
4
6
|
|
5
7
|
module Guard
|
6
8
|
class Jasmine
|
@@ -10,8 +12,13 @@ module Guard
|
|
10
12
|
# writes the result to the console and triggers optional system notifications.
|
11
13
|
#
|
12
14
|
module Runner
|
15
|
+
extend ::Guard::Jasmine::Util
|
16
|
+
|
13
17
|
class << self
|
14
18
|
|
19
|
+
# Name of the coverage threshold options
|
20
|
+
THRESHOLDS = [:statements_threshold, :functions_threshold, :branches_threshold, :lines_threshold]
|
21
|
+
|
15
22
|
# Run the supplied specs.
|
16
23
|
#
|
17
24
|
# @param [Array<String>] paths the spec files or directories
|
@@ -169,6 +176,10 @@ module Guard
|
|
169
176
|
notify_spec_result(result, options)
|
170
177
|
end
|
171
178
|
|
179
|
+
if result['coverage'] && options[:coverage]
|
180
|
+
notify_coverage_result(result['coverage'], file, options)
|
181
|
+
end
|
182
|
+
|
172
183
|
result
|
173
184
|
|
174
185
|
rescue MultiJson::DecodeError => e
|
@@ -231,6 +242,102 @@ module Guard
|
|
231
242
|
Formatter.info("Done.\n")
|
232
243
|
end
|
233
244
|
|
245
|
+
# Notification about the coverage of a spec run, success or failure,
|
246
|
+
# and some stats.
|
247
|
+
#
|
248
|
+
# @param [Hash] coverage the coverage hash from the JSON
|
249
|
+
# @param [String] file the file name of the spec
|
250
|
+
# @param [Hash] options the options for the execution
|
251
|
+
# @option options [Boolean] :notification show notifications
|
252
|
+
# @option options [Boolean] :hide_success hide success message notification
|
253
|
+
#
|
254
|
+
def notify_coverage_result(coverage, file, options)
|
255
|
+
FileUtils.mkdir_p(coverage_root) unless File.exist?(coverage_root)
|
256
|
+
|
257
|
+
update_coverage(coverage, file, options)
|
258
|
+
|
259
|
+
if options[:coverage_summary]
|
260
|
+
generate_summary_report
|
261
|
+
else
|
262
|
+
generate_text_report(file, options)
|
263
|
+
end
|
264
|
+
|
265
|
+
check_coverage(options)
|
266
|
+
|
267
|
+
if options[:coverage_html]
|
268
|
+
generate_html_report
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
# Uses the Istanbul text reported to output the result of the
|
273
|
+
# last coverage run.
|
274
|
+
#
|
275
|
+
# @param [String] file the file name of the spec
|
276
|
+
# @param [Hash] options the options for the execution
|
277
|
+
#
|
278
|
+
def generate_text_report(file, options)
|
279
|
+
Formatter.info 'Spec coverage details:'
|
280
|
+
|
281
|
+
if file == options[:spec_dir]
|
282
|
+
matcher = /[|+]$/
|
283
|
+
else
|
284
|
+
impl = file.sub('_spec', '').sub(options[:spec_dir], '')
|
285
|
+
matcher = /(-+|All files|% Lines|#{ Regexp.escape(File.basename(impl)) }|#{ File.dirname(impl).sub(/^\//, '') }\/[^\/])/
|
286
|
+
end
|
287
|
+
|
288
|
+
puts ''
|
289
|
+
|
290
|
+
`#{ which('istanbul') } report --root #{ coverage_root } text #{ coverage_file }`.each_line do |line|
|
291
|
+
puts line.sub(/\n$/, '') if line =~ matcher
|
292
|
+
end
|
293
|
+
|
294
|
+
puts ''
|
295
|
+
end
|
296
|
+
|
297
|
+
# Uses the Istanbul text reported to output the result of the
|
298
|
+
# last coverage run.
|
299
|
+
#
|
300
|
+
# @param [Hash] options the options for the coverage
|
301
|
+
#
|
302
|
+
def check_coverage(options)
|
303
|
+
if any_coverage_threshold?(options)
|
304
|
+
coverage = `#{ which('istanbul') } check-coverage #{ istanbul_coverage_options(options) } #{ coverage_file } 2>&1`
|
305
|
+
coverage = coverage.split("\n").grep(/ERROR/).join.sub('ERROR:', '')
|
306
|
+
failed = $? && $?.exitstatus != 0
|
307
|
+
|
308
|
+
if failed
|
309
|
+
Formatter.error coverage
|
310
|
+
Formatter.notify(coverage, :title => 'Code coverage failed', :image => :failed, :priority => 2) if options[:notification]
|
311
|
+
else
|
312
|
+
Formatter.success 'Code coverage succeed'
|
313
|
+
Formatter.notify('All code is adequately covered with specs', :title => 'Code coverage succeed') if options[:notification] && !options[:hide_success]
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
# Uses the Istanbul text reported to output the result of the
|
319
|
+
# last coverage run.
|
320
|
+
#
|
321
|
+
def generate_html_report
|
322
|
+
`#{ which('istanbul') } report --root #{ coverage_root } html #{ coverage_file }`
|
323
|
+
Formatter.info "Updated HTML report available at: #{ File.join('coverage', 'index.html') }"
|
324
|
+
end
|
325
|
+
|
326
|
+
# Uses the Istanbul text-summary reporter to output the
|
327
|
+
# summary of all the coverage runs combined.
|
328
|
+
#
|
329
|
+
def generate_summary_report
|
330
|
+
Formatter.info 'Spec coverage summary:'
|
331
|
+
|
332
|
+
puts ''
|
333
|
+
|
334
|
+
`#{ which('istanbul') } report --root #{ coverage_root } text-summary #{ coverage_file }`.each_line do |line|
|
335
|
+
puts line.sub(/\n$/, '') if line =~ /\)$/
|
336
|
+
end
|
337
|
+
|
338
|
+
puts ''
|
339
|
+
end
|
340
|
+
|
234
341
|
# Specdoc like formatting of the result.
|
235
342
|
#
|
236
343
|
# @param [Hash] result the suite result
|
@@ -296,7 +403,7 @@ module Guard
|
|
296
403
|
#
|
297
404
|
def console_logs_shown?(suite, passed, options = { })
|
298
405
|
# Are console messages displayed?
|
299
|
-
console_enabled
|
406
|
+
console_enabled = options[:console] == :always || (options[:console] == :failure && !passed)
|
300
407
|
|
301
408
|
# Are there any logs to display at all for this suite?
|
302
409
|
logs_for_current_options = suite['specs'].select do |spec|
|
@@ -326,7 +433,7 @@ module Guard
|
|
326
433
|
#
|
327
434
|
def error_logs_shown?(suite, passed, options = { })
|
328
435
|
# Are error messages displayed?
|
329
|
-
errors_enabled
|
436
|
+
errors_enabled = options[:errors] == :always || (options[:errors] == :failure && !passed)
|
330
437
|
|
331
438
|
# Are there any errors to display at all for this suite?
|
332
439
|
errors_for_current_options = suite['specs'].select do |spec|
|
@@ -459,6 +566,68 @@ module Guard
|
|
459
566
|
end
|
460
567
|
end
|
461
568
|
|
569
|
+
# Updates the coverage data with new data for the implementation file.
|
570
|
+
# It replaces the coverage data if the file is the spec dir.
|
571
|
+
#
|
572
|
+
# @param [Hash] coverage the last run coverage data
|
573
|
+
# @param [String] file the file name of the spec
|
574
|
+
# @param [Hash] options the options for the execution
|
575
|
+
#
|
576
|
+
def update_coverage(coverage, file, options)
|
577
|
+
if file == options[:spec_dir]
|
578
|
+
File.write(coverage_file, MultiJson.encode(coverage, { :max_nesting => false }))
|
579
|
+
else
|
580
|
+
if File.exist?(coverage_file)
|
581
|
+
impl = file.sub('_spec', '').sub(options[:spec_dir], '')
|
582
|
+
coverage = MultiJson.decode(File.read(coverage_file), { :max_nesting => false })
|
583
|
+
|
584
|
+
coverage.each do |coverage_file, data|
|
585
|
+
coverage[coverage_file] = data if coverage_file == impl
|
586
|
+
end
|
587
|
+
|
588
|
+
File.write(coverage_file, MultiJson.encode(coverage, { :max_nesting => false }))
|
589
|
+
else
|
590
|
+
File.write(coverage_file, MultiJson.encode({ }))
|
591
|
+
end
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
# Do we should check the coverage?
|
596
|
+
#
|
597
|
+
# @return [Boolean] true if any coverage threshold is set
|
598
|
+
#
|
599
|
+
def any_coverage_threshold?(options)
|
600
|
+
THRESHOLDS.any? { |threshold| options[threshold] != 0 }
|
601
|
+
end
|
602
|
+
|
603
|
+
# Converts the options to Istanbul recognized options
|
604
|
+
#
|
605
|
+
# @param [Hash] options the options for the coverage
|
606
|
+
# @return [String] the command line options
|
607
|
+
#
|
608
|
+
def istanbul_coverage_options(options)
|
609
|
+
THRESHOLDS.inject([]) do |coverage, name|
|
610
|
+
threshold = options[name]
|
611
|
+
coverage << (threshold != 0 ? "--#{ name.to_s.sub('_threshold', '') } #{ threshold }" : '')
|
612
|
+
end.reject(&:empty?).join(' ')
|
613
|
+
end
|
614
|
+
|
615
|
+
# Get the coverage file to save all coverage data.
|
616
|
+
# Creates `tmp/coverage` if not exists.
|
617
|
+
#
|
618
|
+
# @return [String] the filename to use
|
619
|
+
#
|
620
|
+
def coverage_file
|
621
|
+
File.join(coverage_root, 'coverage.json')
|
622
|
+
end
|
623
|
+
|
624
|
+
# Create and returns the coverage root directory.
|
625
|
+
#
|
626
|
+
# @return [String] the coverage root
|
627
|
+
#
|
628
|
+
def coverage_root
|
629
|
+
File.expand_path(File.join('tmp', 'coverage'))
|
630
|
+
end
|
462
631
|
end
|
463
632
|
end
|
464
633
|
end
|
data/lib/guard/jasmine/server.rb
CHANGED
@@ -70,10 +70,12 @@ module Guard
|
|
70
70
|
def start_rack_server(server, port, options)
|
71
71
|
environment = options[:server_env]
|
72
72
|
rackup_config = options[:rackup_config]
|
73
|
+
coverage = options[:coverage] ? 'on' : 'off'
|
73
74
|
|
74
|
-
::Guard::UI.info "Guard::Jasmine starts #{ server }
|
75
|
+
::Guard::UI.info "Guard::Jasmine starts #{ server } spec server on port #{ port } in #{ environment } environment (coverage #{ coverage })."
|
75
76
|
|
76
77
|
self.process = ChildProcess.build(*['rackup', '-E', environment.to_s, '-p', port.to_s, '-s', server.to_s, rackup_config].compact)
|
78
|
+
self.process.environment['COVERAGE'] = options[:coverage].to_s
|
77
79
|
self.process.io.inherit! if ::Guard.respond_to?(:options) && ::Guard.options && ::Guard.options[:verbose]
|
78
80
|
self.process.start
|
79
81
|
|
@@ -91,10 +93,12 @@ module Guard
|
|
91
93
|
#
|
92
94
|
def start_unicorn_server(port, options)
|
93
95
|
environment = options[:server_env]
|
96
|
+
coverage = options[:coverage] ? 'on' : 'off'
|
94
97
|
|
95
|
-
::Guard::UI.info "Guard::Jasmine starts Unicorn
|
98
|
+
::Guard::UI.info "Guard::Jasmine starts Unicorn spec server on port #{ port } in #{ environment } environment (coverage #{ coverage })."
|
96
99
|
|
97
100
|
self.process = ChildProcess.build('unicorn_rails', '-E', environment.to_s, '-p', port.to_s)
|
101
|
+
self.process.environment['COVERAGE'] = options[:coverage].to_s
|
98
102
|
self.process.io.inherit! if ::Guard.respond_to?(:options) && ::Guard.options && ::Guard.options[:verbose]
|
99
103
|
self.process.start
|
100
104
|
|
metadata
CHANGED
@@ -1,96 +1,104 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: guard-jasmine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
4
|
+
prerelease:
|
5
|
+
version: 1.12.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Michael Kessler
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: guard
|
16
|
-
|
17
|
-
none: false
|
16
|
+
version_requirements: !ruby/object:Gem::Requirement
|
18
17
|
requirements:
|
19
18
|
- - ! '>='
|
20
19
|
- !ruby/object:Gem::Version
|
21
20
|
version: 1.1.0
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
21
|
none: false
|
22
|
+
requirement: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 1.1.0
|
27
|
+
none: false
|
28
|
+
prerelease: false
|
29
|
+
type: :runtime
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: multi_json
|
32
|
-
|
33
|
-
none: false
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
34
33
|
requirements:
|
35
34
|
- - ! '>='
|
36
35
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
38
|
-
|
39
|
-
prerelease: false
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
version: !binary |-
|
37
|
+
MA==
|
41
38
|
none: false
|
39
|
+
requirement: !ruby/object:Gem::Requirement
|
42
40
|
requirements:
|
43
41
|
- - ! '>='
|
44
42
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
43
|
+
version: !binary |-
|
44
|
+
MA==
|
45
|
+
none: false
|
46
|
+
prerelease: false
|
47
|
+
type: :runtime
|
46
48
|
- !ruby/object:Gem::Dependency
|
47
49
|
name: childprocess
|
48
|
-
|
49
|
-
none: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
51
|
requirements:
|
51
52
|
- - ! '>='
|
52
53
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
54
|
-
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
version: !binary |-
|
55
|
+
MA==
|
57
56
|
none: false
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: !binary |-
|
62
|
+
MA==
|
63
|
+
none: false
|
64
|
+
prerelease: false
|
65
|
+
type: :runtime
|
62
66
|
- !ruby/object:Gem::Dependency
|
63
67
|
name: thor
|
64
|
-
|
65
|
-
none: false
|
68
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
69
|
requirements:
|
67
70
|
- - ! '>='
|
68
71
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
70
|
-
|
71
|
-
prerelease: false
|
72
|
-
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
version: !binary |-
|
73
|
+
MA==
|
73
74
|
none: false
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
74
76
|
requirements:
|
75
77
|
- - ! '>='
|
76
78
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
79
|
+
version: !binary |-
|
80
|
+
MA==
|
81
|
+
none: false
|
82
|
+
prerelease: false
|
83
|
+
type: :runtime
|
78
84
|
- !ruby/object:Gem::Dependency
|
79
85
|
name: bundler
|
80
|
-
|
81
|
-
none: false
|
86
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
87
|
requirements:
|
83
88
|
- - ! '>='
|
84
89
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
86
|
-
|
87
|
-
prerelease: false
|
88
|
-
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
version: !binary |-
|
91
|
+
MA==
|
89
92
|
none: false
|
93
|
+
requirement: !ruby/object:Gem::Requirement
|
90
94
|
requirements:
|
91
95
|
- - ! '>='
|
92
96
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
97
|
+
version: !binary |-
|
98
|
+
MA==
|
99
|
+
none: false
|
100
|
+
prerelease: false
|
101
|
+
type: :development
|
94
102
|
description: Guard::Jasmine automatically tests your Jasmine specs on PhantomJS
|
95
103
|
email:
|
96
104
|
- michi@netzpiraten.ch
|
@@ -100,54 +108,85 @@ executables:
|
|
100
108
|
extensions: []
|
101
109
|
extra_rdoc_files: []
|
102
110
|
files:
|
103
|
-
-
|
104
|
-
|
105
|
-
-
|
106
|
-
|
107
|
-
-
|
108
|
-
|
109
|
-
-
|
110
|
-
|
111
|
-
-
|
112
|
-
|
113
|
-
-
|
114
|
-
|
115
|
-
-
|
116
|
-
|
117
|
-
-
|
118
|
-
|
119
|
-
-
|
120
|
-
|
121
|
-
-
|
122
|
-
|
123
|
-
-
|
124
|
-
|
125
|
-
-
|
111
|
+
- !binary |-
|
112
|
+
YmluL2d1YXJkLWphc21pbmU=
|
113
|
+
- !binary |-
|
114
|
+
YmluL2d1YXJkLWphc21pbmUtZGVidWc=
|
115
|
+
- !binary |-
|
116
|
+
bGliL2d1YXJkL2phc21pbmUucmI=
|
117
|
+
- !binary |-
|
118
|
+
bGliL2d1YXJkL2phc21pbmUvY2xpLnJi
|
119
|
+
- !binary |-
|
120
|
+
bGliL2d1YXJkL2phc21pbmUvY292ZXJhZ2UucmI=
|
121
|
+
- !binary |-
|
122
|
+
bGliL2d1YXJkL2phc21pbmUvZm9ybWF0dGVyLnJi
|
123
|
+
- !binary |-
|
124
|
+
bGliL2d1YXJkL2phc21pbmUvaW5zcGVjdG9yLnJi
|
125
|
+
- !binary |-
|
126
|
+
bGliL2d1YXJkL2phc21pbmUvcnVubmVyLnJi
|
127
|
+
- !binary |-
|
128
|
+
bGliL2d1YXJkL2phc21pbmUvc2VydmVyLnJi
|
129
|
+
- !binary |-
|
130
|
+
bGliL2d1YXJkL2phc21pbmUvdGFzay5yYg==
|
131
|
+
- !binary |-
|
132
|
+
bGliL2d1YXJkL2phc21pbmUvdXRpbC5yYg==
|
133
|
+
- !binary |-
|
134
|
+
bGliL2d1YXJkL2phc21pbmUvdmVyc2lvbi5yYg==
|
135
|
+
- !binary |-
|
136
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL2d1YXJkLWphc21pbmUuY29m
|
137
|
+
ZmVl
|
138
|
+
- !binary |-
|
139
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL2d1YXJkLWphc21pbmUuanM=
|
140
|
+
- !binary |-
|
141
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL2xpYi9jb25zb2xlLmpz
|
142
|
+
- !binary |-
|
143
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL2xpYi9yZXBvcnRlci5qcw==
|
144
|
+
- !binary |-
|
145
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL2xpYi9yZXN1bHQuanM=
|
146
|
+
- !binary |-
|
147
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL3NyYy9jb25zb2xlLmNvZmZl
|
148
|
+
ZQ==
|
149
|
+
- !binary |-
|
150
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL3NyYy9yZXBvcnRlci5jb2Zm
|
151
|
+
ZWU=
|
152
|
+
- !binary |-
|
153
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL3NyYy9yZXN1bHQuY29mZmVl
|
154
|
+
- !binary |-
|
155
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL3Rlc3QvY29uc29sZV9zcGVj
|
156
|
+
LmNvZmZlZQ==
|
157
|
+
- !binary |-
|
158
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL3Rlc3QvcmVwb3J0ZXJfc3Bl
|
159
|
+
Yy5jb2ZmZWU=
|
160
|
+
- !binary |-
|
161
|
+
bGliL2d1YXJkL2phc21pbmUvcGhhbnRvbWpzL3Rlc3QvcmVzdWx0X3NwZWMu
|
162
|
+
Y29mZmVl
|
163
|
+
- !binary |-
|
164
|
+
bGliL2d1YXJkL2phc21pbmUvdGVtcGxhdGVzL0d1YXJkZmlsZQ==
|
126
165
|
- LICENSE
|
127
166
|
- README.md
|
128
167
|
homepage: https://github.com/netzpirat/guard-jasmine
|
129
168
|
licenses: []
|
130
|
-
post_install_message:
|
169
|
+
post_install_message:
|
131
170
|
rdoc_options: []
|
132
171
|
require_paths:
|
133
172
|
- lib
|
134
173
|
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
-
none: false
|
136
174
|
requirements:
|
137
175
|
- - ! '>='
|
138
176
|
- !ruby/object:Gem::Version
|
139
|
-
version:
|
140
|
-
|
177
|
+
version: !binary |-
|
178
|
+
MA==
|
141
179
|
none: false
|
180
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
181
|
requirements:
|
143
182
|
- - ! '>='
|
144
183
|
- !ruby/object:Gem::Version
|
145
184
|
version: 1.3.6
|
185
|
+
none: false
|
146
186
|
requirements: []
|
147
187
|
rubyforge_project: guard-jasmine
|
148
|
-
rubygems_version: 1.8.
|
149
|
-
signing_key:
|
188
|
+
rubygems_version: 1.8.24
|
189
|
+
signing_key:
|
150
190
|
specification_version: 3
|
151
191
|
summary: Guard gem for headless testing with Jasmine
|
152
192
|
test_files: []
|
153
|
-
has_rdoc:
|