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.
Files changed (37) hide show
  1. data/.gitignore +13 -0
  2. data/Gemfile +4 -0
  3. data/Rakefile +9 -0
  4. data/bin/qunited +23 -0
  5. data/lib/qunited/js_runner/base.rb +34 -0
  6. data/lib/qunited/js_runner/rhino/js/env.rhino.js +14006 -0
  7. data/lib/qunited/js_runner/rhino/js/js.jar +0 -0
  8. data/lib/qunited/js_runner/rhino/js/qunit-runner.js +168 -0
  9. data/lib/qunited/js_runner/rhino/js/qunit.js +1838 -0
  10. data/lib/qunited/js_runner/rhino/js/yaml.js +22 -0
  11. data/lib/qunited/js_runner/rhino.rb +65 -0
  12. data/lib/qunited/js_runner.rb +2 -0
  13. data/lib/qunited/rake_task.rb +87 -0
  14. data/lib/qunited/results.rb +164 -0
  15. data/lib/qunited/runner.rb +23 -0
  16. data/lib/qunited/version.rb +3 -0
  17. data/lib/qunited.rb +4 -0
  18. data/qunited.gemspec +20 -0
  19. data/test/fixtures/basic_project/app/assets/javascripts/application.js +6 -0
  20. data/test/fixtures/basic_project/test/javascripts/test_basics.js +6 -0
  21. data/test/fixtures/basic_project/test/javascripts/test_math.js +12 -0
  22. data/test/fixtures/dom_project/app/assets/javascripts/application.js +6 -0
  23. data/test/fixtures/dom_project/test/javascripts/test_misc.js +5 -0
  24. data/test/fixtures/errors_project/app/assets/javascripts/no_error.js +5 -0
  25. data/test/fixtures/errors_project/app/assets/javascripts/syntax_error.js +7 -0
  26. data/test/fixtures/errors_project/app/assets/javascripts/undefined_error.js +9 -0
  27. data/test/fixtures/errors_project/test/javascripts/this_test_has_no_errors_in_it.js +5 -0
  28. data/test/fixtures/errors_project/test/javascripts/this_test_has_no_tests.js +4 -0
  29. data/test/fixtures/errors_project/test/javascripts/this_test_has_syntax_error.js +10 -0
  30. data/test/fixtures/errors_project/test/javascripts/this_test_has_undefined_error.js +10 -0
  31. data/test/fixtures/failures_project/app/assets/javascripts/application.js +5 -0
  32. data/test/fixtures/failures_project/test/javascripts/test_basics.js +11 -0
  33. data/test/fixtures/failures_project/test/javascripts/test_math.js +12 -0
  34. data/test/test_helper.rb +5 -0
  35. data/test/unit/test_results.rb +338 -0
  36. data/test/unit/test_rhino_runner.rb +114 -0
  37. metadata +100 -0
@@ -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
+ })();