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

Unified Diff: pkg/polymer/lib/elements/web-animations-js/test/test-runner.html

Issue 175443005: [polymer] import all elements (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: updated from bower Created 6 years, 10 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 side-by-side diff with in-line comments
Download patch
Index: pkg/polymer/lib/elements/web-animations-js/test/test-runner.html
diff --git a/pkg/polymer/lib/elements/web-animations-js/test/test-runner.html b/pkg/polymer/lib/elements/web-animations-js/test/test-runner.html
new file mode 100755
index 0000000000000000000000000000000000000000..e3fc354791b56d3acab3942bc395a430a1264c24
--- /dev/null
+++ b/pkg/polymer/lib/elements/web-animations-js/test/test-runner.html
@@ -0,0 +1,777 @@
+<!--
+Copyright 2012 Google Inc. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<!DOCTYPE html>
+<meta charset="UTF-8">
+
+<style>
+
+#status-box {
+ position: fixed;
+ bottom: 0;
+ right: 0;
+ background: white;
+ border: 1px solid black;
+ padding-right: 5px;
+}
+
+h1 {
+ display: inline;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+td {
+ border: 1px solid black;
+}
+
+iframe {
+ width: 800px;
+ height: 600px;
+}
+
+tbody {
+ color: gray;
+}
+
+td.log ul li {
+ white-space: pre;
+ font-family: monospace;
+}
+
+/* Fail styles */
+tbody.fail {
+ color: red;
+}
+
+li.fail {
+ color: red;
+}
+
+tbody.timeout {
+ color: yellow;
+}
+
+li.timeout {
+ color: yellow;
+}
+
+
+/* Pass styles */
+tbody.pass {
+ color: green;
+}
+
+li.pass {
+ color: green;
+}
+
+tbody.pass-expected-failure {
+ color: #00aa00;
+}
+
+li.pass-expected-failure {
+ color: #00aa00;
+}
+
+tbody.skipped {
+ color: #00aa00;
+}
+
+li.skipped {
+ color: #00aa00;
+}
+
+/* No-test styles */
+tbody.no-tests {
+ color: #ff8a00;
+}
+
+</style>
+<script src="browserdetect/bowser.js"></script>
+<script src="testcases.js"></script>
+
+<div id=status-box>
+<h1 id=status>Pending</h1>
+Tests: <span id=tests></span>
+Loading: <span id=loading></span> (<span id=loaded></span>)
+Running: <span id=running></span> (<span id=finished></span>)
+Posting: <span id=posting></span> (<span id=posted></span>)
+</div>
+
+<table id="results"></table>
+<div id="spacer"></div>
+
+<script>
+'use strict';
+window.onerror = function(msg, url, line) {
+ // Ignore errors caused by webdriver
+ if (msg.match(/webdriver/))
+ return;
+
+ if (document.getElementById('javascript-errors') == null) {
+ document.body.innerHTML = '<pre id="javascript-errors">JAVASCRIPT ERRORS\n\n</pre>';
+ }
+
+ var e = document.getElementById('javascript-errors');
+ var msg = 'Javascript Error in ' + url + '\n' +
+ 'Line ' + line + ': ' + msg + '\n';
+ e.innerHTML += msg;
+};
+</script>
+
+<script>
+'use strict';
+
+(function() {
+window.finished = false;
+window.getTestRunnerProgress = function() {
+ return {
+ completed: testStates['POSTED'].length,
+ total: tests.length,
+ };
+}
+
+var results = [];
+
+if (/coverage/.test(window.location.hash)) {
+ // Trigger coverage runs for child tests.
+ window.__coverage__ = {};
+ // Share resources loaded by child tests to avoid instrumenting the same
+ // source file multiple times.
+ window.__resources__ = {original: {}};
+}
+
+window.addEventListener('load', function() {
+ document.querySelector('#spacer').style.height =
+ getComputedStyle(document.querySelector('body')).height;
+});
+function trueOffsetTop(element) {
+ var t = 0;
+ if (element.offsetParent) {
+ do {
+ t += element.offsetTop;
+ } while (element = element.offsetParent);
+ return t;
+ }
+}
+
+/**
+ * Get a value for busting the cache.
+ */
+var cacheBuster = '' + window.Date.now();
+
+/**
+ * Get the most accurate version of time possible.
+ *
+ * @return {number} Time as this very moment.
+ */
+function now() {
+ try {
+ return window.performance.now();
+ } catch (e) {
+ return Date.now();
+ }
+}
+
+/**
+ * Creates HTML elements in a table for a test.
+ *
+ * +-----------+------+-------+
+ * | Test Name | Link | Count |
+ * +-----------+------+-------+
+ * | Log of test run. |
+ * +--------------------------+
+ * | iFrame containing test |
+ * +--------------------------+
+ *
+ * @param {String} testName Name of the test suite being run.
+ * @param {String} testURL The url of the test suite.
+ * @return {Element} tbody containing newly created table rows.
+ */
+function createTestRows(testName, testURL) {
+ var tableGroup = document.createElement('tbody');
+ tableGroup.id = testName.replace('.', '-');
+
+ var basicInfoRow = document.createElement('tr');
+ basicInfoRow.className = 'info-row';
+ tableGroup.appendChild(basicInfoRow);
+ var iframeRow = document.createElement('tr');
+ tableGroup.appendChild(iframeRow);
+ var logRow = document.createElement('tr');
+ tableGroup.appendChild(logRow);
+
+ // Name
+ var header = document.createElement('h1');
+ header.textContent = testName;
+
+ var headerCell = document.createElement('td');
+ headerCell.appendChild(header);
+ basicInfoRow.appendChild(headerCell);
+
+ // Link
+ var link = document.createElement('a');
+ link.textContent = testName;
+ link.href = testURL;
+
+ var linkCell = document.createElement('td');
+ linkCell.appendChild(link);
+ basicInfoRow.appendChild(linkCell);
+
+ // Test count
+ var countCell = document.createElement('td');
+ countCell.className = 'count';
+ basicInfoRow.appendChild(countCell);
+
+ // Timing info
+ var timingCell = document.createElement('td');
+ timingCell.className = 'timing';
+ basicInfoRow.appendChild(timingCell);
+
+ // iframe containing a preview of object
+ var iframe = document.createElement('iframe');
+ iframe.src = testURL + '?' + cacheBuster + '#message';
+
+ var iframeCell = document.createElement('td');
+ iframeCell.colSpan = '4';
+ iframeCell.appendChild(iframe);
+ iframeRow.appendChild(iframeCell);
+
+ // table row containing the complete test log
+ var logCell = document.createElement('td');
+ logCell.className = 'log';
+ logCell.colSpan = '4';
+ logRow.appendChild(logCell);
+
+ /**
+ * Normally we would use "display: none;" but that causes Firefox to return
+ * null for getComputedStyle, so instead we have to use this visibility hack.
+ */
+ tableGroup.showInfo = function() {
+ logRow.style.visibility = 'visible';
+ logRow.style.position = '';
+ logRow.style.height = 'auto';
+
+ iframeRow.style.visibility = 'visible';
+ iframeRow.style.position = '';
+ iframeRow.style.height = 'auto';
+ };
+ tableGroup.hideInfo = function() {
+ logRow.style.visibility = 'hidden';
+ logRow.style.position = 'absolute';
+ logRow.style.height = '0';
+
+ iframeRow.style.visibility = 'hidden';
+ iframeRow.style.position = 'absolute';
+ iframeRow.style.height = '0';
+ };
+ tableGroup.toggleInfo = function() {
+ if (logRow.style.visibility == 'hidden') {
+ tableGroup.showInfo();
+ } else {
+ tableGroup.hideInfo();
+ }
+ };
+ basicInfoRow.onclick = tableGroup.toggleInfo;
+
+ tableGroup.hideInfo();
+
+ return tableGroup;
+}
+
+/* @type {?number} */ var runTestsId = null;
+
+/**
+ * Checks all the tests are in the loaded state and then kicks of running
+ * the tests.
+ */
+function runTestsIfLoaded() {
+ if (testStates['LOADING'].length > 0)
+ return;
+
+ if (runTestsId == null) {
+ runTestsId = window.setInterval(runTests, 10);
+ }
+}
+
+function generateCoverageReport() {
+ // TODO: generate a pretty report, prompt to save the JSON, post it somewhere
+ for (var file in window.__coverage__) {
+ var results = window.__coverage__[file];
+ var hits = 0;
+ var statements = 0;
+ for (var stmt in results.s) {
+ statements++;
+ if (results.s[stmt] > 0) {
+ hits++;
+ }
+ }
+ var percent = (100 * hits / statements).toFixed(2);
+ console.log(file + ' statement coverage ' +
+ percent + '% (' + hits + '/' + statements + ')');
+ }
+}
+
+/**
+ * This object tracks which state a test is in. An individual test should only
+ * ever be in one of the lists. You use the changeTestState() function to move
+ * from one state to another.
+ *
+ * Tests start off in the loading state and move downwards until ending up in
+ * the finished state.
+ */
+var testStates = {};
+testStates['LOADING'] = []; /* Test which is being loaded. */
+testStates['LOADED'] = []; /* Test which have yet to start. */
+testStates['RUNNING'] = []; /* Test that is currently running. */
+testStates['FINISHED'] = []; /* Test that are finished. */
+testStates['POSTING'] = []; /* Test that is currently posting results to server. */
+testStates['POSTED'] = []; /* Test which have completed and sent their
+ results to the server. */
+
+/**
+ * Track if we should skip the POSTING state, occurs if posting returns an error.
+ */
+/* @type {Boolean} */ var skipPosting = false;
+
+/**
+ * Changes the state of the given test to the given state.
+ * This function doesn't check that the state transition actually make sense.
+ *
+ * @param {Element} test DOM object representing the test. The id will contain
+ * the test name.
+ * @param {States} The new state to transition too.
+ */
+function changeTestState(test, newState) {
+ var i = null;
+
+ if (newState == 'POSTING' && skipPosting) {
+ newState = 'POSTED';
+ }
+
+ var oldState = test.state;
+
+ // If we have already posted, we should never leave...
+ if (oldState == 'POSTED') {
+ throw 'Unexpected state change! Trying to leave POSTED state to ' + newState;
+ return;
+ }
+
+ if (typeof oldState != 'undefined') {
+ var i = testStates[oldState].indexOf(test);
+ testStates[oldState].splice(i, 1);
+ }
+
+ test.state = newState;
+ testStates[test.state].unshift(test);
+
+ function testSort(a, b) {
+ return a.id.localeCompare(b.id);
+ }
+ testStates[test.state].sort(testSort);
+
+ switch(newState) {
+ case 'LOADING':
+ runTestsIfLoaded();
+ break;
+
+ case 'LOADED':
+ if (oldState != 'LOADING') {
+ throw 'Unexpected state change! ' + oldState + ' changing to LOADED';
+ }
+ break;
+
+ case 'RUNNING':
+ if (oldState != 'LOADED') {
+ throw 'Unexpected state change! ' + oldState + ' changing to RUNNING';
+ }
+
+ test.start = now();
+ var testWindow = test.querySelector('iframe').contentWindow;
+ var msg = {type: 'start', url: testWindow.location.href + ''};
+ testWindow.postMessage(msg, '*');
+ break;
+
+ case 'FINISHED':
+ // If a test doesn't use any timing stuff it could come from the LOADING or
+ // LOADED state into the FINISHED state bypassing the RUNNING state.
+ if (oldState != 'LOADING' && oldState != 'LOADED' && oldState != 'RUNNING') {
+ throw 'Unexpected state change! ' + oldState + ' changing to FINISHED';
+ }
+
+ var timingInfo = test.querySelector('.timing');
+ if (test.start) {
+ test.finished = now();
+ timingInfo.textContent = (test.finished - test.start).toFixed(2) + 'ms';
+ } else {
+ timingInfo.textContent = '(Load only)';
+ }
+
+ var test_iframe = test.querySelector('iframe');
+ processResults(test, test_iframe.contentWindow.expected_failures);
+
+ break;
+
+ case 'POSTING':
+ if (oldState != 'FINISHED') {
+ throw 'Unexpected state change! ' + oldState + ' changing to POSTING';
+ }
+
+ if (test.className == 'fail') {
+ // Open up the window of the failed result
+ test.showInfo();
+ // Scroll to it.
+ window.scroll(0, trueOffsetTop(test));
+ }
+
+ // Open the status window for taking of screenshots
+ var data = new FormData();
+ data.append('data', JSON.stringify(test.results_processed));
+
+ var xhr = new XMLHttpRequest();
+ xhr.onload = function (e) {
+ if (e.target.status >= 400) {
+ skipPosting = true;
+ }
+ // Move from running to finished state
+ changeTestState(this, 'POSTED');
+ }.bind(test);
+ xhr.open('POST', 'test-results-post.html', true);
+ xhr.send(data);
+
+ break;
+
+ case 'POSTED':
+ // If we are skipping POSTING, tests can transition straight from FINISHED
+ // state into the POSTED state.
+ if (oldState != 'POSTING' && (!skipPosting || oldState != 'FINISHED')) {
+ throw 'Unexpected state change! ' + oldState + ' changing to POSTED';
+ }
+ break;
+ }
+}
+
+/**
+ * Elements for reporting the overall status.
+ */
+/* @type {Element} */ var statusElement = document.querySelector('#status');
+
+/* @type {Element} */ var testElement = document.querySelector('#tests');
+
+/* @type {Element} */ var loadingElement = document.querySelector('#loading');
+/* @type {Element} */ var loadedElement = document.querySelector('#loaded');
+
+/* @type {Element} */ var runningElement = document.querySelector('#running');
+/* @type {Element} */ var finishedElement = document.querySelector('#finished');
+
+/* @type {Element} */ var postingElement = document.querySelector('#posting');
+/* @type {Element} */ var postedElement = document.querySelector('#posted');
+
+/**
+ * Update the status dialog with information about the current status.
+ */
+function updateStatus() {
+ testElement.textContent = tests.length;
+
+ loadingElement.textContent = testStates['LOADING'].length;
+ loadedElement.textContent = testStates['LOADED'].length;
+
+ runningElement.textContent = testStates['RUNNING'].length;
+ finishedElement.textContent = testStates['FINISHED'].length;
+
+ postingElement.textContent = testStates['POSTING'].length;
+ postedElement.textContent = testStates['POSTED'].length;
+
+ if (testStates['LOADED'].length > 0) {
+ statusElement.textContent = 'Loading';
+ } else if (testStates['RUNNING'].length > 0) {
+ statusElement.textContent = 'Running';
+ } else if (testStates['POSTING'].length > 0) {
+ statusElement.textContent = 'Posting results';
+ } else if (testStates['POSTED'].length == tests.length) {
+ statusElement.textContent = 'Finished';
+
+ window.clearInterval(updateStatusId);
+ window.clearInterval(runTestsId);
+ window.finished = true;
+ if (window.__coverage__) {
+ generateCoverageReport();
+ }
+ }
+}
+
+/* @type {?number} */ var updateStatusId = setInterval(updateStatus, 100);
+
+
+var testRunners = [];
+
+/**
+ * Create the iframes for each test.
+ */
+window.onload = function createTestRunners() {
+ // Filter the tests
+ var filter = window.location.href.split('?')[1];
+ if (filter) {
+ filter = new RegExp(filter);
+ tests = tests.filter(function(v) {
+ return filter.exec(v);
+ });
+ }
+
+ function testSort(a, b) {
+ a = a.replace('.', '-');
+ b = b.replace('.', '-');
+ return a.localeCompare(b);
+ }
+ tests.sort(testSort);
+
+ for (var i = 0; i < tests.length; i++) {
+ var testName = tests[i];
+ var testURL = 'testcases/' + testName;
+
+ var test = createTestRows(testName, testURL);
+ testRunners.unshift(test);
+
+ changeTestState(test, 'LOADING');
+
+ document.querySelector('#results').appendChild(test);
+ test.querySelector('iframe').contentWindow.onload = function() {
+ // You can get multiple onload events, only deal with the first one.
+ if (this.state == 'LOADING') {
+ changeTestState(this, 'LOADED');
+ runTestsIfLoaded();
+ }
+ }.bind(test);
+ }
+
+};
+
+/**
+ * Start as many loaded tests as possible, wait for results and then post
+ * them.
+ */
+function runTests() {
+ // Start a test running
+ if (testStates['LOADED'].length > 0 &&
+ testStates['RUNNING'].length < 1) {
+ changeTestState(testStates['LOADED'][0], 'RUNNING');
+ }
+
+ // Start a test posting
+ if (testStates['FINISHED'].length > 0 &&
+ testStates['POSTING'].length < 1) {
+ changeTestState(testStates['FINISHED'][0], 'POSTING');
+ }
+
+ // Deal with tests which are taking too long...
+ for (var i in testStates['RUNNING']) {
+ var test = testStates['RUNNING'][i];
+ if (now() - test.start > 300e3) {
+ // Only way to stop all the javascript and anything else running in the
+ // test is to clear the document.
+ var test_iframe = test.querySelector('iframe');
+ test_iframe.src = "data:text/html;charset=utf-8,<!DOCTYPE html><html><body>TIMEOUT</body></html>";
+
+ test.results_raw = [];
+ changeTestState(test, 'FINISHED');
+ }
+ }
+}
+
+/* @type {Object.<string, Object>} */ var testResults = {};
+/**
+ * Callback that occurs when the test has finished running.
+ */
+window.addEventListener(
+ 'message',
+ function(evt) {
+ // If the test timed out, this will fail with a cross-origin error.
+ try {
+ var testname = evt.source.location.pathname.split('/').pop().replace('.', '-');
+ } catch (e) {
+ return;
+ }
+
+ var test = document.getElementById(testname);
+
+ // We only respond to complete as postMessage doesn't guarantee order so
+ // result messages can come in after the complete message.
+ if (evt.data['type'] != 'complete')
+ return;
+
+ // Try changing to state FINISHED, but this message may be after the a
+ // timeout or transition.
+ try {
+ test.results_raw = evt.data['tests'];
+ changeTestState(test, 'FINISHED');
+ } catch (e) {
+ console.warn(e);
+ }
+ },
+ false);
+
+
+/**
+ * Processes the test's results and put the information into the test object.
+ *
+ * @param {Element} test DOM object representing the test.
+ * @param {Array.<Object>} results List of testharness.js result objects.
+ */
+function processResults(test, expected_failures) {
+ var browser_expected_failures = {};
+ for(var tname in expected_failures) {
+ for(var bname in bowser) {
+ var fails = expected_failures[tname][bname];
+ if ((typeof fails != "undefined") &&
+ (typeof fails == "boolean" && fails) ||
+ (typeof fails == "object" && fails.indexOf(bowser.version) != -1)) {
+ browser_expected_failures[tname] = expected_failures[tname];
+ }
+ }
+ }
+
+ var counts = {
+ passed: 0,
+ failed: 0,
+ skipped: 0,
+ expected_failed: 0, // This count is included in the above
+ total: test.results_raw.length
+ };
+ var results = [];
+ var newResultsDiv = document.createElement('ul');
+
+ for(var i = 0; i < test.results_raw.length; i++) {
+ var result = test.results_raw[i];
+ results[i] = result;
+
+ // Invert expected_failures
+ var expected_failure = null;
+ for(var tname in browser_expected_failures) {
+ var tomatch = tname;
+ if (tname.charAt(0) == '/' && tname.charAt(tname.length-1) == '/') {
+ tomatch = new RegExp(tname.substr(1, tname.length-2));
+ }
+ if (result['name'].match(tomatch)) {
+ expected_failure = browser_expected_failures[tname];
+ }
+ }
+ if (expected_failure !== null && result.status != result.NOTRUN) {
+ if (result.status != result.FAIL) {
+ result.message = "Expected failure (" + expected_failure.message + "), actually " +
+ {0: 'PASS', 2: 'TIMEOUT', 3:'NOTRUN'}[result.status] + " " +
+ result.message;
+ result.status = result.FAIL;
+ } else {
+ result.status = result.PASS;
+ result.message = "Expected failure (" + expected_failure.message + "): " + result.message;
+ }
+ counts.expected_failed++;
+ }
+
+ var output = document.createElement('li');
+ output.innerHTML += result.name + ': ';
+
+ switch (result.status) {
+ case result.PASS:
+ if (!expected_failure) {
+ output.className = 'pass';
+ } else {
+ output.className = 'pass-expected-failure';
+ }
+ counts.passed++;
+ break;
+
+ case result.TIMEOUT:
+ output.className = 'timeout';
+ counts.failed++;
+ break;
+
+ case result.NOTRUN:
+ output.className = 'skipped';
+ counts.skipped++;
+ break;
+
+ case result.FAIL:
+ default:
+ output.className = 'failed';
+ counts.failed++;
+ }
+
+ output.innerHTML += output.className;
+ if (result.message != null) {
+ output.innerHTML += ' - ' + result.message;
+ }
+ newResultsDiv.appendChild(output);
+ }
+ test.querySelector('.log').appendChild(newResultsDiv);
+
+ var debug = '';
+ try {
+ debug = test.querySelector('iframe').contentDocument.getElementById('debug').innerText;
+ } catch (e) {
+ debug = 'No debug... :(';
+ }
+
+ if (counts.total > 0) {
+ test.results_processed = {
+ type: 'result',
+ testName: test.id,
+ results: results,
+ debug: debug
+ };
+
+ if (counts.failed == 0) {
+ if (counts.expected_failed > 0) {
+ test.className = 'pass-expected-failure';
+ } else if (counts.skipped > 0) {
+ test.className = 'skipped';
+ } else {
+ test.className = 'pass';
+ }
+ } else {
+ test.className = 'fail';
+ }
+
+ var summary = counts.total + ' tests; ';
+ if (counts.passed > 0) {
+ summary += ' ' + counts.passed + ' passed';
+ if (counts.expected_failed > 0) {
+ summary += ' (with ' + counts.expected_failed + ' expected failures)';
+ }
+ }
+ if (counts.failed > 0) {
+ summary += ' ' + counts.failed + ' failed';
+ }
+ if (counts.skipped > 0) {
+ summary += ' ' + counts.skipped + ' skipped';
+ }
+ test.querySelector('.count').textContent = summary;
+ } else {
+ test.results_processed = {
+ type: 'result',
+ testName: test.id,
+ results: [],
+ };
+ test.className = 'no-tests';
+ test.querySelector('.count').textContent = 'TIMEOUT';
+ }
+}
+
+})();
+
+
+</script>

Powered by Google App Engine
This is Rietveld 408576698