loading...
Cover image for Writing tests

Writing tests

iamvarandas profile image ๐ŸŒˆ Andrรฉ Varandas ๐ŸŒˆ ใƒป4 min read

Repository for this part is available on git branch writing-tests

GitHub logo AndreVarandas / mood-sentences

โœจ Mood sentences

Writing tests

Our simple package is almost ready. We only need to add some tests. As the package is small, it should be pretty straight forward.

Let's start by creating a special folder under src named __tests__. Then add a new file and name it index.test.js.

In this file, we will write our tests. These will be automatically picked up by jest thanks to the configuration we added earlier to the jestconfig.json file.

As we are going to use special variables, in order to stop our linter from complaining, we should extend our .eslintrc.js file. Start by adding the jest plugin npm i --save-dev eslint-plugin-jest.

Then modify the .eslintrc.js file to include it:

module.exports = {
  env: {
    browser: true,
    es2020: true,
    node: true,
    jest: true // add this line
  },
  extends: [
    'standard'
  ],
  parserOptions: {
    ecmaVersion: 11,
    sourceType: 'module'
  },
  rules: {
  }
}

Now we should be able to write our tests without any lint errors.

I usually try to test all the exported methods - so I can have some confidence that the consumer is getting the expected results. In our case, we want to test:

module.exports = {
  all: moods,
  anger: moods.anger,
  boredom: moods.boredom,
  excitement: moods.excitement,
  happiness: moods.happiness,
  getRandom,
  list
}

Testing all of these properties and methods will give us 100% of code coverage. Pretty neat!

Our test will only have a "test suite" which is basically defined by the keyword describe. Inside this test suite, we will add our tests. We can start by adding a test to check if the property .all returns, in fact, all the available mood sentences:

// Import our package
const Moods = require('../index')

describe('mood-sentences', () => {
  test('.all should return all sentences', () => {
    const all = require('../mood-sentences.json')
    expect(Moods.all).toMatchObject(all)
  })
})

As our property Moods.all is nothing more than the contents of the json file, this way we can check that they match.

Let's continue adding all the other properties that should match the json file contents.

const Moods = require('../index')

describe('mood-sentences', () => {
  test('.all should return all sentences', () => {
    const all = require('../mood-sentences.json')
    expect(Moods.all).toMatchObject(all)
  })

  test('.anger should return all anger sentences', () => {
    const { anger } = require('../mood-sentences.json')
    expect(Moods.anger).toMatchObject(anger)
  })

  test('.boredom should return all boredom sentences', () => {
    const { boredom } = require('../mood-sentences.json')
    expect(Moods.boredom).toMatchObject(boredom)
  })

  test('.excitement should return all excitement sentences', () => {
    const { excitement } = require('../mood-sentences.json')
    expect(Moods.excitement).toMatchObject(excitement)
  })

  test('.happiness should return all happiness sentences', () => {
    const { happiness } = require('../mood-sentences.json')
    expect(Moods.happiness).toMatchObject(happiness)
  })
})

Nothing too fancy, but it assures us that the json contents are being used.

Next, we want to test the .list property that should return all the available moods. It is used to get random sentences for a mood.

  test('.list should return a list of available moods', () => {
    // Get the json file moods
    const moods = require('../mood-sentences.json')

    // Get all the values defined in the .list property ['anger', 'excitement'...]
    const values = Object.values(Moods.list).sort()

    // Get the json keys ['anger', 'excitement'...]
    const expected = Object.keys(moods).sort()

    expect(values).toEqual(expected)
  })

This way we make sure that all the values in the .list property actually exist and match the keys in the json file. If we decide to add one more mood to the json file, we would also have to add a key->value to our list enum.

Lastly, we need to have a test for the .getRandom method.

 test('.random() should return a random sentence for a mood', () => {
    const randomSentence = Moods.getRandom(Moods.list.HAPPINESS)

    expect(Moods.happiness).toContain(randomSentence)
  })

  // Handle errors (empty call, or non existing mood)
  test('.random() without mood, it throws an error', () => {
    try {
      Moods.getRandom()
    } catch (error) {
      expect(error).toBeInstanceOf(Error)
      expect(error).toHaveProperty('message', 'Requested mood "undefined" is not in the moods list!')
    }
  })

With our last test, we should have reached 100% coverage!
Now we can test it, using the script we previously defined in our package.json file: npm run test.

You should get a result like the following:

jest results console screenshot

With this, we have achieved 100% coverage. It's not hard on such a small library. ๐Ÿค“

We should also add a new pre-push hook to husky, so it will run our tests before pushing to Github. This way if the tests are failing, no code will be pushed to our repository, until we fix our code!

Open package.json and add the pre-push script:

"husky": {
    "hooks": {
      "pre-commit": "npm run lint:fix && npm run lint",
      "pre-push": "npm run test"
    }
  }

Now we can run git add -A and npm run commit and it will run our lint and test tasks!

You can check this finished chapter on github https://github.com/AndreVarandas/mood-sentences/tree/writing-tests

That's all for this part, thanks for reading! In the next part, we will set up our continuous integration (CI) to build our package and publish it into npm!

Discussion

pic
Editor guide