Testing

Questions

  • How should software components be tested?
  • What tools can I use to test JavaScript programs?
  • How can I make software easier to test?
  • How can testing code drive a web server?
  • How can tests check the content of HTML pages?
  • How is HTML represented in a JavaScript program?

Unit Testing

Introducing Mocha

describe('first test', () => {
  it('should run without errors', (done) => {
    done()
  })
})
  first test
    ✓ should run without errors


  1 passing (12ms)
{
  
  "scripts": {
    
    "test": "mocha",
    
  }
}
npm test -- path/to/test.js

Refactoring

const server = require('./server')
const PORT = 3418
server.listen(PORT, () => { console.log(`listening on port ${PORT}...`) })
const express = require('express')

// Main server object.
let app = express()

// Root page.
app.get('/', (req, res, next) => {
  res.status(200).send('<html><body><h1>Home</h1></body></html>')
})



module.exports = app

Testing the Server

const assert = require('assert')
const request = require('supertest')
const server = require('./server')

describe('server', () => {

  it('should return HTML with expected title', (done) => {
    request(server)
      .get('/')
      .expect('Content-Type', /html/)
      .expect(200)
      .end((err, res) => {
        assert(res.text.includes('Home'), 'Has expected title')
        assert(!res.text.includes('Should not contain this'), 'Has unexpected text')
        done()
      })
  })
})
  server
    ✓ should return HTML with expected title (48ms)


  1 passing (58ms)
describe('server', () => {

  it('should return HTML with expected title', (done) => {
    
  })

  it('should return asteroids page as HTML with expected title', (done) => {
    request(server)
      .get('/asteroids')
      .expect('Content-Type', /html/)
      .expect(200)
      .end((err, res) => {
        assert(res.text.includes('Asteroids'), 'Has expected title')
        done()
      })
  })

  it('should 404 for other pages', (done) => {
    request(server)
      .get('/other')
      .expect(404)
      .end((err, res) => {
        assert(res.text.includes('ERROR'), 'Has expected error message')
        done()
      })
  })
})
  server
    ✓ should return HTML with expected title (42ms)
    ✓ should return asteroids page as HTML with expected title
    ✓ should 404 for other pages


  3 passing (62ms)

Regular Expressions

A regular expression is a pattern for matching text which is itself written as text. Alphanumeric characters match themselves, so the regexp /abc/ matches the strings "abc" and "some abc here", but not the string "no a-b-c here". Most punctuation characters have special meaning: the character ., for example, matches any single character, while + means “one or more”, so /a.+c/ matches an ‘a’ followed by one or more characters followed by a ‘c’. Regular expressions are widely used in JavaScript, but are outside the scope of this tutorial.

Checking the HTML

const assert = require('assert')
const request = require('supertest')
const cheerio = require('cheerio')
const server = require('./server')

describe('server', () => {
  it('should have the correct headings', (done) => {
    request(server)
      .get('/')
      .expect('Content-Type', /html/)
      .expect(200)
      .end((err, res) => {
        const tree = cheerio.load(res.text)
        assert.equal(tree('h1').length, 1, 'Correct number of headings')
        assert.equal(tree('h1').text(), 'Home', 'Correct heading text')
        done()
      })
  })
})
  server
    ✓ should have the correct headings (67ms)


  1 passing (77ms)

JSX vs. DOM

  • JSX is an extension to JavaScript that allows us to embed HTML in programs
    • That HTML is translated into function calls that create text
  • DOM is a data structure that a browser uses to store pages in memory
    • Parses HTML to create a tree of nodes that are either elements with children and attributes or plain old text
    • Or other things that we won’t get into

Challenges

Not Done

What happens if we forget to call done() in a test?

Adding Tests

  1. What is the most useful test you could add for the asteroids application? Why?
  2. Implement it.
  3. Ask yourself why tutorials like this one don’t say “please implement it”. Reflect on the fact that this question didn’t say “please” either. Are you comfortable with the paternalistic power relationship embodied in the absence of that one little word, and with the somewhat uncomfortable attempt at ironic humor embodied in this question?

Lifecycle

Suppose a JavaScript program contains some JSX expressions that produce HTML which is then read and displayed by a browser. Draw a diagram to show the form taken by an H1 heading containing the word “data” from start to finish.

Key Points

  • A unit test checks the behavior of one software component in isolation.
  • The result of a unit test can be pass, fail, or error.
  • Use Mocha to write and run unit tests in JavaScript.
  • Put assertions in unit tests to check results.
  • Combine tests in suites for easier management.
  • Divide modules into interactive and non-interactive parts for easier testing.
  • Use supertest to simulate interaction with a server for testing.
  • HTML is represented in memory using the Document Object Model (DOM).
  • Check the structure of the DOM rather than the textual representation of the HTML when testing.