jasmine-headless-webkit 0.6.1 → 0.6.2

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.
@@ -1,429 +1,68 @@
1
1
  /*
2
- Copyright (c) 2010 Sencha Inc.
3
- Copyright (c) 2011 John Bintz
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
22
- */
23
-
24
- #include <QtGui>
25
- #include <QtWebKit>
26
- #include <QFile>
27
- #include <QTextStream>
28
- #include <iostream>
29
- #include <QQueue>
2
+ Copyright (c) 2010 Sencha Inc.
3
+ Copyright (c) 2011 John Bintz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+ */
23
+
24
+ #include "HeadlessSpecRunner/Page.h"
25
+ #include "HeadlessSpecRunner/Runner.h"
30
26
 
31
27
  #if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)
32
28
  #error Use Qt 4.7 or later version
33
29
  #endif
34
30
 
35
- class HeadlessSpecRunnerPage: public QWebPage
36
- {
37
- Q_OBJECT
38
- public:
39
- HeadlessSpecRunnerPage();
40
- void oneFalseConfirm();
41
- signals:
42
- void consoleLog(const QString &msg, int lineNumber, const QString &sourceID);
43
- void internalLog(const QString &note, const QString &msg);
44
- protected:
45
- void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID);
46
- bool javaScriptConfirm(QWebFrame *frame, const QString &msg);
47
- void javaScriptAlert(QWebFrame *frame, const QString &msg);
48
- private:
49
- bool confirmResult;
50
- };
51
-
52
- HeadlessSpecRunnerPage::HeadlessSpecRunnerPage()
53
- : QWebPage()
54
- , confirmResult(true)
55
- {
56
-
57
- }
58
-
59
- void HeadlessSpecRunnerPage::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID)
60
- {
61
- emit consoleLog(message, lineNumber, sourceID);
62
- }
63
-
64
- bool HeadlessSpecRunnerPage::javaScriptConfirm(QWebFrame *frame, const QString &msg)
65
- {
66
- if (confirmResult) {
67
- emit internalLog("TODO", "jasmine-headless-webkit can't handle confirm() yet! You should mock window.confirm for now. Returning true.");
68
- return true;
69
- } else {
70
- confirmResult = true;
71
- return false;
72
- }
73
- }
74
-
75
- void HeadlessSpecRunnerPage::javaScriptAlert(QWebFrame *frame, const QString &msg)
76
- {
77
- emit internalLog("alert", msg);
78
- }
79
-
80
- void HeadlessSpecRunnerPage::oneFalseConfirm()
81
- {
82
- confirmResult = false;
83
- }
84
-
85
- class HeadlessSpecRunner: public QObject
86
- {
87
- Q_OBJECT
88
- public:
89
- HeadlessSpecRunner();
90
- void setColors(bool colors);
91
- void reportFile(const QString &file);
92
- void addFile(const QString &spec);
93
- void go();
94
- public slots:
95
- void log(const QString &msg);
96
- void leavePageAttempt(const QString &msg);
97
- void specPassed();
98
- void specFailed(const QString &specDetail);
99
- void printName(const QString &name);
100
- void printResult(const QString &result);
101
- void finishSuite(const QString &duration, const QString &total, const QString& failed);
102
- private slots:
103
- void watch(bool ok);
104
- void errorLog(const QString &msg, int lineNumber, const QString &sourceID);
105
- void internalLog(const QString &note, const QString &msg);
106
- void addJHW();
107
- protected:
108
- bool hasElement(const char *select);
109
- void timerEvent(QTimerEvent *event);
110
- private:
111
- HeadlessSpecRunnerPage m_page;
112
- QBasicTimer m_ticker;
113
- int m_runs;
114
- bool hasErrors;
115
- bool usedConsole;
116
- bool showColors;
117
- bool isFinished;
118
- bool didFail;
119
- bool consoleNotUsedThisRun;
120
- QQueue<QString> runnerFiles;
121
- QString reportFilename;
122
- QStack<QString> failedSpecs;
123
-
124
- void red();
125
- void green();
126
- void yellow();
127
- void clear();
128
- void loadSpec();
129
- };
130
-
131
- HeadlessSpecRunner::HeadlessSpecRunner()
132
- : QObject()
133
- , m_runs(0)
134
- , hasErrors(false)
135
- , usedConsole(false)
136
- , showColors(false)
137
- , isFinished(false)
138
- , didFail(false)
139
- , consoleNotUsedThisRun(false)
140
- {
141
- m_page.settings()->enablePersistentStorage();
142
- connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(watch(bool)));
143
- connect(&m_page, SIGNAL(consoleLog(QString, int, QString)), this, SLOT(errorLog(QString, int, QString)));
144
- connect(&m_page, SIGNAL(internalLog(QString, QString)), this, SLOT(internalLog(QString, QString)));
145
- connect(m_page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(addJHW()));
146
- }
147
-
148
- void HeadlessSpecRunner::addFile(const QString &spec)
149
- {
150
- runnerFiles.enqueue(spec);
151
- }
152
-
153
- void HeadlessSpecRunner::go()
154
- {
155
- m_ticker.stop();
156
- m_page.setPreferredContentsSize(QSize(1024, 600));
157
- addJHW();
158
- loadSpec();
159
- }
160
- void HeadlessSpecRunner::addJHW()
31
+ int main(int argc, char** argv)
161
32
  {
162
- m_page.mainFrame()->addToJavaScriptWindowObject("JHW", this);
163
- }
33
+ char *reporter = NULL;
34
+ char showColors = false;
164
35
 
