6

这是我的惰性组件:

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

4 回答 4

5

我不确定这是否是您正在寻找的答案,但听起来问题的一部分是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(例如 模拟Suspenselazy)上下文中的一些其他选项,这些选项也可能与sinon.

于 2020-01-30T03:25:56.647 回答
2

你不需要lazy()使用.then(x => x.default)React 来解析函数,它已经为你做了。

React.lazy 接受一个必须调用动态 import() 的函数。这必须返回一个 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-lazy-component-test


至于测试,你可以按照默认提供的 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()
})

实时示例:单击浏览器选项卡旁边的测试选项卡。如果它不起作用,只需重新加载页面。

编辑 react-lazy-component-testing

您可以在他们的Docs网站上找到更多react-testing-library复杂示例。

于 2020-01-24T12:24:10.190 回答
0

我需要使用 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");

这很 hacky,但对 Enzyme 库很有效。

于 2021-12-09T19:27:53.540 回答
-3

要模拟你的惰性组件,首先想到的是将测试转换为异步并等待组件存在,例如:

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();
}
于 2020-01-29T12:18:14.213 回答