[Web Animations] Update WPT tests related to Web Animations and remove imported Mozil...
[WebKit-https.git] / LayoutTests / imported / w3c / web-platform-tests / css / css-transitions / support / generalParallelTest.js
1 (function(root) {
2 'use strict';
3 //
4 var index = 0;
5 var suite = root.generalParallelTest = {
6     // prepare individual test
7     setup: function(data, options) {
8         suite._setupDom(data, options);
9         suite._setupEvents(data, options);
10     },
11     // clone fixture and prepare data containers
12     _setupDom: function(data, options) {
13         // clone fixture into off-viewport test-canvas
14         data.fixture = document.getElementById('fixture').cloneNode(true);
15         data.fixture.id = 'test-' + (index++);
16         (document.getElementById('offscreen') || document.body).appendChild(data.fixture);
17
18         // data container for #fixture > .container > .transition
19         data.transition = {
20             node: data.fixture.querySelector('.transition'),
21             values: [],
22             events: [],
23             computedStyle: function(property) {
24                 return computedStyle(data.transition.node, property);
25             }
26         };
27
28         // data container for #fixture > .container
29         data.container = {
30             node: data.transition.node.parentNode,
31             values: [],
32             events: [],
33             computedStyle: function(property) {
34                 return computedStyle(data.container.node, property);
35             }
36         };
37
38         // data container for #fixture > .container > .transition[:before | :after]
39         if (data.pseudo) {
40             data.pseudo = {
41                 name: data.pseudo,
42                 values: [],
43                 computedStyle: function(property) {
44                     return computedStyle(data.transition.node, property, ':' + data.pseudo.name);
45                 }
46             };
47         }
48     },
49     // bind TransitionEnd event listeners
50     _setupEvents: function(data, options) {
51         ['transition', 'container'].forEach(function(elem) {
52             var handler = function(event) {
53                 event.stopPropagation();
54                 var name = event.propertyName;
55                 var time = Math.round(event.elapsedTime * 1000) / 1000;
56                 var pseudo = event.pseudoElement ? (':' + event.pseudoElement) : '';
57                 data[elem].events.push(name + pseudo + ":" + time + "s");
58             };
59             data[elem].node.addEventListener('transitionend', handler, false);
60             data[elem]._events = {'transitionend': handler};
61         });
62     },
63     // cleanup after individual test
64     teardown: function(data, options) {
65         // data.fixture.remove();
66         if (data.fixture.parentNode) {
67             data.fixture.parentNode.removeChild(data.fixture);
68         }
69     },
70     // invoked prior to running a slice of tests
71     sliceStart: function(options, tests) {
72         // inject styles into document
73         setStyle(options.styles);
74         // kick off value collection loop
75         generalParallelTest.startValueCollection(options);
76     },
77     // invoked after running a slice of tests
78     sliceDone: function(options, tests) {
79         // stop value collection loop
80         generalParallelTest.stopValueCollection(options);
81         // reset styles cache
82         options.styles = {};
83     },
84     // called once all tests are done
85     done: function(options) {
86         // reset document styles
87         setStyle();
88         reflow();
89     },
90     // add styles of individual test to slice cache
91     addStyles: function(data, options, styles) {
92         if (!options.styles) {
93             options.styles = {};
94         }
95
96         Object.keys(styles).forEach(function(key) {
97             var selector = '#' + data.fixture.id
98                 // fixture must become #fixture.fixture rather than a child selector
99                 + (key.substring(0, 8) === '.fixture' ? '' : ' ')
100                 + key;
101
102             options.styles[selector] = styles[key];
103         });
104     },
105     // set style and compute values for container and transition
106     getStyle: function(data) {
107         reflow();
108         // grab current styles: "initial state"
109         suite._getStyleFor(data, 'from');
110         // apply target state
111         suite._addClass(data, 'to', true);
112         // grab current styles: "target state"
113         suite._getStyleFor(data, 'to');
114         // remove target state
115         suite._removeClass(data, 'to', true);
116
117         // clean up the mess created for value collection
118         data.container._values = [];
119         data.transition._values = [];
120         if (data.pseudo) {
121             data.pseudo._values = [];
122         }
123     },
124     // grab current styles and store in respective element's data container
125     _getStyleFor: function(data, key) {
126         data.container[key] = data.container.computedStyle(data.property);
127         data.transition[key] = data.transition.computedStyle(data.property);
128         if (data.pseudo) {
129             data.pseudo[key] = data.pseudo.computedStyle(data.property);
130         }
131     },
132     // add class to test's elements and possibly reflow
133     _addClass: function(data, className, forceReflow) {
134         data.container.node.classList.add(className);
135         data.transition.node.classList.add(className);
136         if (forceReflow) {
137             reflow();
138         }
139     },
140     // remove class from test's elements and possibly reflow
141     _removeClass: function(data, className, forceReflow) {
142         data.container.node.classList.remove(className);
143         data.transition.node.classList.remove(className);
144         if (forceReflow) {
145             reflow();
146         }
147     },
148     // add transition and to classes to container and transition
149     startTransition: function(data) {
150         // add transition-defining class
151         suite._addClass(data, 'how', true);
152         // add target state (without reflowing)
153         suite._addClass(data, 'to', false);
154     },
155     // requestAnimationFrame runLoop to collect computed values
156     startValueCollection: function(options) {
157         var raf = window.requestAnimationFrame || function(callback){
158             setTimeout(callback, 20);
159         };
160
161         // flag denoting if the runLoop should continue (true) or exit (false)
162         options._collectValues = true;
163
164         function runLoop() {
165             if (!options._collectValues) {
166                 // test's are done, stop annoying the CPU
167                 return;
168             }
169
170             // collect current style for test's elements
171             options.tests.forEach(function(data) {
172                 if (!data.property) {
173                     return;
174                 }
175
176                 ['transition', 'container', 'pseudo'].forEach(function(elem) {
177                     var pseudo = null;
178                     if (!data[elem] || (elem === 'pseudo' && !data.pseudo)) {
179                         return;
180                     }
181
182                     var current = data[elem].computedStyle(data.property);
183                     var values = data[elem].values;
184                     var length = values.length;
185                     if (!length || values[length - 1] !== current) {
186                         values.push(current);
187                     }
188                 });
189             });
190
191             // rinse and repeat
192             raf(runLoop);
193         }
194
195         runLoop();
196     },
197     // stop requestAnimationFrame runLoop collecting computed values
198     stopValueCollection: function(options) {
199         options._collectValues = false;
200     },
201
202     // generate test.step function asserting collected events match expected
203     assertExpectedEventsFunc: function(data, elem, expected) {
204         return function() {
205             var _result = data[elem].events.sort().join(" ");
206             var _expected = typeof expected === 'string' ? expected : expected.sort().join(" ");
207             assert_equals(_result, _expected, "Expected TransitionEnd events triggered on ." + elem);
208         };
209     },
210     // generate test.step function asserting collected values are neither initial nor target
211     assertIntermediateValuesFunc: function(data, elem) {
212         return function() {
213             // the first value (index: 0) is always going to be the initial value
214             // the last value is always going to be the target value
215             var values = data[elem].values;
216             if (data.flags.discrete) {
217                 // a discrete value will just switch from one state to another without having passed intermediate states.
218                 assert_equals(values[0], data[elem].from, "must be initial value while transitioning on ." + elem);
219                 assert_equals(values[1], data[elem].to, "must be target value after transitioning on ." + elem);
220                 assert_equals(values.length, 2, "discrete property only has 2 values ." + elem);
221             } else {
222                 assert_not_equals(values[1], data[elem].from, "may not be initial value while transitioning on ." + elem);
223                 assert_not_equals(values[1], data[elem].to, "may not be target value while transitioning on ." + elem);
224             }
225
226             // TODO: first value must be initial, last value must be target
227         };
228     }
229 };
230
231 })(window);