Index: bower_components/web-animations-js/test/bootstrap.js |
diff --git a/bower_components/web-animations-js/test/bootstrap.js b/bower_components/web-animations-js/test/bootstrap.js |
deleted file mode 100644 |
index 224045f795b974bc56a58bcc707de69a6c2fc84d..0000000000000000000000000000000000000000 |
--- a/bower_components/web-animations-js/test/bootstrap.js |
+++ /dev/null |
@@ -1,1266 +0,0 @@ |
-/** |
- * Copyright 2013 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. |
- */ |
-'use strict'; |
- |
-(function() { |
- |
-var log_element = document.createElement('pre'); |
-log_element.id = 'debug'; |
- |
-var log_element_parent = setInterval(function() { |
- if (log_element.parentNode == null && document.body != null) { |
- document.body.appendChild(log_element); |
- clearInterval(log_element_parent); |
- } |
-}, 100); |
- |
-function log() { |
- |
- var output = []; |
- for (var i = 0; i < arguments.length; i++) { |
- if (typeof arguments[i] === "function") { |
- arguments[i] = '' + arguments[i]; |
- } |
- if (typeof arguments[i] === "string") { |
- var bits = arguments[i].replace(/\s*$/, '').split('\n'); |
- if (bits.length > 5) { |
- bits.splice(3, bits.length-5, '...'); |
- } |
- output.push(bits.join('\n')); |
- } else if (typeof arguments[i] === "object" && typeof arguments[i].name === "string") { |
- output.push('"'+arguments[i].name+'"'); |
- } else { |
- output.push(JSON.stringify(arguments[i], undefined, 2)); |
- } |
- output.push(' '); |
- } |
- log_element.appendChild(document.createTextNode(output.join('') + '\n')); |
-} |
- |
-var thisScript = document.querySelector("script[src$='bootstrap.js']"); |
-var coverageMode = Boolean(parent.window.__coverage__) || /coverage/.test(window.location.hash); |
- |
-// Inherit these properties from the parent test-runner if any. |
-window.__resources__ = parent.window.__resources__ || {original: {}}; |
-window.__coverage__ = parent.window.__coverage__; |
- |
-function getSync(src) { |
- var xhr = new XMLHttpRequest(); |
- xhr.open('GET', src, false); |
- xhr.send(); |
- if (xhr.responseCode > 400) { |
- console.error('Error loading ' + src); |
- return ''; |
- } |
- return xhr.responseText; |
-} |
- |
-function loadScript(src, options) { |
- // Add changing parameter to prevent script caching. |
- options = options || {coverage: true}; |
- if (window.__resources__[src]) { |
- document.write('<script type="text/javascript">eval(window.__resources__["'+src+'"]);</script>'); |
- } else if (coverageMode && options.coverage) { |
- instrument(src); |
- loadScript(src); |
- } else { |
- if (!inExploreMode()) { |
- src += '?' + getCacheBuster(); |
- } |
- document.write('<script type="text/javascript" src="'+ src + '"></script>'); |
- } |
-} |
- |
-function loadCSS(src) { |
- document.write('<link rel="stylesheet" type="text/css" href="' + src + '">'); |
-} |
- |
-function forEach(array, callback, thisObj) { |
- for (var i=0; i < array.length; i++) { |
- if (array.hasOwnProperty(i)) { |
- callback.call(thisObj, array[i], i, array); |
- } |
- } |
-} |
- |
-function hasFlag(flag) { |
- return thisScript && thisScript.getAttribute(flag) !== null; |
-} |
- |
-function testType() { |
- var p = location.pathname; |
- p = p.replace(/^disabled-/, ''); |
- |
- var match = /(auto|impl|manual|unit)-test[^\\\/]*$/.exec(p); |
- return match ? match[1]: 'unknown'; |
-} |
- |
-function inExploreMode() { |
- return '#explore' == window.location.hash || window.location.hash.length == 0; |
-} |
- |
-/** |
- * Get a value for busting the cache. If we got given a cache buster, pass it |
- * along, otherwise generate a new one. |
- */ |
-var cacheBusterValue = '' + window.Date.now(); |
-function getCacheBuster() { |
- if (window.location.search.length > 0) |
- cacheBusterValue = window.location.search.substr(1, window.location.search.length); |
- return cacheBusterValue; |
-} |
- |
-var instrumentationDepsLoaded = false; |
-/** |
- * Instrument the source at {@code location} and store it in |
- * {@code window.__resources__[name]}. |
- */ |
-function instrument(src) { |
- if (__resources__[src]) { |
- return; |
- } |
- if (!instrumentationDepsLoaded) { |
- instrumentationDepsLoaded = true; |
- (function() { |
- eval(getSync('../coverage/esprima/esprima.js')); |
- eval(getSync('../coverage/escodegen/escodegen.browser.js')); |
- eval(getSync('../coverage/istanbul/lib/instrumenter.js')); |
- }).call(window); |
- } |
- var js = getSync(src); |
- window.__resources__.original[src] = js; |
- var inst = window.__resources__[src] = new Instrumenter().instrumentSync(js, src); |
-} |
- |
-var svg_namespace_uri = 'http://www.w3.org/2000/svg'; |
- |
-/** |
- * Figure out a useful name for an element. |
- * |
- * @param {Element} element Element to get the name for. |
- * |
- * @private |
- */ |
-function _element_name(element) { |
- if (element.id) { |
- return element.tagName.toLowerCase() + '#' + element.id; |
- } else { |
- return 'An anonymous ' + element.tagName.toLowerCase(); |
- } |
-} |
- |
-/** |
- * Get the style for a given element. |
- * |
- * @param {Array.<Object.<string, string>>|Object.<string, string>} style |
- * Either; |
- * * A list of dictionaries, each node returned is checked against the |
- * associated dictionary, or |
- * * A single dictionary, each node returned is checked against the |
- * given dictionary. |
- * Each dictionary should be of the form {style_name: style_value}. |
- * |
- * @private |
- */ |
-function _assert_style_get(style, i) { |
- if (typeof style[i] === 'undefined') { |
- return style; |
- } else { |
- return style[i]; |
- } |
-} |
- |
-/** |
- * Extract all the informative parts of a string. Ignores spacing, punctuation |
- * and other random extra characters. |
- */ |
-function _extract_important(input) { |
- var re = /([-+]?[0-9]+\.?[0-9]*(?:[eE][-+]?[0-9]+)?)|[A-Za-z%]+/g; |
- |
- var match; |
- var result = []; |
- while (match = re.exec(input)) { |
- var value = match[0]; |
- if (typeof match[1] != "undefined") { |
- value = Number(match[1]); |
- } |
- result.push(value); |
- } |
- return result; |
-} |
-window.assert_styles_extract_important = _extract_important; |
- |
-function AssertionError(message) { |
- this.message = message; |
-} |
-window.assert_styles_assertion_error = AssertionError; |
- |
-/** |
- * Asserts that a string is in the array of expected only comparing the |
- * important parts. Ignores spacing, punctuation and other random extra |
- * characters. |
- */ |
-function _assert_important_in_array(actual, expected, message) { |
- var actual_array = _extract_important(actual); |
- |
- var expected_array_array = []; |
- for (var i = 0; i < expected.length; i++) { |
- expected_array_array.push(_extract_important(expected[i])); |
- } |
- |
- var errors = []; |
- for (var i = 0; i < expected_array_array.length; i++) { |
- var expected_array = expected_array_array[i]; |
- |
- var element_errors = []; |
- if (actual_array.length != expected_array.length) { |
- element_errors.push('Number of elements don\'t match'); |
- } |
- |
- for (var j = 0; j < expected_array.length; j++) { |
- var actual = actual_array[j]; |
- var expected = expected_array[j]; |
- |
- try { |
- assert_equals(typeof actual, typeof expected); |
- |
- if (typeof actual === 'number') { |
- if (Math.abs(actual) < 1e-10) { |
- actual = 0; |
- } |
- actual = '' + actual.toPrecision(4); |
- } |
- if (typeof expected === 'number') { |
- if (Math.abs(expected) < 1e-10) { |
- expected = 0; |
- } |
- expected = '' + expected.toPrecision(4); |
- } |
- |
- assert_equals(actual, expected); |
- } catch (e) { |
- element_errors.push( |
- 'Element ' + j + ' - ' + e.message); |
- } |
- } |
- |
- if (element_errors.length == 0) { |
- return; |
- } else { |
- errors.push( |
- ' Expectation ' + JSON.stringify(expected_array) + ' did not match\n' + |
- ' ' + element_errors.join('\n ')); |
- } |
- } |
- if (expected_array_array.length > 1) |
- errors.unshift(' ' + expected_array_array.length + ' possible expectations'); |
- |
- errors.unshift(' Actual - ' + JSON.stringify(actual_array)); |
- if (typeof message !== 'undefined') { |
- errors.unshift(message); |
- } |
- throw new AssertionError(errors.join('\n')); |
-} |
-window.assert_styles_assert_important_in_array = _assert_important_in_array; |
- |
-/** |
- * asserts that actual has the same styles as the dictionary given by |
- * expected. |
- * |
- * @param {Element} object DOM node to check the styles on |
- * @param {Object.<string, string>} styles Dictionary of {style_name: style_value} to check |
- * on the object. |
- * @param {String} description Human readable description of what you are |
- * trying to check. |
- * |
- * @private |
- */ |
-function _assert_style_element(object, style, description) { |
- if (typeof message == 'undefined') |
- description = ''; |
- |
- // Create an element of the same type as testing so the style can be applied |
- // from the test. This is so the css property (not the -webkit-does-something |
- // tag) can be read. |
- var reference_element = (object.namespaceURI == svg_namespace_uri) ? |
- document.createElementNS(svg_namespace_uri, object.nodeName) : |
- document.createElement(object.nodeName); |
- var computedObjectStyle = getComputedStyle(object, null); |
- for (var i = 0; i < computedObjectStyle.length; i++) { |
- var property = computedObjectStyle[i]; |
- reference_element.style.setProperty(property, |
- computedObjectStyle.getPropertyValue(property)); |
- } |
- reference_element.style.position = 'absolute'; |
- if (object.parentNode) { |
- object.parentNode.appendChild(reference_element); |
- } |
- |
- try { |
- // Apply the style |
- for (var prop_name in style) { |
- // If the passed in value is an element then grab its current style for |
- // that property |
- if (style[prop_name] instanceof HTMLElement || |
- style[prop_name] instanceof SVGElement) { |
- |
- var prop_value = getComputedStyle(style[prop_name], null)[prop_name]; |
- } else { |
- var prop_value = style[prop_name]; |
- } |
- |
- prop_value = '' + prop_value; |
- |
- var output_prop_name = _WebAnimationsTestingUtilities._prefixProperty(prop_name); |
- |
- var is_svg = _WebAnimationsTestingUtilities._propertyIsSVGAttrib(prop_name, object); |
- if (is_svg) { |
- reference_element.setAttribute(prop_name, prop_value); |
- |
- var current_style = object.attributes; |
- var target_style = reference_element.attributes; |
- } else { |
- reference_element.style[output_prop_name] = prop_value; |
- |
- var current_style = computedObjectStyle; |
- var target_style = getComputedStyle(reference_element, null); |
- |
- _assert_important_in_array( |
- prop_value, [reference_element.style[output_prop_name], target_style[output_prop_name]], |
- 'Tried to set the reference element\'s '+ output_prop_name + |
- ' to ' + JSON.stringify(prop_value) + |
- ' but neither the style' + |
- ' ' + JSON.stringify(reference_element.style[output_prop_name]) + |
- ' nor computedStyle ' + JSON.stringify(target) + |
- ' ended up matching requested value.'); |
- } |
- |
- if (prop_name == 'ctm') { |
- var ctm = object.getCTM(); |
- var curr = '{' + ctm.a + ', ' + |
- ctm.b + ', ' + ctm.c + ', ' + ctm.d + ', ' + |
- ctm.e + ', ' + ctm.f + '}'; |
- |
- var target = prop_value; |
- |
- } else if (is_svg) { |
- var target = target_style[prop_name].value; |
- var curr = current_style[prop_name].value; |
- } else { |
- var target = target_style[output_prop_name]; |
- var curr = current_style[output_prop_name]; |
- } |
- |
- var description_extra = '\n Property ' + prop_name; |
- if (prop_name != output_prop_name) |
- description_extra += '(actually ' + output_prop_name + ')'; |
- |
- _assert_important_in_array(curr, [target], description + description_extra); |
- } |
- } finally { |
- if (reference_element.parentNode) { |
- reference_element.parentNode.removeChild(reference_element); |
- } |
- } |
-} |
- |
-/** |
- * asserts that elements in the list have given styles. |
- * |
- * @param {Array.<Element>} objects List of DOM nodes to check the styles on |
- * @param {Array.<Object.<string, string>>|Object.<string, string>} style |
- * See _assert_style_get for information. |
- * @param {String} description Human readable description of what you are |
- * trying to check. |
- * |
- * @private |
- */ |
-function _assert_style_element_list(objects, style, description) { |
- var error = ''; |
- forEach(objects, function(object, i) { |
- try { |
- _assert_style_element( |
- object, _assert_style_get(style, i), |
- description + ' ' + _element_name(object) |
- ); |
- } catch (e) { |
- if (error) { |
- error += '; '; |
- } |
- error += 'Element ' + _element_name(object) + ' at index ' + i + ' failed ' + e.message + '\n'; |
- } |
- }); |
- if (error) { |
- throw error; |
- } |
-} |
- |
-/** |
- * asserts that elements returned from a query selector have a list of styles. |
- * |
- * @param {string} qs A query selector to use to get the DOM nodes. |
- * @param {Array.<Object.<string, string>>|Object.<string, string>} style |
- * See _assert_style_get for information. |
- * @param {String} description Human readable description of what you are |
- * trying to check. |
- * |
- * @private |
- */ |
-function _assert_style_queryselector(qs, style, description) { |
- var objects = document.querySelectorAll(qs); |
- assert_true(objects.length > 0, description + |
- ' is invalid, no elements match query selector: ' + qs); |
- _assert_style_element_list(objects, style, description); |
-} |
- |
-/** |
- * asserts that elements returned from a query selector have a list of styles. |
- * |
- * Assert the element with id #hello is 100px wide; |
- * assert_styles(document.getElementById('hello'), {'width': '100px'}) |
- * assert_styles('#hello'), {'width': '100px'}) |
- * |
- * Assert all divs are 100px wide; |
- * assert_styles(document.getElementsByTagName('div'), {'width': '100px'}) |
- * assert_styles('div', {'width': '100px'}) |
- * |
- * Assert all objects with class 'red' are 100px wide; |
- * assert_styles(document.getElementsByClassName('red'), {'width': '100px'}) |
- * assert_styles('.red', {'width': '100px'}) |
- * |
- * Assert first div is 100px wide, second div is 200px wide; |
- * assert_styles(document.getElementsByTagName('div'), |
- * [{'width': '100px'}, {'width': '200px'}]) |
- * assert_styles('div', |
- * [{'width': '100px'}, {'width': '200px'}]) |
- * |
- * @param {string|Element|Array.<Element>} objects Either; |
- * * A query selector to use to get DOM nodes, |
- * * A DOM node. |
- * * A list of DOM nodes. |
- * @param {Array.<Object.<string, string>>|Object.<string, string>} style |
- * See _assert_style_get for information. |
- */ |
-function assert_styles(objects, style, description) { |
- switch (typeof objects) { |
- case 'string': |
- _assert_style_queryselector(objects, style, description); |
- break; |
- |
- case 'object': |
- if (objects instanceof Array || objects instanceof NodeList) { |
- _assert_style_element_list(objects, style, description); |
- } else if (objects instanceof Element) { |
- _assert_style_element(objects, style, description); |
- } else { |
- throw new Error('Expected Array, NodeList or Element but got ' + objects); |
- } |
- break; |
- } |
-} |
-window.assert_styles = assert_styles; |
- |
-/** |
- * Schedule something to be called at a given time. |
- * |
- * @constructor |
- * @param {number} millis Milliseconds after start at which the callback should |
- * be called. |
- * @param {bool} autostart Auto something... |
- */ |
-function TestTimelineGroup(millis) { |
- this.millis = millis; |
- |
- /** |
- * @type {bool} |
- */ |
- this.autorun_ = false; |
- |
- /** |
- * @type {!Array.<function(): ?Object>} |
- */ |
- this.startCallbacks = null; |
- |
- /** |
- * Callbacks which are added after the timeline has started. We clear them |
- * when going backwards. |
- * |
- * @type {?Array.<function(): ?Object>} |
- */ |
- this.lateCallbacks = null; |
- |
- /** |
- * @type {Element} |
- */ |
- this.marker = document.createElement('img'); |
- /** |
- * @type {Element} |
- */ |
- this.info = document.createElement('div'); |
- |
- this.setup_(); |
-} |
- |
-TestTimelineGroup.prototype.setup_ = function() { |
- this.endTime_ = 0; |
- this.startCallbacks = new Array(); |
- this.lateCallbacks = null; |
- this.marker.innerHTML = ''; |
- this.info.innerHTML = ''; |
-}; |
- |
-/** |
- * Add a new callback to the event group |
- * |
- * @param {function(): ?Object} callback Callback given the currentTime of |
- * callback. |
- */ |
-TestTimelineGroup.prototype.add = function(callback) { |
- if (this.lateCallbacks === null) { |
- this.startCallbacks.unshift(callback); |
- } else { |
- this.lateCallbacks.unshift(callback); |
- } |
- |
- // Trim out extra 'function() { ... }' |
- var callbackString = callback.name; |
- // FIXME: This should probably unindent too.... |
- this.info.innerHTML += '<div>' + callbackString + '</div>'; |
-}; |
- |
-/** |
- * Reset this event group to the state before start was called. |
- */ |
-TestTimelineGroup.prototype.reset = function() { |
- this.lateCallbacks = null; |
- |
- var callbacks = this.startCallbacks.slice(0); |
- this.setup_(); |
- while (callbacks.length > 0) { |
- var callback = callbacks.shift(); |
- this.add(callback); |
- } |
-}; |
- |
-/** |
- * Tell the event group that the timeline has started and that any callbacks |
- * added from now are dynamically generated and hence should be cleared when a |
- * reset is called. |
- */ |
-TestTimelineGroup.prototype.start = function() { |
- this.lateCallbacks = new Array(); |
-}; |
- |
-/** |
- * Call all the callbacks in the EventGroup. |
- */ |
-TestTimelineGroup.prototype.call = function() { |
- var callbacks = (this.startCallbacks.slice(0)).concat(this.lateCallbacks); |
- var statuses = this.info.children; |
- |
- var overallResult = true; |
- while (callbacks.length > 0) { |
- var callback = callbacks.pop(); |
- |
- var status_ = statuses[statuses.length - callbacks.length - 1]; |
- |
- if (typeof callback == 'function') { |
- log('TestTimelineGroup', 'calling function', callback); |
- try { |
- callback(); |
- } catch (e) { |
- // On IE the only way to get the real stack is to do this |
- window.onerror(e.message, e.fileName, e.lineNumber, e); |
- // On other browsers we want to throw the error later |
- setTimeout(function () { throw e; }, 0); |
- } |
- } else { |
- log('TestTimelineGroup', 'calling test', callback); |
- var result = callback.step(callback.f); |
- callback.done(); |
- } |
- |
- if (result === undefined || result == null) { |
- overallResult = overallResult && true; |
- |
- status_.style.color = 'green'; |
- } else { |
- overallResult = overallResult && false; |
- status_.style.color = 'red'; |
- status_.innerHTML += '<div>' + result.toString() + '</div>'; |
- } |
- } |
- if (overallResult) { |
- this.marker.src = '../img/success.png'; |
- } else { |
- this.marker.src = '../img/error.png'; |
- } |
-} |
- |
-/** |
- * Draw the EventGroup's marker at the correct position on the timeline. |
- * |
- * FIXME(mithro): This mixes display and control :( |
- * |
- * @param {number} endTime The endtime of the timeline in millis. Used to |
- * display the marker at the right place on the timeline. |
- */ |
-TestTimelineGroup.prototype.draw = function(container, endTime) { |
- this.marker.title = this.millis + 'ms'; |
- this.marker.className = 'marker'; |
- this.marker.src = '../img/unknown.png'; |
- |
- var mleft = 'calc(100% - 10px)'; |
- if (endTime != 0) { |
- mleft = 'calc(' + (this.millis / endTime) * 100.0 + '%' + ' - 10px)'; |
- } |
- this.marker.style.left = mleft; |
- |
- container.appendChild(this.marker); |
- |
- this.info.className = 'info'; |
- container.appendChild(this.info); |
- |
- // Display details about the events at this time period when hovering over |
- // the marker. |
- this.marker.onmouseover = function() { |
- this.style.display = 'block'; |
- }.bind(this.info); |
- |
- this.marker.onmouseout = function() { |
- this.style.display = 'none'; |
- }.bind(this.info); |
- |
- |
- var offset = Math.ceil(this.info.offsetWidth / 2); |
- var ileft = 'calc(100% - ' + offset + 'px)'; |
- if (endTime != 0) { |
- ileft = 'calc(' + (this.millis / endTime) * 100.0 + '%' + ' - ' + offset + |
- 'px)'; |
- } |
- this.info.style.left = ileft; |
- |
- this.info.style.display = 'none'; |
-}; |
- |
- |
- |
-/** |
- * Moves the testharness_timeline in "real time". |
- * (IE 1 test second takes 1 real second). |
- * |
- * @constructor |
- */ |
-function RealtimeRunner(timeline) { |
- this.timeline = timeline; |
- |
- // Capture the real requestAnimationFrame so we can run in 'real time' mode |
- // rather than as fast as possible. |
- var nativeRequestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame; |
- this.boundRequestAnimationFrame = function(f) { |
- nativeRequestAnimationFrame(f.bind(this)) |
- }; |
- this.now = window.Date.now; |
- |
- this.zeroTime = null; // Time the page loaded |
- this.pauseStartTime = null; // Time at which we paused raf |
- this.timeDrift = 0; // Amount we have been stopped for |
-} |
- |
-/** |
- * Callback called from nativeRequestAnimationFrame. |
- * |
- * @private |
- * @param {number} timestamp The current time for the animation frame |
- * (in millis). |
- */ |
-RealtimeRunner.prototype.animationFrame_ = function(timestamp) { |
- if (this.zeroTime === null) { |
- this.zeroTime = timestamp; |
- } |
- |
- // Are we paused? Stop calling requestAnimationFrame. |
- if (this.pauseStartTime != null) { |
- return; |
- } |
- |
- var virtualAnimationTime = timestamp - this.zeroTime - this.timeDrift; |
- var endTime = this.timeline.endTime_; |
- // If we have no events paste t=0, endTime is going to be zero. Instead |
- // make the test run for 2 minutes. |
- if (endTime == 0) { |
- endTime = 120e3; |
- } |
- |
- // Do we still have time to go? |
- if (virtualAnimationTime < endTime) { |
- try { |
- this.timeline.setTime(virtualAnimationTime); |
- } finally { |
- this.boundRequestAnimationFrame(this.animationFrame_); |
- } |
- |
- } else { |
- // Have we gone past endTime_? Force the harness to its endTime_. |
- |
- this.timeline.setTime(endTime); |
- // Don't continue to raf |
- } |
-}; |
- |
-RealtimeRunner.prototype.start = function() { |
- if (this.pauseStartTime != null) { |
- this.timeDrift += (this.now() - this.pauseStartTime); |
- this.pauseStartTime = null; |
- } |
- this.boundRequestAnimationFrame(this.animationFrame_); |
-}; |
- |
-RealtimeRunner.prototype.pause = function() { |
- if (this.pauseStartTime != null) { |
- return; |
- } |
- this.pauseStartTime = this.now(); |
-}; |
- |
- |
-/** |
- * Class for storing events that happen during at given times (such as |
- * animation checks, or setTimeout). |
- * |
- * @constructor |
- */ |
-function TestTimeline(everyFrame) { |
- log('TestTimeline', 'constructor', everyFrame); |
- /** |
- * Stores the events which are upcoming. |
- * |
- * @type Object.<number, TestTimelineGroup> |
- * @private |
- */ |
- this.timeline_ = new Array(); |
- |
- this.everyFrame = everyFrame; |
- this.frameMillis = 1000.0 / 60; //60fps |
- |
- this.currentTime_ = -this.frameMillis; |
- |
- // Schedule an event at t=0, needed temporarily. |
- this.schedule(function() {}, 0); |
- |
- this.reset(); |
- |
- this.runner_ = new RealtimeRunner(this); |
-} |
- |
-/** |
- * Create the GUI controller for the timeline. |
- * @param {Element} body DOM element to add the GUI too, normally the <body> |
- * element. |
- */ |
-TestTimeline.prototype.createGUI = function(body) { |
- // HTML needed to create the timeline UI |
- this.div = document.createElement('div'); |
- this.div.id = 'timeline'; |
- |
- this.timelinebar = document.createElement('div'); |
- this.timelinebar.className = 'bar'; |
- |
- this.timelineprogress = document.createElement('div'); |
- this.timelineprogress.className = 'progress'; |
- |
- this.timelinebar.appendChild(this.timelineprogress); |
- this.div.appendChild(this.timelinebar); |
- |
- this.next = document.createElement('button'); |
- this.next.innerText = '>'; |
- this.next.id = 'next'; |
- this.next.onclick = this.toNextEvent.bind(this); |
- this.div.appendChild(this.next); |
- |
- this.prev = document.createElement('button'); |
- this.prev.innerText = '<'; |
- this.prev.id = 'prev'; |
- this.prev.onclick = this.toPrevEvent.bind(this); |
- this.div.appendChild(this.prev); |
- |
- this.control = document.createElement('button'); |
- this.control.innerText = 'Pause'; |
- this.control.id = 'control'; |
- this.control.onclick = function() { |
- if (this.control.innerText == 'Go!') { |
- this.runner_.start(); |
- this.control.innerText = 'Pause'; |
- } else { |
- this.runner_.pause(); |
- this.control.innerText = 'Go!'; |
- } |
- }.bind(this); |
- this.div.appendChild(this.control); |
- |
- body.appendChild(this.div); |
-} |
- |
-/** |
- * Update GUI elements. |
- * |
- * @private |
- */ |
-TestTimeline.prototype.updateGUI = function () { |
- // Update the timeline |
- var width = "100%"; |
- if (this.endTime_ != 0) { |
- width = (this.currentTime_ / this.endTime_) * 100.0 +'%' |
- } |
- this.timelineprogress.style.width = width; |
- this.timelinebar.title = (this.currentTime_).toFixed(0) + 'ms'; |
-}; |
- |
- |
-/** |
- * Sort the timeline into run order. Should be called after adding something to |
- * the timeline. |
- * |
- * @private |
- */ |
-TestTimeline.prototype.sort_ = function() { |
- this.timeline_.sort(function(a,b) { |
- return a.millis - b.millis; |
- }); |
-}; |
- |
-/** |
- * Schedule something to be called at a given time. |
- * |
- * @param {function(number)} callback Callback to call after the number of millis |
- * have elapsed. |
- * @param {number} millis Milliseconds after start at which the callback should |
- * be called. |
- */ |
-TestTimeline.prototype.schedule = function(callback, millis) { |
- log('TestTimeline', 'schedule', millis, callback); |
- if (millis < this.currentTime_) { |
- // Can't schedule something in the past? |
- return; |
- } |
- |
- // See if there is something at that time in the timeline already? |
- var timeline = this.timeline_.slice(0); |
- var group = null; |
- while (timeline.length > 0) { |
- if (timeline[0].millis == millis) { |
- group = timeline[0]; |
- break; |
- } else { |
- timeline.shift(); |
- } |
- } |
- |
- // If not, create a node at that time. |
- if (group === null) { |
- group = new TestTimelineGroup(millis); |
- this.timeline_.unshift(group); |
- this.sort_(); |
- } |
- group.add(callback); |
- |
- var newEndTime = this.timeline_.slice(-1)[0].millis * 1.1; |
- if (this.endTime_ != newEndTime) { |
- this.endTime_ = newEndTime; |
- } |
-}; |
- |
-/** |
- * Return the current time in milliseconds. |
- */ |
-TestTimeline.prototype.now = function() { |
- log('TestTimeline', 'now', Math.max(this.currentTime_, 0)); |
- return Math.max(this.currentTime_, 0); |
-}; |
- |
-/** |
- * Set the current time to a given value. |
- * |
- * @param {number} millis Time in milliseconds to set the current time too. |
- */ |
-TestTimeline.prototype.setTime = function(millis) { |
- log('TestTimeline', 'setTime', millis); |
- // Time is going backwards, we actually have to reset and go forwards as |
- // events can cause the creation of more events. |
- if (this.currentTime_ > millis) { |
- this.reset(); |
- this.start(); |
- } |
- |
- var events = this.timeline_.slice(0); |
- |
- // Already processed events |
- while (events.length > 0 && events[0].millis <= this.currentTime_) { |
- events.shift(); |
- } |
- |
- while (this.currentTime_ < millis) { |
- var event_ = null; |
- var moveTo = millis; |
- |
- if (events.length > 0 && events[0].millis <= millis) { |
- event_ = events.shift(); |
- moveTo = event_.millis; |
- } |
- |
- // Call the callback |
- if (this.currentTime_ != moveTo) { |
- log('TestTimeline', 'setting time to', moveTo); |
- this.currentTime_ = moveTo; |
- this.animationFrame(this.currentTime_); |
- } |
- |
- if (event_) { |
- event_.call(); |
- } |
- } |
- |
- this.updateGUI(); |
- |
- if (millis >= this.endTime_) { |
- this.done(); |
- } |
-}; |
- |
-/** |
- * Call all callbacks registered for the next (virtual) animation frame. |
- * |
- * @param {number} millis Time in milliseconds. |
- * @private |
- */ |
-TestTimeline.prototype.animationFrame = function(millis) { |
- /* FIXME(mithro): Code should appear here to allow testing of running |
- * every animation frame. |
- |
- if (this.everyFrame) { |
- } |
- |
- */ |
- |
- var callbacks = this.animationFrameCallbacks; |
- callbacks.reverse(); |
- this.animationFrameCallbacks = []; |
- for (var i = 0; i < callbacks.length; i++) { |
- log('TestTimeline raf callback', callbacks[i], millis); |
- try { |
- callbacks[i](millis); |
- } catch (e) { |
- // On IE the only way to get the real stack is to do this |
- window.onerror(e.message, e.fileName, e.lineNumber, e); |
- // On other browsers we want to throw the error later |
- setTimeout(function () { throw e; }, 0); |
- } |
- } |
-}; |
- |
-/** |
- * Set a callback to run at the next (virtual) animation frame. |
- * |
- * @param {function(millis)} millis Time in milliseconds to set the current |
- * time too. |
- */ |
-TestTimeline.prototype.requestAnimationFrame = function(callback) { |
- // FIXME: This should return a reference that allows people to cancel the |
- // animationFrame callback. |
- this.animationFrameCallbacks.push(callback); |
- return -1; |
-}; |
- |
-/** |
- * Go to next scheduled event in timeline. |
- */ |
-TestTimeline.prototype.toNextEvent = function() { |
- var events = this.timeline_.slice(0); |
- while (events.length > 0 && events[0].millis <= this.currentTime_) { |
- events.shift(); |
- } |
- if (events.length > 0) { |
- this.setTime(events[0].millis); |
- |
- if (this.autorun_) { |
- setTimeout(this.toNextEvent.bind(this), 0); |
- } |
- |
- return true; |
- } else { |
- this.setTime(this.endTime_); |
- return false; |
- } |
- |
-}; |
- |
-/** |
- * Go to previous scheduled event in timeline. |
- * (This actually goes back to time zero and then forward to this event.) |
- */ |
-TestTimeline.prototype.toPrevEvent = function() { |
- var events = this.timeline_.slice(0); |
- while (events.length > 0 && |
- events[events.length - 1].millis >= this.currentTime_) { |
- events.pop(); |
- } |
- if (events.length > 0) { |
- this.setTime(events[events.length - 1].millis); |
- return true; |
- } else { |
- this.setTime(0); |
- return false; |
- } |
-}; |
- |
-/** |
- * Reset the timeline to time zero. |
- */ |
-TestTimeline.prototype.reset = function () { |
- for (var t in this.timeline_) { |
- this.timeline_[t].reset(); |
- } |
- |
- this.currentTime_ = -this.frameMillis; |
- this.animationFrameCallbacks = []; |
- this.started_ = false; |
-}; |
- |
-/** |
- * Call to initiate starting??? |
- */ |
-TestTimeline.prototype.start = function () { |
- this.started_ = true; |
- |
- var parent = this; |
- |
- for (var t in this.timeline_) { |
- this.timeline_[t].start(); |
- // FIXME(mithro) this is confusing... |
- this.timeline_[t].draw(this.timelinebar, this.endTime_); |
- |
- this.timeline_[t].marker.onclick = function(event) { |
- parent.setTime(this.millis); |
- event.stopPropagation(); |
- }.bind(this.timeline_[t]); |
- } |
- |
- this.timelinebar.onclick = function(evt) { |
- var setPercent = |
- ((evt.clientX - this.offsetLeft) / this.offsetWidth); |
- parent.setTime(setPercent * parent.endTime_); |
- }.bind(this.timelinebar); |
-}; |
- |
-TestTimeline.prototype.done = function () { |
- log('TestTime', 'done'); |
- done(); |
-}; |
- |
-TestTimeline.prototype.autorun = function() { |
- this.autorun_ = true; |
- this.toNextEvent(); |
-}; |
- |
-function testharness_timeline_setup() { |
- log('testharness_timeline_setup'); |
- testharness_timeline.createGUI(document.getElementsByTagName('body')[0]); |
- testharness_timeline.start(); |
- testharness_timeline.updateGUI(); |
- |
- // Start running the test on message |
- if ('#message' == window.location.hash) { |
- window.addEventListener('message', function(evt) { |
- switch (evt.data['type']) { |
- case 'start': |
- if (evt.data['url'] == window.location.href) { |
- testharness_timeline.autorun(); |
- } |
- break; |
- } |
- }); |
- } else if ('#auto' == window.location.hash || '#coverage' == window.location.hash) { |
- // Run the test as fast as possible, skipping time. |
- |
- // Need non-zero timeout to allow chrome to run other code. |
- setTimeout(testharness_timeline.autorun.bind(testharness_timeline), 1); |
- |
- } else if (inExploreMode()) { |
- setTimeout(testharness_timeline.runner_.start.bind(testharness_timeline.runner_), 1); |
- } else { |
- alert('Unknown start mode.'); |
- } |
-} |
- |
-// Capture testharness's test as we are about to screw with it. |
-var testharness_test = window.test; |
- |
-function override_at(replacement_at, f, args) { |
- var orig_at = window.at; |
- window.at = replacement_at; |
- f.apply(null, args); |
- window.at = orig_at; |
-} |
- |
-function timing_test(f, desc) { |
- /** |
- * at function inside a timing_test function allows testing things at a |
- * given time rather then onload. |
- * @param {number} millis Milliseconds after page load to run the tests. |
- * @param {function()} f Closure containing the asserts to be run. |
- * @param {string} desc Description |
- */ |
- var at = function(millis, f, desc_at) { |
- assert_true(typeof millis == 'number', "at's first argument shoud be a number."); |
- assert_true(!isNaN(millis), "at's first argument should be a number not NaN!"); |
- assert_true(millis >= 0, "at's first argument should be greater then 0."); |
- assert_true(isFinite(millis), "at's first argument should be finite."); |
- |
- assert_true(typeof f == 'function', "at's second argument should be a function."); |
- |
- // Deliberately hoist the desc if we where not given one. |
- if (typeof desc_at == 'undefined' || desc_at == null || desc_at.length == 0) { |
- desc_at = desc; |
- } |
- |
- // And then provide 'Unnamed' as a default |
- if (typeof desc_at == 'undefined' || desc_at == null || desc_at.length == 0) { |
- desc_at = 'Unnamed assert'; |
- } |
- |
- var t = async_test(desc_at + ' at t=' + millis + 'ms'); |
- t.f = f; |
- window.testharness_timeline.schedule(t, millis); |
- }; |
- override_at(at, f); |
-} |
- |
-function test_without_at(f, desc) { |
- // Make sure calling at inside a test() function is a failure. |
- override_at(function() { |
- throw {'message': 'Can not use at() inside a test, use a timing_test instead.'}; |
- }, function() { testharness_test(f, desc); }); |
-} |
- |
-/** |
- * at function schedules a to be called at a given point. |
- * @param {number} millis Milliseconds after page load to run the function. |
- * @param {function()} f Function to be called. Called with no arguments |
- */ |
-function at(millis, f) { |
- assert_true(typeof millis == 'number', "at's first argument shoud be a number."); |
- assert_true(typeof f == 'function', "at's second argument should be a function."); |
- |
- window.testharness_timeline.schedule(f, millis); |
-} |
- |
-window.testharness_after_loaded = function() { |
- log('testharness_after_loaded'); |
- /** |
- * These steps needs to occur after testharness is loaded. |
- */ |
- setup(function() {}, { |
- explicit_timeout: true, |
- explicit_done: ((typeof window.testharness_timeline) !== 'undefined')}); |
- |
- /** |
- * Create an testharness test which makes sure the page contains no |
- * javascript errors. This is needed otherwise if the page contains errors |
- * then preventing the tests loading it will look like it passed. |
- */ |
- var pageerror_test = async_test('Page contains no errors'); |
- |
- window.onerror = function(msg, url, line, e) { |
- var msg = '\nError in ' + url + '\n' + |
- 'Line ' + line + ': ' + msg + '\n'; |
- |
- if (typeof e != "undefined") { |
- msg += e.stack; |
- } |
- |
- pageerror_test.is_done = true; |
- pageerror_test.step(function() { |
- throw new AssertionError(msg); |
- }); |
- pageerror_test.is_done = false; |
- }; |
- |
- var pageerror_tests; |
- function pageerror_othertests_finished(test, harness) { |
- if (harness == null && pageerror_tests == null) { |
- return; |
- } |
- |
- if (pageerror_tests == null) { |
- pageerror_tests = harness; |
- } |
- |
- if (pageerror_tests.all_loaded && pageerror_tests.num_pending == 1) { |
- pageerror_test.done(); |
- } |
- } |
- add_result_callback(pageerror_othertests_finished); |
- addEventListener('load', pageerror_othertests_finished); |
- |
-}; |
- |
-loadScript('../testharness/testharness.js', {coverage: false}); |
-document.write('<script type="text/javascript">window.testharness_after_loaded();</script>'); |
-loadCSS('../testharness/testharness.css'); |
-loadCSS('../testharness_timing.css'); |
- |
-if (testType() == 'auto') { |
- var checksFile = location.pathname; |
- checksFile = checksFile.replace(/disabled-/, ''); |
- checksFile = checksFile.replace(/.html$/, '-checks.js') |
- loadScript(checksFile, {coverage: false}); |
-} |
- |
-document.write('<div id="log"></div>'); |
-loadScript('../testharness/testharnessreport.js', {coverage: false}); |
- |
-if (!hasFlag('nopolyfill')) { |
- loadScript('../../web-animations.js'); |
-} |
- |
-addEventListener('load', function() { |
- if (window._WebAnimationsTestingUtilities) { |
- // Currently enabling asserts breaks auto-test-initial in IE. |
- //_WebAnimationsTestingUtilities._enableAsserts(); |
- } |
-}); |
- |
-// Don't export the timing functions in unittests. |
-if (testType() != 'unit') { |
- addEventListener('load', testharness_timeline_setup); |
- |
- window.at = at; |
- window.timing_test = timing_test; |
- window.test = test_without_at; |
- |
- // Expose the extra API |
- window.testharness_timeline = new TestTimeline(); |
- |
- // Override existing timing functions |
- window.requestAnimationFrame = |
- testharness_timeline.requestAnimationFrame.bind(testharness_timeline); |
- window.performance.now = null; |
- window.Date.now = testharness_timeline.now.bind(testharness_timeline); |
-} |
- |
-window.inExploreMode = inExploreMode; |
- |
-})(); |