Testing Javascript Application Part 1

Weather reports can be used to save lives and properties. They can also be used for planning activities. These activities include recreational, social, and economic activities. In this write up we shall be considering how to build and test a weather application using JavaScript Technologies.

The weather application will work as follows: 

  • it will be a backend application. 
  • it will connect weather sensors simulators.
  • it will be JSON-based. 

below is the link to my github repository for this write up

https://github.com/gkcharlesdevs/weather

 Tutorial Outline 

  • Connect to database (MongoDB)
  • Create a user model 
  • Create a weather model 
  • create a weather logger model for the remote sensors. 
  • Write unit tests for user controller 
  • Write unit tests for weather controller 
  • Create weather routes 
  • Create user routes 
  • Create user controller logic 
  • Create weather controller logic 

Pre-requisites 

– Knowledge about Node.JS and JavaScript 

– knowledge about Mocha and Sinon. 

– install Node.Js: You can check my previous post Building Application using Node.js HTTPS Module and Africa’s Talking SMS API on how to install node.js  

– Install sinon.js 

npm install sinon 

– install mocha.js 

npm install mocha 

– Install mongoose 

npm install mongoose --save 

– Install nodemon 

npm install --save-dev nodemon 

– Install nyc 

npm i nyc 

– Install dotenv  

npm i dotenv 

– Install express  

npm install express –save 

– install Mongodb 

https://www.mongodb.com/

– Install code editor 

– configure the npm script 

{ 

"scripts": { 

"test": "mocha", 

"start": "node server.js", 

"dev": "nodemon server.js", 

"coverage": "nyc npm run test" 

} 

} 

Project structure 

weatherapp 

-- config 

-- controllers 

-- models 

-- routes 

-- test 

-- server.js 

-- package.json 

Connect to database 

Add the following code to db.js inside the config folder 

const mongoose = require("mongoose"); 

const connect = function () { 

mongoose.connect( 

"mongodb://localhost:27017/weatherapp", 

{ 

useNewUrlParser: true, 

useUnifiedTopology: true, 

}, 

function (err) { 

console.log("Connection to localhost:27017/weatherapp esatblished"); 

} 

); 

}; 

module.exports = connect; 

– create a config.env file in the config folder and add the environment variable MONGO_URI and the value for the MONGO_URI, 

Create User model and schema 

Add the following code in the User.js file in the model folder 

const mongoose = require("mongoose"); 

const UserSchema = new mongoose.Schema({ 

name: { 

type: String, 

required: [true, "please enter name"], 

}, 

email: { 

type: String, 

required: [true, "Please add an email"], 

unique: true, 

match: [ 

/^\w+([\.-]?\w+)_@\w+([\.-]?\w+)_(\.\w{2,3})+$/, 

"Please add a valid email", 

], 

}, 

role: { 

type: String, 

require: [true, "please add a role"], 

enum: ["user"], 

default: "user", 

}, 

password: { 

type: String, 

required: [true, "Please add a password"], 

minlength: 6, 

select: false, 

}, 

resetPasswordToken: String, 

resetPasswordExpire: Date, 

createdAt: { 

type: Date, 

default: Date.now, 

}, 

}); 

 
module.exports = mongoose.model("User", UserSchema); 

Create Weather model and Schema 

const mongoose = require("mongoose"); 

const WeatherSchema = new mongoose.Schema({ 

temperature: { 

type: Number, 

required: [true, "Please add temperature value"], 

}, 

windSpeed: { 

type: Number, 

required: [true, "Please add windspeed"], 

}, 

humidity: { 

type: Number, 

required: [true, "Please add humidity value"], 

}, 

airpressure: { 

type: Number, 

required: [true, "Please add airpressure value"], 

}, 

city: { 

type: String, 

required: [true, "Please add city value"], 

}, 

country: { 

type: String, 

required: [true, "Please add country value"], 

}, 

createdAt: { 

type: Date, 

default: Date.now, 

}, 

}); 

module.exports = mongoose.model("Weather", WeatherSchema); 

Create Logger model and Schema 

Paste the following in the file Logger.js in the models folder 

const mongoose = require("mongoose"); 

const LoggerSchema = new mongose.Schema({ 

loggerId: { 

type: String, 

unique: true, 

required: [true, "No logger Id"], 

}, 

city: { 

type: String, 

required: [true, "No city included"], 

}, 

latitude: { 

type: Number, 

required: [true, "Please add the latitude"], 

}, 

longitude: { 

type: Number, 

required: [true, "Please add the longitude"], 

}, 

createdAt: { 

type: Date, 

default: Date.now, 

}, 

}); 

 
 

model.exports = mongoose.model("Logger", LoggerSchema); 

Write unit tests for User controller 

