【问题标题】:How to test a potential null value from an async void function without using @ts-ignore in TypeScript如何在 TypeScript 中不使用 @ts-ignore 从异步 void 函数测试潜在的空值
【发布时间】:2019-12-18 23:05:45
【问题描述】:

这可能更像是一个 JavaScript/TypeScript 问题,然后是关于 React/Testing。

但我会给出完整的故事。所以我有一个具有基本路由功能的测试应用程序和测试来验证路由是否有效。

App.tsx https://github.com/Leejjon/pwa-seo/blob/6f621968de1184b03744a262a68d291b4571c5c1/src/App.tsx

App.test.tsx https://github.com/Leejjon/pwa-seo/blob/6f621968de1184b03744a262a68d291b4571c5c1/src/App.test.tsx

一切正常。然后我添加了一个 useEffect 挂钩来初始化我的国际化库:

useEffect(() => {
    async function initMessages() {
        await intl.init({
            currentLocale: "en-US",
            locales
        });
    }

    initMessages().then(() => setLoading(false));
}, [loading]);

这会加载我所有的英文文本资源。这工作正常,但通过以下错误消息破坏了我的所有测试: Warning: An update to App inside a test was not wrapped in act(...).

在阅读了on the internet 之后,我设法通过添加这个“行为”功能来修复我的测试,这里是一个例子:

import React from 'react';
import {act, render, fireEvent, waitForElement} from '@testing-library/react';
import "@testing-library/jest-dom/extend-expect";
import App from './App';

test('Verify home page header', async() => {
    let app: HTMLElement;
    await act(async () => {
        const {container} = render(<App/>);
        app = container;
    });
    // @ts-ignore
    if (app) {
        const pageHeaderContent = app.querySelector("#pageHeader")?.firstChild?.textContent;
        expect(pageHeaderContent).toMatch('Home page');
    } else {
        fail("The app should have been initialized.");
    }
});

现在我正在使用@ts-ignore 抑制TS2454: Variable 'app' is used before being assigned. 警告。这很丑陋。如果我将断言移到 act 函数中,我会再次收到相同的 Warning: An update to App inside a test was not wrapped in act(...). 错误。

有没有办法从渲染函数中获取解构的容器对象,而不必使用@ts-ignore 和 if 子句进行空检查?

我为与这个问题相关的当前代码创建了一个标签: https://github.com/Leejjon/pwa-seo/releases/tag/uglylines 链接到最后一次提交:https://github.com/Leejjon/pwa-seo/commit/2434f78c0619be2d55f9de965149f6bd6d1a0b90

【问题讨论】:

  • 它可以是未定义的,但你声明它只是HTMLElement?
  • TypeScript 无法判断 act 是否会调用回调,也不能保证 app 会被定义。您可以尝试将 act 包装在另一个承诺中,该承诺将在回调内部使用 app 解决。在继续之前,您可能还需要等待 act 解决。
  • @alexey 说了什么。您可以在回调中移动测试代码。这会让 TS 闭嘴,因为它会保证 app 被定义。
  • @colefner 他试过了,但这违背了act 的目的,即允许 React 在使用expect 进行断言之前完成所有生命周期钩子。
  • 啊,是的,我错过了那部分。很好的收获,@AlexeyLebedev

标签: reactjs typescript jestjs react-testing-library


【解决方案1】:

Typescript 抱怨当您在 if 语句中访问 app 变量时尚未初始化它。您可以通过将null 分配给它来简单地解决这个问题。

let app: HTMLElement = null;

如果您使用严格的 null 检查,则必须在类型上允许 null:

let app: HTMLElement | null = null;

【讨论】:

    【解决方案2】:

    困惑后这是我的结果

    test('Verify home page header', async() => {
        let app: HTMLElement | undefined = undefined;
        await act(async () => {
            const {container} = render(<App/>);
            app = container;
        });
        let appAsHtmlElement = (app as unknown as HTMLElement);
        const pageHeaderContent = appAsHtmlElement.querySelector("#pageHeader")?.firstChild?.textContent;
        expect(pageHeaderContent).toMatch('Home page');
    });
    

    仍然欢迎更好的建议(如果有某种方式不必使用“act”功能)。

    【讨论】:

      猜你喜欢
      • 2021-02-10
      • 1970-01-01
      • 2022-11-10
      • 2018-12-12
      • 1970-01-01
      • 1970-01-01
      • 2019-11-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多