ReactJs 18:新的自动批处理导致组件无法在 Karma 集成测试中渲染

问题描述 投票:0回答:1

我有一个应用程序,我只使用 createElement 方法渲染 React 组件,如下所示:

public static render<T>(target: HTMLElement, reactComponent: FC<T>, attrs: T) {
        const root = createRoot(target);

        root.render(
            React.createElement(reactComponent, attrs),
        );
    }

代码在浏览器中运行良好,但是一旦我测试整个页面(包括组件),该组件就不会呈现。 FC 代码仅在测试结束时调用,一次性执行所有操作。

我正在使用 Karma/Jasmine 和 ReactJS 18(具有本机自动批处理功能)测试我的应用程序,直到测试结束我的组件才呈现。

上面的代码已被修改为使用flushSync()来使其立即渲染,但是flushSync还需要在我的任何钩子上完成,这感觉有点矫枉过正。

public static render<T>(target: HTMLElement, reactComponent: FC<T>, attrs: T) {
        const root = createRoot(target);

        // Any state change needs to be sync for Karma test purposes.
        // In reality, we should not need it.
        // React 18 now batches changes, which Karma does not like.
        flushSync(() => root.render(
            React.createElement(reactComponent, attrs),
        ));
    }

有没有办法在集成测试(业力)中强制渲染,而不需要更改我的所有代码以使用flushSync?

谢谢

reactjs typescript karma-jasmine
1个回答
0
投票

所以我找到了解决问题的方法。

我创建了一个类如下,并在断言之前调用这个flush方法:

import { act } from "react-dom/test-utils";

export default class ReactJsActions {
    public static async flush() {
        await act(async () => {
            // tslint:disable-next-line: no-unused-expression
            await new Promise((resolve) => setTimeout(resolve));
        });
    }
}

这是我如何使用它的示例:

it("stuff", async () => {
    [code that would cause the state of the react component to change]
    await ReactJsActions.flush();
    expect([something]).toEqual([something]);
});

act 用于为断言准备组件,通常,在使用常用框架的reactjs 测试中,您会将正在执行的操作放在

act
lambda 方法中,然后在其后进行断言。就我而言,我正在执行一个reactjs无法控制的操作,因此将操作放入其中没有任何作用。

await new Promise((resolve) => setTimeout(resolve))
纳入该法案即可解决问题。

根据我的理解,带有

setTimeout(resolve)
且没有时间的新 Promise 将允许执行任何其他 setTimeout,我相信
scheduler
严重依赖于此,并且调度程序将用于批处理。

如果有人有更相关的原因,请分享。

© www.soinside.com 2019 - 2024. All rights reserved.