Jest模拟React上下文

ckx4rj1h  于 2023-06-20  发布在  Jest
关注(0)|答案(3)|浏览(154)

我需要一些帮助来理解如何使用ReactContext测试应用程序。
这是我的示例设置。

    • context. js**
import React from 'react'

export const AppContext = React.createContext()
    • App. js**
import React from 'react'

import MyComponent from './MyComponent'
import {AppContext} from './context'

const App extends React.Component {

  state = {
    items: []
  }

  handleItemAdd = newItem => {
    const {items} = this.state
    items.push(newItem)
    this.setState(items)
  }

  render() {
    return (
      <AppContext.Provider value={{
        addItem: this.handleItemAdd
      }}>
        <MyComponent />
      </AppContext.Provider>
    )
  }
}

export default App
    • MyComponent. js**
import React from 'react'

import {AppContext} from './context'

const MyComponent extends React.Component {    
  render() {
    return (
      <AppContext.Consumer>
        {addItem => 
          <button onClick={() => addItem('new item')}>
            Click me
          </button>
        }
      </AppContext.Consumer>
    )
  }
}

export default MyComponent

这是一个简化的示例。假设在AppMyComponent之间有更多的层,因此使用ReactContext
下面是我的MyComponent测试文件。

    • MyComponent. test. js**
import React from 'react'
import {render, fireEvent} from 'react-testing-library'

test('component handles button click', () => {
  const {getByText} = render(
    <MyComponent />
  )
  const button = getByText('Click me')
  fireEvent.click(button)
  expect...?
}

问题是,AppContext.ConsumerMyComponent实现的一部分,所以在这个测试中我不能直接访问它。如何模拟AppContext.Consumer,以便实际验证单击按钮是否会触发函数调用?
我知道理论上我可以通过在App中渲染MyComponent来测试它,但是我只想为MyComponent编写一个单元测试。

inn6fuwd

inn6fuwd1#

您只需使用组件呈现上下文。

const addItem = jest.fn()
render(
  <AppContext.Provider value={{ addItem }}>
    <MyComponent />
  </AppContext.Provider>
)

参见Mocking context with react-testing-library

km0tfn4u

km0tfn4u2#

我想通过使用@Giorgio的解决方案添加一个完整的测试示例。这里我们测试MyComponent是否被渲染,并且它的按钮是否被点击一次。

MyComponent.test.js

import React from 'react'
import { render, fireEvent } from 'react-testing-library'

test('component handles button click', () => {
  const addItem = jest.fn()
  render(
    <AppContext.Provider value={{ addItem }}>
      <MyComponent />
    </AppContext.Provider>
  )
  fireEvent.click(screen.getByText(/click me/))
  expect(addItem).toHaveBeenCalledTimes(1)
}
dwthyt8l

dwthyt8l3#

如果有任何TypeScript用户无法使用此解决方案,我想为任何有困难的人添加我的测试示例。
在我的例子中,我添加了一个定制的组件 Package 器,它可以在应用程序的测试环境中重用。如果您要测试嵌套在希望模拟的上下文中的多个组件,这会很方便。
作为奖励,我还模仿了rxjs行为主题,以防有人在测试中使用这个库:

// Create a mock BehaviorSubject instance
    class MockBehaviorSubject<T> extends BehaviorSubject<T> {
    constructor(initialValue: T) {
        super(initialValue);
    }

    // Override necessary methods
    getValue(): T {
        return this.getValue();
    }

    // Add any other required methods here
    // For example, you might need to add `next` method:
    // next(value: T): void {
    //   this.next(value);
    // }

    // Create a custom wrapper component to provide the mock context values
    export const MockAppProvider: React.FC<WithChildren> = ({ children }) => {
    // Define your mock context values here
    const id= 'test';

    // Create a mock BehaviorSubject instance
    const mockCreateObservablesCallbackSubject = new MockBehaviorSubject<
        TObservableEvent | undefined
    >(undefined);

    return (
        <AppProviderContext.Provider
            value={{
                id: mockCycleId,
                setId: jest.fn(),
                observables: undefined,
                setObservables: jest.fn(),
                createObservablesCallbackSubject: mockCreateObservablesCallbackSubject,
            }}
        >
            {children}
        </AppProviderContext.Provider>
    );
};

}

相关问题