| 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;
|
| -
|
| -})();
|
|
|