Merge pull request #7727 from backstage/test-utils-core

Move test-utils-core into test-utils
This commit is contained in:
Johan Haals
2021-10-25 11:09:16 +02:00
committed by GitHub
30 changed files with 263 additions and 221 deletions
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/test-utils': patch
'@backstage/test-utils-core': patch
---
Migrates all utility methods from `test-utils-core` into `test-utils` and delete exports from the old package.
This should have no impact since this package is considered internal and have no usages outside core packages.
Notable changes are that the testing tool `msw.setupDefaultHandlers()` have been deprecated in favour of `setupRequestMockHandlers()`.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/config': patch
'@backstage/core-app-api': patch
'@backstage/core-plugin-api': patch
---
Replace usage of test-utils-core with test-utils
+1 -1
View File
@@ -34,7 +34,7 @@
"lodash": "^4.17.21"
},
"devDependencies": {
"@backstage/test-utils-core": "^0.1.2",
"@backstage/test-utils": "^0.1.19",
"@types/jest": "^26.0.7",
"@types/node": "^14.14.32"
},
+1 -1
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { withLogCollector } from '@backstage/test-utils-core';
import { withLogCollector } from '@backstage/test-utils';
import { ConfigReader } from './reader';
const DATA = {
-1
View File
@@ -48,7 +48,6 @@
"devDependencies": {
"@backstage/cli": "^0.8.0",
"@backstage/test-utils": "^0.1.19",
"@backstage/test-utils-core": "^0.1.3",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2",
@@ -25,7 +25,7 @@ import {
import { ApiProvider } from './ApiProvider';
import { ApiRegistry } from './ApiRegistry';
import { render } from '@testing-library/react';
import { withLogCollector } from '@backstage/test-utils-core';
import { withLogCollector } from '@backstage/test-utils';
import { useVersionedContext } from '@backstage/version-bridge';
describe('ApiProvider', () => {
+1 -2
View File
@@ -45,8 +45,7 @@
"devDependencies": {
"@backstage/cli": "^0.8.0",
"@backstage/core-app-api": "^0.1.18",
"@backstage/test-utils": "^0.1.18",
"@backstage/test-utils-core": "^0.1.3",
"@backstage/test-utils": "^0.1.19",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2",
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { withLogCollector } from '@backstage/test-utils-core';
import { withLogCollector } from '@backstage/test-utils';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { useAnalyticsContext } from '../analytics/AnalyticsContext';
+1 -109
View File
@@ -3,113 +3,5 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { ReactElement } from 'react';
import { RenderResult } from '@testing-library/react';
// Warning: (ae-missing-release-tag) "AsyncLogCollector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export type AsyncLogCollector = () => Promise<void>;
// Warning: (ae-missing-release-tag) "CollectedLogs" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export type CollectedLogs<T extends LogFuncs> = {
[key in T]: string[];
};
// Warning: (ae-missing-release-tag) "Keyboard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export class Keyboard {
constructor(
target: any,
{
debug,
}?: {
debug?: boolean | undefined;
},
);
// (undocumented)
click(): Promise<void>;
// (undocumented)
debug: boolean;
// (undocumented)
document: any;
// (undocumented)
enter(value: any): Promise<void>;
// (undocumented)
escape(): Promise<void>;
// (undocumented)
get focused(): any;
// (undocumented)
static fromReadableInput(input: any): any;
// (undocumented)
_log(message: any, ...args: any[]): void;
// (undocumented)
_pretty(element: any): string;
// (undocumented)
send(chars: any): Promise<void>;
// (undocumented)
_sendKey(key: any, charCode: any, action: any): Promise<void>;
// (undocumented)
tab(): Promise<void>;
// (undocumented)
static toReadableInput(chars: any): any;
// (undocumented)
toString(): string;
// (undocumented)
static type(target: any, input: any): Promise<void>;
// (undocumented)
type(input: any): Promise<void>;
// (undocumented)
static typeDebug(target: any, input: any): Promise<void>;
}
// Warning: (ae-missing-release-tag) "LogCollector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export type LogCollector = AsyncLogCollector | SyncLogCollector;
// Warning: (ae-missing-release-tag) "LogFuncs" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export type LogFuncs = 'log' | 'warn' | 'error';
// Warning: (ae-missing-release-tag) "renderWithEffects" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function renderWithEffects(nodes: ReactElement): Promise<RenderResult>;
// Warning: (ae-missing-release-tag) "SyncLogCollector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export type SyncLogCollector = () => void;
// Warning: (ae-missing-release-tag) "withLogCollector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
// Warning: (ae-missing-release-tag) "withLogCollector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
// Warning: (ae-missing-release-tag) "withLogCollector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
// Warning: (ae-missing-release-tag) "withLogCollector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function withLogCollector(
callback: AsyncLogCollector,
): Promise<CollectedLogs<LogFuncs>>;
// @public (undocumented)
export function withLogCollector(
callback: SyncLogCollector,
): CollectedLogs<LogFuncs>;
// @public (undocumented)
export function withLogCollector<T extends LogFuncs>(
logsToCollect: T[],
callback: AsyncLogCollector,
): Promise<CollectedLogs<T>>;
// @public (undocumented)
export function withLogCollector<T extends LogFuncs>(
logsToCollect: T[],
callback: SyncLogCollector,
): CollectedLogs<T>;
// (No @packageDocumentation comment for this package)
```
+2 -8
View File
@@ -23,18 +23,12 @@
"scripts": {
"build": "backstage-cli build --outputs types,esm",
"lint": "backstage-cli lint",
"test": "backstage-cli test",
"test": "backstage-cli test --passWithNoTests",
"prepack": "backstage-cli prepack",
"postpack": "backstage-cli postpack",
"clean": "backstage-cli clean"
},
"dependencies": {
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@types/react": "*",
"react": "^16.12.0",
"react-dom": "^16.12.0"
},
"dependencies": {},
"devDependencies": {
"@types/jest": "^26.0.7",
"@types/node": "^14.14.32"
+4 -7
View File
@@ -14,10 +14,7 @@
* limitations under the License.
*/
/**
* Utilities to test Backstage core
*
* @packageDocumentation
*/
export * from './testUtils';
export {};
throw new Error(
'This module has been removed. Use @backstage/dev-utils instead',
);
@@ -1,17 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import '@testing-library/jest-dom';
@@ -1,19 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './Keyboard';
export * from './logCollector';
export * from './testingLibrary';
+120 -29
View File
@@ -17,9 +17,73 @@ import { RouteRef } from '@backstage/core-plugin-api';
import { StorageApi } from '@backstage/core-plugin-api';
import { StorageValueChange } from '@backstage/core-plugin-api';
// Warning: (ae-missing-release-tag) "MockAnalyticsApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export type AsyncLogCollector = () => Promise<void>;
// @public
export type CollectedLogs<T extends LogFuncs> = {
[key in T]: string[];
};
// @public
export type ErrorWithContext = {
error: Error;
context?: ErrorContext;
};
// @public @deprecated (undocumented)
export class Keyboard {
constructor(
target: any,
{
debug,
}?: {
debug?: boolean | undefined;
},
);
// (undocumented)
click(): Promise<void>;
// (undocumented)
debug: boolean;
// (undocumented)
document: any;
// (undocumented)
enter(value: any): Promise<void>;
// (undocumented)
escape(): Promise<void>;
// (undocumented)
get focused(): any;
// (undocumented)
static fromReadableInput(input: any): any;
// (undocumented)
_log(message: any, ...args: any[]): void;
// (undocumented)
_pretty(element: any): string;
// (undocumented)
send(chars: any): Promise<void>;
// (undocumented)
_sendKey(key: any, charCode: any, action: any): Promise<void>;
// (undocumented)
tab(): Promise<void>;
// (undocumented)
static toReadableInput(chars: any): any;
// (undocumented)
toString(): string;
// (undocumented)
static type(target: any, input: any): Promise<void>;
// (undocumented)
type(input: any): Promise<void>;
// (undocumented)
static typeDebug(target: any, input: any): Promise<void>;
}
// @public
export type LogCollector = AsyncLogCollector | SyncLogCollector;
// @public
export type LogFuncs = 'log' | 'warn' | 'error';
// @public
export class MockAnalyticsApi implements AnalyticsApi {
// (undocumented)
captureEvent({
@@ -33,9 +97,6 @@ export class MockAnalyticsApi implements AnalyticsApi {
getEvents(): AnalyticsEvent[];
}
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
// Warning: (ae-missing-release-tag) "mockBreakpoint" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export function mockBreakpoint({
matches,
@@ -43,19 +104,14 @@ export function mockBreakpoint({
matches?: boolean | undefined;
}): void;
// Warning: (ae-missing-release-tag) "MockErrorApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export class MockErrorApi implements ErrorApi {
// Warning: (ae-forgotten-export) The symbol "Options" needs to be exported by the entry point index.d.ts
constructor(options?: Options);
constructor(options?: MockErrorApiOptions);
// (undocumented)
error$(): Observable<{
error: Error;
context?: ErrorContext;
}>;
// Warning: (ae-forgotten-export) The symbol "ErrorWithContext" needs to be exported by the entry point index.d.ts
//
// (undocumented)
getErrors(): ErrorWithContext[];
// (undocumented)
@@ -64,9 +120,12 @@ export class MockErrorApi implements ErrorApi {
waitForError(pattern: RegExp, timeoutMs?: number): Promise<ErrorWithContext>;
}
// Warning: (ae-missing-release-tag) "MockStorageApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export type MockErrorApiOptions = {
collect?: boolean;
};
// @public
export class MockStorageApi implements StorageApi {
// (undocumented)
static create(data?: MockStorageBucket): MockStorageApi;
@@ -82,16 +141,12 @@ export class MockStorageApi implements StorageApi {
set<T>(key: string, data: T): Promise<void>;
}
// Warning: (ae-missing-release-tag) "MockStorageBucket" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export type MockStorageBucket = {
[key: string]: any;
};
// Warning: (ae-missing-release-tag) "msw" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public @deprecated (undocumented)
export const msw: {
setupDefaultHandlers: (worker: {
listen: (t: any) => void;
@@ -100,22 +155,58 @@ export const msw: {
}) => void;
};
// Warning: (ae-forgotten-export) The symbol "TestAppOptions" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "renderInTestApp" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export function renderInTestApp(
Component: ComponentType | ReactNode,
options?: TestAppOptions,
): Promise<RenderResult>;
// Warning: (ae-missing-release-tag) "wrapInTestApp" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export function renderWithEffects(nodes: ReactElement): Promise<RenderResult>;
// @public
export function setupRequestMockHandlers(worker: {
listen: (t: any) => void;
close: () => void;
resetHandlers: () => void;
}): void;
// @public
export type SyncLogCollector = () => void;
// @public
export type TestAppOptions = {
routeEntries?: string[];
mountedRoutes?: {
[path: string]: RouteRef | ExternalRouteRef;
};
};
// @public
export function withLogCollector(
callback: AsyncLogCollector,
): Promise<CollectedLogs<LogFuncs>>;
// @public
export function withLogCollector(
callback: SyncLogCollector,
): CollectedLogs<LogFuncs>;
// @public
export function withLogCollector<T extends LogFuncs>(
logsToCollect: T[],
callback: AsyncLogCollector,
): Promise<CollectedLogs<T>>;
// @public
export function withLogCollector<T extends LogFuncs>(
logsToCollect: T[],
callback: SyncLogCollector,
): CollectedLogs<T>;
// @public
export function wrapInTestApp(
Component: ComponentType | ReactNode,
options?: TestAppOptions,
): ReactElement;
export * from '@backstage/test-utils-core';
```
-1
View File
@@ -31,7 +31,6 @@
"dependencies": {
"@backstage/core-app-api": "^0.1.18",
"@backstage/core-plugin-api": "^0.1.11",
"@backstage/test-utils-core": "^0.1.3",
"@backstage/theme": "^0.2.11",
"@backstage/types": "^0.1.1",
"@material-ui/core": "^4.12.2",
-1
View File
@@ -21,4 +21,3 @@
*/
export * from './testUtils';
export * from '@backstage/test-utils-core';
@@ -23,6 +23,10 @@ const codes = {
Esc: 27,
};
/**
* @public
* @deprecated because it has no usages. Perhaps resurfaced in the future when need be.
*/
export class Keyboard {
static async type(target, input) {
await new Keyboard(target).type(input);
@@ -16,6 +16,11 @@
import { AnalyticsApi, AnalyticsEvent } from '@backstage/core-plugin-api';
/**
* Mock implementation of {@link core-plugin-api#AnalyticsApi} with helpers to ensure that events are sent correctly.
* Use getEvents in tests to verify captured events.
* @public
*/
export class MockAnalyticsApi implements AnalyticsApi {
private events: AnalyticsEvent[] = [];
@@ -17,11 +17,20 @@
import { ErrorApi, ErrorContext } from '@backstage/core-plugin-api';
import { Observable } from '@backstage/types';
type Options = {
/**
* Constructor arguments for {@link MockErrorApi}
* @public
*/
export type MockErrorApiOptions = {
// Need to be true if getErrors is used in testing.
collect?: boolean;
};
type ErrorWithContext = {
/**
* ErrorWithContext contains error and ErrorContext
* @public
*/
export type ErrorWithContext = {
error: Error;
context?: ErrorContext;
};
@@ -39,11 +48,16 @@ const nullObservable = {
},
};
/**
* Mock implementation of the {@link core-plugin-api#ErrorApi} to be used in tests.
* Incudes withForError and getErrors methods for error testing.
* @public
*/
export class MockErrorApi implements ErrorApi {
private readonly errors = new Array<ErrorWithContext>();
private readonly waiters = new Set<Waiter>();
constructor(private readonly options: Options = {}) {}
constructor(private readonly options: MockErrorApiOptions = {}) {}
post(error: Error, context?: ErrorContext) {
if (this.options.collect) {
@@ -15,3 +15,4 @@
*/
export { MockErrorApi } from './MockErrorApi';
export type { MockErrorApiOptions, ErrorWithContext } from './MockErrorApi';
@@ -18,8 +18,16 @@ import { StorageApi, StorageValueChange } from '@backstage/core-plugin-api';
import { Observable } from '@backstage/types';
import ObservableImpl from 'zen-observable';
/**
* Type for map holding data in {@link MockStorageApi}
* @public
*/
export type MockStorageBucket = { [key: string]: any };
/**
* Mock implementation of the {@link core-plugin-api#StorageApi} to be used in tests
* @public
*/
export class MockStorageApi implements StorageApi {
private readonly namespace: string;
private readonly data: MockStorageBucket;
@@ -23,7 +23,7 @@ import {
useApi,
useRouteRef,
} from '@backstage/core-plugin-api';
import { withLogCollector } from '@backstage/test-utils-core';
import { withLogCollector } from './logCollector';
import { render } from '@testing-library/react';
import React, { useEffect } from 'react';
import { Route, Routes } from 'react-router';
@@ -27,7 +27,7 @@ import {
createRouteRef,
} from '@backstage/core-plugin-api';
import { RenderResult } from '@testing-library/react';
import { renderWithEffects } from '@backstage/test-utils-core';
import { renderWithEffects } from './testingLibrary';
import { mockApis } from './mockApis';
const ErrorBoundaryFallback = ({ error }: { error: Error }) => {
@@ -43,8 +43,9 @@ const Progress = () => <div data-testid="progress" />;
/**
* Options to customize the behavior of the test app wrapper.
* @public
*/
type TestAppOptions = {
export type TestAppOptions = {
/**
* Initial route entries to pass along as `initialEntries` to the router.
*/
@@ -56,11 +57,11 @@ type TestAppOptions = {
* used by `useRouteRef` in the rendered elements.
*
* @example
* wrapInTestApp(<MyComponent />, {
* mountedRoutes: {
* wrapInTestApp(<MyComponent />, \{
* mountedRoutes: \{
* '/my-path': myRouteRef,
* }
* })
* \}
* \})
* // ...
* const link = useRouteRef(myRouteRef)
*/
@@ -80,6 +81,7 @@ function isExternalRouteRef(
*
* @param Component - A component or react node to render inside the test app.
* @param options - Additional options for the rendering.
* @public
*/
export function wrapInTestApp(
Component: ComponentType | ReactNode,
@@ -171,6 +173,7 @@ export function wrapInTestApp(
*
* @param Component - A component or react node to render inside the test app.
* @param options - Additional options for the rendering.
* @public
*/
export async function renderInTestApp(
Component: ComponentType | ReactNode,
@@ -17,4 +17,8 @@
export * from './apis';
export { default as mockBreakpoint } from './mockBreakpoint';
export { wrapInTestApp, renderInTestApp } from './appWrappers';
export type { TestAppOptions } from './appWrappers';
export * from './msw';
export * from './Keyboard';
export * from './logCollector';
export * from './testingLibrary';
@@ -16,36 +16,65 @@
/* eslint-disable no-console */
/**
* Severity levels of {@link CollectedLogs}
* @public */
export type LogFuncs = 'log' | 'warn' | 'error';
/**
* AsyncLogCollector type used in {@link (withLogCollector:1)} callback function.
* @public */
export type AsyncLogCollector = () => Promise<void>;
/**
* SyncLogCollector type used in {@link (withLogCollector:2)} callback function.
* @public */
export type SyncLogCollector = () => void;
/**
* Union type used in {@link (withLogCollector:3)} callback function.
* @public */
export type LogCollector = AsyncLogCollector | SyncLogCollector;
/**
* Map of severity level and corresponding log lines.
* @public */
export type CollectedLogs<T extends LogFuncs> = { [key in T]: string[] };
const allCategories = ['log', 'warn', 'error'];
// Asynchronous log collector with that collects all categories
/**
* Asynchronous log collector with that collects all categories
* @public */
export function withLogCollector(
callback: AsyncLogCollector,
): Promise<CollectedLogs<LogFuncs>>;
// Synchronous log collector with that collects all categories
/**
* Synchronous log collector with that collects all categories
* @public */
export function withLogCollector(
callback: SyncLogCollector,
): CollectedLogs<LogFuncs>;
// Asynchronous log collector with that only collects selected categories
/**
* Asynchronous log collector with that only collects selected categories
* @public
*/
export function withLogCollector<T extends LogFuncs>(
logsToCollect: T[],
callback: AsyncLogCollector,
): Promise<CollectedLogs<T>>;
// Synchronous log collector with that only collects selected categories
/**
* Synchronous log collector with that only collects selected categories
* @public */
export function withLogCollector<T extends LogFuncs>(
logsToCollect: T[],
callback: SyncLogCollector,
): CollectedLogs<T>;
/**
* Log collector that collect logs either from a sync or async collector.
* @public
* @deprecated import from test-utils instead
* */
export function withLogCollector(
logsToCollect: LogFuncs[] | LogCollector,
callback?: LogCollector,
@@ -24,7 +24,7 @@
* If there are any updates from MUI React on testing `useMediaQuery` this mock should be replaced
* https://material-ui.com/components/use-media-query/#testing
*
* @param matchMediaOptions
* @public
*/
export default function mockBreakpoint({ matches = false }) {
Object.defineProperty(window, 'matchMedia', {
+20 -3
View File
@@ -14,14 +14,31 @@
* limitations under the License.
*/
/**
* @deprecated use {@link setupRequestMockHandlers} instead which can be called directly with the worker.
* @public
*/
export const msw = {
setupDefaultHandlers: (worker: {
listen: (t: any) => void;
close: () => void;
resetHandlers: () => void;
}) => {
beforeAll(() => worker.listen({ onUnhandledRequest: 'error' }));
afterAll(() => worker.close());
afterEach(() => worker.resetHandlers());
setupRequestMockHandlers(worker);
},
};
/**
* Sets up handlers for request mocking
* @public
* @param worker - service worker
*/
export function setupRequestMockHandlers(worker: {
listen: (t: any) => void;
close: () => void;
resetHandlers: () => void;
}) {
beforeAll(() => worker.listen({ onUnhandledRequest: 'error' }));
afterAll(() => worker.close());
afterEach(() => worker.resetHandlers());
}
@@ -18,11 +18,18 @@ import { ReactElement } from 'react';
import { act } from 'react-dom/test-utils';
import { render, RenderResult } from '@testing-library/react';
// Components using useEffect to perform an asynchronous action (such as fetch) must be rendered within an async
// act call to properly get the final state, even with mocked responses. This utility method makes the signature a bit
// cleaner, since act doesn't return the result of the evaluated function.
// https://github.com/testing-library/react-testing-library/issues/281
// https://github.com/facebook/react/pull/14853
/**
* @public
* Simplifies rendering of async components in by taking care of the wrapping inside act
*
* @remarks
*
* Components using useEffect to perform an asynchronous action (such as fetch) must be rendered within an async
* act call to properly get the final state, even with mocked responses. This utility method makes the signature a bit
* cleaner, since act doesn't return the result of the evaluated function.
* https://github.com/testing-library/react-testing-library/issues/281
* https://github.com/facebook/react/pull/14853
*/
export async function renderWithEffects(
nodes: ReactElement,
): Promise<RenderResult> {