如何通过使用反应测试库更新上下文提供程序中的值来调用 useEffect?

How to call useEffect by updating values in a Context provider with react testing library?

我正在尝试的是测试依赖于上下文的组件是否调用 useEffect 以及是否从那里调用函数(被 jest.fn() 模拟)。

这是我的代码的简化版本:

MyComponent.tsx

export function MyComponent() {
    const ref = createRef();
    const { date } = useMyContext(); // "date" is a string (e.g. `2021-11-01`) 

    useEffect(() => {
        if (date && ref.current) 
            ref.current.scrollIntoView();
    }, [date, ref]);

    return (
        <div>
            {/* some other elements are here */}
            <AnotherComponent ref={ref} />
        </div>
    );
}

MyComponent.test.tsx

it('should scroll into AnotherComponent when date is updated', () => {
    const mockContextValue = { date: '2021-11-01' };
    window.HTMLElement.prototype.scrollIntoView = jest.fn();

    render(
        <MyContext.Provider value={mockContextValue}>
            <MyComponent />
        </MyContext.Provider>,
    );

    // update the date in MyContext.Provider 

    // then, useEffect should be called

    // then, expect scrollIntoView was called
});

我不知道该怎么做

  1. MyComponent@testing-library/react
  2. 的渲染函数渲染后更新 MyContext 中的 date
  3. 查看date更新后是否调用了useEffect

我已经在谷歌上搜索了几个小时,但没有找到任何解决方案。 任何建议将不胜感激。

您可以使用 RTL 的 rerender 函数,此函数可用于更新渲染组件的道具或上下文。

此外,您不需要声明要调用的 useEffect 挂钩。因为当Dependencies改变时,它会再次被调用,这是一个已经完全测试过的行为,我们不需要测试它。

我们也可以通过断言.scrollIntoView()是否被调用来间接断言useEffect被调用

例如

MyComponent.tsx:

import React from 'react';
import { createRef, useContext, useEffect } from 'react';
import { AnotherComponent } from './AnotherComponent';

export const MyContext = React.createContext({ date: '' });

export function MyComponent() {
  const ref = createRef<HTMLDivElement>();
  const { date } = useContext(MyContext);

  useEffect(() => {
    if (date && ref.current) {
      console.log('date: ', date);
      ref.current.scrollIntoView();
    }
  }, [date, ref]);

  return (
    <div>
      <AnotherComponent ref={ref} />
    </div>
  );
}

AnotherComponent.tsx:

import React from 'react';

export const AnotherComponent = React.forwardRef<HTMLDivElement>((props, ref) => {
  return <div ref={ref}>another</div>;
});

MyComponent.test.tsx:

import { render } from '@testing-library/react';
import React from 'react';
import { MyComponent, MyContext } from './MyComponent';

describe('70068118', () => {
  it('should scroll into AnotherComponent when date is updated', () => {
    const mScrollIntoView = jest.fn();
    window.HTMLElement.prototype.scrollIntoView = mScrollIntoView;

    const { rerender } = render(
      <MyContext.Provider value={{ date: '' }}>
        <MyComponent />
      </MyContext.Provider>
    );
    expect(mScrollIntoView).not.toBeCalled();

    rerender(
      <MyContext.Provider value={{ date: '2021-11-01' }}>
        <MyComponent />
      </MyContext.Provider>
    );
    expect(mScrollIntoView).toBeCalled();
  });
});

测试结果:

 PASS  examples/70068118/MyComponent.test.tsx (9.695 s)
  70068118
    ✓ should scroll into AnotherComponent when date is updated (39 ms)

  console.log
    date:  2021-11-01

      at examples/70068118/MyComponent.tsx:13:15

----------------------|---------|----------|---------|---------|-------------------
File                  | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------------------|---------|----------|---------|---------|-------------------
All files             |     100 |      100 |     100 |     100 |                   
 AnotherComponent.tsx |     100 |      100 |     100 |     100 |                   
 MyComponent.tsx      |     100 |      100 |     100 |     100 |                   
----------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        10.281 s