Paste the following in a file named user.controller.spec.js in the test folder

const sinon = require("sinon");
const User = require("../models/User");
const {
  createUser,
  getUser,
  getUsers,
  updateUser,
  deleteUser,
} = require("../controllers/user");

describe("User Controller", function () {
  let request = {
      body: {
        name: "Josiah Mensah",
        email: "josiah.mensah@itlock.com",
        role: "user",
      },
      params: {
        userId: "610e2cc2c38e103be50257db",
      },
    },
    error,
    response = {},
    expected;

  describe("createUser", function () {
    beforeEach(function () {
      response = {
        json: sinon.spy(),
        status: sinon.stub().returns(response),
      };
    });

    afterEach(function () {
      sinon.restore();
    });

    it("should return user object", function () {
      expected = {
        _id: "610e2cc2c38e103be50257db",
        name: "Josiah Mensah",
        email: "josiah.mensah@itlock.com",
        role: "user",
        createdAt: "2021-08-07T06:48:34.855Z",
        __v: 0,
      };
      sinon.stub(User, "create").yields(null, expected);
      createUser(request, response);
      sinon.assert.calledWith(User.create, request.body);
      sinon.assert.calledWith(response.status, 200);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ _id: expected._id })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ name: expected.name })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ email: expected.email })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ role: expected.role })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ createdAt: expected.createdAt })
      );

      sinon.assert.calledWith(response.json, sinon.match({ _v: expected._v }));
      sinon.assert.calledOnce(response.json);
      sinon.assert.calledOnce(response.status);
    });

    it("should return status 500 on server error", function () {
      let error = new Error();
      sinon.stub(User, "create").yields(error); // For the error message check mongoose documentation
      createUser(request, response);
      sinon.assert.calledWith(User.create, request.body);
      sinon.assert.calledWith(response.status, 500);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.json);
      sinon.assert.calledOnce(response.status);
    });
  });

  describe("getUsers", function () {
    beforeEach(function () {
      response = {
        json: sinon.spy(),
        status: sinon.stub().returns(response),
      };
      expected = [
        {
          _id: "610e354a131d8e53a36f11c9",
          name: "Donogan Richie",
          email: "donogan.richie@outlook.com",
          role: "user",
          createdAt: "2021-08-07T07:24:58.151Z",
          __v: 0,
        },
        {
          _id: "610e2cc2c38e103be50257db",
          name: "Blessing Kinks",
          email: "blessing.kinks@itlock.com",
          role: "user",
          createdAt: "2021-08-07T06:48:34.855Z",
          __v: 0,
        },
        {
          _id: "610e36e60610f9564ecda91f",
          name: "Uchia Hush",
          email: "uchia.hush@itlock.com",
          role: "user",
          createdAt: "2021-08-07T07:31:50.969Z",
          __v: 0,
        },
      ]; // this should be replaced with mock
    });

    afterEach(function () {
      sinon.restore();
    });

    it("should return array of users", function () {
      sinon.stub(User, "find").yields(null, expected);
      getUsers(request, response);
      sinon.assert.calledWith(User.find, {});
      sinon.assert.calledWith(response.json, sinon.match.array);
      sinon.assert.calledWith(response.json, expected);
      sinon.assert.calledOnce(response.json);
      sinon.assert.calledOnce(response.status);
    });

    it("should return empty array", function () {
      let expected = [];
      sinon.stub(User, "find").yields(null, expected);
      getUsers(request, response);
      sinon.assert.calledWith(User.find, {});
      sinon.assert.calledWith(response.json, sinon.match.array);
      sinon.assert.calledWith(response.json, expected);
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });

    it("should return status 500 on server error", function () {
      let error = new Error();
      sinon.stub(User, "find").yields(error);
      getUsers(request, response);
      sinon.assert.calledWith(User.find, {});
      sinon.assert.calledWith(response.status, 500);
      sinon.assert.calledWith(
        response.json,
        sinon.match({
          error: error.message,
        })
      );
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });
  });

  describe("getUser", function () {
    beforeEach(function () {
      response = {
        json: sinon.spy(),
        status: sinon.stub().returns(response),
      };
      expected = {
        _id: "610e2cc2c38e103be50257db",
        name: "Blessing Kinks",
        email: "blessing.kinks@itlock.com",
        role: "user",
        createdAt: "2021-08-07T06:48:34.855Z",
        __v: 0,
      };
    });

    afterEach(function () {
      sinon.restore();
    });

    it("should return user object", function () {
      sinon.stub(User, "findById").yields(null, expected);
      getUser(request, response);
      sinon.assert.calledWith(User.findById, request.params.userId);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ _id: expected._id })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ name: expected.name })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ email: expected.email })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ role: expected.role })
      );

      sinon.assert.calledWith(
        response.json,
        sinon.match({ createdAt: expected.createdAt })
      );

      sinon.assert.calledWith(response.json, sinon.match({ _v: expected._v }));
      sinon.assert.calledWith(response.status, 200);
      sinon.assert.calledOnce(response.json);
      sinon.assert.calledOnce(response.status);
    });

    it("should return 404 for non-existing User id", function () {
      let error = new Error(
        `The record with the id ${request.params.weatherId} does not exist`
      );
      error.name = "CastError";
      sinon.stub(User, "findById").yields(error, null);
      getUser(request, response);
      sinon.assert.calledWith(User.findById, request.params.userId);
      sinon.assert.calledWith(response.status, 404);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });

    it("should return status 500 on server error", function () {
      let error = new Error();
      sinon.stub(User, "findById").yields(error);
      getUser(request, response);
      sinon.assert.calledWith(User.findById, request.params.userId);
      sinon.assert.calledWith(response.status, 500);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });
  });

  describe("deleteUser", function () {
    beforeEach(function () {
      response = {
        json: sinon.spy(),
        status: sinon.stub().returns(response),
      };
    });

    afterEach(function () {
      sinon.restore();
    });

    it("should return the deleted user", function () {
      sinon.stub(User, "findByIdAndDelete").yields(null, {});
      deleteUser(request, response);
      sinon.assert.calledWith(User.findByIdAndDelete, request.params.userId);
      sinon.assert.calledWith(
        response.json,
        sinon.match({
          message: `User with the ${request.params.userId} deleted`,
        })
      );
    });

    it("should return 404 for non-existing user id", function () {
      let error = new Error(
        `The user record with the id ${request.params.userId} does not exist`
      );
      error.name = "CastError";
      sinon.stub(User, "findByIdAndDelete").yields(error, null);
      deleteUser(request, response);
      sinon.assert.calledWith(User.findByIdAndDelete, request.params.userId);
      sinon.assert.calledWith(response.status, 404);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });

    it("should return status 500 on server error", function () {
      let error = new Error();
      sinon.stub(User, "findByIdAndDelete").yields(error, null);
      deleteUser(request, response);
      sinon.assert.calledWith(User.findByIdAndDelete, request.params.userId);
      sinon.assert.calledWith(response.status, 500);
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
    });
  });

  describe("updateUser", function () {
    beforeEach(function () {
      response = {
        json: sinon.spy(),
        status: sinon.stub().returns(response),
      };
      expected = request.body;
    });

    afterEach(function () {
      sinon.restore();
    });

    it("should return updated User object", function () {
      let request = {
        body: {
          name: "Kingley Impela",
          email: "kingley.impela@out.com",
        },
        params: {
          userId: "610e2cc2c38e103be50257db",
        },
      };

      let expected = {
        _id: "610e2cc2c38e103be50257db",
        name: "Kingley Impela",
        email: "kingley.impela@out.com",
        role: "user",
        createdAt: "2021-08-07T06:48:34.855Z",
        _V: 0,
      };
      sinon.stub(User, "findByIdAndUpdate").yields(null, expected);
      updateUser(request, response);
      sinon.assert.calledWith(
        User.findByIdAndUpdate,
        request.params.userId,
        request.body,
        { new: true }
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ _id: expected._id })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ name: expected.name })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ email: expected.email })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ role: expected.role })
      );

      sinon.assert.calledWith(
        response.json,
        sinon.match({ createdAt: expected.createdAt })
      );
      sinon.assert.calledWith(response.json, sinon.match({ _v: expected._v }));
      sinon.assert.calledWith(response.status, 200);
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });

    it("should return 404 for non-existing user id", function () {
      let error = new Error(
        `The user record with the id ${request.params.userId} does not exist`
      );
      error.name = "CastError";
      sinon.stub(User, "findByIdAndUpdate").yields(error, null);
      updateUser(request, response);
      sinon.assert.calledWith(
        User.findByIdAndUpdate,
        request.params.userId,
        request.body,
        sinon.match({ new: true })
      );
      sinon.assert.calledWith(response.status, 404);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });

    it("should return status 500 on server error", function () {
      let error = new Error();
      sinon.stub(User, "findByIdAndUpdate").yields(error, null);
      updateUser(request, response);
      sinon.assert.calledWith(
        User.findByIdAndUpdate,
        request.params.userId,
        request.body,
        sinon.match({ new: true })
      );
      sinon.assert.calledWith(response.status, 500);
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.json);
    });
  });
});

