13

下面的测试通过了,但我两次收到以下警告,我不知道为什么。有人可以帮我弄清楚吗?

    console.error
    Warning: You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);
      at printWarning (../../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:120:30)
      at error (../../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:92:5)
      at ../../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14953:13
      at tryCallOne (../../node_modules/react-native/node_modules/promise/lib/core.js:37:12)
      at ../../node_modules/react-native/node_modules/promise/lib/core.js:123:15
      at flush (../../node_modules/asap/raw.js:50:29)
import { fireEvent } from '@testing-library/react-native'
import { renderScreen } from 'test/render'

describe('screens/home', () => {
  it('should render and redirect to the EventScreen', async () => {
    const {
      getByA11yLabel,
      findByA11yLabel,
      findAllByA11yLabel,
      toJSON
    } = renderScreen('Main')
    expect(toJSON()).toMatchSnapshot('Default render')

    const title = 'New event'
    const titleInput = getByA11yLabel('event.title')

    // Change title - sync fn
    fireEvent.changeText(titleInput, title)

    // Create button should be visible
    const createButton = await findByA11yLabel('event.create')
    expect(titleInput.props.value).toBe(title)
    expect(createButton).toBeTruthy()
    expect(toJSON()).toMatchSnapshot('Change title')

    // Create event - async fn
    fireEvent.press(createButton)

    // The app should be redirected to the EventScreen
    const titleInputs = await findAllByA11yLabel('event.title')
    const upsertButton = await findByA11yLabel('event.upsert')
    expect(toJSON()).toMatchSnapshot('Create event')
    expect(titleInputs).toHaveLength(2)
    expect(titleInputs[0].props.value).toBe('') // @MainScreen
    expect(titleInputs[1].props.value).toBe(title) // @EventScreen
    expect(upsertButton).toBeTruthy()
  })
})
  • 据我所知,没有必要fireEventact-链接包装
  • findBy*也被自动包装act-链接
  • GitHub中的相关问题仍未解决

依赖项:

  • 反应:16.13.1
  • 世博会:39.0.4
  • 开玩笑:26.6.3
  • ts-开玩笑:26.4.4
  • 开玩笑博览会:39.0.0
  • @testing-library/jest-native:3.4.3
  • @测试库/反应:11.2.2
  • @testing-library/react-native:7.1.0
  • 反应测试渲染器:16.13.1
  • 打字稿:4.1.2
4

2 回答 2

2

如果您已经用尽所有其他调试工作并且非常确定您的代码编写正确,则可能与用模拟react-native/jest-preset替换有关(请参阅问题)。global.Promise

在这种情况下,问题的解决方案是覆盖/修补 jest 预设以首先保存原始全局 Promise,应用react-native/jest-preset然后恢复原始 Promise(覆盖模拟版本)。这使我可以await在与渲染无关的测试中使用而不会触发可怕的

console.error
Warning: You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);

此片段显示了执行此补丁的一种方法:https ://github.com/sbalay/without_await/commit/64a76486f31bdc41f5c240d28263285683755938

于 2021-09-16T02:58:13.493 回答
2

我面临着同样的问题。对于我的情况,我useEffect在我的组件中使用。在测试时,它提示我将渲染包装在一个act()调用中。一旦我这样做了,即act(async () => ...)我最初的问题得到解决,但我得到了上述错误(Warning: You called act(async () => ...) without await.)。我不得不await act(async () => ...)在我的测试中使用来解决这个问题。虽然我仍然不确定为什么需要它。

作为参考,我正在添加一个完整的示例组件和相应的测试await act(async () => ...);

LocationComponent.tsx

/** @jsx jsx */
import { jsx } from 'theme-ui';
import { FunctionComponent, useEffect, useState } from 'react';

type Coordinate = {
  latitude: number;
  longitude: number;
};

const LocationComponent: FunctionComponent<any> = () => {
  const [coordinate, setCoordinate] = useState<Coordinate>();
  const [sharedLocation, setSharedLocation] = useState<boolean>();
  useEffect(() => {
    let mounted = true;

    if (!coordinate && navigator) {
      navigator.geolocation.getCurrentPosition(function (position) {
        setCoordinate({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
        });
      });
      navigator.permissions
        .query({ name: 'geolocation' })
        .then(function (result) {
          if (mounted) setSharedLocation(result.state === 'granted');
        });
    }

    return () => (mounted = false);
  });

  return (
    <>
      <div>Location shared:{sharedLocation ? 'Yes' : 'No'}</div>
      <div>Latitude:{coordinate?.latitude}</div>
      <div>Longitude:{coordinate?.longitude}</div>
    </>
  );
};
export default LocationComponent;

LocationComponent.spec.tsx

import React from 'react';
import { render, waitFor } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import LocationComponent from '../../../../../src/components/scheduler/location/LocationComponent';

const TEST_COORDS = {
  latitude: 41.8817089,
  longitude: -87.643301,
};

global.navigator.permissions = {
  query: jest
    .fn()
    .mockImplementationOnce(() => Promise.resolve({ state: 'granted' })),
};

global.navigator.geolocation = {
  getCurrentPosition: jest.fn().mockImplementationOnce((success) =>
    Promise.resolve(
      success({
        coords: TEST_COORDS,
      })
    )
  ),
};

describe("Location Component when location share is 'granted'", () => {
  it('should display current location details', async () => {
    await act(async () => {
      const { getByText } = render(<LocationComponent />);

      /*expect(
        await waitFor(() => getByText('Location shared:Yes'))
      ).toBeInTheDocument();*/
      expect(
        await waitFor(() => getByText('Latitude:41.8817089'))
      ).toBeInTheDocument();
      expect(
        await waitFor(() => getByText('Longitude:-87.643301'))
      ).toBeInTheDocument();
    });
  });
});

于 2020-11-25T02:18:27.923 回答