Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Mastering React Test-Driven Development - Second Edition

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

Product type Book
Published in Sep 2022
Publisher Packt
ISBN-13 9781803247120
Pages 564 pages
Edition 2nd Edition
Languages
Author (1):
Daniel Irvine Daniel Irvine
Profile icon Daniel Irvine

Table of Contents (26) Chapters

Preface 1. Part 1 – Exploring the TDD Workflow
2. Chapter 1: First Steps with Test-Driven Development 3. Chapter 2: Rendering Lists and Detail Views 4. Chapter 3: Refactoring the Test Suite 5. Chapter 4: Test-Driving Data Input 6. Chapter 5: Adding Complex Form Interactions 7. Chapter 6: Exploring Test Doubles 8. Chapter 7: Testing useEffect and Mocking Components 9. Chapter 8: Building an Application Component 10. Part 2 – Building Application Features
11. Chapter 9: Form Validation 12. Chapter 10: Filtering and Searching Data 13. Chapter 11: Test-Driving React Router 14. Chapter 12: Test-Driving Redux 15. Chapter 13: Test-Driving GraphQL 16. Part 3 – Interactivity
17. Chapter 14: Building a Logo Interpreter 18. Chapter 15: Adding Animation 19. Chapter 16: Working with WebSockets 20. Part 4 – Behavior-Driven Development with Cucumber
21. Chapter 17: Writing Your First Cucumber Test 22. Chapter 18: Adding Features Guided by Cucumber Tests 23. Chapter 19: Understanding TDD in the Wider Testing Landscape 24. Index 25. Other Books You May Enjoy

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 2022 Publisher: Packt ISBN-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.
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}