Skip to content

Commit

Permalink
Merge pull request #1 from phryneas/pr/api-bikeshedding
Browse files Browse the repository at this point in the history
  • Loading branch information
phryneas authored Oct 9, 2024
2 parents a59c1ab + 2bf91c1 commit 8fcd546
Show file tree
Hide file tree
Showing 13 changed files with 298 additions and 190 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
],
"dependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.0.1",
"jsdom": "^25.0.1",
"rehackt": "^0.1.0"
},
Expand Down
26 changes: 26 additions & 0 deletions src/assertable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { RenderStream } from "./profile/profile.js";

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

/**
* A function or object that can be used in assertions, like e.g.
```ts
expect(assertable).toRerender()
expect(assertable).not.toRerender()
expect(assertable).toRenderExactlyTimes(3)
```
*/
export type Assertable = {
[assertableSymbol]: RenderStream<any>;
};

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

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

export { renderToRenderStream } from "./renderToRenderStream.js";
export { renderHookToSnapshotStream } from "./renderHookToSnapshotStream.js";

export type { Assertable } from "./assertable.js";
24 changes: 11 additions & 13 deletions src/jest/ProfiledComponent.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import type { MatcherFunction } from "expect";
import { WaitForRenderTimeoutError } from "@testing-library/react-render-stream";
import type {
Assertable,
NextRenderOptions,
Profiler,
ProfiledComponent,
ProfiledHook,
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";

export const toRerender: MatcherFunction<[options?: NextRenderOptions]> =
async function (actual, options) {
const _profiler = actual as
| Profiler<any>
| ProfiledComponent<any, any>
| ProfiledHook<any, any>;
const profiler = "Profiler" in _profiler ? _profiler.Profiler : _profiler;
const _profiler = actual as RenderStream<any> | Assertable;
const profiler =
assertableSymbol in _profiler ? _profiler[assertableSymbol] : _profiler;
const hint = this.utils.matcherHint("toRerender", "ProfiledComponent", "");
let pass = true;
try {
Expand Down Expand Up @@ -44,11 +44,9 @@ const failed = {};
export const toRenderExactlyTimes: MatcherFunction<
[times: number, options?: NextRenderOptions]
> = async function (actual, times, optionsPerRender) {
const _profiler = actual as
| Profiler<any>
| ProfiledComponent<any, any>
| ProfiledHook<any, any>;
const profiler = "Profiler" in _profiler ? _profiler.Profiler : _profiler;
const _profiler = actual as RenderStream<any> | Assertable;
const profiler =
assertableSymbol in _profiler ? _profiler[assertableSymbol] : _profiler;
const options = { timeout: 100, ...optionsPerRender };
const hint = this.utils.matcherHint("toRenderExactlyTimes");
let pass = true;
Expand Down
29 changes: 13 additions & 16 deletions src/jest/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,30 @@ import { expect } from "@jest/globals";
import { toRerender, toRenderExactlyTimes } from "./ProfiledComponent.js";
import type {
NextRenderOptions,
Profiler,
ProfiledComponent,
ProfiledHook,
} from "../profile/index.js";
RenderStream,
Assertable,
} from "@testing-library/react-render-stream";

expect.extend({
toRerender,
toRenderExactlyTimes,
});
interface ApolloCustomMatchers<R = void, T = {}> {
toRerender: T extends
| Profiler<any>
| ProfiledComponent<any, any>
| ProfiledHook<any, any>
interface CustomMatchers<R = void, T = {}> {
toRerender: T extends RenderStream<any> | Assertable
? (options?: NextRenderOptions) => Promise<R>
: { error: "matcher needs to be called on a ProfiledComponent instance" };
: {
error: "matcher needs to be called on a `takeRender` function, `takeSnapshot` function or `RenderStream` instance";
};

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

declare global {
namespace jest {
interface Matchers<R = void, T = {}> extends ApolloCustomMatchers<R, T> {}
interface Matchers<R = void, T = {}> extends CustomMatchers<R, T> {}
}
}
7 changes: 2 additions & 5 deletions src/profile/Render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { within, screen } from "@testing-library/dom";
import { JSDOM, VirtualConsole } from "jsdom";
import { applyStackTrace, captureStackTrace } from "./traces.js";

/** @internal */
export interface BaseRender {
id: string;
phase: "mount" | "update" | "nested-update";
Expand All @@ -28,7 +27,7 @@ export interface BaseRender {
}

type Screen = typeof screen;
/** @internal */

export type SyncScreen = {
[K in keyof Screen]: K extends `find${string}`
? {
Expand All @@ -38,7 +37,6 @@ export type SyncScreen = {
: Screen[K];
};

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

/** @internal */
export class RenderInstance<Snapshot> implements Render<Snapshot> {
id: string;
phase: "mount" | "update" | "nested-update";
Expand Down Expand Up @@ -138,7 +135,7 @@ export class RenderInstance<Snapshot> implements Render<Snapshot> {
return () => snapScreen;
}
}
/** @internal */

export function errorOnDomInteraction() {
const events: Array<keyof DocumentEventMap> = [
"auxclick",
Expand Down
15 changes: 0 additions & 15 deletions src/profile/index.ts

This file was deleted.

Loading

0 comments on commit 8fcd546

Please sign in to comment.