Skip to content

Instantly share code, notes, and snippets.

@ivankisyov
Last active December 8, 2022 02:15
Show Gist options
  • Save ivankisyov/46c6115c77fe397a8a111048136e5cd0 to your computer and use it in GitHub Desktop.
Save ivankisyov/46c6115c77fe397a8a111048136e5cd0 to your computer and use it in GitHub Desktop.
Writing Tests with Jest on Node.js

Writing Tests with Jest on Node.js

Installation

npm i --save-dev jest

Configuration

package.json

...
"scripts": {
  "test": "jest --watchAll --verbose --coverage" // --env node
},
"jest": {
  "testEnvironment": "node"
}
...

Configuration - Setting up timeout globally(useful for longer async calls)

package.json

"scripts": {
   ...
    "test": "jest --watchAll --coverage --verbose --silent --runInBand"
  }

jest.config.js

module.exports = {
  setupFilesAfterEnv: ["./jest.setup.js"]
};

jest.setup.js

jest.setTimeout(30000);

Custom commands

run only this test

npm test -- -t "should register a new user"
// -t: the title of the test 

Test cases

Testing string equality

strings.js

function sayHelloTo(person) {
  return `Hi, ${person}!`;
}

module.exports = sayHelloTo;

strings.spec.js

const sayHelloTo = require("./../strings");

describe("The string package", () => {
  describe("the sayHelloTo function", () => {
    it("should return 'Hi, Peter!' if the argument is 'Peter'", () => {
      const actual = sayHelloTo("Peter");
      const expected = "Hi, Peter!";
      expect(actual).toBe(expected);
    });
  });
});

Testing object equality

classes.js

class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
    this.errors = [];
  }
  validateName() {
    if (this.name) {
      if (this.name.length < 5) {
        this.errors.push("the name must be at least 5 chars long");
      }
    } else {
      this.errors.push("the name is required");
    }
  }
}

module.exports = User;

classes.spec.js

const User = require("./../classes");

describe("The User class", () => {
  it("should create a new user", () => {
    const user1 = new User("smith", "smith@test.com");

    expect(user1).toEqual({
      name: "smith",
      email: "smith@test.com",
      errors: []
    });
  });
  describe("The validateName function", () => {
    it("should create new error message if the user name is less than 5 characters", () => {
      const user2 = new User("tom", "tom@test.com");
      user2.validateName();

      expect(user2.errors).toEqual(["the name must be at least 5 chars long"]);
    });
  });
});

Spies

classes.js

class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
    this.errors = [];
  }
  validateName() {
    if (this.name) {
      if (this.name.length < 5) {
        this.errors.push("the name must be at least 5 chars long");
      }
    } else {
      this.errors.push("the name is required");
    }
  }

  validateEmail() {
    console.log("validating email...");
  }

  validatePassword() {
    console.log("validating password...");
  }

  isValid() {
    this.validateName();
    this.validateEmail();
    this.validatePassword();
  }
}

module.exports = User;

classes.spec.js

describe("The isValid function", () => {
  it("should call validateName, validateEmail, validatePassword functions when isValid fn is called", () => {
    // arrange
    const user = new User();

    jest.spyOn(user, "validateName");
    jest.spyOn(user, "validatePassword");
    jest.spyOn(user, "validateEmail");

    // action
    user.isValid();

    // assertion
    expect(user.validatePassword).toHaveBeenCalled();
    expect(user.validateName).toHaveBeenCalled();
    expect(user.validateEmail).toHaveBeenCalled();
  });
});

Mock functions

const next = jest.fn();

....

expect(next).toHaveBeenCalled();

  • beforeEach
  • afterEach
  • beforeAll
  • afterAll

Integration testing

supertest

npm i --save-dev supertest

Setting up supertest

const supertest = require("supertest");
const app = require("../src/app");

const server = supertest(app)

Handle the eaddrinuse error:

app.js

if(!module.parent) {
  app.listen(3000);
}

This gist is part of:


Additional Info:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment