如何通过使用反应测试库更新上下文提供程序中的值来调用 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
});
我不知道该怎么做
- 在
MyComponent
被 @testing-library/react
的渲染函数渲染后更新 MyContext
中的 date
值
- 查看
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
我正在尝试的是测试依赖于上下文的组件是否调用 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
});
我不知道该怎么做
- 在
MyComponent
被@testing-library/react
的渲染函数渲染后更新 - 查看
date
更新后是否调用了useEffect
MyContext
中的 date
值
我已经在谷歌上搜索了几个小时,但没有找到任何解决方案。 任何建议将不胜感激。
您可以使用 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