├── .gitmodules
├── README.markdown
├── Rakefile
├── dist
└── evidence.js
└── src
├── assertion_helpers
├── assertion_failed_error.js
├── assertion_message.js
└── assertion_skipped_error.js
├── assertions.js
├── auto_runner.js
├── constants.yml
├── evidence.js
├── helpers.js
├── test_case.js
├── test_loader.js
├── test_result.js
├── test_result_tree.js
├── test_runner.js
├── test_suite.js
├── ui.js
└── ui
├── ascii_view_builder.js
├── console.js
├── console
├── command_line_logger.js
├── logger.js
├── popup_logger.js
├── test_result.js
└── test_runner.js
├── web.js
└── web
├── abstract_widget.js
├── gui.js
├── labelled_text.js
├── list.js
├── list_element.js
├── progress_bar.js
├── test_result.js
└── test_runner.js
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "vendor/sprockets"]
2 | path = vendor/sprockets
3 | url = git://github.com/sstephenson/sprockets.git
4 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tobie/Evidence/16fa654f1321d8a900bbf40f957e5327d3974219/README.markdown
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | EVIDENCE_ROOT_DIR = File.expand_path(File.dirname(__FILE__))
2 | EVIDENCE_DIST_DIR = File.join(EVIDENCE_ROOT_DIR, 'dist')
3 | EVIDENCE_SRC_DIR = File.join(EVIDENCE_ROOT_DIR, 'src')
4 |
5 | $:.unshift File.join(EVIDENCE_ROOT_DIR, 'vendor', 'sprockets', 'lib')
6 |
7 | def sprocketize(path, source, destination, strip_comments = true)
8 | begin
9 | require 'sprockets'
10 | rescue LoadError => e
11 | puts "\nYou'll need Sprockets to build Evidence. Just run:\n\n"
12 | puts " $ git submodule init"
13 | puts " $ git submodule update"
14 | puts "\nand you should be all set.\n\n"
15 | end
16 |
17 | secretary = Sprockets::Secretary.new(
18 | :root => File.join(EVIDENCE_ROOT_DIR, path),
19 | :load_path => [EVIDENCE_SRC_DIR],
20 | :source_files => [source],
21 | :strip_comments => strip_comments
22 | )
23 |
24 | secretary.concatenation.save_to(destination)
25 | end
26 |
27 | desc 'Builds the distribution.'
28 | task :dist do
29 | dest = File.join(EVIDENCE_DIST_DIR, 'evidence.js')
30 | sprocketize('src', 'evidence.js', dest)
31 | end
32 |
33 |
--------------------------------------------------------------------------------
/dist/evidence.js:
--------------------------------------------------------------------------------
1 | /* evidence.js, version 0.6
2 | *
3 | * Copyright (c) 2009 Tobie Langel (http://tobielangel.com)
4 | *
5 | * evidence.js is freely distributable under the terms of an MIT-style license.
6 | *--------------------------------------------------------------------------*/
7 |
8 | (function(global) {
9 | var originalEvidence = global.Evidence,
10 | originalOnload = global.onload;
11 |
12 | function Evidence() {
13 | TestCase.extend.apply(TestCase, arguments);
14 | }
15 |
16 | function noConflict() {
17 | global.Evidence = originalEvidence;
18 | return Evidence;
19 | }
20 |
21 | Evidence.noConflict = noConflict;
22 | Evidence.VERSION = '0.6';
23 |
24 | var FILE_REGEXP = /.*?\/(\w+\.html)(.*)/;
25 |
26 | function getNameFromFile() {
27 | return (global.location || '').toString().replace(FILE_REGEXP, '$1');
28 | }
29 |
30 | function chain(subclass, superclass) {
31 | function Subclass() {}
32 | Subclass.prototype = superclass.prototype;
33 | subclass.prototype = new Subclass();
34 | subclass.prototype.constructor = subclass;
35 | return subclass;
36 | }
37 |
38 | function defer(block, context) {
39 | if ('setTimeout' in global) {
40 | global.setTimeout(function() {
41 | block.call(context);
42 | }, 0);
43 | } else {
44 | block.call(context);
45 | }
46 | }
47 | function AssertionSkippedError(message) {
48 | this.message = message;
49 | }
50 |
51 | AssertionSkippedError.displayName = 'AssertionSkippedError';
52 |
53 | (function(p) {
54 | p.name = 'AssertionSkippedError';
55 | })(AssertionSkippedError.prototype);
56 | Evidence.AssertionSkippedError = AssertionSkippedError;
57 | function AssertionFailedError(message, template, args) {
58 | this.message = message;
59 | this.template = template || '';
60 | this.args = args;
61 | }
62 |
63 | AssertionFailedError.displayName = 'AssertionFailedError';
64 |
65 | (function(p) {
66 | p.name = 'AssertionFailedError';
67 | })(AssertionFailedError.prototype);
68 | Evidence.AssertionFailedError = AssertionFailedError;
69 | function AssertionMessage(message, template, args) {
70 | this.message = message.replace(/%/g, '%%');
71 | this.template = template || '';
72 | this.args = args;
73 | }
74 |
75 | AssertionMessage.displayName = 'AssertionMessage';
76 |
77 | (function(p) {
78 | function toString() {
79 | return UI.printf(this.message + this.template, this.args);
80 | }
81 | p.toString = toString;
82 | })(AssertionMessage.prototype);
83 | Evidence.AssertionMessage = AssertionMessage;
84 |
85 | var Assertions = (function() {
86 | function _assertExpression(expression, message, template) {
87 | if (expression) {
88 | this.addAssertion();
89 | } else {
90 | var args = Array.prototype.slice.call(arguments, 3);
91 | throw new AssertionFailedError(message, template, args);
92 | }
93 | }
94 |
95 | function skip(message) {
96 | throw new AssertionSkippedError(message || 'Skipped!');
97 | }
98 |
99 | function fail(message) {
100 | this._assertExpression(false, message || 'Flunked!');
101 | }
102 |
103 | function assert(test, message) {
104 | this._assertExpression(
105 | !!test,
106 | message || 'Failed assertion.',
107 | 'Expected %o to evaluate to true.', test
108 | );
109 | }
110 |
111 | function refute(test, message) {
112 | this._assertExpression(
113 | !test,
114 | message || 'Failed refutation.',
115 | 'Expected %o to evaluate to false.', test
116 | );
117 | }
118 |
119 | function assertTrue(test, message) {
120 | this._assertExpression(
121 | (test === true),
122 | message || 'Failed assertion.',
123 | 'Expected %o to be true.', test
124 | );
125 | }
126 |
127 | function refuteTrue(test, message) {
128 | this._assertExpression(
129 | (test !== true),
130 | message || 'Failed refutation.',
131 | 'Expected %o to not be true.', test
132 | );
133 | }
134 |
135 | function assertNull(test, message) {
136 | this._assertExpression(
137 | (test === null),
138 | message || 'Failed assertion.',
139 | 'Expected %o to be null.', test
140 | );
141 | }
142 |
143 | function refuteNull(test, message) {
144 | this._assertExpression(
145 | (test !== null),
146 | message || 'Failed refutation.',
147 | 'Expected %o to not be null.', test
148 | );
149 | }
150 |
151 | function assertUndefined(test, message) {
152 | this._assertExpression(
153 | (typeof test === 'undefined'),
154 | message || 'Failed assertion.',
155 | 'Expected %o to be undefined.', test
156 | );
157 | }
158 |
159 | function refuteUndefined(test, message) {
160 | this._assertExpression(
161 | (typeof test !== 'undefined'),
162 | message || 'Failed refutation.',
163 | 'Expected %o to not be undefined.', test
164 | );
165 | }
166 |
167 | function assertFalse(test, message) {
168 | this._assertExpression(
169 | (test === false),
170 | message || 'Failed assertion.',
171 | 'Expected %o to be false.', test
172 | );
173 | }
174 |
175 | function refuteFalse(test, message) {
176 | this._assertExpression(
177 | (test !== false),
178 | message || 'Failed refutation.',
179 | 'Expected %o to not be false.', test
180 | );
181 | }
182 |
183 | function assertEqual(expected, actual, message) {
184 | this._assertExpression(
185 | (expected == actual),
186 | message || 'Failed assertion.',
187 | 'Expected %o to be == to %o.', actual, expected
188 | );
189 | }
190 |
191 | function refuteEqual(expected, actual, message) {
192 | this._assertExpression(
193 | (expected != actual),
194 | message || 'Failed refutation.',
195 | 'Expected %o to be != to %o.', actual, expected
196 | );
197 | }
198 |
199 | function assertIdentical(expected, actual, message) {
200 | this._assertExpression(
201 | (expected === actual),
202 | message || 'Failed assertion.',
203 | 'Expected %o to be === to %o.', actual, expected
204 | );
205 | }
206 |
207 | function refuteIdentical(expected, actual, message) {
208 | this._assertExpression(
209 | (expected !== actual),
210 | message || 'Failed refutation.',
211 | 'Expected %o to be !== to %o.', actual, expected
212 | );
213 | }
214 |
215 | function assertIn(property, object, message) {
216 | this._assertExpression(
217 | (property in object),
218 | message || 'Failed assertion.',
219 | 'Expected "%s" to be a property of %o.', property, object
220 | );
221 | }
222 |
223 | function refuteIn(property, object, message) {
224 | this._assertExpression(
225 | !(property in object),
226 | message || 'Failed refutation.',
227 | 'Expected "%s" to not be a property of %o.', property, object
228 | );
229 | }
230 |
231 | return {
232 | _assertExpression: _assertExpression,
233 | skip: skip,
234 | assert: assert,
235 | refute: refute,
236 | assertNot: refute,
237 | assertTrue: assertTrue,
238 | assertNull: assertNull,
239 | assertUndefined: assertUndefined,
240 | assertFalse: assertFalse,
241 | assertIdentical: assertIdentical,
242 | refuteIdentical: refuteIdentical,
243 | assertEqual: assertEqual,
244 | refuteEqual: refuteEqual,
245 | assertIn: assertIn,
246 | refuteIn: refuteIn,
247 | fail: fail,
248 | flunk: fail
249 | };
250 | })();
251 | Evidence.Assertions = Assertions;
252 | function TestCase(methodName) {
253 | this._methodName = methodName;
254 | this.name = methodName;
255 | }
256 |
257 | (function() {
258 | function extend(name, methods) {
259 | function TestCaseSubclass(methodName) {
260 | TestCase.call(this, methodName);
261 | }
262 |
263 | if (!methods) {
264 | methods = name;
265 | name = getNameFromFile();
266 | }
267 |
268 | chain(TestCaseSubclass, this);
269 | TestCaseSubclass.displayName = name;
270 | TestCaseSubclass.extend = extend;
271 |
272 | for(var prop in methods) {
273 | TestCaseSubclass.prototype[prop] = methods[prop];
274 | }
275 | TestCase.subclasses.push(TestCaseSubclass);
276 | return TestCaseSubclass;
277 | }
278 |
279 | function AssertionsMixin() {}
280 | AssertionsMixin.prototype = Assertions;
281 | TestCase.prototype = new AssertionsMixin();
282 | TestCase.constructor = TestCase;
283 |
284 | TestCase.displayName = 'TestCase';
285 | TestCase.extend = extend;
286 | TestCase.subclasses = [];
287 | TestCase.defaultTimeout = 10000;
288 | })();
289 |
290 | (function(p) {
291 | function run(result) {
292 | this._result = result;
293 | defer(this._run, this);
294 | }
295 | function _run() {
296 | try {
297 | if (this._nextAssertions) {
298 | this._result.restartTest(this);
299 | this._nextAssertions(this);
300 | } else {
301 | /*this._globalProperties = objectKeys(global);*/
302 | this._result.startTest(this);
303 | this.setUp(this);
304 | this[this._methodName](this);
305 | }
306 | } catch(e) {
307 | this._filterException(e);
308 | } finally {
309 | if (this._paused) {
310 | this._result.pauseTest(this);
311 | } else {
312 | try {
313 | this.tearDown(this);
314 | } catch(e) {
315 | this._filterException(e);
316 | } finally {
317 | this._nextAssertions = null;
318 | this._result.stopTest(this);
319 | this.parent.next();
320 | }
321 | }
322 | }
323 | }
324 |
325 | function _filterException(e) {
326 | var name = e.name;
327 | switch(name) {
328 | case 'AssertionFailedError':
329 | this._result.addFailure(this, e);
330 | break;
331 | case 'AssertionSkippedError':
332 | this._result.addSkip(this, e);
333 | break;
334 | default:
335 | this._result.addError(this, e);
336 | }
337 | }
338 |
339 | function pause(assertions) {
340 | this._paused = true;
341 | var self = this;
342 | if (assertions) { this._nextAssertions = assertions; }
343 | self._timeoutId = global.setTimeout(function() {
344 | self.resume(function() {
345 | self.fail('Test timed out. Testing was not resumed after being paused.');
346 | });
347 | }, TestCase.defaultTimeout);
348 | }
349 |
350 | function resume(assertions) {
351 | if (this._paused) { // avoid race conditions
352 | this._paused = false;
353 | global.clearTimeout(this._timeoutId);
354 | if (assertions) { this._nextAssertions = assertions; }
355 | this._run();
356 | }
357 | }
358 |
359 | function size() {
360 | return 1;
361 | }
362 |
363 | function toString() {
364 | return this.constructor.displayName + '#' + this.name;
365 | }
366 |
367 | function addAssertion() {
368 | this._result.addAssertion();
369 | }
370 |
371 | p.run = run;
372 | p._run = _run;
373 | p.addAssertion = addAssertion;
374 | p._filterException = _filterException;
375 | p.pause = pause;
376 | p.resume = resume;
377 | p.size = size;
378 | p.toString = toString;
379 | p.setUp = function() {};
380 | p.tearDown = function() {};
381 | })(TestCase.prototype);
382 | Evidence.TestCase = TestCase;
383 | function TestSuite(name, tests) {
384 | this.name = name;
385 | this._tests = [];
386 | if (tests) {
387 | this.push.apply(this, tests);
388 | }
389 | }
390 |
391 | TestSuite.displayName = 'TestSuite';
392 |
393 | (function(p) {
394 | function run(result) {
395 | this._index = 0;
396 | this._result = result;
397 | result.startSuite(this);
398 | this.next();
399 | return result;
400 | }
401 |
402 | function next() {
403 | var next = this._tests[this._index];
404 | if (next) {
405 | this._index++;
406 | next.run(this._result);
407 | } else {
408 | this._result.stopSuite(this);
409 | if (this.parent) {
410 | this.parent.next();
411 | } else {
412 | this._result.stop(new Date());
413 | }
414 | }
415 | }
416 |
417 | function push() {
418 | for (var i = 0, length = arguments.length; i < length; i++) {
419 | var test = arguments[i];
420 | test.parent = this;
421 | this._tests.push(test);
422 | }
423 | }
424 |
425 | function addTest(test) {
426 | test.parent = this;
427 | this._tests.push(test);
428 | }
429 |
430 | function addTests(tests) {
431 | for (var i = 0, length = tests.length; i < length; i++) {
432 | this.addTest(tests[i]);
433 | }
434 | }
435 |
436 | function size() {
437 | var tests = this._tests,
438 | length = tests.length,
439 | sum = 0;
440 |
441 | for (var i = 0; i < length; i++) {
442 | sum += tests[i].size();
443 | }
444 | return sum;
445 | }
446 |
447 | function isEmpty() {
448 | return this.size() === 0;
449 | }
450 |
451 | function toString() {
452 | return this.name;
453 | }
454 | p.run = run;
455 | p.next = next;
456 | p.push = push;
457 | p.size = size;
458 | p.isEmpty = isEmpty;
459 | p.toString = toString;
460 | })(TestSuite.prototype);
461 | Evidence.TestSuite = TestSuite;
462 | function TestRunner() {
463 | }
464 |
465 | TestRunner.displayName = 'TestRunner';
466 |
467 | (function(p) {
468 | function run(suite) {
469 | suite.parent = null;
470 | var result = this._makeResult();
471 | result.start(new Date());
472 | suite.run(result);
473 | return result;
474 | }
475 |
476 | function _makeResult() {
477 | return new TestResult();
478 | }
479 |
480 | p.run = run;
481 | p._makeResult = _makeResult;
482 | })(TestRunner.prototype);
483 | Evidence.TestRunner = TestRunner;
484 | function TestLoader() {
485 | }
486 |
487 | TestLoader.displayName = 'TestLoader';
488 |
489 | (function(p) {
490 | function loadTestsFromTestCase(testcaseClass) {
491 | var suite = new TestSuite(testcaseClass.displayName),
492 | props = this.getTestCaseNames(testcaseClass);
493 | for (var i=0; i < props.length; i++) {
494 | suite.push(new testcaseClass(props[i]));
495 | }
496 | return suite;
497 | }
498 |
499 | function loadTestsFromTestCases(testcases) {
500 | var suite = new TestSuite(getNameFromFile());
501 | for (var i = 0; i < testcases.length; i++) {
502 | var testcase = testcases[i];
503 | var subSuite = defaultLoader.loadTestsFromTestCase(testcase);
504 | if (!subSuite.isEmpty()) { suite.push(subSuite); }
505 | }
506 | return suite;
507 | }
508 |
509 | function getTestCaseNames(testcaseClass) {
510 | var results = [],
511 | proto = testcaseClass.prototype,
512 | prefix = this.testMethodPrefix;
513 |
514 | for (var property in proto) {
515 | if (property.indexOf(prefix) === 0) {
516 | results.push(property);
517 | }
518 | }
519 | return results.sort();
520 | }
521 |
522 | function loadRegisteredTestCases() {
523 | return loadTestsFromTestCases(TestCase.subclasses);
524 | }
525 |
526 | p.loadTestsFromTestCase = loadTestsFromTestCase;
527 | p.loadRegisteredTestCases = loadRegisteredTestCases;
528 | p.loadTestsFromTestCases = loadTestsFromTestCases;
529 | p.testMethodPrefix = 'test';
530 | p.getTestCaseNames = getTestCaseNames;
531 |
532 | })(TestLoader.prototype);
533 | Evidence.TestLoader = TestLoader;
534 | function AutoRunner() {
535 | if (global.console && global.console.log) {
536 | this.logger = Logger;
537 | } else if (Object.prototype.toString.call(global.environment) === '[object Environment]' && global.print) {
538 | this.logger = CommandLineLogger;
539 | } else {
540 | this.logger = PopupLogger;
541 | }
542 | this.autoRun = true;
543 | this.verbosity = Logger.INFO;
544 | this.runner = ConsoleTestRunner;
545 | }
546 |
547 | (function() {
548 | function run(options) {
549 | var autoRunner = new this();
550 | options = options || autoRunner.retrieveOptions();
551 | autoRunner.processOptions(options);
552 | if (autoRunner.autoRun) { autoRunner.run() };
553 | }
554 |
555 | AutoRunner.run = run;
556 | AutoRunner.displayName = 'AutoRunner';
557 | AutoRunner.LOGGERS = {
558 | console: Logger,
559 | popup: PopupLogger,
560 | command_line: CommandLineLogger
561 | };
562 |
563 | AutoRunner.RUNNERS = {
564 | console: ConsoleTestRunner
565 | };
566 | })();
567 |
568 | (function(p) {
569 | function run() {
570 | var logger = new this.logger(this.verbosity),
571 | runner = new this.runner(logger),
572 | suite = defaultLoader.loadRegisteredTestCases();
573 | if (suite._tests.length <= 1) {
574 | suite = suite._tests[0];
575 | }
576 | return runner.run(suite);
577 | }
578 |
579 | function processQueryString(str) {
580 | var results = {};
581 | str = (str + '').match(/^(?:[^?#]*\?)([^#]+?)(?:#.*)?$/);
582 | str = str && str[1];
583 |
584 | if (!str) { return results; }
585 |
586 | var pairs = str.split('&'),
587 | length = pairs.length;
588 | if (!length) { return results; }
589 |
590 | for (var i = 0; i < length; i++) {
591 | var pair = pairs[i].split('='),
592 | key = decodeURIComponent(pair[0]),
593 | value = pair[1];
594 | value = value ? decodeURIComponent(value) : true;
595 | results[key] = value;
596 | }
597 | return results;
598 | }
599 |
600 | function processArguments(args) { // RHINO
601 | var results = {};
602 |
603 | for (var i = 0; i < args.length; i++) {
604 | var arg = args[i];
605 | if (arg.indexOf('-') === 0) {
606 | var value = args[i + 1];
607 | if (value && value.indexOf('-') !== 0) {
608 | i++;
609 | } else {
610 | value = true;
611 | }
612 | results[arg.substr(1)] = value;
613 | }
614 | }
615 | return results;
616 | }
617 |
618 | function retrieveOptions() {
619 | if (global.location) {
620 | return this.processQueryString(global.location);
621 | }
622 | if (global.arguments) {
623 | return this.processArguments(global.arguments);
624 | }
625 | return {};
626 | }
627 |
628 | function processOptions(options) {
629 | for(var key in options) {
630 | var value = options[key];
631 | switch(key) {
632 | case 'timeout':
633 | TestCase.defaultTimeout = global.parseFloat(value) * 1000;
634 | break;
635 | case 'run':
636 | this.autoRun = value === 'false' ? false : true;
637 | break;
638 | case 'logger':
639 | this.logger = AutoRunner.LOGGERS[value];
640 | break;
641 | case 'verbosity':
642 | var i = global.parseInt(value);
643 | this.verbosity = global.isNaN(i) ? Logger[value] : i;
644 | break;
645 | case 'runner':
646 | this.runner = AutoRunner.RUNNERS[value];
647 | break;
648 | }
649 | }
650 | }
651 |
652 | p.run = run;
653 | p.processQueryString = processQueryString;
654 | p.processArguments = processArguments;
655 | p.retrieveOptions = retrieveOptions;
656 | p.processOptions = processOptions;
657 | })(AutoRunner.prototype);
658 | Evidence.AutoRunner = AutoRunner;
659 | function TestResult() {
660 | this.testCount = 0;
661 | this.assertionCount = 0;
662 | this.skipCount = 0;
663 | this.skips = [];
664 | this.failureCount = 0;
665 | this.failures = [];
666 | this.errors = [];
667 | this.errorCount = 0;
668 | this.testCount = 0;
669 | }
670 |
671 | TestResult.displayName = 'TestResult';
672 |
673 | (function(p) {
674 | function addAssertion() {
675 | this.assertionCount++;
676 | }
677 |
678 | function addSkip(testcase, reason) {
679 | this.skipCount++;
680 | this.skips.push(reason);
681 | }
682 |
683 | function addFailure(testcase, reason) {
684 | this.failureCount++;
685 | this.failures.push(reason);
686 | }
687 |
688 | function addError(testcase, error) {
689 | this.errorCount++;
690 | this.errors.push(error);
691 | }
692 |
693 | function startTest(testcase) {
694 | this.testCount++;
695 | }
696 |
697 | function stopTest(testcase) {}
698 |
699 | function pauseTest(testcase) {}
700 |
701 | function restartTest(testcase) {}
702 |
703 | function startSuite(suite) {}
704 |
705 | function stopSuite(suite) {}
706 |
707 | function start(t0) {
708 | this.t0 = t0;
709 | }
710 |
711 | function stop(t1) {
712 | this.t1 = t1;
713 | }
714 |
715 | function toString() {
716 | return this.testCount + ' tests, ' +
717 | this.assertionCount + ' assertions, ' +
718 | this.failureCount + ' failures, ' +
719 | this.errorCount + ' errors, ' +
720 | this.skipCount + ' skips';
721 | }
722 |
723 | p.addAssertion = addAssertion;
724 | p.addSkip = addSkip;
725 | p.addFailure = addFailure;
726 | p.addError = addError;
727 | p.startTest = startTest;
728 | p.stopTest = stopTest;
729 | p.pauseTest = pauseTest;
730 | p.restartTest = restartTest;
731 | p.startSuite = startSuite;
732 | p.stopSuite = stopSuite;
733 | p.start = start;
734 | p.stop = stop;
735 | p.toString = toString;
736 | })(TestResult.prototype);
737 | Evidence.TestResult = TestResult;
738 | function TestResultTree(name) {
739 | this.testCount = 0;
740 | this.assertionCount = 0;
741 | this.skipCount = 0;
742 | this.skips = [];
743 | this.failureCount = 0;
744 | this.failures = [];
745 | this.errors = [];
746 | this.errorCount = 0;
747 | this.testCount = 0;
748 | this.name = name;
749 | }
750 |
751 | TestResultTree.displayName = 'TestResultTree';
752 |
753 | (function(p) {
754 | function addAssertion() {
755 | var node = this.currentNode;
756 | do {
757 | node.assertionCount++;
758 | } while (node = node.parent);
759 | }
760 |
761 | function addSkip(testcase, reason) {
762 | var node = this.currentNode;
763 | do {
764 | node.skipCount++;
765 | node.skips.push(reason);
766 | } while (node = node.parent);
767 | }
768 |
769 | function addFailure(testcase, reason) {
770 | var node = this.currentNode;
771 | do {
772 | node.failureCount++;
773 | node.failures.push(reason);
774 | } while (node = node.parent);
775 | }
776 |
777 | function addError(testcase, error) {
778 | var node = this.currentNode;
779 | do {
780 | node.errorCount++;
781 | node.errors.push(error);
782 | } while (node = node.parent);
783 | }
784 |
785 | function startTest(testcase) {
786 | var node = this.createChildNode(testcase.name);
787 | do {
788 | node.testCount++;
789 | } while (node = node.parent);
790 | }
791 |
792 | function stopTest(testcase) {
793 | this.currentNode = this.currentNode.parent || this;
794 | }
795 |
796 | function pauseTest(testcase) {}
797 |
798 | function restartTest(testcase) {}
799 |
800 | function startSuite(suite) {
801 | this.createChildNode(suite.name);
802 | }
803 |
804 | function stopSuite(suite) {
805 | this.currentNode = this.currentNode.parent || this;
806 | }
807 |
808 | function start(t0) {
809 | this.t0 = t0;
810 | this.currentNode = this;
811 | }
812 |
813 | function stop(t1) {
814 | this.t1 = t1;
815 | this.currentNode = null;
816 | }
817 |
818 | function toString() {
819 | var results = '';
820 | if (this.children) {
821 | results += this.testCount;
822 | results += ' tests, ';
823 | }
824 | return results +
825 | this.assertionCount + ' assertions, ' +
826 | this.failureCount + ' failures, ' +
827 | this.errorCount + ' errors, ' +
828 | this.skipCount + ' skips';
829 | }
830 |
831 | function createChildNode(name) {
832 | var node = new this.constructor(name);
833 | this.currentNode.appendChild(node);
834 | this.currentNode = node;
835 | return node;
836 | }
837 |
838 | function appendChild(child) {
839 | this.children = this.children || [];
840 | this.children.push(child);
841 | child.parent = this;
842 | }
843 |
844 | function toASCIITree(prefix) {
845 | var str = '',
846 | results = this.toString(),
847 | name = this.name || 'Test results',
848 | childLength = this.children && this.children.length,
849 | rest,
850 | max;
851 |
852 | prefix = prefix || '';
853 | max = 100 - results.length - prefix.length;
854 | max = Math.max(max, 0);
855 |
856 | if (name.length > max) {
857 | name = '...' + name.substr(name.length - max + 3);
858 | }
859 |
860 | rest = (max - name.length);
861 | str += name;
862 | str += ' ';
863 | for (var i = 0; i < rest; i++) { str += '_'; }
864 | str += ' ';
865 | str += results;
866 |
867 | if (this.errorCount > 0) {
868 | str += ' E';
869 | } else if (this.failureCount > 0) {
870 | str += ' F';
871 | } else if (this.skipCount > 0) {
872 | str += ' S';
873 | }
874 |
875 | str += '\n';
876 |
877 | if (childLength) {
878 | for (var i = 0; i < childLength; i++) {
879 | str += prefix;
880 | if (i == childLength - 1) { // last
881 | str += '\'-- ';
882 | str += this.children[i].toASCIITree(prefix + ' ');
883 | str += prefix;
884 | str += '\n';
885 | } else {
886 | str += '|-- ';
887 | str += this.children[i].toASCIITree(prefix + '| ');
888 | }
889 | }
890 | }
891 | return str;
892 | }
893 |
894 | p.toASCIITree = toASCIITree;
895 | p.createChildNode = createChildNode;
896 | p.appendChild = appendChild;
897 | p.addAssertion = addAssertion;
898 | p.addSkip = addSkip;
899 | p.addFailure = addFailure;
900 | p.addError = addError;
901 | p.startTest = startTest;
902 | p.stopTest = stopTest;
903 | p.pauseTest = pauseTest;
904 | p.restartTest = restartTest;
905 | p.startSuite = startSuite;
906 | p.stopSuite = stopSuite;
907 | p.start = start;
908 | p.stop = stop;
909 | p.toString = toString;
910 | })(TestResultTree.prototype);
911 | Evidence.TestResultTree = TestResultTree;
912 | var Console = {};
913 |
914 | function Logger(level) {
915 | if (typeof level !== 'undefined') {
916 | this.level = level;
917 | }
918 | }
919 |
920 | Logger.displayName = 'Logger';
921 | Logger.LEVELS = ['NOTSET', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'];
922 | Logger.CRITICAL = 5;
923 | Logger.ERROR = 4;
924 | Logger.WARN = 3;
925 | Logger.INFO = 2;
926 | Logger.DEBUG = 1;
927 | Logger.NOTSET = 0;
928 |
929 | (function(p) {
930 | function critical(template, params) {
931 | this.log(Logger.CRITICAL, template, params);
932 | }
933 |
934 | function error(template, params) {
935 | this.log(Logger.ERROR, template, params);
936 | }
937 |
938 | function warn(template, params) {
939 | this.log(Logger.WARN, template, params);
940 | }
941 |
942 | function info(template, params) {
943 | this.log(Logger.INFO, template, params);
944 | }
945 |
946 | function debug(template, params) {
947 | this.log(Logger.DEBUG, template, params);
948 | }
949 |
950 | function log(level, template, params) {
951 | level = level || Logger.NOTSET;
952 | var c = global.console;
953 |
954 | var method = Logger.LEVELS[level].toLowerCase();
955 | if (method === 'critical') { method = 'error'; }
956 | method = (method in c) ? method : 'log';
957 |
958 | if (level >= this.level) {
959 | if (params) {
960 | params = params.slice(0);
961 | params.unshift(template);
962 | c[method].apply(c, params);
963 | } else {
964 | c[method](template);
965 | }
966 | }
967 | }
968 |
969 | p.log = log;
970 | p.critical = critical;
971 | p.error = error;
972 | p.warn = warn;
973 | p.info = info;
974 | p.debug = debug;
975 | p.level = 0;
976 | })(Logger.prototype);
977 | Console.Logger = Logger;
978 | function PopupLogger(level) {
979 | Logger.call(this, level);
980 | }
981 |
982 | chain(PopupLogger, Logger);
983 | PopupLogger.displayName = 'PopupLogger';
984 |
985 | (function(p) {
986 | var BASIC_STYLES = 'color: #333; background-color: #fff; font-family: monospace; border-bottom: 1px solid #ccc;';
987 | var STYLES = {
988 | WARN: 'color: #000; background-color: #fc6;',
989 | ERROR: 'color: #f00; background-color: #fcc;',
990 | CRITICAL: 'color: #fff; background-color: #000;'
991 | };
992 |
993 | function _cleanup(html) {
994 | return html.replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&').replace(/[\n\r]+/, '
');
995 | }
996 |
997 | function _makePopup() {
998 | var popup = global.open('','popup','height=400,width=400');
999 | var doc = popup.document;
1000 | doc.write('\
1001 | \
1002 |
\
1003 | \
1004 | Console\
1005 | \
1006 | \
1007 | ');
1008 | doc.close();
1009 | popup.focus();
1010 | return popup;
1011 | }
1012 |
1013 | function _appendLine(level, msg) {
1014 | this.popup = this.popup || this._makePopup();
1015 | var levelName = Logger.LEVELS[level];
1016 |
1017 | var html = '';
1021 | if (level > Logger.INFO) {
1022 | html += '';
1023 | html += levelName;
1024 | html += ': ';
1025 | }
1026 | html += _cleanup(msg);
1027 | html += '
';
1028 | var doc = this.popup.document,
1029 | div = doc.createElement('div');
1030 | div.innerHTML = html;
1031 | html = div.firstChild;
1032 | div = null;
1033 | doc.getElementById('evidence_console').appendChild(html);
1034 | }
1035 |
1036 | function log(level, msg, params) {
1037 | level = level || Logger.NOTSET;
1038 | if (level >= this.level) {
1039 | if (params) {
1040 | msg = UI.printf(msg, params);
1041 | }
1042 | this._appendLine(level, msg);
1043 | }
1044 | }
1045 |
1046 | p.log = log;
1047 | p._makePopup = _makePopup;
1048 | p._appendLine = _appendLine;
1049 | })(PopupLogger.prototype);
1050 | Console.PopupLogger = PopupLogger;
1051 | function CommandLineLogger(level) {
1052 | Logger.call(this, level);
1053 | }
1054 |
1055 | chain(CommandLineLogger, Logger);
1056 | CommandLineLogger.displayName = 'CommandLineLogger';
1057 |
1058 | (function(p) {
1059 |
1060 | function log(level, msg, params) {
1061 | level = level || Logger.NOTSET;
1062 | if (level >= this.level) {
1063 | var prefix = '';
1064 | if (level > Logger.INFO) {
1065 | prefix = Logger.LEVELS[level]+ ': ';
1066 | }
1067 | if (params) {
1068 | msg = UI.printf(msg, params);
1069 | }
1070 | global.print(prefix + msg);
1071 | }
1072 | }
1073 |
1074 | p.log = log;
1075 | })(CommandLineLogger.prototype);
1076 | Console.CommandLineLogger = CommandLineLogger;
1077 | function ConsoleTestRunner(logger) {
1078 | TestRunner.call(this);
1079 | this.logger = logger;
1080 | }
1081 |
1082 | chain(ConsoleTestRunner, TestRunner);
1083 | ConsoleTestRunner.displayName = 'ConsoleTestRunner';
1084 |
1085 | (function(p) {
1086 | function _makeResult() {
1087 | return new ConsoleTestResult(this.logger);
1088 | }
1089 |
1090 | p._makeResult = _makeResult;
1091 | })(ConsoleTestRunner.prototype);
1092 | Console.TestRunner = ConsoleTestRunner;
1093 | function ConsoleTestResult(logger) {
1094 | TestResult.call(this);
1095 | this.logger = logger;
1096 | }
1097 |
1098 | chain(ConsoleTestResult, TestResult);
1099 | ConsoleTestResult.displayName = 'ConsoleTestResult';
1100 |
1101 | (function(p) {
1102 | var _super = TestResult.prototype;
1103 |
1104 | function addAssertion() {
1105 | this.assertionCount++;
1106 | }
1107 |
1108 | function addSkip(testcase, msg) {
1109 | _super.addSkip.call(this, testcase, msg);
1110 | this.logger.warn('Skipping testcase ' + testcase + ': ' + msg.message);
1111 | }
1112 |
1113 | function addFailure(testcase, msg) {
1114 | _super.addFailure.call(this, testcase, msg);
1115 | this.logger.error(testcase + ': ' + msg.message + ' ' + msg.template, msg.args);
1116 | }
1117 |
1118 | function addError(testcase, error) {
1119 | _super.addError.call(this, testcase, error);
1120 | this.logger.error(testcase + ' threw an error. ' + error);
1121 | }
1122 |
1123 | function startTest(testcase) {
1124 | _super.startTest.call(this, testcase);
1125 | this.logger.debug('Started testcase ' + testcase + '.');
1126 | }
1127 |
1128 | function stopTest(testcase) {
1129 | this.logger.debug('Completed testcase ' + testcase + '.');
1130 | }
1131 |
1132 | function pauseTest(testcase) {
1133 | this.logger.info('Paused testcase ' + testcase + '.');
1134 | }
1135 |
1136 | function restartTest(testcase) {
1137 | this.logger.info('Restarted testcase ' + testcase + '.');
1138 | }
1139 |
1140 | function startSuite(suite) {
1141 | this.logger.info('Started suite ' + suite + '.');
1142 | }
1143 |
1144 | function stopSuite(suite) {
1145 | this.logger.info('Completed suite ' + suite + '.');
1146 | }
1147 |
1148 | function start(t0) {
1149 | _super.start.call(this, t0);
1150 | this.logger.info('Started tests.');
1151 | }
1152 |
1153 | function stop(t1) {
1154 | _super.stop.call(this, t1);
1155 | this.logger.info('Completed tests in ' + ((t1 - this.t0)/1000) + 's.');
1156 | this.logger.info(this.toString() + '.');
1157 | }
1158 |
1159 | p.addAssertion = addAssertion;
1160 | p.addSkip = addSkip;
1161 | p.addFailure = addFailure;
1162 | p.addError = addError;
1163 | p.startTest = startTest;
1164 | p.stopTest = stopTest;
1165 | p.pauseTest = pauseTest;
1166 | p.restartTest = restartTest;
1167 | p.startSuite = startSuite;
1168 | p.stopSuite = stopSuite;
1169 | p.start = start;
1170 | p.stop = stop;
1171 | })(ConsoleTestResult.prototype);
1172 |
1173 |
1174 | Console.TestResult = ConsoleTestResult;
1175 | var Web = {};
1176 | function AbstractWidget(doc) {
1177 | this.doc = doc || document;
1178 | }
1179 |
1180 | AbstractWidget.displayName = 'Widget';
1181 |
1182 | (function(p) {
1183 | function escapeHTML(html) {
1184 | return (html + '').replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');
1185 | }
1186 |
1187 | function toElement() {
1188 | return this.element;
1189 | }
1190 |
1191 | function appendChild(child) {
1192 | var element = child && child.toElement ? child.toElement() : child;
1193 | this.element.appendChild(element);
1194 | return child;
1195 | }
1196 |
1197 | p.appendChild = appendChild;
1198 | p.escapeHTML = escapeHTML;
1199 | p.toElement = toElement;
1200 | })(AbstractWidget.prototype);
1201 | Web.AbstractWidget = AbstractWidget;
1202 | function LabelledText(label, doc) {
1203 | AbstractWidget.call(this, doc)
1204 | this.label = label;
1205 | this.element = this.doc.createElement('p');
1206 | }
1207 |
1208 | chain(LabelledText, AbstractWidget);
1209 | LabelledText.displayName = 'LabelledText';
1210 |
1211 | (function(p) {
1212 | function update(content) {
1213 | content = this.escapeHTML(content);
1214 | content = TEMPLATE.replace('{{ label }}', this.label).replace('{{ content }}', content);
1215 | defer(function() { this.element.innerHTML = content; }, this);
1216 | return this;
1217 | }
1218 |
1219 | var TEMPLATE = '{{ label }}: {{ content }}';
1220 |
1221 | p.update = update;
1222 | })(LabelledText.prototype);
1223 | Web.LabelledText = LabelledText;
1224 | function ProgressBar(width, doc) {
1225 | this.width = width;
1226 | this.level = 0;
1227 | AbstractWidget.call(this, doc);
1228 | this.build();
1229 | }
1230 |
1231 | chain(ProgressBar, AbstractWidget);
1232 | ProgressBar.displayName = 'ProgressBar';
1233 |
1234 | (function(p) {
1235 | function build() {
1236 | this.element = this.createDiv(this.width);
1237 | this.element.id = 'evidence_progress_bar_container';
1238 | this.progressBar = this.createDiv(0);
1239 | this.progressBar.id = 'evidence_progress_bar';
1240 | this.element.appendChild(this.progressBar);
1241 | return this;
1242 | }
1243 |
1244 | function createDiv(width) {
1245 | var element = this.doc.createElement('div');
1246 | element.style.width = width + 'px';
1247 | return element;
1248 | }
1249 |
1250 | function update(ratio) {
1251 | var value = Math.floor(ratio * this.width);
1252 | defer(function() {
1253 | this.progressBar.style.width = value + 'px';
1254 | }, this);
1255 | return this;
1256 | }
1257 |
1258 | function setLevel(level) {
1259 | if (level > this.level) {
1260 | this.level = level;
1261 | this.progressBar.className = (Logger.LEVELS[level] || '').toLowerCase();
1262 | }
1263 | return this;
1264 | }
1265 |
1266 | p.build = build;
1267 | p.createDiv = createDiv;
1268 | p.update = update;
1269 | p.setLevel = setLevel;
1270 | })(ProgressBar.prototype);
1271 | Web.ProgressBar = ProgressBar;
1272 | function WebGUI(doc) {
1273 | AbstractWidget.call(this, doc);
1274 | }
1275 |
1276 | chain(WebGUI, AbstractWidget);
1277 | WebGUI.displayName = 'WebGUI';
1278 |
1279 | (function(p) {
1280 | function build() {
1281 | this.element = this.doc.createElement('div');
1282 | this.element.id = 'evidence';
1283 | this.appendChild(new LabelledText('User agent string').update(global.navigator.userAgent))
1284 | this.status = this.appendChild(new LabelledText('Status').update('Idle.'));
1285 | this.progressBar = this.appendChild(new ProgressBar(300));
1286 | this.results = this.appendChild(new LabelledText('Results'));
1287 | return this;
1288 | }
1289 |
1290 |
1291 | function updateResults(txt) {
1292 | txt = this.appendFullStop(txt);
1293 | this.results.update(txt);
1294 | return this;
1295 | }
1296 |
1297 | function updateStatus(txt) {
1298 | txt = this.appendFullStop(txt);
1299 | this.status.update(txt);
1300 | return this;
1301 | }
1302 |
1303 | function updateProgressBar(ratio) {
1304 | this.progressBar.update(ratio);
1305 | return this;
1306 | }
1307 |
1308 | function setLevel(level) {
1309 | this.progressBar.setLevel(level);
1310 | return this;
1311 | }
1312 |
1313 | function appendFullStop(txt) {
1314 | return (txt + '').replace(/\.?\s*$/, '.');
1315 | }
1316 |
1317 | p.build = build;
1318 | p.updateResults = updateResults;
1319 | p.updateStatus = updateStatus;
1320 | p.updateProgressBar = updateProgressBar;
1321 | p.setLevel = setLevel;
1322 | p.appendFullStop = appendFullStop;
1323 | })(WebGUI.prototype);
1324 | Web.GUI = WebGUI;
1325 | function WebTestRunner(logger) {
1326 | TestRunner.call(this);
1327 | this.logger = logger;
1328 | }
1329 |
1330 | chain(WebTestRunner, TestRunner);
1331 | WebTestRunner.displayName = 'WebTestRunner';
1332 |
1333 | (function(p) {
1334 | function _makeResult() {
1335 | return new WebTestResult();
1336 | }
1337 |
1338 | p._makeResult = _makeResult;
1339 | })(WebTestRunner.prototype);
1340 | Web.TestRunner = WebTestRunner;
1341 | function WebTestResult(name) {
1342 | TestResultTree.call(this, name);
1343 | }
1344 |
1345 | chain(WebTestResult, TestResultTree);
1346 | WebTestResult.displayName = 'WebTestResult';
1347 |
1348 | (function(p) {
1349 | var _super = TestResultTree.prototype;
1350 |
1351 | function addAssertion() {
1352 | _super.addAssertion.call(this);
1353 | this.gui.updateResults(this);
1354 | }
1355 |
1356 | function addSkip(testcase, msg) {
1357 | _super.addSkip.call(this, testcase, msg);
1358 | var gui = this.gui;
1359 | gui.updateResults(this);
1360 | gui.setLevel(Logger.WARN);
1361 | gui.updateStatus('Skipping testcase ' + testcase + ': ' + msg.message);
1362 | }
1363 |
1364 | function addFailure(testcase, msg) {
1365 | _super.addFailure.call(this, testcase, msg);
1366 | var gui = this.gui;
1367 | gui.updateResults(this);
1368 | gui.setLevel(Logger.ERROR);
1369 | gui.updateStatus(testcase + ': ' + msg.message + ' ' + msg.template, msg.args);
1370 | }
1371 |
1372 | function addError(testcase, error) {
1373 | _super.addError.call(this, testcase, error);
1374 | var gui = this.gui;
1375 | gui.updateResults(this);
1376 | gui.setLevel(Logger.ERROR);
1377 | gui.updateStatus(testcase + ' threw an error. ' + error);
1378 | }
1379 |
1380 | function startTest(testcase) {
1381 | _super.startTest.call(this, testcase);
1382 | this.gui.updateStatus('Started testcase ' + testcase);
1383 | }
1384 |
1385 | function stopTest(testcase) {
1386 | _super.stopTest.call(this, testcase);
1387 | var gui = this.gui;
1388 | gui.updateProgressBar(this.testCount / this.size);
1389 | gui.updateStatus('Completed testcase ' + testcase);
1390 | }
1391 |
1392 | function pauseTest(testcase) {
1393 | this.gui.updateStatus('Paused testcase ' + testcase + '...');
1394 | }
1395 |
1396 | function restartTest(testcase) {
1397 | this.gui.updateStatus('Restarted testcase ' + testcase);
1398 | }
1399 |
1400 | function startSuite(suite) {
1401 | _super.startSuite.call(this, suite);
1402 | if (!this.size) { this.size = suite.size(); }
1403 | this.gui.updateStatus('Started suite ' + suite);
1404 | }
1405 |
1406 | function stopSuite(suite) {
1407 | _super.stopSuite.call(this, suite);
1408 | this.gui.updateStatus('Completed suite ' + suite);
1409 | }
1410 |
1411 | function start(t0) {
1412 | _super.start.call(this, t0);
1413 | var gui = new WebGUI(document);
1414 | this.gui = gui;
1415 | document.body.appendChild(gui.build().toElement());
1416 | gui.updateResults(this);
1417 | }
1418 |
1419 | function stop(t1) {
1420 | _super.stop.call(this, t1);
1421 | this.gui.updateStatus('Completed tests in ' + ((t1 - this.t0)/1000) + 's');
1422 | }
1423 |
1424 | p.addAssertion = addAssertion;
1425 | p.addSkip = addSkip;
1426 | p.addFailure = addFailure;
1427 | p.addError = addError;
1428 | p.startTest = startTest;
1429 | p.stopTest = stopTest;
1430 | p.pauseTest = pauseTest;
1431 | p.restartTest = restartTest;
1432 | p.startSuite = startSuite;
1433 | p.stopSuite = stopSuite;
1434 | p.start = start;
1435 | p.stop = stop;
1436 | })(WebTestResult.prototype);
1437 |
1438 |
1439 | Web.TestResult = WebTestResult;
1440 | var UI = (function() {
1441 | function printf(template, args, inspector) {
1442 | var parts = [],
1443 | regexp = /(^%|.%)([a-zA-Z])/,
1444 | args = args.splice(0); // clone args
1445 |
1446 | inspector = inspector || String;
1447 |
1448 | if (template.length <= 0) {
1449 | return '';
1450 | }
1451 | while (m = regexp.exec(template)) {
1452 | var match = m[0], index = m.index, type, arg;
1453 |
1454 | if (match.indexOf('%%') === 0) {
1455 | parts.push(template.substr(0, index));
1456 | parts.push(match.substr(1));
1457 | } else {
1458 | parts.push(template.substr(0, match.indexOf('%' === 0) ? index + 1 : index));
1459 | type = m[2];
1460 | arg = args.shift();
1461 | arg = inspector(arg, type);
1462 | parts.push(arg);
1463 | }
1464 | template = template.substr(index + match.length);
1465 | }
1466 | parts.push(template);
1467 | return parts.join('');
1468 | }
1469 |
1470 | return {
1471 | printf: printf,
1472 | Console: Console,
1473 | Web: Web
1474 | };
1475 | })();
1476 | Evidence.UI = UI;
1477 |
1478 | var defaultLoader = new TestLoader();
1479 | Evidence.defaultLoader = defaultLoader;
1480 |
1481 | global.Evidence = Evidence;
1482 |
1483 | if (global.location) {
1484 | global.onload = function() {
1485 | if (typeof originalOnload === 'function') {
1486 | originalOnload.call(global);
1487 | }
1488 | AutoRunner.run();
1489 | };
1490 | } else if (global.arguments) {
1491 | var runtime = java.lang.Runtime.getRuntime();
1492 | var thread = new java.lang.Thread(function() {
1493 | AutoRunner.run();
1494 | });
1495 | runtime.addShutdownHook(thread);
1496 | }
1497 |
1498 | })(this);
1499 |
--------------------------------------------------------------------------------
/src/assertion_helpers/assertion_failed_error.js:
--------------------------------------------------------------------------------
1 | function AssertionFailedError(message, template, args) {
2 | this.message = message;
3 | this.template = template || '';
4 | this.args = args;
5 | }
6 |
7 | AssertionFailedError.displayName = 'AssertionFailedError';
8 |
9 | (function(p) {
10 | p.name = 'AssertionFailedError';
11 | })(AssertionFailedError.prototype);
12 |
--------------------------------------------------------------------------------
/src/assertion_helpers/assertion_message.js:
--------------------------------------------------------------------------------
1 | function AssertionMessage(message, template, args) {
2 | this.message = message.replace(/%/g, '%%');
3 | this.template = template || '';
4 | this.args = args;
5 | }
6 |
7 | AssertionMessage.displayName = 'AssertionMessage';
8 |
9 | (function(p) {
10 | function toString() {
11 | return UI.printf(this.message + this.template, this.args);
12 | }
13 | p.toString = toString;
14 | })(AssertionMessage.prototype);
15 |
--------------------------------------------------------------------------------
/src/assertion_helpers/assertion_skipped_error.js:
--------------------------------------------------------------------------------
1 | function AssertionSkippedError(message) {
2 | this.message = message;
3 | }
4 |
5 | AssertionSkippedError.displayName = 'AssertionSkippedError';
6 |
7 | (function(p) {
8 | p.name = 'AssertionSkippedError';
9 | })(AssertionSkippedError.prototype);
10 |
--------------------------------------------------------------------------------
/src/assertions.js:
--------------------------------------------------------------------------------
1 | //= require "assertion_helpers/assertion_skipped_error"
2 | Evidence.AssertionSkippedError = AssertionSkippedError;
3 | //= require "assertion_helpers/assertion_failed_error"
4 | Evidence.AssertionFailedError = AssertionFailedError;
5 | //= require "assertion_helpers/assertion_message"
6 | Evidence.AssertionMessage = AssertionMessage;
7 |
8 | var Assertions = (function() {
9 | function _assertExpression(expression, message, template) {
10 | if (expression) {
11 | this.addAssertion();
12 | } else {
13 | var args = Array.prototype.slice.call(arguments, 3);
14 | throw new AssertionFailedError(message, template, args);
15 | }
16 | }
17 |
18 | function skip(message) {
19 | throw new AssertionSkippedError(message || 'Skipped!');
20 | }
21 |
22 | function fail(message) {
23 | this._assertExpression(false, message || 'Flunked!');
24 | }
25 |
26 | function assert(test, message) {
27 | this._assertExpression(
28 | !!test,
29 | message || 'Failed assertion.',
30 | 'Expected %o to evaluate to true.', test
31 | );
32 | }
33 |
34 | function refute(test, message) {
35 | this._assertExpression(
36 | !test,
37 | message || 'Failed refutation.',
38 | 'Expected %o to evaluate to false.', test
39 | );
40 | }
41 |
42 | function assertTrue(test, message) {
43 | this._assertExpression(
44 | (test === true),
45 | message || 'Failed assertion.',
46 | 'Expected %o to be true.', test
47 | );
48 | }
49 |
50 | function refuteTrue(test, message) {
51 | this._assertExpression(
52 | (test !== true),
53 | message || 'Failed refutation.',
54 | 'Expected %o to not be true.', test
55 | );
56 | }
57 |
58 | function assertNull(test, message) {
59 | this._assertExpression(
60 | (test === null),
61 | message || 'Failed assertion.',
62 | 'Expected %o to be null.', test
63 | );
64 | }
65 |
66 | function refuteNull(test, message) {
67 | this._assertExpression(
68 | (test !== null),
69 | message || 'Failed refutation.',
70 | 'Expected %o to not be null.', test
71 | );
72 | }
73 |
74 | function assertUndefined(test, message) {
75 | this._assertExpression(
76 | (typeof test === 'undefined'),
77 | message || 'Failed assertion.',
78 | 'Expected %o to be undefined.', test
79 | );
80 | }
81 |
82 | function refuteUndefined(test, message) {
83 | this._assertExpression(
84 | (typeof test !== 'undefined'),
85 | message || 'Failed refutation.',
86 | 'Expected %o to not be undefined.', test
87 | );
88 | }
89 |
90 | function assertFalse(test, message) {
91 | this._assertExpression(
92 | (test === false),
93 | message || 'Failed assertion.',
94 | 'Expected %o to be false.', test
95 | );
96 | }
97 |
98 | function refuteFalse(test, message) {
99 | this._assertExpression(
100 | (test !== false),
101 | message || 'Failed refutation.',
102 | 'Expected %o to not be false.', test
103 | );
104 | }
105 |
106 | function assertEqual(expected, actual, message) {
107 | this._assertExpression(
108 | (expected == actual),
109 | message || 'Failed assertion.',
110 | 'Expected %o to be == to %o.', actual, expected
111 | );
112 | }
113 |
114 | function refuteEqual(expected, actual, message) {
115 | this._assertExpression(
116 | (expected != actual),
117 | message || 'Failed refutation.',
118 | 'Expected %o to be != to %o.', actual, expected
119 | );
120 | }
121 |
122 | function assertIdentical(expected, actual, message) {
123 | this._assertExpression(
124 | (expected === actual),
125 | message || 'Failed assertion.',
126 | 'Expected %o to be === to %o.', actual, expected
127 | );
128 | }
129 |
130 | function refuteIdentical(expected, actual, message) {
131 | this._assertExpression(
132 | (expected !== actual),
133 | message || 'Failed refutation.',
134 | 'Expected %o to be !== to %o.', actual, expected
135 | );
136 | }
137 |
138 | function assertIn(property, object, message) {
139 | this._assertExpression(
140 | (property in object),
141 | message || 'Failed assertion.',
142 | 'Expected "%s" to be a property of %o.', property, object
143 | );
144 | }
145 |
146 | function refuteIn(property, object, message) {
147 | this._assertExpression(
148 | !(property in object),
149 | message || 'Failed refutation.',
150 | 'Expected "%s" to not be a property of %o.', property, object
151 | );
152 | }
153 |
154 | return {
155 | _assertExpression: _assertExpression,
156 | skip: skip,
157 | assert: assert,
158 | refute: refute,
159 | assertNot: refute,
160 | assertTrue: assertTrue,
161 | assertNull: assertNull,
162 | assertUndefined: assertUndefined,
163 | assertFalse: assertFalse,
164 | assertIdentical: assertIdentical,
165 | refuteIdentical: refuteIdentical,
166 | assertEqual: assertEqual,
167 | refuteEqual: refuteEqual,
168 | assertIn: assertIn,
169 | refuteIn: refuteIn,
170 | fail: fail,
171 | flunk: fail
172 | };
173 | })();
--------------------------------------------------------------------------------
/src/auto_runner.js:
--------------------------------------------------------------------------------
1 | function AutoRunner() {
2 | if (global.console && global.console.log) {
3 | this.logger = Logger;
4 | } else if (Object.prototype.toString.call(global.environment) === '[object Environment]' && global.print) {
5 | // most probably Rhino
6 | this.logger = CommandLineLogger;
7 | } else {
8 | this.logger = PopupLogger;
9 | }
10 | this.autoRun = true;
11 | this.verbosity = Logger.INFO;
12 | this.runner = ConsoleTestRunner;
13 | //this.root = '/';
14 | //this.pages = []; // ????
15 | }
16 |
17 | (function() {
18 | function run(options) {
19 | var autoRunner = new this();
20 | options = options || autoRunner.retrieveOptions();
21 | autoRunner.processOptions(options);
22 | if (autoRunner.autoRun) { autoRunner.run() };
23 | }
24 |
25 | AutoRunner.run = run;
26 | AutoRunner.displayName = 'AutoRunner';
27 | AutoRunner.LOGGERS = {
28 | console: Logger,
29 | popup: PopupLogger,
30 | command_line: CommandLineLogger
31 | };
32 |
33 | AutoRunner.RUNNERS = {
34 | console: ConsoleTestRunner
35 | };
36 | })();
37 |
38 | (function(p) {
39 | function run() {
40 | var logger = new this.logger(this.verbosity),
41 | runner = new this.runner(logger),
42 | suite = defaultLoader.loadRegisteredTestCases();
43 | if (suite._tests.length <= 1) {
44 | suite = suite._tests[0];
45 | }
46 | return runner.run(suite);
47 | }
48 |
49 | function processQueryString(str) {
50 | var results = {};
51 | str = (str + '').match(/^(?:[^?#]*\?)([^#]+?)(?:#.*)?$/);
52 | str = str && str[1];
53 |
54 | if (!str) { return results; }
55 |
56 | var pairs = str.split('&'),
57 | length = pairs.length;
58 | if (!length) { return results; }
59 |
60 | for (var i = 0; i < length; i++) {
61 | var pair = pairs[i].split('='),
62 | key = decodeURIComponent(pair[0]),
63 | value = pair[1];
64 | value = value ? decodeURIComponent(value) : true;
65 | results[key] = value;
66 | }
67 | return results;
68 | }
69 |
70 | function processArguments(args) { // RHINO
71 | var results = {};
72 |
73 | for (var i = 0; i < args.length; i++) {
74 | var arg = args[i];
75 | if (arg.indexOf('-') === 0) {
76 | var value = args[i + 1];
77 | if (value && value.indexOf('-') !== 0) {
78 | i++;
79 | } else {
80 | value = true;
81 | }
82 | results[arg.substr(1)] = value;
83 | }
84 | }
85 | return results;
86 | }
87 |
88 | function retrieveOptions() {
89 | if (global.location) {
90 | return this.processQueryString(global.location);
91 | }
92 | if (global.arguments) {
93 | return this.processArguments(global.arguments);
94 | }
95 | return {};
96 | }
97 |
98 | function processOptions(options) {
99 | for(var key in options) {
100 | var value = options[key];
101 | switch(key) {
102 | case 'timeout':
103 | TestCase.defaultTimeout = global.parseFloat(value) * 1000;
104 | break;
105 | case 'run':
106 | this.autoRun = value === 'false' ? false : true;
107 | break;
108 | case 'logger':
109 | this.logger = AutoRunner.LOGGERS[value];
110 | break;
111 | case 'verbosity':
112 | var i = global.parseInt(value);
113 | this.verbosity = global.isNaN(i) ? Logger[value] : i;
114 | break;
115 | case 'runner':
116 | this.runner = AutoRunner.RUNNERS[value];
117 | break;
118 | }
119 | }
120 | }
121 |
122 | p.run = run;
123 | p.processQueryString = processQueryString;
124 | p.processArguments = processArguments;
125 | p.retrieveOptions = retrieveOptions;
126 | p.processOptions = processOptions;
127 | })(AutoRunner.prototype);
--------------------------------------------------------------------------------
/src/constants.yml:
--------------------------------------------------------------------------------
1 | EVIDENCE_VERSION: 0.6
--------------------------------------------------------------------------------
/src/evidence.js:
--------------------------------------------------------------------------------
1 | /* evidence.js, version <%= EVIDENCE_VERSION %>
2 | *
3 | * Copyright (c) 2009 Tobie Langel (http://tobielangel.com)
4 | *
5 | * evidence.js is freely distributable under the terms of an MIT-style license.
6 | *--------------------------------------------------------------------------*/
7 |
8 | (function(global) {
9 | var originalEvidence = global.Evidence,
10 | originalOnload = global.onload;
11 |
12 | /**
13 | * Evidence(tests) -> Evidence.TestResult
14 | * Library namespace. Doubles-up as a shortcut for
15 | * running tests and collect tests results.
16 | *
17 | **/
18 | function Evidence() {
19 | TestCase.extend.apply(TestCase, arguments);
20 | }
21 |
22 | /**
23 | * Evidence.noConflict() -> evidence
24 | * Restores the global namespace and returns the evidence object.
25 | *
26 | **/
27 | function noConflict() {
28 | global.Evidence = originalEvidence;
29 | return Evidence;
30 | }
31 |
32 | Evidence.noConflict = noConflict;
33 | Evidence.VERSION = '<%= EVIDENCE_VERSION %>';
34 |
35 | //= require "helpers"
36 | //= require "assertions"
37 | Evidence.Assertions = Assertions;
38 | //= require "test_case"
39 | Evidence.TestCase = TestCase;
40 | //= require "test_suite"
41 | Evidence.TestSuite = TestSuite;
42 | //= require "test_runner"
43 | Evidence.TestRunner = TestRunner;
44 | //= require "test_loader"
45 | Evidence.TestLoader = TestLoader;
46 | //= require "auto_runner"
47 | Evidence.AutoRunner = AutoRunner;
48 | //= require "test_result"
49 | Evidence.TestResult = TestResult;
50 | //= require "test_result_tree"
51 | Evidence.TestResultTree = TestResultTree;
52 | //= require "ui"
53 | Evidence.UI = UI;
54 |
55 | var defaultLoader = new TestLoader();
56 | Evidence.defaultLoader = defaultLoader;
57 |
58 | global.Evidence = Evidence;
59 |
60 | if (global.location) {
61 | global.onload = function() {
62 | if (typeof originalOnload === 'function') {
63 | originalOnload.call(global);
64 | }
65 | AutoRunner.run();
66 | };
67 | } else if (global.arguments) {
68 | var runtime = java.lang.Runtime.getRuntime();
69 | var thread = new java.lang.Thread(function() {
70 | AutoRunner.run();
71 | });
72 | runtime.addShutdownHook(thread);
73 | }
74 |
75 | })(this);
76 |
--------------------------------------------------------------------------------
/src/helpers.js:
--------------------------------------------------------------------------------
1 | var FILE_REGEXP = /.*?\/(\w+\.html)(.*)/;
2 |
3 | function getNameFromFile() {
4 | return (global.location || '').toString().replace(FILE_REGEXP, '$1');
5 | }
6 |
7 | function chain(subclass, superclass) {
8 | function Subclass() {}
9 | Subclass.prototype = superclass.prototype;
10 | subclass.prototype = new Subclass();
11 | subclass.prototype.constructor = subclass;
12 | return subclass;
13 | }
14 |
15 | function defer(block, context) {
16 | if ('setTimeout' in global) {
17 | global.setTimeout(function() {
18 | block.call(context);
19 | }, 0);
20 | } else {
21 | block.call(context);
22 | }
23 | }
--------------------------------------------------------------------------------
/src/test_case.js:
--------------------------------------------------------------------------------
1 | function TestCase(methodName) {
2 | this._methodName = methodName;
3 | this.name = methodName;
4 | }
5 |
6 | (function() {
7 | function extend(name, methods) {
8 | function TestCaseSubclass(methodName) {
9 | TestCase.call(this, methodName);
10 | }
11 |
12 | if (!methods) {
13 | methods = name;
14 | name = getNameFromFile();
15 | }
16 |
17 | chain(TestCaseSubclass, this);
18 | TestCaseSubclass.displayName = name;
19 | TestCaseSubclass.extend = extend;
20 |
21 | for(var prop in methods) {
22 | TestCaseSubclass.prototype[prop] = methods[prop];
23 | }
24 | TestCase.subclasses.push(TestCaseSubclass);
25 | return TestCaseSubclass;
26 | }
27 |
28 | // Mixin Assertions
29 | function AssertionsMixin() {}
30 | AssertionsMixin.prototype = Assertions;
31 | TestCase.prototype = new AssertionsMixin();
32 | TestCase.constructor = TestCase;
33 |
34 | TestCase.displayName = 'TestCase';
35 | TestCase.extend = extend;
36 | TestCase.subclasses = [];
37 | TestCase.defaultTimeout = 10000;
38 | })();
39 |
40 | (function(p) {
41 |
42 | function run(result, callback) {
43 | this._result = result;
44 | this._callback = callback || function() {};
45 | defer(function() { this.next(result); }, this);
46 | }
47 |
48 | function next(result) {
49 | try {
50 | if (this._nextAssertions) {
51 | result.resumeTest(this);
52 | this._nextAssertions(this);
53 | } else {
54 | result.startTest(this);
55 | this.setUp(this);
56 | this[this._methodName](this);
57 | }
58 | } catch(e) {
59 | this._filterException(e);
60 | } finally {
61 | if (this._paused) {
62 | result.pauseTest(this);
63 | } else {
64 | try {
65 | this.tearDown(this);
66 | } catch(e) {
67 | this._filterException(e);
68 | } finally {
69 | this._nextAssertions = null;
70 | result.stopTest(this);
71 | this._callback(result);
72 | }
73 | }
74 | }
75 | }
76 |
77 | function _filterException(e) {
78 | // Check e.name for cross-frame support.
79 | var name = e.name,
80 | result = this._result;
81 | switch(name) {
82 | case 'AssertionFailedError':
83 | result.addFailure(this, e);
84 | break;
85 | case 'AssertionSkippedError':
86 | result.addSkip(this, e);
87 | break;
88 | default:
89 | result.addError(this, e);
90 | }
91 | }
92 |
93 | function pause(assertions) {
94 | var self = this;
95 | this._paused = true;
96 | if (assertions) { self._nextAssertions = assertions; }
97 | self._timeoutId = global.setTimeout(function() {
98 | self.resume(function() {
99 | self.fail('Test timed out. Testing was not resumed after being paused.');
100 | });
101 | }, TestCase.defaultTimeout);
102 | }
103 |
104 | function resume(assertions) {
105 | if (this._paused) { // avoid race conditions
106 | this._paused = false;
107 | global.clearTimeout(this._timeoutId);
108 | if (assertions) { this._nextAssertions = assertions; }
109 | this.next(this._result);
110 | }
111 | }
112 |
113 | function size() {
114 | return 1;
115 | }
116 |
117 | function toString() {
118 | return this.constructor.displayName + '#' + this.name;
119 | }
120 |
121 | function addAssertion() {
122 | this._result.addAssertion();
123 | }
124 |
125 | p.run = run;
126 | p.next = next;
127 | p.addAssertion = addAssertion;
128 | p._filterException = _filterException;
129 | p.pause = pause;
130 | p.resume = resume;
131 | p.size = size;
132 | p.toString = toString;
133 | p.setUp = function() {};
134 | p.tearDown = function() {};
135 | })(TestCase.prototype);
136 |
--------------------------------------------------------------------------------
/src/test_loader.js:
--------------------------------------------------------------------------------
1 | function TestLoader() {
2 | }
3 |
4 | TestLoader.displayName = 'TestLoader';
5 |
6 | (function(p) {
7 | function loadTestsFromTestCase(testcaseClass) {
8 | var suite = new TestSuite(testcaseClass.displayName),
9 | props = this.getTestCaseNames(testcaseClass);
10 | for (var i=0; i < props.length; i++) {
11 | suite.push(new testcaseClass(props[i]));
12 | }
13 | return suite;
14 | }
15 |
16 | function loadTestsFromTestCases(testcases) {
17 | var suite = new TestSuite(getNameFromFile());
18 | for (var i = 0; i < testcases.length; i++) {
19 | var testcase = testcases[i];
20 | var subSuite = defaultLoader.loadTestsFromTestCase(testcase);
21 | if (!subSuite.isEmpty()) { suite.push(subSuite); }
22 | }
23 | return suite;
24 | }
25 |
26 | function getTestCaseNames(testcaseClass) {
27 | var results = [],
28 | proto = testcaseClass.prototype,
29 | prefix = this.testMethodPrefix;
30 |
31 | for (var property in proto) {
32 | if (property.indexOf(prefix) === 0) {
33 | results.push(property);
34 | }
35 | }
36 | return results.sort();
37 | }
38 |
39 | function loadRegisteredTestCases() {
40 | return loadTestsFromTestCases(TestCase.subclasses);
41 | }
42 |
43 | p.loadTestsFromTestCase = loadTestsFromTestCase;
44 | p.loadRegisteredTestCases = loadRegisteredTestCases;
45 | p.loadTestsFromTestCases = loadTestsFromTestCases;
46 | p.testMethodPrefix = 'test';
47 | p.getTestCaseNames = getTestCaseNames;
48 |
49 | })(TestLoader.prototype);
--------------------------------------------------------------------------------
/src/test_result.js:
--------------------------------------------------------------------------------
1 | function TestResult() {
2 | this.testCount = 0;
3 | this.assertionCount = 0;
4 | this.skipCount = 0;
5 | this.skips = [];
6 | this.failureCount = 0;
7 | this.failures = [];
8 | this.errors = [];
9 | this.errorCount = 0;
10 | this.testCount = 0;
11 | }
12 |
13 | TestResult.displayName = 'TestResult';
14 |
15 | (function(p) {
16 | function addAssertion() {
17 | this.assertionCount++;
18 | }
19 |
20 | function addSkip(testcase, reason) {
21 | this.skipCount++;
22 | this.skips.push(reason);
23 | }
24 |
25 | function addFailure(testcase, reason) {
26 | this.failureCount++;
27 | this.failures.push(reason);
28 | }
29 |
30 | function addError(testcase, error) {
31 | this.errorCount++;
32 | this.errors.push(error);
33 | }
34 |
35 | function startTest(testcase) {
36 | this.testCount++;
37 | }
38 |
39 | function stopTest(testcase) {}
40 |
41 | function pauseTest(testcase) {}
42 |
43 | function resumeTest(testcase) {}
44 |
45 | function startSuite(suite) {}
46 |
47 | function stopSuite(suite) {}
48 |
49 | function loadPage(win) {}
50 |
51 | function startPage(win, suite) {}
52 |
53 | function stopPage(win) {}
54 |
55 | function start(t0) {
56 | this.t0 = t0;
57 | }
58 |
59 | function stop(t1) {
60 | this.t1 = t1;
61 | }
62 |
63 | function toString() {
64 | return this.testCount + ' tests, ' +
65 | this.assertionCount + ' assertions, ' +
66 | this.failureCount + ' failures, ' +
67 | this.errorCount + ' errors, ' +
68 | this.skipCount + ' skips';
69 | }
70 |
71 | p.addAssertion = addAssertion;
72 | p.addSkip = addSkip;
73 | p.addFailure = addFailure;
74 | p.addError = addError;
75 | p.startTest = startTest;
76 | p.stopTest = stopTest;
77 | p.pauseTest = pauseTest;
78 | p.resumeTest = resumeTest;
79 | p.startSuite = startSuite;
80 | p.stopSuite = stopSuite;
81 | p.loadPage = loadPage;
82 | p.startPage = startPage;
83 | p.stopPage = stopPage;
84 | p.start = start;
85 | p.stop = stop;
86 | p.toString = toString;
87 | })(TestResult.prototype);
--------------------------------------------------------------------------------
/src/test_result_tree.js:
--------------------------------------------------------------------------------
1 | function TestResultTree(name) {
2 | this.testCount = 0;
3 | this.assertionCount = 0;
4 | this.skipCount = 0;
5 | this.skips = [];
6 | this.failureCount = 0;
7 | this.failures = [];
8 | this.errors = [];
9 | this.errorCount = 0;
10 | this.testCount = 0;
11 | this.name = name;
12 | }
13 |
14 | chain(TestResultTree, TestResult);
15 | TestResultTree.displayName = 'TestResultTree';
16 |
17 | (function(p) {
18 | function addAssertion() {
19 | var node = this.currentNode;
20 | do {
21 | node.assertionCount++;
22 | } while (node = node.parent);
23 | }
24 |
25 | function addSkip(testcase, reason) {
26 | var node = this.currentNode;
27 | do {
28 | node.skipCount++;
29 | node.skips.push(reason);
30 | } while (node = node.parent);
31 | }
32 |
33 | function addFailure(testcase, reason) {
34 | var node = this.currentNode;
35 | do {
36 | node.failureCount++;
37 | node.failures.push(reason);
38 | } while (node = node.parent);
39 | }
40 |
41 | function addError(testcase, error) {
42 | var node = this.currentNode;
43 | do {
44 | node.errorCount++;
45 | node.errors.push(error);
46 | } while (node = node.parent);
47 | }
48 |
49 | function startTest(testcase) {
50 | var node = this.createChildNode(testcase.name);
51 | do {
52 | node.testCount++;
53 | } while (node = node.parent);
54 | }
55 |
56 | function stopTest(testcase) {
57 | this.currentNode = this.currentNode.parent || this;
58 | }
59 |
60 | function startSuite(suite) {
61 | this.createChildNode(suite.name);
62 | }
63 |
64 | function stopSuite(suite) {
65 | this.currentNode = this.currentNode.parent || this;
66 | }
67 |
68 | function start() {
69 | this.t0 = new Date();
70 | this.currentNode = this;
71 | }
72 |
73 | function stop() {
74 | this.currentNode = null;
75 | this.t1 = new Date();
76 | }
77 |
78 | function toString() {
79 | var results = '';
80 | if (this.children) {
81 | results += this.testCount;
82 | results += ' tests, ';
83 | }
84 | return results +
85 | this.assertionCount + ' assertions, ' +
86 | this.failureCount + ' failures, ' +
87 | this.errorCount + ' errors, ' +
88 | this.skipCount + ' skips';
89 | }
90 |
91 | function createChildNode(name) {
92 | var node = new this.constructor(name);
93 | this.currentNode.appendChild(node);
94 | this.currentNode = node;
95 | return node;
96 | }
97 |
98 | function appendChild(child) {
99 | this.children = this.children || [];
100 | this.children.push(child);
101 | child.parent = this;
102 | }
103 |
104 | p.createChildNode = createChildNode;
105 | p.appendChild = appendChild;
106 | p.addAssertion = addAssertion;
107 | p.addSkip = addSkip;
108 | p.addFailure = addFailure;
109 | p.addError = addError;
110 | p.startTest = startTest;
111 | p.stopTest = stopTest;
112 | p.startSuite = startSuite;
113 | p.stopSuite = stopSuite;
114 | p.start = start;
115 | p.stop = stop;
116 | p.toString = toString;
117 | })(TestResultTree.prototype);
--------------------------------------------------------------------------------
/src/test_runner.js:
--------------------------------------------------------------------------------
1 | function TestRunner() {
2 | }
3 |
4 | TestRunner.displayName = 'TestRunner';
5 |
6 | (function(p) {
7 | function run(suite) {
8 | var self = this,
9 | result = self._makeResult();
10 | Evidence.currentResult = result;
11 | this._suite = suite;
12 | self.start(result);
13 | suite.run(result, function(result) {
14 | self.stop(result);
15 | });
16 | return result;
17 | }
18 |
19 | function _makeResult() {
20 | return new TestResult();
21 | }
22 |
23 | function start(result) {
24 | result.start();
25 | }
26 |
27 | function stop(result) {
28 | result.stop();
29 | }
30 |
31 | p.start = start;
32 | p.stop = stop;
33 | p.run = run;
34 | p._makeResult = _makeResult;
35 | })(TestRunner.prototype);
36 |
--------------------------------------------------------------------------------
/src/test_suite.js:
--------------------------------------------------------------------------------
1 | function TestSuite(name, tests) {
2 | this.name = name;
3 | this._tests = [];
4 | if (tests) {
5 | this.push.apply(this, tests);
6 | }
7 | }
8 |
9 | TestSuite.displayName = 'TestSuite';
10 |
11 | (function(p) {
12 | function run(result, callback) {
13 | this._index = 0;
14 | this._callback = callback || function() {};
15 | result.startSuite(this);
16 | this.next(result);
17 | return result;
18 | }
19 |
20 | function next(result) {
21 | var self = this,
22 | next = self._tests[self._index];
23 | if (next) {
24 | self._index++;
25 | next.run(result, function(result) {
26 | self.next(result);
27 | });
28 | } else {
29 | result.stopSuite(self);
30 | self._callback(result);
31 | }
32 | }
33 |
34 | function push() {
35 | for (var i = 0, length = arguments.length; i < length; i++) {
36 | this._tests.push(arguments[i]);
37 | }
38 | }
39 |
40 | function addTest(test) {
41 | this._tests.push(test);
42 | }
43 |
44 | function addTests(tests) {
45 | for (var i = 0, length = tests.length; i < length; i++) {
46 | this._tests.push(tests[i]);
47 | }
48 | }
49 |
50 | function size() {
51 | var tests = this._tests,
52 | length = tests.length,
53 | sum = 0;
54 |
55 | for (var i = 0; i < length; i++) {
56 | sum += tests[i].size();
57 | }
58 | return sum;
59 | }
60 |
61 | function isEmpty() {
62 | return this.size() === 0;
63 | }
64 |
65 | function toString() {
66 | return this.name;
67 | }
68 |
69 | p.run = run;
70 | p.next = next;
71 | p.push = push;
72 | p.size = size;
73 | p.isEmpty = isEmpty;
74 | p.toString = toString;
75 | })(TestSuite.prototype);
--------------------------------------------------------------------------------
/src/ui.js:
--------------------------------------------------------------------------------
1 | //= require "ui/console"
2 | //= require "ui/web"
3 | //= require "ui/ascii_view_builder"
4 |
5 | var UI = (function() {
6 | function printf(template, args, inspector) {
7 | var parts = [],
8 | regexp = /(^%|.%)([a-zA-Z])/,
9 | args = args.splice(0); // clone args
10 |
11 | inspector = inspector || String;
12 |
13 | if (template.length <= 0) {
14 | return '';
15 | }
16 | while (m = regexp.exec(template)) {
17 | var match = m[0], index = m.index, type, arg;
18 |
19 | if (match.indexOf('%%') === 0) {
20 | parts.push(template.substr(0, index));
21 | parts.push(match.substr(1));
22 | } else {
23 | parts.push(template.substr(0, match.indexOf('%' === 0) ? index + 1 : index));
24 | type = m[2];
25 | arg = args.shift();
26 | arg = inspector(arg, type);
27 | parts.push(arg);
28 | }
29 | template = template.substr(index + match.length);
30 | }
31 | parts.push(template);
32 | return parts.join('');
33 | }
34 |
35 | return {
36 | printf: printf,
37 | Console: Console,
38 | Web: Web
39 | };
40 | })();
--------------------------------------------------------------------------------
/src/ui/ascii_view_builder.js:
--------------------------------------------------------------------------------
1 | function AsciiViewBuilder(result) {
2 | this.prefix = '';
3 | this._result = result;
4 | }
5 |
6 | AsciiViewBuilder.name = AsciiViewBuilder.displayName = 'AsciiViewBuilder';
7 |
8 | (function(p) {
9 |
10 | function draw() {
11 | return this._build(this._result);
12 | }
13 |
14 | function _build(r) {
15 | var rString = r.toString(),
16 | max = 100 - rString.length - this.prefix.length,
17 | str = r.name || 'Anonymous TestSuite';
18 |
19 | str = this._truncate(str, max);
20 | str += ' ' + this._times('.', max - str.length) + ' ';
21 | str += rString;
22 | str += this._displayStatus(r)
23 | str += '\n';
24 |
25 | var length = r.children ? r.children.length : 0,
26 | i;
27 | for (i = 0; i < length; i++) {
28 | if (i === length - 1) { // last
29 | str += this._buildChild(' ', '\'-- ', r.children[i], this.prefix + '\n');
30 | } else {
31 | str += this._buildChild('| ', '|-- ', r.children[i]);
32 | }
33 | }
34 | return str;
35 | }
36 |
37 | function _buildChild(modifier, prefix, child, suffix) {
38 | var str, original = this.prefix;
39 | suffix = suffix || '';
40 | this.prefix += modifier;
41 | str = original + prefix + this._build(child) + suffix;
42 | this.prefix = original;
43 | return str;
44 | }
45 |
46 | function _truncate(str, size) {
47 | size = Math.max(size, 0);
48 | if (str.length > size) {
49 | return '...' + str.substr(str.length - size + 3);
50 | }
51 | return str;
52 | }
53 |
54 | function _times(c, times) {
55 | var str = '';
56 | for (var i = 0; i < times; i++) { str += c; }
57 | return str;
58 | }
59 |
60 | function _displayStatus(r) {
61 | if (r.children) { return ''; }
62 | if (r.errorCount > 0) { return ' E'; }
63 | if (r.failureCount > 0) { return ' F'; }
64 | if (r.skipCount > 0) { return ' S'; }
65 | return '';
66 | }
67 |
68 | p.draw = draw;
69 | p._build = _build;
70 | p._buildChild = _buildChild;
71 | p._displayStatus = _displayStatus;
72 | p._times = _times;
73 | p._truncate = _truncate;
74 | })(AsciiViewBuilder.prototype);
--------------------------------------------------------------------------------
/src/ui/console.js:
--------------------------------------------------------------------------------
1 | var Console = {};
2 |
3 | //= require "console/logger"
4 | Console.Logger = Logger;
5 | //= require "console/popup_logger"
6 | Console.PopupLogger = PopupLogger;
7 | //= require "console/command_line_logger"
8 | Console.CommandLineLogger = CommandLineLogger;
9 | //= require "console/test_runner"
10 | Console.TestRunner = ConsoleTestRunner;
11 | //= require "console/test_result"
12 | Console.TestResult = ConsoleTestResult;
--------------------------------------------------------------------------------
/src/ui/console/command_line_logger.js:
--------------------------------------------------------------------------------
1 | function CommandLineLogger(level) {
2 | Logger.call(this, level);
3 | }
4 |
5 | chain(CommandLineLogger, Logger);
6 | CommandLineLogger.displayName = 'CommandLineLogger';
7 |
8 | (function(p) {
9 |
10 | function log(level, msg, params) {
11 | level = level || Logger.NOTSET;
12 | if (level >= this.level) {
13 | var prefix = this.prefix;
14 | if (level > Logger.INFO) {
15 | prefix += Logger.LEVELS[level]+ ': ';
16 | }
17 | if (params) {
18 | msg = UI.printf(msg, params);
19 | }
20 | global.print(prefix + msg);
21 | }
22 | }
23 |
24 | p.log = log;
25 | })(CommandLineLogger.prototype);
--------------------------------------------------------------------------------
/src/ui/console/logger.js:
--------------------------------------------------------------------------------
1 | function Logger(level) {
2 | if (typeof level !== 'undefined') {
3 | this.level = level;
4 | }
5 | }
6 |
7 | Logger.displayName = 'Logger';
8 | Logger.LEVELS = ['NOTSET', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'];
9 | Logger.CRITICAL = 5;
10 | Logger.ERROR = 4;
11 | Logger.WARN = 3;
12 | Logger.INFO = 2;
13 | Logger.DEBUG = 1;
14 | Logger.NOTSET = 0;
15 |
16 | (function(p) {
17 | function critical(template, params) {
18 | this.log(Logger.CRITICAL, template, params);
19 | }
20 |
21 | function error(template, params) {
22 | this.log(Logger.ERROR, template, params);
23 | }
24 |
25 | function warn(template, params) {
26 | this.log(Logger.WARN, template, params);
27 | }
28 |
29 | function info(template, params) {
30 | this.log(Logger.INFO, template, params);
31 | }
32 |
33 | function debug(template, params) {
34 | this.log(Logger.DEBUG, template, params);
35 | }
36 |
37 | function group(title) {
38 | this.prefix += ' ';
39 | //global.console.group(title);
40 | }
41 |
42 | function groupEnd() {
43 | //global.console.groupEnd();
44 | this.prefix = this.prefix.substr(0, this.prefix.length - 4);
45 | }
46 |
47 | function log(level, template, params) {
48 | level = level || Logger.NOTSET;
49 | var c = global.console;
50 |
51 | var method = Logger.LEVELS[level].toLowerCase();
52 | if (method === 'critical') { method = 'error'; }
53 | method = (method in c) ? method : 'log';
54 | template = this.prefix + template;
55 | if (level >= this.level) {
56 | if (params) {
57 | params = params.slice(0);
58 | params.unshift(template);
59 | c[method].apply(c, params);
60 | } else {
61 | c[method](template);
62 | }
63 | }
64 | }
65 |
66 | p.prefix = '';
67 | p.group = group;
68 | p.groupEnd = groupEnd;
69 | p.log = log;
70 | p.critical = critical;
71 | p.error = error;
72 | p.warn = warn;
73 | p.info = info;
74 | p.debug = debug;
75 | p.level = 0;
76 | })(Logger.prototype);
--------------------------------------------------------------------------------
/src/ui/console/popup_logger.js:
--------------------------------------------------------------------------------
1 | function PopupLogger(level) {
2 | Logger.call(this, level);
3 | }
4 |
5 | chain(PopupLogger, Logger);
6 | PopupLogger.displayName = 'PopupLogger';
7 |
8 | (function(p) {
9 | var BASIC_STYLES = 'color: #333; background-color: #fff; font-family: monospace; border-bottom: 1px solid #ccc;';
10 | var STYLES = {
11 | WARN: 'color: #000; background-color: #fc6;',
12 | ERROR: 'color: #f00; background-color: #fcc;',
13 | CRITICAL: 'color: #fff; background-color: #000;'
14 | };
15 |
16 | function _cleanup(html) {
17 | return html.replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&').replace(/[\n\r]+/, '
');
18 | }
19 |
20 | function _makePopup() {
21 | var popup = global.open('','popup','height=400,width=400');
22 | var doc = popup.document;
23 | doc.write('\
24 | \
25 | \
26 | \
27 | Console\
28 | \
29 | \
30 | ');
31 | doc.close();
32 | popup.focus();
33 | return popup;
34 | }
35 |
36 | function _appendLine(level, msg) {
37 | this.popup = this.popup || this._makePopup();
38 | var levelName = Logger.LEVELS[level];
39 |
40 | var html = '';
44 | if (level > Logger.INFO) {
45 | html += '';
46 | html += levelName;
47 | html += ': ';
48 | }
49 | html += _cleanup(msg);
50 | html += '
';
51 | var doc = this.popup.document,
52 | div = doc.createElement('div');
53 | div.innerHTML = html;
54 | html = div.firstChild;
55 | div = null;
56 | doc.getElementById('evidence_console').appendChild(html);
57 | }
58 |
59 | function log(level, msg, params) {
60 | level = level || Logger.NOTSET;
61 | if (level >= this.level) {
62 | if (params) {
63 | msg = UI.printf(msg, params);
64 | }
65 | this._appendLine(level, msg);
66 | }
67 | }
68 |
69 | p.log = log;
70 | p._makePopup = _makePopup;
71 | p._appendLine = _appendLine;
72 | })(PopupLogger.prototype);
--------------------------------------------------------------------------------
/src/ui/console/test_result.js:
--------------------------------------------------------------------------------
1 | function ConsoleTestResult(logger) {
2 | TestResult.call(this);
3 | this.logger = logger;
4 | }
5 |
6 | chain(ConsoleTestResult, TestResult);
7 | ConsoleTestResult.displayName = 'ConsoleTestResult';
8 |
9 | (function(p) {
10 | var _super = TestResult.prototype;
11 |
12 | function addAssertion() {
13 | this.assertionCount++;
14 | }
15 |
16 | function addSkip(testcase, msg) {
17 | _super.addSkip.call(this, testcase, msg);
18 | this.logger.warn('Skipping testcase ' + testcase + ': ' + msg.message);
19 | }
20 |
21 | function addFailure(testcase, msg) {
22 | _super.addFailure.call(this, testcase, msg);
23 | this.logger.error(testcase + ': ' + msg.message + ' ' + msg.template, msg.args);
24 | }
25 |
26 | function addError(testcase, error) {
27 | _super.addError.call(this, testcase, error);
28 | this.logger.error(testcase + ' threw an error. ' + error);
29 | }
30 |
31 | function startTest(testcase) {
32 | _super.startTest.call(this, testcase);
33 | this.logger.debug('Started testcase ' + testcase + '.');
34 | }
35 |
36 | function stopTest(testcase) {
37 | this.logger.debug('Completed testcase ' + testcase + '.');
38 | }
39 |
40 | function pauseTest(testcase) {
41 | this.logger.info('Paused testcase ' + testcase + '.');
42 | }
43 |
44 | function resumeTest(testcase) {
45 | this.logger.info('Restarted testcase ' + testcase + '.');
46 | }
47 |
48 | function startSuite(suite) {
49 | this.logger.info('Started suite ' + suite + '.');
50 | this.logger.group('Suite ' + suite);
51 | }
52 |
53 | function stopSuite(suite) {
54 | this.logger.groupEnd();
55 | this.logger.info('Completed suite ' + suite + '.');
56 | }
57 |
58 | function start(t0) {
59 | _super.start.call(this, t0);
60 | this.logger.info('Started tests.');
61 | this.logger.group('Tests');
62 | }
63 |
64 | function stop(t1) {
65 | _super.stop.call(this, t1);
66 | this.logger.groupEnd();
67 | this.logger.info('Completed tests in ' + ((t1 - this.t0)/1000) + 's.');
68 | this.logger.info(this.toString() + '.');
69 | }
70 |
71 | p.addAssertion = addAssertion;
72 | p.addSkip = addSkip;
73 | p.addFailure = addFailure;
74 | p.addError = addError;
75 | p.startTest = startTest;
76 | p.stopTest = stopTest;
77 | p.pauseTest = pauseTest;
78 | p.resumeTest = resumeTest;
79 | p.startSuite = startSuite;
80 | p.stopSuite = stopSuite;
81 | p.start = start;
82 | p.stop = stop;
83 | })(ConsoleTestResult.prototype);
84 |
85 |
86 |
--------------------------------------------------------------------------------
/src/ui/console/test_runner.js:
--------------------------------------------------------------------------------
1 | function ConsoleTestRunner(logger) {
2 | TestRunner.call(this);
3 | this.logger = logger;
4 | }
5 |
6 | chain(ConsoleTestRunner, TestRunner);
7 | ConsoleTestRunner.displayName = 'ConsoleTestRunner';
8 |
9 | (function(p) {
10 | function _makeResult() {
11 | return new ConsoleTestResult(this.logger);
12 | }
13 |
14 | p._makeResult = _makeResult;
15 | })(ConsoleTestRunner.prototype);
16 |
--------------------------------------------------------------------------------
/src/ui/web.js:
--------------------------------------------------------------------------------
1 | var Web = {};
2 | //= require "web/abstract_widget"
3 | Web.AbstractWidget = AbstractWidget;
4 | //= require "web/labelled_text"
5 | Web.LabelledText = LabelledText;
6 | //= require "web/progress_bar"
7 | Web.ProgressBar = ProgressBar;
8 | //= require "web/gui"
9 | Web.GUI = WebGUI;
10 | //= require "web/test_runner"
11 | Web.TestRunner = WebTestRunner;
12 | //= require "web/test_result"
13 | Web.TestResult = WebTestResult;
14 |
--------------------------------------------------------------------------------
/src/ui/web/abstract_widget.js:
--------------------------------------------------------------------------------
1 | function AbstractWidget(doc) {
2 | this.doc = doc || document;
3 | }
4 |
5 | AbstractWidget.displayName = 'Widget';
6 |
7 | (function(p) {
8 | function escapeHTML(html) {
9 | return (html + '').replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');
10 | }
11 |
12 | function toElement() {
13 | return this.element;
14 | }
15 |
16 | function appendChild(child) {
17 | var element = child && child.toElement ? child.toElement() : child;
18 | this.element.appendChild(element);
19 | return child;
20 | }
21 | p.draw = function() { return this; };
22 | p.redraw = function() { return this.draw() };
23 | p.appendChild = appendChild;
24 | p.escapeHTML = escapeHTML;
25 | p.toElement = toElement;
26 | })(AbstractWidget.prototype);
--------------------------------------------------------------------------------
/src/ui/web/gui.js:
--------------------------------------------------------------------------------
1 | function WebGUI(doc) {
2 | AbstractWidget.call(this, doc);
3 | this._build();
4 | }
5 |
6 | chain(WebGUI, AbstractWidget);
7 | WebGUI.displayName = 'WebGUI';
8 |
9 | (function(p) {
10 | function _build() {
11 | this.element = this.doc.createElement('div');
12 | this.element.id = 'evidence';
13 | this.appendChild(new LabelledText('User agent string').setContent(global.navigator.userAgent).draw())
14 | this.status = this.appendChild(new LabelledText('Status'));
15 | this.progressBar = this.appendChild(new ProgressBar(300));
16 | this.results = this.appendChild(new LabelledText('Results'));
17 | return this;
18 | }
19 |
20 | function draw() {
21 | defer(function() {
22 | this.status.draw();
23 | this.progressBar.draw();
24 | this.results.draw();
25 | }, this);
26 | }
27 |
28 | function setResults(txt) {
29 | txt = this._appendFullStop(txt);
30 | this.results.setContent(txt);
31 | return this;
32 | }
33 |
34 | function setStatus(txt) {
35 | txt = this._appendFullStop(txt);
36 | this.status.setContent(txt);
37 | this.draw();
38 | return this;
39 | }
40 |
41 | function setProgress(ratio) {
42 | this.progressBar.setValue(ratio);
43 | return this;
44 | }
45 |
46 | function setLevel(level) {
47 | this.progressBar.setLevel(level);
48 | return this;
49 | }
50 |
51 | function _appendFullStop(txt) {
52 | return (txt + '').replace(/\.?\s*$/, '.');
53 | }
54 |
55 | p._build = _build;
56 | p.setResults = setResults;
57 | p.setStatus = setStatus;
58 | p.setProgress = setProgress;
59 | p.setLevel = setLevel;
60 | p._appendFullStop = _appendFullStop;
61 | p.draw = draw;
62 | })(WebGUI.prototype);
--------------------------------------------------------------------------------
/src/ui/web/labelled_text.js:
--------------------------------------------------------------------------------
1 | function LabelledText(label, doc) {
2 | AbstractWidget.call(this, doc)
3 | this.label = label;
4 | this.element = this.doc.createElement('p');
5 | }
6 |
7 | chain(LabelledText, AbstractWidget);
8 | LabelledText.displayName = 'LabelledText';
9 |
10 | (function(p) {
11 | function setContent(content) {
12 | this._content = this.escapeHTML(content);
13 | this._content = TEMPLATE.replace('{{ label }}', this.label).replace('{{ content }}', content);
14 | return this;
15 | }
16 |
17 | function draw() {
18 | this.element.innerHTML = this._content;
19 | return this;
20 | }
21 |
22 | var TEMPLATE = '{{ label }}: {{ content }}';
23 |
24 | p.setContent = setContent;
25 | p.draw = draw;
26 | })(LabelledText.prototype);
--------------------------------------------------------------------------------
/src/ui/web/list.js:
--------------------------------------------------------------------------------
1 | function List(name, doc) {
2 | this.name = name;
3 | this.doc = doc || document;
4 | this.level = 0;
5 | }
6 |
7 | List.displayName = 'List';
8 |
9 | (function(p) {
10 |
11 | function build() {
12 | this.element = this.doc.createElement('div');
13 | this.element.className = 'suite';
14 | var name = this.name.replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');
15 | this.element.innerHTML = TEMPLATE.replace('{{ name }}', name);
16 | return this;
17 | }
18 |
19 | function appendTo(container) {
20 | container.appendChild(this.element);
21 | return this;
22 | }
23 |
24 | function appendChild(child) {
25 | this.children = this.children || [];
26 | this.children.push(child);
27 | child.parent = this;
28 | this.element.lastChild.appendChild(child.element);
29 | return this;
30 | }
31 |
32 | function updateResults(results) {
33 | this.element.childNodes[1].innerHTML = results;
34 | return this;
35 | }
36 |
37 | function setLevel(level) {
38 | if (level > this.level) {
39 | this.element.className = 'suite ' + (Logger.LEVELS[level] || '').toLowerCase();;
40 | this.element.lastChild.style.display = '';
41 | this.level = level;
42 | if (level > Logger.WARN) {
43 | this.element.firstChild.firstChild.firstChild.checked = true;
44 | }
45 | if (this.parent) {
46 | this.parent.setLevel(level);
47 | }
48 | }
49 | }
50 |
51 | var TEMPLATE = '';
52 |
53 | p.build = build;
54 | p.updateResults = updateResults;
55 | p.setLevel = setLevel;
56 | p.appendTo = appendTo;
57 | p.appendChild = appendChild;
58 | })(List.prototype);
--------------------------------------------------------------------------------
/src/ui/web/list_element.js:
--------------------------------------------------------------------------------
1 | function ListElement(name, doc) {
2 | this.name = name;
3 | this.doc = doc || document;
4 | this.level = 0;
5 | }
6 |
7 | ListElement.displayName = 'ListElement';
8 |
9 | (function(p) {
10 |
11 | function build() {
12 | this.element = this.doc.createElement('li');
13 | var name = this.name.replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');
14 | this.element.innerHTML = TEMPLATE.replace('{{ name }}', name);
15 | return this;
16 | }
17 |
18 | function appendTo(container) {
19 | container.appendChild(this.element);
20 | return this;
21 | }
22 |
23 | function updateResults(results) {
24 | this.element.firstChild.lastChild.innerHTML = results;
25 | return this;
26 | }
27 |
28 | function setLevel(level) {
29 | if (level > this.level) {
30 | this.element.className = (Logger.LEVELS[level] || '').toLowerCase();;
31 | this.level = level;
32 | if (level > Logger.WARN) {
33 | this.element.firstChild.firstChild.checked = true;
34 | }
35 | }
36 | this.parent.setLevel(level);
37 | }
38 |
39 | var TEMPLATE = '';
40 |
41 | p.build = build;
42 | p.updateResults = updateResults;
43 | p.setLevel = setLevel;
44 | p.appendTo = appendTo;
45 | })(ListElement.prototype);
--------------------------------------------------------------------------------
/src/ui/web/progress_bar.js:
--------------------------------------------------------------------------------
1 | function ProgressBar(width, doc) {
2 | this._width = width;
3 | this._level = 0;
4 | AbstractWidget.call(this, doc);
5 | this._build();
6 | }
7 |
8 | chain(ProgressBar, AbstractWidget);
9 | ProgressBar.displayName = 'ProgressBar';
10 |
11 | (function(p) {
12 | function _build() {
13 | this.element = this._createDiv(this.width);
14 | this.element.id = 'evidence_progress_bar_container';
15 | this.progressBar = this._createDiv(0);
16 | this.progressBar.id = 'evidence_progress_bar';
17 | this.element.appendChild(this.progressBar);
18 | return this;
19 | }
20 |
21 | function _createDiv(width) {
22 | var element = this.doc.createElement('div');
23 | element.style.width = width + 'px';
24 | return element;
25 | }
26 |
27 | function draw() {
28 | this.progressBar.style.width = this._value + 'px';
29 | var className = (Logger.LEVELS[this._level] || '').toLowerCase();
30 | this.progressBar.className = className;
31 | return this;
32 | }
33 |
34 | function setValue(ratio) {
35 | this._value = Math.floor(ratio * this._width);
36 | return this;
37 | }
38 |
39 | function setLevel(level) {
40 | if (level > this._level) {
41 | this._level = level;
42 | }
43 | return this;
44 | }
45 |
46 | p._build = _build;
47 | p._createDiv = _createDiv;
48 | p.draw = draw;
49 | p.setValue = setValue;
50 | p.setLevel = setLevel;
51 | })(ProgressBar.prototype);
--------------------------------------------------------------------------------
/src/ui/web/test_result.js:
--------------------------------------------------------------------------------
1 | function WebTestResult(name) {
2 | TestResultTree.call(this, name);
3 | this.pageCount = 0;
4 | }
5 |
6 | chain(WebTestResult, TestResultTree);
7 | WebTestResult.displayName = 'WebTestResult';
8 |
9 | (function(p) {
10 | var _super = TestResultTree.prototype;
11 |
12 | function addAssertion() {
13 | _super.addAssertion.call(this);
14 | this.gui.setResults(this);
15 | }
16 |
17 | function addSkip(testcase, msg) {
18 | _super.addSkip.call(this, testcase, msg);
19 | var gui = this.gui;
20 | gui.setResults(this);
21 | gui.setLevel(Logger.WARN);
22 | gui.setStatus('Skipping testcase ' + testcase + ': ' + msg.message);
23 | }
24 |
25 | function addFailure(testcase, msg) {
26 | _super.addFailure.call(this, testcase, msg);
27 | var gui = this.gui;
28 | gui.setResults(this);
29 | gui.setLevel(Logger.ERROR);
30 | gui.setStatus(testcase + ': ' + msg.message + ' ' + msg.template, msg.args);
31 | }
32 |
33 | function addError(testcase, error) {
34 | _super.addError.call(this, testcase, error);
35 | var gui = this.gui;
36 | gui.setResults(this);
37 | gui.setLevel(Logger.ERROR);
38 | gui.setStatus(testcase + ' threw an error. ' + error);
39 | }
40 |
41 | function startTest(testcase) {
42 | _super.startTest.call(this, testcase);
43 | this.gui.setStatus('Started testcase ' + testcase);
44 | }
45 |
46 | function stopTest(testcase) {
47 | _super.stopTest.call(this, testcase);
48 | var gui = this.gui;
49 | gui.setProgress(this.getRatio());
50 | gui.setStatus('Completed testcase ' + testcase);
51 | }
52 |
53 | function pauseTest(testcase) {
54 | this.gui.setStatus('Paused testcase ' + testcase + '...');
55 | }
56 |
57 | function resumeTest(testcase) {
58 | this.gui.setStatus('Resumed testcase ' + testcase);
59 | }
60 |
61 | function startSuite(suite) {
62 | _super.startSuite.call(this, suite);
63 | if (!this.size) { this.size = suite.size(); }
64 | this.gui.setStatus('Started suite ' + suite);
65 | }
66 |
67 | function stopSuite(suite) {
68 | _super.stopSuite.call(this, suite);
69 | this.gui.setStatus('Completed suite ' + suite);
70 | }
71 |
72 | function loadPage(page) {
73 | this.gui.setStatus('Loading page ' + page.location.pathname + '...');
74 | }
75 |
76 | function startPage(page, suite) {
77 | this.pageSize = suite.size();
78 | this.previousTestCount = this.testCount;
79 | this.gui.setStatus('Loaded page ' + page.location.pathname);
80 | }
81 |
82 | function stopPage(page) {
83 | this.pageCount++;
84 | this.gui.setStatus('Finished page ' + page.location.pathname);
85 | }
86 |
87 | function getRatio() {
88 | if (!this.pageSize) {
89 | return this.testCount / this.size;
90 | }
91 | var pageRatio = (this.testCount - this.previousTestCount) / this.pageSize;
92 | return (pageRatio + this.pageCount) / this.size;
93 | }
94 |
95 | function start() {
96 | _super.start.call(this);
97 | var gui = new WebGUI(document);
98 | this.gui = gui;
99 | document.body.appendChild(gui.toElement());
100 | gui.setResults(this);
101 | }
102 |
103 | function stop() {
104 | _super.stop.call(this);
105 | this.gui.setStatus('Completed tests in ' + ((this.t1 - this.t0)/1000) + 's');
106 |
107 | console.log(new AsciiViewBuilder(this).draw())
108 | }
109 |
110 | p.getRatio = getRatio;
111 | p.addAssertion = addAssertion;
112 | p.addSkip = addSkip;
113 | p.addFailure = addFailure;
114 | p.addError = addError;
115 | p.startTest = startTest;
116 | p.stopTest = stopTest;
117 | p.pauseTest = pauseTest;
118 | p.resumeTest = resumeTest;
119 | p.startSuite = startSuite;
120 | p.stopSuite = stopSuite;
121 | p.loadPage = loadPage;
122 | p.startPage = startPage;
123 | p.stopPage = stopPage;
124 | p.start = start;
125 | p.stop = stop;
126 | })(WebTestResult.prototype);
127 |
128 |
129 |
--------------------------------------------------------------------------------
/src/ui/web/test_runner.js:
--------------------------------------------------------------------------------
1 | function WebTestRunner(logger) {
2 | TestRunner.call(this);
3 | this.logger = logger;
4 | }
5 |
6 | chain(WebTestRunner, TestRunner);
7 | WebTestRunner.displayName = 'WebTestRunner';
8 |
9 | (function(p) {
10 | function _makeResult() {
11 | return new WebTestResult();
12 | }
13 |
14 | p._makeResult = _makeResult;
15 | })(WebTestRunner.prototype);
16 |
--------------------------------------------------------------------------------