22import { broadcast , type EventRegistry } from "@simulcast/core" ;
33import { useBroadcast } from "@simulcast/preact" ;
44import { assertStrictEquals } from "@std/assert" ;
5- import { mockDOM } from "@test/mockDOM.ts " ;
6- import { timeout } from "@test/timeout.ts " ;
7- import { type ComponentProps , render , type TargetedMouseEvent } from "preact" ;
5+ import { cleanup , render , screen } from "@testing-library/preact " ;
6+ import { userEvent } from "@testing-library/user-event " ;
7+ import type { ComponentProps , TargetedMouseEvent } from "preact" ;
88import { useState } from "preact/hooks" ;
99
1010const CountComponent = ( properties : ComponentProps < "button" > ) => {
1111 const [ count , setCount ] = useState ( 0 ) ;
1212
1313 return (
1414 < button
15- className = "add"
1615 onClick = { ( ) => setCount ( count + 1 ) }
16+ title = "Add"
1717 { ...properties }
1818 >
1919 { count }
@@ -22,7 +22,6 @@ const CountComponent = (properties: ComponentProps<"button">) => {
2222} ;
2323
2424const BroadcastComponent = ( {
25- className,
2625 registry,
2726 state,
2827 ...properties
@@ -40,22 +39,21 @@ const BroadcastComponent = ({
4039
4140 return (
4241 < button
43- className = { className ?? "broadcast" }
4442 onClick = { emitClick }
43+ title = "Broadcast"
4544 { ...properties }
4645 >
4746 Click me!
4847 </ button >
4948 ) ;
5049} ;
5150
51+ Deno . test . afterEach ( cleanup ) ;
52+
5253Deno . test (
5354 "Broadcast's on handler is called once even when it re-renders" ,
5455 async ( ) => {
55- mockDOM ( { fakeTimers : true } ) ;
56-
5756 const state = { calledTimes : 0 } ;
58- const root = document . querySelector ( "#root" ) as HTMLDivElement ;
5957 const { registry } = broadcast < {
6058 click : TargetedMouseEvent < HTMLButtonElement > ;
6159 } > ( ) ;
@@ -67,31 +65,24 @@ Deno.test(
6765 < CountComponent />
6866 </ >
6967 ) ,
70- root ,
7168 ) ;
7269
73- const addButton = document . querySelector < HTMLButtonElement > (
74- "button.add" ,
75- ) as HTMLButtonElement ;
76- const broadcastButton = document . querySelector < HTMLButtonElement > (
77- "button.broadcast" ,
78- ) as HTMLButtonElement ;
79-
80- addButton . click ( ) ; // Click button that will re-render once
81- await timeout ( 10 ) ;
82- addButton . click ( ) ; // Click button that will re-render twice
83- await timeout ( 10 ) ;
84- broadcastButton . click ( ) ; // Click broadcast button once
70+ const addButton = screen . getByTitle < HTMLButtonElement > ( "Add" ) ;
71+ const broadcastButton = screen . getByTitle < HTMLButtonElement > (
72+ "Broadcast" ,
73+ ) ;
74+
75+ await userEvent . click ( addButton ) ; // Click button that will re-render once
76+ await userEvent . click ( addButton ) ; // Click button that will re-render twice
77+ await userEvent . click ( broadcastButton ) ; // Click broadcast button once
8578 assertStrictEquals ( state . calledTimes , 1 ) ; // State should be updated once
8679 assertStrictEquals ( addButton . textContent , "2" ) ; // Even when it re-rendered twice
8780 } ,
8881) ;
8982
9083Deno . test ( "Broadcast's on handler is removed when unmounted" , async ( ) => {
91- mockDOM ( { fakeTimers : true } ) ;
9284 const state1 = { calledTimes : 0 } ;
9385 const state2 = { calledTimes : 0 } ;
94- const root = document . querySelector ( "#root" ) as HTMLDivElement ;
9586 const { registry } = broadcast < {
9687 click : TargetedMouseEvent < HTMLButtonElement > ;
9788 } > ( ) ;
@@ -111,13 +102,13 @@ Deno.test("Broadcast's on handler is removed when unmounted", async () => {
111102 )
112103 : undefined }
113104 < BroadcastComponent
114- className = "always-visible-broadcast"
115105 state = { state2 }
106+ title = "Always visible Broadcast"
116107 { ...{ registry } }
117108 />
118109 < button
119- className = "toggle"
120110 onClick = { ( ) => setVisible ( ! visible ) }
111+ title = "Toggle"
121112 type = "button"
122113 >
123114 Toggle Visibility
@@ -126,32 +117,22 @@ Deno.test("Broadcast's on handler is removed when unmounted", async () => {
126117 ) ;
127118 } ;
128119
129- render ( < App /> , root ) ;
130-
131- await timeout ( ) ;
120+ render ( < App /> ) ;
132121
133- const toggleButton = document . querySelector < HTMLButtonElement > (
134- "button.toggle" ,
135- ) as HTMLButtonElement ;
136- const broadcastButton = document . querySelector < HTMLButtonElement > (
137- "button.broadcast" ,
138- ) as HTMLButtonElement ;
139- const alwaysVisibleBroadcastButton = document . querySelector <
122+ const toggleButton = screen . getByTitle < HTMLButtonElement > ( "Toggle" ) ;
123+ const broadcastButton = screen . getByTitle < HTMLButtonElement > ( "Broadcast" ) ;
124+ const alwaysVisibleBroadcastButton = screen . getByTitle <
140125 HTMLButtonElement
141- > (
142- "button.always-visible-broadcast" ,
143- ) as HTMLButtonElement ;
126+ > ( "Always visible Broadcast" ) ;
144127
145- await timeout ( ) ;
146128 // Click broadcast button that will be removed from the DOM
147- broadcastButton . click ( ) ;
129+ await userEvent . click ( broadcastButton ) ;
148130 // Click broadcast button that will stay in the DOM
149- alwaysVisibleBroadcastButton . click ( ) ;
131+ await userEvent . click ( alwaysVisibleBroadcastButton ) ;
150132 // Click toggle button (removes the first broadcast button)
151- toggleButton . click ( ) ;
152- await timeout ( ) ;
133+ await userEvent . click ( toggleButton ) ;
153134 // Click broadcast button that stayed again
154- alwaysVisibleBroadcastButton . click ( ) ;
135+ await userEvent . click ( alwaysVisibleBroadcastButton ) ;
155136 assertStrictEquals ( state1 . calledTimes , 2 ) ; // State 1 should have registered events until removed
156137 assertStrictEquals ( state2 . calledTimes , 3 ) ; // State 2 should have registered all events
157138} ) ;
0 commit comments