Skip to content

use kcd-scripts #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 10, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tsup.config.ts
dist/
18 changes: 18 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
extends: 'kentcdodds',
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-interface': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/unified-signatures': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'after-used',
argsIgnorePattern: '^_',
ignoreRestSiblings: true,
varsIgnorePattern: '^_',
},
],
},
}
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# format with kcd-scripts
325d59e3cd0bf4c7ab738381e1bb49aef3bc7363
4 changes: 2 additions & 2 deletions .github/workflows/pkg-pr-new-publish.yml
Original file line number Diff line number Diff line change
@@ -4,9 +4,9 @@ on:
pull_request:
push:
branches:
- "**"
- '**'
tags:
- "!**"
- '!**'

jobs:
prerelease:
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -5,4 +5,5 @@ dist/
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
!.yarn/versions
*.tsbuildinfo
1 change: 1 addition & 0 deletions .prettierrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require("kcd-scripts/prettier.js");
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -61,6 +61,7 @@
"@types/react": "^18",
"@types/react-dom": "^18",
"expect": "^29.7.0",
"kcd-scripts": "^16.0.0",
"pkg-pr-new": "^0.0.29",
"prettier": "^3.3.3",
"publint": "^0.2.11",
@@ -79,7 +80,15 @@
"build": "tsup",
"pkg-pr-new-publish": "yarn build && pkg-pr-new publish --no-template",
"prepack": "yarn build",
"verify": "attw --pack . && publint"
"format": "kcd-scripts format",
"lint": "kcd-scripts lint --config .eslintrc.cjs",
"test": "kcd-scripts test --passWithNoTests",
"verify": "attw --pack . && publint",
"typecheck": "kcd-scripts typecheck --build",
"validate": "CI=true kcd-scripts validate verify,lint,typecheck,test"
},
"packageManager": "[email protected]"
"packageManager": "[email protected]",
"resolutions": {
"eslint-config-kentcdodds": "^21.0.0"
}
}
14 changes: 7 additions & 7 deletions src/assertable.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { RenderStream } from "./renderStream/createRenderStream.js";
import {type RenderStream} from './renderStream/createRenderStream.js'

export const assertableSymbol = Symbol.for(
"@testing-library/react-render-stream:assertable"
);
'@testing-library/react-render-stream:assertable',
)

/**
* A function or object that can be used in assertions, like e.g.
@@ -13,14 +13,14 @@ export const assertableSymbol = Symbol.for(
```
*/
export type Assertable = {
[assertableSymbol]: RenderStream<any>;
};
[assertableSymbol]: RenderStream<any>
}

export function markAssertable<T extends {}>(
assertable: T,
stream: RenderStream<any>
stream: RenderStream<any>,
): T & Assertable {
return Object.assign(assertable, {
[assertableSymbol]: stream,
});
})
}
16 changes: 8 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -3,18 +3,18 @@ export type {
RenderStream,
RenderStreamWithRenderFn,
RenderStreamOptions,
} from "./renderStream/createRenderStream.js";
} from './renderStream/createRenderStream.js'
export {
createRenderStream,
useTrackRenders,
WaitForRenderTimeoutError,
} from "./renderStream/createRenderStream.js";
} from './renderStream/createRenderStream.js'

export type { SyncScreen } from "./renderStream/Render.js";
export type {SyncScreen} from './renderStream/Render.js'

export { renderToRenderStream } from "./renderToRenderStream.js";
export type { RenderStreamWithRenderResult } from "./renderToRenderStream.js";
export { renderHookToSnapshotStream } from "./renderHookToSnapshotStream.js";
export type { SnapshotStream } from "./renderHookToSnapshotStream.js";
export {renderToRenderStream} from './renderToRenderStream.js'
export type {RenderStreamWithRenderResult} from './renderToRenderStream.js'
export {renderHookToSnapshotStream} from './renderHookToSnapshotStream.js'
export type {SnapshotStream} from './renderHookToSnapshotStream.js'

export type { Assertable } from "./assertable.js";
export type {Assertable} from './assertable.js'
13 changes: 9 additions & 4 deletions src/jest/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { expect } from "@jest/globals";
import { toRerender, toRenderExactlyTimes } from "./renderStreamMatchers.js";
import type { RenderStreamMatchers } from "./renderStreamMatchers.js";
import {expect} from '@jest/globals'
import {
toRerender,
toRenderExactlyTimes,
type RenderStreamMatchers,
} from './renderStreamMatchers.js'

