qunited 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +13 -0
- data/Gemfile +4 -0
- data/Rakefile +9 -0
- data/bin/qunited +23 -0
- data/lib/qunited/js_runner/base.rb +34 -0
- data/lib/qunited/js_runner/rhino/js/env.rhino.js +14006 -0
- data/lib/qunited/js_runner/rhino/js/js.jar +0 -0
- data/lib/qunited/js_runner/rhino/js/qunit-runner.js +168 -0
- data/lib/qunited/js_runner/rhino/js/qunit.js +1838 -0
- data/lib/qunited/js_runner/rhino/js/yaml.js +22 -0
- data/lib/qunited/js_runner/rhino.rb +65 -0
- data/lib/qunited/js_runner.rb +2 -0
- data/lib/qunited/rake_task.rb +87 -0
- data/lib/qunited/results.rb +164 -0
- data/lib/qunited/runner.rb +23 -0
- data/lib/qunited/version.rb +3 -0
- data/lib/qunited.rb +4 -0
- data/qunited.gemspec +20 -0
- data/test/fixtures/basic_project/app/assets/javascripts/application.js +6 -0
- data/test/fixtures/basic_project/test/javascripts/test_basics.js +6 -0
- data/test/fixtures/basic_project/test/javascripts/test_math.js +12 -0
- data/test/fixtures/dom_project/app/assets/javascripts/application.js +6 -0
- data/test/fixtures/dom_project/test/javascripts/test_misc.js +5 -0
- data/test/fixtures/errors_project/app/assets/javascripts/no_error.js +5 -0
- data/test/fixtures/errors_project/app/assets/javascripts/syntax_error.js +7 -0
- data/test/fixtures/errors_project/app/assets/javascripts/undefined_error.js +9 -0
- data/test/fixtures/errors_project/test/javascripts/this_test_has_no_errors_in_it.js +5 -0
- data/test/fixtures/errors_project/test/javascripts/this_test_has_no_tests.js +4 -0
- data/test/fixtures/errors_project/test/javascripts/this_test_has_syntax_error.js +10 -0
- data/test/fixtures/errors_project/test/javascripts/this_test_has_undefined_error.js +10 -0
- data/test/fixtures/failures_project/app/assets/javascripts/application.js +5 -0
- data/test/fixtures/failures_project/test/javascripts/test_basics.js +11 -0
- data/test/fixtures/failures_project/test/javascripts/test_math.js +12 -0
- data/test/test_helper.rb +5 -0
- data/test/unit/test_results.rb +338 -0
- data/test/unit/test_rhino_runner.rb +114 -0
- metadata +100 -0
Binary file
|
@@ -0,0 +1,168 @@
|
|
1
|
+
// Runs QUnit tests with Envjs and outputs test results as
|
2
|
+
// an array of data serialized in YAML format.
|
3
|
+
//
|
4
|
+
// The first argument should be the lib directory containing JavaScript dependencies. The second
|
5
|
+
// argument is the file to use for test results output. The next arguments are source JavaScript
|
6
|
+
// files to test, until "--" is encountered. After the "--" the rest of the arguments are QUnit
|
7
|
+
// test files.
|
8
|
+
//
|
9
|
+
// Example:
|
10
|
+
// java -jar js.jar -opt -1 qunit-runner.js libdir outfile.yaml source.js -- test1.js test2.js
|
11
|
+
// ^ our args start here
|
12
|
+
|
13
|
+
var QUnited = { sourceFiles: [], testFiles: [] };
|
14
|
+
|
15
|
+
(function(args) {
|
16
|
+
var libDir = args.shift();
|
17
|
+
QUnited.outputFile = args.shift();
|
18
|
+
|
19
|
+
['env.rhino.js', 'qunit.js', 'yaml.js'].forEach(function(lib) {
|
20
|
+
load(libDir + '/' + lib);
|
21
|
+
});
|
22
|
+
|
23
|
+
var readingSource = true;
|
24
|
+
args.forEach(function(arg) {
|
25
|
+
if (arg === '--') {
|
26
|
+
readingSource = false; // Now reading tests
|
27
|
+
} else {
|
28
|
+
(readingSource ? QUnited.sourceFiles : QUnited.testFiles).push(arg);
|
29
|
+
}
|
30
|
+
});
|
31
|
+
|
32
|
+
// QUnit config
|
33
|
+
QUnit.init();
|
34
|
+
QUnit.config.blocking = false;
|
35
|
+
QUnit.config.autorun = true;
|
36
|
+
QUnit.config.updateRate = 0;
|
37
|
+
|
38
|
+
// Various state we'll need while running the tests
|
39
|
+
QUnited.modulesMap = {};
|
40
|
+
QUnited.currentTestFile = null; // Set when loading files, see below
|
41
|
+
var currentModule, currentTest;
|
42
|
+
|
43
|
+
///// Listen for QUnit events during tests
|
44
|
+
|
45
|
+
QUnit.testStart(function(data) {
|
46
|
+
currentTest = {
|
47
|
+
name: data.name,
|
48
|
+
assertion_data: [], // Ruby-style, since we'll be reading it with Ruby
|
49
|
+
start: new Date(),
|
50
|
+
assertions: 0,
|
51
|
+
file: QUnited.currentTestFile
|
52
|
+
};
|
53
|
+
|
54
|
+
var moduleName = data.module || "(no module)",
|
55
|
+
module = QUnited.modulesMap[moduleName];
|
56
|
+
if (!module) {
|
57
|
+
module = {name: moduleName, tests: []};
|
58
|
+
QUnited.modulesMap[moduleName] = module;
|
59
|
+
}
|
60
|
+
module.tests.push(currentTest);
|
61
|
+
});
|
62
|
+
|
63
|
+
QUnit.testDone(function(data) {
|
64
|
+
currentTest.duration = ((new Date()).getTime() - currentTest.start.getTime()) / 1000;
|
65
|
+
currentTest.failed = data.failed;
|
66
|
+
currentTest.total = data.total;
|
67
|
+
});
|
68
|
+
|
69
|
+
/*
|
70
|
+
* Called on every assertion AND whenever we have an expect(num) fail. You cannot tell this
|
71
|
+
* apart from an assertion (even though you could make a good guess) with certainty so just
|
72
|
+
* don't worry about it as it will only throw assertions count off on a failing test.
|
73
|
+
*/
|
74
|
+
QUnit.log(function(data) {
|
75
|
+
currentTest.assertions++;
|
76
|
+
currentTest.assertion_data.push(data);
|
77
|
+
});
|
78
|
+
|
79
|
+
})(Array.prototype.slice.call(arguments, 0));
|
80
|
+
|
81
|
+
// Load source files under test
|
82
|
+
QUnited.sourceFiles.forEach(function(file) {
|
83
|
+
load(file);
|
84
|
+
});
|
85
|
+
|
86
|
+
// Load test files
|
87
|
+
QUnited.testFiles.forEach(function(file) {
|
88
|
+
QUnited.currentTestFile = file;
|
89
|
+
|
90
|
+
// There are some tricky issues with loading files in Rhino and properly handling errors in the
|
91
|
+
// loaded files (like undefined and syntax errors). Eventually I settled on just loading using
|
92
|
+
// Rhino's load() even though it is impossible (in this version, it may be fixed in the future)
|
93
|
+
// to know whether or not there was an error in the loaded file. Rhino simply dumps some info to
|
94
|
+
// stderr and keeps on going without letting the caller of load() know what happened!
|
95
|
+
//
|
96
|
+
// Another option is to slurp in the file, eval it, and try/catch the errors and handle them
|
97
|
+
// accordingly. But, I found that the slurp and eval approach introduced to many subtle
|
98
|
+
// misbehaviors to be worth it.
|
99
|
+
//
|
100
|
+
// The thing is, if a test file crashes and the tests aren't run then the build will succeed and
|
101
|
+
// that is a bad, bad thing. We need to fail the build somehow in this case. A non-ideal solution
|
102
|
+
// that I've come up with is to make sure at least one test is run after a file is loaded. A
|
103
|
+
// failure when no tests have been written is not unreasonable and it will have the desirable side
|
104
|
+
// effect that the build is failed if loading fails and tests are not run.
|
105
|
+
load(file);
|
106
|
+
|
107
|
+
// Check that the file had at least one test in it. See above.
|
108
|
+
var foundOne = false;
|
109
|
+
Object.keys(QUnited.modulesMap).forEach(function(key) {
|
110
|
+
var tests = QUnited.modulesMap[key].tests, i, test;
|
111
|
+
for (i = 0; test = tests[i++];) {
|
112
|
+
if (test.file === file) {
|
113
|
+
foundOne = true;
|
114
|
+
break;
|
115
|
+
}
|
116
|
+
};
|
117
|
+
});
|
118
|
+
|
119
|
+
if (!foundOne) {
|
120
|
+
// Create our own test failure in the default module
|
121
|
+
var defaultModuleName = "(no module)",
|
122
|
+
module = QUnited.modulesMap[defaultModuleName];
|
123
|
+
if (!module) {
|
124
|
+
module = {name: defaultModuleName, tests: []};
|
125
|
+
QUnited.modulesMap[defaultModuleName] = module;
|
126
|
+
}
|
127
|
+
|
128
|
+
// Push our failed test data into the default module
|
129
|
+
module.tests.push({
|
130
|
+
name: "Nonexistent test",
|
131
|
+
assertion_data: [{
|
132
|
+
result: false, message: "Test file did not contain any tests (or there was an error loading it)"
|
133
|
+
}],
|
134
|
+
start: new Date(), duration: 0,
|
135
|
+
assertions: 1, failed: 1, total: 1,
|
136
|
+
file: file
|
137
|
+
});
|
138
|
+
}
|
139
|
+
});
|
140
|
+
|
141
|
+
(function() {
|
142
|
+
var modules = [];
|
143
|
+
|
144
|
+
var ISODateString = function(d) {
|
145
|
+
function pad(n) { return n < 10 ? '0' + n : n; }
|
146
|
+
return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1)+'-' + pad(d.getUTCDate()) + 'T' +
|
147
|
+
pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + 'Z';
|
148
|
+
}
|
149
|
+
|
150
|
+
// Make a modules array for outputing results
|
151
|
+
Object.keys(QUnited.modulesMap).forEach(function(key) {
|
152
|
+
var mod = QUnited.modulesMap[key],
|
153
|
+
tests = mod.tests;
|
154
|
+
modules.push(mod);
|
155
|
+
tests.forEach(function(test) {
|
156
|
+
// YAML serializer doesn't seem to do dates; make them strings
|
157
|
+
test.start = ISODateString(test.start);
|
158
|
+
// Convert the duration to a string since the YAML serializer makes them all 0s otherwise
|
159
|
+
test.duration = "" + test.duration;
|
160
|
+
});
|
161
|
+
});
|
162
|
+
|
163
|
+
|
164
|
+
// Write all the results as YAML
|
165
|
+
var writer = new java.io.PrintWriter(QUnited.outputFile);
|
166
|
+
writer.write(YAML.encode(modules));
|
167
|
+
writer.close();
|
168
|
+
})();
|