Write unit tests for weather controller 

Paste the code below in the file weather.controller.spec.js in the test folder

const sinon = require("sinon");
const Weather = require("../models/Weather");
const {
  createWeather,
  getWeathers,
  getWeather,
  updateWeather,
  deleteWeather,
} = require("../controllers/weather");

describe("Weather Controller", function () {
  let request = {
      body: {
        temperature: 13,
        windSpeed: 4,
        humidity: 67,
        airpressure: 1025,
        city: "Nairobi",
        zipcode: 00100,
        country: "Kenya",
      },
      params: {
        weatherId: "610e2cc2c38e103be50257db",
        loggerId: "loggerId",
      },
    },
    error,
    response = {},
    expected;

  describe("createWeather", function () {
    beforeEach(function () {
      response = {
        json: sinon.spy(),
        status: sinon.stub().returns(response),
      };
    });

    afterEach(function () {
      sinon.restore();
    });

    it("should return Weather object", function () {
      expected = {
        _id: "610e2cc2c38e103be50257db",
        temperature: 13,
        windSpeed: 4,
        humidity: 67,
        airpressure: 1025,
        city: "Nairobi",
        zipcode: 64,
        country: "Kenya",
        createdAt: "2021-08-07T06:48:34.855Z",
        __v: 0,
      };
      sinon.stub(Weather, "create").yields(null, expected);
      createWeather(request, response);
      sinon.assert.calledWith(Weather.create, request.body);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ _id: expected._id })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ temperature: expected.temperature })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ windSpeed: expected.windSpeed })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ humidity: expected.humidity })
      );

      sinon.assert.calledWith(
        response.json,
        sinon.match({ airpressure: expected.airpressure })
      );

      sinon.assert.calledWith(
        response.json,
        sinon.match({ city: expected.city })
      );

      sinon.assert.calledWith(
        response.json,
        sinon.match({ zipcode: expected.zipcode })
      );

      sinon.assert.calledWith(
        response.json,
        sinon.match({ country: expected.country })
      );

      sinon.assert.calledWith(
        response.json,
        sinon.match({ createdAt: expected.createdAt })
      );

      sinon.assert.calledWith(response.json, sinon.match({ _v: expected._V }));
    });

    it("should return status 500 on server error", function () {
      sinon
        .stub(Weather, "create")
        .yields(new Error("Could not create weather")); // For the error message check mongoose documentation
      createWeather(request, response);
      sinon.assert.calledWith(Weather.create, request.body);
      sinon.assert.calledWith(response.status, 500);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: "Weather could not be created" })
      );
      sinon.assert.calledOnce(response.json);
    });
  });

  describe("getWeathers", function () {
    beforeEach(function () {
      response = {
        json: sinon.spy(),
        status: sinon.stub().returns(response),
      };
      expected = [
        {
          _id: "610e354a131d8e53a36f11c9",
          temperature: 15,
          windSpeed: 8,
          humidity: 24,
          airpressure: 1030,
          city: "Johannesburg",
          zipcode: 2153,
          country: "South Africa",
          createdAt: "2021-08-07T07:24:58.151Z",
          __v: 0,
        },
        {
          _id: "610e2cc2c38e103be50257db",
          temperature: 13,
          windSpeed: 4,
          humidity: 67,
          airpressure: 1025,
          city: "Nairobi",
          zipcode: 64,
          country: "Kenya",
          createdAt: "2021-08-07T06:48:34.855Z",
          __v: 0,
        },
        {
          _id: "610e36e60610f9564ecda91f",
          temperature: 34,
          windSpeed: 15,
          humidity: 47,
          airpressure: 1006,
          city: "Cairo",
          zipcode: 11511,
          country: "Egypt",
          createdAt: "2021-08-07T07:31:50.969Z",
          __v: 0,
        },
      ]; // this should be replaced with mock
    });

    afterEach(function () {
      sinon.restore();
    });

    it("should return array of weathers", function () {
      sinon.stub(Weather, "find").yields(null, expected);
      getWeathers(request, response);
      sinon.assert.calledWith(Weather.find, {});
      sinon.assert.calledWith(response.json, sinon.match.array);
      sinon.assert.calledWith(response.json, expected);
    });

    it("should return empty array", function () {
      let expected = [];
      sinon.stub(Weather, "find").yields(null, expected);
      getWeathers(request, response);
      sinon.assert.calledWith(Weather.find, {});
      sinon.assert.calledWith(response.json, sinon.match.array);
      sinon.assert.calledWith(response.json, expected);
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });

    it("should return status 500 on server error", function () {
      sinon.stub(Weather, "find").yields(new Error());
      getWeathers(request, response);
      sinon.assert.calledWith(Weather.find, {});
      sinon.assert.calledWith(response.status, 500);
      sinon.assert.calledWith(response.json, {
        error: "Server error unable to get list",
      });
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });
  });

  describe("getWeather", function () {
    beforeEach(function () {
      response = {
        json: sinon.spy(),
        status: sinon.stub().returns(response),
      };
      expected = {
        _id: "610e2cc2c38e103be50257db",
        temperature: 13,
        windSpeed: 4,
        humidity: 67,
        airpressure: 1025,
        city: "Nairobi",
        zipcode: 64,
        country: "Kenya",
        createdAt: "2021-08-07T06:48:34.855Z",
        __v: 0,
      };
    });

    afterEach(function () {
      sinon.restore();
    });

    it("should return Weather obj", function () {
      sinon.stub(Weather, "findById").yields(null, expected);
      getWeather(request, response);
      sinon.assert.calledWith(Weather.findById, request.params.weatherId);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ _id: expected._id })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ temperature: expected.temperature })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ windSpeed: expected.windSpeed })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ humidity: expected.humidity })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ airpressure: expected.airpressure })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ city: expected.city })
      );

      sinon.assert.calledWith(
        response.json,
        sinon.match({ zipcode: expected.zipcode })
      );

      sinon.assert.calledWith(
        response.json,
        sinon.match({ country: expected.country })
      );

      sinon.assert.calledWith(
        response.json,
        sinon.match({ createdAt: expected.createdAt })
      );

      sinon.assert.calledWith(response.json, sinon.match({ _v: expected._v }));
    });

    it("should return 404 for non-existing Weather id", function () {
      let error = new Error(
        `The record with the id ${request.params.weatherId} does not exist`
      );
      error.name = "CastError";
      sinon.stub(Weather, "findById").yields(error, null);
      getWeather(request, response);
      sinon.assert.calledWith(Weather.findById, request.params.weatherId);
      sinon.assert.calledWith(response.status, 404);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });

    it("should return status 500 on server error", function () {
      let error = new Error();
      sinon.stub(Weather, "findById").yields(error);
      getWeather(request, response);
      sinon.assert.calledWith(Weather.findById, request.params.weatherId);
      sinon.assert.calledWith(response.status, 500);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });
  });

  describe("deleteWeather", function () {
    beforeEach(function () {
      response = {
        json: sinon.spy(),
        status: sinon.stub().returns(response),
      };
    });

    afterEach(function () {
      sinon.restore();
    });

    it("should return successful deletion message", function () {
      sinon.stub(Weather, "findByIdAndDelete").yields(null, {});
      deleteWeather(request, response);
      sinon.assert.calledWith(
        Weather.findByIdAndDelete,
        request.params.weatherId
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ message: "Weather record removed" })
      );
    });

    it("should return 404 for non-existing weather id", function () {
      let error = new Error(
        `The weather record with the id ${request.params.weatherId} does not exist`
      );
      error.name = "CastError";
      sinon.stub(Weather, "findByIdAndDelete").yields(error, null);
      deleteWeather(request, response);
      sinon.assert.calledWith(
        Weather.findByIdAndDelete,
        request.params.weatherId
      );
      sinon.assert.calledWith(response.status, 404);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });

    it("should return status 500 on server error", function () {
      let error = new Error();
      sinon.stub(Weather, "findByIdAndDelete").yields(error, null);
      deleteWeather(request, response);
      sinon.assert.calledWith(
        Weather.findByIdAndDelete,
        request.params.weatherId
      );
      sinon.assert.calledWith(response.status, 500);
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
    });
  });

  describe("updateWeather", function () {
    beforeEach(function () {
      response = {
        json: sinon.spy(),
        status: sinon.stub().returns(response),
      };
      expected = request.body;
    });

    afterEach(function () {
      sinon.restore();
    });

    it("should return updated Weather object", function () {
      let request = {
        body: {
          temperature: 34,
          windSpeed: 5,
          humidity: 80,
        },
        params: {
          weatherId: "610e2cc2c38e103be50257db",
        },
      };

      let expected = {
        _id: "610e2cc2c38e103be50257db",
        temperature: 34,
        windSpeed: 5,
        humidity: 80,
        airpressure: 1025,
        city: "Nairobi",
        zipcode: 00100,
        country: "Kenya",
        createdAt: "2021-08-07T06:48:34.855Z",
        _V: 0,
      };
      sinon.stub(Weather, "findByIdAndUpdate").yields(null, expected);
      updateWeather(request, response);
      sinon.assert.calledWith(
        Weather.findByIdAndUpdate,
        request.params.weatherId,
        request.body,
        { new: true }
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ _id: expected._id })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ temperature: expected.temperature })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ windSpeed: expected.windSpeed })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ humidity: expected.humidity })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ airpressure: expected.airpressure })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ city: expected.city })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ zipcode: expected.zipcode })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ country: expected.country })
      );
      sinon.assert.calledWith(
        response.json,
        sinon.match({ createdAt: expected.createdAt })
      );
      sinon.assert.calledWith(response.json, sinon.match({ _v: expected._v }));
      sinon.assert.calledWith(response.status, 200);
    });

    it("should return 404 for non-existing weather id", function () {
      let error = new Error(
        `The weather record with the id ${request.params.weatherId} does not exist`
      );
      error.name = "CastError";
      sinon.stub(Weather, "findByIdAndUpdate").yields(error, null);
      updateWeather(request, response);
      sinon.assert.calledWith(
        Weather.findByIdAndUpdate,
        request.params.weatherId,
        request.body,
        sinon.match({ new: true })
      );
      sinon.assert.calledWith(response.status, 404);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledOnce(response.json);
    });

    it("should return status 500 on server error", function () {
      let error = new Error();
      sinon.stub(Weather, "findByIdAndUpdate").yields(error, null);
      updateWeather(request, response);
      sinon.assert.calledWith(
        Weather.findByIdAndUpdate,
        request.params.weatherId,
        request.body,
        sinon.match({ new: true })
      );
      sinon.assert.calledWith(response.status, 500);
      sinon.assert.calledOnce(response.status);
      sinon.assert.calledWith(
        response.json,
        sinon.match({ error: error.message })
      );
      sinon.assert.calledOnce(response.json);
    });
  });
});

