Having issue in writing simple unit test for Google Cloud Function using Chai, Mocha and Sinon although I am referring Google unit testing reference doc but unable to understand it.
Problems
- I'm getting below error message while running unit test.
TypeError: response.status is not a function
- Why do I need to typecast Request and Response object while call function? In Google docs example (Github), they are not doing typecasting.
onCalculate(req as Request, res as unknown as Response);
Objective: Test should pass
onCalculate.ts
import * as functions from "firebase-functions";
export const onCalculate = functions.https.onRequest((request, response) => {
const param1 = request.body.param1;
const param2 = request.body.param2;
response.status(200).send(calculate(param1 as number, param2 as number));
});
/**
* Function to calculate two numbers
* @param {number} param1
* @param {number} param2
* @return {number}
*/
function calculate(param1: number, param2: number): number {
return param1 param2;
}
onCalculate.spec.ts
import firebase from "firebase-functions-test";
import { Request, Response } from "firebase-functions";
import { stub } from "sinon";
import { assert } from "chai";
import { onCalculate } from "./onCalculate";
const test = firebase();
describe("Calculate", () => {
after(() => {
test.cleanup();
});
it("should return 3", () => {
const req = {
query: {},
body: {
param1: 1,
param2: 2,
},
};
const res = { send: stub() };
onCalculate(req as Request, res as unknown as Response);
assert.ok(res.send.calledOnce);
});
});
CodePudding user response:
You should stub the res.status()
method, since res.status(xxx).send()
is method chain call, you need to use sinon.stub().returnsThis()
to achieve this.
Sinon.JS ships with a set of assertions that mirror most behavior verification methods and properties on spies and stubs, it's enough. See assertions, so you don't need to use assert
from the chai
package.
req
and res
are mock objects that contain only the properties and methods we need for testing. Not completely satisfied with the Request
and Response
interfaces, so we need to use type assertions to tell TSC - "These two objects' shapes are correct". The official repo uses JS, not TS.
E.g.
onCalculate.ts
:
import * as functions from 'firebase-functions';
export const onCalculate = functions.https.onRequest((request, response) => {
const param1 = request.body.param1;
const param2 = request.body.param2;
response.status(200).send(calculate(param1 as number, param2 as number));
});
/**
* Function to calculate two numbers
* @param {number} param1
* @param {number} param2
* @return {number}
*/
function calculate(param1: number, param2: number): number {
return param1 param2;
}
onCalculate.spec.ts
:
import firebase from 'firebase-functions-test';
import { Request, Response } from 'firebase-functions';
import sinon from 'sinon';
import { onCalculate } from './onCalculate';
const test = firebase();
describe('Calculate', () => {
after(() => {
test.cleanup();
});
it('should return 3', () => {
const req = {
query: {},
body: {
param1: 1,
param2: 2,
},
};
const res = { status: sinon.stub().returnsThis(), send: sinon.stub() };
onCalculate(req as Request, (res as unknown) as Response);
sinon.assert.calledWithExactly(res.status, 200);
sinon.assert.calledWithExactly(res.send, 3);
});
});
Test result:
Calculate
✓ should return 3
1 passing (4ms)
---------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
onCalculate.spec.ts | 100 | 100 | 100 | 100 |
onCalculate.ts | 100 | 100 | 100 | 100 |
---------------------|---------|----------|---------|---------|-------------------