165
- void HeadlessSpecRunner::loadSpec()
166
- {
167
- m_page.mainFrame()->load(runnerFiles.dequeue());
168
- m_ticker.start(200, this);
169
- }
36
+ int c, index;
170
37
 
171
- void HeadlessSpecRunner::watch(bool ok)
172
- {
173
- if (!ok) {
174
- std::cerr << "Can't load " << qPrintable(m_page.mainFrame()->url().toString()) << ", the file may be broken." << std::endl;
175
- std::cerr << "Out of curiosity, did your tests try to submit a form and you haven't prevented that?" << std::endl;
176
- std::cerr << "Try running your tests in your browser with the Jasmine server and see what happens." << std::endl;
177
- QApplication::instance()->exit(1);
178
- return;
38
+ while ((c = getopt(argc, argv, "cr:")) != -1) {
39
+ switch(c) {
40
+ case 'c':
41
+ showColors = true;
42
+ break;
43
+ case 'r':
44
+ reporter = optarg;
45
+ break;
179
46
  }
180
-
181
- m_ticker.start(200, this);
182
- }
183
-
184
- bool HeadlessSpecRunner::hasElement(const char *select)
185
- {
186
- return !m_page.mainFrame()->findFirstElement(select).isNull();
187
- }
188
-
189
- void HeadlessSpecRunner::setColors(bool colors)
190
- {
191
- showColors = colors;
192
- }
193
-
194
- void HeadlessSpecRunner::reportFile(const QString &file)
195
- {
196
- reportFilename = file;
197
- }
198
-
199
- void HeadlessSpecRunner::red()
200
- {
201
- if (showColors) std::cout << "\033[0;31m";
202
- }
203
-
204
- void HeadlessSpecRunner::green()
205
- {
206
- if (showColors) std::cout << "\033[0;32m";
207
- }
208
-
209
- void HeadlessSpecRunner::yellow()
210
- {
211
- if (showColors) std::cout << "\033[0;33m";
212
- }
213
-
214
- void HeadlessSpecRunner::clear()
215
- {
216
- if (showColors) std::cout << "\033[m";
217
- }
218
-
219
- void HeadlessSpecRunner::specPassed()
220
- {
221
- consoleNotUsedThisRun = true;
222
- green();
223
- std::cout << '.';
224
- clear();
225
- fflush(stdout);
226
- }
227
-
228
- void HeadlessSpecRunner::specFailed(const QString &specDetail)
229
- {
230
- consoleNotUsedThisRun = true;
231
- didFail = true;
232
- red();
233
- std::cout << 'F';
234
- failedSpecs.push(specDetail);
235
- clear();
236
- fflush(stdout);
237
- }
238
-
239
- void HeadlessSpecRunner::errorLog(const QString &msg, int lineNumber, const QString &sourceID)
240
- {
241
- red();
242
- std::cout << "[error] ";
243
- clear();
244
- std::cout << qPrintable(sourceID) << ":" << lineNumber << " : " << qPrintable(msg);
245
- std::cout << std::endl;
246
-
247
- hasErrors = true;
248
- m_runs = 0;
249
- m_ticker.start(200, this);
250
- }
251
-
252
- void HeadlessSpecRunner::internalLog(const QString &note, const QString &msg) {
253
- red();
254
- std::cout << "[" << qPrintable(note) << "] ";
255
- clear();
256
- std::cout << qPrintable(msg);
257
- std::cout << std::endl;
258
- }
259
-
260
- void HeadlessSpecRunner::log(const QString &msg)
261
- {
262
- usedConsole = true;
263
- green();
264
- if (consoleNotUsedThisRun) {
265
- std::cout << std::endl;
266
- consoleNotUsedThisRun = false;
267
47
  }
268
- std::cout << "[console] ";
269
- clear();
270
- if (msg.contains("\n"))
271
- std::cout << std::endl;
272
- std::cout << qPrintable(msg);
273
- std::cout << std::endl;
274
- }
275
48
 
276
- void HeadlessSpecRunner::leavePageAttempt(const QString &msg)
277
- {
278
- red();
279
- std::cout << "[error] ";
280
- clear();
281
- std::cout << qPrintable(msg) << std::endl;
282
- m_page.oneFalseConfirm();
283
- hasErrors = true;
284
- }
285
-
286
- void HeadlessSpecRunner::printName(const QString &name)
287
- {
288
- std::cout << std::endl << std::endl;
289
- red();
290
- std::cout << qPrintable(name) << std::endl;
291
- clear();
292
- }
293
-
294
- void HeadlessSpecRunner::printResult(const QString &result)
295
- {
296
- red();
297
- std::cout << " " << qPrintable(result) << std::endl;
298
- clear();
299
- }
300
-
301
- void HeadlessSpecRunner::finishSuite(const QString &duration, const QString &total, const QString& failed)
302
- {
303
- std::cout << std::endl;
304
- if (didFail) {
305
- red();
306
- std::cout << "FAIL: ";
307
- } else {
308
- green();
309
- std::cout << "PASS";
310
-
311
- if (hasErrors) {
312
- std::cout << " with JS errors";
313
- }
314
-
315
- std::cout << ": ";
49
+ if (optind == argc) {
50
+ std::cerr << "Run Jasmine's SpecRunner headlessly" << std::endl << std::endl;
51
+ std::cerr << " specrunner [-c] [-r <report file>] specrunner.html ..." << std::endl;
52
+ return 1;
316
53
  }
317
54
 
318
- std::cout << qPrintable(total) << " tests, " << qPrintable(failed) << " failures, " << qPrintable(duration) << " secs.";
319
- clear();
320
- std::cout << std::endl;
321
-
322
- if (!reportFilename.isEmpty()) {
323
- QFile reportFH(reportFilename);
324
-
325
- if (reportFH.open(QFile::WriteOnly)) {
326
- QTextStream report(&reportFH);
327
- report << qPrintable(total) << "/" << qPrintable(failed) << "/";
328
- report << (usedConsole ? "T" : "F");
329
- report << "/" << qPrintable(duration) << "\n";
55
+ QApplication app(argc, argv);
56
+ app.setApplicationName("jasmine-headless-webkit");
57
+ HeadlessSpecRunner::Runner runner;
58
+ runner.setColors(showColors);
59
+ runner.reportFile(reporter);
330
60
 
331
- QString failedSpec;
332
-
333
- while (!failedSpecs.isEmpty()) {
334
- failedSpec = failedSpecs.pop();
335
- report << qPrintable(failedSpec) << "\n";
336
- }
337
-
338
- reportFH.close();
339
- }
61
+ for (index = optind; index < argc; index++) {
62
+ runner.addFile(QString::fromLocal8Bit(argv[index]));
340
63
  }
64
+ runner.go();
341
65
 
342
- isFinished = true;
343
- }
344
-
345
- void HeadlessSpecRunner::timerEvent(QTimerEvent *event)
346
- {
347
- ++m_runs;
348
-
349
- if (event->timerId() != m_ticker.timerId())
350
- return;
351
-
352
- if (hasErrors && m_runs > 2)
353
- QApplication::instance()->exit(1);
354
-
355
- if (isFinished) {
356
- int exitCode = 0;
357
- if (didFail || hasErrors) {
358
- exitCode = 1;
359
- } else {
360
- if (usedConsole) {
361
- exitCode = 2;
362
- }
363
- }
364
-
365
- bool runAgain = true;
366
-
367
- if (runnerFiles.count() == 0) {
368
- runAgain = false;
369
- } else {
370
- if (exitCode == 1) {
371
- runAgain = false;
372
- }
373
- }
374
-
375
- if (runAgain) {
376
- isFinished = false;
377
- loadSpec();
378
- } else {
379
- QApplication::instance()->exit(exitCode);
380
- }
381
- }
382
-
383
- if (m_runs > 30) {
384
- std::cout << "WARNING: too many runs and the test is still not finished!" << std::endl;
385
- QApplication::instance()->exit(1);
386
- }
387
- }
388
-
389
- #include "specrunner.moc"
390
-
391
- int main(int argc, char** argv)
392
- {
393
- char *reporter = NULL;
394
- char showColors = false;
395
-
396
- int c, index;
397
-
398
- while ((c = getopt(argc, argv, "cr:")) != -1) {
399
- switch(c) {
400
- case 'c':
401
- showColors = true;
402
- break;
403
- case 'r':
404
- reporter = optarg;
405
- break;
406
- }
407
- }
408
-
409
- if (optind == argc) {
410
- std::cerr << "Run Jasmine's SpecRunner headlessly" << std::endl << std::endl;
411
- std::cerr << " specrunner [-c] [-r <report file>] specrunner.html ..." << std::endl;
412
- return 1;
413
- }
414
-
415
- QApplication app(argc, argv);
416
- app.setApplicationName("jasmine-headless-webkit");
417
- HeadlessSpecRunner runner;
418
- runner.setColors(showColors);
419
- runner.reportFile(reporter);
420
-
421
- for (index = optind; index < argc; index++) {
422
- runner.addFile(QString::fromLocal8Bit(argv[index]));
423
- }
424
- runner.go();
425
-
426
- return app.exec();
66
+ return app.exec();
427
67
  }
428
68
 
429
-
@@ -1,7 +1,8 @@
1
1
  TEMPLATE = app
2
2
  CONFIG -= app_bundle
3
3
  TARGET = jasmine-webkit-specrunner
4
- SOURCES = specrunner.cpp
4
+ SOURCES = HeadlessSpecRunner/Page.cpp HeadlessSpecRunner/Runner.cpp specrunner.cpp
5
+ HEADERS = HeadlessSpecRunner/Page.h HeadlessSpecRunner/Runner.h
5
6
  QT += network webkit
6
7
  QMAKE_INFO_PLIST = Info.plist
7
8
  QMAKESPEC = macx-gcc
@@ -54,6 +54,8 @@ class jasmine.HeadlessReporter
54
54
  @failedCount = 0
55
55
  @length = 0
56
56
  reportRunnerResults: (runner) ->
57
+ return if this.hasError()
58
+
57
59
  for result in @results
58
60
  result.print()
59
61
 
@@ -62,6 +64,8 @@ class jasmine.HeadlessReporter
62
64
  reportRunnerStarting: (runner) ->
63
65
  @startTime = new Date()
64
66
  reportSpecResults: (spec) ->
67
+ return if this.hasError()
68
+
65
69
  results = spec.results()
66
70
  @length++
67
71
  if results.passed()
@@ -75,4 +79,10 @@ class jasmine.HeadlessReporter
75
79
  failureResult.addResult(result.message)
76
80
  @results.push(failureResult)
77
81
  reportSpecStarting: (spec) ->
82
+ if this.hasError()
83
+ spec.finish()
84
+ spec.suite.finish()
78
85
  reportSuiteResults: (suite) ->
86
+ hasError: ->
87
+ JHW.hasError()
88
+
@@ -88,6 +88,9 @@
88
88
  }
89
89
  HeadlessReporter.prototype.reportRunnerResults = function(runner) {
90
90
  var result, _i, _len, _ref;
91
+ if (this.hasError()) {
92
+ return;
93
+ }
91
94
  _ref = this.results;
92
95
  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
93
96
  result = _ref[_i];
@@ -103,6 +106,9 @@
103
106
  };
104
107
  HeadlessReporter.prototype.reportSpecResults = function(spec) {
105
108
  var failureResult, result, results, _i, _len, _ref;
109
+ if (this.hasError()) {
110
+ return;
111
+ }
106
112
  results = spec.results();
107
113
  this.length++;
108
114
  if (results.passed()) {
@@ -121,8 +127,16 @@
121
127
  return this.results.push(failureResult);
122
128
  }
123
129
  };
124
- HeadlessReporter.prototype.reportSpecStarting = function(spec) {};
130
+ HeadlessReporter.prototype.reportSpecStarting = function(spec) {
131
+ if (this.hasError()) {
132
+ spec.finish();
133
+ return spec.suite.finish();
134
+ }
135
+ };
125
136
  HeadlessReporter.prototype.reportSuiteResults = function(suite) {};
137
+ HeadlessReporter.prototype.hasError = function() {
138
+ return JHW.hasError();
139
+ };
126
140
  return HeadlessReporter;
127
141
  })();
128
142
  }).call(this);
