• [React Testing] React Testing library note


    https://github.com/kentcdodds/react-testing-library-course/commit/1148e920b8d055d9ca9ef1c372e233d2e950ff1f

    User-event:

    https://testing-library.com/docs/ecosystem-user-event/

    Jest-dom:

    https://github.com/testing-library/jest-dom#with-typescript

    jest-axe

    https://github.com/nickcolley/jest-axe

    getBy* vs queryBy*

    getBy*: if not found, throw error, sometime you don't want test fail because no element found.

    queryBy*: if not found, return null, so you can do .toBeNull()

    Mock

    import React from 'react'
    import {render, screen} from '@testing-library/react'
    import userEvent from '@testing-library/user-event'
    import {reportError as mockReportError} from '../api'
    import {ErrorBoundary} from '../error-boundary'
    
    jest.mock('../api')
    
    beforeAll(() => {
      jest.spyOn(console, 'error').mockImplementation(() => {})
    })
    
    afterAll(() => {
      console.error.mockRestore()
    })
    
    afterEach(() => {
      jest.clearAllMocks()
    })
    
    function Bomb({shouldThrow}) {
      if (shouldThrow) {
        throw new Error('')
      } else {
        return null
      }
    }
    
    test('calls reportError and renders that there was a problem', async () => {
      mockReportError.mockResolvedValueOnce({success: true})
      const {rerender} = render(<Bomb />, {wrapper: ErrorBoundary})
    
      rerender(<Bomb shouldThrow={true} />)
    
      const error = expect.any(Error)
      const info = {componentStack: expect.stringContaining('Bomb')}
      expect(mockReportError).toHaveBeenCalledWith(error, info)
      expect(mockReportError).toHaveBeenCalledTimes(1)
    
      expect(console.error).toHaveBeenCalledTimes(2)
    
      expect(screen.getByRole('alert').textContent).toMatchInlineSnapshot(
        `"There was a problem."`,
      )
    
      console.error.mockClear()
      mockReportError.mockClear()
    
      rerender(<Bomb />)
    
      await userEvent.click(screen.getByText(/try again/i))
    
      expect(mockReportError).not.toHaveBeenCalled()
      expect(console.error).not.toHaveBeenCalled()
      expect(screen.queryByRole('alert')).not.toBeInTheDocument()
      expect(screen.queryByText(/try again/i)).not.toBeInTheDocument()
    })

    Mock a component from 3rd-party library, skip 1000ms transition, make test run faster

    import React from 'react'
    import {render, screen} from '@testing-library/react'
    import userEvent from '@testing-library/user-event'
    import {HiddenMessage} from '../hidden-message'
    
    jest.mock('react-transition-group', () => {
      return {
        CSSTransition: (props) => (props.in ? props.children : null),
      }
    })
    
    test('shows hidden message when toggle is clicked', async () => {
      const myMessage = 'hello world'
      render(<HiddenMessage>{myMessage}</HiddenMessage>)
      const toggleButton = screen.getByText(/toggle/i)
      expect(screen.queryByText(myMessage)).not.toBeInTheDocument()
      await userEvent.click(toggleButton)
      expect(screen.getByText(myMessage)).toBeInTheDocument()
      await userEvent.click(toggleButton)
      expect(screen.queryByText(myMessage)).not.toBeInTheDocument()
    })

    http jest mock:

    import React from 'react'
    import {render, screen, waitFor} from '@testing-library/react'
    import userEvent from '@testing-library/user-event'
    import {loadGreeting as mockLoadGreeting} from '../api'
    import {GreetingLoader} from '../greeting-loader-01-mocking'
    
    jest.mock('../api')
    
    test('loads greetings on click', async () => {
      const testGreeting = 'TEST_GREETING'
      mockLoadGreeting.mockResolvedValueOnce({data: {greeting: testGreeting}})
      render(<GreetingLoader />)
      const nameInput = screen.getByLabelText(/name/i)
      const loadButton = screen.getByText(/load/i)
      await userEvent.type(nameInput, 'Mary')
      await userEvent.click(loadButton)
      expect(mockLoadGreeting).toHaveBeenCalledWith('Mary')
      expect(mockLoadGreeting).toHaveBeenCalledTimes(1)
      await waitFor(() =>
        expect(screen.getByLabelText(/greeting/i)).toHaveTextContent(testGreeting),
      )
    })

     msw for mock http server

    npm i whatwg-fetch

    npm i msw

    import 'whatwg-fetch'
    import * as React from 'react'
    import {render, screen, waitFor} from '@testing-library/react'
    import userEvent from '@testing-library/user-event'
    import {rest} from 'msw'
    import {setupServer} from 'msw/node'
    import {GreetingLoader} from '../greeting-loader-01-mocking'
    
    const server = setupServer(
      rest.post('/greeting', (req, res, ctx) => {
        return res(ctx.json({data: {greeting: `Hello ${req.body.subject}`}}))
      }),
    )
    
    beforeAll(() => server.listen({onUnhandledRequest: 'error'}))
    afterAll(() => server.close())
    afterEach(() => server.resetHandlers())
    
    test('loads greetings on click', async () => {
      render(<GreetingLoader />)
      const nameInput = screen.getByLabelText(/name/i)
      const loadButton = screen.getByText(/load/i)
      userEvent.type(nameInput, 'Mary')
      userEvent.click(loadButton)
      await waitFor(() =>
        expect(screen.getByLabelText(/greeting/i)).toHaveTextContent('Hello Mary'),
      )
    })

    Test Unmounting a React Component with React Testing Library

    Sometimes your react component may need to do some cleanup work in the return value from useEffect or useLayoutEffect, or the componentWillUnmount lifecycle method for class components. Luckily for us, as far as React Testing Library is concerned, whichever of those you use is an implementation detail, so your test looks exactly the same regardless of how you implement it. Check out how you can test that simply with React Testing Library and a <Countdown /> component.

    import React from 'react'
    import {render, act} from '@testing-library/react'
    import {Countdown} from '../countdown'
    
    beforeAll(() => {
      jest.spyOn(console, 'error').mockImplementation(() => {})
    })
    
    afterAll(() => {
      console.error.mockRestore()
    })
    
    afterEach(() => {
      jest.clearAllMocks()
      jest.useRealTimers()
    })
    
    test('does not attempt to set state when unmounted (to prevent memory leaks)', () => {
      jest.useFakeTimers() // we don't want to wait 10 seconds
      const {unmount} = render(<Countdown />)
      unmount()
      act(() => jest.runOnlyPendingTimers()) // Using act with useFakeTimers()
      expect(console.error).not.toHaveBeenCalled()
    })

    Improve Reliability of Integration Tests using find* Queries from React Testing Library

    By using some of the get queries, we’re assuming that those elements will be available on the page right when we execute the query. This is a bit of an implementation detail and it’d be cool if we could not make that assumption in our test. Let’s swap all those for find queries.

      await userEvent.click(await findByText(/fill.*form/i))
      await userEvent.click(await screen.findByText(/fill.*form/i))

    Router testing

    import React from 'react'
    import {BrowserRouter} from 'react-router-dom'
    import {render, screen} from '@testing-library/react'
    import userEvent from '@testing-library/user-event'
    import {Main} from '../main'
    
    test('main renders about and home and I can navigate to those pages', () => {
      window.history.pushState({}, 'Test page', '/')
      render(
        <BrowserRouter>
          <Main />
        </BrowserRouter>,
      )
      expect(screen.getByRole('heading')).toHaveTextContent(/home/i)
      userEvent.click(screen.getByText(/about/i))
      expect(screen.getByRole('heading')).toHaveTextContent(/about/i)
    })
    
    test('landing on a bad page shows no match component', () => {
      window.history.pushState({}, 'Test page', '/something-that-does-not-match')
      render(
        <BrowserRouter>
          <Main />
        </BrowserRouter>,
      )
      expect(screen.getByRole('heading')).toHaveTextContent(/404/i)
    })

    Write a Setup Function to Reduce Duplication of Testing Custom React Hooks

    import React from 'react'
    import {render, act} from '@testing-library/react'
    import {useCounter} from '../use-counter'
    
    function setup({initialProps} = {}) {
      const result = {}
      function TestComponent(props) {
        result.current = useCounter(props)
        return null
      }
      render(<TestComponent {...initialProps} />)
      return result
    }
    
    test('exposes the count and increment/decrement functions', () => {
      const result = setup()
      expect(result.current.count).toBe(0)
      act(() => result.current.increment())
      expect(result.current.count).toBe(1)
      act(() => result.current.decrement())
      expect(result.current.count).toBe(0)
    })
    
    test('allows customization of the initial count', () => {
      const result = setup({initialProps: {initialCount: 3}})
      expect(result.current.count).toBe(3)
    })
    
    test('allows customization of the step', () => {
      const result = setup({initialProps: {step: 2}})
      expect(result.current.count).toBe(0)
      act(() => result.current.increment())
      expect(result.current.count).toBe(2)
      act(() => result.current.decrement())
      expect(result.current.count).toBe(0)
    })
    
    test('the step can be changed', () => {
      const {result, rerender} = renderHook(useCounter, {
        initialProps: {step: 3},
      })
      expect(result.current.count).toBe(0)
      act(() => result.current.increment())
      expect(result.current.count).toBe(3)
      rerender({step: 2})
      act(() => result.current.decrement())
      expect(result.current.count).toBe(1)
    })

    Test React Portals with within from React Testing Library

     When you use a React Portal, much of your component can be rendered outside the main DOM tree. Let’s see how we can use utilities provided by React Testing Library to allow us to select elements within the portal. To perform actions and assert on what’s rendered.

    
    
    import React from 'react'
    import {render, within} from '@testing-library/react'
    import {Modal} from '../modal'
    
    test('modal shows the children', () => {
      render(
        <Modal>
          <div data-testid="test" />
        </Modal>,
      )
      const {getByTestId} = within(document.getElementById('modal-root')) // within: only look for elements inside Modal
      expect(getByTestId('test')).toBeInTheDocument()
    })
  • 相关阅读:
    csu 1965
    csu 1947 三分
    Codeforces 336C 0-1背包
    POJ 1743 后缀数组
    POJ 2774 后缀数组
    UVA 12333 大数,字典树
    POJ 2942 圆桌骑士
    POJ 1503 大整数
    POJ 2342 树的最大独立集
    POJ 3088 斯特林
  • 原文地址:https://www.cnblogs.com/Answer1215/p/16803172.html
Copyright © 2020-2023  润新知