expect.extend({
toRerender,
toRenderExactlyTimes,
});
})

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface Matchers<R = void, T = {}> extends RenderStreamMatchers<R, T> {}
}
}
96 changes: 51 additions & 45 deletions src/jest/renderStreamMatchers.ts
Original file line number Diff line number Diff line change
@@ -1,104 +1,110 @@
import type { MatcherFunction } from "expect";
import { WaitForRenderTimeoutError } from "@testing-library/react-render-stream";
import type {
Assertable,
NextRenderOptions,
RenderStream,
} from "@testing-library/react-render-stream";
import {MatcherContext, type MatcherFunction} from 'expect'
import {
WaitForRenderTimeoutError,
type Assertable,
type NextRenderOptions,
type RenderStream,
} from '@testing-library/react-render-stream'
// explicitly imported the symbol from the internal file
// this will bundle the `Symbol.for` call twice, but we keep it private
import { assertableSymbol } from "../assertable.js";
import {assertableSymbol} from '../assertable.js'

export interface RenderStreamMatchers<R = void, T = {}> {
toRerender: T extends RenderStream<any> | Assertable
? (options?: NextRenderOptions) => Promise<R>
: {
error: "matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance";
};
error: 'matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance'
}

toRenderExactlyTimes: T extends RenderStream<any> | Assertable
? (count: number, options?: NextRenderOptions) => Promise<R>
: {
error: "matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance";
};
error: 'matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance'
}
}

export const toRerender: MatcherFunction<[options?: NextRenderOptions]> =
async function (actual, options) {
const _stream = actual as RenderStream<any> | Assertable;
async function toRerender(this: MatcherContext, actual, options) {
const _stream = actual as RenderStream<any> | Assertable
const stream =
assertableSymbol in _stream ? _stream[assertableSymbol] : _stream;
const hint = this.utils.matcherHint("toRerender");
let pass = true;
assertableSymbol in _stream ? _stream[assertableSymbol] : _stream
const hint = this.utils.matcherHint('toRerender')
let pass = true
try {
await stream.peekRender({ timeout: 100, ...options });
await stream.peekRender({timeout: 100, ...options})
} catch (e) {
if (e instanceof WaitForRenderTimeoutError) {
pass = false;
pass = false
} else {
throw e;
throw e
}
}

return {
pass,
message() {
return (
hint +
`\n\nExpected component to${pass ? " not" : ""} rerender, ` +
`but it did${pass ? "" : " not"}.`
);
`${hint}\n\nExpected component to${pass ? ' not' : ''} rerender, ` +
`but it did${pass ? '' : ' not'}.`
)
},
};
};
}
}

/** to be thrown to "break" test execution and fail it */
const failed = {};
const failed = new Error()

export const toRenderExactlyTimes: MatcherFunction<
[times: number, options?: NextRenderOptions]
> = async function (actual, times, optionsPerRender) {
const _stream = actual as RenderStream<any> | Assertable;
> = async function toRenderExactlyTimes(
this: MatcherContext,
actual,
times,
optionsPerRender,
) {
const _stream = actual as RenderStream<any> | Assertable
const stream =
assertableSymbol in _stream ? _stream[assertableSymbol] : _stream;
const options = { timeout: 100, ...optionsPerRender };
const hint = this.utils.matcherHint("toRenderExactlyTimes");
let pass = true;
assertableSymbol in _stream ? _stream[assertableSymbol] : _stream
const options = {timeout: 100, ...optionsPerRender}
const hint = this.utils.matcherHint('toRenderExactlyTimes')
let pass = true
try {
if (stream.totalRenderCount() > times) {
throw failed;
throw failed
}
try {
while (stream.totalRenderCount() < times) {
await stream.waitForNextRender(options);
// eslint-disable-next-line no-await-in-loop
await stream.waitForNextRender(options)
}
} catch (e) {
// timeouts here should just fail the test, rethrow other errors
throw e instanceof WaitForRenderTimeoutError ? failed : e;
throw e instanceof WaitForRenderTimeoutError ? failed : e
}
try {
await stream.waitForNextRender(options);
await stream.waitForNextRender(options)
} catch (e) {
// we are expecting a timeout here, so swallow that error, rethrow others
if (!(e instanceof WaitForRenderTimeoutError)) {
throw e;
throw e
}
}
} catch (e) {
if (e === failed) {
pass = false;
pass = false
} else {
throw e;
throw e
}
}
return {
pass,
message() {
return (
hint +
` Expected component to${pass ? " not" : ""} render exactly ${times}.` +
`${
hint
} Expected component to${pass ? ' not' : ''} render exactly ${times}.` +
` It rendered ${stream.totalRenderCount()} times.`
);
)
},
};
};
}
}
62 changes: 31 additions & 31 deletions src/renderHookToSnapshotStream.tsx
Original file line number Diff line number Diff line change
@@ -1,88 +1,88 @@
import { RenderHookOptions } from "@testing-library/react";
import { createRenderStream } from "./renderStream/createRenderStream.js";
import type { NextRenderOptions } from "./renderStream/createRenderStream.js";
import {RenderHookOptions} from '@testing-library/react'
import {createElement} from 'rehackt'
import {createRenderStream} from './renderStream/createRenderStream.js'
import {type NextRenderOptions} from './renderStream/createRenderStream.js'

