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

Working with WebSockets

In this chapter, we’ll look at how to test-drive the WebSocket API within our React app. We’ll use it to build a teaching mechanism whereby one person can share their screen and others can watch as they type out commands.

The WebSocket API isn’t straightforward. It uses a number of different callbacks and requires functions to be called in a certain order. To make things harder, we’ll do this all within a Redux saga: that means we’ll need to do some work to convert the callback API to one that can work with generator functions.

Because this is the last chapter covering unit testing techniques, it does things a little differently. It doesn’t follow a strict TDD process. The starting point for this chapter has a skeleton of our functions already completed. You’ll flesh out these functions, concentrating on learning test-driven techniques for WebSocket connections.

This chapter covers the following topics...

Technical requirements

Designing a WebSocket interaction

In this section, we’ll start by describing the sharing workflow, then we’ll look at the new UI elements that support this workflow, and finally we’ll walk through the code changes you’ll make in this chapter.

The sharing workflow

A sharing session is made up of one presenter and zero or more watchers. That means there are two modes that the app can be in: either presenting or watching.

When the app is in presenting mode, then everyone watching will get a copy of your Spec Logo instructions. All your instructions are sent to the server via a WebSocket.

When your app is in watching mode, a WebSocket receives instructions from the server and immediately outputs them onto your screen.

The messages sent to and from the server are simple JSON-formatted data structures.

Figure 16.1 shows how the interface looks when it’s in presenter mode.

Figure 16.1 – Spec Logo in presenter...

Test-driving a WebSocket connection

We start by filling out that first function, startSharing. This function is invoked when the START_SHARING action is received. That action is triggered when the user clicks the Start sharing button:

  1. Open test/middleware/sharingSagas.test.js and add the following imports at the top:
    import { storeSpy, expectRedux } from "expect-redux";
    import { act } from "react-dom/test-utils";
    import { configureStore } from "../../src/store";
  2. At the bottom of the file, add a new describe block and its setup. We’ll break this into a couple of steps: first, set up the Redux store and the WebSocket spy. Because window.WebSocket is a constructor function, we use mockImplementation to stub it out:
    describe("sharingSaga", () => {
      let store;
      let socketSpyFactory;
      beforeEach(() => {
        store = configureStore([storeSpy]);
        socketSpyFactory...

Streaming events with redux-saga

We’ll repeat a lot of the same techniques in this section. There are two new concepts: first, pulling out the search param for the watcher ID, and second, using eventChannel to subscribe to the onmessage callback. This is used to continually stream messages from the WebSocket into the Redux store.

Let’s being by specifying the new URL behavior:

  1. Write a new describe block at the bottom of test/middleware/sharingSagas.test.js, but still nested inside the main describe block:
    describe("watching", () => {
      beforeEach(() => {
        Object.defineProperty(window, "location", {
          writable: true,
          value: {
            host: "test:1234",
            pathname: "/index.html",
            search...

Updating the app

We’ve completed the work on building the sagas, but we have just a couple of adjustments to make in the rest of the app.

The MenuButtons component is already functionally complete, but we need to update the tests to properly exercise the middleware, in two ways: first, we must stub out the WebSocket constructor, and second, we need to fire off a TRY_START_WATCHING action as soon as the app starts:

  1. Open test/MenuButtons.test.js and start by importing the act function. We’ll need this to await our socket saga actions:
    import { act } from "react-dom/test-utils";
  2. Next, find the describe block named sharing button and insert the following beforeEach block, which is similar to the same stubbed constructor you used in the saga tests:
    describe("sharing button", () => {
      let socketSpyFactory;
      let socketSpy;
      beforeEach(() => {
        socketSpyFactory = jest.spyOn(
     ...

Summary

In this chapter, we’ve covered how to test against the WebSocket API.

You’ve seen how to mock the WebSocket constructor function, and how to test-drive its onopen, onclose, and onmessage callbacks.

You’ve also seen how to use a Promise object to convert a callback into something that can be yielded in a generator function, and how you can use eventChannel to take a stream of events and send them into the Redux store.

In the next chapter, we’ll look at using Cucumber tests to drive some improvements to the sharing feature.

Exercises

What tests could you add to ensure that socket errors are handled gracefully?

Further reading

The WebSocket specification:

https://www.w3.org/TR/websockets/

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}