React 测试库:如何测试包含 useLocation() 的组件?

Dar*_*now 5 testing reactjs react-router react-testing-library redwoodjs

我正在使用RedwoodJS,它在后台使用 React 和 React 测试库。由于 useLocation() 挂钩,我正在努力测试一个组件(以及树中具有此组件的所有页面组件)。

\n

当在我的组件中使用useLocation()钩子时,我需要使用模拟浏览器位置历史记录的路由器来包装我的正在测试的组件以防止错误Error: Uncaught [TypeError: Cannot read property \'pathname\' of undefined]

\n

然而,当我这样做时,导航组件不再完全呈现,所以我无法测试它......有什么想法吗?

\n

导航.js

\n
//import statements\n\nconst renderListItems = (pathname) => {\n  const NavigationItems = [{..},{..},{..}] // example\n\n  return NavigationItems.map((item) => {\n    const selected = pathname.indexOf(item.path) ? false : true\n    return (\n      <ListItem\n        button\n        key={item.text}\n        onClick={() => {\n          navigate(item.route)\n        }}\n        selected={selected}\n      >\n        <ListItemText primary={item.text} />\n      </ListItem>\n    )\n  })\n}\n\nconst Navigation = () => {\n  const { pathname } = useLocation() // this is why I need to wrap the Navigation component in a router for testing; I\'m trying to get the current pathname so that I can give a specific navigation item an active state.\n\n  return (\n    <List data-testid="navigation" disablePadding>\n      {renderListItems(pathname)}\n    </List>\n  )\n}\n\nexport default Navigation\n\n
Run Code Online (Sandbox Code Playgroud)\n

导航.test.js

\n
import { screen } from \'@redwoodjs/testing\'\nimport { renderWithRouter } from \'src/utilities/testHelpers\'\n\nimport Navigation from \'./Navigation\'\n\ndescribe(\'Navigation\', () => {\n  it(\'renders successfully\', () => {\n    expect(() => {\n      renderWithRouter(<Navigation />)\n    }).not.toThrow()\n  })\n  it(\'has a "Dashboard" navigation menu item\', () => {\n    renderWithRouter(<Navigation />)\n    expect(\n      screen.getByRole(\'button\', { text: /Dashboard/i })\n    ).toBeInTheDocument()\n  })\n})\n\n
Run Code Online (Sandbox Code Playgroud)\n

testHelpers.js

\n

这是为了防止Navigation.jsuseLocation()内部破坏测试所必需的。

\n
import { Router, Route } from \'@redwoodjs/router\'\nimport { createMemoryHistory } from \'history\'\nimport { render } from \'@redwoodjs/testing\'\nconst history = createMemoryHistory()\n\nexport const renderWithRouter = (Component) =>\n  render(\n    <Router history={history}>\n      <Route component={Component} />\n    </Router>\n  )\n
Run Code Online (Sandbox Code Playgroud)\n

结果错误

\n
Navigation \xe2\x80\xba has a "Dashboard" navigation menu item\n\nTestingLibraryElementError: Unable to find an accessible element with the role "button"\n\n    There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the `hidden` option to `true`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole\n\n    <body>\n      <div />\n    </body>\n
Run Code Online (Sandbox Code Playgroud)\n

Jon*_*ern 0

您可以模拟useLocation返回您想要的路径名。这可以适用于任何函数

简单的


//Put within testing file
jest.mock("router-package", () => ({
  ...jest.requireActual("router-package"),
  useLocation: () => ({
    pathname: "customPath/To/Return"
  })
}));
Run Code Online (Sandbox Code Playgroud)

详细的

您可以创建一个辅助函数,您可以在其中传递path( string),它会自动为您模拟它

随机测试.js

import { setUpPageRender } from 'src/utilities/testHelpers'
import Navigation from './Navigation'

describe('Navigation', () => {
  //Where we set up our custom path for the describe
  const render = setUpPageRender('/customPathForThisDescribe/Foo')

  it('renders successfully', () => {
    expect(() => {
      render(<Navigation />)
    }).not.toThrow()
  })
})

Run Code Online (Sandbox Code Playgroud)

testHelpers.js

//Mocked Functions
jest.mock('router-package', () => ({
  __esModule: true,
  ...jest.requireActual('router-package'),
  useLocation: jest.fn(),
}))
import { useLocation } from 'router-package'


export const setUpPageRender = (location) => {
  useLocation.mockReturnValue(location)

  beforeEach(() => {
    jest.clearAllMocks()
  })

  return (component) => {
    return render( <Router history={history}>
      <Route component={Component} />
    </Router>)
  }
}
Run Code Online (Sandbox Code Playgroud)