guard-jasmine 1.17.0 → 1.18.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 60fc1ca74efcf8df719d1d9943044e0ad59d51a3
4
- data.tar.gz: 24ef532486b920209d34741b4c7bce58b5ef8c53
3
+ metadata.gz: f8a880f0eac45a32232516339a2591ff56af0a4f
4
+ data.tar.gz: be38c7d0218b9354e3f4e84dd4683bc73ff7709b
5
5
  SHA512:
6
- metadata.gz: d62f8ea0aed0bbd2e856c1c7a9cf50fb43b9d8f9a92ca7a936a74136b7011c72b185955ccda13e07f9eadc4939c6eef02cda1278d71b6128dafa916116f725d5
7
- data.tar.gz: b5466cd09a10167866e6fa4c9ee439cb7afee8c420799b7747e182003b64faab1c910af3ba8e8165bfe06cf4213364ce64b616794088c3374ed9d5352c8fa059
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
@@ -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'
@@ -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[:jasmine_url] = options.url || "http://localhost:#{ runner_options[:port] }#{ options.server.to_sym == :jasmine_gem ? '/' : '/jasmine' }"
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
- page.evaluate ->
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
- return page.evaluate(function() {
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, "&amp;")
23
+ .replace(/</g, "&lt;")
24
+ .replace(/\>/g, "&gt;")
25
+ .replace(/\"/g, "&quot;")
26
+ .replace(/\'/g, "&apos;");
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++) {
@@ -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
- IO.popen("#{ phantomjs_command(options) } \"#{ suite }\" #{ options[:timeout] * 1000 } #{ options[:specdoc] } #{ options[:focus] } #{ options[:console] } #{ options[:errors] }", 'r:UTF-8')
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.
@@ -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.17.0'
4
+ VERSION = '1.18.0'
5
5
  end
6
6
  end
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.17.0
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-27 00:00:00.000000000 Z
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.2
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