11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci// Runs a set of tests for a given prefixed/unprefixed animation event (e.g.
41cb0ef41Sopenharmony_ci// animationstart/webkitAnimationStart).
51cb0ef41Sopenharmony_ci//
61cb0ef41Sopenharmony_ci// The eventDetails object must have the following form:
71cb0ef41Sopenharmony_ci// {
81cb0ef41Sopenharmony_ci//   isTransition: false, <-- can be omitted, default false
91cb0ef41Sopenharmony_ci//   unprefixedType: 'animationstart',
101cb0ef41Sopenharmony_ci//   prefixedType: 'webkitAnimationStart',
111cb0ef41Sopenharmony_ci//   animationCssStyle: '1ms',  <-- must NOT include animation name or
121cb0ef41Sopenharmony_ci//                                  transition property
131cb0ef41Sopenharmony_ci// }
141cb0ef41Sopenharmony_cifunction runAnimationEventTests(eventDetails) {
151cb0ef41Sopenharmony_ci  const {
161cb0ef41Sopenharmony_ci    isTransition,
171cb0ef41Sopenharmony_ci    unprefixedType,
181cb0ef41Sopenharmony_ci    prefixedType,
191cb0ef41Sopenharmony_ci    animationCssStyle
201cb0ef41Sopenharmony_ci  } = eventDetails;
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci  // Derive the DOM event handler names, e.g. onanimationstart.
231cb0ef41Sopenharmony_ci  const unprefixedHandler = `on${unprefixedType}`;
241cb0ef41Sopenharmony_ci  const prefixedHandler = `on${prefixedType.toLowerCase()}`;
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci  const style = document.createElement('style');
271cb0ef41Sopenharmony_ci  document.head.appendChild(style);
281cb0ef41Sopenharmony_ci  if (isTransition) {
291cb0ef41Sopenharmony_ci    style.sheet.insertRule(
301cb0ef41Sopenharmony_ci      `.baseStyle { width: 100px; transition: width ${animationCssStyle}; }`);
311cb0ef41Sopenharmony_ci    style.sheet.insertRule('.transition { width: 200px !important; }');
321cb0ef41Sopenharmony_ci  } else {
331cb0ef41Sopenharmony_ci    style.sheet.insertRule('@keyframes anim {}');
341cb0ef41Sopenharmony_ci  }
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  function triggerAnimation(div) {
371cb0ef41Sopenharmony_ci    if (isTransition) {
381cb0ef41Sopenharmony_ci      div.classList.add('transition');
391cb0ef41Sopenharmony_ci    } else {
401cb0ef41Sopenharmony_ci      div.style.animation = `anim ${animationCssStyle}`;
411cb0ef41Sopenharmony_ci    }
421cb0ef41Sopenharmony_ci  }
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  test(t => {
451cb0ef41Sopenharmony_ci    const div = createDiv(t);
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci    assert_equals(div[unprefixedHandler], null,
481cb0ef41Sopenharmony_ci        `${unprefixedHandler} should initially be null`);
491cb0ef41Sopenharmony_ci    assert_equals(div[prefixedHandler], null,
501cb0ef41Sopenharmony_ci        `${prefixedHandler} should initially be null`);
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci    // Setting one should not affect the other.
531cb0ef41Sopenharmony_ci    div[unprefixedHandler] = () => { };
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci    assert_not_equals(div[unprefixedHandler], null,
561cb0ef41Sopenharmony_ci        `setting ${unprefixedHandler} should make it non-null`);
571cb0ef41Sopenharmony_ci    assert_equals(div[prefixedHandler], null,
581cb0ef41Sopenharmony_ci        `setting ${unprefixedHandler} should not affect ${prefixedHandler}`);
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci    div[prefixedHandler] = () => { };
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci    assert_not_equals(div[prefixedHandler], null,
631cb0ef41Sopenharmony_ci        `setting ${prefixedHandler} should make it non-null`);
641cb0ef41Sopenharmony_ci    assert_not_equals(div[unprefixedHandler], div[prefixedHandler],
651cb0ef41Sopenharmony_ci        'the setters should be different');
661cb0ef41Sopenharmony_ci  }, `${unprefixedHandler} and ${prefixedHandler} are not aliases`);
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci  // The below tests primarily test the interactions of prefixed animation
691cb0ef41Sopenharmony_ci  // events in the algorithm for invoking events:
701cb0ef41Sopenharmony_ci  // https://dom.spec.whatwg.org/#concept-event-listener-invoke
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  promise_test(async t => {
731cb0ef41Sopenharmony_ci    const div = createDiv(t);
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci    let receivedEventCount = 0;
761cb0ef41Sopenharmony_ci    addTestScopedEventHandler(t, div, prefixedHandler, () => {
771cb0ef41Sopenharmony_ci      receivedEventCount++;
781cb0ef41Sopenharmony_ci    });
791cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, div, prefixedType, () => {
801cb0ef41Sopenharmony_ci      receivedEventCount++;
811cb0ef41Sopenharmony_ci    });
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci    // The HTML spec[0] specifies that the prefixed event handlers have an
841cb0ef41Sopenharmony_ci    // 'Event handler event type' of the appropriate prefixed event type. E.g.
851cb0ef41Sopenharmony_ci    // onwebkitanimationend creates a listener for the event type
861cb0ef41Sopenharmony_ci    // 'webkitAnimationEnd'.
871cb0ef41Sopenharmony_ci    //
881cb0ef41Sopenharmony_ci    // [0]: https://html.spec.whatwg.org/multipage/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects
891cb0ef41Sopenharmony_ci    div.dispatchEvent(new AnimationEvent(prefixedType));
901cb0ef41Sopenharmony_ci    assert_equals(receivedEventCount, 2,
911cb0ef41Sopenharmony_ci                'prefixed listener and handler received event');
921cb0ef41Sopenharmony_ci  }, `dispatchEvent of a ${prefixedType} event does trigger a ` +
931cb0ef41Sopenharmony_ci      `prefixed event handler or listener`);
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  promise_test(async t => {
961cb0ef41Sopenharmony_ci    const div = createDiv(t);
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci    let receivedEvent = false;
991cb0ef41Sopenharmony_ci    addTestScopedEventHandler(t, div, unprefixedHandler, () => {
1001cb0ef41Sopenharmony_ci      receivedEvent = true;
1011cb0ef41Sopenharmony_ci    });
1021cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, div, unprefixedType, () => {
1031cb0ef41Sopenharmony_ci      receivedEvent = true;
1041cb0ef41Sopenharmony_ci    });
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci    div.dispatchEvent(new AnimationEvent(prefixedType));
1071cb0ef41Sopenharmony_ci    assert_false(receivedEvent,
1081cb0ef41Sopenharmony_ci                'prefixed listener or handler received event');
1091cb0ef41Sopenharmony_ci  }, `dispatchEvent of a ${prefixedType} event does not trigger an ` +
1101cb0ef41Sopenharmony_ci    `unprefixed event handler or listener`);
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  promise_test(async t => {
1141cb0ef41Sopenharmony_ci    const div = createDiv(t);
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci    let receivedEvent = false;
1171cb0ef41Sopenharmony_ci    addTestScopedEventHandler(t, div, prefixedHandler, () => {
1181cb0ef41Sopenharmony_ci      receivedEvent = true;
1191cb0ef41Sopenharmony_ci    });
1201cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, div, prefixedType, () => {
1211cb0ef41Sopenharmony_ci      receivedEvent = true;
1221cb0ef41Sopenharmony_ci    });
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci    // The rewrite rules from
1251cb0ef41Sopenharmony_ci    // https://dom.spec.whatwg.org/#concept-event-listener-invoke step 8 do not
1261cb0ef41Sopenharmony_ci    // apply because isTrusted will be false.
1271cb0ef41Sopenharmony_ci    div.dispatchEvent(new AnimationEvent(unprefixedType));
1281cb0ef41Sopenharmony_ci    assert_false(receivedEvent, 'prefixed listener or handler received event');
1291cb0ef41Sopenharmony_ci  }, `dispatchEvent of an ${unprefixedType} event does not trigger a ` +
1301cb0ef41Sopenharmony_ci      `prefixed event handler or listener`);
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  promise_test(async t => {
1331cb0ef41Sopenharmony_ci    const div = createDiv(t);
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci    let receivedEvent = false;
1361cb0ef41Sopenharmony_ci    addTestScopedEventHandler(t, div, prefixedHandler, () => {
1371cb0ef41Sopenharmony_ci      receivedEvent = true;
1381cb0ef41Sopenharmony_ci    });
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci    triggerAnimation(div);
1411cb0ef41Sopenharmony_ci    await waitForEventThenAnimationFrame(t, unprefixedType);
1421cb0ef41Sopenharmony_ci    assert_true(receivedEvent, `received ${prefixedHandler} event`);
1431cb0ef41Sopenharmony_ci  }, `${prefixedHandler} event handler should trigger for an animation`);
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci  promise_test(async t => {
1461cb0ef41Sopenharmony_ci    const div = createDiv(t);
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci    let receivedPrefixedEvent = false;
1491cb0ef41Sopenharmony_ci    addTestScopedEventHandler(t, div, prefixedHandler, () => {
1501cb0ef41Sopenharmony_ci      receivedPrefixedEvent = true;
1511cb0ef41Sopenharmony_ci    });
1521cb0ef41Sopenharmony_ci    let receivedUnprefixedEvent = false;
1531cb0ef41Sopenharmony_ci    addTestScopedEventHandler(t, div, unprefixedHandler, () => {
1541cb0ef41Sopenharmony_ci      receivedUnprefixedEvent = true;
1551cb0ef41Sopenharmony_ci    });
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci    triggerAnimation(div);
1581cb0ef41Sopenharmony_ci    await waitForEventThenAnimationFrame(t, unprefixedType);
1591cb0ef41Sopenharmony_ci    assert_true(receivedUnprefixedEvent, `received ${unprefixedHandler} event`);
1601cb0ef41Sopenharmony_ci    assert_false(receivedPrefixedEvent, `received ${prefixedHandler} event`);
1611cb0ef41Sopenharmony_ci  }, `${prefixedHandler} event handler should not trigger if an unprefixed ` +
1621cb0ef41Sopenharmony_ci      `event handler also exists`);
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  promise_test(async t => {
1651cb0ef41Sopenharmony_ci    const div = createDiv(t);
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci    let receivedPrefixedEvent = false;
1681cb0ef41Sopenharmony_ci    addTestScopedEventHandler(t, div, prefixedHandler, () => {
1691cb0ef41Sopenharmony_ci      receivedPrefixedEvent = true;
1701cb0ef41Sopenharmony_ci    });
1711cb0ef41Sopenharmony_ci    let receivedUnprefixedEvent = false;
1721cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, div, unprefixedType, () => {
1731cb0ef41Sopenharmony_ci      receivedUnprefixedEvent = true;
1741cb0ef41Sopenharmony_ci    });
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci    triggerAnimation(div);
1771cb0ef41Sopenharmony_ci    await waitForEventThenAnimationFrame(t, unprefixedHandler);
1781cb0ef41Sopenharmony_ci    assert_true(receivedUnprefixedEvent, `received ${unprefixedHandler} event`);
1791cb0ef41Sopenharmony_ci    assert_false(receivedPrefixedEvent, `received ${prefixedHandler} event`);
1801cb0ef41Sopenharmony_ci  }, `${prefixedHandler} event handler should not trigger if an unprefixed ` +
1811cb0ef41Sopenharmony_ci      `listener also exists`);
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci  promise_test(async t => {
1841cb0ef41Sopenharmony_ci    // We use a parent/child relationship to be able to register both prefixed
1851cb0ef41Sopenharmony_ci    // and unprefixed event handlers without the deduplication logic kicking in.
1861cb0ef41Sopenharmony_ci    const parent = createDiv(t);
1871cb0ef41Sopenharmony_ci    const child = createDiv(t);
1881cb0ef41Sopenharmony_ci    parent.appendChild(child);
1891cb0ef41Sopenharmony_ci    // After moving the child, we have to clean style again.
1901cb0ef41Sopenharmony_ci    getComputedStyle(child).transition;
1911cb0ef41Sopenharmony_ci    getComputedStyle(child).width;
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci    let observedUnprefixedType;
1941cb0ef41Sopenharmony_ci    addTestScopedEventHandler(t, parent, unprefixedHandler, e => {
1951cb0ef41Sopenharmony_ci      observedUnprefixedType = e.type;
1961cb0ef41Sopenharmony_ci    });
1971cb0ef41Sopenharmony_ci    let observedPrefixedType;
1981cb0ef41Sopenharmony_ci    addTestScopedEventHandler(t, child, prefixedHandler, e => {
1991cb0ef41Sopenharmony_ci      observedPrefixedType = e.type;
2001cb0ef41Sopenharmony_ci    });
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci    triggerAnimation(child);
2031cb0ef41Sopenharmony_ci    await waitForEventThenAnimationFrame(t, unprefixedType);
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ci    assert_equals(observedUnprefixedType, unprefixedType);
2061cb0ef41Sopenharmony_ci    assert_equals(observedPrefixedType, prefixedType);
2071cb0ef41Sopenharmony_ci  }, `event types for prefixed and unprefixed ${unprefixedType} event ` +
2081cb0ef41Sopenharmony_ci    `handlers should be named appropriately`);
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci  promise_test(async t => {
2111cb0ef41Sopenharmony_ci    const div = createDiv(t);
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci    let receivedEvent = false;
2141cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, div, prefixedType, () => {
2151cb0ef41Sopenharmony_ci      receivedEvent = true;
2161cb0ef41Sopenharmony_ci    });
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci    triggerAnimation(div);
2191cb0ef41Sopenharmony_ci    await waitForEventThenAnimationFrame(t, unprefixedHandler);
2201cb0ef41Sopenharmony_ci    assert_true(receivedEvent, `received ${prefixedType} event`);
2211cb0ef41Sopenharmony_ci  }, `${prefixedType} event listener should trigger for an animation`);
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci  promise_test(async t => {
2241cb0ef41Sopenharmony_ci    const div = createDiv(t);
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci    let receivedPrefixedEvent = false;
2271cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, div, prefixedType, () => {
2281cb0ef41Sopenharmony_ci      receivedPrefixedEvent = true;
2291cb0ef41Sopenharmony_ci    });
2301cb0ef41Sopenharmony_ci    let receivedUnprefixedEvent = false;
2311cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, div, unprefixedType, () => {
2321cb0ef41Sopenharmony_ci      receivedUnprefixedEvent = true;
2331cb0ef41Sopenharmony_ci    });
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci    triggerAnimation(div);
2361cb0ef41Sopenharmony_ci    await waitForEventThenAnimationFrame(t, unprefixedHandler);
2371cb0ef41Sopenharmony_ci    assert_true(receivedUnprefixedEvent, `received ${unprefixedType} event`);
2381cb0ef41Sopenharmony_ci    assert_false(receivedPrefixedEvent, `received ${prefixedType} event`);
2391cb0ef41Sopenharmony_ci  }, `${prefixedType} event listener should not trigger if an unprefixed ` +
2401cb0ef41Sopenharmony_ci      `listener also exists`);
2411cb0ef41Sopenharmony_ci
2421cb0ef41Sopenharmony_ci  promise_test(async t => {
2431cb0ef41Sopenharmony_ci    const div = createDiv(t);
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci    let receivedPrefixedEvent = false;
2461cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, div, prefixedType, () => {
2471cb0ef41Sopenharmony_ci      receivedPrefixedEvent = true;
2481cb0ef41Sopenharmony_ci    });
2491cb0ef41Sopenharmony_ci    let receivedUnprefixedEvent = false;
2501cb0ef41Sopenharmony_ci    addTestScopedEventHandler(t, div, unprefixedHandler, () => {
2511cb0ef41Sopenharmony_ci      receivedUnprefixedEvent = true;
2521cb0ef41Sopenharmony_ci    });
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ci    triggerAnimation(div);
2551cb0ef41Sopenharmony_ci    await waitForEventThenAnimationFrame(t, unprefixedHandler);
2561cb0ef41Sopenharmony_ci    assert_true(receivedUnprefixedEvent, `received ${unprefixedType} event`);
2571cb0ef41Sopenharmony_ci    assert_false(receivedPrefixedEvent, `received ${prefixedType} event`);
2581cb0ef41Sopenharmony_ci  }, `${prefixedType} event listener should not trigger if an unprefixed ` +
2591cb0ef41Sopenharmony_ci       `event handler also exists`);
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_ci  promise_test(async t => {
2621cb0ef41Sopenharmony_ci    // We use a parent/child relationship to be able to register both prefixed
2631cb0ef41Sopenharmony_ci    // and unprefixed event listeners without the deduplication logic kicking in.
2641cb0ef41Sopenharmony_ci    const parent = createDiv(t);
2651cb0ef41Sopenharmony_ci    const child = createDiv(t);
2661cb0ef41Sopenharmony_ci    parent.appendChild(child);
2671cb0ef41Sopenharmony_ci    // After moving the child, we have to clean style again.
2681cb0ef41Sopenharmony_ci    getComputedStyle(child).transition;
2691cb0ef41Sopenharmony_ci    getComputedStyle(child).width;
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_ci    let observedUnprefixedType;
2721cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, parent, unprefixedType, e => {
2731cb0ef41Sopenharmony_ci      observedUnprefixedType = e.type;
2741cb0ef41Sopenharmony_ci    });
2751cb0ef41Sopenharmony_ci    let observedPrefixedType;
2761cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, child, prefixedType, e => {
2771cb0ef41Sopenharmony_ci      observedPrefixedType = e.type;
2781cb0ef41Sopenharmony_ci    });
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci    triggerAnimation(child);
2811cb0ef41Sopenharmony_ci    await waitForEventThenAnimationFrame(t, unprefixedHandler);
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_ci    assert_equals(observedUnprefixedType, unprefixedType);
2841cb0ef41Sopenharmony_ci    assert_equals(observedPrefixedType, prefixedType);
2851cb0ef41Sopenharmony_ci  }, `event types for prefixed and unprefixed ${unprefixedType} event ` +
2861cb0ef41Sopenharmony_ci      `listeners should be named appropriately`);
2871cb0ef41Sopenharmony_ci
2881cb0ef41Sopenharmony_ci  promise_test(async t => {
2891cb0ef41Sopenharmony_ci    const div = createDiv(t);
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci    let receivedEvent = false;
2921cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, div, prefixedType.toLowerCase(), () => {
2931cb0ef41Sopenharmony_ci      receivedEvent = true;
2941cb0ef41Sopenharmony_ci    });
2951cb0ef41Sopenharmony_ci    addTestScopedEventListener(t, div, prefixedType.toUpperCase(), () => {
2961cb0ef41Sopenharmony_ci      receivedEvent = true;
2971cb0ef41Sopenharmony_ci    });
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci    triggerAnimation(div);
3001cb0ef41Sopenharmony_ci    await waitForEventThenAnimationFrame(t, unprefixedHandler);
3011cb0ef41Sopenharmony_ci    assert_false(receivedEvent, `received ${prefixedType} event`);
3021cb0ef41Sopenharmony_ci  }, `${prefixedType} event listener is case sensitive`);
3031cb0ef41Sopenharmony_ci}
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci// Below are utility functions.
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci// Creates a div element, appends it to the document body and removes the
3081cb0ef41Sopenharmony_ci// created element during test cleanup.
3091cb0ef41Sopenharmony_cifunction createDiv(test) {
3101cb0ef41Sopenharmony_ci  const element = document.createElement('div');
3111cb0ef41Sopenharmony_ci  element.classList.add('baseStyle');
3121cb0ef41Sopenharmony_ci  document.body.appendChild(element);
3131cb0ef41Sopenharmony_ci  test.add_cleanup(() => {
3141cb0ef41Sopenharmony_ci    element.remove();
3151cb0ef41Sopenharmony_ci  });
3161cb0ef41Sopenharmony_ci
3171cb0ef41Sopenharmony_ci  // Flush style before returning. Some browsers only do partial style re-calc,
3181cb0ef41Sopenharmony_ci  // so ask for all important properties to make sure they are applied.
3191cb0ef41Sopenharmony_ci  getComputedStyle(element).transition;
3201cb0ef41Sopenharmony_ci  getComputedStyle(element).width;
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ci  return element;
3231cb0ef41Sopenharmony_ci}
3241cb0ef41Sopenharmony_ci
3251cb0ef41Sopenharmony_ci// Adds an event handler for |handlerName| (calling |callback|) to the given
3261cb0ef41Sopenharmony_ci// |target|, that will automatically be cleaned up at the end of the test.
3271cb0ef41Sopenharmony_cifunction addTestScopedEventHandler(test, target, handlerName, callback) {
3281cb0ef41Sopenharmony_ci  assert_regexp_match(
3291cb0ef41Sopenharmony_ci      handlerName, /^on/, 'Event handler names must start with "on"');
3301cb0ef41Sopenharmony_ci  assert_equals(target[handlerName], null,
3311cb0ef41Sopenharmony_ci                `${handlerName} must be supported and not previously set`);
3321cb0ef41Sopenharmony_ci  target[handlerName] = callback;
3331cb0ef41Sopenharmony_ci  // We need this cleaned up even if the event handler doesn't run.
3341cb0ef41Sopenharmony_ci  test.add_cleanup(() => {
3351cb0ef41Sopenharmony_ci    if (target[handlerName])
3361cb0ef41Sopenharmony_ci      target[handlerName] = null;
3371cb0ef41Sopenharmony_ci  });
3381cb0ef41Sopenharmony_ci}
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci// Adds an event listener for |type| (calling |callback|) to the given
3411cb0ef41Sopenharmony_ci// |target|, that will automatically be cleaned up at the end of the test.
3421cb0ef41Sopenharmony_cifunction addTestScopedEventListener(test, target, type, callback) {
3431cb0ef41Sopenharmony_ci  target.addEventListener(type, callback);
3441cb0ef41Sopenharmony_ci  // We need this cleaned up even if the event handler doesn't run.
3451cb0ef41Sopenharmony_ci  test.add_cleanup(() => {
3461cb0ef41Sopenharmony_ci    target.removeEventListener(type, callback);
3471cb0ef41Sopenharmony_ci  });
3481cb0ef41Sopenharmony_ci}
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_ci// Returns a promise that will resolve once the passed event (|eventName|) has
3511cb0ef41Sopenharmony_ci// triggered and one more animation frame has happened. Automatically chooses
3521cb0ef41Sopenharmony_ci// between an event handler or event listener based on whether |eventName|
3531cb0ef41Sopenharmony_ci// begins with 'on'.
3541cb0ef41Sopenharmony_ci//
3551cb0ef41Sopenharmony_ci// We always listen on window as we don't want to interfere with the test via
3561cb0ef41Sopenharmony_ci// triggering the prefixed event deduplication logic.
3571cb0ef41Sopenharmony_cifunction waitForEventThenAnimationFrame(test, eventName) {
3581cb0ef41Sopenharmony_ci  return new Promise((resolve, _) => {
3591cb0ef41Sopenharmony_ci    const eventFunc = eventName.startsWith('on')
3601cb0ef41Sopenharmony_ci        ? addTestScopedEventHandler : addTestScopedEventListener;
3611cb0ef41Sopenharmony_ci    eventFunc(test, window, eventName, () => {
3621cb0ef41Sopenharmony_ci      // rAF once to give the event under test time to come through.
3631cb0ef41Sopenharmony_ci      requestAnimationFrame(resolve);
3641cb0ef41Sopenharmony_ci    });
3651cb0ef41Sopenharmony_ci  });
3661cb0ef41Sopenharmony_ci}
367