Day Log App in Node.js Part 1: Home page

This is the first part of a series of my attempt to implement my previous Laravel project “Day Log App” in Node.js. I made a post about customizing an Express site with EmbeddedJS and this is actually the prologue to this project. I will post the other parts within the following weeks as I successfully implement my personal feature goals for each article.

In the spirit of my original Laravel article each section follows the TDD/BDD development (functional tests in this case).

Table of Contents

Steps

Install dependencies

We will use the browser testing library zombie.js to test our application’s web pages’ behavior.

> npm install zombie --save-dev
> npm install expect.js --save-dev

First functional test case

Our test will visit http://localhost:3000/ and should expect the following page:

DayLogApp Node.js index page

Create the test folder. This is the default location where Mocha, the JavaScript testing framework Zombie is based on, will search for test files. Since we are interested in functional tests, create the folder functional inside it and index.test.js as our first test file.

'use strict';

process.env.NODE_ENV = 'test';

var expect = require('expect.js');
var Browser = require('zombie');
var browser = new Browser();

const BASE_URL = 'http://localhost:3000/';

describe('User visits home page', () => {
    before((done) => {
        browser.visit(BASE_URL, done);
    });

    it('should contain the jumbotron', () => {
        browser.assert.success();
        browser.assert.text('title', 'DayLogApp');
        expect(browser.assert.element('.jumbotron')).to.exist;
    });

    after((done) => {
        done();
    });
});

browser refers to the environment where Zombie will perform our tests given by the visit() method. This task is placed inside the before method (or setup) as recommended by the creator:

Use before blocks for navigation (browser.visit, clickLink, etc), it blocks for assertions.

browser.assert.success(); is added to make sure the page is loaded with status 200.

.jumbotron refers to the splash page element I decided to include. It is simply lifted from the Bootsrap 4 documentations.

Running mocha /test/functional/index.test.js should fail page we have not modified the .ejs view files.

Make the test pass

Update routes

The routes used in the application are declared in app.js as:

var indexRoutes = require('./routes/index.route');
...
app.use('/', indexRoutes);

Modify /routes/index.route.js with the following:

'use strict';

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'DayLogApp' });
});

module.exports = router;

Update views

First delete the file /views/layout.ejs as it has no use in this project.

Prepare the header and footer for the entire project:

  • /views/partials/header.ejs

    This project will just use Bootstrap 4 loaded online.

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta name="viewport" content="width=device-width, initial-scale=1">
    
            <title>DayLogApp</title>
    
            <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css">
        </head>
    
        <body>
            <nav class="navbar navbar-toggleable-md navbar-light bg-faded"
                style="margin-bottom: 2em">
                <div class="container col-sm-6">
                    <button class="navbar-toggler navbar-toggler-right" type="button"
                        data-toggle="collapse" data-target="#navbarSupportedContent"
                        aria-controls="navbarSupportedContent" aria-expanded="false"
                        aria-label="Toggle navigation">
                        <span class="navbar-toggler-icon"></span>
                    </button>
                    <a class="navbar-brand" href="#">DayLogApp</a>
                </div>
            </nav>
    
            <div class="row">
                <div class="container col-sm-6">
    
  • /views/partials/footer.ejs

                </div><!-- .container -->
            </div><!-- .row -->
    
            <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>
            <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>
        </body>
    </html>
    

Next is the splash page in /views/index.ejs

<% include partials/header %>

<div class="jumbotron">
    <h1 class="display-3">Day Log App</h1>
    <p class="lead">Manage your daily logs and their tasks.</p>
    <hr class="my-4">
    <p class="lead">
        <a class="btn btn-info btn-lg" href="#" role="button">See more</a>
    </p>
</div>

<% include partials/footer %>

Optional (but recommended) is the error page (/views/error.ejs) to display helpful information in case of trouble, especially during testing.

<% include partials/header %>

<h2>An error occurred.</h2>
<p><%= message %></p>
<p><%= error.status %></p>
<code><%= error.stack %></code>

<% include partials/footer %>

Run test

To confirm that our index page has been setup correctly, run the test:

> mocha /test/functional/index.test.js

and it should pass!

  User visits home page
    ✓ should contain the jumbotron

  1 passing (1s)

Timeout

In case the test fails with the following timeout message:

> Error: Timeout of <time> exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

add the a time parameter -t to the execution and try which value accommodates the timeout issue:

> mocha /test/functional/index.test.js -t 5000

References

Twitter, LinkedIn