Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: bower_components/web-animations-js/test/test-runner.html

Issue 786953007: npm_modules: Fork bower_components into Polymer 0.4.0 and 0.5.0 versions (Closed) Base URL: https://chromium.googlesource.com/infra/third_party/npm_modules.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 <!--
2 Copyright 2012 Google Inc. All Rights Reserved.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <!DOCTYPE html>
17 <meta charset="UTF-8">
18
19 <style>
20
21 #status-box {
22 position: fixed;
23 bottom: 0;
24 right: 0;
25 background: white;
26 border: 1px solid black;
27 padding-right: 5px;
28 }
29
30 h1 {
31 display: inline;
32 }
33
34 table {
35 border-collapse: collapse;
36 }
37
38 td {
39 border: 1px solid black;
40 }
41
42 iframe {
43 width: 800px;
44 height: 600px;
45 }
46
47 tbody {
48 color: gray;
49 }
50
51 td.log ul li {
52 white-space: pre;
53 font-family: monospace;
54 }
55
56 /* Fail styles */
57 tbody.fail {
58 color: red;
59 }
60
61 li.fail {
62 color: red;
63 }
64
65 tbody.timeout {
66 color: yellow;
67 }
68
69 li.timeout {
70 color: yellow;
71 }
72
73
74 /* Pass styles */
75 tbody.pass {
76 color: green;
77 }
78
79 li.pass {
80 color: green;
81 }
82
83 tbody.pass-expected-failure {
84 color: #00aa00;
85 }
86
87 li.pass-expected-failure {
88 color: #00aa00;
89 }
90
91 tbody.skipped {
92 color: #00aa00;
93 }
94
95 li.skipped {
96 color: #00aa00;
97 }
98
99 /* No-test styles */
100 tbody.no-tests {
101 color: #ff8a00;
102 }
103
104 </style>
105 <script src="browserdetect/bowser.js"></script>
106 <script src="testcases.js"></script>
107
108 <div id=status-box>
109 <h1 id=status>Pending</h1>
110 Tests: <span id=tests></span>
111 Loading: <span id=loading></span> (<span id=loaded></span>)
112 Running: <span id=running></span> (<span id=finished></span>)
113 Posting: <span id=posting></span> (<span id=posted></span>)
114 </div>
115
116 <table id="results"></table>
117 <div id="spacer"></div>
118
119 <script>
120 'use strict';
121 window.onerror = function(msg, url, line) {
122 // Ignore errors caused by webdriver
123 if (msg.match(/webdriver/))
124 return;
125
126 if (document.getElementById('javascript-errors') == null) {
127 document.body.innerHTML = '<pre id="javascript-errors">JAVASCRIPT ERRORS\n\n </pre>';
128 }
129
130 var e = document.getElementById('javascript-errors');
131 var msg = 'Javascript Error in ' + url + '\n' +
132 'Line ' + line + ': ' + msg + '\n';
133 e.innerHTML += msg;
134 };
135 </script>
136
137 <script>
138 'use strict';
139
140 (function() {
141 window.finished = false;
142 window.getTestRunnerProgress = function() {
143 return {
144 completed: testStates['POSTED'].length,
145 total: tests.length,
146 };
147 }
148
149 var results = [];
150
151 if (/coverage/.test(window.location.hash)) {
152 // Trigger coverage runs for child tests.
153 window.__coverage__ = {};
154 // Share resources loaded by child tests to avoid instrumenting the same
155 // source file multiple times.
156 window.__resources__ = {original: {}};
157 }
158
159 window.addEventListener('load', function() {
160 document.querySelector('#spacer').style.height =
161 getComputedStyle(document.querySelector('body')).height;
162 });
163 function trueOffsetTop(element) {
164 var t = 0;
165 if (element.offsetParent) {
166 do {
167 t += element.offsetTop;
168 } while (element = element.offsetParent);
169 return t;
170 }
171 }
172
173 /**
174 * Get a value for busting the cache.
175 */
176 var cacheBuster = '' + window.Date.now();
177
178 /**
179 * Get the most accurate version of time possible.
180 *
181 * @return {number} Time as this very moment.
182 */
183 function now() {
184 try {
185 return window.performance.now();
186 } catch (e) {
187 return Date.now();
188 }
189 }
190
191 /**
192 * Creates HTML elements in a table for a test.
193 *
194 * +-----------+------+-------+
195 * | Test Name | Link | Count |
196 * +-----------+------+-------+
197 * | Log of test run. |
198 * +--------------------------+
199 * | iFrame containing test |
200 * +--------------------------+
201 *
202 * @param {String} testName Name of the test suite being run.
203 * @param {String} testURL The url of the test suite.
204 * @return {Element} tbody containing newly created table rows.
205 */
206 function createTestRows(testName, testURL) {
207 var tableGroup = document.createElement('tbody');
208 tableGroup.id = testName.replace('.', '-');
209
210 var basicInfoRow = document.createElement('tr');
211 basicInfoRow.className = 'info-row';
212 tableGroup.appendChild(basicInfoRow);
213 var iframeRow = document.createElement('tr');
214 tableGroup.appendChild(iframeRow);
215 var logRow = document.createElement('tr');
216 tableGroup.appendChild(logRow);
217
218 // Name
219 var header = document.createElement('h1');
220 header.textContent = testName;
221
222 var headerCell = document.createElement('td');
223 headerCell.appendChild(header);
224 basicInfoRow.appendChild(headerCell);
225
226 // Link
227 var link = document.createElement('a');
228 link.textContent = testName;
229 link.href = testURL;
230
231 var linkCell = document.createElement('td');
232 linkCell.appendChild(link);
233 basicInfoRow.appendChild(linkCell);
234
235 // Test count
236 var countCell = document.createElement('td');
237 countCell.className = 'count';
238 basicInfoRow.appendChild(countCell);
239
240 // Timing info
241 var timingCell = document.createElement('td');
242 timingCell.className = 'timing';
243 basicInfoRow.appendChild(timingCell);
244
245 // iframe containing a preview of object
246 var iframe = document.createElement('iframe');
247 iframe.src = testURL + '?' + cacheBuster + '#message';
248
249 var iframeCell = document.createElement('td');
250 iframeCell.colSpan = '4';
251 iframeCell.appendChild(iframe);
252 iframeRow.appendChild(iframeCell);
253
254 // table row containing the complete test log
255 var logCell = document.createElement('td');
256 logCell.className = 'log';
257 logCell.colSpan = '4';
258 logRow.appendChild(logCell);
259
260 /**
261 * Normally we would use "display: none;" but that causes Firefox to return
262 * null for getComputedStyle, so instead we have to use this visibility hack.
263 */
264 tableGroup.showInfo = function() {
265 logRow.style.visibility = 'visible';
266 logRow.style.position = '';
267 logRow.style.height = 'auto';
268
269 iframeRow.style.visibility = 'visible';
270 iframeRow.style.position = '';
271 iframeRow.style.height = 'auto';
272 };
273 tableGroup.hideInfo = function() {
274 logRow.style.visibility = 'hidden';
275 logRow.style.position = 'absolute';
276 logRow.style.height = '0';
277
278 iframeRow.style.visibility = 'hidden';
279 iframeRow.style.position = 'absolute';
280 iframeRow.style.height = '0';
281 };
282 tableGroup.toggleInfo = function() {
283 if (logRow.style.visibility == 'hidden') {
284 tableGroup.showInfo();
285 } else {
286 tableGroup.hideInfo();
287 }
288 };
289 basicInfoRow.onclick = tableGroup.toggleInfo;
290
291 tableGroup.hideInfo();
292
293 return tableGroup;
294 }
295
296 /* @type {?number} */ var runTestsId = null;
297
298 /**
299 * Checks all the tests are in the loaded state and then kicks of running
300 * the tests.
301 */
302 function runTestsIfLoaded() {
303 if (testStates['LOADING'].length > 0)
304 return;
305
306 if (runTestsId == null) {
307 runTestsId = window.setInterval(runTests, 10);
308 }
309 }
310
311 function generateCoverageReport() {
312 // TODO: generate a pretty report, prompt to save the JSON, post it somewhere
313 for (var file in window.__coverage__) {
314 var results = window.__coverage__[file];
315 var hits = 0;
316 var statements = 0;
317 for (var stmt in results.s) {
318 statements++;
319 if (results.s[stmt] > 0) {
320 hits++;
321 }
322 }
323 var percent = (100 * hits / statements).toFixed(2);
324 console.log(file + ' statement coverage ' +
325 percent + '% (' + hits + '/' + statements + ')');
326 }
327 }
328
329 /**
330 * This object tracks which state a test is in. An individual test should only
331 * ever be in one of the lists. You use the changeTestState() function to move
332 * from one state to another.
333 *
334 * Tests start off in the loading state and move downwards until ending up in
335 * the finished state.
336 */
337 var testStates = {};
338 testStates['LOADING'] = []; /* Test which is being loaded. */
339 testStates['LOADED'] = []; /* Test which have yet to start. */
340 testStates['RUNNING'] = []; /* Test that is currently running. */
341 testStates['FINISHED'] = []; /* Test that are finished. */
342 testStates['POSTING'] = []; /* Test that is currently posting results to server . */
343 testStates['POSTED'] = []; /* Test which have completed and sent their
344 results to the server. */
345
346 /**
347 * Track if we should skip the POSTING state, occurs if posting returns an error .
348 */
349 /* @type {Boolean} */ var skipPosting = false;
350
351 /**
352 * Changes the state of the given test to the given state.
353 * This function doesn't check that the state transition actually make sense.
354 *
355 * @param {Element} test DOM object representing the test. The id will contain
356 * the test name.
357 * @param {States} The new state to transition too.
358 */
359 function changeTestState(test, newState) {
360 var i = null;
361
362 if (newState == 'POSTING' && skipPosting) {
363 newState = 'POSTED';
364 }
365
366 var oldState = test.state;
367
368 // If we have already posted, we should never leave...
369 if (oldState == 'POSTED') {
370 throw 'Unexpected state change! Trying to leave POSTED state to ' + newState ;
371 return;
372 }
373
374 if (typeof oldState != 'undefined') {
375 var i = testStates[oldState].indexOf(test);
376 testStates[oldState].splice(i, 1);
377 }
378
379 test.state = newState;
380 testStates[test.state].unshift(test);
381
382 function testSort(a, b) {
383 return a.id.localeCompare(b.id);
384 }
385 testStates[test.state].sort(testSort);
386
387 switch(newState) {
388 case 'LOADING':
389 runTestsIfLoaded();
390 break;
391
392 case 'LOADED':
393 if (oldState != 'LOADING') {
394 throw 'Unexpected state change! ' + oldState + ' changing to LOADED';
395 }
396 break;
397
398 case 'RUNNING':
399 if (oldState != 'LOADED') {
400 throw 'Unexpected state change! ' + oldState + ' changing to RUNNING';
401 }
402
403 test.start = now();
404 var testWindow = test.querySelector('iframe').contentWindow;
405 var msg = {type: 'start', url: testWindow.location.href + ''};
406 testWindow.postMessage(msg, '*');
407 break;
408
409 case 'FINISHED':
410 // If a test doesn't use any timing stuff it could come from the LOADING or
411 // LOADED state into the FINISHED state bypassing the RUNNING state.
412 if (oldState != 'LOADING' && oldState != 'LOADED' && oldState != 'RUNNING') {
413 throw 'Unexpected state change! ' + oldState + ' changing to FINISHED';
414 }
415
416 var timingInfo = test.querySelector('.timing');
417 if (test.start) {
418 test.finished = now();
419 timingInfo.textContent = (test.finished - test.start).toFixed(2) + 'ms';
420 } else {
421 timingInfo.textContent = '(Load only)';
422 }
423
424 var test_iframe = test.querySelector('iframe');
425 processResults(test, expectedFailuresForBrowser(test_iframe.contentWindow.ex pected_failures));
426
427 break;
428
429 case 'POSTING':
430 if (oldState != 'FINISHED') {
431 throw 'Unexpected state change! ' + oldState + ' changing to POSTING';
432 }
433
434 if (test.className == 'fail') {
435 // Open up the window of the failed result
436 test.showInfo();
437 // Scroll to it.
438 window.scroll(0, trueOffsetTop(test));
439 }
440
441 // Open the status window for taking of screenshots
442 var data = new FormData();
443 data.append('data', JSON.stringify(test.results_processed));
444
445 var xhr = new XMLHttpRequest();
446 xhr.onload = function (e) {
447 if (e.target.status >= 400) {
448 skipPosting = true;
449 }
450 // Move from running to finished state
451 changeTestState(this, 'POSTED');
452 }.bind(test);
453 xhr.open('POST', 'test-results-post.html', true);
454 xhr.send(data);
455
456 break;
457
458 case 'POSTED':
459 // If we are skipping POSTING, tests can transition straight from FINISHED
460 // state into the POSTED state.
461 if (oldState != 'POSTING' && (!skipPosting || oldState != 'FINISHED')) {
462 throw 'Unexpected state change! ' + oldState + ' changing to POSTED';
463 }
464 break;
465 }
466 }
467
468 /**
469 * Elements for reporting the overall status.
470 */
471 /* @type {Element} */ var statusElement = document.querySelector('#status');
472
473 /* @type {Element} */ var testElement = document.querySelector('#tests');
474
475 /* @type {Element} */ var loadingElement = document.querySelector('#loading');
476 /* @type {Element} */ var loadedElement = document.querySelector('#loaded');
477
478 /* @type {Element} */ var runningElement = document.querySelector('#running');
479 /* @type {Element} */ var finishedElement = document.querySelector('#finished');
480
481 /* @type {Element} */ var postingElement = document.querySelector('#posting');
482 /* @type {Element} */ var postedElement = document.querySelector('#posted');
483
484 /**
485 * Update the status dialog with information about the current status.
486 */
487 function updateStatus() {
488 testElement.textContent = tests.length;
489
490 loadingElement.textContent = testStates['LOADING'].length;
491 loadedElement.textContent = testStates['LOADED'].length;
492
493 runningElement.textContent = testStates['RUNNING'].length;
494 finishedElement.textContent = testStates['FINISHED'].length;
495
496 postingElement.textContent = testStates['POSTING'].length;
497 postedElement.textContent = testStates['POSTED'].length;
498
499 if (testStates['LOADED'].length > 0) {
500 statusElement.textContent = 'Loading';
501 } else if (testStates['RUNNING'].length > 0) {
502 statusElement.textContent = 'Running';
503 } else if (testStates['POSTING'].length > 0) {
504 statusElement.textContent = 'Posting results';
505 } else if (testStates['POSTED'].length == tests.length) {
506 statusElement.textContent = 'Finished';
507
508 window.clearInterval(updateStatusId);
509 window.clearInterval(runTestsId);
510 window.finished = true;
511 if (window.__coverage__) {
512 generateCoverageReport();
513 }
514 }
515 }
516
517 /* @type {?number} */ var updateStatusId = setInterval(updateStatus, 100);
518
519
520 var testRunners = [];
521
522 /**
523 * Create the iframes for each test.
524 */
525 window.onload = function createTestRunners() {
526 // Filter the tests
527 var filter = window.location.href.split('?')[1];
528 if (filter) {
529 filter = new RegExp(filter);
530 tests = tests.filter(function(v) {
531 return filter.exec(v);
532 });
533 }
534
535 function testSort(a, b) {
536 a = a.replace('.', '-');
537 b = b.replace('.', '-');
538 return a.localeCompare(b);
539 }
540 tests.sort(testSort);
541
542 for (var i = 0; i < tests.length; i++) {
543 var testName = tests[i];
544 var testURL = 'testcases/' + testName;
545
546 var test = createTestRows(testName, testURL);
547 testRunners.unshift(test);
548
549 changeTestState(test, 'LOADING');
550
551 document.querySelector('#results').appendChild(test);
552 test.querySelector('iframe').contentWindow.onload = function() {
553 // You can get multiple onload events, only deal with the first one.
554 if (this.state == 'LOADING') {
555 changeTestState(this, 'LOADED');
556 runTestsIfLoaded();
557 }
558 }.bind(test);
559 }
560
561 };
562
563 /**
564 * Start as many loaded tests as possible, wait for results and then post
565 * them.
566 */
567 function runTests() {
568 // Start a test running
569 if (testStates['LOADED'].length > 0 &&
570 testStates['RUNNING'].length < 1) {
571 changeTestState(testStates['LOADED'][0], 'RUNNING');
572 }
573
574 // Start a test posting
575 if (testStates['FINISHED'].length > 0 &&
576 testStates['POSTING'].length < 1) {
577 changeTestState(testStates['FINISHED'][0], 'POSTING');
578 }
579
580 // Deal with tests which are taking too long...
581 for (var i in testStates['RUNNING']) {
582 var test = testStates['RUNNING'][i];
583 if (now() - test.start > 300e3) {
584 // Only way to stop all the javascript and anything else running in the
585 // test is to clear the document.
586 var test_iframe = test.querySelector('iframe');
587 test_iframe.src = "data:text/html;charset=utf-8,<!DOCTYPE html><html><body >TIMEOUT</body></html>";
588
589 test.results_raw = [];
590 changeTestState(test, 'FINISHED');
591 }
592 }
593 }
594
595 /* @type {Object.<string, Object>} */ var testResults = {};
596 /**
597 * Callback that occurs when the test has finished running.
598 */
599 window.addEventListener(
600 'message',
601 function(evt) {
602 // If the test timed out, this will fail with a cross-origin error.
603 try {
604 var testname = evt.source.location.pathname.split('/').pop().replace('.', '-');
605 } catch (e) {
606 return;
607 }
608
609 var test = document.getElementById(testname);
610
611 // We only respond to complete as postMessage doesn't guarantee order so
612 // result messages can come in after the complete message.
613 if (evt.data['type'] != 'complete')
614 return;
615
616 // Try changing to state FINISHED, but this message may be after the a
617 // timeout or transition.
618 try {
619 test.results_raw = evt.data['tests'];
620 changeTestState(test, 'FINISHED');
621 } catch (e) {
622 console.warn(e);
623 }
624 },
625 false);
626
627
628 /**
629 * Filters expected test failures for ones that match the current browser
630 * configuration.
631 *
632 * @param {Array.<Object>} Test failure expectations for all browser
633 * configurations.
634 * @return {Object.<string, string>} Mapping from test regex to failure reason
635 * for current browser.
636 */
637 function expectedFailuresForBrowser(expected_failures) {
638 var browser_expected_failures = {};
639 if (typeof expected_failures === 'object') {
640 expected_failures.forEach(function(expected_failure) {
641 if (expected_failure.browser_configurations.some(
642 browserConfigurationMatches)) {
643 expected_failure.tests.forEach(function(test) {
644 browser_expected_failures[test] = expected_failure.message;
645 });
646 }
647 });
648 }
649 return browser_expected_failures;
650 }
651
652 /**
653 * Returns whether the browser configuration pattern matches the browser
654 * configuration reported by bowser.js.
655 * Example:
656 * { name: 'Chrome', version: '28|29' }
657 * matches browser configuration:
658 * { name: 'Chrome', webkit: true, chrome: true, version: '28.0' }
659 *
660 * @param {Object} Key - RegExp value pairs to check against.
661 * @return {bool}
662 */
663 function browserConfigurationMatches(browser_configuration) {
664 for (var browser_feature in browser_configuration) {
665 var valueRegex = new RegExp(browser_configuration[browser_feature]);
666 if (!valueRegex.test(bowser[browser_feature])) {
667 return false;
668 }
669 }
670 return true;
671 }
672
673 /**
674 * Processes the test's results and put the information into the test object.
675 *
676 * @param {Element} test DOM object representing the test.
677 * @param {Array.<Object>} results List of testharness.js result objects.
678 */
679 function processResults(test, browser_expected_failures) {
680 var counts = {
681 passed: 0,
682 failed: 0,
683 skipped: 0,
684 expected_failed: 0, // This count is included in the above
685 total: test.results_raw.length
686 };
687 var results = [];
688 var newResultsDiv = document.createElement('ul');
689
690 for(var i = 0; i < test.results_raw.length; i++) {
691 var result = test.results_raw[i];
692 results[i] = result;
693
694 // Invert expected_failures
695 var expected_failure = null;
696 for(var tname in browser_expected_failures) {
697 var tomatch = tname;
698 if (tname.charAt(0) == '/' && tname.charAt(tname.length-1) == '/') {
699 tomatch = new RegExp(tname.substr(1, tname.length-2));
700 }
701 if (result['name'].match(tomatch)) {
702 expected_failure = browser_expected_failures[tname];
703 }
704 }
705 if (expected_failure !== null && result.status != result.NOTRUN) {
706 if (result.status != result.FAIL) {
707 result.message = "Expected failure (" + expected_failure + "), actually " +
708 {0: 'PASS', 2: 'TIMEOUT', 3:'NOTRUN'}[result.status] + " " +
709 result.message;
710 result.status = result.FAIL;
711 } else {
712 result.status = result.PASS;
713 result.message = "Expected failure (" + expected_failure + "): " + resul t.message;
714 }
715 counts.expected_failed++;
716 }
717
718 var output = document.createElement('li');
719 output.innerHTML += result.name + ': ';
720
721 switch (result.status) {
722 case result.PASS:
723 if (!expected_failure) {
724 output.className = 'pass';
725 } else {
726 output.className = 'pass-expected-failure';
727 }
728 counts.passed++;
729 break;
730
731 case result.TIMEOUT:
732 output.className = 'timeout';
733 counts.failed++;
734 break;
735
736 case result.NOTRUN:
737 output.className = 'skipped';
738 counts.skipped++;
739 break;
740
741 case result.FAIL:
742 default:
743 output.className = 'failed';
744 counts.failed++;
745 }
746
747 output.innerHTML += output.className;
748 if (result.message != null) {
749 output.innerHTML += ' - ' + result.message;
750 }
751 newResultsDiv.appendChild(output);
752 }
753 test.querySelector('.log').appendChild(newResultsDiv);
754
755 var debug = '';
756 try {
757 debug = test.querySelector('iframe').contentDocument.getElementById('debug') .innerText;
758 } catch (e) {
759 debug = 'No debug... :(';
760 }
761
762 if (counts.total > 0) {
763 test.results_processed = {
764 type: 'result',
765 testName: test.id,
766 results: results,
767 debug: debug
768 };
769
770 if (counts.failed == 0) {
771 if (counts.expected_failed > 0) {
772 test.className = 'pass-expected-failure';
773 } else if (counts.skipped > 0) {
774 test.className = 'skipped';
775 } else {
776 test.className = 'pass';
777 }
778 } else {
779 test.className = 'fail';
780 }
781
782 var summary = counts.total + ' tests; ';
783 if (counts.passed > 0) {
784 summary += ' ' + counts.passed + ' passed';
785 if (counts.expected_failed > 0) {
786 summary += ' (with ' + counts.expected_failed + ' expected failures)';
787 }
788 }
789 if (counts.failed > 0) {
790 summary += ' ' + counts.failed + ' failed';
791 }
792 if (counts.skipped > 0) {
793 summary += ' ' + counts.skipped + ' skipped';
794 }
795 test.querySelector('.count').textContent = summary;
796 } else {
797 test.results_processed = {
798 type: 'result',
799 testName: test.id,
800 results: [],
801 };
802 test.className = 'no-tests';
803 test.querySelector('.count').textContent = 'TIMEOUT';
804 }
805 }
806
807 })();
808
809
810 </script>
OLDNEW
« no previous file with comments | « bower_components/web-animations-js/test/test-results-post.html ('k') | bower_components/web-animations-js/test/testcases.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698