Create User Controller 

create the user controller code just enough to fail the user controller test in a TDD way 

– Paste the following the controller folder 

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

exports.createUser = (req, res) => {}; 

exports.getUsers = (req, res) => {}; 

exports.getUser = (req, res) => {}; 

exports.updateUser = (req, res) => {}; 

exports.deleteUser = (req, res) => {}

Create Weather Controller 

create the weather controller code just enough to fail the weather controller test in a TDD way 

Paste the following in the weather controller file in the controller folder 

const Weather = require("../models/Weather"); 

exports.createWeather = (req, res) => {}; 

exports.getWeathers = (req, res) => {}; 

exports.getWeather = (req, res) => {}; 

exports.updateWeather = (req, res) => {}; 

exports.deleteWeather = (req, res) => {}; 

Run the test 

Open the command line and navigate to the root folder. Type the following in the command line to run the test. The test will fail.

npm test

The following is displayed  

  User Controller
    createUser
      1) should return user object
      2) should return status 500 on server error
    getUsers
      3) should return array of users
      4) should return empty array
      5) should return status 500 on server error
    getUser
      6) should return user object
      7) should return 404 for non-existing User id
      8) should return status 500 on server error
    deleteUser
      9) should return the deleted user
      10) should return 404 for non-existing user id
      11) should return status 500 on server error
    updateUser
      12) should return updated User object
      13) should return 404 for non-existing user id
      14) should return status 500 on server error

  Weather Controller
    createWeather
      15) should return Weather object
      16) should return status 500 on server error
    getWeathers
      17) should return array of weathers
      18) should return empty array
      19) should return status 500 on server error
    getWeather
      20) should return Weather obj
      21) should return 404 for non-existing Weather id
      22) should return status 500 on server error
    deleteWeather
      23) should return successful deletion message
      24) should return 404 for non-existing weather id
      25) should return status 500 on server error
    updateWeather
      26) should return updated Weather object
      27) should return 404 for non-existing weather id
      28) should return status 500 on server error


  0 passing (73ms)
  28 failing

  1) User Controller
       createUser
         should return user object:
     AssertError: expected create to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:49:20)
      at processImmediate (node:internal/timers:464:21)

  2) User Controller
       createUser
         should return status 500 on server error:
     AssertError: expected create to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:81:20)
      at processImmediate (node:internal/timers:464:21)

  3) User Controller
       getUsers
         should return array of users:
     AssertError: expected find to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:133:20)
      at processImmediate (node:internal/timers:464:21)

  4) User Controller
       getUsers
         should return empty array:
     AssertError: expected find to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:144:20)
      at processImmediate (node:internal/timers:464:21)

  5) User Controller
       getUsers
         should return status 500 on server error:
     AssertError: expected find to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:155:20)
      at processImmediate (node:internal/timers:464:21)

  6) User Controller
       getUser
         should return user object:
     AssertError: expected findById to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:191:20)
      at processImmediate (node:internal/timers:464:21)

  7) User Controller
       getUser
         should return 404 for non-existing User id:
     AssertError: expected findById to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:227:20)
      at processImmediate (node:internal/timers:464:21)

  8) User Controller
       getUser
         should return status 500 on server error:
     AssertError: expected findById to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:241:20)
      at processImmediate (node:internal/timers:464:21)

  9) User Controller
       deleteUser
         should return the deleted user:
     AssertError: expected findByIdAndDelete to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:267:20)
      at processImmediate (node:internal/timers:464:21)

  10) User Controller
       deleteUser
         should return 404 for non-existing user id:
     AssertError: expected findByIdAndDelete to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:283:20)
      at processImmediate (node:internal/timers:464:21)

  11) User Controller
       deleteUser
         should return status 500 on server error:
     AssertError: expected findByIdAndDelete to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:297:20)
      at processImmediate (node:internal/timers:464:21)

  12) User Controller
       updateUser
         should return updated User object:
     AssertError: expected findByIdAndUpdate to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:342:20)
      at processImmediate (node:internal/timers:464:21)

  13) User Controller
       updateUser
         should return 404 for non-existing user id:
     AssertError: expected findByIdAndUpdate to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:382:20)
      at processImmediate (node:internal/timers:464:21)

  14) User Controller
       updateUser
         should return status 500 on server error:
     AssertError: expected findByIdAndUpdate to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/user.controller.spec.js:401:20)
      at processImmediate (node:internal/timers:464:21)

  15) Weather Controller
       createWeather
         should return Weather object:
     AssertError: expected create to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:58:20)
      at processImmediate (node:internal/timers:464:21)

  16) Weather Controller
       createWeather
         should return status 500 on server error:
     AssertError: expected create to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:109:20)
      at processImmediate (node:internal/timers:464:21)

  17) Weather Controller
       getWeathers
         should return array of weathers:
     AssertError: expected find to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:172:20)
      at processImmediate (node:internal/timers:464:21)

  18) Weather Controller
       getWeathers
         should return empty array:
     AssertError: expected find to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:181:20)
      at processImmediate (node:internal/timers:464:21)

  19) Weather Controller
       getWeathers
         should return status 500 on server error:
     AssertError: expected find to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:191:20)
      at processImmediate (node:internal/timers:464:21)

  20) Weather Controller
       getWeather
         should return Weather obj:
     AssertError: expected findById to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:228:20)
      at processImmediate (node:internal/timers:464:21)

  21) Weather Controller
       getWeather
         should return 404 for non-existing Weather id:
     AssertError: expected findById to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:279:20)
      at processImmediate (node:internal/timers:464:21)

  22) Weather Controller
       getWeather
         should return status 500 on server error:
     AssertError: expected findById to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:293:20)
      at processImmediate (node:internal/timers:464:21)

  23) Weather Controller
       deleteWeather
         should return successful deletion message:
     AssertError: expected findByIdAndDelete to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:319:20)
      at processImmediate (node:internal/timers:464:21)

  24) Weather Controller
       deleteWeather
         should return 404 for non-existing weather id:
     AssertError: expected findByIdAndDelete to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:336:20)
      at processImmediate (node:internal/timers:464:21)

  25) Weather Controller
       deleteWeather
         should return status 500 on server error:
     AssertError: expected findByIdAndDelete to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:353:20)
      at processImmediate (node:internal/timers:464:21)

  26) Weather Controller
       updateWeather
         should return updated Weather object:
     AssertError: expected findByIdAndUpdate to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:406:20)
      at processImmediate (node:internal/timers:464:21)

  27) Weather Controller
       updateWeather
         should return 404 for non-existing weather id:
     AssertError: expected findByIdAndUpdate to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:459:20)
      at processImmediate (node:internal/timers:464:21)

  28) Weather Controller
       updateWeather
         should return status 500 on server error:
     AssertError: expected findByIdAndUpdate to be called with arguments 
      at Object.fail (node_modules/sinon/lib/sinon/assert.js:120:25)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:20)
      at Object.assert.<computed> [as calledWith] (node_modules/sinon/lib/sinon/assert.js:95:17)
      at Context.<anonymous> (test/weather.controller.spec.js:478:20)
      at processImmediate (node:internal/timers:464:21)

