Create a Task Manager with Test Driven Development Part 1 — The Setup

Peter Nguyen
5 min readJun 2, 2019

--

For over a year, I have been learning how to code. My interest started from wanting to build some kind of smart aquaponics system. From there I explored a bunch of resources, guides, and courses. I started with freecodecamp, did CS50, detoured to python and machine learning, and even Unity/C# and game development. During that time, I did actually build an arduino powered fish feeder. Now I find myself back in the web development space and working to build out some projects for my portfolio. The first will be a task manager using node/express/mongo on the backend and I’m thinking of building both a vuejs and react frontend for practice.

Backend Source
Frontend Source

Table of Contents

  1. The Setup
  2. Adding the User
  3. Read, Update, Delete Users
  4. Tasks
  5. Frontend Beginnings

The challenge will be to make this a TDD project. So let’s start with some basic user stories.

  1. Users can create, read, update, and delete tasks
  2. Users can create projects / categories to house tasks (like Asana boards)
  3. Users can create larger projects that also house smaller projects or tasks (this is a feature that I wanted in Asana)
  4. Users can switch between board view and list view easily (another feature I wanted in Asana)
  5. Non-logged in users can immediately start creating tasks but to save their data to a db, they must log in

So basically, I’m going to try to make an Asana like task manager with some additional features added in. Next, let’s just set up our basic express app.

git init
npm init -y //configures npm with default configs
npm i express

Okay so to start a basic express app, I created an index.js file within my a src folder.

const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
app.listen(3000, () => {
console.log(`Server is up on port 3000`);
});

Let’s install some more modules.

npm i env-cmd nodemon jest supertest --save-dev

env-cmd will let us configure our own environment variables for our local setup so we don’t have to hardcode any values and nodemon will auto restart our app whenever we make any file changes.

First let’s create dev.env file in our root directory. Inside just write

PORT=3000

Then in our package.json file in scripts, we’re going to add

“dev”: “env-cmd -f ./dev.env nodemon src/index.js”,

The -f flag lets env-cmd know that we’re not using the default file name/location for env variables.

Here you can see what my package.json file looks like as well as my folder structure

And then finally in our index.js file we refactor our code to

const express = require('express');
const app = express();
const port = process.env.PORT;
app.get('/', (req, res) => {
res.send('Hello World');
});
app.listen(port, () => {
console.log(`Server is up on port ${port}`);
});

From the terminal, if we run npm run dev. Everything should still work.

Now we’re ready to setup our testing environment. For this, were going to use jest and supertest.

First create a new test.env file in the root and also write PORT=3000. We don’t really need a separate file now because obviously is exactly the same as the dev.env, but we’re going to want to have separate env variables for our test environment when we start using mongodb. This is because we don’t want our test environment db to affect our dev environment db.

Next create a test folder in your root directory and in there let’s create a file called user.test.js. The .test.js extension is important for jest to recognize which are test files. And in here we’re going to put all of our tests related to users. We’re going to need to import our express app into our tests so we have to do a bit of refactoring. In index.js our app is created and we then listen to the port. We actually want to separate these two actions because supertest can start the server on its own.

So let’s create an app.js file in the src directory and take move the following code.

const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
module.exports = app;

I’ve added the line at the bottom so we can export it. Back in index.js we need to now import the app so it should look like.

const app = require('./app');
const port = process.env.PORT;
app.listen(port, () => {
console.log(`Server is up on port ${port}`);
});

Now back in our user.test.js file we can import the express app and create our first test.

const request = require('supertest');
const app = require('../src/app');
test('Should create server and connect successfully at root', async () => {
await request(app)
.get('/')
.send()
.expect(200);
});

So what this test is doing is sending a get request to the root of the app and it expects to get a response back with the status 200 to make sure everything is okay. Now it’s important that we use async await here because if we don’t tell jest that this is an async function, then it will complete the test before we ever get a response and since no error was thrown it will assume it was correct.

To run the test, we have to go back to our package.json file and under scripts edit test with the following

"test": "env-cmd -f ./test.env jest --watch --runInBand"

The watch flag allows jest to autorestart every time we save like nodemon and the runInBand flag tells jest to run our test files one after another. This is more for prepping for the future. When we start creating tests for our tasks and they start interacting with our database, jest usually runs these asynchronously so they could inadvertently change the database and mess up our tests. So we should tell jest not to do that and run one test file after another so that we make sure our database is what it should be.

So to run our tests, just type npm test from our terminal and hopefully you get the following!

So I think that’s good enough to stop for now. Let’s get ready to commit our changes making sure to ignore our env files and the node_modules folder. So add .gitignore to your root and put

node_modules/
dev.env
test.env

If you have any questions, let me know and I’ll try to google the answers. If you want to fork my code, the github for this project is (https://github.com/iampeternguyen/task-manager-api)

--

--

Peter Nguyen

Founder of thelabvungtau.com, educator, passionate about social justice, code/tech enthusiast, and occasional ukulele player.