I am learning unit testing. I wanted to mock the database response from the controller.
How can I do that?
here is my code:
imageController.ts
const getImages = async (req: Request, res: Response) => {
const images = await Image.find({}).sort({ date: -1 });
return res.status(200).json(images);
};
image.test.ts
describe("It shuld be get methoad", () => {
test("get all image url", async () => {
const res = await request(app).get("/api/v1/all");
expect(res.statusCode).toBe(200);
// console.log(res.body);
let images = res.body
// expect(images.length).toBeGreaterThan(0);
});
});
It seems you are using Mongoose, so I would suggest using a nice and quite popular library for mocking Mongoose: https://www.npmjs.com/package/mockingoose
I got a solution using the mongodb-memory-server package.
import request from "supertest";
import app from "../src/app";
import { MongoMemoryServer } from "mongodb-memory-server";
import mongoose from "mongoose";
import { fakeImage, fakeAddImage } from "../src/utils/data";
import Image from "../src/models/image";
describe("Image CRUD operation test", () => {
//For mocking db
beforeAll(async () => {
const mongoServer = await MongoMemoryServer.create();
await mongoose.connect(mongoServer.getUri());
});
afterAll(async () => {
await mongoose.disconnect();
await mongoose.connection.close();
});
it("should return a 200 & get image by id", async () => {
const image = await Image.create(fakeImage);
console.log("image", image);
const { body, statusCode } = await request(app).get(
`/api/v1/image/${image._id}`
);
// console.log("body", body);
expect(statusCode).toBe(200);
expect(body.data.title).toBe(image.title);
});
});
Related
I am trying to mock an HTTP resource .
In the controller, a function from an external module is invoked. I am able to invoke the controller. But unable to mock the external call inside it.
How to mock a function call inside a controller.
From the below example, I am able to invoke getData () from my app.test.js. But how to mock externalAPICall(param1,param2) inside this function?
Contoller.js
const { externalAPICall } = require('#/external-module');
const getData = async (req, res, next) => {
try {
const response = await externalAPICall(param1,param2)
.then(resp => resp.payload)
.catch(error => {
throw (error);
});
res.status(200).send(response);
} catch (error) {
next(error) //Calling next error handling middleware
}
};
module.exports = {
getData
}
app.test.js
const {Server} = require('../src/server');
const server = new Server();
const request = require("supertest");
describe('testAPI', () => {
const app = server.app
test("GET method response has status code = 200", async () => {
const response = await request(app).get("/api/app1")
.auth('user', 'password');
expect(response.statusCode).toBe(200);
});
});
I am trying to implement jest unit testing for firebase functions in my application. I was purely looking at implementing an offline test. I have mocked the request and response objects and am still trying to access some other firebase resources on execution. I am not sure whether I missed any sort of mocking. I intend to not use any firebase-related configuration URLs.
Here is my function and test samples,
randomgenerator.ts
import { https } from "firebase-functions";
export const generateTrickyNumber = https.onRequest(async (req, res) => {
corsHandler(req, res, async () => {
try {
let num =0;
switch (req.body.type) {
case "palindrome":
num= await generatePalindrome(req.body.startnumber,req.body.endnumber);
break;
case "prime":
num= await generatePrime(req.body.startnumber,req.body.endnumber);
break;
default:
break;
}
return res.status(200).send(num);
} catch (err) {
console.log({ err });
return;
}
});
});
randomgenerator.test.ts
import 'jest';
import * as httpMock from 'node-mocks-http';
import * as TestFunctions from 'firebase-functions-test';
const testEnv = TestFunctions();
import { generateTrickyNumber } from "../src/randomgenrator.ts";
describe('generateTrickyNumber ', () => {
test('it returns a successful response with a valid card', async () => {
const req = { method: "POST", body: {type:"palindrome", startnumber:1,endnumber:200} };
const res = {
send: (payload) => {
expect(payload).toBe(153)
},
};
await generateTrickyNumber (req as any, res as any);
});
test('it returns an error if the method is not passed', async () => {
const req = { body: { type: "palindrome" } };
const res = {
send: (payload) => {
expect(payload).toBe('Missing value!')
},
};
await generateTrickyNumber (req as any, res as any);
});
});
Do we need to handle any more mocking for making this successful? Please feel free to suggest.
After a lot of efforts i was not able to figure this one out and hence planned to get the help. I am using a middleware in my node+ express app which looks like :
import mainConfig from '../mainConfig/index';
const axios = require('axios');
module.exports = {
authHandler: (req, res, next) => {
return mainConfig.initialize().then(() => {
const apiUri = mainConfig.get('app.api');
if (apiUri) {
return axios.get(apiUri).then(response => {
next();
}).catch(error => {
res.redirect('/expired');
throw new Error(error);
});
}
}).catch(() => {
});
}
};
For this, I have written the test case in which I was able to mock the axios and my mainCongig module. Now, I want to test whether next() was called as the request was resolved for axios. Can someone help me with the same?
test case I have written is :
import mainConfig from '../mainConfig';
const axios = require('axios');
const middlewares = require('./check-auth');
jest.mock('axios');
describe('Check-Auth Token', () => {
it('should call the Sign In API when live Conf is initalized and have the API URL', () => {
mainConfig.get = jest.fn();
mainConfig.get.mockReturnValue('https://reqres.in/api/users');
mainConfig.initialize = jest.fn(() => Promise.resolve({ data: {} }));
const req = jest.fn(), res = { sendStatus: jest.fn() }, next = jest.fn();
axios.get.mockImplementation(() => Promise.resolve({ data: {} }));
middlewares.authHandler(req, res, next);
expect(next).toHaveBeenCalled(); // coming as not called.
});
});
You have to wait for the middleware to resolve. As you are returning a promise from your middleware, you can wait in the test with an await statement:
import mainConfig from '../mainConfig';
const axios = require('axios');
const middlewares = require('./check-auth');
jest.mock('axios');
describe('Check-Auth Token', () => {
it('should call the Sign In API when live Conf is initalized and have the API URL', async () => {
mainConfig.get = jest.fn();
mainConfig.get.mockReturnValue('https://reqres.in/api/users');
mainConfig.initialize = jest.fn(() => Promise.resolve({ data: {} }));
const req = jest.fn(), res = { sendStatus: jest.fn() }, next = jest.fn();
axios.get.mockImplementation(() => Promise.resolve({ data: {} }));
await middlewares.authHandler(req, res, next);
expect(next).toHaveBeenCalled(); // coming as not called.
});
});
Note that in order to be able to use the await keyword you need to define your test with async.
I'm not an expert, but as far as I know you are testing asynchronous code. So you have to use the done() keyword. Lookup this for more information: https://jestjs.io/docs/en/asynchronous
I'm using nodejs exif library to retrieve metadata from JPEG files.
this lib is used this way :
import * as exif from 'exif'
new exif.ExifImage('path_to_file.jpg', function(err, metadata){ ... })
I've found everywhere how to stub a class method using sinon, pretty simple.
But I don't get how to stub this class constructor so that metadata (or err if I want to test failing case) will be the stubbed value I need to perform my test.
We can still use Sinon with callsFake function. Here is the example:
// src.js
const exif = require("exif");
function readImage() {
// convert to promise for easier testing
return new Promise((resolve, reject) => {
new exif.ExifImage("path_to_file.jpg", function(err, metadata) {
if (err) {
reject(err);
}
resolve(metadata);
});
});
}
module.exports = { readImage };
meanwhile for test
// test.js
const sinon = require('sinon');
const src = require('./src');
const exif = require('exif');
const expect = require('chai').expect;
describe('test exifimage', () => {
let exifStub;
beforeEach(function() {
exifStub = sinon.stub(exif, 'ExifImage')
})
afterEach(function() {
sinon.restore();
})
it('test when success', async () => {
const metadata = 'cinta';
// mock ExifImage as similar as its function signature
exifStub.callsFake((filename, callback) => {
callback(null, metadata); // error is set as null then we set metadata
});
const response = await src.readImage();
expect(response).to.equal(metadata);
});
it('test when error', async () => {
const errorMessage = 'this is error';
exifStub.callsFake((filename, callback) => {
callback(errorMessage); // specify error, error is defined as first param
});
try {
await src.readImage();
} catch (error) {
expect(error).to.equal(errorMessage);
}
});
});
Hope it helps
How can I mock fetch function in Node.js by Jest?
api.js
'use strict'
var fetch = require('node-fetch');
const makeRequest = async () => {
const res = await fetch("http://httpbin.org/get");
const resJson = await res.json();
return resJson;
};
module.exports = makeRequest;
test.js
describe('fetch-mock test', () => {
it('check fetch mock test', async () => {
var makeRequest = require('../mock/makeRequest');
// I want to mock here
global.fetch = jest.fn().mockImplementationOnce(() => {
return new Promise((resolve, reject) => {
resolve({
ok: true,
status,
json: () => {
return returnBody ? returnBody : {};
},
});
});
});
makeRequest().then(function (data) {
console.log('got data', data);
}).catch((e) => {
console.log(e.message)
});
});
});
I tried to use jest-fetch-mock, nock and jest.mock but failed.
Thanks.
You can mock node-fetch using jest.mock. Then in your test set the actual mock response
import fetch from 'node-fetch'
jest.mock('node-fetch', ()=>jest.fn())
describe('fetch-mock test', () => {
it('check fetch mock test', async () => {
var makeRequest = require('../mock/makeRequest');
const response = Promise.resolve({
ok: true,
status,
json: () => {
return returnBody ? returnBody : {};
},
})
fetch.mockImplementation(()=> response)
await response
makeRequest().then(function (data) {
console.log('got data', data);
}).catch((e) => {
console.log(e.message)
});
});
});
import fetch, { Response } from 'node-fetch';
jest.mock('node-fetch');
describe('fetch-mock test', () => {
const mockFetch = fetch as jest.MockedFunction<typeof fetch>;
it('check fetch mock test', async () => {
const json = jest.fn() as jest.MockedFunction<any>;
json.mockResolvedValue({ status: 200}); //just sample expected json return value
mockFetch.mockResolvedValue({ ok: true, json } as Response); //just sample expected fetch response
await makeRequest();
expect(json.mock.calls.length).toBe(1);
})
})