@@ -75,30 +75,6 @@ vi.mock("./device-identity.ts", () => ({
7575
7676const { GatewayBrowserClient } = await import ( "./gateway.ts" ) ;
7777
78- function createStorageMock ( ) : Storage {
79- const store = new Map < string , string > ( ) ;
80- return {
81- get length ( ) {
82- return store . size ;
83- } ,
84- clear ( ) {
85- store . clear ( ) ;
86- } ,
87- getItem ( key : string ) {
88- return store . get ( key ) ?? null ;
89- } ,
90- key ( index : number ) {
91- return Array . from ( store . keys ( ) ) [ index ] ?? null ;
92- } ,
93- removeItem ( key : string ) {
94- store . delete ( key ) ;
95- } ,
96- setItem ( key : string , value : string ) {
97- store . set ( key , String ( value ) ) ;
98- } ,
99- } ;
100- }
101-
10278function getLatestWebSocket ( ) : MockWebSocket {
10379 const ws = wsInstances . at ( - 1 ) ;
10480 if ( ! ws ) {
@@ -118,23 +94,8 @@ describe("GatewayBrowserClient", () => {
11894 publicKey : "public-key" , // pragma: allowlist secret
11995 } ) ;
12096
121- const localStorage = createStorageMock ( ) ;
97+ window . localStorage . clear ( ) ;
12298 vi . stubGlobal ( "WebSocket" , MockWebSocket ) ;
123- vi . stubGlobal ( "localStorage" , localStorage ) ;
124- vi . stubGlobal ( "crypto" , {
125- randomUUID : vi . fn ( ( ) => "req-1" ) ,
126- subtle : { } ,
127- } ) ;
128- vi . stubGlobal ( "navigator" , {
129- language : "en-GB" ,
130- platform : "test-platform" ,
131- userAgent : "test-agent" ,
132- } ) ;
133- vi . stubGlobal ( "window" , {
134- clearTimeout : vi . fn ( ) ,
135- localStorage,
136- setTimeout : vi . fn ( ( ) => 1 ) ,
137- } ) ;
13899
139100 storeDeviceAuthToken ( {
140101 deviceId : "device-1" ,
@@ -148,7 +109,7 @@ describe("GatewayBrowserClient", () => {
148109 vi . unstubAllGlobals ( ) ;
149110 } ) ;
150111
151- it ( "keeps shared auth token separate from cached device token " , async ( ) => {
112+ it ( "prefers explicit shared auth over cached device tokens " , async ( ) => {
152113 const client = new GatewayBrowserClient ( {
153114 url : "ws://127.0.0.1:18789" ,
154115 token : "shared-auth-token" ,
@@ -162,19 +123,47 @@ describe("GatewayBrowserClient", () => {
162123 event : "connect.challenge" ,
163124 payload : { nonce : "nonce-1" } ,
164125 } ) ;
165- await Promise . resolve ( ) ;
126+ await vi . waitFor ( ( ) => expect ( ws . sent . length ) . toBeGreaterThan ( 0 ) ) ;
166127
167128 const connectFrame = JSON . parse ( ws . sent . at ( - 1 ) ?? "{}" ) as {
168129 id ?: string ;
169130 method ?: string ;
170131 params ?: { auth ?: { token ?: string } } ;
171132 } ;
172- expect ( connectFrame . id ) . toBe ( "req-1 " ) ;
133+ expect ( typeof connectFrame . id ) . toBe ( "string " ) ;
173134 expect ( connectFrame . method ) . toBe ( "connect" ) ;
174135 expect ( connectFrame . params ?. auth ?. token ) . toBe ( "shared-auth-token" ) ;
175136 expect ( signDevicePayloadMock ) . toHaveBeenCalledWith ( "private-key" , expect . any ( String ) ) ;
176137 const signedPayload = signDevicePayloadMock . mock . calls [ 0 ] ?. [ 1 ] ;
138+ expect ( signedPayload ) . toContain ( "|shared-auth-token|nonce-1" ) ;
139+ expect ( signedPayload ) . not . toContain ( "stored-device-token" ) ;
140+ } ) ;
141+
142+ it ( "uses cached device tokens only when no explicit shared auth is provided" , async ( ) => {
143+ const client = new GatewayBrowserClient ( {
144+ url : "ws://127.0.0.1:18789" ,
145+ } ) ;
146+
147+ client . start ( ) ;
148+ const ws = getLatestWebSocket ( ) ;
149+ ws . emitOpen ( ) ;
150+ ws . emitMessage ( {
151+ type : "event" ,
152+ event : "connect.challenge" ,
153+ payload : { nonce : "nonce-1" } ,
154+ } ) ;
155+ await vi . waitFor ( ( ) => expect ( ws . sent . length ) . toBeGreaterThan ( 0 ) ) ;
156+
157+ const connectFrame = JSON . parse ( ws . sent . at ( - 1 ) ?? "{}" ) as {
158+ id ?: string ;
159+ method ?: string ;
160+ params ?: { auth ?: { token ?: string } } ;
161+ } ;
162+ expect ( typeof connectFrame . id ) . toBe ( "string" ) ;
163+ expect ( connectFrame . method ) . toBe ( "connect" ) ;
164+ expect ( connectFrame . params ?. auth ?. token ) . toBe ( "stored-device-token" ) ;
165+ expect ( signDevicePayloadMock ) . toHaveBeenCalledWith ( "private-key" , expect . any ( String ) ) ;
166+ const signedPayload = signDevicePayloadMock . mock . calls [ 0 ] ?. [ 1 ] ;
177167 expect ( signedPayload ) . toContain ( "|stored-device-token|nonce-1" ) ;
178- expect ( signedPayload ) . not . toContain ( "shared-auth-token" ) ;
179168 } ) ;
180169} ) ;
0 commit comments