import { Render } from "./renderStream/Render.js";
import { createElement } from "rehackt";
import { Assertable, assertableSymbol, markAssertable } from "./assertable.js";
import {Render} from './renderStream/Render.js'
import {Assertable, assertableSymbol, markAssertable} from './assertable.js'

export interface SnapshotStream<Snapshot, Props> extends Assertable {
/**
* An array of all renders that have happened so far.
* Errors thrown during component render will be captured here, too.
*/
renders: Array<
| Render<{ value: Snapshot }>
| { phase: "snapshotError"; count: number; error: unknown }
>;
| Render<{value: Snapshot}>
| {phase: 'snapshotError'; count: number; error: unknown}
>
/**
* Peeks the next render from the current iterator position, without advancing the iterator.
* If no render has happened yet, it will wait for the next render to happen.
* @throws {WaitForRenderTimeoutError} if no render happens within the timeout
*/
peekSnapshot(options?: NextRenderOptions): Promise<Snapshot>;
peekSnapshot(options?: NextRenderOptions): Promise<Snapshot>
/**
* Iterates to the next render and returns it.
* If no render has happened yet, it will wait for the next render to happen.
* @throws {WaitForRenderTimeoutError} if no render happens within the timeout
*/
takeSnapshot: Assertable &
((options?: NextRenderOptions) => Promise<Snapshot>);
((options?: NextRenderOptions) => Promise<Snapshot>)
/**
* Returns the total number of renders.
*/
totalSnapshotCount(): number;
totalSnapshotCount(): number
/**
* Returns the current render.
* @throws {Error} if no render has happened yet
*/
getCurrentSnapshot(): Snapshot;
getCurrentSnapshot(): Snapshot
/**
* Waits for the next render to happen.
* Does not advance the render iterator.
*/
waitForNextSnapshot(options?: NextRenderOptions): Promise<Snapshot>;
rerender: (rerenderCallbackProps: Props) => void;
unmount: () => void;
waitForNextSnapshot(options?: NextRenderOptions): Promise<Snapshot>
rerender: (rerenderCallbackProps: Props) => void
unmount: () => void
}

export function renderHookToSnapshotStream<ReturnValue, Props extends {}>(
renderCallback: (props: Props) => ReturnValue,
{ initialProps, ...options }: RenderHookOptions<Props> = {}
{initialProps, ...renderOptions}: RenderHookOptions<Props> = {},
): SnapshotStream<ReturnValue, Props> {
const { render, ...stream } = createRenderStream<{ value: ReturnValue }>();
const {render, ...stream} = createRenderStream<{value: ReturnValue}>()

const HookComponent: React.FC<Props> = (props) => {
stream.replaceSnapshot({ value: renderCallback(props) });
return null;
};
const HookComponent: React.FC<Props> = props => {
stream.replaceSnapshot({value: renderCallback(props)})
return null
}

const { rerender: baseRerender, unmount } = render(
const {rerender: baseRerender, unmount} = render(
createElement(HookComponent, initialProps),
options
);
renderOptions,
)

function rerender(rerenderCallbackProps: Props) {
return baseRerender(createElement(HookComponent, rerenderCallbackProps));
return baseRerender(createElement(HookComponent, rerenderCallbackProps))
}

return {
[assertableSymbol]: stream,
renders: stream.renders,
totalSnapshotCount: stream.totalRenderCount,
async peekSnapshot(options) {
return (await stream.peekRender(options)).snapshot.value;
return (await stream.peekRender(options)).snapshot.value
},
takeSnapshot: markAssertable(async function takeSnapshot(options) {
return (await stream.takeRender(options)).snapshot.value;
return (await stream.takeRender(options)).snapshot.value
}, stream),
getCurrentSnapshot() {
return stream.getCurrentRender().snapshot.value;
return stream.getCurrentRender().snapshot.value
},
async waitForNextSnapshot(options) {
return (await stream.waitForNextRender(options)).snapshot.value;
return (await stream.waitForNextRender(options)).snapshot.value
},
rerender,
unmount,
};
}
}
222 changes: 114 additions & 108 deletions src/renderStream/Render.tsx
Original file line number Diff line number Diff line change
@@ -9,43 +9,43 @@ if we do not ignore this file in code coverage.
As we only use this file in our internal tests, we can safely ignore it.
*/

