首页 > 解决方案 > React 测试库清理在 Jest 的描述块中不起作用

问题描述

我有一些正在进行的测试,这是按预期工作的:

describe('Parent', () => {
    afterEach(() => {
        cleanup();
        jest.resetModules();
    });

    describe('Test 1', () => {
        const wrapper = render(
            <MockProvider>
                <MyComponent />
            </MockProvider>,
        );

        test('1 ', () => {
            expect(wrapper.baseElement).toMatchSnapshot();
            expect(wrapper.getByText('Apply').disabled).toBe(true);
        });
    });

    describe('Test 2', () => {
        test('1 ', () => {
            const wrapper = render(
                <MockProvider>
                    <MyComponent />
                </MockProvider>,
            );
            console.log(wrapper.getByText('Apply').disabled);
            expect(1).toBe(1);
        });
    });
});

但是,当我将第二个渲染函数移出测试时,它会出错:

describe('Parent', () => {
    afterEach(() => {
        cleanup();
        jest.resetModules();
    });

    describe('Test 1', () => {
        const wrapper = render(
            <MockProvider>
                <MyComponent />
            </MockProvider>,
        );

        test('1 ', () => {
            expect(wrapper.baseElement).toMatchSnapshot();
            expect(wrapper.getByText('Apply').disabled).toBe(true);
        });
    });

    describe('Test 2', () => {
        const wrapper = render(
            <MockProvider>
                <MyComponent />
            </MockProvider>,
        );
        test('1 ', () => {
            console.log(wrapper.getByText('Apply').disabled);
            expect(1).toBe(1);
        });
    });
});

我得到的错误是

找到带有文本的多个元素:应用

我可以在控制台中看到组件被渲染了两次,所以我认为清理功能在描述块方面一定不能正常工作。这很奇怪,因为我们已经进行了 Enzyme 测试,并且设置和拆卸对这些都很好。

标签: jestjsreact-testing-library

解决方案


为了理解这一点,我们需要了解一点关于如何Jest运行我们的测试以及如何React Testing Library渲染我们的组件。


笑话

考虑下面的代码并尝试猜测输出将是什么

describe('First describe', () => {
  console.log('First describe');

  it('First test', () => {
    console.log('First test');
  });
});

describe('Second describe', () => {
  console.log('Second describe');

  it('Second test', () => {
    console.log('Second test');
  });
});

输出(悬停查看):

第一次描述
第二次描述
第一次测试
第二次测试

请注意,所有describe方法都是在测试开始运行之前初始化的。

这应该已经让您对问题有所了解,但现在让我们看看 RTL。


反应测试库

考虑下面的代码并尝试猜测 DOM 在控制台中的外观:

const Greeting = () => 'Hello world';

describe('First describe', () => {
  const wrapper = render(<Greeting />);

  it('First test', () => {
    console.log(wrapper.debug());
  });
});

describe('Second describe', () => {
  render(<Greeting />);
});

输出(悬停查看):

<body> <div>Hello world</div> <div>Hello world</div> </body>

当我们没有为render函数指定基本元素时,它总是使用相同的document.body

当我们不指定自定义容器时,<div>元素包装由 RTL 添加。Hello world

默认情况下,所有 RTL 查询都绑定到基本元素document.body——在这种情况下。

所以,

getByText('Hello world'); // will find two elements and throw


这就是RTL 中的代码在函数中的样子render。(半伪代码)

if(!baseElement) {
  baseElement = document.body // body will be shared across renders
}
if(!container) {
  baseElement.appendChild(document.createElement('div')) // wraps our component
}
ReactDOM.render(component, container)

return {  container, baseElement, ...getQueriesForElement(baseElement)  }


为了解决这个问题

执行以下操作之一:

  1. renderitortest方法中调用
  2. container在查询中指定
  3. 为每个指定不同的基本元素render

推荐阅读