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.

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

Development Process

In this tutorial we will develop a flashcard app using both Agile Development and Test Driven Development. Agile Development is a way of thinking about and organizing software features. 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.

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.

Setup: The Easy Way

Clone the git repo 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

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.

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:

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:



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

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.

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:



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:



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 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:



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

to this:



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:



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.

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:



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

to this:



< 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.'

Now the test passes again!



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.

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 is a programming language that runs in the web browser.

TypeScript

TypeScript 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 is a library that makes it easier to build user interfaces with JavaScript.

Semantic UI React

Semantic UI React is a library of components. They look nice and have an easy to use interface.

The Semantic UI React components

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: A component to keep other components organized.

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: Makes the text content larger and easier to see. We will use this to show the question to the user.

Icon: A little picture. Semantic UI React has a built in selection of icons.

Input: A place where the user can type information.

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: Shows information when the user hovers the mouse over a component.

SideBar: Shows components on the side of a page. We'll put our Selector in a SideBar.

TextArea: 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: Animates showing and hiding. We'll put the card answers inside a Transition so they animate when they appear.

Divs

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 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 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 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.