Put the Answering Component on Screen
Tags: react, typescript, testing, tutorial
Published: 2020-01-17 04:41:22

In the last post you wrote the `Answering` component. In this post we will change the main `App` component to show `Answering` to the user. 

Right now, you have the default `App.tsx` file in the `/src/` folder. The code looks like this: 

```typescript
import React from 'react';
import logo from './logo.svg';
import './App.css';

const App: React.FC = () => {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;
```

What it does is show a rotating React logo and a link to reactjs.org. That's great, but it's not what we want. We want it to show the flashcard app. So we need to change the code in `App.tsx`. But this is test driven development! So first we'll write a test in `App.test.tsx`, then we will change the code in `App.tsx` so it passes the test.

##Tests for App.tsx
>File: src/App.test.tsx
>Will Match: [src/complete/test-1.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/complete/test-1.tsx)

`create-react-app` gives you one test for `App.tsx`. The code looks like this:

```javascript
import React from 'react';
import { render } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  const { getByText } = render(<App />);
  const linkElement = getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});
```

We don't want to render a link. We want the `App` component to show the `Answering` component to the user. So let's write a test for that. 

Start by importing the necessary files and calling `afterEach`. This is just like the tests for the `Answering` component, except that we are rendering `App`. 

```javascript
import React from 'react';
import { render, cleanup, getByTestId } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import App from './App';

afterEach(cleanup);
```

##Write comments
Write a comment for each test you are going to do.
All we want the `App` to do at this step is show `Answering`. So that's the first test we are going to add. Then we'll add a snapshot test.

```javascript
//shows the Answering scene
//snapshot
```

##App Test 1: Shows Answering
>File: src/App.test.tsx
>Will Match: [src/complete/test-2.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/complete/test-2.tsx)

```javascript
//shows the Answering component
it('shows the Answering component', () => {

  const { getByTestId } = render(<App/>);

  const answering = getByTestId('answering');
  expect(answering).toBeInTheDocument();
});
```

This test is the same format as the tests we wrote for the `Answering` component. Can you identify the name of the test? 
How about the function that is passed to `it()`? 
What query method are we using to find the component with the testId 'answering'?

##Run the Tests
To run all of the tests, open a command prompt, navigate to the flashcard folder, and run the command `npm test`. Or if the tests are currently running, type `a` to run all tests, or type `p` to open the pattern matcher, find the file you want to run, select it and run it. If Jest is running and you want to stop it, hit `ctrl+c`.

The test 'shows the Answering component' will fail. This test fails because you haven't changed the `App` component to show the `Answering` component. It will pass once you make the changes.

