Как протестировать/макетировать клиент socket.io

Я пытаюсь издеваться над методом emit из io, но я не знаю, как его издеваться. Это мой Join.jsx файл

//Join.jsx

import React from 'react';
import io from 'socket.io-client';

const Join = () => {
  let socket;
  const ENDPOINT = 'localhost:5000';

  const join = () => {
    socket = io(ENDPOINT);
    socket.emit('join', { name: 'Paola', room: '1' }, () => { });
  };

  return (
    <div className="join-container">
        <a className="join-button" onClick={join}>Sign in</a>
    </div>
  );
};

export default Join;

Это одна вещь, которую я пробовал

//Join.test.jsx
import React from 'react';
import { shallow } from 'enzyme';
import io from 'socket.io-client';
import Join from './Join';

describe(('Join') => {
  it(('joins a chat') => {
    jest.mock('socket.io-client', () => {
      return jest.fn(() => ({
        emit: jest.fn(),
      }));
    });
    const ENDPOINT = 'localhost:5000';
    const mockSocket = io(ENDPOINT);
    const joinWrapper = shallow(<Join />);
    joinWrapper.find('a').simulate('click');
    expect(mockSocket.emit).toHaveBeenCalledWith('join', { name: 'Paola', room: '1' }, () => { });
  })
})

Это ошибка, которую я получаю в терминале

expect(received).toHaveBeenCalledWith(...expected)

    Matcher error: received value must be a mock or spy function

    Received has type:  function
    Received has value: [Function anonymous]

      52 |     const joinWrapper = shallow(<Join />);
      53 |     joinWrapper.find('a').simulate('click');
    > 54 |     expect(mockSocket.emit).toHaveBeenCalledWith('join', { name: 'Paola', room: '1' }, () => { });
         |                             ^
      55 |   });
      56 | });
      57 | 

Пожалуйста, не будьте грубы с вашими ответами, я новичок в тестировании, и я действительно потерян. Заранее спасибо за ответы!!


person Paola Arredondo    schedule 26.08.2020    source источник
comment
Ваш подход довольно точен, вам просто нужно переместить блок jest.mock в область, где вы импортируете библиотеку, т.е. перед блоком описания   -  person Teneff    schedule 27.08.2020


Ответы (1)


В вашем тестовом коде есть три проблемы:

  1. Переместите блок кода jest.mock в область модуля. Он будет поднят в верхнюю часть блока кода. Это означает, что даже если вы сначала используете модуль import Join from './Join' (на уровне порядка написания кода), модуль socket.io-client будет фиктивной версией как для тестового файла, так и для недотестированного файла.

  2. Используйте ту же ссылку на фиктивный объект сокета в фиктивной фабрике, иначе объект сокета в тестовом коде и объект сокета в тестируемом коде не будут одной и той же ссылкой для каждого вызова функции io.

  3. Анонимные функции — это не та же ссылка, что и в тестовом коде. Таким образом, утверждение .toBeCalledWith() будет отклонено. Вместо этого вы должны использовать expect.any(Function).

Вот решение модульного теста:

Join.tsx:

import React from 'react';
import io from 'socket.io-client';

const Join = () => {
  let socket;
  const ENDPOINT = 'localhost:5000';

  const join = () => {
    socket = io(ENDPOINT);
    socket.emit('join', { name: 'Paola', room: '1' }, () => {});
  };

  return (
    <div className="join-container">
      <a className="join-button" onClick={join}>
        Sign in
      </a>
    </div>
  );
};

export default Join;

Join.test.tsx:

import React from 'react';
import { shallow } from 'enzyme';
import io from 'socket.io-client';
import Join from './Join';

jest.mock('socket.io-client', () => {
  const mSocket = {
    emit: jest.fn(),
  };
  return jest.fn(() => mSocket);
});

describe('Join', () => {
  it('joins a chat', () => {
    const ENDPOINT = 'localhost:5000';
    const mockSocket = io(ENDPOINT);
    const joinWrapper = shallow(<Join />);
    joinWrapper.find('a').simulate('click');
    expect(mockSocket.emit).toHaveBeenCalledWith('join', { name: 'Paola', room: '1' }, expect.any(Function));
  });
});

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

 PASS  src/stackoverflow/63605899/Join.test.tsx
  Join
    ✓ joins a chat (14ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |    66.67 |      100 |                   |
 Join.tsx |      100 |      100 |    66.67 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.162s, estimated 13s

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

person slideshowp2    schedule 07.09.2020