@@ -7,6 +7,7 @@ import {ipcMain} from 'electron';
77import WebContentsManager from 'app/views/webContentsManager' ;
88import {
99 SERVER_REMOVED ,
10+ SESSION_ATTRIBUTES_FIELD_UPDATED ,
1011 SESSION_ATTRIBUTES_MANIFEST_INVALIDATED ,
1112 SESSION_ATTRIBUTES_RESEND_REQUESTED ,
1213} from 'common/communication' ;
@@ -47,6 +48,7 @@ jest.mock('common/servers/serverManager', () => ({
4748 getServer : jest . fn ( ) ,
4849 lookupServerByURL : jest . fn ( ) ,
4950 getRemoteInfo : jest . fn ( ) ,
51+ updateRemoteInfo : jest . fn ( ) ,
5052 } ,
5153} ) ) ;
5254
@@ -84,6 +86,7 @@ describe('main/sessionAttributes/sessionAttributesManager', () => {
8486 let serverRemovedHandler : ( srv : typeof server ) => void ;
8587 let manifestInvalidatedHandler : ( event : IpcMainEvent ) => void ;
8688 let resendRequestedHandler : ( event : IpcMainEvent ) => void ;
89+ let fieldUpdatedHandler : ( event : IpcMainEvent , field : unknown ) => void ;
8790
8891 beforeEach ( ( ) => {
8992 jest . clearAllMocks ( ) ;
@@ -101,6 +104,9 @@ describe('main/sessionAttributes/sessionAttributesManager', () => {
101104 if ( channel === SESSION_ATTRIBUTES_RESEND_REQUESTED ) {
102105 resendRequestedHandler = handler ;
103106 }
107+ if ( channel === SESSION_ATTRIBUTES_FIELD_UPDATED ) {
108+ fieldUpdatedHandler = handler ;
109+ }
104110 return ipcMainMock ;
105111 } ) ;
106112 ServerManagerMock . getServer . mockReturnValue ( server as never ) ;
@@ -231,4 +237,116 @@ describe('main/sessionAttributes/sessionAttributesManager', () => {
231237 expect ( updateServerInfos ) . not . toHaveBeenCalled ( ) ;
232238 expect ( ( manager as unknown as { lastSentAt : Map < string , Map < string , number > > } ) . lastSentAt . has ( server . id ) ) . toBe ( true ) ;
233239 } ) ;
240+
241+ it ( 'appends a new field to the manifest on SESSION_ATTRIBUTES_FIELD_UPDATED' , ( ) => {
242+ ServerManagerMock . getRemoteInfo . mockReturnValue ( {
243+ sessionAttributesManifest : [
244+ { name : 'os_platform' , type : 'text' , ttl_seconds : 0 , grace_period_seconds : 0 , platforms : [ 'desktop' ] } ,
245+ ] ,
246+ } ) ;
247+ WebContentsManagerMock . getViewByWebContentsId . mockReturnValue ( { serverId : server . id } as never ) ;
248+
249+ fieldUpdatedHandler ( { sender : { id : 42 } } as IpcMainEvent , {
250+ name : 'hardware_id' ,
251+ type : 'text' ,
252+ attrs : { enabled : true , ttl_seconds : 300 , grace_period_seconds : 300 , platforms : [ 'desktop' ] } ,
253+ } ) ;
254+
255+ expect ( ServerManagerMock . updateRemoteInfo ) . toHaveBeenCalledWith ( server . id , {
256+ sessionAttributesManifest : [
257+ { name : 'os_platform' , type : 'text' , ttl_seconds : 0 , grace_period_seconds : 0 , platforms : [ 'desktop' ] } ,
258+ { name : 'hardware_id' , type : 'text' , ttl_seconds : 300 , grace_period_seconds : 300 , platforms : [ 'desktop' ] } ,
259+ ] ,
260+ } ) ;
261+ } ) ;
262+
263+ it ( 'replaces an existing field in the manifest on SESSION_ATTRIBUTES_FIELD_UPDATED' , ( ) => {
264+ ServerManagerMock . getRemoteInfo . mockReturnValue ( {
265+ sessionAttributesManifest : [
266+ { name : 'hardware_id' , type : 'text' , ttl_seconds : 60 , grace_period_seconds : 60 , platforms : [ 'desktop' ] } ,
267+ ] ,
268+ } ) ;
269+ WebContentsManagerMock . getViewByWebContentsId . mockReturnValue ( { serverId : server . id } as never ) ;
270+
271+ fieldUpdatedHandler ( { sender : { id : 42 } } as IpcMainEvent , {
272+ name : 'hardware_id' ,
273+ type : 'text' ,
274+ attrs : { enabled : true , ttl_seconds : 300 , grace_period_seconds : 300 , platforms : [ 'desktop' ] } ,
275+ } ) ;
276+
277+ expect ( ServerManagerMock . updateRemoteInfo ) . toHaveBeenCalledWith ( server . id , {
278+ sessionAttributesManifest : [
279+ { name : 'hardware_id' , type : 'text' , ttl_seconds : 300 , grace_period_seconds : 300 , platforms : [ 'desktop' ] } ,
280+ ] ,
281+ } ) ;
282+ } ) ;
283+
284+ it ( 'removes a field from the manifest when it is disabled' , ( ) => {
285+ ServerManagerMock . getRemoteInfo . mockReturnValue ( {
286+ sessionAttributesManifest : [
287+ { name : 'hardware_id' , type : 'text' , ttl_seconds : 300 , grace_period_seconds : 300 , platforms : [ 'desktop' ] } ,
288+ ] ,
289+ } ) ;
290+ WebContentsManagerMock . getViewByWebContentsId . mockReturnValue ( { serverId : server . id } as never ) ;
291+
292+ fieldUpdatedHandler ( { sender : { id : 42 } } as IpcMainEvent , {
293+ name : 'hardware_id' ,
294+ type : 'text' ,
295+ attrs : { enabled : false , ttl_seconds : 300 , grace_period_seconds : 300 , platforms : [ 'desktop' ] } ,
296+ } ) ;
297+
298+ expect ( ServerManagerMock . updateRemoteInfo ) . toHaveBeenCalledWith ( server . id , {
299+ sessionAttributesManifest : [ ] ,
300+ } ) ;
301+ } ) ;
302+
303+ it ( 'does not track a field that no longer targets the desktop' , ( ) => {
304+ ServerManagerMock . getRemoteInfo . mockReturnValue ( {
305+ sessionAttributesManifest : [
306+ { name : 'hardware_id' , type : 'text' , ttl_seconds : 300 , grace_period_seconds : 300 , platforms : [ 'desktop' ] } ,
307+ ] ,
308+ } ) ;
309+ WebContentsManagerMock . getViewByWebContentsId . mockReturnValue ( { serverId : server . id } as never ) ;
310+
311+ fieldUpdatedHandler ( { sender : { id : 42 } } as IpcMainEvent , {
312+ name : 'hardware_id' ,
313+ type : 'text' ,
314+ attrs : { enabled : true , ttl_seconds : 300 , grace_period_seconds : 300 , platforms : [ 'mobile' ] } ,
315+ } ) ;
316+
317+ expect ( ServerManagerMock . updateRemoteInfo ) . toHaveBeenCalledWith ( server . id , {
318+ sessionAttributesManifest : [ ] ,
319+ } ) ;
320+ } ) ;
321+
322+ it ( 'clears the lastSentAt entry for the updated field so it is resent' , ( ) => {
323+ ServerManagerMock . getRemoteInfo . mockReturnValue ( {
324+ sessionAttributesManifest : [
325+ { name : 'hardware_id' , type : 'text' , ttl_seconds : 300 , grace_period_seconds : 300 , platforms : [ 'desktop' ] } ,
326+ ] ,
327+ } ) ;
328+ ( manager as unknown as { lastSentAt : Map < string , Map < string , number > > } ) . lastSentAt . set ( server . id , new Map ( [ [ 'hardware_id' , Date . now ( ) ] ] ) ) ;
329+ WebContentsManagerMock . getViewByWebContentsId . mockReturnValue ( { serverId : server . id } as never ) ;
330+
331+ fieldUpdatedHandler ( { sender : { id : 42 } } as IpcMainEvent , {
332+ name : 'hardware_id' ,
333+ type : 'text' ,
334+ attrs : { enabled : true , ttl_seconds : 600 , grace_period_seconds : 300 , platforms : [ 'desktop' ] } ,
335+ } ) ;
336+
337+ expect ( ( manager as unknown as { lastSentAt : Map < string , Map < string , number > > } ) . lastSentAt . get ( server . id ) ?. has ( 'hardware_id' ) ) . toBe ( false ) ;
338+ } ) ;
339+
340+ it ( 'ignores an invalid field payload on SESSION_ATTRIBUTES_FIELD_UPDATED' , ( ) => {
341+ ServerManagerMock . getRemoteInfo . mockReturnValue ( {
342+ sessionAttributesManifest : [
343+ { name : 'hardware_id' , type : 'text' , ttl_seconds : 300 , grace_period_seconds : 300 , platforms : [ 'desktop' ] } ,
344+ ] ,
345+ } ) ;
346+ WebContentsManagerMock . getViewByWebContentsId . mockReturnValue ( { serverId : server . id } as never ) ;
347+
348+ fieldUpdatedHandler ( { sender : { id : 42 } } as IpcMainEvent , { name : 'hardware_id' } ) ;
349+
350+ expect ( ServerManagerMock . updateRemoteInfo ) . not . toHaveBeenCalled ( ) ;
351+ } ) ;
234352} ) ;
0 commit comments