1
- import {
2
- renderHook ,
3
- type RenderHookResult ,
4
- waitFor ,
5
- } from "@testing-library/react" ;
1
+ import { renderHook , waitFor } from "@testing-library/react" ;
6
2
import type { WorkspaceAgentLog } from "api/typesGenerated" ;
7
3
import { MockWorkspaceAgent } from "testHelpers/entities" ;
8
4
import { createUseAgentLogs } from "./useAgentLogs" ;
@@ -22,14 +18,28 @@ function generateMockLogs(count: number): WorkspaceAgentLog[] {
22
18
} ) ) ;
23
19
}
24
20
25
- type MountHookResult = Readonly <
26
- RenderHookResult < readonly WorkspaceAgentLog [ ] , { enabled : boolean } > & {
27
- publisher : MockWebSocketPublisher ;
28
- }
29
- > ;
21
+ // A mutable object holding the most recent mock WebSocket connection. This
22
+ // value will change as the hook opens/closes new connections
23
+ type PublisherResult = {
24
+ current : MockWebSocketPublisher ;
25
+ } ;
26
+
27
+ type MountHookResult = Readonly < {
28
+ // Note: the value of `current` should be readonly, but the `current`
29
+ // property itself should be mutable
30
+ hookResult : {
31
+ current : readonly WorkspaceAgentLog [ ] ;
32
+ } ;
33
+ rerender : ( props : { enabled : boolean } ) => void ;
34
+ publisherResult : PublisherResult ;
35
+ } > ;
30
36
31
37
function mountHook ( ) : MountHookResult {
32
- let publisher ! : MockWebSocketPublisher ;
38
+ // Have to cheat the types a little bit to avoid a chicken-and-the-egg
39
+ // scenario. publisherResult will be initialized with an undefined current
40
+ // value, but it'll be guaranteed not to be undefined by the time this
41
+ // function returns.
42
+ const publisherResult : Partial < PublisherResult > = { current : undefined } ;
33
43
const useAgentLogs = createUseAgentLogs ( ( agentId , params ) => {
34
44
return new OneWayWebSocket ( {
35
45
apiRoute : `/api/v2/workspaceagents/${ agentId } /logs` ,
@@ -38,41 +48,45 @@ function mountHook(): MountHookResult {
38
48
after : params ?. after ?. toString ( ) || "0" ,
39
49
} ) ,
40
50
websocketInit : ( url ) => {
41
- const [ mockSocket , mockPub ] = createMockWebSocket ( url ) ;
42
- publisher = mockPub ;
51
+ const [ mockSocket , mockPublisher ] = createMockWebSocket ( url ) ;
52
+ publisherResult . current = mockPublisher ;
43
53
return mockSocket ;
44
54
} ,
45
55
} ) ;
46
56
} ) ;
47
57
48
- const { result, rerender, unmount } = renderHook (
58
+ const { result, rerender } = renderHook (
49
59
( { enabled } ) => useAgentLogs ( MockWorkspaceAgent , enabled ) ,
50
60
{ initialProps : { enabled : true } } ,
51
61
) ;
52
62
53
- return { result, rerender, unmount, publisher } ;
63
+ return {
64
+ rerender,
65
+ hookResult : result ,
66
+ publisherResult : publisherResult as PublisherResult ,
67
+ } ;
54
68
}
55
69
56
70
describe ( "useAgentLogs" , ( ) => {
57
71
it ( "clears logs when hook becomes disabled (protection to avoid duplicate logs when hook goes back to being re-enabled)" , async ( ) => {
58
- const { result , rerender , publisher } = mountHook ( ) ;
72
+ const { hookResult , publisherResult , rerender } = mountHook ( ) ;
59
73
60
74
// Verify that logs can be received after mount
61
75
const initialLogs = generateMockLogs ( 3 ) ;
62
76
const initialEvent = new MessageEvent < string > ( "message" , {
63
77
data : JSON . stringify ( initialLogs ) ,
64
78
} ) ;
65
- publisher . publishMessage ( initialEvent ) ;
79
+ publisherResult . current . publishMessage ( initialEvent ) ;
66
80
await waitFor ( ( ) => {
67
81
// Using expect.arrayContaining to account for the fact that we're
68
82
// not guaranteed to receive WebSocket events in order
69
- expect ( result . current ) . toEqual ( expect . arrayContaining ( initialLogs ) ) ;
83
+ expect ( hookResult . current ) . toEqual ( expect . arrayContaining ( initialLogs ) ) ;
70
84
} ) ;
71
85
72
86
// Disable the hook (and have the hook close the connection behind the
73
87
// scenes)
74
88
rerender ( { enabled : false } ) ;
75
- await waitFor ( ( ) => expect ( result . current ) . toHaveLength ( 0 ) ) ;
89
+ await waitFor ( ( ) => expect ( hookResult . current ) . toHaveLength ( 0 ) ) ;
76
90
77
91
// Re-enable the hook (creating an entirely new connection), and send
78
92
// new logs
@@ -81,9 +95,9 @@ describe("useAgentLogs", () => {
81
95
const newEvent = new MessageEvent < string > ( "message" , {
82
96
data : JSON . stringify ( newLogs ) ,
83
97
} ) ;
84
- publisher . publishMessage ( newEvent ) ;
98
+ publisherResult . current . publishMessage ( newEvent ) ;
85
99
await waitFor ( ( ) => {
86
- expect ( result . current ) . toEqual ( expect . arrayContaining ( newLogs ) ) ;
100
+ expect ( hookResult . current ) . toEqual ( expect . arrayContaining ( newLogs ) ) ;
87
101
} ) ;
88
102
} ) ;
89
103
} ) ;
0 commit comments