Как смоделировать и протестировать метод, который обертывает функцию модуля с помощью Jest? - PullRequest
0 голосов
/ 28 января 2020

Я написал функцию, которая использует модуль pushover-notifications для отправки уведомлений через Pushover. Это выглядит следующим образом:

const Push = require('pushover-notifications')

const sendPushoverNotification = (message) => {
    const p = new Push({
        user: process.env.PUSHOVER_USER_KEY,
        token: process.env.PUSHOVER_AUTH_TOKEN,
        onerror: (error) => {} // Needs to be specified since this error cannot be caught in the p.send block.
    })

    const msg = {
        // These values correspond to the parameters for msg are detailed on https://pushover.net/api
        // 'message' is required. All other values are optional.
        message,    // Required.
        title: 'Title',
        sound: 'pushover',
        priority: 1
    }

    p.send(msg, (error, result) => {
        if (error) {
            console.error('[Pushover] An error occurred.')
            console.error(error)
        }

        if (JSON.parse(result).status === 1) { // Status 1 means push was sent successfully.
            console.log('[Pushover] Push notification sent.')
        } else {
            console.error('[Pushover] An error occurred.')
            console.error(result)
        }
    })
}

module.exports = sendPushoverNotification

Я хочу смоделировать p.send(msg, (error, result) так, чтобы сработал кодовый блок под ним, который либо регистрирует [Pushover] An error occurred., либо [Pushover] Push notification sent..

В файле с именем tests/__mocks__/pushover-notifications.js для макета модуля со следующим кодом у меня есть:

function Pushover() {

}

Pushover.prototype.send = () => {
    console.log('Message sent')
}

module.exports = {
    Pushover
}

Под tests/send-pushover-notification.test.js:

const sendPushoverNotification = require('../../src/send-pushover-notification')

test('Should send Pushover message', () => {
    sendPushoverNotification('message')
})

Ошибка Я получаю это от первого блока кода, который я отправил:

TypeError: Push is not a constructor

  2 | 
  3 | const sendPushoverNotification = (message) => {
> 4 |     const p = new Push({

1 Ответ

1 голос
/ 04 февраля 2020

Вы можете использовать jest.mock (moduleName, factory, options) mock pushover-notifications module.

Например

index.js:

const Push = require('pushover-notifications');

const sendPushoverNotification = (message) => {
  const p = new Push({
    user: process.env.PUSHOVER_USER_KEY,
    token: process.env.PUSHOVER_AUTH_TOKEN,
    onerror: (error) => {},
  });

  const msg = {
    message,
    title: 'Title',
    sound: 'pushover',
    priority: 1,
  };

  p.send(msg, (error, result) => {
    if (error) {
      console.error('[Pushover] An error occurred.');
      console.error(error);
      return;
    }

    if (JSON.parse(result).status === 1) {
      console.log('[Pushover] Push notification sent.');
    } else {
      console.error('[Pushover] An error occurred.');
      console.error(result);
    }
  });
};

module.exports = sendPushoverNotification;

index.test.js:

const sendPushoverNotification = require('.');
const Push = require('pushover-notifications');

jest.mock(
  'pushover-notifications',
  () => {
    const mPush = { send: jest.fn() };
    return jest.fn(() => mPush);
  },
  { virtual: true },
);

describe('59942177', () => {
  it('should send notification', () => {
    const p = new Push();
    const mResult = JSON.stringify({ status: 1 });
    p.send.mockImplementationOnce((msg, callback) => {
      callback(null, mResult);
    });
    const logSpy = jest.spyOn(console, 'log');
    sendPushoverNotification('message');
    expect(Push).toBeCalledWith({ user: undefined, token: undefined, onerror: expect.any(Function) });
    expect(p.send).toBeCalledWith(
      { message: 'message', title: 'Title', sound: 'pushover', priority: 1 },
      expect.any(Function),
    );
    expect(logSpy).toBeCalledWith('[Pushover] Push notification sent.');
  });

  it('should handle error if status is not equal 1', () => {
    const p = new Push();
    const mResult = JSON.stringify({ status: 2 });
    p.send.mockImplementationOnce((msg, callback) => {
      callback(null, mResult);
    });
    const errorLogSpy = jest.spyOn(console, 'error');
    sendPushoverNotification('message');
    expect(Push).toBeCalledWith({ user: undefined, token: undefined, onerror: expect.any(Function) });
    expect(p.send).toBeCalledWith(
      { message: 'message', title: 'Title', sound: 'pushover', priority: 1 },
      expect.any(Function),
    );
    expect(errorLogSpy).toBeCalledWith('[Pushover] An error occurred.');
    expect(errorLogSpy).toBeCalledWith(mResult);
  });

  it('should handle error if push failure', () => {
    const p = new Push();
    const mError = new Error('network error');
    p.send.mockImplementationOnce((msg, callback) => {
      callback(mError);
    });
    const errorLogSpy = jest.spyOn(console, 'error');
    sendPushoverNotification('message');
    expect(Push).toBeCalledWith({ user: undefined, token: undefined, onerror: expect.any(Function) });
    expect(p.send).toBeCalledWith(
      { message: 'message', title: 'Title', sound: 'pushover', priority: 1 },
      expect.any(Function),
    );
    expect(errorLogSpy).toBeCalledWith('[Pushover] An error occurred.');
    expect(errorLogSpy).toBeCalledWith(mError);
  });
});

Результаты модульных испытаний с отчетом о покрытии:

 PASS  src/stackoverflow/59942177/index.test.js
  59942177
    ✓ should send notification (16ms)
    ✓ should handle error if status is not equal 1 (2ms)
    ✓ should handle error if push failure (5ms)

  console.log node_modules/jest-mock/build/index.js:860
    [Pushover] Push notification sent.

  console.error node_modules/jest-mock/build/index.js:860
    [Pushover] An error occurred.

  console.error node_modules/jest-mock/build/index.js:860
    {"status":2}

  console.error node_modules/jest-mock/build/index.js:860
    [Pushover] An error occurred.

  console.error node_modules/jest-mock/build/index.js:860
    Error: network error
        at Object.it (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/59942177/index.test.js:49:20)
        at Object.asyncJestTest (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)
        at resolve (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
        at new Promise (<anonymous>)
        at mapper (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:26:19)
        at promise.then (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:73:41)
        at process._tickCallback (internal/process/next_tick.js:68:7)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |    66.67 |      100 |                   |
 index.js |      100 |      100 |    66.67 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        5.033s, estimated 10s

Исходный код: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59942177

...