Make the Test Pass

  • User Controller: Make user controller pass by pasting the following in the file user.js in the controller folder
const User = require("../models/User");

exports.createUser = (req, res) => {
  User.create(req.body, (err, user) => {
    if (err) {
      res.status(500);
      return res.json({ error: err.message });
    } else {
      res.status(200);
      res.json(user);
    }
  });
};

exports.getUsers = (req, res) => {
  User.find({}, (err, user) => {
    if (err) {
      res.status(500);
      res.json({ error: err.message });
    } else {
      res.status(200);
      res.json(user);
    }
  });
};

exports.getUser = (req, res) => {
  User.findById(req.params.userId, (err, user) => {
    if (err) {
      if (err.name === "CastError") {
        res.status(404);
        return res.json({ error: err.message });
      }

      res.status(500);
      res.json({ error: err.message });
    } else {
      res.status(200);
      res.json(user);
    }
  });
};

exports.updateUser = (req, res) => {
  User.findByIdAndUpdate(
    req.params.userId,
    req.body,
    {
      new: true,
    },
    (err, user) => {
      if (err) {
        if (err.name === "CastError") {
          res.status(404);
          return res.json({ error: err.message });
        } else {
          res.status(500);
          return res.json({ error: err.message });
        }
      } else {
        res.status(200);
        res.json(user);
      }
    }
  );
};

