Reader small image

You're reading from  Mastering React Test-Driven Development - Second Edition

Product typeBook
Published inSep 2022
Reading LevelIntermediate
PublisherPackt
ISBN-139781803247120
Edition2nd Edition
Languages
Tools
Right arrow
Author (1)
Daniel Irvine
Daniel Irvine
author image
Daniel Irvine

Daniel Irvine is a UK-based software consultant. He helps businesses simplify their existing codebases and assists dev teams in improving the quality of their software using eXtreme programming (XP) practices. He has been coaching developers for many years and co-founded the Queer Code London meetup.
Read more about Daniel Irvine

Right arrow

Adding Animation

Animation lends itself to test-driven development just as much as any other feature. In this chapter, we’ll animate the Logo turtle movement as the user inputs commands.

There are two types of animation in Spec Logo:

  • First, when the turtle moves forward. For example, when the user enters forward 100 as an instruction, the turtle should move 100 units along, at a fixed speed. As it moves, it will draw a line behind it.
  • Second, when the turtle rotates. For example, if the user types rotate 90, then the turtle should rotate slowly until it has made a quarter turn.

Much of this chapter is about test-driving the window.requestAnimationFrame function. This is the browser API that allows us to animate visual elements on the screen, such as the position of the turtle or the length of a line. The mechanics of this function are explained in the third section of this chapter, Animating with requestAnimationFrame.

The importance of manual testing...

Technical requirements

Designing animation

As you read through this section, you may wish to open src/Drawing.js and read the existing code to understand what it’s doing.

The current Drawing component shows a static snapshot of how the drawing looks at this point. It renders a set of Scalable Vector Graphics (SVG) lines to represent the path the turtle has taken to this point, and a triangle to represent the turtle.

The component makes use of two child components:

  • The Turtle component is displayed once and draws an SVG triangle at the given location
  • The StaticLines component is a set of SVG lines that are drawn onscreen to represent the drawn commands

We will add a new AnimatedLine component that represents the current line being animated. As lines complete their animation, they will move into the StaticLines collection.

We’ll need to do some work to convert this from a static view to an animated representation.

As it stands, the component takes a turtle prop...

Building an animated line component

In this section, we’ll create a new AnimatedLine component.

This component contains no animation logic itself but, instead, draws a line from the start of the line being animated to the current turtle position. Therefore, it needs two props: commandToAnimate, which would be one of the drawLine command structures shown previously, and the turtle prop, containing the position.

Let’s begin:

  1. Create a new file, test/AnimatedLine.test.js, and prime it with the following imports and describe block setup. Notice the inclusion of the sample instruction definition for horizontalLine:
    import React from "react";
    import ReactDOM from "react-dom";
    import {
      initializeReactContainer,
      render,
      element,
    } from "./reactTestExtensions";
    import { AnimatedLine } from "../src/AnimatedLine";
    import { horizontalLine } from "./sampleInstructions";
    const turtle ...

Animating with requestAnimationFrame

In this section, you will use the useEffect hook in combination with window.requestAnimationFrame to adjust the positioning of AnimatedLine and Turtle.

The window.requestAnimationFrame function is used to animate visual properties. For example, you can use it to increase the length of a line from 0 units to 200 units over a given time period, such as 2 seconds.

To make this work, you provide it with a callback that will be run at the next repaint interval. This callback is provided with the current animation time when it’s called:

const myCallback = time => {
  // animating code here
};
window.requestAnimationFrame(myCallback);

If you know the start time of your animation, you can work out the elapsed animation time and use that to calculate the current value of your animated property.

The browser can invoke your callback at a very high refresh rate, such as 60 times per second. Because of these very small intervals...

Canceling animations with cancelAnimationFrame

The useEffect hook we’ve written has commandToAnimate and isDrawingLine in its dependency list. That means that when either of these values updates, the useEffect hook is torn down and will be restarted. But there are other occasions when we want to cancel the animation. One time this happens is when the user resets their screen.

If a command is currently animating when the user clicks the Reset button, we don’t want the current animation frame to continue. We want to clean that up.

Let’s add a test for that now:

  1. Add the following test at the bottom of test/Drawing.test.js:
    it("calls cancelAnimationFrame on reset", () => {
      renderWithStore(<Drawing />, {
        script: { drawCommands: [horizontalLine] }
      });
      renderWithStore(<Drawing />, {
        script: { drawCommands: [] }
      });
      expect(window...

Varying animation behavior

Our lines and turtle are now animating nicely. However, we still need to handle the second type of draw command: rotations. The turtle will move at a constant speed when rotating to a new angle. A full rotation should take 1 second to complete, and we can use this to calculate the duration of the rotation. For example, a quarter rotation will take 0.25 seconds to complete.

In the last section, we started with a test to check that we were calling requestAnimationFrame. This time, that test isn’t essential because we’ve already proved the same design with drawing lines. We can jump right into the more complex tests, using the same triggerRequestAnimationFrame helper as before.

Let’s update Drawing to animate the turtle’s coordinates:

  1. Add the following test to the bottom of the Drawing describe block. Create it in another nested describe block, just below the last test you wrote. The test follows the same principle as...

Summary

In this chapter, we’ve explored how to test the requestAnimationFrame browser API. It’s not a straightforward process, and there are multiple tests that need to be written if you wish to be fully covered.

Nevertheless, you’ve seen that it is entirely possible to write automated tests for onscreen animation. The benefit of doing so is that the complex production code is fully documented via the tests.

In the next chapter, we’ll look at adding WebSocket communication into Spec Logo.

Exercises

  1. Update Drawing so that it resets the turtle position when the user clears the screen with the Reset button.
  2. Our tests have a lot of duplication due to the repeated calls to triggerRequestAnimationFrame. Simplify how this is called by creating a wrapper function called triggerAnimationSequence that takes an array of frame times and calls triggerRequestAnimationFrame for each of those times.
  3. Loading an existing script (for example, on startup) will take a long time to animate all instructions, and so will pasting in code snippets. Add a Skip animation button that can be used to skip all the queued animations.
  4. Ensure that the Undo button works correctly when animations are in progress.
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Mastering React Test-Driven Development - Second Edition
Published in: Sep 2022Publisher: PacktISBN-13: 9781803247120
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Daniel Irvine

Daniel Irvine is a UK-based software consultant. He helps businesses simplify their existing codebases and assists dev teams in improving the quality of their software using eXtreme programming (XP) practices. He has been coaching developers for many years and co-founded the Queer Code London meetup.
Read more about Daniel Irvine