import { within, screen } from "@testing-library/dom";
import { JSDOM, VirtualConsole } from "jsdom";
import {within, screen} from '@testing-library/dom'
import {JSDOM, VirtualConsole} from 'jsdom'

export interface BaseRender {
id: string;
phase: "mount" | "update" | "nested-update";
actualDuration: number;
baseDuration: number;
startTime: number;
commitTime: number;
id: string
phase: 'mount' | 'update' | 'nested-update'
actualDuration: number
baseDuration: number
startTime: number
commitTime: number
/**
* The number of renders that have happened so far (including this render).
*/
count: number;
count: number
}

type Screen = typeof screen;
type Screen = typeof screen

export type SyncScreen = {
[K in keyof Screen]: K extends `find${string}`
? {
/** @deprecated A snapshot is static, so avoid async queries! */
(...args: Parameters<Screen[K]>): ReturnType<Screen[K]>;
(...args: Parameters<Screen[K]>): ReturnType<Screen[K]>
}
: Screen[K];
};
: Screen[K]
}

export interface Render<Snapshot> extends BaseRender {
/**
* The snapshot, as returned by the `takeSnapshot` option of `createRenderStream`.
*/
snapshot: Snapshot;
snapshot: Snapshot
/**
* A DOM snapshot of the rendered component, if the `snapshotDOM`
* option of `createRenderStream` was enabled.
*/
readonly domSnapshot: HTMLElement;
readonly domSnapshot: HTMLElement
/**
* Returns a callback to receive a `screen` instance that is scoped to the
* DOM snapshot of this `Render` instance.
@@ -57,65 +57,71 @@ export interface Render<Snapshot> extends BaseRender {
* +expect(withinDOM().getByText("foo")).toBeInTheDocument();
* ```
*/
withinDOM: () => SyncScreen;
withinDOM: () => SyncScreen

renderedComponents: Array<string | React.ComponentType>;
renderedComponents: Array<string | React.ComponentType>
}

