Node.js testing

  • Use mocha for writing tests.
  • Use chai for assertions.
  • Use timekeeper for mocking or freezing time.
  • Use [chai-as-promised])(https://github.com/domenic/chai-as-promised) for testing promise rejection/resolve. See server/src/user/spec/user.spec.js for examples.
  • Use chai-change for expectation blocks.
  • Use local variables to mimic RSpec’s let functionality:
    describe('example test', () => {
    let user
    
    beforeEach(async () => {
      user = await models.User.findOne()
    })
    
    it('user has name', () => {
      return expect(user.name).to.eql('John')
    })
    })
    

Unit tests

  • Place unit tests in spec folder which exists in the same folder as the code. e.g. user/interactors/Create.js spec should be found at user/interactors/spec/Create.spec.js.

Feature tests

  • Place feature tests in test/features directory.
  • Use Puppeteer for interaction with a browser. This has several benefits:
    • Tests are faster compared to Selenium WebDriver or WebDrive.IO.
    • Easy to run tests in headless mode.
    • Brings it’s own chromium browser, so no more issues with chromedriver and chrome browser versions mismatch.
  • Add await before each expectation when a test has multiple assertions.
  • However Puppeteer has very low-level API, so few helpers are needed to reduce tests verbosity. You can find them (or add your own) in tests/helpers folder.
  • Each feature test starts with feature directive instead of regular describe. Make sure to use feature only at the top. If you need to nest feature tests, use describe:
    feature('logging in', () => {
    describe('with correct login details', () => {
      it('logins user', async () => {
        await page.goto('http://localhost:3000/login', { waitUntil: 'networkidle' })
    
        await page.typeText('input[name=username]', 'admin')
        await page.typeText('input[name=password]', 'secret123')
        await page.clickOn('#signin')
        await page.waitForNetworkIdle()
    
        expect(await page.plainText()).to.include('admin')
      })
    })
    })