Freezing animations

👍

Covered in this doc

  • The challenge of animations in visual testing
  • How Percy automatically freezes CSS animations and GIFs
  • Freezing jQuery, Highcharts, and Velocity animations

A big challenge of visual testing is reducing false-positive visual diffs. False-positives can be caused by many variables (including system and hardware differences between browser environments), but are commonly caused by page animations.

For example, take this awesome pure-CSS animation:

See the Pen Submarine with CSS by Mike Fotinakis (@fotinakis) on CodePen.

If you captured a page with this animation multiple times, you would end up with noisy and false-positive visual diffs:

828

Though fun to look at, this doesn't really help us identify visual regressions!

Automatic animation freezing in Percy


Percy does a lot of work behind the scenes to make sure that pages are rendered consistently and deterministically. One of the things we do is freeze different kinds of animations that can cause false-positive visual diffs.

Percy will automatically:

  • Freeze animated GIFs on the first frame.
  • Freeze most CSS animation and transition styles.

Other than animations, Percy does other server-side tricks to create a consistent rendering environment and avoid other kinds of false-positives (such as font rendering differences, sub-pixel antialiasing, width and height changes, etc.)

Freezing other animations


jQuery animation handling

Percy does not by default execute JavaScript in our rendering pipeline, but JavaScript is likely enabled in the browser that runs your acceptance tests locally or on CI. You might be unknowingly running jQuery animations in tests simply by using them in your app.

In addition to causing false-positives if the DOM is captured in the middle of animation, jQuery animations can also have the adverse effect of slowing down your acceptance tests---assertions might wait for animations to complete before an element exists on the page. Temporarily disabling jQuery animations might help speed up your acceptance tests, as well as will help Percy avoid capturing the DOM state while elements are still animating.

You can set a jQuery config to disable animations:

$.fx.off = true;

🚧

NOTE: You should only include this snippet in your testing environment!

As the jQuery docs say: "When this property is set to true all animation methods will immediately set elements to their final state when called, rather than displaying an effect."

Freeze SVG animations

SVGs can be animated using animateTransform and will not be frozen by Percy in all browsers. To freeze these animations you must utilize Percy specific CSS.

Let's go through an example. The following page has an SVG loading animation that spins using the transform attribute. To freeze this in Percy, we've added some Percy specific CSS in the head.

<html>
  <head>
    <style type="text/css">
      @media only percy {
        .loading-spinner {
          transform: rotate(0);
        }
      }
    </style>
  </head>
  <body>
    <svg width="21" height="21" viewBox="0 0 21 21">
      <g fill="none">
        <path 
          stroke="#9E66BF"
          stroke-width="2"
          d="M1,10 C1.14147949,5.49999934 5.00437084,0.956663874 10.5013061,1.00031374 C15.9982414,1.04396361 19.8972168,5.49999934 19.9998888,10"
          class="loading-spinner"
        >
          <animateTransform
            attributeType="xml"
            attributeName="transform"
            type="rotate"
            from="0 10.5 10.5"
            to="360 10.5 10.5"
            dur="1s"
            repeatCount="indefinite" />
        </path>
      </g>
    </svg>
  </body>
</html>

The CSS property used to freeze this animation must be the same as what's used in animateTransform. In this example we are using type="rotate" so the corresponding freeze for this is transform: rotate(0);. Using transform: none; will not freeze the animation here.

Freeze Highcharts animations

Highcharts.setOptions({
  chart: {
    animation: false
  },
  plotOptions: {
    series: {
      animation: false
    }
  }
});

Velocity animation handling

If you are using the Velocity animation accelerator, you can mock time when animating elements to disable the animation tweening entirely. This allows you to snapshot the end state of your animation. To do so, add the following to your Velocity config to disable animations:

$.Velocity.mock = true;

This will force all Velocity animations to run with 0ms duration and 0ms delay on the next animation tick. For more information on how this works, see the Velocity documentation

Pausing Greensock animations

Greensock is relies on requestAnimationFrame under the hood. If you use TweenMax you can set the globalTimeScale to 0 in your test environment to pause animations on all timelines:

TweenMax.globalTimeScale(0)

TimelineLite also has a way to adjust time scale via exportRoot