你如何使用浅层测试酶 Reactjs 模拟 useLocation() 路径名?

IT技术 reactjs react-router jestjs enzyme
2021-05-07 20:46:18

我有如下标题组件:

import { useLocation } from "react-router-dom";

const Header = () => {
   let route = useLocation().pathname; 
   return route === "/user" ? <ComponentA /> : <ComponentB />;
}

您将如何模拟这个 useLocation() 以获取用户路径?

我不能简单地在我的测试文件中调用 Header 组件,因为我收到错误:

类型错误:无法在 useLocation 读取未定义的属性“位置”

describe("<Header/>", () => {
    it("call the header component", () => {
        const wrapper = shallow(<Header />);
        expect(wrapper.find(ComponentA)).toHaveLength(1);
    });
});

我试过看起来类似于链接如何使用新的react-router钩子测试组件?但它没有用。

我试过如下:

const wrapper = shallow(
      <Provider store={store}>
        <MemoryRouter initialEntries={['/abc']}>
          <Switch>
            <AppRouter />
          </Switch>
        </MemoryRouter>
      </Provider>,
    );
    jestExpect(wrapper.find(AppRouter)
      .dive()
      .find(Route)
      .filter({path: '/abc'})
      .renderProp('render', { history: mockedHistory})
      .find(ContainerABC)
    ).toHaveLength(1);

来自使用浅层渲染测试react-router的链接但它没有用。

请告诉我。

提前致谢。

4个回答

我发现我可以使用以下模式模拟像 useLocation 这样的 React Router 钩子:

import React from "react"
import ExampleComponent from "./ExampleComponent"
import { shallow } from "enzyme"

jest.mock("react-router-dom", () => ({
  ...jest.requireActual("react-router-dom"),
  useLocation: () => ({
    pathname: "localhost:3000/example/path"
  })
}));

describe("<ExampleComponent />", () => {
  it("should render ExampleComponent", () => {
    shallow(<ExampleComponent/>);
  });
});

如果您在 ExampleComponent 中调用了 useLocation,则上述模式应该允许您在 Enzyme / Jest 测试中浅渲染组件而不会出错。希望有帮助!

我最近也在纠结这个。。。

我发现这很好用:

import React from "react"
import ExampleComponent from "./ExampleComponent"
import { shallow } from "enzyme"

const mockUseLocationValue = {
    pathname: "/testroute",
    search: '',
    hash: '',
    state: null
}
jest.mock('react-router', () => ({
    ...jest.requireActual("react-router") as {},
    useLocation: jest.fn().mockImplementation(() => {
        return mockUseLocationValue;
    })
}));

describe("<ExampleComponent />", () => {
  it("should render ExampleComponent", () => {
    mockUseLocationValue.pathname = "test specific path";
    shallow(<ExampleComponent/>);
    ...
    expect(...
  });
});

通过这种方式,我能够模拟 useLocation 并根据需要在特定测试中为路径名提供值。

HTH

我知道这不是您问题的直接答案,但是如果您想要测试浏览器位置或历史记录,您可以使用mountRoute在最后添加一个额外的内容,您可以“捕获”历史记录和位置对象。

test(`Foobar`, () => {
  let testHistory
  let testLocation

  const wrapper = mount(
    <MemoryRouter initialEntries={[`/`]}>
      <MyRoutes />
      <Route
        path={`*`}
        render={routeProps => {
          testHistory = routeProps.history
          testLocation = routeProps.location
          return null
        }}/>
    </MemoryRouter>
  )

  // Manipulate wrapper

  expect(testHistory)...
  expect(testLocation)...
)}

你有没有尝试过:

describe("<Header/>", () => {
    it("call the header component", () => {
        const wrapper = shallow(<MemoryRouter initialEntries={['/abc']}><Header /></MemoryRouter>);
        expect(wrapper.find(Header).dive().find(ComponentA)).toHaveLength(1);
    });
});

使用shallow时只渲染第一个lvl,所以需要使用div来渲染另一个组件。