Макет импортированного компонента Lazy React
Вот мой ленивый компонент:
const LazyBones = React.lazy(() => import('@graveyard/Bones')
.then(module => ({default: module.BonesComponent}))
export default LazyBones
Импортирую вот так:
import Bones from './LazyBones'
export default () => (
<Suspense fallback={<p>Loading bones</p>}>
<Bones />
</Suspense>
)
И в моем тесте у меня есть такие вещи:
import * as LazyBones from './LazyBones';
describe('<BoneYard />', function() {
let Bones;
let wrapper;
beforeEach(function() {
Bones = sinon.stub(LazyBones, 'default');
Bones.returns(() => (<div />));
wrapper = shallow(<BoneYard />);
});
afterEach(function() {
Bones.restore();
});
it('renders bones', function() {
console.log(wrapper)
expect(wrapper.exists(Bones)).to.equal(true);
})
})
Я ожидаю, что тест пройдет, а журнал console.log распечатает:
<Suspense fallback={{...}}>
<Bones />
</Suspense>
Но вместо <Bones />
я получил <lazy />
и он не проходит тест.
Как я могу имитировать импортированный компонент Lazy React, чтобы мой упрощенный тест прошел?
4 ответа
Я не уверен, что это именно тот ответ, который вы ищете, но похоже, что часть проблемы shallow
. Согласно этой теме,shallow
не будет работать с React.lazy
.
Однако, mount
также не работает при попытке заглушить ленивый компонент - если вы отлаживаете вывод DOM (с console.log(wrapper.debug())
) ты это видишь Bones
находится в DOM, но это настоящая (не заглушенная) версия.
Хорошие новости: если вы только пытаетесь это проверить Bones
существует, вам вообще не нужно имитировать компонент! Этот тест проходит:
import { Bones } from "./Bones";
import BoneYard from "./app";
describe("<BoneYard />", function() {
it("renders bones", function() {
const wrapper = mount(<BoneYard />);
console.log(wrapper.debug());
expect(wrapper.exists(Bones)).to.equal(true);
wrapper.unmount();
});
});
Если вам нужно издеваться над компонентом по другой причине, jest
позволит вам это сделать, но похоже, что вы пытаетесь избежать jest
. В этой ветке обсуждаются некоторые другие варианты в контекстеjest
(например,
издевательствоSuspense
а также lazy
), который также может работать с sinon
.
Вам не нужно разрешать lazy()
функция с помощью .then(x => x.default)
React уже делает это за вас.
React.lazy принимает функцию, которая должна вызывать динамический импорт (). Это должно вернуть Promise, который разрешается в модуль с экспортом по умолчанию, содержащим компонент React. Реагировать на разделение кода
Синтаксис должен выглядеть примерно так:
const LazyBones = React.lazy(() => import("./LazyBones"))
Пример:
// LazyComponent.js
import React from 'react'
export default () => (
<div>
<h1>I'm Lazy</h1>
<p>This component is Lazy</p>
</div>
)
// App.js
import React, { lazy, Suspense } from 'react'
// This will import && resolve LazyComponent.js that located in same path
const LazyComponent = lazy(() => import('./LazyComponent'))
// The lazy component should be rendered inside a Suspense component
function App() {
return (
<div className="App">
<Suspense fallback={<p>Loading...</p>}>
<LazyComponent />
</Suspense>
</div>
)
}
Что касается тестирования, вы можете следовать примеру тестирования React, который по умолчанию поставляется вcreate-react-app
и немного измените это.
Создайте новый файл с именем LazyComponent.test.js
и добавить:
// LazyComponent.test.js
import React, { lazy, Suspense } from 'react'
import { render, screen } from '@testing-library/react'
const LazyComponent = lazy(() => import('./LazyComponent'))
test('renders lazy component', async () => {
// Will render the lazy component
render(
<Suspense fallback={<p>Loading...</p>}>
<LazyComponent />
</Suspense>
)
// Match text inside it
const textToMatch = await screen.findByText(/I'm Lazy/i)
expect(textToMatch).toBeInTheDocument()
})
Живой пример: щелкните вкладку " Тесты" рядом с вкладкой " Браузер ". если не работает, просто перезагрузите страницу.
Вы можете найти больше сложных примеров реакции-тестирования-библиотеки на их сайте Документов.
Мне нужно было протестировать мой ленивый компонент с помощью Enzyme. Следующий подход помог мне проверить завершение загрузки компонента:
const myComponent = React.lazy(() =>
import('@material-ui/icons')
.then(module => ({
default: module.KeyboardArrowRight
})
)
);
Тестовый код ->
//mock actual component inside suspense
jest.mock("@material-ui/icons", () => {
return {
KeyboardArrowRight: () => "KeyboardArrowRight",
}
});
const lazyComponent = mount(<Suspense fallback={<div>Loading...</div>}>
{<myComponent>}
</Suspense>);
const componentToTestLoaded = await componentToTest.type._result; // to get actual component in suspense
expect(componentToTestLoaded.text())`.toEqual("KeyboardArrowRight");
Это хакерство, но хорошо работает для библиотеки Enzyme.
Чтобы издеваться над вашим ленивым компонентом, сначала подумайте, это преобразовать тест в асинхронный и подождать, пока компонент не появится, например:
import CustomComponent, { Bones } from './Components';
it('renders bones', async () => {
const wrapper = mount(<Suspense fallback={<p>Loading...</p>}>
<CustomComponent />
</Suspense>
await Bones;
expect(wrapper.exists(Bones)).toBeTruthy();
}