Ashish Narnoli
Ashish Narnoli

Reputation: 77

How to use Chai and Mocha for Google Cloud functions unit testing

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

TypeError: response.status is not a function
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);
  });
});

Upvotes: 1

Views: 980

Answers (1)

Lin Du
Lin Du

Reputation: 102567

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 |                   
---------------------|---------|----------|---------|---------|-------------------

Upvotes: 2

Related Questions