Testing the login form

Now that we have the user creation flow tested, let's test if that user can log in.

Following the test file pattern we have been using, you need to create a file under test/session.js with the following content:

  1. First, import the missing dependencies:
    var assert  = require('assert'),
        Browser = require('zombie'),
        app     = require('../app'),
        couchdb = require('../lib/couchdb'),
        dbName  = 'users',
        db      = couchdb.use(dbName),
        fixtures = require('./fixtures');
    
    describe('Session', function() {
    
      before(function(done) {
        app.start(3000, done);
      });
    
      after(function(done) {
        app.server.close(done);
      });

    That concludes the opening ceremonies!

  2. Now we are ready to start describing the login form:
      describe('Log in form', function() {
    
        before(function(done) {
          db.get(fixtures.user.email, function(err, doc) {
            if (err && err.status_code === 404) {
              return db.insert(fixtures.user, fixtures.user.email, done);
            }
            if (err) throw err;
            done();
          });
        });

    This before hook creates the test user document if one doesn't exist (instead of removing if it existed).

  3. Next, we will test whether the login form loads and contains the relevant elements:
        
        it('should load', function(done) {
          Browser.visit("http://localhost:3000/session/new",
            function(err, browser) {
              if (err) throw err;
              assert.ok(browser.success, 'page loaded');
              assert.equal(browser.text('h1'), 'Log in');
              
              var form = browser.query('form');
              
              assert(form, 'form exists');
              assert.equal(form.method, 'POST', 'uses POST method');
              assert.equal(form.action, '/session', 'posts to /session');
    
              assert(browser.query('input[type=email]#email', form),
                'has email input');
              assert(browser.query('input[type=password]#password', form),
                'has password input');
              assert(browser.query('input[type=submit]', form),
                'has submit button');
    
              done();
            });
        });

    The only difference here from the user code is that the heading string should be Log in instead of New User. This happens because we have such a minimal user creation form, which suits us for the time being.

  4. Next we are testing to see whether the login form actually works:
        it("should allow you to log in", function(done) {
    
          Browser.visit("http://localhost:3000/session/new",
            function(err, browser) {
              if (err) throw err;
    
              browser
                .fill('E-mail', fixtures.user.email)
                .fill('Password', fixtures.user.password)
                .pressButton('Log In', function(err) {
                  if (err) throw err;
    
                  assert.equal(browser.location.pathname, '/todos',
                    'should be redirected to /todos');
                  done();
                });
    
            });
        });
    
      });
    });

    Here we're loading and filling in the e-mail and password fields and clicking on the Log In button. When clicking on the button, the login form is posted, the session is initiated, and the user is redirected to the to-do items page.

  5. Now run this test file from the command line:
    $ ./node_modules/.bin/mocha test/session.js
      ․․
    
      ✔ 2 tests complete (750ms)
  6. This test includes the case for when the user enters the right username and password, but what happens when that's not the case? Let's create a test case for it:
    it("should not allow you to log in with wrong password", function(done) {
    
      Browser.visit("http://localhost:3000/session/new",
        function(err, browser) {
          if (err) throw err;
    
          browser
            .fill('E-mail', fixtures.user.email)
            .fill('Password', fixtures.user.password +
              'thisisnotmypassword')
            .pressButton('Log In', function(err) {
              assert(err, 'expected an error');
              assert.equal(browser.statusCode, 403, 
                'replied with 403 status code');
              assert.equal(browser.location.pathname, '/session');
              assert.equal(browser.text('#messages .alert .message'),
                'Invalid password');
              done();
            });
        }
      );
    });

    Here we're loading and filling the login form, but this time we're providing a wrong password. After clicking on the Log In button, the server should return 403 status code, which will trigger an error passed in to our callback. Then we need to check the return status code by inspecting the browser.statusCode attribute, making sure it's the expected 403 forbidden code. Then we also verify that the user did not get redirected to the /todo URL and that the response document contains an alert message saying Invalid password.