Introduction, Setup, and Overview
Tags: react, typescript, testing, tutorial
Published: 2020-01-17 04:38:31

This tutorial will show you how to use Test Driven Development and some concepts from Agile development to make a flashcard app using React and TypeScript. This tutorial may take you 5-10 hours, depending on your experience level and how many of the external links you decide to read through. Each entry will take 10-30 minutes to read. You will also spend some time writing or copying the code, saving the files, running the tests and observing the results of the tests.

###You can click this link to CodeSandbox to see the app running along with all the code: [Flashcard App running on CodeSandbox](https://codesandbox.io/s/github/jacobwicks/flashcard/tree/complete).

###Here's the Github repository: [Flashcard App repository on Github](https://github.com/jacobwicks/flashcard).

##Why Make a Flashcard App?
I just took an online data structures class. Writing my own questions and the answers to them is a good way for me to review the contents of a course. I was inspired by all the examples of data structures being used to model real life objects so I decided to write a flashcard program to help me review the data structures course material. 
 
In this tutorial I use the Agile development process, React and Typescript to create the app. I chose to use them because they allow for quick and effective development of applications. I am also using this as an opportunity to learn React Testing Library and the process of Test Driven Development.

In each post I explain what we are doing as well as the reasoning behind the decisions that I made. I give in depth explanations of the important methods and concepts that we use. 

##What the App Will Do
This app will model a deck of flashcards. A flashcard is an index card with a question written on one side and an answer written on the other side. Flashcards are used for studying. You make the cards, then shuffle them and look at the questions. You answer the question, then flip the card over and compare the answer on the card with the answer that you gave.

The user will be able to 
* create new cards by entering a subject, a prompt and an answer
* edit existing cards
* delete cards
* view cards by subject
* store and retrieve cards from the browser's localStorage
* export and import cards as .json files (this will be added in a future tutorial)
* view a card's question prompt 
* type their answer
* view the card's answer
* record if they got the question right or wrong
* skip the question rather than answer it
* keep statistics for each question- how many times asked, how many times skipped, how many times answered correctly / incorrectly
* view the statistics