exports.deleteUser = (req, res) => {
  User.findByIdAndDelete(req.params.userId, (err, user) => {
    if (err) {
      if (err.name === "CastError") {
        res.status(404);
        return res.json({ error: err.message });
      }

      res.status(500);
      return res.json({ error: err.message });
    } else {
      res.status(200);
      res.json({ message: `User with the ${req.params.userId} deleted` });
    }
  });
};
  • Weather Controller: Make weather controller pass by pasting the following in the file weather.js in controller folder.
const Weather = require("../models/Weather");

exports.createWeather = (req, res) => {
  Weather.create(req.body, function (error, weather) {
    if (error) {
      res.status(500);
      return res.json({ error: "Weather could not be created" });
    } else {
      return res.json(weather);
    }
  });
};

exports.getWeathers = (req, res) => {
  Weather.find({}, (error, weather) => {
    if (error) {
      res.status(500);
      return res.json({ error: "Server error unable to get list" });
    } else {
      res.status(200);
      res.json(weather);
    }
  });
};

exports.getWeather = (req, res) => {
  Weather.findById(req.params.weatherId, (error, weather) => {
    if (error) {
      if (error.name === "CastError") {
        res.status(404);
        return res.json({ error: error.message });
      } else {
        res.status(500);
        return res.json({ error: error.message });
      }
    } else {
      res.status(200);
      res.json(weather);
    }
  });
};

