guard-jasmine 1.11.1 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
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 and change the Jasmine url:
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 (growl, libnotify or notifu) are shown after a spec run:
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`).
@@ -11,35 +11,43 @@ module Guard
11
11
  #
12
12
  class Jasmine < Guard
13
13
 
14
- autoload :Inspector, 'guard/jasmine/inspector'
15
- autoload :Runner, 'guard/jasmine/runner'
16
- autoload :Server, 'guard/jasmine/server'
17
- autoload :Util, 'guard/jasmine/util'
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 => :auto,
25
- :server_env => ENV['RAILS_ENV'] || 'development',
26
- :server_timeout => 15,
27
- :port => nil,
28
- :rackup_config => nil,
29
- :jasmine_url => nil,
30
- :timeout => 10,
31
- :spec_dir => 'spec/javascripts',
32
- :notification => true,
33
- :hide_success => false,
34
- :all_on_start => true,
35
- :keep_failed => true,
36
- :clean => true,
37
- :all_after_pass => true,
38
- :max_error_notify => 3,
39
- :specdoc => :failure,
40
- :console => :failure,
41
- :errors => :failure,
42
- :focus => true
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
+
@@ -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] = options.port || CLI.find_free_server_port
105
- runner_options[:jasmine_url] = options.url || "http://localhost:#{ runner_options[:port] }/jasmine"
106
- runner_options[:phantomjs_bin] = options.bin || CLI.which('phantomjs')
107
- runner_options[:timeout] = options.timeout
108
- runner_options[:server] = options.server.to_sym
109
- runner_options[:server_env] = options.server_env
110
- runner_options[:server_timeout] = options.server_timeout
111
- runner_options[:rackup_config] = options.rackup_config
112
- runner_options[:spec_dir] = options.spec_dir
113
- runner_options[:console] = [:always, :never, :failure].include?(options.console.to_sym) ? options.console.to_sym : :failure
114
- runner_options[:errors] = [:always, :never, :failure].include?(options.errors.to_sym) ? options.errors.to_sym : :failure
115
- runner_options[:specdoc] = [:always, :never, :failure].include?(options.specdoc.to_sym) ? options.specdoc.to_sym : :always
116
- runner_options[:focus] = options.focus
117
-
118
-
119
- runner_options[:notification] = false
120
- runner_options[:hide_success] = true
121
-
122
- runner_options[:max_error_notify] = 0
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
@@ -84,6 +84,9 @@
84
84
  failures: runner.results().failedCount,
85
85
  time: runtime
86
86
  };
87
+ if (window.__coverage__) {
88
+ this.runnerResult['coverage'] = window.__coverage__;
89
+ }
87
90
  end = function() {
88
91
  return console.log("RUNNER_END");
89
92
  };
@@ -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
@@ -62,7 +62,8 @@ class Result
62
62
 
63
63
  suite
64
64
 
65
- # Writes the result output to the console.
65
+ # Processes the collected results and returns
66
+ # a single result object.
66
67
  #
67
68
  # @return [Object] the Jasmine result
68
69
  #
@@ -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 = options[:console] == :always || (options[:console] == :failure && !passed)
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 = options[:errors] == :always || (options[:errors] == :failure && !passed)
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
@@ -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 } test server on port #{ port } in #{ environment } environment."
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 test server on port #{ port } in #{ environment } environment."
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
 
@@ -1,6 +1,6 @@
1
1
  module Guard
2
2
  module JasmineVersion
3
3
  # Guard::Jasmine version that is used for the Gem specification
4
- VERSION = '1.11.1'
4
+ VERSION = '1.12.0'
5
5
  end
6
6
  end
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
- version: 1.11.1
5
- prerelease:
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-11 00:00:00.000000000 Z
12
+ date: 2013-01-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: guard
16
- requirement: !ruby/object:Gem::Requirement
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
- requirement: !ruby/object:Gem::Requirement
33
- none: false
32
+ version_requirements: !ruby/object:Gem::Requirement
34
33
  requirements:
35
34
  - - ! '>='
36
35
  - !ruby/object:Gem::Version
37
- version: '0'
38
- type: :runtime
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: '0'
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
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
+ version_requirements: !ruby/object:Gem::Requirement
50
51
  requirements:
51
52
  - - ! '>='
52
53
  - !ruby/object:Gem::Version
53
- version: '0'
54
- type: :runtime
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: '0'
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
- requirement: !ruby/object:Gem::Requirement
65
- none: false
68
+ version_requirements: !ruby/object:Gem::Requirement
66
69
  requirements:
67
70
  - - ! '>='
68
71
  - !ruby/object:Gem::Version
69
- version: '0'
70
- type: :runtime
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: '0'
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
- requirement: !ruby/object:Gem::Requirement
81
- none: false
86
+ version_requirements: !ruby/object:Gem::Requirement
82
87
  requirements:
83
88
  - - ! '>='
84
89
  - !ruby/object:Gem::Version
85
- version: '0'
86
- type: :development
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: '0'
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
- - bin/guard-jasmine
104
- - bin/guard-jasmine-debug
105
- - lib/guard/jasmine/cli.rb
106
- - lib/guard/jasmine/formatter.rb
107
- - lib/guard/jasmine/inspector.rb
108
- - lib/guard/jasmine/phantomjs/guard-jasmine.coffee
109
- - lib/guard/jasmine/phantomjs/guard-jasmine.js
110
- - lib/guard/jasmine/phantomjs/lib/console.js
111
- - lib/guard/jasmine/phantomjs/lib/reporter.js
112
- - lib/guard/jasmine/phantomjs/lib/result.js
113
- - lib/guard/jasmine/phantomjs/src/console.coffee
114
- - lib/guard/jasmine/phantomjs/src/reporter.coffee
115
- - lib/guard/jasmine/phantomjs/src/result.coffee
116
- - lib/guard/jasmine/phantomjs/test/console_spec.coffee
117
- - lib/guard/jasmine/phantomjs/test/reporter_spec.coffee
118
- - lib/guard/jasmine/phantomjs/test/result_spec.coffee
119
- - lib/guard/jasmine/runner.rb
120
- - lib/guard/jasmine/server.rb
121
- - lib/guard/jasmine/task.rb
122
- - lib/guard/jasmine/templates/Guardfile
123
- - lib/guard/jasmine/util.rb
124
- - lib/guard/jasmine/version.rb
125
- - lib/guard/jasmine.rb
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: '0'
140
- required_rubygems_version: !ruby/object:Gem::Requirement
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.23
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: