测试

react-router 依赖 React.context 来正常工作。这会影响你测试组件的方法。

Context

如果尝试对渲染等的组件之一进行单元测试,则会收到一些有关 Context 的错误和警告。虽然你会倾向于替换掉路由器的 context,我们建议您将测试用例用基础路由包裹,或者或者(如果 window.history 在测试环境中全局可用)。

建议使用 MemoryRouter 或自定义 history,以便能够在两次测试之间重置路由器。

class Sidebar extends Component {
  // ...
  render() {
    return (
      <div>
        <button onClick={this.toggleExpand}>expand</button>
        <ul>
          {users.map(user => (
            <li>
              <Link to={user.path}>{user.name}</Link>
            </li>
          ))}
        </ul>
      </div>
    )
  }
}

// 错误 ❌
test('it expands when the button is clicked', () => {
  render(<Sidebar />)
  click(theButton)
  expect(theThingToBeOpen)
})

// 正确 ✅
test('it expands when the button is clicked', () => {
  render(
    <MemoryRouter>
      <Sidebar />
    </MemoryRouter>
  )
  click(theButton)
  expect(theThingToBeOpen)
})

从特定的路由路径开始测试

<MemoryRouter>支持 initialEntriesinitialIndex 属性,所以你可以从任意路由开始您的测试。

test('current user is active in sidebar', () => {
  render(
    <MemoryRouter initialEntries={['/users/2']}>
      <Sidebar />
    </MemoryRouter>
  )
  expectUserToBeActive(2)
})

导航

我们进行了大量的测试来确保在 location 变化时候路由能够正确的渲染,所以你不必亲自测试它们。但如果你真的需要, 你可以这样测试:

// app.js (a component file)
import React from 'react'
import { Route, Link } from 'react-router-dom'

// our Subject, the App, but you can test any sub
// section of your app too
const App = () => (
  <div>
    <Route
      exact
      path="/"
      render={() => (
        <div>
          <h1>Welcome</h1>
        </div>
      )}
    />
    <Route
      path="/dashboard"
      render={() => (
        <div>
          <h1>Dashboard</h1>
          <Link to="/" id="click-me">
            Home
          </Link>
        </div>
      )}
    />
  </div>
)
// you can also use a renderer like "@testing-library/react" or "enzyme/mount" here
import { render, unmountComponentAtNode } from 'react-dom'
import { act } from 'react-dom/test-utils'
import { MemoryRouter } from 'react-router-dom'

// app.test.js
it('navigates home when you click the logo', async => {
  // 在真正的测试中 "@testing-library/react" 会为你生成真实测试dom
  const root = document.createElement('div')
  document.body.appendChild(root)

  // 渲染
  render(
    <MemoryRouter initialEntries={['/my/initial/route']}>
      <App />
    </MemoryRouter>,
    root
  )

  // 交互
  act(() => {
    // 找到需要点击的路由
    const goHomeLink = document.querySelector('#nav-logo-home')
    // 点击
    goHomeLink.dispatchEvent(new MouseEvent('click', { bubbles: true }))
  })

  // 验证正确的路由是否被渲染
  expect(document.body.textContent).toBe('Home')
})

在测试中验证 location

您不必在测试中经常访问 location 或 history 对象,但是如果这样做(例如,验证是否在 url 栏中设置了新的查询参数),则可以添加一条路由来更新测试中的变量:

// app.test.js
test('clicking filter links updates product query params', () => {
  let history, location
  render(
    <MemoryRouter initialEntries={['/my/initial/route']}>
      <App />
      <Route
        path="*"
        render={({ history, location }) => {
          history = history
          location = location
          return null
        }}
      />
    </MemoryRouter>,
    node
  )

  act(() => {
    // example: 点击 <Link> 到 /products?id=1234
  })

  // 验证url
  expect(location.pathname).toBe('/products')
  const searchParams = new URLSearchParams(location.search)
  expect(searchParams.has('id')).toBe(true)
  expect(searchParams.get('id')).toEqual('1234')
})

备择方案

  1. BrowserRouter 如果您的测试环境具有浏览器全局变量,window.location 并且也可以使用 window.history(这是 Jest 通过 JSDOM 的默认设置,但是您无法重置测试之间的历史记录)。
  2. 除了将自定义路由传递给 MemoryRouter 之外,您还可以将基数 Router 与包中的 historyprop 一起使用 history:

React 应用测试包

请参阅官方文档中的示例:使用React Testing Library测试 React Router

最后修改时间: 50 seconds ago