jasmine-headless-webkit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.gitmodules +3 -0
- data/Gemfile +4 -0
- data/README.md +51 -0
- data/Rakefile +2 -0
- data/bin/jasmine-headless-webkit +71 -0
- data/ext/jasmine-webkit-specrunner/Info.plist +22 -0
- data/ext/jasmine-webkit-specrunner/extconf.rb +2 -0
- data/ext/jasmine-webkit-specrunner/specrunner.cpp +164 -0
- data/ext/jasmine-webkit-specrunner/specrunner.pro +7 -0
- data/jasmine/lib/jasmine-html.js +190 -0
- data/jasmine/lib/jasmine.css +166 -0
- data/jasmine/lib/jasmine.js +2435 -0
- data/jasmine/lib/json2.js +478 -0
- data/jasmine-headless-webkit.gemspec +24 -0
- data/lib/jasmine-headless-webkit/version.rb +7 -0
- data/lib/jasmine-headless-webkit.rb +7 -0
- metadata +99 -0
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Jasmine Headless WebKit runner
|
2
|
+
|
3
|
+
## Introduction
|
4
|
+
|
5
|
+
This gem works with projects that use the [Jasmine gem](https://github.com/pivotal/jasmine-gem) to
|
6
|
+
create a `jasmine.yml` file defining what to test. The runner loads that
|
7
|
+
`jasmine.yml` file and executes the
|
8
|
+
tests in a Qt WebKit widget, displaying the results to the console and setting the exit code to 0 for
|
9
|
+
success or 1 for failure.
|
10
|
+
|
11
|
+
`console.log` works, too, so you can run your specs side-by-side in a browser if you're so inclined.
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
jasmine-headless-webkit [path to jasmine.yml, defaults to spec/javascripts/support/jasmine.yml]
|
16
|
+
|
17
|
+
*This gem is currently as rough as it gets.*
|
18
|
+
|
19
|
+
Installation requires Qt 4.7. See [senchalabs/examples](https://github.com/senchalabs/examples) and [my fork
|
20
|
+
of examples](https://github.com/johnbintz/examples) for more information on the QtWebKit runner.
|
21
|
+
|
22
|
+
Tested in the following environments:
|
23
|
+
|
24
|
+
* Mac OS X 10.6, with MacPorts Qt and Nokia Qt.mpkg
|
25
|
+
* Kubuntu 10.10
|
26
|
+
|
27
|
+
## License
|
28
|
+
|
29
|
+
* Copyright (c) 2011 John Bintz
|
30
|
+
* Original Qt WebKit runner Copyright (c) 2010 Sencha Inc.
|
31
|
+
* Jasmine JavaScript library Copyright (c) 2008-2011 Pivotal Labs
|
32
|
+
|
33
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
34
|
+
of this software and associated documentation files (the "Software"), to deal
|
35
|
+
in the Software without restriction, including without limitation the rights
|
36
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
37
|
+
copies of the Software, and to permit persons to whom the Software is
|
38
|
+
furnished to do so, subject to the following conditions:
|
39
|
+
|
40
|
+
The above copyright notice and this permission notice shall be included in
|
41
|
+
all copies or substantial portions of the Software.
|
42
|
+
|
43
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
44
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
45
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
46
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
47
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
48
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
49
|
+
THE SOFTWARE.
|
50
|
+
|
51
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
data = YAML.load_file(ARGV[0] || 'spec/javascripts/support/jasmine.yml')
|
7
|
+
gem_dir = File.expand_path('../..', __FILE__)
|
8
|
+
|
9
|
+
files = [
|
10
|
+
'file://' + File.join(gem_dir, 'jasmine/lib/jasmine.js'),
|
11
|
+
'file://' + File.join(gem_dir, 'jasmine/lib/jasmine-html.js'),
|
12
|
+
'file://' + File.join(gem_dir, 'jasmine/lib/jasmine.css')
|
13
|
+
]
|
14
|
+
|
15
|
+
DEFAULTS = {
|
16
|
+
'spec_files' => [ '**/*[sS]pec.js' ],
|
17
|
+
'helpers' => [ 'helpers/**/*.js' ],
|
18
|
+
'spec_dir' => 'spec/javascripts'
|
19
|
+
}
|
20
|
+
|
21
|
+
files += [ [ 'src_files', 'src_dir' ], [ 'stylesheets', 'src_dir' ], [ 'helpers', 'spec_dir' ], [ 'spec_files', 'spec_dir' ] ].collect do |searches, root|
|
22
|
+
data[searches] ||= DEFAULTS[searches]
|
23
|
+
data[root] ||= DEFAULTS[root]
|
24
|
+
|
25
|
+
if data[searches]
|
26
|
+
data[searches].collect do |search|
|
27
|
+
path = search
|
28
|
+
path = File.join(data[root], path) if data[root]
|
29
|
+
Dir[path]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
files = files.flatten.compact.collect { |file|
|
35
|
+
case File.extname(file)
|
36
|
+
when '.js'
|
37
|
+
%{<script type="text/javascript" src="#{file}"></script>}
|
38
|
+
when '.css'
|
39
|
+
%{<link rel="stylesheet" href="#{file}" type="text/css" />}
|
40
|
+
end
|
41
|
+
}
|
42
|
+
|
43
|
+
output = <<-HTML
|
44
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
45
|
+
"http://www.w3.org/TR/html4/loose.dtd">
|
46
|
+
<html>
|
47
|
+
<head>
|
48
|
+
<title>Jasmine Test Runner</title>
|
49
|
+
<script type="text/javascript">
|
50
|
+
window.console = { log: function(data) { debug.log(JSON.stringify(data)); } };
|
51
|
+
</script>
|
52
|
+
#{files.join("\n")}
|
53
|
+
</head>
|
54
|
+
<body>
|
55
|
+
|
56
|
+
<script type="text/javascript">
|
57
|
+
jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
|
58
|
+
jasmine.getEnv().execute();
|
59
|
+
</script>
|
60
|
+
|
61
|
+
</body>
|
62
|
+
</html>
|
63
|
+
HTML
|
64
|
+
|
65
|
+
File.open(target = "specrunner.#{$$}.html", 'w') { |fh| fh.print output }
|
66
|
+
system %{#{File.join(gem_dir, 'ext/jasmine-webkit-specrunner/jasmine-webkit-specrunner')} #{target}}
|
67
|
+
status = ($? == 0) ? 0 : 1
|
68
|
+
FileUtils.rm_f target
|
69
|
+
|
70
|
+
exit status
|
71
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
|
3
|
+
<plist version="0.9">
|
4
|
+
<dict>
|
5
|
+
<key>CFBundleIconFile</key>
|
6
|
+
<string></string>
|
7
|
+
<key>CFBundlePackageType</key>
|
8
|
+
<string>APPL</string>
|
9
|
+
<key>CFBundleGetInfoString</key>
|
10
|
+
<string>Created by Qt/QMake</string>
|
11
|
+
<key>CFBundleSignature</key>
|
12
|
+
<string>????</string>
|
13
|
+
<key>CFBundleExecutable</key>
|
14
|
+
<string>specrunner</string>
|
15
|
+
<key>CFBundleIdentifier</key>
|
16
|
+
<string>com.yourcompany.specrunner</string>
|
17
|
+
<key>NOTE</key>
|
18
|
+
<string>This file was generated by Qt/QMake.</string>
|
19
|
+
<key>LSUIElement</key>
|
20
|
+
<string>1</string>
|
21
|
+
</dict>
|
22
|
+
</plist>
|
@@ -0,0 +1,164 @@
|
|
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 <iostream>
|
27
|
+
|
28
|
+
#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)
|
29
|
+
#error Use Qt 4.7 or later version
|
30
|
+
#endif
|
31
|
+
|
32
|
+
class HeadlessSpecRunner: public QObject
|
33
|
+
{
|
34
|
+
Q_OBJECT
|
35
|
+
public:
|
36
|
+
HeadlessSpecRunner();
|
37
|
+
void load(const QString &spec);
|
38
|
+
public slots:
|
39
|
+
void log(const QString &msg);
|
40
|
+
void specLog(int indent, const QString &msg, const QString &clazz);
|
41
|
+
private slots:
|
42
|
+
void watch(bool ok);
|
43
|
+
protected:
|
44
|
+
bool hasElement(const char *select);
|
45
|
+
void timerEvent(QTimerEvent *event);
|
46
|
+
private:
|
47
|
+
QWebPage m_page;
|
48
|
+
QBasicTimer m_ticker;
|
49
|
+
int m_runs;
|
50
|
+
};
|
51
|
+
|
52
|
+
HeadlessSpecRunner::HeadlessSpecRunner()
|
53
|
+
: QObject()
|
54
|
+
, m_runs(0)
|
55
|
+
{
|
56
|
+
m_page.settings()->enablePersistentStorage();
|
57
|
+
connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(watch(bool)));
|
58
|
+
}
|
59
|
+
|
60
|
+
void HeadlessSpecRunner::load(const QString &spec)
|
61
|
+
{
|
62
|
+
m_ticker.stop();
|
63
|
+
m_page.mainFrame()->addToJavaScriptWindowObject("debug", this);
|
64
|
+
m_page.mainFrame()->load(spec);
|
65
|
+
m_page.setPreferredContentsSize(QSize(1024, 600));
|
66
|
+
}
|
67
|
+
|
68
|
+
void HeadlessSpecRunner::watch(bool ok)
|
69
|
+
{
|
70
|
+
if (!ok) {
|
71
|
+
std::cerr << "Can't load' " << qPrintable(m_page.mainFrame()->url().toString()) << std::endl;
|
72
|
+
QApplication::instance()->exit(1);
|
73
|
+
return;
|
74
|
+
}
|
75
|
+
|
76
|
+
m_ticker.start(200, this);
|
77
|
+
}
|
78
|
+
|
79
|
+
bool HeadlessSpecRunner::hasElement(const char *select)
|
80
|
+
{
|
81
|
+
return !m_page.mainFrame()->findFirstElement(select).isNull();
|
82
|
+
}
|
83
|
+
|
84
|
+
void HeadlessSpecRunner::log(const QString &msg)
|
85
|
+
{
|
86
|
+
std::cout << "\033[0;32m" << "[console] " << "\033[m";
|
87
|
+
std::cout << qPrintable(msg);
|
88
|
+
std::cout << std::endl;
|
89
|
+
}
|
90
|
+
|
91
|
+
void HeadlessSpecRunner::specLog(int indent, const QString &msg, const QString &clazz)
|
92
|
+
{
|
93
|
+
for (int i = 0; i < indent; ++i)
|
94
|
+
std::cout << " ";
|
95
|
+
if ( clazz.endsWith("fail") ) {
|
96
|
+
std::cout << "\033[0;31m" << qPrintable(msg) << "\033[m";
|
97
|
+
} else {
|
98
|
+
std::cout << "\033[0;33m" << qPrintable(msg) << "\033[m";
|
99
|
+
}
|
100
|
+
std::cout << std::endl;
|
101
|
+
}
|
102
|
+
|
103
|
+
#define DUMP_MSG "(function(n, i) { \
|
104
|
+
if (n.toString() === '[object NodeList]') { \
|
105
|
+
for (var c = 0; c < n.length; ++c) arguments.callee(n[c], i); return \
|
106
|
+
}\
|
107
|
+
if (n.className === 'description' || n.className == 'resultMessage fail') {\
|
108
|
+
debug.specLog(i, n.textContent, n.className);\
|
109
|
+
}\
|
110
|
+
var e = n.firstElementChild;\
|
111
|
+
while (e) {\
|
112
|
+
arguments.callee(e, i + 1); e = e.nextElementSibling; \
|
113
|
+
}\
|
114
|
+
n.className = '';\
|
115
|
+
})(document.getElementsByClassName('suite failed'), 0);"
|
116
|
+
|
117
|
+
void HeadlessSpecRunner::timerEvent(QTimerEvent *event)
|
118
|
+
{
|
119
|
+
if (event->timerId() != m_ticker.timerId())
|
120
|
+
return;
|
121
|
+
|
122
|
+
if (!hasElement(".jasmine_reporter") && !hasElement(".runner.running"))
|
123
|
+
return;
|
124
|
+
|
125
|
+
if (hasElement(".runner.passed")) {
|
126
|
+
QWebElement desc = m_page.mainFrame()->findFirstElement(".description");
|
127
|
+
std::cout << "\033[0;32m" << "PASS: " << qPrintable(desc.toPlainText()) << "\033[m" << std::endl;
|
128
|
+
QApplication::instance()->exit(0);
|
129
|
+
return;
|
130
|
+
}
|
131
|
+
|
132
|
+
if (hasElement(".runner.failed")) {
|
133
|
+
QWebElement desc = m_page.mainFrame()->findFirstElement(".description");
|
134
|
+
std::cout << "\033[0;31m" << "FAIL: " << qPrintable(desc.toPlainText()) << "\033[m" << std::endl;
|
135
|
+
m_page.mainFrame()->evaluateJavaScript(DUMP_MSG);
|
136
|
+
//QDesktopServices::openUrl(m_page.mainFrame()->url());
|
137
|
+
QApplication::instance()->exit(1);
|
138
|
+
return;
|
139
|
+
}
|
140
|
+
|
141
|
+
++m_runs;
|
142
|
+
if (m_runs > 20) {
|
143
|
+
std::cout << "WARNING: too many runs and the test is still not finished!" << std::endl;
|
144
|
+
QApplication::instance()->exit(1);
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
#include "specrunner.moc"
|
149
|
+
|
150
|
+
int main(int argc, char** argv)
|
151
|
+
{
|
152
|
+
if (argc != 2) {
|
153
|
+
std::cerr << "Run Jasmine's SpecRunner headlessly" << std::endl << std::endl;
|
154
|
+
std::cerr << " specrunner SpecRunner.html" << std::endl;
|
155
|
+
return 1;
|
156
|
+
}
|
157
|
+
|
158
|
+
QApplication app(argc, argv);
|
159
|
+
|
160
|
+
HeadlessSpecRunner runner;
|
161
|
+
runner.load(QString::fromLocal8Bit(argv[1]));
|
162
|
+
return app.exec();
|
163
|
+
}
|
164
|
+
|
@@ -0,0 +1,190 @@
|
|
1
|
+
jasmine.TrivialReporter = function(doc) {
|
2
|
+
this.document = doc || document;
|
3
|
+
this.suiteDivs = {};
|
4
|
+
this.logRunningSpecs = false;
|
5
|
+
};
|
6
|
+
|
7
|
+
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
|
8
|
+
var el = document.createElement(type);
|
9
|
+
|
10
|
+
for (var i = 2; i < arguments.length; i++) {
|
11
|
+
var child = arguments[i];
|
12
|
+
|
13
|
+
if (typeof child === 'string') {
|
14
|
+
el.appendChild(document.createTextNode(child));
|
15
|
+
} else {
|
16
|
+
if (child) { el.appendChild(child); }
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
for (var attr in attrs) {
|
21
|
+
if (attr == "className") {
|
22
|
+
el[attr] = attrs[attr];
|
23
|
+
} else {
|
24
|
+
el.setAttribute(attr, attrs[attr]);
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
return el;
|
29
|
+
};
|
30
|
+
|
31
|
+
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
|
32
|
+
var showPassed, showSkipped;
|
33
|
+
|
34
|
+
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
|
35
|
+
this.createDom('div', { className: 'banner' },
|
36
|
+
this.createDom('div', { className: 'logo' },
|
37
|
+
this.createDom('a', { href: 'http://pivotal.github.com/jasmine/', target: "_blank" }, "Jasmine"),
|
38
|
+
this.createDom('span', { className: 'version' }, runner.env.versionString())),
|
39
|
+
this.createDom('div', { className: 'options' },
|
40
|
+
"Show ",
|
41
|
+
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
|
42
|
+
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
|
43
|
+
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
|
44
|
+
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
|
45
|
+
)
|
46
|
+
),
|
47
|
+
|
48
|
+
this.runnerDiv = this.createDom('div', { className: 'runner running' },
|
49
|
+
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
|
50
|
+
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
|
51
|
+
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
|
52
|
+
);
|
53
|
+
|
54
|
+
this.document.body.appendChild(this.outerDiv);
|
55
|
+
|
56
|
+
var suites = runner.suites();
|
57
|
+
for (var i = 0; i < suites.length; i++) {
|
58
|
+
var suite = suites[i];
|
59
|
+
var suiteDiv = this.createDom('div', { className: 'suite' },
|
60
|
+
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
|
61
|
+
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
|
62
|
+
this.suiteDivs[suite.id] = suiteDiv;
|
63
|
+
var parentDiv = this.outerDiv;
|
64
|
+
if (suite.parentSuite) {
|
65
|
+
parentDiv = this.suiteDivs[suite.parentSuite.id];
|
66
|
+
}
|
67
|
+
parentDiv.appendChild(suiteDiv);
|
68
|
+
}
|
69
|
+
|
70
|
+
this.startedAt = new Date();
|
71
|
+
|
72
|
+
var self = this;
|
73
|
+
showPassed.onclick = function(evt) {
|
74
|
+
if (showPassed.checked) {
|
75
|
+
self.outerDiv.className += ' show-passed';
|
76
|
+
} else {
|
77
|
+
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
|
78
|
+
}
|
79
|
+
};
|
80
|
+
|
81
|
+
showSkipped.onclick = function(evt) {
|
82
|
+
if (showSkipped.checked) {
|
83
|
+
self.outerDiv.className += ' show-skipped';
|
84
|
+
} else {
|
85
|
+
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
|
86
|
+
}
|
87
|
+
};
|
88
|
+
};
|
89
|
+
|
90
|
+
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
|
91
|
+
var results = runner.results();
|
92
|
+
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
|
93
|
+
this.runnerDiv.setAttribute("class", className);
|
94
|
+
//do it twice for IE
|
95
|
+
this.runnerDiv.setAttribute("className", className);
|
96
|
+
var specs = runner.specs();
|
97
|
+
var specCount = 0;
|
98
|
+
for (var i = 0; i < specs.length; i++) {
|
99
|
+
if (this.specFilter(specs[i])) {
|
100
|
+
specCount++;
|
101
|
+
}
|
102
|
+
}
|
103
|
+
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
|
104
|
+
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
|
105
|
+
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
|
106
|
+
|
107
|
+
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
|
108
|
+
};
|
109
|
+
|
110
|
+
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
|
111
|
+
var results = suite.results();
|
112
|
+
var status = results.passed() ? 'passed' : 'failed';
|
113
|
+
if (results.totalCount === 0) { // todo: change this to check results.skipped
|
114
|
+
status = 'skipped';
|
115
|
+
}
|
116
|
+
this.suiteDivs[suite.id].className += " " + status;
|
117
|
+
};
|
118
|
+
|
119
|
+
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
|
120
|
+
if (this.logRunningSpecs) {
|
121
|
+
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
|
122
|
+
}
|
123
|
+
};
|
124
|
+
|
125
|
+
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
|
126
|
+
var results = spec.results();
|
127
|
+
var status = results.passed() ? 'passed' : 'failed';
|
128
|
+
if (results.skipped) {
|
129
|
+
status = 'skipped';
|
130
|
+
}
|
131
|
+
var specDiv = this.createDom('div', { className: 'spec ' + status },
|
132
|
+
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
|
133
|
+
this.createDom('a', {
|
134
|
+
className: 'description',
|
135
|
+
href: '?spec=' + encodeURIComponent(spec.getFullName()),
|
136
|
+
title: spec.getFullName()
|
137
|
+
}, spec.description));
|
138
|
+
|
139
|
+
|
140
|
+
var resultItems = results.getItems();
|
141
|
+
var messagesDiv = this.createDom('div', { className: 'messages' });
|
142
|
+
for (var i = 0; i < resultItems.length; i++) {
|
143
|
+
var result = resultItems[i];
|
144
|
+
|
145
|
+
if (result.type == 'log') {
|
146
|
+
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
|
147
|
+
} else if (result.type == 'expect' && result.passed && !result.passed()) {
|
148
|
+
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
|
149
|
+
|
150
|
+
if (result.trace.stack) {
|
151
|
+
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
if (messagesDiv.childNodes.length > 0) {
|
157
|
+
specDiv.appendChild(messagesDiv);
|
158
|
+
}
|
159
|
+
|
160
|
+
this.suiteDivs[spec.suite.id].appendChild(specDiv);
|
161
|
+
};
|
162
|
+
|
163
|
+
jasmine.TrivialReporter.prototype.log = function() {
|
164
|
+
var console = jasmine.getGlobal().console;
|
165
|
+
if (console && console.log) {
|
166
|
+
if (console.log.apply) {
|
167
|
+
console.log.apply(console, arguments);
|
168
|
+
} else {
|
169
|
+
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
|
170
|
+
}
|
171
|
+
}
|
172
|
+
};
|
173
|
+
|
174
|
+
jasmine.TrivialReporter.prototype.getLocation = function() {
|
175
|
+
return this.document.location;
|
176
|
+
};
|
177
|
+
|
178
|
+
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
|
179
|
+
var paramMap = {};
|
180
|
+
var params = this.getLocation().search.substring(1).split('&');
|
181
|
+
for (var i = 0; i < params.length; i++) {
|
182
|
+
var p = params[i].split('=');
|
183
|
+
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
|
184
|
+
}
|
185
|
+
|
186
|
+
if (!paramMap.spec) {
|
187
|
+
return true;
|
188
|
+
}
|
189
|
+
return spec.getFullName().indexOf(paramMap.spec) === 0;
|
190
|
+
};
|
@@ -0,0 +1,166 @@
|
|
1
|
+
body {
|
2
|
+
font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
|
3
|
+
}
|
4
|
+
|
5
|
+
|
6
|
+
.jasmine_reporter a:visited, .jasmine_reporter a {
|
7
|
+
color: #303;
|
8
|
+
}
|
9
|
+
|
10
|
+
.jasmine_reporter a:hover, .jasmine_reporter a:active {
|
11
|
+
color: blue;
|
12
|
+
}
|
13
|
+
|
14
|
+
.run_spec {
|
15
|
+
float:right;
|
16
|
+
padding-right: 5px;
|
17
|
+
font-size: .8em;
|
18
|
+
text-decoration: none;
|
19
|
+
}
|
20
|
+
|
21
|
+
.jasmine_reporter {
|
22
|
+
margin: 0 5px;
|
23
|
+
}
|
24
|
+
|
25
|
+
.banner {
|
26
|
+
color: #303;
|
27
|
+
background-color: #fef;
|
28
|
+
padding: 5px;
|
29
|
+
}
|
30
|
+
|
31
|
+
.logo {
|
32
|
+
float: left;
|
33
|
+
font-size: 1.1em;
|
34
|
+
padding-left: 5px;
|
35
|
+
}
|
36
|
+
|
37
|
+
.logo .version {
|
38
|
+
font-size: .6em;
|
39
|
+
padding-left: 1em;
|
40
|
+
}
|
41
|
+
|
42
|
+
.runner.running {
|
43
|
+
background-color: yellow;
|
44
|
+
}
|
45
|
+
|
46
|
+
|
47
|
+
.options {
|
48
|
+
text-align: right;
|
49
|
+
font-size: .8em;
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
.suite {
|
56
|
+
border: 1px outset gray;
|
57
|
+
margin: 5px 0;
|
58
|
+
padding-left: 1em;
|
59
|
+
}
|
60
|
+
|
61
|
+
.suite .suite {
|
62
|
+
margin: 5px;
|
63
|
+
}
|
64
|
+
|
65
|
+
.suite.passed {
|
66
|
+
background-color: #dfd;
|
67
|
+
}
|
68
|
+
|
69
|
+
.suite.failed {
|
70
|
+
background-color: #fdd;
|
71
|
+
}
|
72
|
+
|
73
|
+
.spec {
|
74
|
+
margin: 5px;
|
75
|
+
padding-left: 1em;
|
76
|
+
clear: both;
|
77
|
+
}
|
78
|
+
|
79
|
+
.spec.failed, .spec.passed, .spec.skipped {
|
80
|
+
padding-bottom: 5px;
|
81
|
+
border: 1px solid gray;
|
82
|
+
}
|
83
|
+
|
84
|
+
.spec.failed {
|
85
|
+
background-color: #fbb;
|
86
|
+
border-color: red;
|
87
|
+
}
|
88
|
+
|
89
|
+
.spec.passed {
|
90
|
+
background-color: #bfb;
|
91
|
+
border-color: green;
|
92
|
+
}
|
93
|
+
|
94
|
+
.spec.skipped {
|
95
|
+
background-color: #bbb;
|
96
|
+
}
|
97
|
+
|
98
|
+
.messages {
|
99
|
+
border-left: 1px dashed gray;
|
100
|
+
padding-left: 1em;
|
101
|
+
padding-right: 1em;
|
102
|
+
}
|
103
|
+
|
104
|
+
.passed {
|
105
|
+
background-color: #cfc;
|
106
|
+
display: none;
|
107
|
+
}
|
108
|
+
|
109
|
+
.failed {
|
110
|
+
background-color: #fbb;
|
111
|
+
}
|
112
|
+
|
113
|
+
.skipped {
|
114
|
+
color: #777;
|
115
|
+
background-color: #eee;
|
116
|
+
display: none;
|
117
|
+
}
|
118
|
+
|
119
|
+
|
120
|
+
/*.resultMessage {*/
|
121
|
+
/*white-space: pre;*/
|
122
|
+
/*}*/
|
123
|
+
|
124
|
+
.resultMessage span.result {
|
125
|
+
display: block;
|
126
|
+
line-height: 2em;
|
127
|
+
color: black;
|
128
|
+
}
|
129
|
+
|
130
|
+
.resultMessage .mismatch {
|
131
|
+
color: black;
|
132
|
+
}
|
133
|
+
|
134
|
+
.stackTrace {
|
135
|
+
white-space: pre;
|
136
|
+
font-size: .8em;
|
137
|
+
margin-left: 10px;
|
138
|
+
max-height: 5em;
|
139
|
+
overflow: auto;
|
140
|
+
border: 1px inset red;
|
141
|
+
padding: 1em;
|
142
|
+
background: #eef;
|
143
|
+
}
|
144
|
+
|
145
|
+
.finished-at {
|
146
|
+
padding-left: 1em;
|
147
|
+
font-size: .6em;
|
148
|
+
}
|
149
|
+
|
150
|
+
.show-passed .passed,
|
151
|
+
.show-skipped .skipped {
|
152
|
+
display: block;
|
153
|
+
}
|
154
|
+
|
155
|
+
|
156
|
+
#jasmine_content {
|
157
|
+
position:fixed;
|
158
|
+
right: 100%;
|
159
|
+
}
|
160
|
+
|
161
|
+
.runner {
|
162
|
+
border: 1px solid gray;
|
163
|
+
display: block;
|
164
|
+
margin: 5px 0;
|
165
|
+
padding: 2px 0 2px 10px;
|
166
|
+
}
|