qunited 0.0.1
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.
- 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
|
+
})();
|