CardContext
Tags: react, typescript, testing, tutorial
Published: 2020-01-17 04:42:03

![Image of Flashcards](https://thepracticaldev.s3.amazonaws.com/i/k3hn9dnumxt3ea6o58rq.png)

Now let's make `Answering` display a card to the user. To display a card Answering needs to get the card from somewhere. The component that will give the card to `Answering` is a React [Context](https://reactjs.org/docs/context.html) component. We are going to use a `Context` component named `CardContext` to manage the array of cards. Our components will get the array of cards and the index of the current card from the `CardContext`.

This post will show you how to make the `CardContext`. After we make the `CardContext`, we'll change the `App` and `Answering` so that `Answering` can access the cards. We'll make `Answering` show the question from the current card. The last thing we'll do in this post is make clicking the `Skip` Button change the current index in `CardContext` to the index of next card in the cards array. In the next post we'll make `Answering` show the answer from the current card after the user clicks the `Submit`.

#What is Context?
[Context](https://reactjs.org/docs/context.html) is one of the [React Hooks](https://reactjs.org/docs/hooks-intro.html). `Context` does three things for this app: 
* `Context` contains data, like the array of card objects and the index number of the current card
* `Context` lets the components access the data contained in `Context`
* `Context` lets components dispatch actions to `Context`. When `Context` receives an action it makes changes to the data that it contains

##The Four Parts of CardContext
We'll make the four different parts of the `CardContext`
* `initialState`: the object that has the starting value of the `cards` array and the starting value of the `current` index.
* `reducer`: the function that handles the actions dispatched to `Context` and makes changes to the data in the `Context`. For example, when the `reducer` handles a 'next' action it will change the `current` index to the index of the next card in the `cards` array.
* `CardContext`: The context object contains the data. Contains the array of `cards` and the `current` index.
* `CardProvider`: the React component that gives components inside it access to the data in the `CardContext`.

#Types.ts: Make the types.ts File
>File: src/types.ts
>Will Match: [src/complete/types-1.ts](https://github.com/jacobwicks/flashcard/blob/master/src/complete/types-1.ts)

Before we make `CardContext` we will make the types file. The types file is where we will keep all the TypeScript interface types for this app. Interface types define the shape of objects. Assigning types lets you tell the compiler what properties objects will have. This lets the compiler check for errors, like if you try to use a property that is not on an object. 

Create a new file named `types.ts` in the `src/` folder.

##The Card Interface
Copy or retype the interface `Card` into `types.ts` and save it. `Card` models a single flashcard. It has three properties: answer, question, and subject. Each property is a string.
 
```javascript
//defines the flashcard objects that the app stores and displays
export interface Card {
    //the answer to the question
    answer: string,

    //the question prompt
    question: string,

    //the subject of the question and answer
    subject: string
}
```
We will keep an array of `Card` objects in `CardContext`. We will call this array 'cards.' The array `cards` will be our data model of a real world object, a deck of flashcards. Components in the app will be able to use `CardContext` to look at the `cards`. For example, `Answering` will look at a single card in `cards` and show the user the question property inside of a `Header`.

We will come back to the types file later in this post when we need to declare more types.

#Testing CardContext
To fully test `CardContext` we will test `CardProvider`, `CardContext`, and the `reducer`. We will start by testing the `reducer`, the function that handles actions correctly and returns the state object that holds the cards. Then we will test the `CardProvider`, starting with a test that it renders without crashing. Later we will write a helper component to make sure that `CardContext` returns the right data.

#The Reducer
The `reducer` is what makes changes to the state held in a `Context`. Each `Context` has a `dispatch` function that passes actions to the `reducer`. The `reducer` handles actions using a [switch statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch). The `reducer`'s switch statement looks at the type of the action. 

The switch statement has a block of code, called a `case`, for each action type. The `case` is where you write the code that will change the state. The `reducer` will run the code inside the `case` that matches the action type. The code inside each case handles the action and returns a state object.

We'll start out by testing that the reducer takes a state object and an action object and returns the same state object.

##CardContext Test 1: Reducer Returns State
>File: src/services/CardContext/index.test.tsx
>Will Match: [src/services/CardContext/complete/test-1.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/test-1.tsx)

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

afterEach(cleanup);

describe('CardContext reducer', () => {
    it('returns state', () => {
        const state = {};
        const action = { type: undefined };
        expect(reducer(state, action)).toEqual(state);
    })
})
```
Put this test inside a [describe()](https://jestjs.io/docs/en/api#describename-fn) block. Name the describe block 'CardContext reducer.' The describe block is a way to group tests. When you run the tests, Jest will show you the name of the describe block above the tests that are inside it. The test names will be indented to show that they are inside a describe block.

This test goes inside a describe block because we are going to group all the tests for the reducer together.

##Running Tests for One File
Run this test. While we are making `CardContext` we only care about the tests for `CardContext`. While you are running Jest, type 'p' to bring up the file search. Type 'CardContext,' use the arrow keys to highlight `CardContext/index.test.tsx`, and hit enter to select this test file.

![Select Tests](https://thepracticaldev.s3.amazonaws.com/i/0q0arxsdj9sd64e65q0d.png)

Now we are only running the tests inside this test file. 

##Pass CardContext Test 1: Reducer Returns State
>File: src/services/CardContext/index.tsx
>Will Match: [src/services/CardContext/complete/index-1.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/index-1.tsx)

Write the first version of the `reducer`. The `reducer` takes two parameters. 

The first parameter is the state object. We have not yet declared the shape of the state for `CardContext`. So we'll assign the state parameter a type of `any`. Later we will change the state parameter to a custom `CardState` type. CardState will be defined in the file `types.ts`.

The second parameter is the action object. Actions must have a type. The `reducer` always looks at the type of the action to decide how to handle it. We have not declared the types of actions that `CardContext` will handle. So we'll assign action a type of `any` to the actions. Later we will change it to a custom `CardAction` type. `CardAction` will be defined in the file `types.ts`.

```javascript
//the reducer handles actions
export const reducer = (state: any, action: any) => {
    //switch statement looks at the action type
    //if there is a case that matches the type it will run that code
    //otherwise it will run the default case
    switch(action.type) {
        //default case returns the previous state without changing it
        default: 
            return state
    }
};
```
The way that the `reducer` handles the actions that it receives is with a [switch statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch). The switch statement looks at the action type. 
```javascript
//the first argument passed to the switch statement tells it what to look at
switch(action.type) 
```
The switch statement looks for a `case` that matches the type of the action. If the switch statement finds a case that matches the action type, it will run the code in the case. If the switch case does not find a case that matches the action type, it will run the code in the default case. 

We have only written the default case. The default case returns the state object without any changes. The first test that we wrote passes an empty object {}, and an action with type `undefined`. The `reducer` will pass the action to the switch statement. The switch statement will look for an action with a matching type, `undefined`, fail to find it, and run the default case. The default case will return the empty object {} that the reducer received, so the reducer will return an empty object.

This doesn't do anything useful yet, but it does pass our first test. 
![Returns State](https://thepracticaldev.s3.amazonaws.com/i/jh032u60utlnj0qddogl.png)

##CardContext Test 2: CardProvider Renders Without Crashing
>File: src/services/CardContext/index.test.tsx
>Will Match: [src/services/CardContext/complete/test-2.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/test-2.tsx)

One of the exports from `Context`s is the `Provider`. `Provider`s are React components that make the `Context` available to all of their child components. The `Provider` for `CardContext` is called `CardProvider`. Add an import of the `CardProvider` from index. We will write the `CardProvider` to pass this test.
```javascript
import { CardProvider } from './index';
```

The test to show that the `CardProvider` renders without crashing is just one line. Use JSX to call `CardProvider` inside the `render()` function.

```javascript
it('renders without crashing', () => {
    render(<CardProvider children={[<div key='child'/>]}/>)
});
```
React `Context Provider` requires an array of child components. It can't be rendered empty. So we pass the prop `children` to `CardProvider`. The code
```javascript
[<div key='child'/>]
```
is an array that contains a div. The div has a key because React requires components to have a key when it renders an array of components.

This test will fail because we haven't written the `CardProvider` yet.
![Failed test](https://thepracticaldev.s3.amazonaws.com/i/3se2ce6wz6a8wwqoal23.png)

##Pass CardContext Test 2: CardProvider Renders Without Crashing
>File: src/services/CardContext/index.tsx
>Will Match: [src/services/CardContext/complete/index-2.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/index-2.tsx)

Import `createContext` and `useReducer` from React.
```javascript
import React, { createContext, useReducer } from 'react';
```
We'll use `createContext` and `useReducer` to make the `CardContext` work. Here are some explanations of what they do. **Don't worry if you don't understand createContext and useReducer.** You will learn more about them by seeing them in action.

[createContext()](https://reactjs.org/docs/context.html#reactcreatecontext) takes an initial state object as an argument. It returns a context object that can be used by the `Provider` component. After we pass Test 2 we will make an example array `cards` and pass it to `createContext` as part of the `initialState` object.

[useReducer()](https://reactjs.org/docs/hooks-reference.html#usereducer) takes a `reducer` function like the one we just wrote and adds a `dispatch` method to it. The `dispatch` method is a function that accepts `action` objects. When a React component calls the `dispatch` from a `Context`, the component sends an action to the `reducer` of that `Context`. The `reducer` can then change the `state` in the `Context`. That's how a component can do things like make a button that changes the index to the index of the next card. The button will use `dispatch` to send an action to the `reducer`, and the `reducer` will handle the action and make the changes.

##InitialState

Declare the `initialState` object below the `reducer`.

```javascript
//the object that we use to make the first Context
const initialState = {};
```

Start with an empty object. This empty object `initialState` will be enough to get the `CardProvider` to pass the first test. Later we will define a `CardState` interface and make the `initialState` match that interface. The `CardState` will contain the array `cards` and the `current` index number.

##Make the CardContext
Use `createContext` to make a context object `CardContext` out of the `initialState`.
```javascript
//a context object made from initialState
const CardContext = createContext(initialState);
```

##Declare the CardProviderProps Interface
Declare an interface for the props that `CardProvider` will accept. Call the interface `CardProviderProps`. `CardProvider` can accept React components as children. Assign the type React.ReactNode to the `children` prop.

We keep the interface type declaration for `CardProviderProps` in this file instead of types.ts because we won't need to import the `CardProviderProps` into any other files. It will only be used here. Types.ts holds types that will get used in more than one place in the App.

```javascript
//the Props that the CardProvider will accept
type CardProviderProps = {
    //You can put react components inside of the Provider component
    children: React.ReactNode;
};
```

This is the first version of `CardProvider`. 
Call `useReducer` to get an array containing values for the state object and the dispatch methods. 

Declare an object `value`. We create `value` using the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)\(...).  The spread operator can be used to create arrays and objects. Using the spread operator on the state object tells the compiler to create an object using all the properties of state, but then add the dispatch method. 

`CardProvider` returns a `Provider` component. `CardProvider` makes `value` available to all of its child components. 

```javascript
const CardProvider = ({ children }: Props ) => {
    //useReducer returns an array containing the state at [0]
    //and the dispatch method at [1]
    //use array destructuring to get state and dispatch 
    const [state, dispatch] = useReducer(reducer, initialState);

    //value is an object created by spreading state 
    //and adding the dispatch method
    const value = {...state, dispatch};

    return (
        //returns a Provider with the state and dispatch that we created above
        <CardContext.Provider value={value}>
            {children}
        </CardContext.Provider>
    )};
```

Instead of exporting a default value, export an object containing `CardContext` and `CardProvider`.

```javascript
export { 
    //some components will import CardContext so they can access the state using useContext
    CardContext, 
    //the App will import the CardProvider so the CardContext will be available to components
    CardProvider 
};
```
Save the file. Now `CardContext` renders without crashing!
![CardContext renders without crashing](https://thepracticaldev.s3.amazonaws.com/i/v0yqwjdlvuxesrcinq4e.png)

##Making InitialState and Declaring the CardState Type
>File: src/services/CardContext/index.tsx
>Will match: [src/services/CardContext/complete/index-3.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/index-3.tsx)

Now we are going to make the array of `cards` that will go in the `CardContext`. These cards are objects of the type `Card`. We made the type `Card` earlier. Each `Card` will have an answer, question, and a subject.

Import `Card` from types.

```javascript
import { Card } from '../../types';
```

We are going to declare the variables `card1`, `card2`, and `cards`. Put these variables in the file after the imports but before everything else. JavaScript variables have to be declared before they are used. If you put these variables too far down in the file you'll get an error when you try to use the variables before they are declared.

Declare `card1`. To tell TypeScript that `card1` has the type `Card`, put `: Card` after the declaration but before the =.
Because `card1` is an object of type `Card`, it needs to have an answer, question, and a subject. Answer, question and subject are all strings. But the answer is going to have multiple lines. We will store the answer as a [template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals). That sounds complicated, but what it basically means is that if you write a string inside of backticks instead of quote marks ' ' or " ", then you can use linebreaks.

Here's `card1`:

```javascript
//declare a card object
const card1: Card = {
    question: 'What is a linked list?',
    subject: 'Linked List',
//answer is inside of backticks
//this makes it a 'template literal`
//template literals can contain linebreaks
    answer: `A linked list is a sequential list of nodes. 
    The nodes hold data. 
    The nodes hold pointers that point to other nodes containing data.`
};
```
And `card2`:
```javascript
//declare another card object
const card2: Card = {
    question: 'What is a stack?',
    subject: 'Stack',
    answer: `A stack is a one ended linear data structure.
    The stack models real world situations by having two primary operations: Push and pop.
    Push adds an element to the stack.
    Pop pulls the top element off of the stack.`
};
```

Now declare the array `cards`. TypeScript will infer that `cards` is an array of objects with the type `Card` because all the objects in the array when it is created fit the `Card` interface.

```javascript
//make an array with both cards
//this is the starting deck of flashcards
const cards = [card1, card2];
```

We will put this array of `cards` into the `initialState` object.

##Types.ts: Declare CardState Interface
>File: src/types.ts
>Will Match: [src/complete/types-2.ts](https://github.com/jacobwicks/flashcard/blob/master/src/complete/types-2.ts)

Before we put the `cards` into `initialState`, we need to declare the `CardState` interface. `initialState` will fit the `CardState` interface. `CardState` will have `cards`, which is the array of `Card` objects that represents the deck of flashcards. `CardState` will also have `current`, the number that is the index of the card in `cards` that the user is currently looking at. 

We also need to declare that `CardState` contains the `dispatch` method. `dispatch` is the function that passes actions to the `Context` `reducer`. We haven't made the `CardAction` type that will list all the types of actions that `CardContext` can handle. When we do, we'll change the type of the dispatch actions to `CardAction`. For now, we'll make the actions `any` type.

```javascript
//the shape of the state that CardContext returns
export interface CardState {
    
    //the array of Card objects
    cards: Card[],
    
    //the index of the currently displayed card object
    current: number,
    
    //the dispatch function that accepts actions
    //actions are handled by the reducer in CardContext
    dispatch: (action: any) => void
};
```

##Make the InitialState Object
>File: src/services/CardContext/index.tsx
>Will match: [src/services/CardContext/index-3.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/index-3.tsx)

Import the `CardState` interface.
```javascript
import { Card, CardState } from '../../types';
```

##Make `reducer` Use `CardState`
Now that we have declared the `CardState` interface, `reducer` should require the `state` object to be a `CardState`. 

Change the first line of the `reducer` from
```javascript
//the reducer handles actions
export const reducer = (state: any, action: any) => {
```
To
```javascript
//the reducer handles actions
export const reducer = (state: CardState, action: any) => {
```
Now the `reducer` requires the state to be a `CardState`. 

##Change initialState
Change the definition of `initialState` from
```javascript
//the object that we use to make the first Context
const initialState = {};
```

To this:
```javascript
//the object that we use to make the first Context
//it is a cardState object
export const initialState: CardState = {
    //the deck of cards
    cards,
    
    //the index of the current card that components are looking at
    current: 0,

    //dispatch is a dummy method that will get overwritten with the real dispatch
    //when we call useReducer
    dispatch: ({type}:{type:string}) => undefined,
}; 
```
We have made `initialState` fit the `CardState` interface. `initialState` is exported because it will be used in many test files. 

##Add Optional testState parameter to CardProviderProps
Speaking of tests, we want to be able to use a state object that isn't initialState for some of our tests. Add an optional prop `testState` to `CardProviderProps`. `testState` will fit the interface `CardState`. `testState` is optional, so put a question mark `?` in front of the `:`.

```javascript
//the Props that the CardProvider will accept
type CardProviderProps = {
    //You can put react components inside of the Provider component
    children: React.ReactNode;
    
    //We might want to pass a state into the CardProvider for testing purposes
    testState?: CardState
};
```
##Change CardProvider to Use Optional testState Prop
Add `testState` to the list of props that we get from `CardProviderProps`. Change the arguments passed to `useReducer`. If CardProvider recieved a `testState`, it will pass the `testState` to `useReducer`. Otherwise, it will use the `initialState` object declared earlier in the file.

```javascript
const CardProvider = ({ children, testState }: CardProviderProps ) => {
    //useReducer returns an array containing the state at [0]
    //and the dispatch method at [1]
    //use array destructuring to get state and dispatch 
    const [state, dispatch] = useReducer(reducer, testState ? testState : initialState);
```

##Test That CardContext Provides initialState
>File: src/services/CardContext/index.test.tsx
>Will Match: [src/services/CardContext/complete/test-3.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/test-3.tsx)

Import `initialState` from index.
```javascript
import { CardProvider, initialState } from './index';
```

##Change the CardContext reducer Test for 'returns state'
The first test of the `reducer` isn't passing a `CardState`. It's passing an empty object. Let's change that. Instead of passing `reducer` an empty object, pass it the `initialState` object that we imported from `CardContext/index.tsx`.

Change the 'returns state' test from:
```javascript
it('returns state', () => {
        const state = {};
        const action = { type: undefined };
        expect(reducer(state, action)).toEqual(state);
    });
```

To use `initialState`:
```javascript
it('returns state', () => {
        const action = { type: undefined };
        expect(reducer(initialState, action)).toEqual(initialState);
    });
```

##Testing CardContext
The creator of the React Testing Library says that the closer your tests are to the way that your users use your app, then the more confident you can be that your tests actually tell you the app works. So React Testing Library doesn't look at the inside of React components. It just looks at what is on the screen. 

But the `CardContext` doesn't put anything on the screen. The only time the user will see something from `CardContext` on the screen is when another component gets something from `CardContext` and then shows it to the user. So how do we test `CardContext` with React Testing Library? We make a React component that uses `CardContext` and see if it works!

##Make CardConsumer, A Helper React Component in the Test File
The best way I have figured out how to test `Context` components is to write a component in the test file that uses the `Context` that you are testing. This is not a component that we'll use anywhere else. It doesn't have to look good. All it does is give us an example of what will happen when a component in our app tries to get data from the `Context`.

We'll call the helper component `CardConsumer`. It will use the `CardContext` and display the current index, and all three properties of the current question.

##Isn't the Helper Component Just Doing the Same Thing that the App Components Will Do?
Yes. It is. The other components that we will make in this app will access all the different parts of `CardContext`. We'll write tests for those components to make sure that they work. Taken together, all the tests for all those components will tell us everything that the tests using the helper component will tell us. 

But `CardConsumer` displays it all in one place, and that place is in the test file for the `CardContext` itself. If `CardContext` doesn't work, some of the tests for the components that use `CardContext` might fail. But we know for sure that the tests for `CardContext` will fail. And that gives us confidence that we can modify `CardContext` without breaking the app!

##Make CardConsumer: the Helper Component
>File: src/services/CardContext/index.test.tsx
>Will Match: [src/services/CardContext/complete/test-4.tsx]
(https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/test-4.tsx)

Import `useContext` from React. `CardConsumer` will use `useContext` to access `CardContext`, just like our other components will.

```javascript
import React, { useContext } from 'react';
```

Import `CardState` from `types.ts`.
```
import { CardState } from '../../types';
```

Import `CardContext`.
```javascript
import { CardContext, CardProvider, initialState } from './index';
```

Write the helper component `CardConsumer`. The only new thing you are seeing here is the call to `useContext`. We imported `CardContext` and pass it to `useContext` as an arguent: `useContext(CardContext)`. 

As I talked about earlier, `useContext` lets you access the data in a `Context`. We are using `useContext` to get `cards` and the `current` index. 

Then we declare a const `card` and assign it a reference to the object at the `current` index in `cards`. We return a div with each property from `card` displayed so that we can use React Testing Library matchers to search for them. `CardConsumer` is *using `CardContext` the same way our user will*. That is why it is useful for testing.

```javascript
//A helper component to get cards out of CardContext
//and display them so we can test
const CardConsumer = () => {
    //get cards and the index of the current card 
    const { cards, current } = useContext(CardContext);

    //get the current card
    const card = cards[current];

    //get the question, answer, and subject from the current card
    const { question, answer, subject } = card;

    //display each property in a div
    return <div>
        <div data-testid='current'>{current}</div>
        <div data-testid='question'>{question}</div>
        <div data-testid='answer'>{answer}</div>
        <div data-testid='subject'>{subject}</div>
    </div>
};
```
##Make renderProvider: A Helper Function to Render CardConsumer Inside CardProvider
Every component that uses a `Context` has to be inside the `Provider` component for that `Context`. Every component that will use `CardContext` needs to be inside the `CardContext` `Provider`, which we named `CardProvider`. `CardConsumer` is a component that uses `CardContext`. So `CardConsumer` needs to be inside `CardProvider`. Let's write a helper function named `renderProvider` that renders the CardConsumer inside the CardContext.

```javascript
//renders the CardConsumer inside of CardProvider
const renderProvider = (testState?: CardState) => render(
    <CardProvider testState={testState}>
        <CardConsumer/>
    </CardProvider>
);
```
Now when we want to look at `CardConsumer` for tests we can just call `renderProvider()`. 

Do you see that `renderProvider` takes an optional `testState` prop? That is so that when we want to test a certain state, we can pass the state to `renderProvider`. If we just want the normal `initialState` that the `CardProvider` has, then we don't need to pass anything to `renderProvider`.

##CardContext Tests 4-7: CardContext Provides Correct Values
>File: src/services/CardContext/index.test.tsx
>Will Match: [src/services/CardContext/complete/test-5.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/test-5.tsx)

We already know that `reducer` is working. We have a test that shows that when it receives the `initialState` and an action with type `undefined` it will return the `initialState`. But we don't know that `CardContext` is working. Let's test `CardContext`.

These tests are in addition to the tests for the `reducer`. Do not delete your `reducer` tests.

##What Features of CardContext Should We Test?
Let's test everything that `CardContext` does. `CardContext`
* has an array of `cards`
* has `current`, the number of the index of the current card

We know what's in `initialState` because we just made the `initialState` object. So let's test that `CardConsumer` gets a value of 0 for `current`, finds a `Card` object at the index current in the array `cards`, and that the card object has a question, a subject, and an answer. Write a comment for each test.

```javascript
//current is 0
//question is the same as initialState.cards[0].question
//subject is the same as initialState.cards[0].subject
//answer is the same as initialState.cards[0].answer
```

We'll put all the `CardConsumer` tests inside of a describe block. Name the describe block 'CardConsumer using CardContext.' This will keep our tests organized.
```javascript
//testing the CardConsumer using CardContext inside CardProvider
describe('CardConsumer using CardContext', () => {
    //current is 0
    //question is the same as initialState.cards[0].question
    //subject is the same as initialState.cards[0].subject
    //answer is the same as initialState.cards[0].answer

});
```

##CardContext Test 4: Current is 0

Write the first test and save it.
 
```javascript
//testing the CardConsumer using CardContext inside CardProvider
describe('CardConsumer using CardContext', () => {
    //current is 0
    it('has a current value 0', () => {
        const { getByTestId } = renderProvider();
        const current = getByTestId(/current/i);
        expect(current).toHaveTextContent('0');
    });

    //question is the same as initialState.cards[0].question
    //subject is the same as initialState.cards[0].subject
    //answer is the same as initialState.cards[0].answer
});
```
##Hard-Coded Values in Tests Tell You Different Things Than References to Objects
Notice that we are testing for a hard-coded value of 0. We just made the `initialState` object. We *know* that `initialState.current` is going to start with a value of 0. We could have passed a reference to `initialState.current` in our assertion. But we didn't. We passed a string '0.' 

The rest of the `CardConsumer` tests will expect that the current card is the card found at `cards[0]`. If we changed `initialState` to pass a different index, all those tests would fail. But, with the hardcoded value of 0, the current value test would also fail. We'd know `initialState` was passing a different value. But if we expected current to have text content equal to initialState.current, this test would pass even though initialState.current wasn't the value we thought it would be. You should generally prefer to use hardcoded values in your tests, especially instead of references to objects that are generated by other code.

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

##CardContext Test 5: card.question
Get the question from the current card from the `initialState`. 
Get the `getByTestId` matcher from the `renderProvider` helper function. 
Use `getByTestId` to find the question by its `testid`, passing a case insensitive regular expression to `getByTestId`. 
Assert that the `textContent` of the `question` div will match the question from the current card.

```javascript
    //question is the same as initialState.cards[0].question
    it('question is the same as current card', () => {
        //get cards, current from initialState
        const { cards, current } = initialState;
        
        //get the question from the current card
        const currentQuestion = cards[current].question;

        const { getByTestId } = renderProvider();
        //find the question div
        const question = getByTestId(/question/i);

        //question div should match the current question
        expect(question).toHaveTextContent(currentQuestion);
    });
```

![Question test Passes](https://thepracticaldev.s3.amazonaws.com/i/io848df1ta65qodj6pyt.png)

##CardContext Test 6: card.subject
The test for the subject is almost the same as the test for the question.
```javascript
//subject is the same as initialState.cards[0].subject
      it('subject is the same as current card', () => {
        //get cards, current from initialState
        const { cards, current } = initialState;
        
        //get the subject from the current card
        const currentSubject = cards[current].subject;

        const { getByTestId } = renderProvider();
        //find the subject div
        const subject = getByTestId(/subject/i);

        //subject div should match the current subject
        expect(subject).toHaveTextContent(currentSubject);
    });
```
![Subject Test Passes](https://thepracticaldev.s3.amazonaws.com/i/6gsqrumvf4va13ffmp5j.png)

##CardContext Test 6: card.answer
Write the test for the answer is almost the same as the other two tests.
```javascript
    //answer is the same as initialState.cards[0].answer
    it('answer is the same as current card', () => {
        //get cards, current from initialState
        const { cards, current } = initialState;
        
        //get the answer from the current card
        const currentanswer = cards[current].answer;

        const { getByTestId } = renderProvider();
        //find the answer div
        const answer = getByTestId(/answer/i);

        //answer div should match the current answer
        expect(answer).toHaveTextContent(currentanswer);
    });
```
This test should work, right? Save it and run it. What happens?
![It fails](https://thepracticaldev.s3.amazonaws.com/i/fy1ehtd61i671qecrqn8.png)
It fails! That's surprising, isn't it? Look at the error that Jest gives us:
![Error mesage](https://thepracticaldev.s3.amazonaws.com/i/bpwcoosbem6ci4rpu56b.png)

Now that's puzzling. It's got the same text in 'Expected element to have text content' as it has in 'received.' Why do you think it doesn't match?

##It Doesn't Match Because the Line Breaks from the Template Literal Aren't Showing Up
Puzzles like this are part of the joy of testing, and programming in general. The question, subject, and answer are all strings. But we stored the question and the subject as strings in quotes. We stored the answer as a template literal in backticks because we wanted to have linebreaks in the answer. 

The linebreaks are stored in the template literal. But when the template literal is rendered in the web browser, they won't show up. The linebreaks also won't show up in the simulated web browser of the render function from the testing library. So the text content of the div doesn't exactly match the answer from the current card because the answer from the card has linebreaks and the text content of the div doesn't.

##Solution: Rewrite the Test for card.answer
Let's rewrite the test so it works. We obviously have the right content. And we're not going to somehow convince the render function to change the way it treats template literals with linebreaks. So we need to use a different assertion.

Change the assertion in the answer test from
```javascript
    //answer div should match the current answer
    expect(answer).toHaveTextContent(currentanswer);
```
To: 
```javascript
    //text content answer div should equal the current answer
    expect(answer.textContent).toEqual(currentanswer);
```
That did it! 

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

The lesson here is: when a test fails, it's not always because the component can't pass the test. Sometimes its because you need to change the test.

Great! Now we know that `CardContext` is working. `CardConsumer` is getting all the right answers.  

##Make CardContext Handle the 'next' Action

##Types.ts: Declare CardAction Type
>File: src/types.ts
>Will Match: [src/complete/types-3.ts](https://github.com/jacobwicks/flashcard/blob/master/src/complete/types-3.ts)

Go to types.ts. Declare an [enum](https://www.typescriptlang.org/docs/handbook/enums.html#string-enums) `CardActionTypes`. An enum is basically a list. When you write an enum, then say that an object type is equal to the enum, you know that the object type will be one of the items on the list.

`CardActionTypes` is a list of all the types of action that the `CardContext` `reducer` will handle. Right now it just has 'next,' but we'll add more later.

Also declare a TypeScript type called `CardAction`. This is the interface for the actions that `CardContext` will handle. Save types.ts. We will import `CardAction` into the `CardContext`. We will add more types of action to this type later.


```javascript
//the types of action that the reducer in CardContext will handle
export enum CardActionTypes {
    next = 'next',
};

export type CardAction =    
    //moves to the next card
    | { type: CardActionTypes.next }
```

##CardContext Test 8: Reducer Handles 'next' Action
>File: src/services/CardContext/index.test.tsx
>Will Match: [src/services/CardContext/complete/test-6.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/test-6.tsx)

Import `CardAction` into the `CardContext` test.
```javascript
import { CardAction, CardActionTypes, CardState } from '../../types';
```

Test `reducer` for handling an action with type 'next.' Name the test 'next increments current.' Put this test inside the describe block 'CardContext reducer.'

To test how the reducer handles actions, first create the action object with the type that you want to test. Then pass a state and the action to the `reducer`. You can assign the result to a variable, or just test the property that you are interested in directly. This test looks at the current property of the return value.

```javascript
    it('next increments current', () => {
        //declare CardAction with type of 'next'
        const nextAction: CardAction = { type: CardActionTypes.next };

        //pass initialState and nextAction to the reducer 
        expect(reducer(initialState, nextAction).current).toEqual(1);
    });
```
![Next fails to increment current](https://thepracticaldev.s3.amazonaws.com/i/irso5b0us9600jr1wudt.png)
Test fails.

##Be Aware of Your Assumptions
But wait! Do you see the assumption we are making in that test? We assume that `initialState` will have current === 0. What if it didn't? What if it somehow changed to 1, and what if case 'next' in the reducer switch didn't do anything? The test would still pass. We would think `next` worked when it didn't. We want our tests to give us confidence. How would you change the test to avoid this possibility?

Here's one way: use the spread operator to make a new object out of `initialState`, but overwrite the existing value of `current` with 0.

```javascript
    it('next increments current', () => {
        //declare CardAction with type of 'next'
        const nextAction: CardAction = { type: CardActionTypes.next };

        //create a new CardState with current === 0
        const zeroState = {
            ...initialState,
            current: 0
        };

        //pass initialState and nextAction to the reducer 
        expect(reducer(zeroState, nextAction).current).toEqual(1);
    });
```
##CardContext Test 9: Reducer Handles 'next' Action When Current !== 0
>File: src/services/CardContext/index.test.tsx
>Will Match: [src/services/CardContext/complete/test-6.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/test-6.tsx)

In addition to making sure that case 'next' works when the `current` index is 0, we should test to make sure that it doesn't return an invalid index when the index is the last valid index in the array `cards`. When the current index is the last valid index, the next index should be 0.

```javascript
    it('next action when curent is lastIndex of cards returns current === 0 ', () => {
        const nextAction: CardAction = { type: CardActionTypes.next };

        
        //get last valid index of cards
        const lastIndex = initialState.cards.length - 1;

        //create a CardState object where current is the last valid index of cards
        const lastState = {
            ...initialState,
            current: lastIndex
        };
        
        //pass lastState and nextAction to reducer
        expect(reducer(lastState, nextAction).current).toEqual(0);
    });
```

Ok. Now change the reducer to pass these tests. Think about how you would write the code inside the *next* case. Look at the tests. Does the structure of the tests give you any ideas?

##Pass CardContext Tests 8-9: Reducer Handles 'next' Action
>File: src/services/CardContext/index.tsx
>Will Match: [src/services/CardContext/complete/index-4.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/index-4.tsx)

To make the `reducer` work we are going to write the first case for the switch statement. Add the case 'next' to the switch statement in the `reducer`.

Use object destructuring to get `cards` and `current` out of the state object.

Declare const `total` equal to `cards.length -1`, which is the last valid index in `cards`.

Declare const `next`. If current + 1 is bigger than total, set `next` = 0.

Use the spread operator to create a new state object. Return all the same properties as the old state, but overwrite `current` with the value of `next`.

```javascript
switch(action.type) {
case 'next': {
            //get cards and the current index from state
            const { cards, current } = state;

            //total is the last valid index in cards
            const total = cards.length - 1;

            //if current + 1 is less than or equal to total, set next to total
            //else set next to 0
            const next = current + 1 <= total
                ? current + 1
                : 0;
            
            //return a new object created using spread operator
            //use all values from old state 
            //except overwrite old value of current with next
            return {
                ...state,
                current: next
            }
          }
//default case returns the previous state without changing it
        default: 
            return state
    };
```
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/9shnud5niha1bev8fyf6.png)
That passes the test.

##CardContext Test 10: Use CardConsumer to Test Dispatch of 'next' Action from Components
>File: src/services/CardContext/index.test.tsx
>Will Match: [src/services/CardContext/complete/test-7.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/test-7.tsx)

So now we are confident that the `reducer` works. `reducer` can handle `next` actions. But how can we test if dispatching a `next` action from a component will work? By using `CardConsumer`! We'll add a button to `CardCounsumer` that dispatches next when clicked. Then we'll click it and see if the value in the div that shows `current` changes. 

Let's write the test.

Import `fireEvent` from React Testing Library. We'll use `fireEvent` to click the `next` button we'll add to `CardConsumer`.
```javascript
import { render, cleanup, fireEvent } from '@testing-library/react';
```

Write the test for `CardConsumer`. We'll dispatch the `next` action the way a user would. By finding a button with the text 'Next' and clicking it.

Use the spread operator to create a `CardState` with current === 0.
Get a reference to the currentDiv. Expect it to start at 0, then after clicking the button, it should be 1.

```javascript
    //dispatching next from component increments value of current 
    it('dispatching next action from component increments value of current', () => {
        //create a new CardState with current === 0
        const zeroState = {
            ...initialState,
            current: 0
        };

        const { getByTestId, getByText } = renderProvider(zeroState);
        
        //get currentDiv with testId
        const currentDiv = getByTestId(/current/i);
        //textContent should be 0
        expect(currentDiv).toHaveTextContent('0');

        //get nextButton by text- users find buttons with text
        const nextButton = getByText(/next/i);
        //click the next button
        fireEvent.click(nextButton);

        expect(currentDiv).toHaveTextContent('1');
    });
```


![Test Fails because Next Button is not there](https://thepracticaldev.s3.amazonaws.com/i/68bzotvrw7fw0jvysuxh.png)

#Pass CardContext Test 10: Add 'Next' Button to CardConsumer 
>File: src/services/CardContext/index.test.tsx
>Will Match: [src/services/CardContext/complete/test-7.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/services/CardContext/complete/test-7.tsx)

Import the `Button` component from Semantic UI React. We could use a normal \< button \/>, but you should always make your tests as much like your app as possible. And in our app, we are using the \< Button \/> from Semantic UI React.

```javascript
import { Button } from 'semantic-ui-react';
```
In the `CardConsumer` component get dispatch from `useContext`.

```javascript
//and display them so we can test
const CardConsumer = () => {
    //get cards and the index of the current card
    //also get dispatch 
    const { cards, current, dispatch } = useContext(CardContext);
```

Add a `Button` to the return value of `CardConsumer`. Give the Button an `onClick` function that calls `dispatch` with an object `{type: 'next'}`. When you simulate a click on the button, the button will call the `dispatch` function of `CardContext` with a 'next' action. The `reducer` should handle it, and return a new state. When the new state shows up, `CardConsumer` should show the new value inside its 'current' div.

```javascript
    //display each property in a div
    return <div>
        <div data-testid='current'>{current}</div>
        <div data-testid='question'>{question}</div>
        <div data-testid='answer'>{answer}</div>
        <div data-testid='subject'>{subject}</div>
        <Button onClick={() => dispatch({type: CardActionTypes.next})}>Next</Button>
    </div>
```

![Next button passes](https://thepracticaldev.s3.amazonaws.com/i/irp654decmiy0v06qxvn.png)

That works! Are you feeling confident about adding `CardContext` to the `App`? You should be. You have written tests for all the parts that matter, and they all pass. Now we are ready to import the `CardProvider` into the `App` to make the `cards` available to `Answering`.

##Import CardProvider Into App
>File: src/App.tsx
>Will Match: [src/complete/app-3.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/complete/app-3.tsx)

We are going to add `CardProvider` to the `App` component. You will notice that this doesn't make any of your tests fail. The reason none of the tests fail is because adding `CardProvider` does not change what appears on the screen. `CardProvider` just makes the `CardContext` available to all the components inside of `CardProvider`, it doesn't make anything look different.

Change App.tsx to this:

```javascript
import React from 'react';
import './App.css';
import Answering from './scenes/Answering';
import { CardProvider } from './services/CardContext';

const App: React.FC = () => 
    <CardProvider>
      <Answering />
    </CardProvider>;

export default App;
```

To make the `CardState` in `CardContext` available to components, you have to "wrap" those components in the `CardProvider` component that is exported from `CardContext`. We are adding the `CardProvider` at the App, the highest level component. You do not have to add React `Providers` at the App level. You can import `Providers` in sub-components and wrap other sub-components there. But in this app it makes sense to wrap the components in the provider out here at the App level.

##Answering Test 1: Answering Shows the Question From the Current Card
>File: src/scenes/Answering/index.test.tsx
>Will Match: [src/scenes/Answering/test-8.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/scenes/Answering/complete/test-8.tsx)

If you are only running the tests for `CardContext`, switch to running all tests or the tests for `Answering`.

Import `CardState` from src/types.ts.
Import `CardProvider` and `initialState` from `CardContext`. 

```javascript
import { CardState } from '../../types';
import { CardProvider, initialState } from '../../services/CardContext';
```
Then write a helper function to render the `Answering` component wrapped in the `CardProvider`. Remember, any component that uses a `Context` has to be inside of the `Provider` for that `Context`.

```javascript
afterEach(cleanup);

const renderAnswering = (testState?: CardState) => {
    return render(
      <CardProvider testState={testState? testState : initialState}>
        <Answering />
      </CardProvider>
    );
  }
```

Change the 'has a question prompt' test from this:
```javascript
//test to see if the question prompt is in the document
it('has a question prompt', () => {
    //Use Object Destructuring to get getByTestId from the result of render
    const { getByTestId } = render(<Answering/>);

    //find question by searching for testId 'question'
    const question = getByTestId('question');

    //assert that question is in the document
    expect(question).toBeInTheDocument();
});
```

To this:
```javascript
//test to see if the question prompt is in the document
it('has the question prompt from the current card', () => {
    const { cards, current } = initialState;
    //get the question from current card 
    const currentQuestion = cards[current].question;

    //get getByTestId from the helper function
    const { getByTestId } = renderAnswering();
    
    const question = getByTestId('question');
    
    //question content should be the question from the current card
    expect(question).toHaveTextContent(currentQuestion);
});
```

Save the `Answering/test.index.tsx` file and run your tests. The 'has the question prompt from the current card' test you just changed will fail.

![Question display fails](https://thepracticaldev.s3.amazonaws.com/i/irvxpguzxf8pybyf1k2d.png)
Good job! Next we will make the Answering component actually show the question. 

##Pass Answering Test 1: Answering Shows the Question From the Current Card
>File: src/scenes/Answering/index.tsx
>Will Match: [src/scenes/Answering/index-6.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/scenes/Answering/complete/index-6.tsx)

Now that `Answering` is wrapped in the `CardProvider`, `Answering` can use `CardContext` to access the `cards` in `CardContext`. 

Import `useContext` from React:
```javascript
import React, { useContext } from 'react';
```
[useContext](https://reactjs.org/docs/hooks-reference.html#usecontext) is a method from the react library that lets you get values from a context. We will call `useContext` to get the array `cards` and the index of the `current` card from `CardContext`.

Import `CardContext` into `Answering`.
```javascript
//CardContext gives us access to the cards
import { CardContext } from '../../services/CardContext';
```
Call `useContext` to get `cards` and `current` from `CardContext`. Use object destructuring to get the question from the current card. Pass the question to the `Header` as the content prop.

```javascript
const Answering = () => {
    //get cards and current index from CardContext
    const { cards, current } = useContext(CardContext);

    //get the question from the current card
    const { question } = cards[current];

return (
    <Container data-testid='container' style={{position: 'absolute', left: 200}}>
         <Header data-testid='question' content={question}/>
         <Button>Skip</Button>
         <Form>
            <TextArea data-testid='textarea'/>
        </Form>
        <Button>Submit</Button>
    </Container>
    )}; 
```

That's it! Save it and run your tests.

![Snapshots failed](https://thepracticaldev.s3.amazonaws.com/i/8qt4d79xdfyj0f4n43bp.png)

Passed all tests, but the snapshots failed. Hit u to update the snapshots.

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

There we go! Remember, the snapshots failed because what shows up on the screen changed. Use npm start to run the app.

![The App- it's beautiful](https://thepracticaldev.s3.amazonaws.com/i/mgilrsn27des53e9fs9v.png)

Looking good!

##Make the Skip Button in Answering Work by Dispatching 'next' Action
One last thing. Now that we can see the `cards` in `Answering`, let's make the `Skip` Button cycle to the next one. We will use all the work we did making the `CardContext` reducer handle actions with a type `CardActionTypes.next`. 

We will make the `Skip` button dispatch an action with the type `CardActionTypes.next` to `CardContext`. When `CardContext` receives the action, it will run it through the `reducer`. The `reducer` will run the case 'next' that you wrote earlier. The code in the case 'next' will return a new state object with the `current` index set to the index of the next card in `cards`. 

##Decide What to Test
We should test what happens when the user clicks the `Skip` `Button`. The `current` index should change to the next card in `cards`. We can test for this by looking at the contents of the `question` `Header` and comparing it to the array `cards` from the `initialState` object.

##Answering Test 2: Skip Button Works
>File: src/scenes/Answering/index.test.tsx
>Will Match: [src/scenes/Answering/complete/test-9.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/scenes/Answering/complete/test-9.tsx)

Import fireEvent from React Testing Library so that we can simulate clicking the `Skip` button.
```javascript
import { render, cleanup, fireEvent } from '@testing-library/react';
```

Write the test for clicking the skip button.
```javascript
//test that skip button works
it('clicks the skip button and the next question appears', () => {
    //create a CardState with current set to 0
    const zeroState = {
        ...initialState,
        current: 0
    };

    //current starts out at 0
    const { getByTestId, getByText } = renderAnswering(zeroState);

    const question = getByTestId('question');
    //current starts out at 0, so question should be cards[0]
    expect(question).toHaveTextContent(initialState.cards[0].question);
  
    const skip = getByText(/skip/i);
    //this should change current index from 0 to 1
    fireEvent.click(skip);
  
    expect(question).toHaveTextContent(initialState.cards[1].question);
  });
```
![Clicking Skip Button Fails](https://thepracticaldev.s3.amazonaws.com/i/np88yr65ixy8cmctwyhb.png)

##Pass Answering Test 2: Skip Button Works
>File: src/scenes/Answering/index.tsx
>Will Match: [src/scenes/Answering/index-7.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/scenes/Answering/complete/index-7.tsx)

Import `CardActionTypes` so that we can make `Skip` dispatch a 'next' action. 
```javascript
//The types of action that CardContext can handle
import { CardActionTypes } from '../../types';
```

Get `dispatch` from `CardContext`.
```javascript
    //get cards, current index, and dispatch from CardContext
    const { cards, current, dispatch } = useContext(CardContext);
```

Pass an `onClick` function to the `Skip` button. Make it dispatch an action with type `CardActionTypes.next`. 
```javascript
    <Container data-testid='container' style={{position: 'absolute', left: 200}}>
         <Header data-testid='question' content={question}/>
         <Button onClick={() => dispatch({type: CardActionTypes.next})}>Skip</Button>
         <Form>
            <TextArea data-testid='textarea'/>
        </Form>
        <Button>Submit</Button>
    </Container>
```
That's it. Save it, and the test will pass!

####Next Post
In the next post we will make Answering show the user the answer from the card when the user clicks the 'Submit' button.