![Default App fails Answering Test](https://thepracticaldev.s3.amazonaws.com/i/9qzbl51fbdp5ede3b0ts.png)

##Pass App Test 1: Shows Answering
>File: src/App.tsx
>Will Match: [src/complete/app-1.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/complete/app-1.tsx)

Now rewrite the `App` component. Import `Answering`. Return `Answering` and give it a testId 'answering' so that the `getByTestId` query we used in the test will find it.

```javascript
import React from 'react';
import './App.css';
import Answering from './scenes/Answering';

const App: React.FC = () => 
      <Answering data-testid='answering'/>

export default App;
```

Run the tests. 

What happens? They should pass, right? You imported the `Answering` component. You passed it a testId 'answering'. And your test is looking for the testId 'answering'. 

**But OH NO!** The test failed!
![Changed App Fails Answering Test](https://thepracticaldev.s3.amazonaws.com/i/chhi85yv2r17fnkolj21.png)

##What's going on?
Is Jest broken? Nope. Did you make a typo? Probably not (but it never hurts to check!) The best way to figure out what is going on is to take a look at what is getting rendered. 

##Use debug to Look at the Result of Rendering
As you can see, when a test fails Jest will print out the rendered code. You can scroll up and look at it. But sometimes you will want to see the rendered result without a failing test. 

The way to take a look at what is getting rendered is the `debug()` method. Go into your `App.test.tsx` file and change the test to this: 

```javascript
//shows the Answering component
it('shows the Answering component', () => {

//get the debug method from the result of render
  const { getByTestId, debug } = render(<App/>);

//call debug
  debug();

//comment out the query and the assertion
  //const answering = getByTestId('answering');
  //expect(answering).toBeInTheDocument();
});
``` 

####debug()
[debug()](https://testing-library.com/docs/react-testing-library/api#debug) is a method that React Testing Library gives us in the object returned from `render()`. Calling `debug` prints the rendered code on the screen so you can see what's in it.
We are using Object Destructuring to get the debug method out of `render(< App />)`. Then we are calling `debug()`. 

We commented out the declaration of `answering` and the `expect()` test for `answering` because we know they are failing. Now we need to figure out why.

##OK, Run the Test Again. 
The test will pass because you commented out the part that was failing. Jest does not run the code because it is commented out. When no code in the test fails, then the test passes. The test passes even if the test isn't really testing anything. So all the tests passed. But scroll up and you will see this: 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/wh0mnm6iq7adr9eg98vi.png)

You can see that the `Answering` component is showing up. There's all the testids that we gave to the components inside `Answering`. You can see `data-testid='container'`, `data-testid='question'`, and all the others. But what don't you see? 

That's right! **`data-testid='answering'` isn't showing up anywhere!** That's why the test was failing.

Even though we passed `data-testid='answering'` to the `Answering` component, 'answering' didn't show up in the render result. Because 'answering' wasn't there, `getByTestId('answering')` threw an error and the test failed.

##Fixing the Missing testId Problem
The reason that the testId doesn't show up is that the `Answering` component that we wrote doesn't do anything with the props that it receives. Assigning data-testid worked for all the other components because they are part of the Semantic-UI-React library. They are written to handle props that are passed to them in a way that makes data-testid show up. 

We could change the `Answering` component so that it looks for props, and displays a `testId` if it receives one. But where would we put the testId? Take a look at `Answering`. The container component already has a testId. We would have to add another component around the container to have somewhere to put the testId. We *could* do that, but we shouldn't!

To make data-testid show up we need to have it show up on a component that gets rendered when `Answering` is shown on the screen. But the outer component, the `Container`, already has a data-testid assigned to it from the tests that we wrote for `Answering`. The container can't have two testids. So to make the data-testid from the props show up we would have to add another div outside of `Container`. Then we could write code to accept data-testId as a prop, and if it got a testId, put the testId on the outer div.

##Adding an Outer Div Would be Bad Design
The outer div wouldn't do anything for us except be a place to show the data-testid. That's bad design. If it doesn't actually do anything to make features work, then you don't need or want it in your app! 

You should write your tests to show that your components work the way you need them to. Don't add code just to pass a test if that code doesn't do anything to make features work. If you find yourself doing that, it's a sign that you should delete the test instead of adding the code!

##Why Don't We Just Look for a testId That is in Answering?
You could look for a testId that is in `Answering`. They show up, and you could find them and it would pass the test. But that would be bad test design. That would be bad test design because the testIds in `Answering` don't have anything to do with making features work.

The testIds in `Answering` are only there to pass the tests in `Answering`. Later, we might decide to take the testIds out of the `Answering`. All the features of `Answering` would still work, but the test for `App` would stop working. When a test is designed so that can happen, it means that the test is not actually testing any feature that matters to the user! 

It is much better to design your tests so that they test based on features that the user sees and uses. That way, your tests will only fail when the features aren't working, not when something that doesn't matter (like a testId) gets changed.

##You Shouldn't Always Test Using testIds
Here's the part of the tutorial that gives you one of the difficult pieces of advice about programming. **There is no one best way to test if something is displayed on the screen.** Sometimes using a testId is a good way to it. In other situations a testId is not the best way to do it.

##Ok, Then How *Should* We Test to Make Sure Answering is Showing Up?
We know the `Answering` component shows a button that lets the user submit their answer. This button has the text 'Submit'. The button with the text 'Submit' is a feature that actually matters to the user. So let's make the test look for the text 'Submit' in the rendered component. 

##App Test 1: Second Version
>File: src/App.test.tsx
>Will Match: [src/complete/test-3.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/complete/test-3.tsx)

Change the test for showing `Answering` to this:

```javascript
//shows the Answering scene
it('shows the Answering scene', () => {
    const { getByText } = render(<App/>);
  
    //the Answering scene shows the Skip button
    const skip = getByText(/skip/i);
  
    //if we find the skip button, we know Answering is showing up
    expect(skip).toBeInTheDocument();
  });
```

Delete the `data-testid='answering'` from the `Answering` component in the `App`.  You aren't using it and it didn't show up anyway. This is what the return value of the `App` looks like without the testId.

```javascript
const App: React.FC = () => 
      <Answering/>
```
Now run the test. 

![Answering Test Passes](https://thepracticaldev.s3.amazonaws.com/i/otxjj3v8fpwbnwkk1mos.png)

There we go! `Answering` is showing up in the `App` component. 
Hit `ctrl+c` to stop running the tests. Type `npm start` to run the app. You should get a message that it has compiled successfully.

![Compiled](https://thepracticaldev.s3.amazonaws.com/i/i75ksrvpwi0qx7b3mw14.png)

Once the app loads into your web browser, it should look like this:

![The App so far](https://thepracticaldev.s3.amazonaws.com/i/5e6ykyzupxza9wut464y.png)

There's the `Answering` component! Beautiful, isn't it?

If the app does not load automatically, open a web browser and type the url: localhost:3000. There it is!

##But the App Doesn't Do Anything
That's right, the `Answering` component doesn't do anything- yet! We haven't made it do anything useful. We'll change that in the next post when we make the `CardContext` provide the cards so `Answering` has something to show the user! Let's finish off the work on the `App` component with a snapshot test.

##Snapshot Test
>File: src/App.test.tsx
>Will Match: [src/complete/test-4.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/complete/test-4.tsx)

This is just like the snapshot test for the Answering component, except that we are rendering `App`. 
```javascript
it('Matches Snapshot', () => {
  const { asFragment } = render(<App/>);
  expect(asFragment()).toMatchSnapshot(); 
});
```

##Run the Tests
![Snapshot Passes](https://thepracticaldev.s3.amazonaws.com/i/w6v0gt54qtobeu13smg0.png)

The snapshot test passed because this is the first time it has been run. The first time you run a snapshot test for a component, Jest will create a new snapshot for that component. So when you ran the snapshot test for the `App` component it created a new snapshot, and it looked like that snapshot so it passed. The snapshot test will fail once you change the code of the `App` component to display the `Answering` component. The snapshot test will fail because the `App` component will look different. When the snapshot test fails because you made changes that you wanted to make, you will update the snapshot by pressing 'u' on the screen that tells you the test failed. If the snapshot fails when you didn't want to change what shows up, you need to fix the changes you made.

####Next Post: CardContext
The next post will show you how to make the `CardContext`. The CardContext is the component that tracks the cards and makes them available to the other components in the `App`.