export class RenderInstance<Snapshot> implements Render<Snapshot> {
id: string;
phase: "mount" | "update" | "nested-update";
actualDuration: number;
baseDuration: number;
startTime: number;
commitTime: number;
count: number;
id: string
phase: 'mount' | 'update' | 'nested-update'
actualDuration: number
baseDuration: number
startTime: number
commitTime: number
count: number
public snapshot: Snapshot
private stringifiedDOM: string | undefined
public renderedComponents: Array<string | React.ComponentType>

constructor(
baseRender: BaseRender,
public snapshot: Snapshot,
private stringifiedDOM: string | undefined,
public renderedComponents: Array<string | React.ComponentType>
snapshot: Snapshot,
stringifiedDOM: string | undefined,
renderedComponents: Array<string | React.ComponentType>,
) {
this.id = baseRender.id;
this.phase = baseRender.phase;
this.actualDuration = baseRender.actualDuration;
this.baseDuration = baseRender.baseDuration;
this.startTime = baseRender.startTime;
this.commitTime = baseRender.commitTime;
this.count = baseRender.count;
this.snapshot = snapshot
this.stringifiedDOM = stringifiedDOM
this.renderedComponents = renderedComponents
this.id = baseRender.id
this.phase = baseRender.phase
this.actualDuration = baseRender.actualDuration
this.baseDuration = baseRender.baseDuration
this.startTime = baseRender.startTime
this.commitTime = baseRender.commitTime
this.count = baseRender.count
}

private _domSnapshot: HTMLElement | undefined;
private _domSnapshot: HTMLElement | undefined
get domSnapshot() {
if (this._domSnapshot) return this._domSnapshot;
if (this._domSnapshot) return this._domSnapshot
if (!this.stringifiedDOM) {
throw new Error(
"DOM snapshot is not available - please set the `snapshotDOM` option"
);
'DOM snapshot is not available - please set the `snapshotDOM` option',
)
}

const virtualConsole = new VirtualConsole();
virtualConsole.on("jsdomError", (error: any) => {
throw error;
});
const virtualConsole = new VirtualConsole()
virtualConsole.on('jsdomError', (error: any) => {
throw error
})

const snapDOM = new JSDOM(this.stringifiedDOM, {
runScripts: "dangerously",
runScripts: 'dangerously',
virtualConsole,
});
const document = snapDOM.window.document;
const body = document.body;
const script = document.createElement("script");
script.type = "text/javascript";
})
const document = snapDOM.window.document
const body = document.body
const script = document.createElement('script')
script.type = 'text/javascript'
script.text = `
${errorOnDomInteraction.toString()};
${errorOnDomInteraction.name}();
`;
body.appendChild(script);
body.removeChild(script);
`
body.appendChild(script)
body.removeChild(script)

return (this._domSnapshot = body);
return (this._domSnapshot = body)
}

get withinDOM(): () => SyncScreen {
@@ -128,70 +134,70 @@ export class RenderInstance<Snapshot> implements Render<Snapshot> {
typeof screen.logTestingPlaygroundURL
>
) => screen.logTestingPlaygroundURL(dom, ...rest),
});
return () => snapScreen;
})
return () => snapScreen
}
}

export function errorOnDomInteraction() {
const events: Array<keyof DocumentEventMap> = [
"auxclick",
"blur",
"change",
"click",
"copy",
"cut",
"dblclick",
"drag",
"dragend",
"dragenter",
"dragleave",
"dragover",
"dragstart",
"drop",
"focus",
"focusin",
"focusout",
"input",
"keydown",
"keypress",
"keyup",
"mousedown",
"mouseenter",
"mouseleave",
"mousemove",
"mouseout",
"mouseover",
"mouseup",
"paste",
"pointercancel",
"pointerdown",
"pointerenter",
"pointerleave",
"pointermove",
"pointerout",
"pointerover",
"pointerup",
"scroll",
"select",
"selectionchange",
"selectstart",
"submit",
"toggle",
"touchcancel",
"touchend",
"touchmove",
"touchstart",
"wheel",
];
'auxclick',
'blur',
'change',
'click',
'copy',
'cut',
'dblclick',
'drag',
'dragend',
'dragenter',
'dragleave',
'dragover',
'dragstart',
'drop',
'focus',
'focusin',
'focusout',
'input',
'keydown',
'keypress',
'keyup',
'mousedown',
'mouseenter',
'mouseleave',
'mousemove',
'mouseout',
'mouseover',
'mouseup',
'paste',
'pointercancel',
'pointerdown',
'pointerenter',
'pointerleave',
'pointermove',
'pointerout',
'pointerover',
'pointerup',
'scroll',
'select',
'selectionchange',
'selectstart',
'submit',
'toggle',
'touchcancel',
'touchend',
'touchmove',
'touchstart',
'wheel',
]
function warnOnDomInteraction() {
throw new Error(`
DOM interaction with a snapshot detected in test.
Please don't interact with the DOM you get from \`withinDOM\`,
but still use \`screen\' to get elements for simulating user interaction.
`);
but still use \`screen\` to get elements for simulating user interaction.
`)
}
events.forEach((event) => {
document.addEventListener(event, warnOnDomInteraction);
});
events.forEach(event => {
document.addEventListener(event, warnOnDomInteraction)
})
}
18 changes: 9 additions & 9 deletions src/renderStream/context.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import * as React from "rehackt";
import * as React from 'rehackt'

export interface RenderStreamContextValue {
renderedComponents: Array<React.ComponentType | string>;
renderedComponents: Array<React.ComponentType | string>
}

const RenderStreamContext = React.createContext<
RenderStreamContextValue | undefined
>(undefined);
>(undefined)

export function RenderStreamContextProvider({
children,
value,
}: {
children: React.ReactNode;
value: RenderStreamContextValue;
children: React.ReactNode
value: RenderStreamContextValue
}) {
const parentContext = useRenderStreamContext();
const parentContext = useRenderStreamContext()

if (parentContext) {
throw new Error("Render streams should not be nested in the same tree");
throw new Error('Render streams should not be nested in the same tree')
}

return (
<RenderStreamContext.Provider value={value}>
{children}
</RenderStreamContext.Provider>
);
)
}

export function useRenderStreamContext() {
return React.useContext(RenderStreamContext);
return React.useContext(RenderStreamContext)
}
303 changes: 152 additions & 151 deletions src/renderStream/createRenderStream.tsx

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions src/renderStream/disableActWarnings.ts
Original file line number Diff line number Diff line change
@@ -4,13 +4,13 @@
* https://github.com/reactwg/react-18/discussions/102
*/
export function disableActWarnings() {
const anyThis = globalThis as any;
const prevActEnv = anyThis.IS_REACT_ACT_ENVIRONMENT;
anyThis.IS_REACT_ACT_ENVIRONMENT = false;
const anyThis = globalThis as any as {IS_REACT_ACT_ENVIRONMENT?: boolean}
const prevActEnv = anyThis.IS_REACT_ACT_ENVIRONMENT
anyThis.IS_REACT_ACT_ENVIRONMENT = false

return {
[Symbol.dispose]() {
anyThis.IS_REACT_ACT_ENVIRONMENT = prevActEnv;
anyThis.IS_REACT_ACT_ENVIRONMENT = prevActEnv
},
};
}
}
28 changes: 14 additions & 14 deletions src/renderToRenderStream.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import {
type RenderOptions as BaseOptions,
type RenderResult as BaseResult,
} from "@testing-library/react";
import { createRenderStream } from "./renderStream/createRenderStream.js";
import type {
RenderStreamOptions,
RenderStream,
ValidSnapshot,
} from "./renderStream/createRenderStream.js";
} from '@testing-library/react'
import {
createRenderStream,
type RenderStreamOptions,
type RenderStream,
type ValidSnapshot,
} from './renderStream/createRenderStream.js'

type RenderOptions<Snapshot extends ValidSnapshot = void> = BaseOptions &
RenderStreamOptions<Snapshot>;
RenderStreamOptions<Snapshot>

export interface RenderStreamWithRenderResult<
Snapshot extends ValidSnapshot = void,
> extends RenderStream<Snapshot> {
renderResultPromise: Promise<BaseResult>;
renderResultPromise: Promise<BaseResult>
}

/**
@@ -30,17 +30,17 @@ export function renderToRenderStream<Snapshot extends ValidSnapshot = void>(
initialSnapshot,
skipNonTrackingRenders,
...options
}: RenderOptions<Snapshot> = {}
}: RenderOptions<Snapshot> = {},
): RenderStreamWithRenderResult<Snapshot> {
const { render, ...stream } = createRenderStream<Snapshot>({
const {render, ...stream} = createRenderStream<Snapshot>({
onRender,
snapshotDOM,
initialSnapshot,
skipNonTrackingRenders,
});
})
// `render` needs to be called asynchronously here, because the definition of `ui`
// might contain components that reference the return value of `renderToRenderStream`
// itself, e.g. `replaceSnapshot` or `mergeSnapshot`.
const renderResultPromise = Promise.resolve().then(() => render(ui, options));
return { ...stream, renderResultPromise };
const renderResultPromise = Promise.resolve().then(() => render(ui, options))
return {...stream, renderResultPromise}
}
15 changes: 4 additions & 11 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -10,19 +10,12 @@
"sourceMap": true,
"jsx": "react",
"declarationMap": true,
"types": [
"react",
"node"
],
"types": ["react", "node"],
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"paths": {
"@testing-library/react-render-stream": [
"./src/index.ts"
]
"@testing-library/react-render-stream": ["./src/index.ts"]
}
},
"include": [
"src"
]
}
"include": ["src"]
}
12 changes: 6 additions & 6 deletions tsup.config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { defineConfig } from "tsup";
import {defineConfig} from 'tsup'

export default defineConfig({
entry: {
index: "src/index.ts",
jest: "src/jest/index.ts",
index: 'src/index.ts',
jest: 'src/jest/index.ts',
},
splitting: false,
sourcemap: true,
clean: true,
dts: true,
format: ["cjs", "esm"],
target: ["node20"],
format: ['cjs', 'esm'],
target: ['node20'],
external: [/^@testing-library\/react-render-stream/],
});
})
9,822 changes: 8,293 additions & 1,529 deletions yarn.lock

Large diffs are not rendered by default.