@@ -1,4 +1,5 @@
1
1
  require 'jasmine-core'
2
+ require 'iconv'
2
3
 
3
4
  module Jasmine
4
5
  class FilesList
@@ -14,7 +15,9 @@ module Jasmine
14
15
  def get_spec_line_numbers(file)
15
16
  line_numbers = {}
16
17
 
18
+ ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
17
19
  file.lines.each_with_index.each { |line, index|
20
+ line = ic.iconv(line + ' ')[0..-2]
18
21
  if description = line[%r{(describe|context|it)[( ]*(["'])(.*)\2}, 3]
19
22
  (line_numbers[description] ||= []) << (index + 1)
20
23
  end
@@ -31,8 +34,6 @@ module Jasmine
31
34
  @spec_outside_scope = false
32
35
  @spec_files = []
33
36
  use_config! if config?
34
-
35
- @code_for_file = {}
36
37
  end
37
38
 
38
39
  def has_spec_outside_scope?
@@ -68,8 +69,6 @@ module Jasmine
68
69
  coffeescript_run = []
69
70
 
70
71
  files.collect { |file|
71
- next @code_for_file[file] if @code_for_file[file]
72
-
73
72
  coffeescript_run << file if (ext = File.extname(file)) == '.coffee'
74
73
 
75
74
  output = []
@@ -86,8 +85,6 @@ module Jasmine
86
85
  end
87
86
  end
88
87
 
89
- @code_for_file[file] = output if output.length == 1
90
-
91
88
  output
92
89
  }.flatten.reject(&:empty?)
93
90
  end
@@ -24,6 +24,7 @@ module Jasmine
24
24
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
25
25
  <html>
26
26
  <head>
27
+ <meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
27
28
  <title>Jasmine Test Runner</title>
28
29
  <script type="text/javascript">
29
30
  window.console = { log: function(data) {
@@ -1,7 +1,7 @@
1
1
  module Jasmine
2
2
  module Headless
3
3
  module Webkit
4
- VERSION = "0.6.1"
4
+ VERSION = "0.6.2"
5
5
  end
6
6
  end
7
7
  end
@@ -5,5 +5,5 @@ module Jasmine
5
5
  end
6
6
  end
7
7
 
8
- require 'jasmine/headless/railtie' if defined?(Rails)
8
+ require 'jasmine/headless/railtie' if defined?(Rails) && Rails::VERSION::MAJOR >= 3
9
9