guard-jasmine 1.17.0 → 1.18.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.
- checksums.yaml +4 -4
- data/README.md +30 -1
- data/lib/guard/jasmine.rb +8 -2
- data/lib/guard/jasmine/cli.rb +25 -1
- data/lib/guard/jasmine/phantomjs/guard-jasmine.coffee +51 -2
- data/lib/guard/jasmine/phantomjs/guard-jasmine.js +81 -9
- data/lib/guard/jasmine/phantomjs/lib/console.js +1 -9
- data/lib/guard/jasmine/phantomjs/lib/junit_reporter.js +224 -0
- data/lib/guard/jasmine/phantomjs/lib/reporter.js +1 -5
- data/lib/guard/jasmine/phantomjs/lib/result.js +1 -9
- data/lib/guard/jasmine/runner.rb +13 -1
- data/lib/guard/jasmine/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f8a880f0eac45a32232516339a2591ff56af0a4f
|
|
4
|
+
data.tar.gz: be38c7d0218b9354e3f4e84dd4683bc73ff7709b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 43088c46d2ea7f7143c9ed9131cbc602ba0f38f82d8ad76c4444afbfe369d5ad0205621da86c91caed2b38a5ec6f61372f0486ee6a1b94473403a829efc07ec8
|
|
7
|
+
data.tar.gz: 5880051b4970b435a624ad4262a7df51f28e99b9573b16af012d0cd994221ca47623c0d4e2b734bfbf52b16ee1c9565ef555039e4fb13354256680354f25f360
|
data/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Ruby.
|
|
|
15
15
|
* Fast headless testing on [PhantomJS][], a full featured WebKit browser with native support for
|
|
16
16
|
various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.
|
|
17
17
|
|
|
18
|
-
* Runs the standard Jasmine test runner, so you can use [Jasminerice][] for integrating [Jasmine][] into the
|
|
18
|
+
* Runs the standard Jasmine test runner, so you can use [Jasminerice][] or [jasmine-rails][] for integrating [Jasmine][] into the
|
|
19
19
|
[Rails asset pipeline][] and write your specs in [CoffeeScript][].
|
|
20
20
|
|
|
21
21
|
* Integrates [Istanbul](https://github.com/gotwarlost/istanbul) to instrument your code in the asset pipeline and
|
|
@@ -143,6 +143,34 @@ It also creates an empty `spec/javascripts/spec.css` file as it is always reques
|
|
|
143
143
|
|
|
144
144
|
Now you can access `/jasmine` when you start your Rails server normally.
|
|
145
145
|
|
|
146
|
+
### Jasmine-Rails
|
|
147
|
+
|
|
148
|
+
[jasmine-rails][] is another option for integrating your [Jasmine][] tests with an asset pipeline-enabled Rails application. The quick-and-dirty recipe for this is:
|
|
149
|
+
|
|
150
|
+
1. Add `jasmine-rails` to your `Gemfile`:
|
|
151
|
+
|
|
152
|
+
```ruby
|
|
153
|
+
group :test do
|
|
154
|
+
gem "jasmine-rails"
|
|
155
|
+
end
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
2. Configure a mount point in your application's `routes.rb` (please refer to the [jasmine-rails][] documentation for more details):
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
mount JasmineRails::Engine => '/spec' if defined?(JasmineRails)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
3. Configure **Guard::Jasmine** to reference the mount point in your `Guardfile`:
|
|
165
|
+
|
|
166
|
+
```ruby
|
|
167
|
+
guard 'jasmine', :server => :webrick, :server_mount => '/specs' do
|
|
168
|
+
# watch stuff
|
|
169
|
+
end
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
4. Profit! Seriously, you should be able to access the Jasmine runner at `/specs` within your Rails application, *and* **Guard::Jasmine** should run the same specs. Now no more excuses, get that javascript tested!
|
|
173
|
+
|
|
146
174
|
### Jasmine Stories acceptance tests
|
|
147
175
|
|
|
148
176
|
[Jasmine Stories](https://github.com/DominikGuzei/jasmine-stories) is a Jasminerice clone and that serves
|
|
@@ -884,6 +912,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
884
912
|
[PhantomJS build instructions]: http://code.google.com/p/phantomjs/wiki/BuildInstructions
|
|
885
913
|
[Brad Phelan]: http://twitter.com/#!/bradgonesurfing
|
|
886
914
|
[Jasminerice]: https://github.com/bradphelan/jasminerice
|
|
915
|
+
[jasmine-rails]: https://github.com/searls/jasmine-rails
|
|
887
916
|
[Pivotal Labs]: http://pivotallabs.com/
|
|
888
917
|
[Jasmine]: http://pivotal.github.com/jasmine/
|
|
889
918
|
[the Jasmine Gem]: https://github.com/pivotal/jasmine-gem
|
data/lib/guard/jasmine.rb
CHANGED
|
@@ -25,7 +25,7 @@ module Guard
|
|
|
25
25
|
server: :auto,
|
|
26
26
|
server_env: ENV['RAILS_ENV'] || 'development',
|
|
27
27
|
server_timeout: 60,
|
|
28
|
-
server_mount: '/jasmine',
|
|
28
|
+
server_mount: '/jasmine', # set here for documentation purposes; actually determiend at runtime by presence (or lack thereof) of the JasmineRails constant
|
|
29
29
|
port: nil,
|
|
30
30
|
rackup_config: nil,
|
|
31
31
|
jasmine_url: nil,
|
|
@@ -49,7 +49,10 @@ module Guard
|
|
|
49
49
|
statements_threshold: 0,
|
|
50
50
|
functions_threshold: 0,
|
|
51
51
|
branches_threshold: 0,
|
|
52
|
-
lines_threshold: 0
|
|
52
|
+
lines_threshold: 0,
|
|
53
|
+
junit: false,
|
|
54
|
+
junit_consolidate: true,
|
|
55
|
+
junit_save_path: ''
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
# Initialize Guard::Jasmine.
|
|
@@ -61,6 +64,7 @@ module Guard
|
|
|
61
64
|
# @option options [Integer] :server_timeout the number of seconds to wait for the Jasmine spec server
|
|
62
65
|
# @option options [String] :port the port for the Jasmine test server
|
|
63
66
|
# @option options [String] :rackup_config custom rackup config to use
|
|
67
|
+
# @option options [String] :server_mount custom mount point to use; defaults to '/specs' if JasmineRails is on the load path, otherwise '/jasmine'
|
|
64
68
|
# @option options [String] :jasmine_url the url of the Jasmine test runner
|
|
65
69
|
# @option options [String] :phantomjs_bin the location of the PhantomJS binary
|
|
66
70
|
# @option options [Integer] :timeout the maximum time in seconds to wait for the spec runner to finish
|
|
@@ -86,6 +90,8 @@ module Guard
|
|
|
86
90
|
# @option options [Hash] :run_all options overwrite options when run all specs
|
|
87
91
|
#
|
|
88
92
|
def initialize(watchers = [], options = { })
|
|
93
|
+
options[:server_mount] ||= defined?(JasmineRails) ? '/specs' : '/jasmine'
|
|
94
|
+
|
|
89
95
|
options = DEFAULT_OPTIONS.merge(options)
|
|
90
96
|
|
|
91
97
|
options[:spec_dir] ||= File.exists?(File.join('spec', 'javascripts')) ? File.join('spec', 'javascripts') : 'spec'
|
data/lib/guard/jasmine/cli.rb
CHANGED
|
@@ -70,6 +70,11 @@ module Guard
|
|
|
70
70
|
aliases: '-u',
|
|
71
71
|
desc: 'The url of the Jasmine test runner'
|
|
72
72
|
|
|
73
|
+
method_option :mount,
|
|
74
|
+
type: :string,
|
|
75
|
+
aliases: '-m',
|
|
76
|
+
desc: 'The mount point of the Jasmine test runner'
|
|
77
|
+
|
|
73
78
|
method_option :timeout,
|
|
74
79
|
type: :numeric,
|
|
75
80
|
aliases: '-t',
|
|
@@ -137,6 +142,21 @@ module Guard
|
|
|
137
142
|
default: 0,
|
|
138
143
|
desc: 'Lines coverage threshold'
|
|
139
144
|
|
|
145
|
+
method_option :junit,
|
|
146
|
+
type: :boolean,
|
|
147
|
+
default: false,
|
|
148
|
+
desc: 'Whether to save jasmine test results in JUnit-compatible xml files'
|
|
149
|
+
|
|
150
|
+
method_option :junit_consolidate,
|
|
151
|
+
type: :boolean,
|
|
152
|
+
default: false,
|
|
153
|
+
desc: 'Whether to save nested describes within the same xml file as their parent'
|
|
154
|
+
|
|
155
|
+
method_option :junit_save_path,
|
|
156
|
+
type: :string,
|
|
157
|
+
default: '',
|
|
158
|
+
desc: 'The directory to save junit xml files into'
|
|
159
|
+
|
|
140
160
|
# Run the Guard::Jasmine::Runner with options from
|
|
141
161
|
# the command line.
|
|
142
162
|
#
|
|
@@ -147,7 +167,8 @@ module Guard
|
|
|
147
167
|
runner_options[:port] = options.port || CLI.find_free_server_port
|
|
148
168
|
runner_options[:spec_dir] = options.spec_dir || (File.exists?(File.join('spec', 'javascripts')) ? File.join('spec', 'javascripts') : 'spec')
|
|
149
169
|
runner_options[:server] = options.server.to_sym == :auto ? ::Guard::Jasmine::Server.detect_server(runner_options[:spec_dir]) : options.server.to_sym
|
|
150
|
-
runner_options[:
|
|
170
|
+
runner_options[:server_mount] = options.mount || (defined?(JasmineRails) ? '/specs' : '/jasmine')
|
|
171
|
+
runner_options[:jasmine_url] = options.url || "http://localhost:#{ runner_options[:port] }#{ options.server.to_sym == :jasmine_gem ? '/' : runner_options[:server_mount] }"
|
|
151
172
|
runner_options[:phantomjs_bin] = options.bin || CLI.which('phantomjs')
|
|
152
173
|
runner_options[:timeout] = options.timeout
|
|
153
174
|
runner_options[:verbose] = options.verbose
|
|
@@ -169,6 +190,9 @@ module Guard
|
|
|
169
190
|
runner_options[:notification] = false
|
|
170
191
|
runner_options[:hide_success] = true
|
|
171
192
|
runner_options[:max_error_notify] = 0
|
|
193
|
+
runner_options[:junit] = options.junit
|
|
194
|
+
runner_options[:junit_consolidate] = options.junit_consolidate
|
|
195
|
+
runner_options[:junit_save_path] = options.junit_save_path
|
|
172
196
|
|
|
173
197
|
::Guard::UI.options = ::Guard::UI.options.merge({ :template => ':message' })
|
|
174
198
|
|
|
@@ -10,6 +10,9 @@ options =
|
|
|
10
10
|
focus: /true/i.test phantom.args[3]
|
|
11
11
|
console: phantom.args[4] || 'failure'
|
|
12
12
|
errors: phantom.args[5] || 'failure'
|
|
13
|
+
junit: /true/i.test phantom.args[6]
|
|
14
|
+
junit_consolidate: /true/i.test phantom.args[7]
|
|
15
|
+
junit_save_path: phantom.args[8] || ''
|
|
13
16
|
|
|
14
17
|
# Create the web page.
|
|
15
18
|
#
|
|
@@ -20,6 +23,8 @@ page = require('webpage').create()
|
|
|
20
23
|
currentSpecId = -1
|
|
21
24
|
logs = {}
|
|
22
25
|
errors = {}
|
|
26
|
+
resultsKey = "__jr" + Math.ceil(Math.random() * 1000000)
|
|
27
|
+
fs = require("fs")
|
|
23
28
|
|
|
24
29
|
# Catch JavaScript errors
|
|
25
30
|
#
|
|
@@ -47,18 +52,57 @@ page.onConsoleMessage = (msg, line, source) ->
|
|
|
47
52
|
# Initialize the page before the JavaScript is run.
|
|
48
53
|
#
|
|
49
54
|
page.onInitialized = ->
|
|
55
|
+
overloadPageEvaluate(page)
|
|
56
|
+
setupWriteFileFunction(page, resultsKey, fs.separator)
|
|
57
|
+
|
|
50
58
|
page.injectJs 'lib/console.js'
|
|
51
59
|
page.injectJs 'lib/reporter.js'
|
|
60
|
+
page.injectJs 'lib/junit_reporter.js'
|
|
52
61
|
|
|
53
|
-
|
|
62
|
+
setupReporters = ->
|
|
54
63
|
# Attach the console reporter when the document is ready.
|
|
55
64
|
window.onload = ->
|
|
56
65
|
window.onload = null
|
|
57
66
|
window.resultReceived = false
|
|
58
67
|
window.reporter = new ConsoleReporter()
|
|
59
68
|
if window.jasmine
|
|
69
|
+
jasmine.getEnv().addReporter(new JUnitXmlReporter("%save_path%", "%consolidate%"))
|
|
60
70
|
jasmine.getEnv().addReporter(window.reporter)
|
|
61
71
|
|
|
72
|
+
page.evaluate(setupReporters, {save_path: options.junit_save_path, consolidate: options.junit_consolidate})
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
getXmlResults = (page, key) ->
|
|
76
|
+
getWindowObj = ->
|
|
77
|
+
window["%resultsObj%"] || {}
|
|
78
|
+
page.evaluate getWindowObj, {resultsObj: key}
|
|
79
|
+
|
|
80
|
+
replaceFunctionPlaceholders= (fn, replacements) ->
|
|
81
|
+
if replacements && typeof replacements == 'object'
|
|
82
|
+
fn = fn.toString()
|
|
83
|
+
for p of replacements
|
|
84
|
+
if replacements.hasOwnProperty(p)
|
|
85
|
+
match = new RegExp("%" + p + "%", "g")
|
|
86
|
+
loop
|
|
87
|
+
fn = fn.replace(match, replacements[p])
|
|
88
|
+
break unless fn.indexOf(match) != -1
|
|
89
|
+
fn
|
|
90
|
+
|
|
91
|
+
overloadPageEvaluate = (page) ->
|
|
92
|
+
page._evaluate = page.evaluate
|
|
93
|
+
page.evaluate = (fn, replacements) ->
|
|
94
|
+
page._evaluate(replaceFunctionPlaceholders(fn, replacements))
|
|
95
|
+
page
|
|
96
|
+
|
|
97
|
+
setupWriteFileFunction= (page,key, path_separator) ->
|
|
98
|
+
saveData = () ->
|
|
99
|
+
window["%resultsObj%"] = {}
|
|
100
|
+
window.fs_path_separator = "%fs_path_separator%"
|
|
101
|
+
window.__phantom_writeFile = (filename, text) ->
|
|
102
|
+
window["%resultsObj%"][filename] = text;
|
|
103
|
+
|
|
104
|
+
page.evaluate saveData, {resultsObj: key, fs_path_separator: path_separator}
|
|
105
|
+
|
|
62
106
|
# Open web page and run the Jasmine test runner
|
|
63
107
|
#
|
|
64
108
|
page.open options.url, (status) ->
|
|
@@ -70,7 +114,6 @@ page.open options.url, (status) ->
|
|
|
70
114
|
else
|
|
71
115
|
waitFor jasmineReady, jasmineAvailable, options.timeout, jasmineMissing
|
|
72
116
|
|
|
73
|
-
|
|
74
117
|
# Test if the jasmine has been loaded
|
|
75
118
|
#
|
|
76
119
|
jasmineReady = ->
|
|
@@ -116,6 +159,12 @@ specsTimedout = ->
|
|
|
116
159
|
console.log JSON.stringify({ error: 'Timeout for the Jasmine test results!' })
|
|
117
160
|
|
|
118
161
|
specsDone = ->
|
|
162
|
+
if options.junit == true
|
|
163
|
+
xml_results = getXmlResults(page, resultsKey)
|
|
164
|
+
for filename of xml_results
|
|
165
|
+
if xml_results.hasOwnProperty(filename) && (output = xml_results[filename]) && typeof(output) == 'string'
|
|
166
|
+
fs.write(filename, output, 'w')
|
|
167
|
+
|
|
119
168
|
phantom.exit()
|
|
120
169
|
|
|
121
170
|
# Wait until the test condition is true or a timeout occurs.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
// Generated by CoffeeScript 1.6.3
|
|
1
2
|
(function() {
|
|
2
|
-
var currentSpecId, errors, jasmineAvailable, jasmineMissing, jasmineReady, logs, options, page, specsDone, specsReady, specsTimedout, waitFor;
|
|
3
|
+
var currentSpecId, errors, fs, getXmlResults, jasmineAvailable, jasmineMissing, jasmineReady, logs, options, overloadPageEvaluate, page, replaceFunctionPlaceholders, resultsKey, setupWriteFileFunction, specsDone, specsReady, specsTimedout, waitFor;
|
|
3
4
|
|
|
4
5
|
phantom.injectJs('lib/result.js');
|
|
5
6
|
|
|
@@ -9,7 +10,10 @@
|
|
|
9
10
|
specdoc: phantom.args[2] || 'failure',
|
|
10
11
|
focus: /true/i.test(phantom.args[3]),
|
|
11
12
|
console: phantom.args[4] || 'failure',
|
|
12
|
-
errors: phantom.args[5] || 'failure'
|
|
13
|
+
errors: phantom.args[5] || 'failure',
|
|
14
|
+
junit: /true/i.test(phantom.args[6]),
|
|
15
|
+
junit_consolidate: /true/i.test(phantom.args[7]),
|
|
16
|
+
junit_save_path: phantom.args[8] || ''
|
|
13
17
|
};
|
|
14
18
|
|
|
15
19
|
page = require('webpage').create();
|
|
@@ -20,6 +24,10 @@
|
|
|
20
24
|
|
|
21
25
|
errors = {};
|
|
22
26
|
|
|
27
|
+
resultsKey = "__jr" + Math.ceil(Math.random() * 1000000);
|
|
28
|
+
|
|
29
|
+
fs = require("fs");
|
|
30
|
+
|
|
23
31
|
page.onError = function(msg, trace) {
|
|
24
32
|
if (currentSpecId) {
|
|
25
33
|
errors[currentSpecId] || (errors[currentSpecId] = []);
|
|
@@ -32,7 +40,6 @@
|
|
|
32
40
|
|
|
33
41
|
page.onConsoleMessage = function(msg, line, source) {
|
|
34
42
|
var result;
|
|
35
|
-
|
|
36
43
|
if (/^RUNNER_END$/.test(msg)) {
|
|
37
44
|
result = page.evaluate(function() {
|
|
38
45
|
return window.reporter.runnerResult;
|
|
@@ -50,17 +57,78 @@
|
|
|
50
57
|
};
|
|
51
58
|
|
|
52
59
|
page.onInitialized = function() {
|
|
60
|
+
var setupReporters;
|
|
61
|
+
overloadPageEvaluate(page);
|
|
62
|
+
setupWriteFileFunction(page, resultsKey, fs.separator);
|
|
53
63
|
page.injectJs('lib/console.js');
|
|
54
64
|
page.injectJs('lib/reporter.js');
|
|
55
|
-
|
|
65
|
+
page.injectJs('lib/junit_reporter.js');
|
|
66
|
+
setupReporters = function() {
|
|
56
67
|
return window.onload = function() {
|
|
57
68
|
window.onload = null;
|
|
58
69
|
window.resultReceived = false;
|
|
59
70
|
window.reporter = new ConsoleReporter();
|
|
60
71
|
if (window.jasmine) {
|
|
72
|
+
jasmine.getEnv().addReporter(new JUnitXmlReporter("%save_path%", "%consolidate%"));
|
|
61
73
|
return jasmine.getEnv().addReporter(window.reporter);
|
|
62
74
|
}
|
|
63
75
|
};
|
|
76
|
+
};
|
|
77
|
+
return page.evaluate(setupReporters, {
|
|
78
|
+
save_path: options.junit_save_path,
|
|
79
|
+
consolidate: options.junit_consolidate
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
getXmlResults = function(page, key) {
|
|
84
|
+
var getWindowObj;
|
|
85
|
+
getWindowObj = function() {
|
|
86
|
+
return window["%resultsObj%"] || {};
|
|
87
|
+
};
|
|
88
|
+
return page.evaluate(getWindowObj, {
|
|
89
|
+
resultsObj: key
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
replaceFunctionPlaceholders = function(fn, replacements) {
|
|
94
|
+
var match, p;
|
|
95
|
+
if (replacements && typeof replacements === 'object') {
|
|
96
|
+
fn = fn.toString();
|
|
97
|
+
for (p in replacements) {
|
|
98
|
+
if (replacements.hasOwnProperty(p)) {
|
|
99
|
+
match = new RegExp("%" + p + "%", "g");
|
|
100
|
+
while (true) {
|
|
101
|
+
fn = fn.replace(match, replacements[p]);
|
|
102
|
+
if (fn.indexOf(match) === -1) {
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return fn;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
overloadPageEvaluate = function(page) {
|
|
113
|
+
page._evaluate = page.evaluate;
|
|
114
|
+
page.evaluate = function(fn, replacements) {
|
|
115
|
+
return page._evaluate(replaceFunctionPlaceholders(fn, replacements));
|
|
116
|
+
};
|
|
117
|
+
return page;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
setupWriteFileFunction = function(page, key, path_separator) {
|
|
121
|
+
var saveData;
|
|
122
|
+
saveData = function() {
|
|
123
|
+
window["%resultsObj%"] = {};
|
|
124
|
+
window.fs_path_separator = "%fs_path_separator%";
|
|
125
|
+
return window.__phantom_writeFile = function(filename, text) {
|
|
126
|
+
return window["%resultsObj%"][filename] = text;
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
return page.evaluate(saveData, {
|
|
130
|
+
resultsObj: key,
|
|
131
|
+
fs_path_separator: path_separator
|
|
64
132
|
});
|
|
65
133
|
};
|
|
66
134
|
|
|
@@ -88,10 +156,8 @@
|
|
|
88
156
|
|
|
89
157
|
jasmineMissing = function() {
|
|
90
158
|
var error, text;
|
|
91
|
-
|
|
92
159
|
text = page.evaluate(function() {
|
|
93
160
|
var _ref;
|
|
94
|
-
|
|
95
161
|
return (_ref = document.getElementsByTagName('body')[0]) != null ? _ref.innerText : void 0;
|
|
96
162
|
});
|
|
97
163
|
if (text) {
|
|
@@ -114,10 +180,8 @@
|
|
|
114
180
|
|
|
115
181
|
specsTimedout = function() {
|
|
116
182
|
var error, text;
|
|
117
|
-
|
|
118
183
|
text = page.evaluate(function() {
|
|
119
184
|
var _ref;
|
|
120
|
-
|
|
121
185
|
return (_ref = document.getElementsByTagName('body')[0]) != null ? _ref.innerText : void 0;
|
|
122
186
|
});
|
|
123
187
|
if (text) {
|
|
@@ -133,12 +197,20 @@
|
|
|
133
197
|
};
|
|
134
198
|
|
|
135
199
|
specsDone = function() {
|
|
200
|
+
var filename, output, xml_results;
|
|
201
|
+
if (options.junit === true) {
|
|
202
|
+
xml_results = getXmlResults(page, resultsKey);
|
|
203
|
+
for (filename in xml_results) {
|
|
204
|
+
if (xml_results.hasOwnProperty(filename) && (output = xml_results[filename]) && typeof output === 'string') {
|
|
205
|
+
fs.write(filename, output, 'w');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
136
209
|
return phantom.exit();
|
|
137
210
|
};
|
|
138
211
|
|
|
139
212
|
waitFor = function(test, ready, timeout, timeoutFunction) {
|
|
140
213
|
var condition, interval, start, wait;
|
|
141
|
-
|
|
142
214
|
if (timeout == null) {
|
|
143
215
|
timeout = 10000;
|
|
144
216
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Generated by CoffeeScript 1.6.3
|
|
1
2
|
(function() {
|
|
2
3
|
var Console,
|
|
3
4
|
__slice = [].slice;
|
|
@@ -5,35 +6,29 @@
|
|
|
5
6
|
Console = (function() {
|
|
6
7
|
function Console(console) {
|
|
7
8
|
var log;
|
|
8
|
-
|
|
9
9
|
log = console.log;
|
|
10
10
|
console.log = function() {
|
|
11
11
|
var args;
|
|
12
|
-
|
|
13
12
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
14
13
|
return log.call(console, Console.format.apply(Console, args));
|
|
15
14
|
};
|
|
16
15
|
console.info = function() {
|
|
17
16
|
var args;
|
|
18
|
-
|
|
19
17
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
20
18
|
return log.call(console, "INFO: " + (Console.format.apply(Console, args)));
|
|
21
19
|
};
|
|
22
20
|
console.warn = function() {
|
|
23
21
|
var args;
|
|
24
|
-
|
|
25
22
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
26
23
|
return log.call(console, "WARN: " + (Console.format.apply(Console, args)));
|
|
27
24
|
};
|
|
28
25
|
console.error = function() {
|
|
29
26
|
var args;
|
|
30
|
-
|
|
31
27
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
32
28
|
return log.call(console, "ERROR: " + (Console.format.apply(Console, args)));
|
|
33
29
|
};
|
|
34
30
|
console.debug = function() {
|
|
35
31
|
var args;
|
|
36
|
-
|
|
37
32
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
38
33
|
return log.call(console, "DEBUG: " + (Console.format.apply(Console, args)));
|
|
39
34
|
};
|
|
@@ -44,7 +39,6 @@
|
|
|
44
39
|
Console.format = function() {
|
|
45
40
|
var arg, args, result, _i, _len,
|
|
46
41
|
_this = this;
|
|
47
|
-
|
|
48
42
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
49
43
|
result = [];
|
|
50
44
|
if (typeof args[0] === 'string' && /%[sdifo]/gi.test(args[0])) {
|
|
@@ -62,7 +56,6 @@
|
|
|
62
56
|
|
|
63
57
|
Console.inspect = function(object, type) {
|
|
64
58
|
var match, result;
|
|
65
|
-
|
|
66
59
|
switch (type) {
|
|
67
60
|
case '%s':
|
|
68
61
|
result = String(object);
|
|
@@ -100,7 +93,6 @@
|
|
|
100
93
|
|
|
101
94
|
Console.pp = function(object, depth) {
|
|
102
95
|
var key, result, type, value, _i, _len;
|
|
103
|
-
|
|
104
96
|
if (depth == null) {
|
|
105
97
|
depth = 0;
|
|
106
98
|
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
function elapsed(startTime, endTime) {
|
|
3
|
+
return (endTime - startTime)/1000;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function ISODateString(d) {
|
|
7
|
+
function pad(n) { return n < 10 ? '0'+n : n; }
|
|
8
|
+
|
|
9
|
+
return d.getFullYear() + '-' +
|
|
10
|
+
pad(d.getMonth()+1) + '-' +
|
|
11
|
+
pad(d.getDate()) + 'T' +
|
|
12
|
+
pad(d.getHours()) + ':' +
|
|
13
|
+
pad(d.getMinutes()) + ':' +
|
|
14
|
+
pad(d.getSeconds());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function trim(str) {
|
|
18
|
+
return str.replace(/^\s+/, "" ).replace(/\s+$/, "" );
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function escapeInvalidXmlChars(str) {
|
|
22
|
+
return str.replace(/\&/g, "&")
|
|
23
|
+
.replace(/</g, "<")
|
|
24
|
+
.replace(/\>/g, ">")
|
|
25
|
+
.replace(/\"/g, """)
|
|
26
|
+
.replace(/\'/g, "'");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Generates JUnit XML for the given spec run.
|
|
31
|
+
* Allows the test results to be used in java based CI
|
|
32
|
+
* systems like CruiseControl and Hudson.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} savePath where to save the files
|
|
35
|
+
* @param {boolean} consolidate whether to save nested describes within the
|
|
36
|
+
* same file as their parent; default: true
|
|
37
|
+
* @param {boolean} useDotNotation whether to separate suite names with
|
|
38
|
+
* dots rather than spaces (ie "Class.init" not
|
|
39
|
+
* "Class init"); default: true
|
|
40
|
+
*/
|
|
41
|
+
var JUnitXmlReporter = function(savePath, consolidate, useDotNotation) {
|
|
42
|
+
this.savePath = savePath || '';
|
|
43
|
+
this.consolidate = consolidate === jasmine.undefined ? true : consolidate;
|
|
44
|
+
this.useDotNotation = useDotNotation === jasmine.undefined ? true : useDotNotation;
|
|
45
|
+
};
|
|
46
|
+
JUnitXmlReporter.finished_at = null; // will be updated after all files have been written
|
|
47
|
+
|
|
48
|
+
JUnitXmlReporter.prototype = {
|
|
49
|
+
reportSpecStarting: function(spec) {
|
|
50
|
+
spec.startTime = new Date();
|
|
51
|
+
|
|
52
|
+
if (!spec.suite.startTime) {
|
|
53
|
+
spec.suite.startTime = spec.startTime;
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
reportSpecResults: function(spec) {
|
|
58
|
+
var results = spec.results();
|
|
59
|
+
spec.didFail = !results.passed();
|
|
60
|
+
spec.duration = elapsed(spec.startTime, new Date());
|
|
61
|
+
spec.output = '<testcase classname="' + this.getFullName(spec.suite) +
|
|
62
|
+
'" name="' + escapeInvalidXmlChars(spec.description) + '" time="' + spec.duration + '">';
|
|
63
|
+
if(results.skipped) {
|
|
64
|
+
spec.output = spec.output + "<skipped />";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
var failure = "";
|
|
68
|
+
var failures = 0;
|
|
69
|
+
var resultItems = results.getItems();
|
|
70
|
+
for (var i = 0; i < resultItems.length; i++) {
|
|
71
|
+
var result = resultItems[i];
|
|
72
|
+
|
|
73
|
+
if (result.type == 'expect' && result.passed && !result.passed()) {
|
|
74
|
+
failures += 1;
|
|
75
|
+
failure += '<failure type="' + result.type + '" message="' + trim(escapeInvalidXmlChars(result.message)) + '">';
|
|
76
|
+
failure += escapeInvalidXmlChars(result.trace.stack || result.message);
|
|
77
|
+
failure += "</failure>";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (failure) {
|
|
81
|
+
spec.output += failure;
|
|
82
|
+
}
|
|
83
|
+
spec.output += "</testcase>";
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
reportSuiteResults: function(suite) {
|
|
87
|
+
var results = suite.results();
|
|
88
|
+
var specs = suite.specs();
|
|
89
|
+
var specOutput = "";
|
|
90
|
+
// for JUnit results, let's only include directly failed tests (not nested suites')
|
|
91
|
+
var failedCount = 0;
|
|
92
|
+
|
|
93
|
+
suite.status = results.passed() ? 'Passed.' : 'Failed.';
|
|
94
|
+
if (results.totalCount === 0) { // todo: change this to check results.skipped
|
|
95
|
+
suite.status = 'Skipped.';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// if a suite has no (active?) specs, reportSpecStarting is never called
|
|
99
|
+
// and thus the suite has no startTime -- account for that here
|
|
100
|
+
suite.startTime = suite.startTime || new Date();
|
|
101
|
+
suite.duration = elapsed(suite.startTime, new Date());
|
|
102
|
+
|
|
103
|
+
for (var i = 0; i < specs.length; i++) {
|
|
104
|
+
failedCount += specs[i].didFail ? 1 : 0;
|
|
105
|
+
specOutput += "\n " + specs[i].output;
|
|
106
|
+
}
|
|
107
|
+
suite.output = '\n<testsuite name="' + this.getFullName(suite) +
|
|
108
|
+
'" errors="0" tests="' + specs.length + '" failures="' + failedCount +
|
|
109
|
+
'" time="' + suite.duration + '" timestamp="' + ISODateString(suite.startTime) + '">';
|
|
110
|
+
suite.output += specOutput;
|
|
111
|
+
suite.output += "\n</testsuite>";
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
reportRunnerResults: function(runner) {
|
|
115
|
+
var suites = runner.suites();
|
|
116
|
+
for (var i = 0; i < suites.length; i++) {
|
|
117
|
+
var suite = suites[i];
|
|
118
|
+
var fileName = 'TEST-' + this.getFullName(suite, true) + '.xml';
|
|
119
|
+
var output = '<?xml version="1.0" encoding="UTF-8" ?>';
|
|
120
|
+
// if we are consolidating, only write out top-level suites
|
|
121
|
+
if (this.consolidate && suite.parentSuite) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
else if (this.consolidate) {
|
|
125
|
+
output += "\n<testsuites>";
|
|
126
|
+
output += this.getNestedOutput(suite);
|
|
127
|
+
output += "\n</testsuites>";
|
|
128
|
+
this.writeFile(this.savePath, fileName, output);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
output += suite.output;
|
|
132
|
+
this.writeFile(this.savePath, fileName, output);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// When all done, make it known on JUnitXmlReporter
|
|
136
|
+
JUnitXmlReporter.finished_at = (new Date()).getTime();
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
getNestedOutput: function(suite) {
|
|
140
|
+
var output = suite.output;
|
|
141
|
+
for (var i = 0; i < suite.suites().length; i++) {
|
|
142
|
+
output += this.getNestedOutput(suite.suites()[i]);
|
|
143
|
+
}
|
|
144
|
+
return output;
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
writeFile: function(path, filename, text) {
|
|
148
|
+
function getQualifiedFilename(separator) {
|
|
149
|
+
if (path && path.substr(-1) !== separator && filename.substr(0) !== separator) {
|
|
150
|
+
path += separator;
|
|
151
|
+
}
|
|
152
|
+
return path + filename;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Rhino
|
|
156
|
+
try {
|
|
157
|
+
// turn filename into a qualified path
|
|
158
|
+
if (path) {
|
|
159
|
+
filename = getQualifiedFilename(java.lang.System.getProperty("file.separator"));
|
|
160
|
+
// create parent dir and ancestors if necessary
|
|
161
|
+
var file = java.io.File(filename);
|
|
162
|
+
var parentDir = file.getParentFile();
|
|
163
|
+
if (!parentDir.exists()) {
|
|
164
|
+
parentDir.mkdirs();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// finally write the file
|
|
168
|
+
var out = new java.io.BufferedWriter(new java.io.FileWriter(filename));
|
|
169
|
+
out.write(text);
|
|
170
|
+
out.close();
|
|
171
|
+
return;
|
|
172
|
+
} catch (e) {}
|
|
173
|
+
// PhantomJS, via a method injected by phantomjs-testrunner.js
|
|
174
|
+
try {
|
|
175
|
+
// turn filename into a qualified path
|
|
176
|
+
filename = getQualifiedFilename(window.fs_path_separator);
|
|
177
|
+
__phantom_writeFile(filename, text);
|
|
178
|
+
return;
|
|
179
|
+
} catch (f) {}
|
|
180
|
+
// Node.js
|
|
181
|
+
try {
|
|
182
|
+
var fs = require("fs");
|
|
183
|
+
var nodejs_path = require("path");
|
|
184
|
+
var fd = fs.openSync(nodejs_path.join(path, filename), "w");
|
|
185
|
+
fs.writeSync(fd, text, 0);
|
|
186
|
+
fs.closeSync(fd);
|
|
187
|
+
return;
|
|
188
|
+
} catch (g) {}
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
getFullName: function(suite, isFilename) {
|
|
192
|
+
var fullName;
|
|
193
|
+
if (this.useDotNotation) {
|
|
194
|
+
fullName = suite.description;
|
|
195
|
+
for (var parentSuite = suite.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
|
|
196
|
+
fullName = parentSuite.description + '.' + fullName;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
fullName = suite.getFullName();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Either remove or escape invalid XML characters
|
|
204
|
+
if (isFilename) {
|
|
205
|
+
return fullName.replace(/[^\w]/g, "");
|
|
206
|
+
}
|
|
207
|
+
return escapeInvalidXmlChars(fullName);
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
log: function(str) {
|
|
211
|
+
var console = jasmine.getGlobal().console;
|
|
212
|
+
|
|
213
|
+
if (console && console.log) {
|
|
214
|
+
console.log(str);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
220
|
+
module.exports = JUnitXmlReporter;
|
|
221
|
+
} else {
|
|
222
|
+
window.JUnitXmlReporter = JUnitXmlReporter;
|
|
223
|
+
}
|
|
224
|
+
}).call(this);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Generated by CoffeeScript 1.6.3
|
|
1
2
|
(function() {
|
|
2
3
|
var ConsoleReporter;
|
|
3
4
|
|
|
@@ -26,7 +27,6 @@
|
|
|
26
27
|
|
|
27
28
|
ConsoleReporter.prototype.reportSpecResults = function(spec) {
|
|
28
29
|
var messages, result, specResult, _base, _i, _len, _name, _ref;
|
|
29
|
-
|
|
30
30
|
if (!spec.results().skipped) {
|
|
31
31
|
specResult = {
|
|
32
32
|
id: spec.id,
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
|
|
53
53
|
ConsoleReporter.prototype.reportSuiteResults = function(suite) {
|
|
54
54
|
var parent, suiteResult, _base, _ref;
|
|
55
|
-
|
|
56
55
|
if (!suite.results().skipped) {
|
|
57
56
|
suiteResult = {
|
|
58
57
|
id: suite.id,
|
|
@@ -78,7 +77,6 @@
|
|
|
78
77
|
|
|
79
78
|
ConsoleReporter.prototype.reportRunnerResults = function(runner) {
|
|
80
79
|
var end, runtime;
|
|
81
|
-
|
|
82
80
|
runtime = (new Date().getTime() - this.startTime) / 1000;
|
|
83
81
|
this.runnerResult['passed'] = runner.results().failedCount === 0;
|
|
84
82
|
this.runnerResult['stats'] = {
|
|
@@ -101,7 +99,6 @@
|
|
|
101
99
|
|
|
102
100
|
ConsoleReporter.prototype.addNestedSuites = function(suiteResult) {
|
|
103
101
|
var suite, _i, _len, _ref, _results;
|
|
104
|
-
|
|
105
102
|
if (this.nestedSuiteResults[suiteResult.id]) {
|
|
106
103
|
_ref = this.nestedSuiteResults[suiteResult.id];
|
|
107
104
|
_results = [];
|
|
@@ -116,7 +113,6 @@
|
|
|
116
113
|
|
|
117
114
|
ConsoleReporter.prototype.removeEmptySuites = function(suiteResult) {
|
|
118
115
|
var suite, suites, _i, _len, _ref;
|
|
119
|
-
|
|
120
116
|
suites = [];
|
|
121
117
|
_ref = suiteResult.suites;
|
|
122
118
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Generated by CoffeeScript 1.6.3
|
|
1
2
|
(function() {
|
|
2
3
|
var Result;
|
|
3
4
|
|
|
@@ -11,10 +12,8 @@
|
|
|
11
12
|
|
|
12
13
|
Result.prototype.addLogs = function(suite) {
|
|
13
14
|
var id, s, spec;
|
|
14
|
-
|
|
15
15
|
suite.suites = (function() {
|
|
16
16
|
var _i, _len, _ref, _results;
|
|
17
|
-
|
|
18
17
|
_ref = suite.suites;
|
|
19
18
|
_results = [];
|
|
20
19
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
@@ -26,7 +25,6 @@
|
|
|
26
25
|
if (suite.specs) {
|
|
27
26
|
suite.specs = (function() {
|
|
28
27
|
var _i, _len, _ref, _results;
|
|
29
|
-
|
|
30
28
|
_ref = suite.specs;
|
|
31
29
|
_results = [];
|
|
32
30
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
@@ -47,10 +45,8 @@
|
|
|
47
45
|
|
|
48
46
|
Result.prototype.addErrors = function(suite) {
|
|
49
47
|
var id, s, spec;
|
|
50
|
-
|
|
51
48
|
suite.suites = (function() {
|
|
52
49
|
var _i, _len, _ref, _results;
|
|
53
|
-
|
|
54
50
|
_ref = suite.suites;
|
|
55
51
|
_results = [];
|
|
56
52
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
@@ -62,7 +58,6 @@
|
|
|
62
58
|
if (suite.specs) {
|
|
63
59
|
suite.specs = (function() {
|
|
64
60
|
var _i, _len, _ref, _results;
|
|
65
|
-
|
|
66
61
|
_ref = suite.specs;
|
|
67
62
|
_results = [];
|
|
68
63
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
@@ -83,7 +78,6 @@
|
|
|
83
78
|
|
|
84
79
|
Result.prototype.addGlobalError = function(suite) {
|
|
85
80
|
var b, err, errMsg, globalErrors, noSpecs, noSuites, _i, _len, _ref;
|
|
86
|
-
|
|
87
81
|
noSuites = !suite.suites || suite.suites.length === 0;
|
|
88
82
|
noSpecs = !suite.specs || suite.specs.length === 0;
|
|
89
83
|
globalErrors = this.errors[-1] && this.errors[-1].length !== 0;
|
|
@@ -102,10 +96,8 @@
|
|
|
102
96
|
|
|
103
97
|
Result.prototype.cleanResult = function(suite) {
|
|
104
98
|
var s, spec, _i, _len, _ref;
|
|
105
|
-
|
|
106
99
|
suite.suites = (function() {
|
|
107
100
|
var _i, _len, _ref, _results;
|
|
108
|
-
|
|
109
101
|
_ref = suite.suites;
|
|
110
102
|
_results = [];
|
|
111
103
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
data/lib/guard/jasmine/runner.rb
CHANGED
|
@@ -94,7 +94,19 @@ module Guard
|
|
|
94
94
|
def run_jasmine_spec(file, options)
|
|
95
95
|
suite = jasmine_suite(file, options)
|
|
96
96
|
Formatter.info("Run Jasmine suite at #{ suite }")
|
|
97
|
-
|
|
97
|
+
|
|
98
|
+
arguments = [
|
|
99
|
+
options[:timeout] * 1000,
|
|
100
|
+
options[:specdoc],
|
|
101
|
+
options[:focus],
|
|
102
|
+
options[:console],
|
|
103
|
+
options[:errors],
|
|
104
|
+
options[:junit],
|
|
105
|
+
options[:junit_consolidate],
|
|
106
|
+
"'#{ options[:junit_save_path] }'"
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
IO.popen("#{ phantomjs_command(options) } \"#{ suite }\" #{ arguments.collect { |i| i.to_s }.join(' ')}", 'r:UTF-8')
|
|
98
110
|
end
|
|
99
111
|
|
|
100
112
|
# Get the PhantomJS binary and script to execute.
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: guard-jasmine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.18.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Kessler
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2013-06
|
|
11
|
+
date: 2013-08-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: guard
|
|
@@ -112,6 +112,7 @@ files:
|
|
|
112
112
|
- lib/guard/jasmine/phantomjs/guard-jasmine.coffee
|
|
113
113
|
- lib/guard/jasmine/phantomjs/guard-jasmine.js
|
|
114
114
|
- lib/guard/jasmine/phantomjs/lib/console.js
|
|
115
|
+
- lib/guard/jasmine/phantomjs/lib/junit_reporter.js
|
|
115
116
|
- lib/guard/jasmine/phantomjs/lib/reporter.js
|
|
116
117
|
- lib/guard/jasmine/phantomjs/lib/result.js
|
|
117
118
|
- lib/guard/jasmine/phantomjs/src/console.coffee
|
|
@@ -148,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
148
149
|
version: 1.3.6
|
|
149
150
|
requirements: []
|
|
150
151
|
rubyforge_project: guard-jasmine
|
|
151
|
-
rubygems_version: 2.0.
|
|
152
|
+
rubygems_version: 2.0.3
|
|
152
153
|
signing_key:
|
|
153
154
|
specification_version: 4
|
|
154
155
|
summary: Guard gem for headless testing with Jasmine
|