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> |