使用Jest,useRouteMatch,react-route-dom进行动态测试

时间:2020-06-29 16:08:33

标签: jestjs react-router-dom

我有一个Switch组件,该组件基于一个以Routes作为参数并返回字符串的switch语句来呈现useRouteMatch().path

在单元测试中,我想动态模拟这一点,但是似乎每个文件只能设置一个jest.mock

SectionComponent.tsx:

import React from 'react'
import { useRouteMatch } from 'react-router-dom'

import * as strings from '../../../strings'
import Header from '../../shared/header/Header'

const SectionComponent: React.FC = ({ children }) => {
    const { path } = useRouteMatch()

    const sectionTitle = () => {
        switch (path) {
            case '/header':
                return strings.demo.header.title
            case '/navbars':
                return strings.demo.navbar.title
            case '/button':
                // ...etc
            default:
                return ''
        }
    }

    return (
        <div>
            <Header
                title={sectionTitle()}
                titleColor={strings.theme.orange}
                titleSize="S"
                bgColor={strings.theme.white}
                size="S"
            />
            {children}
        </div>
    )
}

export default SectionComponent

SectionComponent.spec.tsx:

import React from 'react'
import { render } from '@testing-library/react'
import SectionComponent from './SectionComponent'
import * as strings from '../../../strings'

// list I want to dynamically generate useRouteMatch().path and expected result from
const options = [
    { name: 'header', to: '/header' },
    { name: 'navbars', to: '/navbars' },
    { name: 'button', to: '/button' },
    { name: 'typography', to: '/typography' },
    { name: 'form', to: '/form' },
    { name: 'navs', to: '/navs' },
    { name: 'indicators', to: '/indicators' },
    { name: 'list-group', to: '/list-group' },
    { name: 'cards', to: '/cards' },
]

// Can only do this once per file
jest.mock('react-router-dom', () => ({
    ...jest.requireActual('react-router-dom'), // use actual for all non-hook parts
    useRouteMatch: () => ({ path: '/header' }), // return value can't access outside variables eg option.to ('/header')
}))

describe('SectionComponent', () => {
    // ideally want to map thorugh options and test here:
    it('should render with each Title', () => {
        const { getByText } = render(<SectionComponent />)

        expect(getByText(strings.demo.header.title)).toBeInTheDocument()
    })
})

有人有什么建议吗?如有必要,我很乐意提供更多信息

1 个答案:

答案 0 :(得分:0)

使用jest.fn().mockReturnValueOnce()多次找出解决方法

import React from 'react'
import { render } from '@testing-library/react'
import SectionComponent from './SectionComponent'

const options = [
    { name: 'Headers' },
    { name: 'Navbars' },
    { name: 'Button' },
    { name: 'Typography' },
    { name: 'Forms' },
    { name: 'Navs' },
    { name: 'Indicators' },
    { name: 'List Group' },
    { name: 'Cards' },
]

jest.mock('react-router', () => ({
    useRouteMatch: jest
        .fn()
        .mockReturnValueOnce({ path: '/header' })
        .mockReturnValueOnce({ path: '/navbars' })
        .mockReturnValueOnce({ path: '/button' })
        .mockReturnValueOnce({ path: '/typography' })
        .mockReturnValueOnce({ path: '/form' })
        .mockReturnValueOnce({ path: '/navs' })
        .mockReturnValueOnce({ path: '/indicators' })
        .mockReturnValueOnce({ path: '/list-group' })
        .mockReturnValueOnce({ path: '/cards' }),
}))

options.forEach(option => {
    describe('SectionComponent', () => {
        it('should render with each Title', () => {
            const { getByText } = render(<SectionComponent />)

            expect(getByText(option.name)).toBeInTheDocument()
        })
    })
})

Maybe not the most efficient but it works