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 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: