Skip to content

Commit 8fcd546

Browse files
authored
Merge pull request #1 from phryneas/pr/api-bikeshedding
2 parents a59c1ab + 2bf91c1 commit 8fcd546

13 files changed

+298
-190
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
],
5050
"dependencies": {
5151
"@testing-library/dom": "^10.4.0",
52+
"@testing-library/react": "^16.0.1",
5253
"jsdom": "^25.0.1",
5354
"rehackt": "^0.1.0"
5455
},

src/assertable.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { RenderStream } from "./profile/profile.js";
2+
3+
export const assertableSymbol = Symbol.for(
4+
"@testing-library/react-render-stream:assertable"
5+
);
6+
7+
/**
8+
* A function or object that can be used in assertions, like e.g.
9+
```ts
10+
expect(assertable).toRerender()
11+
expect(assertable).not.toRerender()
12+
expect(assertable).toRenderExactlyTimes(3)
13+
```
14+
*/
15+
export type Assertable = {
16+
[assertableSymbol]: RenderStream<any>;
17+
};
18+
19+
export function markAssertable<T extends {}>(
20+
assertable: T,
21+
stream: RenderStream<any>
22+
): T & Assertable {
23+
return Object.assign(assertable, {
24+
[assertableSymbol]: stream,
25+
});
26+
}

src/index.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export type {
2+
NextRenderOptions,
3+
RenderStream,
4+
RenderStreamWithRenderFn,
5+
} from "./profile/profile.js";
6+
export {
7+
createRenderStream,
8+
useTrackRenders,
9+
WaitForRenderTimeoutError,
10+
} from "./profile/profile.js";
11+
12+
export type { SyncScreen } from "./profile/Render.js";
13+
14+
export { renderToRenderStream } from "./renderToRenderStream.js";
15+
export { renderHookToSnapshotStream } from "./renderHookToSnapshotStream.js";
16+
17+
export type { Assertable } from "./assertable.js";

src/jest/ProfiledComponent.ts

+11-13
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import type { MatcherFunction } from "expect";
22
import { WaitForRenderTimeoutError } from "@testing-library/react-render-stream";
33
import type {
4+
Assertable,
45
NextRenderOptions,
5-
Profiler,
6-
ProfiledComponent,
7-
ProfiledHook,
6+
RenderStream,
87
} from "@testing-library/react-render-stream";
8+
// explicitly imported the symbol from the internal file
9+
// this will bundle the `Symbol.for` call twice, but we keep it private
10+
import { assertableSymbol } from "../assertable.js";
911

1012
export const toRerender: MatcherFunction<[options?: NextRenderOptions]> =
1113
async function (actual, options) {
12-
const _profiler = actual as
13-
| Profiler<any>
14-
| ProfiledComponent<any, any>
15-
| ProfiledHook<any, any>;
16-
const profiler = "Profiler" in _profiler ? _profiler.Profiler : _profiler;
14+
const _profiler = actual as RenderStream<any> | Assertable;
15+
const profiler =
16+
assertableSymbol in _profiler ? _profiler[assertableSymbol] : _profiler;
1717
const hint = this.utils.matcherHint("toRerender", "ProfiledComponent", "");
1818
let pass = true;
1919
try {
@@ -44,11 +44,9 @@ const failed = {};
4444
export const toRenderExactlyTimes: MatcherFunction<
4545
[times: number, options?: NextRenderOptions]
4646
> = async function (actual, times, optionsPerRender) {
47-
const _profiler = actual as
48-
| Profiler<any>
49-
| ProfiledComponent<any, any>
50-
| ProfiledHook<any, any>;
51-
const profiler = "Profiler" in _profiler ? _profiler.Profiler : _profiler;
47+
const _profiler = actual as RenderStream<any> | Assertable;
48+
const profiler =
49+
assertableSymbol in _profiler ? _profiler[assertableSymbol] : _profiler;
5250
const options = { timeout: 100, ...optionsPerRender };
5351
const hint = this.utils.matcherHint("toRenderExactlyTimes");
5452
let pass = true;

src/jest/index.ts

+13-16
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,30 @@ import { expect } from "@jest/globals";
22
import { toRerender, toRenderExactlyTimes } from "./ProfiledComponent.js";
33
import type {
44
NextRenderOptions,
5-
Profiler,
6-
ProfiledComponent,
7-
ProfiledHook,
8-
} from "../profile/index.js";
5+
RenderStream,
6+
Assertable,
7+
} from "@testing-library/react-render-stream";
98

109
expect.extend({
1110
toRerender,
1211
toRenderExactlyTimes,
1312
});
14-
interface ApolloCustomMatchers<R = void, T = {}> {
15-
toRerender: T extends
16-
| Profiler<any>
17-
| ProfiledComponent<any, any>
18-
| ProfiledHook<any, any>
13+
interface CustomMatchers<R = void, T = {}> {
14+
toRerender: T extends RenderStream<any> | Assertable
1915
? (options?: NextRenderOptions) => Promise<R>
20-
: { error: "matcher needs to be called on a ProfiledComponent instance" };
16+
: {
17+
error: "matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance";
18+
};
2119

22-
toRenderExactlyTimes: T extends
23-
| Profiler<any>
24-
| ProfiledComponent<any, any>
25-
| ProfiledHook<any, any>
20+
toRenderExactlyTimes: T extends RenderStream<any> | Assertable
2621
? (count: number, options?: NextRenderOptions) => Promise<R>
27-
: { error: "matcher needs to be called on a ProfiledComponent instance" };
22+
: {
23+
error: "matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance";
24+
};
2825
}
2926

3027
declare global {
3128
namespace jest {
32-
interface Matchers<R = void, T = {}> extends ApolloCustomMatchers<R, T> {}
29+
interface Matchers<R = void, T = {}> extends CustomMatchers<R, T> {}
3330
}
3431
}

src/profile/Render.tsx

+2-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { within, screen } from "@testing-library/dom";
1313
import { JSDOM, VirtualConsole } from "jsdom";
1414
import { applyStackTrace, captureStackTrace } from "./traces.js";
1515

16-
/** @internal */
1716
export interface BaseRender {
1817
id: string;
1918
phase: "mount" | "update" | "nested-update";
@@ -28,7 +27,7 @@ export interface BaseRender {
2827
}
2928

3029
type Screen = typeof screen;
31-
/** @internal */
30+
3231
export type SyncScreen = {
3332
[K in keyof Screen]: K extends `find${string}`
3433
? {
@@ -38,7 +37,6 @@ export type SyncScreen = {
3837
: Screen[K];
3938
};
4039

41-
/** @internal */
4240
export interface Render<Snapshot> extends BaseRender {
4341
/**
4442
* The snapshot, as returned by the `takeSnapshot` option of `profile`.
@@ -66,7 +64,6 @@ export interface Render<Snapshot> extends BaseRender {
6664
renderedComponents: Array<string | React.ComponentType>;
6765
}
6866

69-
/** @internal */
7067
export class RenderInstance<Snapshot> implements Render<Snapshot> {
7168
id: string;
7269
phase: "mount" | "update" | "nested-update";
@@ -138,7 +135,7 @@ export class RenderInstance<Snapshot> implements Render<Snapshot> {
138135
return () => snapScreen;
139136
}
140137
}
141-
/** @internal */
138+
142139
export function errorOnDomInteraction() {
143140
const events: Array<keyof DocumentEventMap> = [
144141
"auxclick",

src/profile/index.ts

-15
This file was deleted.

0 commit comments

Comments
 (0)