##What we will use to make it
* [Agile development](https://en.wikipedia.org/wiki/Agile_software_development)
* [Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
* [TypeScript](https://www.typescriptlang.org/)
* [React](https://www.reactjs.org)
* [React Hooks](https://reactjs.org/docs/hooks-intro.html)
* [React Context](https://reactjs.org/docs/context.html)
* [Test Driven Development](https://en.wikipedia.org/wiki/Test-driven_development)
* [Jest](https://jestjs.io/en/)
* [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)
* [Semantic UI React](https://react.semantic-ui.com/)

##Development Process
In this tutorial we will develop a flashcard app using both Agile Development and Test Driven Development. [Agile Development](https://en.wikipedia.org/wiki/Agile_software_development) is a way of thinking about and organizing software features. [Test Driven Development](https://en.wikipedia.org/wiki/Test-driven_development) is figuring out what to test and writing the tests before writing code to pass the tests. Test Driven Development is usually abbreviated as TDD. 

TDD is also called the 'red, green, refactor' cycle. It is called 'red, green, refactor' because failing tests are red and passing tests are green. You write the tests first so they start out failing, then you write the component and the tests turn green. Once the tests are green you can refactor your code. 

Refactoring means rewriting and improving code. You know that your code will still work after refactoring because you are testing it.

#Setup
There are two ways you can get started on this project. The easy way is to clone the Git repo. The less easy way is to use create-react-app to set up a new react app, then install the support libraries.

##Install Node.js
If you don't already have it, install [Node.js](https://nodejs.org/en/download/).

##Install a Code Editor
You'll need some way to edit the code files. You can use any text editor, but software made for editing code has useful features like syntax highlighting. I use [Visual Studio Code](https://code.visualstudio.com/download).

##Setup: The Easy Way
* Clone the [git repo](https://github.com/jacobwicks/flashcard) and install the libraries, either using npm install or some other package manager

Cloning the repository is the easy way to get started. Each folder in the repo includes a subfolder named 'complete' that contains versions of the files from start to finish. However, the index.tsx and index.test.tsx files have been left out so that you can fill them in as you follow along with the tutorial.

##How to Clone a Git Repository
###1. Install git
[Download Git here](https://git-scm.com/downloads)

###2. Clone
Using a command prompt, go to the folder where you want to create the flashcard app and run this command:
```
git clone https://github.com/jacobwicks/flashcard.git
```

###3. Install node modules
Using a command prompt, navigate to the flashcard folder. Run the `npm install` command.
```
flashcard> npm install
```

That's it! Once npm install runs successfully you have set up the app and are ready to get started. We'll take a quick look at some of the code, then I'll tell you about what the structure of the app will be, and how we'll make it.

##Where Are All the Files? I Don't Want to Have to Write Them Myself!
The main branch of this repo has had the index files and tests taken out so that you can build it yourself. If you want to see the final version of all the files, switch to the branch named 'complete'. You can switch to the branch named 'complete' by running this command:
```
git checkout -b complete origin/complete
```

And you can switch back by running this command:
```
git checkout master
```

##What's the Less Easy Way?
The less easy way is to use create-react-app to install a blank React project and then install the support libraries yourself. Instructions on how to set it up the less easy way [can be found here](https://dev.to/jacobwicks/setup-flashcard-app-the-hard-way-24pd).

##Each Step Has Links to Complete Files
When I was starting out I always found it really helpful to have an example of how the code *should* look that I could check my work against. So the git repo includes a version of each file that shows how it will look after you complete each step. Each folder has a subfolder called `complete` in it. In the `complete` folder are copies of each version of the tests and the file to show how they should look at each step from start to finish.

Whenever you see this:
>File: src/components/NavBar/index.tsx
>Will Match: [src/components/NavBar/complete/index-4.tsx](https://github.com/jacobwicks/flashcard/blob/master/src/components/NavBar/complete/index-4.tsx)

It means: in this step you are working on the `index.tsx` file found in the `src/components/NavBar` folder. When you are done with this step, your `NavBar/index.tsx` should match the file `index-4.tsx` in the `NavBar/complete/` folder. `index-4.tsx` is the fourth version of `index.tsx` that we have made.

##Run the Default App
Now that you have the app set up, you have some code that you can look at and run. This project was started with create-react-app. Create-react-app automatically sets up a lot of the stuff that is needed to make a React app work. The main app file is `src/App.tsx`.

The code for the default React app is: 

```javascript
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;
```

You can run the default app. Open a command prompt. Go to the folder where you installed the project. Type `npm start` and hit enter. The app will start to run.

```
flashcard>npm start
```

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

Running the app should make a new web browser tab open. If it doesn't open, you can access it by opening a browser tab and type `http://localhost:3000/` in the address bar.

![Default App](https://thepracticaldev.s3.amazonaws.com/i/dhput1lz73kcph1u4sp4.png)

The default app displays some text, a link, and a rotating logo graphic.

##Run the Default Test
Create-react-app automatically sets up a test for the main app file. The main app test file is `src/App.test.tsx`. We'll take a quick look at the default test here. I'll explain what all the parts of tests do in the next post, where we build the first custom component of the app. This is just a quick introduction.

The default test is ready to run. Open a command prompt. Go to the folder where you installed the project. Type `npm test` and hit enter. The test will run.

```
flashcard>npm test
```

When you run the npm test command, the default test will run. It will look like this:
![Default Test](https://thepracticaldev.s3.amazonaws.com/i/zd51mmrf12ko4zifz77n.png)

#What is a Test, Anyway?
A test is code that lets you look at and talk about other code. You run the code you want to test, and use the tools that the testing software gives you to make statements about what results you expect to get. The testing library tells you if you got the result you expected or not. We'll be writing a lot of tests. 

The code for the default test 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();
});
```

The default test finds the link that says 'Learn React.' You've seen the app. You saw the result of the app getting rendered on the screen by the web browser. You saw the link that says 'Learn React,' so you know it's there. But the test doesn't look at what the app looks like on the screen. So how can the test know if there's a link that says 'Learn React?' 

The test uses the render function from React Testing Library to simulate rendering the app. The render function turns the app into this code:

![The Test Render](https://thepracticaldev.s3.amazonaws.com/i/aus60965zju7n9qsg3ee.png)

The rest of the test looks through that code. Do you see where it says 'Learn React' in the code? When you read through that code and find where it says 'Learn React,' you are basically doing the same thing that the test does. When the test runs and the result matches the statement about what results you expected, the test passes. If the result doesn't match, then the test fails. Simple as that.

You'll see a detailed explanation of all the parts of tests in the next post, as well as the rest of the tutorial. After we try changing the default test to fail and changing the app to pass the changed test, the rest of this post will give you an overview of the development process and the structure of the app. 

##Change the Default Test so It Fails
This test passes. That's because the app does what the test expects. But if we change what the test looks for to something that isn't on the screen, the test will fail. Let's give that a try. Change the text that the test is looking for from 'learn react' to 'learn tdd'. The app doesn't render any text that says 'Learn TDD', so the test will fail.

In the file `src/App.test.tsx` Change this:
```javascript
test('renders learn react link', () => {
  const { getByText } = render(<App />);
  const linkElement = getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});
```

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

Now save it. What happens? The test fails! Here's what you'll see at first when a test fails: 
![Failed Default Test Bottom of Screen](https://thepracticaldev.s3.amazonaws.com/i/d8plzxdhy5hk07ocmp0t.png)

Scroll up and you'll see that Jest tells you which test failed, and prints out the code that it rendered and searched through. Here's a screenshot of what it looks like when you scroll to the top of the display for a failed test.

![Failed Default Test Top of Screen](https://thepracticaldev.s3.amazonaws.com/i/l6nlfg5ivyzlj4q180wp.png)

##Change the Default App to Pass the Test 
The test failed because the app prints 'Learn React' and not 'Learn TDD,' but the test is looking for 'Learn TDD.' To make the app component pass the test, you can change the text that it puts on the screen from 'Learn React' to 'Learn TDD.'

In the file `src/App.tsx` change this: 

```javascript
 <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
```

to this:

```javascript
 <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn TDD
        </a>
```

Save the app file. The text of the link has changed to 'Learn TDD.'
 
![Learn TDD](https://thepracticaldev.s3.amazonaws.com/i/qb6ht304bl12k4jbqf3d.png)

Now the test passes again!
![Default Test Passes Again](https://thepracticaldev.s3.amazonaws.com/i/dbjsu8z4cxqbib0dlcp7.png)

##Agile Development
Teaching Agile Development is outside the scope of this tutorial. But I will be talking about some concepts from Agile Development in the tutorial. One of the basic concepts of Agile Development is that you write "user stories." A user story is a short description of things users will be able to do with the application. 

##An Example of a User Story: 
"The user sees a question displayed on the screen. The user writes an answer to the question. When the user is done with their answer, they click the submit button. The app shows them the answer key. The user compares their answer to the answer key. The user decides they got the question right, and clicks the 'right answer' button. Then the user sees the next question."

##What Do You Do With User Stories?
You use the stories to figure out what features you need to make in order for the user story to be possible. You then assign difficulty estimates to the features and divide them up into groups of stories, or 'sprints'. Stories, estimates, and sprints give you a basis for estimating how long developing an app will take. We won't assign difficulty, time estimates, or make sprints in this tutorial. But we are going to use user stories.

Every time we make a component we are going to look back at the user stories. We will figure out what features we need to make. Then we will choose what types of components we are going to use to make those features work. Then we'll figure out what we need to test and write the tests. After we write a test, we'll write enough code to pass the test. When we can pass all the tests we wrote the component is done. You will see this process repeated throughout the tutorial. This process is test driven development.

##User Stories for the Flashcard App
* The user sees a question displayed on the screen. The user writes an answer to the question. When the user is done with their answer, they click the submit button. The app shows them the answer key. The user compares their answer to the answer key. The user decides they got the question right, and clicks the 'right answer' button. Then the user sees the next question.

* The user thinks of a new card. The user opens the card editor. The user clicks the button to make a new card. The user writes in the card subject, question, and an answer to the question. The user saves their new card.

* The user loads the app. The user sees a list of the cards they have written. The user selects the subject that they want to study. The program displays the cards in that subject in random order.

* The user sees a card. They hover their mouse over an icon and a popup appears. The popup shows the user how many times they have seen the card, and how many times they have gotten the answer right or wrong.

* The user sees a card and wants to change the answer. The user opens the card editor. The user selects the card that they want to change. The user changes that card and saves their changes.

* The user deletes a card.

We'll refer back to these user stories throughout the tutorial. We will look at the user story we are working on and figure out what features we need to implement to make it work. We can also use the user stories to help us figure out what kind of components we should use.

#Turning User Stories into Features
Getting a list of features from a user story is an important part of Agile Development. A feature is something that the app does. The user story shows why the app should have the feature. The user story shows what the feature actually lets the user do with the app.

##Why Get Features from User Stories?
It is a very helpful way to organize your development. It will stop you from taking time to write something without a reason why you are writing it. Every time you write a feature, you will be able to say "I am writing this feature because the app needs to do it so that this user story can happen."

##How to Get Features from User Stories
Read the user story. Then read through each part of it. Think about what the user is doing in the story. Think about how the app would look when they are doing what the story is talking about. Make a list of what the app needs to do so that the user can do what they do in the story. This is a process that will get easier the more you do it. It's not something you have to do perfectly. So have fun with it!

##Example of Getting Features from a User Story
Let's look at the first sentence of the first user story:

* The user sees a question displayed on the screen. 

What features does the app need to make this possible? 
* Store cards
* Load cards
* Show the question from a card

Second sentence:
* The user writes an answer to the question. 

Feature:
* Space to write an answer

Third and fourth sentences:
* When the user is done with their answer, they click the submit button. The app shows them the answer key.

Features:
* A submit button
* Track when to show the answer and when to hide it
* Show the answer from a card

That's how we'll be turning our user stories into a list of features that our app needs to have.

Here's a screenshot of the final version of the app running.

![Done](https://thepracticaldev.s3.amazonaws.com/i/um9v1gx0b1to8n43ra1z.png)

This app will model a deck of flashcards. We'll use TypeScript to describe a type for the card object. We'll keep the cards in an array. We'll track the user's right and wrong answers for each card. We will track the right and wrong answers using an object. We'll use React Context to track the cards and make them available to components. We'll use React Context to track the stats and make them available to components. We'll use components from Semantic UI React to show the cards to the user.

##Overview of the Major Parts of the App
* Answering: A page that shows a single card to the user. The user sees the question, answers the question, and records if they got their answer right or wrong 
* CardContext: Stores the array of flashcards. Handles changes to the cards and tracks what card the user is looking at
* StatsContext: tracks the stats for each card
* Stats: shows the user their stats for a card
* Writing: A page where the user can create a new card, change an existing card, and delete cards
* NavBar: lets the user choose between the Answering and Writing components 
* Save: saves the cards and stats in between sessions, loads them back into the Contexts
* Selector: lets the user select a single question and choose what subjects to look at

##The libraries we will use to build the app

###JavaScript
[JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript) is a programming language that runs in the web browser.

###TypeScript
[TypeScript](https://www.typescriptlang.org/) is a language that compiles to JavaScript. TypeScript lets you write JavaScript with types. This is useful because the compiler will tell you if you are trying to do something that won't work because you have the wrong type of data.

###React 
[React](https://reactjs.org/) is a library that makes it easier to build user interfaces with JavaScript.

###Semantic UI React
[Semantic UI React](react.semantic-ui.com) is a library of components. They look nice and have an easy to use interface.

###The Semantic UI React components
[Button](https://react.semantic-ui.com/elements/button/): A button. You click it and it makes things happen. We will use Buttons to let the user skip to the next question, submit their answer, and mark their answer right or wrong.
[Container](https://react.semantic-ui.com/elements/container/): A component to keep other components organized.
[Form](https://react.semantic-ui.com/collections/form/): Keeps input fields together. When a form is 'submitted' it fires an event that lets you collect the values of the input fields.
[Header](https://react.semantic-ui.com/elements/header/): Makes the text content larger and easier to see. We will use this to show the question to the user.
[Icon](https://react.semantic-ui.com/elements/icon/): A little picture. Semantic UI React has a built in selection of icons.
[Input](https://react.semantic-ui.com/elements/input/): A place where the user can type information.
[Menu](https://react.semantic-ui.com/collections/menu/): Displays a set of 'Menu Items.' We'll use the menu to let the user choose between the Answering component and the Writing component. 
[Popup](https://react.semantic-ui.com/modules/popup/): Shows information when the user hovers the mouse over a component.
[SideBar](https://react.semantic-ui.com/modules/sidebar/): Shows components on the side of a page. We'll put our Selector in a SideBar.
[TextArea](https://react.semantic-ui.com/addons/text-area/): A large area that the user can type their answer in. The Semantic UI React TextArea has to be wrapped in (be inside) a Form component or it won't look right.
[Transition](https://react.semantic-ui.com/modules/transition/): Animates showing and hiding. We'll put the card answers inside a Transition so they animate when they appear.

###Divs
[Div](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div): In addition to the Semantic UI React components, we'll also use divs. A div is a basic component that is used to build webpages. It doesn't look like anything on its own, but it can contain text and other components. It can also be styled using CSS.

###CSS
[CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) stands for Cascading Style Sheets. CSS is not a JavaScript library, but we do use it to write some code in this project. CSS lets you tell the browser how your components should look. Mostly we will use it to put components in the right place on the page.

###Jest 
[Jest](https://jestjs.io/) is a testing framework. It is a program that finds and runs the test files that you write. It tells you if your code passed the tests that you wrote or not.

###React Testing Library
[React Testing Library](https://testing-library.com/docs/react-testing-library/intro) helps you test UI components made with React.

###Next Post
The next post will show you how to design a component and write tests. We will start by making the Answering component, where the user will see questions and answer them.