exports.updateWeather = (req, res) => {
  Weather.findByIdAndUpdate(
    req.params.weatherId,
    req.body,
    {
      new: true,
    },
    (err, weather) => {
      if (err) {
        if (err.name === "CastError") {
          res.status(404);
          return res.json({ error: err.message });
        } else {
          res.status(500);
          return res.json({ error: err.message });
        }
      } else {
        res.status(200);
        res.json(weather);
      }
    }
  );
};

exports.deleteWeather = (req, res) => {
  Weather.findByIdAndDelete(req.params.weatherId, (err, weather) => {
    if (err) {
      if (err.name === "CastError") {
        res.status(404);
        res.json({ error: err.message });
      } else {
        res.status(500);
        res.json({ error: err.message });
      }
    } else {
      res.json({ message: "Weather record removed" });
    }
  });
};

exports.getWeatherByCity = (req, res) => {
  Weather.find({});
};

Run test

Open the command line and navigate to the root folder. Type the following in the command line to run the test.

npm test

All the tests pass and the following is displayed


  User Controller
    createUser
      ✔ should return user object
      ✔ should return status 500 on server error
    getUsers
      ✔ should return array of users
      ✔ should return empty array
      ✔ should return status 500 on server error
    getUser
      ✔ should return user object
      ✔ should return 404 for non-existing User id
      ✔ should return status 500 on server error
    deleteUser
      ✔ should return the deleted user
      ✔ should return 404 for non-existing user id
      ✔ should return status 500 on server error
    updateUser
      ✔ should return updated User object
      ✔ should return 404 for non-existing user id
      ✔ should return status 500 on server error

  Weather Controller
    createWeather
      ✔ should return Weather object
      ✔ should return status 500 on server error
    getWeathers
      ✔ should return array of weathers
      ✔ should return empty array
      ✔ should return status 500 on server error
    getWeather
      ✔ should return Weather obj
      ✔ should return 404 for non-existing Weather id
      ✔ should return status 500 on server error
    deleteWeather
      ✔ should return successful deletion message
      ✔ should return 404 for non-existing weather id
      ✔ should return status 500 on server error
    updateWeather
      ✔ should return updated Weather object
      ✔ should return 404 for non-existing weather id
      ✔ should return status 500 on server error


  28 passing (70ms)

Conclusion

In the above write up we considered unit testing a user controller and a weather controller for a javascript weather application. We used sinon to create test doubles. We followed TDD testing pattern by writing the test first and writing the code just enough to fail the test.

References

Weather https://en.wikipedia.org/wiki/Weather

Test-Driven JavaScript Development by Christian Johansen

Testable JavaScript by Mark Ethan Trostler

Unit Testing Principles, Practices, and Patterns by Vladimir Khorikov

0 Shares:
You May Also Like