Search code examples
node.jsunit-testingjestjsmulterjest-fetch-mock

How to write unit test case for uploadFiles method using jest?


i am trying to write unit test case for uploadFiles() method. This method returns function so i have to check toHaveBeenCalledWith('files', 5). I have updated my test case below, I don't know how to mock return function upload.array. can anyone tell me is that possible?

Method

  uploadFiles = (
    storage: StorageType,
    validationFn: (request: Request, file: Express.Multer.File, cb: FileFilterCallback) => Promise<void>,
  ) => {
    // fileSize - size of an individual file (1024 * 1024 * 1 = 1mb)
    const upload = multer({
      storage: this[storage](),
      limits: { fileSize: 1024 * 1024 * FILE_SIZE },
      fileFilter: this.fileUtil.fileValidation(validationFn),
    });
    return upload.array("files", 5); // maximum files allowed to upload in a single request
  };

Test Case

describe('FileService', () => {
  // fileValidation Test suite
  describe('fileValidation', () => {
    let callbackFn: jest.Mock<any, any>;
    let validationFn: jest.Mock<any, any>;
    beforeEach(() => {
      callbackFn = jest.fn();
      validationFn = jest.fn();
    });

    afterEach(() => {
      callbackFn.mockClear();
      validationFn.mockClear();
    });

    it('should call the file filter method with image file types when request body has type image', async () => {
      // Preparing
      const request = {
        body: {
          entity_no: 'AEZ001',
          type: 'image',
          category: 'Shipping',
        },
      };
      const file = {
        originalname: 'some-name.png',
        mimetype: 'image/png',
      };
      // Executing
      const func = fileService.uploadFiles(StorageType.DISK, validationFn);
      await func(request as Request, file as any, callbackFn);
    });
  });
});

Solution

  • You can use jest.mock(moduleName, factory, options) to mock multer module.

    E.g.

    fileService.ts:

    import multer from 'multer';
    
    const FILE_SIZE = 1;
    type FileFilterCallback = any;
    
    export enum StorageType {
      DISK = 'disk',
    }
    
    export class FileService {
      fileUtil = {
        fileValidation(fn) {
          return fn;
        },
      };
      disk() {
        return multer.diskStorage({
          destination: function (req, file, cb) {
            cb(null, '/tmp/my-uploads');
          },
          filename: function (req, file, cb) {
            cb(null, file.fieldname + '-' + Date.now());
          },
        });
      }
      uploadFiles = (
        storage: StorageType,
        validationFn: (request: Request, file: Express.Multer.File, cb: FileFilterCallback) => Promise<void>
      ) => {
        const upload = multer({
          storage: this[storage](),
          limits: { fileSize: 1024 * 1024 * FILE_SIZE },
          fileFilter: this.fileUtil.fileValidation(validationFn),
        });
        return upload.array('files', 5);
      };
    }
    

    fileService.test.ts:

    import { FileService, StorageType } from './fileService';
    import multer from 'multer';
    
    const mMulter = {
      array: jest.fn(),
    };
    
    jest.mock('multer', () => {
      const multer = jest.fn(() => mMulter);
      const oMulter = jest.requireActual('multer');
      for (let prop in oMulter) {
        if (oMulter.hasOwnProperty(prop)) {
          multer[prop] = oMulter[prop];
        }
      }
      return multer;
    });
    
    describe('65317652', () => {
      afterAll(() => {
        jest.resetAllMocks();
      });
      let validationFn: jest.Mock<any, any>;
      beforeEach(() => {
        validationFn = jest.fn();
      });
    
      afterEach(() => {
        validationFn.mockClear();
      });
    
      it('should pass', () => {
        const fileService = new FileService();
        fileService.uploadFiles(StorageType.DISK, validationFn);
        expect(multer).toBeCalled();
        expect(mMulter.array).toHaveBeenCalledWith('files', 5);
      });
    });
    

    unit test result:

     PASS  examples/65317652/fileService.test.ts
      65317652
        ✓ should pass (3 ms)
    
    ----------------|---------|----------|---------|---------|-------------------
    File            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ----------------|---------|----------|---------|---------|-------------------
    All files       |   84.62 |      100 |   71.43 |   84.62 |                   
     fileService.ts |   84.62 |      100 |   71.43 |   84.62 | 19-22             
    ----------------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        4.693 s