1
1
import { RenderHookOptions } from "@testing-library/react" ;
2
2
import {
3
3
createProfiler ,
4
+ NextRenderOptions ,
4
5
ProfiledComponentFields ,
5
6
ValidSnapshot ,
6
7
} from "./profile/profile.js" ;
7
8
import { Render } from "./profile/Render.js" ;
8
9
import { createElement } from "react" ;
9
-
10
- type StringReplaceRenderWithSnapshot < T extends string > =
11
- T extends `${infer Pre } Render${infer Post } ` ? `${Pre } Snapshot${Post } ` : T ;
12
-
13
- type ResultReplaceRenderWithSnapshot < T > = T extends (
14
- ...args : infer Args
15
- ) => Render < infer Snapshot >
16
- ? ( ...args : Args ) => Snapshot
17
- : T extends ( ...args : infer Args ) => Promise < Render < infer Snapshot > >
18
- ? ( ...args : Args ) => Promise < Snapshot >
19
- : T ;
20
-
21
- type ProfiledHookFields < ReturnValue > =
22
- ProfiledComponentFields < ReturnValue > extends infer PC
23
- ? {
24
- [ K in keyof PC as StringReplaceRenderWithSnapshot <
25
- K & string
26
- > ] : ResultReplaceRenderWithSnapshot < PC [ K ] > ;
27
- }
28
- : never ;
10
+ import { Assertable , assertableSymbol , markAssertable } from "./assertable.js" ;
29
11
30
12
/** @internal */
31
- export interface ProfiledHook < Props , ReturnValue extends ValidSnapshot >
32
- extends ProfiledHookFields < ReturnValue > {
33
- //Profiler: RenderStream<ReturnValue>;
13
+ export interface ProfiledHook < Snapshot extends ValidSnapshot >
14
+ extends Assertable {
15
+ /**
16
+ * An array of all renders that have happened so far.
17
+ * Errors thrown during component render will be captured here, too.
18
+ */
19
+ renders : Array <
20
+ Render < Snapshot > | { phase : "snapshotError" ; count : number ; error : unknown }
21
+ > ;
22
+ /**
23
+ * Peeks the next render from the current iterator position, without advancing the iterator.
24
+ * If no render has happened yet, it will wait for the next render to happen.
25
+ * @throws {WaitForRenderTimeoutError } if no render happens within the timeout
26
+ */
27
+ peekSnapshot ( options ?: NextRenderOptions ) : Promise < Snapshot > ;
28
+ /**
29
+ * Iterates to the next render and returns it.
30
+ * If no render has happened yet, it will wait for the next render to happen.
31
+ * @throws {WaitForRenderTimeoutError } if no render happens within the timeout
32
+ */
33
+ takeSnapshot : Assertable &
34
+ ( ( options ?: NextRenderOptions ) => Promise < Snapshot > ) ;
35
+ /**
36
+ * Returns the total number of renders.
37
+ */
38
+ totalSnapshotCount ( ) : number ;
39
+ /**
40
+ * Returns the current render.
41
+ * @throws {Error } if no render has happened yet
42
+ */
43
+ getCurrentSnapshot ( ) : Snapshot ;
44
+ /**
45
+ * Waits for the next render to happen.
46
+ * Does not advance the render iterator.
47
+ */
48
+ waitForNextSnapshot ( options ?: NextRenderOptions ) : Promise < Snapshot > ;
49
+ }
50
+
51
+ interface HookSnapshotStream < Props , ReturnValue extends ValidSnapshot >
52
+ extends ProfiledHook < ReturnValue > ,
53
+ Assertable {
54
+ rerender : ( rerenderCallbackProps : Props ) => void ;
55
+ unmount : ( ) => void ;
34
56
}
35
57
36
58
export function renderHookToSnapshotStream <
@@ -39,13 +61,7 @@ export function renderHookToSnapshotStream<
39
61
> (
40
62
renderCallback : ( props : Props ) => ReturnValue ,
41
63
{ initialProps, ...options } : RenderHookOptions < Props > = { }
42
- ) : [
43
- stream : ProfiledHook < Props , ReturnValue > ,
44
- renderResult : {
45
- rerender : ( rerenderCallbackProps : Props ) => void ;
46
- unmount : ( ) => void ;
47
- } ,
48
- ] {
64
+ ) : HookSnapshotStream < Props , ReturnValue > {
49
65
const { render, ...stream } = createProfiler < ReturnValue > ( ) ;
50
66
51
67
const ProfiledHook : React . FC < Props > = ( props ) => {
@@ -62,26 +78,23 @@ export function renderHookToSnapshotStream<
62
78
return baseRerender ( createElement ( ProfiledHook , rerenderCallbackProps ) ) ;
63
79
}
64
80
65
- return [
66
- Object . assign ( { } , stream , {
67
- renders : stream . renders ,
68
- totalSnapshotCount : stream . totalRenderCount ,
69
- async peekSnapshot ( options ) {
70
- return ( await stream . peekRender ( options ) ) . snapshot ;
71
- } ,
72
- async takeSnapshot ( options ) {
73
- return ( await stream . takeRender ( options ) ) . snapshot ;
74
- } ,
75
- getCurrentSnapshot ( ) {
76
- return stream . getCurrentRender ( ) . snapshot ;
77
- } ,
78
- async waitForNextSnapshot ( options ) {
79
- return ( await stream . waitForNextRender ( options ) ) . snapshot ;
80
- } ,
81
- } satisfies ProfiledHookFields < ReturnValue > ) ,
82
- {
83
- rerender,
84
- unmount,
81
+ return {
82
+ [ assertableSymbol ] : stream ,
83
+ renders : stream . renders ,
84
+ totalSnapshotCount : stream . totalRenderCount ,
85
+ async peekSnapshot ( options ) {
86
+ return ( await stream . peekRender ( options ) ) . snapshot ;
87
+ } ,
88
+ takeSnapshot : markAssertable ( async function takeSnapshot ( options ) {
89
+ return ( await stream . takeRender ( options ) ) . snapshot ;
90
+ } , stream ) ,
91
+ getCurrentSnapshot ( ) {
92
+ return stream . getCurrentRender ( ) . snapshot ;
85
93
} ,
86
- ] ;
94
+ async waitForNextSnapshot ( options ) {
95
+ return ( await stream . waitForNextRender ( options ) ) . snapshot ;
96
+ } ,
97
+ rerender,
98
+ unmount,
99
+ } ;
87
100
}
0 commit comments