22
33import type { MockedObject } from "vitest" ;
44import { afterEach , beforeEach , describe , expect , it , vi } from "vitest" ;
5+ import type { AbstractTransport } from "../src/core/Transport.js" ;
56import {
67 NativeWebSocketTransport ,
78 WebSocketTransportFactory ,
89 WsWebSocketTransport ,
910} from "../src/core/Transport.js" ;
1011import * as ws from "ws" ;
11- import type { RosbridgeMessage } from "../src/types/protocol.js" ;
12+ import type {
13+ RosbridgeMessage ,
14+ RosbridgePngMessage ,
15+ } from "../src/types/protocol.js" ;
16+ import pngparse from "pngparse" ;
17+
18+ vi . mock ( "pngparse" ) ;
1219
1320describe ( "Transport" , ( ) => {
1421 afterEach ( ( ) => {
@@ -17,7 +24,140 @@ describe("Transport", () => {
1724 } ) ;
1825
1926 describe ( "AbstractTransport" , ( ) => {
20- it . todo ( "todo" ) ;
27+ let mockPngParseModule : MockedObject < typeof pngparse > ;
28+ let mockSocket : MockedObject < WebSocket > ;
29+ let transport : AbstractTransport ;
30+
31+ beforeEach ( ( ) => {
32+ // So that the nodejs decompress png util is used, not the browser one
33+ vi . stubGlobal ( "window" , undefined ) ;
34+
35+ mockPngParseModule = vi . mocked ( pngparse ) ;
36+
37+ mockSocket = {
38+ send : vi . fn ( ) ,
39+ close : vi . fn ( ) ,
40+ readyState : WebSocket . OPEN ,
41+ onopen : null ,
42+ onclose : null ,
43+ onerror : null ,
44+ onmessage : null ,
45+ } as unknown as MockedObject < WebSocket > ;
46+
47+ transport = new NativeWebSocketTransport ( mockSocket ) ;
48+ } ) ;
49+
50+ it ( "should handle RosbridgeMessage" , ( ) => {
51+ const messageListener = vi . fn ( ) ;
52+
53+ transport . on ( "message" , messageListener ) ;
54+
55+ const message : RosbridgeMessage = {
56+ op : "test" ,
57+ } ;
58+
59+ const messageEvent : Partial < MessageEvent > = {
60+ type : "message" ,
61+ data : JSON . stringify ( message ) ,
62+ } ;
63+
64+ mockSocket . onmessage ?.( messageEvent as MessageEvent ) ;
65+
66+ expect ( messageListener ) . toHaveBeenCalledWith ( message ) ;
67+ } ) ;
68+
69+ it ( "should handle RosbridgeFragmentMessage" , ( ) => {
70+ // TODO
71+ } ) ;
72+
73+ it ( "should handle RosbridgePngMessage" , async ( ) => {
74+ mockPngParseModule . parse . mockImplementation (
75+ (
76+ // Normally, this is the compressed PNG data.
77+ // For our tests, it's a string buffer of "success" or "failure".
78+ data : Buffer ,
79+ cb : ( error ?: Error , data ?: pngparse . ImageData ) => void ,
80+ ) => {
81+ const decodedImage : pngparse . ImageData = {
82+ width : 100 ,
83+ height : 100 ,
84+ channels : 1 ,
85+ data : Buffer . from ( JSON . stringify ( { op : "test" } ) ) ,
86+ trailer : Buffer . from ( "" ) ,
87+ } ;
88+ switch ( data . toString ( ) ) {
89+ case "success" :
90+ cb ( undefined , decodedImage ) ;
91+ break ;
92+ case "failure" :
93+ cb ( new Error ( "test" ) , undefined ) ;
94+ break ;
95+ }
96+ } ,
97+ ) ;
98+
99+ const messageListener = vi . fn ( ) ;
100+ const errorListener = vi . fn ( ) ;
101+
102+ transport . on ( "message" , messageListener ) ;
103+ transport . on ( "error" , errorListener ) ;
104+
105+ // Obviously these are not real PNG encoded messages.
106+ // But they're good enough for mocking responses in our tests.
107+ const successMessage : RosbridgePngMessage = {
108+ op : "png" ,
109+ data : Buffer . from ( "success" ) . toString ( "base64" ) ,
110+ } ;
111+
112+ const failureMessage : RosbridgePngMessage = {
113+ op : "png" ,
114+ data : Buffer . from ( "failure" ) . toString ( "base64" ) ,
115+ } ;
116+
117+ // -- SUCCESS -- //
118+
119+ mockSocket . onmessage ?.( {
120+ type : "message" ,
121+ data : JSON . stringify ( successMessage ) ,
122+ } as MessageEvent ) ;
123+
124+ // Wait for the message to be processed.
125+ // PNG decompression occurs asynchronously.
126+ await vi . waitFor ( ( ) => {
127+ expect ( errorListener ) . not . toHaveBeenCalled ( ) ;
128+ expect ( messageListener ) . toHaveBeenCalledWith ( { op : "test" } ) ;
129+ } , 500 ) ;
130+
131+ vi . clearAllMocks ( ) ;
132+
133+ // -- FAILURE -- //
134+
135+ mockSocket . onmessage ?.( {
136+ type : "message" ,
137+ data : JSON . stringify ( failureMessage ) ,
138+ } as MessageEvent ) ;
139+
140+ // Wait for the message to be processed.
141+ // PNG decompression occurs asynchronously.
142+ await vi . waitFor ( ( ) => {
143+ expect ( errorListener ) . toHaveBeenCalledWith (
144+ new Error ( "Cannot process PNG encoded message: test" ) ,
145+ ) ;
146+ expect ( messageListener ) . not . toHaveBeenCalled ( ) ;
147+ } , 500 ) ;
148+ } ) ;
149+
150+ it ( "should handle BSON message" , ( ) => {
151+ // TODO
152+ } ) ;
153+
154+ it ( "should handle CBOR message" , ( ) => {
155+ // TODO
156+ } ) ;
157+
158+ it ( "should handle JSON message" , ( ) => {
159+ // TODO
160+ } ) ;
21161 } ) ;
22162
23163 describe ( "NativeWebSocketTransport" , ( ) => {
0 commit comments