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

Side by Side Diff: LayoutTests/animations/interpolation/resources/interpolation-test.js

Issue 203723005: Web Animations API: Update interpolation test harness to test element.animate() (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Rebased and added rounding to numbers that get displayed Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 * results. This function may not be used in a ref test. 46 * results. This function may not be used in a ref test.
47 * * convertToReference - This is intended to be used interactively to 47 * * convertToReference - This is intended to be used interactively to
48 * construct a reference given the results of a test. To build a 48 * construct a reference given the results of a test. To build a
49 * reference, run the test, open the inspector and trigger this 49 * reference, run the test, open the inspector and trigger this
50 * function, then copy/paste the results. 50 * function, then copy/paste the results.
51 */ 51 */
52 'use strict'; 52 'use strict';
53 (function() { 53 (function() {
54 var webkitPrefix = 'webkitAnimation' in document.documentElement.style ? '-web kit-' : ''; 54 var webkitPrefix = 'webkitAnimation' in document.documentElement.style ? '-web kit-' : '';
55 var isRefTest = false; 55 var isRefTest = false;
56 var webAnimationsTest = typeof Element.prototype.animate === 'function';
56 var startEvent = webkitPrefix ? 'webkitAnimationStart' : 'animationstart'; 57 var startEvent = webkitPrefix ? 'webkitAnimationStart' : 'animationstart';
57 var endEvent = webkitPrefix ? 'webkitAnimationEnd' : 'animationend'; 58 var endEvent = webkitPrefix ? 'webkitAnimationEnd' : 'animationend';
58 var testCount = 0; 59 var testCount = 0;
59 var animationEventCount = 0; 60 var animationEventCount = 0;
60 // FIXME: This should be 0, but 0 duration animations are broken in at least 61 // FIXME: This should be 0, but 0 duration animations are broken in at least
61 // pre-Web-Animations Blink, WebKit and Gecko. 62 // pre-Web-Animations Blink, WebKit and Gecko.
62 var durationSeconds = 0.001; 63 var durationSeconds = 0.001;
63 var iterationCount = 0.5; 64 var iterationCount = 0.5;
64 var delaySeconds = 0; 65 var delaySeconds = 0;
65 var cssText = '.test:hover:before {\n' + 66 var cssText = '.test:hover:before {\n' +
66 ' content: attr(description);\n' + 67 ' content: attr(description);\n' +
67 ' position: absolute;\n' + 68 ' position: absolute;\n' +
68 ' z-index: 1000;\n' + 69 ' z-index: 1000;\n' +
69 ' background: gold;\n' + 70 ' background: gold;\n' +
70 '}\n'; 71 '}\n';
71 var fragment = document.createDocumentFragment(); 72 var fragment = document.createDocumentFragment();
73 var fragmentAttachedListeners = [];
72 var style = document.createElement('style'); 74 var style = document.createElement('style');
75 var cssTests = document.createElement('div');
76 cssTests.id = 'css-tests';
77 cssTests.textContent = 'CSS Animations:';
73 var afterTestCallback = null; 78 var afterTestCallback = null;
74 fragment.appendChild(style); 79 fragment.appendChild(style);
80 fragment.appendChild(cssTests);
81
82 if (webAnimationsTest) {
83 var waTests = document.createElement('div');
84 waTests.id = 'web-animations-tests';
85 waTests.textContent = 'Web Animations API:';
86 fragment.appendChild(waTests);
87 }
75 88
76 var updateScheduled = false; 89 var updateScheduled = false;
77 function maybeScheduleUpdate() { 90 function maybeScheduleUpdate() {
78 if (updateScheduled) { 91 if (updateScheduled) {
79 return; 92 return;
80 } 93 }
81 updateScheduled = true; 94 updateScheduled = true;
82 setTimeout(function() { 95 setTimeout(function() {
83 updateScheduled = false; 96 updateScheduled = false;
84 style.innerHTML = cssText; 97 style.innerHTML = cssText;
85 document.body.appendChild(fragment); 98 document.body.appendChild(fragment);
99 fragmentAttachedListeners.forEach(function(listener) {listener();});
86 }, 0); 100 }, 0);
87 } 101 }
88 102
89 function dumpResults() { 103 function dumpResults() {
90 var targets = document.querySelectorAll('.target.active'); 104 var targets = document.querySelectorAll('.target.active');
91 if (isRefTest) { 105 if (isRefTest) {
92 // Convert back to reference to avoid cases where the computed style is 106 // Convert back to reference to avoid cases where the computed style is
93 // out of sync with the compositor. 107 // out of sync with the compositor.
94 for (var i = 0; i < targets.length; i++) { 108 for (var i = 0; i < targets.length; i++) {
95 targets[i].convertToReference(); 109 targets[i].convertToReference();
96 } 110 }
97 style.parentNode.removeChild(style); 111 style.parentNode.removeChild(style);
98 } else { 112 } else {
99 var resultString = ''; 113 var cssResultString = 'CSS Animations:\n';
114 var waResultString = 'Web Animations API:\n';
100 for (var i = 0; i < targets.length; i++) { 115 for (var i = 0; i < targets.length; i++) {
101 resultString += targets[i].getResultString() + '\n'; 116 if (targets[i].testType === 'css') {
117 cssResultString += targets[i].getResultString() + '\n';
118 } else {
119 waResultString += targets[i].getResultString() + '\n';
120 }
102 } 121 }
103 var results = document.createElement('div'); 122 var results = document.createElement('pre');
104 results.style.whiteSpace = 'pre'; 123 results.textContent = cssResultString + (webAnimationsTest ? '\n' + waResu ltString : '');
105 results.textContent = resultString;
106 results.id = 'results'; 124 results.id = 'results';
107 document.body.appendChild(results); 125 document.body.appendChild(results);
108 } 126 }
109 } 127 }
110 128
111 function convertToReference() { 129 function convertToReference() {
112 console.assert(isRefTest); 130 console.assert(isRefTest);
113 var scripts = document.querySelectorAll('script'); 131 var scripts = document.querySelectorAll('script');
114 for (var i = 0; i < scripts.length; i++) { 132 for (var i = 0; i < scripts.length; i++) {
115 scripts[i].parentNode.removeChild(scripts[i]); 133 scripts[i].parentNode.removeChild(scripts[i]);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 167
150 function testInterpolationAt(fractions, params) { 168 function testInterpolationAt(fractions, params) {
151 if (!Array.isArray(fractions)) { 169 if (!Array.isArray(fractions)) {
152 fractions = [fractions]; 170 fractions = [fractions];
153 } 171 }
154 assertInterpolation(params, fractions.map(function(fraction) { 172 assertInterpolation(params, fractions.map(function(fraction) {
155 return {at: fraction}; 173 return {at: fraction};
156 })); 174 }));
157 } 175 }
158 176
159 function describeTest(params) { 177 function createTestContainer(description, className) {
160 return params.property + ': from [' + params.from + '] to [' + params.to + ' ]'; 178 var testContainer = document.createElement('div');
179 testContainer.setAttribute('description', description);
180 testContainer.classList.add('test');
181 if (className) {
182 testContainer.classList.add(className);
183 }
184 return testContainer;
185 }
186
187 function convertPropertyToCamelCase(property) {
188 return property.replace(/^-/, '').replace(/-\w/g, function(m) {return m[1].t oUpperCase();});
189 }
190
191 function describeCSSTest(params) {
192 return 'CSS ' + params.property + ': from [' + params.from + '] to [' + para ms.to + ']';
193 }
194
195 function describeWATest(params) {
196 return 'element.animate() ' + convertPropertyToCamelCase(params.property) + ': from [' + params.from + '] to [' + params.to + ']';
161 } 197 }
162 198
163 function assertInterpolation(params, expectations) { 199 function assertInterpolation(params, expectations) {
164 // If the prefixed property is not supported, try to unprefix it. 200 // If the prefixed property is not supported, try to unprefix it.
165 if (/^-[^-]+-/.test(params.property) && !CSS.supports(params.property, 'init ial')) { 201 if (/^-[^-]+-/.test(params.property) && !CSS.supports(params.property, 'init ial')) {
166 var unprefixed = params.property.replace(/^-[^-]+-/, ''); 202 var unprefixed = params.property.replace(/^-[^-]+-/, '');
167 if (CSS.supports(unprefixed, 'initial')) { 203 if (CSS.supports(unprefixed, 'initial')) {
168 params.property = unprefixed; 204 params.property = unprefixed;
169 } 205 }
170 } 206 }
171 var testId = defineKeyframes(params); 207 var testId = defineKeyframes(params);
172 var nextCaseId = 0; 208 var nextCaseId = 0;
173 var testContainer = document.createElement('div'); 209 var cssTestContainer = createTestContainer(describeCSSTest(params), testId);
174 testContainer.setAttribute('description', describeTest(params)); 210 cssTests.appendChild(cssTestContainer);
175 testContainer.classList.add('test'); 211 if (webAnimationsTest) {
176 testContainer.classList.add(testId); 212 var waTestContainer = createTestContainer(describeWATest(params), testId);
177 fragment.appendChild(testContainer); 213 waTests.appendChild(waTestContainer);
214 }
178 expectations.forEach(function(expectation) { 215 expectations.forEach(function(expectation) {
179 testContainer.appendChild(makeInterpolationTest( 216 cssTestContainer.appendChild(makeInterpolationTest(
180 expectation.at, testId, 'case-' + ++nextCaseId, params, expectation.is )); 217 'css', expectation.at, testId, 'case-' + ++nextCaseId, params, expecta tion.is));
181 }); 218 });
219 if (webAnimationsTest) {
220 expectations.forEach(function(expectation) {
221 waTestContainer.appendChild(makeInterpolationTest(
222 'web-animations', expectation.at, testId, 'case-' + ++nextCaseId, pa rams, expectation.is));
223 });
224 }
182 maybeScheduleUpdate(); 225 maybeScheduleUpdate();
183 } 226 }
184 227
185 var nextKeyframeId = 0; 228 var nextKeyframeId = 0;
186 function defineKeyframes(params) { 229 function defineKeyframes(params) {
187 var testId = 'test-' + ++nextKeyframeId; 230 var testId = 'test-' + ++nextKeyframeId;
188 cssText += '@' + webkitPrefix + 'keyframes ' + testId + ' { \n' + 231 cssText += '@' + webkitPrefix + 'keyframes ' + testId + ' { \n' +
189 ' 0% { ' + params.property + ': ' + params.from + '; }\n' + 232 ' 0% { ' + params.property + ': ' + params.from + '; }\n' +
190 ' 100% { ' + params.property + ': ' + params.to + '; }\n' + 233 ' 100% { ' + params.property + ': ' + params.to + '; }\n' +
191 '}\n'; 234 '}\n';
192 return testId; 235 return testId;
193 } 236 }
194 237
195 function normalizeValue(value) { 238 function roundNumbers(value) {
196 return value. 239 return value.
197 // Round numbers to two decimal places. 240 // Round numbers to two decimal places.
198 replace(/-?\d*\.\d+/g, function(n) { 241 replace(/-?\d*\.\d+/g, function(n) {
199 return (parseFloat(n).toFixed(2)). 242 return (parseFloat(n).toFixed(2)).
200 replace(/\.0*$/, ''). 243 replace(/\.\d+/, function(m) {
244 return m.replace(/0+$/, '');
245 }).
246 replace(/\.$/, '').
201 replace(/^-0$/, '0'); 247 replace(/^-0$/, '0');
202 }). 248 });
249 }
250
251 function normalizeValue(value) {
252 return roundNumbers(value).
203 // Place whitespace between tokens. 253 // Place whitespace between tokens.
204 replace(/([\w\d.]+|[^\s])/g, '$1 '). 254 replace(/([\w\d.]+|[^\s])/g, '$1 ').
205 replace(/\s+/g, ' '); 255 replace(/\s+/g, ' ');
206 } 256 }
207 257
208 function createTargetContainer(id) { 258 function createTargetContainer(id) {
209 var targetContainer = document.createElement('div'); 259 var targetContainer = document.createElement('div');
210 var template = document.querySelector('#target-template'); 260 var template = document.querySelector('#target-template');
211 if (template) { 261 if (template) {
212 targetContainer.appendChild(template.content.cloneNode(true)); 262 targetContainer.appendChild(template.content.cloneNode(true));
(...skipping 23 matching lines...) Expand all
236 var url = /url\(([^\)]*)\)/g.exec(matches[i])[1]; 286 var url = /url\(([^\)]*)\)/g.exec(matches[i])[1];
237 var anchor = document.createElement('a'); 287 var anchor = document.createElement('a');
238 anchor.href = url; 288 anchor.href = url;
239 anchor.pathname = '...' + anchor.pathname.substring(anchor.pathname.last IndexOf('/')); 289 anchor.pathname = '...' + anchor.pathname.substring(anchor.pathname.last IndexOf('/'));
240 value = value.replace(matches[i], 'url(' + anchor.href + ')'); 290 value = value.replace(matches[i], 'url(' + anchor.href + ')');
241 } 291 }
242 } 292 }
243 return value; 293 return value;
244 } 294 }
245 295
246 function makeInterpolationTest(fraction, testId, caseId, params, expectation) { 296 function makeInterpolationTest(testType, fraction, testId, caseId, params, exp ectation) {
247 console.assert(expectation === undefined || !isRefTest); 297 console.assert(expectation === undefined || !isRefTest);
248 var targetContainer = createTargetContainer(caseId); 298 var targetContainer = createTargetContainer(caseId);
249 var target = targetContainer.querySelector('.target') || targetContainer; 299 var target = targetContainer.querySelector('.target') || targetContainer;
250 target.classList.add('active'); 300 target.classList.add('active');
251 var replicaContainer, replica; 301 var replicaContainer, replica;
252 if (expectation !== undefined) { 302 if (expectation !== undefined) {
253 replicaContainer = createTargetContainer(caseId); 303 replicaContainer = createTargetContainer(caseId);
254 replica = replicaContainer.querySelector('.target') || replicaContainer; 304 replica = replicaContainer.querySelector('.target') || replicaContainer;
255 replica.classList.add('replica'); 305 replica.classList.add('replica');
256 replica.style.setProperty(params.property, expectation); 306 replica.style.setProperty(params.property, expectation);
257 } 307 }
308 target.testType = testType;
258 target.getResultString = function() { 309 target.getResultString = function() {
259 if (!CSS.supports(params.property, expectation)) { 310 if (!CSS.supports(params.property, expectation)) {
260 return 'FAIL: [' + params.property + ': ' + expectation + '] is not supp orted'; 311 return 'FAIL: [' + params.property + ': ' + expectation + '] is not supp orted';
261 } 312 }
262 var value = getComputedStyle(this).getPropertyValue(params.property); 313 var value = getComputedStyle(this).getPropertyValue(params.property);
263 var result = ''; 314 var result = '';
264 var reason = ''; 315 var reason = '';
316 var property = testType === 'css' ? params.property : convertPropertyToCam elCase(params.property);
265 if (expectation !== undefined) { 317 if (expectation !== undefined) {
266 var parsedExpectation = getComputedStyle(replica).getPropertyValue(param s.property); 318 var parsedExpectation = getComputedStyle(replica).getPropertyValue(param s.property);
267 var pass = normalizeValue(value) === normalizeValue(parsedExpectation); 319 var pass = normalizeValue(value) === normalizeValue(parsedExpectation);
268 result = pass ? 'PASS: ' : 'FAIL: '; 320 result = pass ? 'PASS: ' : 'FAIL: ';
269 reason = pass ? '' : ', expected [' + expectation + ']' + 321 reason = pass ? '' : ', expected [' + expectation + ']' +
270 (expectation === parsedExpectation ? '' : ' (parsed as [' + sanitize Urls(parsedExpectation) + '])'); 322 (expectation === parsedExpectation ? '' : ' (parsed as [' + sanitize Urls(roundNumbers(parsedExpectation)) + '])');
271 value = pass ? expectation : sanitizeUrls(value); 323 value = pass ? expectation : sanitizeUrls(value);
272 } 324 }
273 return result + params.property + ' from [' + params.from + '] to ' + 325 return result + property + ' from [' + params.from + '] to ' +
274 '[' + params.to + '] was [' + value + ']' + 326 '[' + params.to + '] was [' + value + ']' +
275 ' at ' + fraction + reason; 327 ' at ' + fraction + reason;
276 }; 328 };
277 target.convertToReference = function() { 329 target.convertToReference = function() {
278 this.style[params.property] = getComputedStyle(this).getPropertyValue(para ms.property); 330 this.style[params.property] = getComputedStyle(this).getPropertyValue(para ms.property);
279 }; 331 };
280 var easing = createEasing(fraction); 332 var easing = createEasing(fraction);
281 cssText += '.' + testId + ' .' + caseId + '.active {\n' +
282 ' ' + webkitPrefix + 'animation: ' + testId + ' ' + durationSeconds + ' s forwards;\n' +
283 ' ' + webkitPrefix + 'animation-timing-function: ' + easing + ';\n' +
284 ' ' + webkitPrefix + 'animation-iteration-count: ' + iterationCount + ' ;\n' +
285 ' ' + webkitPrefix + 'animation-delay: ' + delaySeconds + 's;\n' +
286 '}\n';
287 testCount++; 333 testCount++;
334 if (testType === 'css') {
335 cssText += '.' + testId + ' .' + caseId + '.active {\n' +
336 ' ' + webkitPrefix + 'animation: ' + testId + ' ' + durationSeconds + 's forwards;\n' +
337 ' ' + webkitPrefix + 'animation-timing-function: ' + easing + ';\n' +
338 ' ' + webkitPrefix + 'animation-iteration-count: ' + iterationCount + ';\n' +
339 ' ' + webkitPrefix + 'animation-delay: ' + delaySeconds + 's;\n' +
340 '}\n';
341 } else {
342 var keyframes = [{}, {}];
343 keyframes[0][convertPropertyToCamelCase(params.property)] = params.from;
344 keyframes[1][convertPropertyToCamelCase(params.property)] = params.to;
345 fragmentAttachedListeners.push(function() {
346 target.animate(keyframes, {
347 fill: 'forwards',
348 duration: 1,
349 easing: easing,
350 delay: -0.5,
351 iterations: 0.5,
352 });
353 animationEnded();
354 });
355 }
288 var testFragment = document.createDocumentFragment(); 356 var testFragment = document.createDocumentFragment();
289 testFragment.appendChild(targetContainer); 357 testFragment.appendChild(targetContainer);
290 replica && testFragment.appendChild(replicaContainer); 358 replica && testFragment.appendChild(replicaContainer);
291 testFragment.appendChild(document.createTextNode('\n')); 359 testFragment.appendChild(document.createTextNode('\n'));
292 return testFragment; 360 return testFragment;
293 } 361 }
294 362
295 var finished = false; 363 var finished = false;
296 function finishTest() { 364 function finishTest() {
297 finished = true; 365 finished = true;
(...skipping 13 matching lines...) Expand all
311 } 379 }
312 380
313 if (window.testRunner) { 381 if (window.testRunner) {
314 testRunner.waitUntilDone(); 382 testRunner.waitUntilDone();
315 } 383 }
316 384
317 function isLastAnimationEvent() { 385 function isLastAnimationEvent() {
318 return !finished && animationEventCount === testCount; 386 return !finished && animationEventCount === testCount;
319 } 387 }
320 388
321 function endEventListener() { 389 function animationEnded() {
322 animationEventCount++; 390 animationEventCount++;
323 if (!isLastAnimationEvent()) { 391 if (!isLastAnimationEvent()) {
324 return; 392 return;
325 } 393 }
326 finishTest(); 394 finishTest();
327 } 395 }
328 396
329 if (window.internals) { 397 if (window.internals) {
330 durationSeconds = 0; 398 durationSeconds = 0;
331 document.documentElement.addEventListener(endEvent, endEventListener); 399 document.documentElement.addEventListener(endEvent, animationEnded);
332 } else if (webkitPrefix) { 400 } else if (webkitPrefix) {
333 durationSeconds = 1e9; 401 durationSeconds = 1e9;
334 iterationCount = 1; 402 iterationCount = 1;
335 delaySeconds = -durationSeconds / 2; 403 delaySeconds = -durationSeconds / 2;
336 document.documentElement.addEventListener(startEvent, function() { 404 document.documentElement.addEventListener(startEvent, function() {
337 animationEventCount++; 405 animationEventCount++;
338 if (!isLastAnimationEvent()) { 406 if (!isLastAnimationEvent()) {
339 return; 407 return;
340 } 408 }
341 setTimeout(finishTest, 0); 409 setTimeout(finishTest, 0);
342 }); 410 });
343 } else { 411 } else {
344 document.documentElement.addEventListener(endEvent, endEventListener); 412 document.documentElement.addEventListener(endEvent, animationEnded);
345 } 413 }
346 414
347 if (!window.testRunner) { 415 if (!window.testRunner) {
348 setTimeout(function() { 416 setTimeout(function() {
349 if (finished) { 417 if (finished) {
350 return; 418 return;
351 } 419 }
352 finishTest(); 420 finishTest();
353 }, 10000); 421 }, 10000);
354 } 422 }
355 423
356 window.runAsRefTest = runAsRefTest; 424 window.runAsRefTest = runAsRefTest;
357 window.testInterpolationAt = testInterpolationAt; 425 window.testInterpolationAt = testInterpolationAt;
358 window.assertInterpolation = assertInterpolation; 426 window.assertInterpolation = assertInterpolation;
359 window.convertToReference = convertToReference; 427 window.convertToReference = convertToReference;
360 window.afterTest = afterTest; 428 window.afterTest = afterTest;
361 })(); 429 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698