jasmine-headless-webkit 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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