Модульный тест функции функционального компонента React

#reactjs #typescript #unit-testing #jestjs #react-functional-component

Вопрос:

есть ли в любом случае возможность модульного тестирования функции в функциональном компоненте react. Поскольку wrapper.instance() для функциональных компонентов будет возвращено значение null, каков наилучший способ включить эту функцию в тест, чтобы получить максимальный охват.

 
const SimpleFC: React.FC = () => {

    const callbackFunction = () => {
        // Do Stuffs
    }

    return (
        <ChildComponent callback={callbackFunction} />
    )
}

export { SimpleFC };
 

В этом сегменте кода как мы можем вызвать callbackFunction ?

Заранее спасибо

Комментарии:

1. Тесты IMHO не должны быть сосредоточены на деталях реализации . Утверждение о том, вызывается ли функция, не добавляет никакого значения . Вместо этого вам следует проверить, как изменяется пользовательский интерфейс при вызове этой функции xyz. Делает ли что-то добавленное в пользовательский интерфейс или удаленное из пользовательского интерфейса . Ваш тест должен быть больше сосредоточен на том, как пользователь будет использовать ваше приложение . Пользователю все равно, вызывается ли ваша функция обратного вызова . Все, что его волнует, — это то, что он видит в пользовательском интерфейсе .

2. Каково поведение , которое реализует обратный вызов? Как ChildComponent собирается запустить его?

3. @Shyam да, что заботит пользователя, так это изменение пользовательского интерфейса, но для изменения пользовательского интерфейса нам нужно запустить функцию. Мой вопрос в том, как вызвать функцию, не взаимодействуя с дочерним компонентом.

Ответ №1:

Поскольку вы используете wrapper.instance() API, я произвольно думаю, что вы используете enzyme библиотеку. Вы можете использовать .invoke(invokePropName)(…args) => Любой> метод для ChildComponent прямого вызова функции.

Напр.

SimpleFC.tsx :

 import React from 'react';
import ChildComponent from './ChildComponent';

const SimpleFC: React.FC = () => {
  const callbackFunction = () => {
    // Do Stuffs
    console.log('Do Stuffs');
  };

  return <ChildComponent callback={callbackFunction} />;
};

export { SimpleFC };
 

ChildComponent.tsx :

 import React from 'react';

export default function ChildComponent({ callback }) {
  return <div onClick={callback}>child component</div>;
}
 

SimpleFC.test.tsx :

 import { shallow } from 'enzyme';
import React from 'react';
import { SimpleFC } from './SimpleFC';

describe('67774847', () => {
  it('should pass', () => {
    const logSpy = jest.spyOn(console, 'log');
    const wrapper = shallow(<SimpleFC />);
    wrapper.invoke('callback')();
    expect(logSpy).toBeCalledWith('Do Stuffs');
    logSpy.mockRestore();
  });
});
 

результат теста:

  PASS  examples/67774847/SimpleFC.test.tsx (8.752 s)
  67774847
    ✓ should pass (48 ms)

  console.log
    Do Stuffs

      at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)

--------------------|---------|----------|---------|---------|-------------------
File                | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
--------------------|---------|----------|---------|---------|-------------------
All files           |      90 |      100 |   66.67 |      90 |                   
 ChildComponent.tsx |   66.67 |      100 |       0 |   66.67 | 4                 
 SimpleFC.tsx       |     100 |      100 |     100 |     100 |                   
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.654 s
 

Комментарии:

1. Я попробовал invoke сделать вот так wrapper.invoke('getCustomerAddress')() , я получаю сообщение об ошибке «Это выражение невозможно вызвать. Тип «никогда» не имеет сигнатур вызовов.Аргумент ts(2349) типа «строка» не может быть присвоен параметру типа «никогда».»

2. @sinthu225 Это проблема с типом TS, вы можете ввести any ее . Судя по вашему вопросу, я не могу воспроизвести эту проблему. В getCustomerAddress вашем вопросе нет опоры для функций.

3. Я отключил подкладку и наложил гипс как любой другой. Ошибка типа: ShallowWrapper::invoke() требует имени реквизита, значением которого является функция

4. const wrapper = shallow(<Foo />); wrapper.find('button').invoke('onClick')().then(() => { // expect() }); Это сработает, если у нас будет кнопка или что-нибудь в этом роде