2026-09-03 18:11:07 +08:00
import assert from 'node:assert/strict'
import test from 'node:test'
import {
2026-10-05 17:13:46 +08:00
accessTokenIdentity ,
2026-09-03 18:11:07 +08:00
ACCESS_TOKEN_KEY ,
REFRESH_TOKEN_KEY ,
REMEMBERED_LOGIN_ID_KEY ,
clearSessionTokens ,
getRememberedLoginId ,
persistRememberedLoginId ,
persistTokenPair ,
} from './session.ts'
function storage () {
const values = new Map ()
return {
getItem : ( key ) => values . get ( key ) ?? null ,
setItem : ( key , value ) => values . set ( key , String ( value )),
removeItem : ( key ) => values . delete ( key ),
}
}
function installStorage () {
globalThis . localStorage = storage ()
globalThis . sessionStorage = storage ()
}
test ( 'persists the normal rotating session independently of remembered account preference' , () => {
installStorage ()
persistTokenPair ({
tokenType : 'Bearer' ,
accessToken : 'access-token' ,
expiresIn : 1440 ,
refreshToken : 'refresh-token' ,
refreshExpiresIn : 604800 ,
})
assert . equal ( localStorage . getItem ( ACCESS_TOKEN_KEY ), 'access-token' )
assert . equal ( localStorage . getItem ( REFRESH_TOKEN_KEY ), 'refresh-token' )
assert . equal ( sessionStorage . getItem ( ACCESS_TOKEN_KEY ), null )
assert . equal ( sessionStorage . getItem ( REFRESH_TOKEN_KEY ), null )
})
test ( 'remembers only the login id and keeps it when session tokens are cleared' , () => {
installStorage ()
persistRememberedLoginId ( 'merchant-user' , true )
localStorage . setItem ( ACCESS_TOKEN_KEY , 'access-token' )
localStorage . setItem ( REFRESH_TOKEN_KEY , 'refresh-token' )
clearSessionTokens ()
assert . equal ( getRememberedLoginId (), 'merchant-user' )
assert . equal ( localStorage . getItem ( REMEMBERED_LOGIN_ID_KEY ), 'merchant-user' )
assert . equal ( localStorage . getItem ( ACCESS_TOKEN_KEY ), null )
assert . equal ( localStorage . getItem ( REFRESH_TOKEN_KEY ), null )
persistRememberedLoginId ( 'merchant-user' , false )
assert . equal ( getRememberedLoginId (), '' )
})
2026-10-02 23:29:20 +08:00
test ( 'normal token rotation never removes either shared token between writes' , () => {
installStorage ()
localStorage . setItem ( ACCESS_TOKEN_KEY , 'old-access' )
localStorage . setItem ( REFRESH_TOKEN_KEY , 'old-refresh' )
const removed = []
const remove = localStorage . removeItem
localStorage . removeItem = key => { removed . push ( key ); remove ( key ) }
persistTokenPair ({ accessToken : 'new-access' , refreshToken : 'new-refresh' })
assert . ok ( ! removed . includes ( ACCESS_TOKEN_KEY ))
assert . ok ( ! removed . includes ( REFRESH_TOKEN_KEY ))
})
2026-10-05 17:13:46 +08:00
function rawIdentity ( overrides = '' ) {
return `test. ${ Buffer . from ( `{"user_id":2107003446494334978,"tenant_id":2107003446494334978,"membership_id":2107003446494334978,"app_code":"MERCHANT" ${ overrides } }` ). toString ( 'base64url' ) } .test`
}
test ( 'identity preserves low digits of numeric 19 digit user customer and membership' ,()=>{
const original = rawIdentity (); const json = Buffer . from ( original . split ( '.' )[ 1 ], 'base64url' ). toString ();
for ( const field of [ 'user_id' , 'tenant_id' , 'membership_id' ]){
const changed = json . replace ( `" ${ field } ":2107003446494334978` , `" ${ field } ":2107003446494334979` )
assert . notEqual ( accessTokenIdentity ( original ), accessTokenIdentity ( `test. ${ Buffer . from ( changed ). toString ( 'base64url' ) } .test` ))
}
})
test ( 'identity string and numeric integers are equivalent without changing other strings' ,()=>{
const a = rawIdentity (); const raw = Buffer . from ( a . split ( '.' )[ 1 ], 'base64url' ). toString ();
const b = `test. ${ Buffer . from ( raw . replaceAll ( ':2107003446494334978' , ':"2107003446494334978"' )). toString ( 'base64url' ) } .test`
assert . equal ( accessTokenIdentity ( a ), accessTokenIdentity ( b ))
const decorated = rawIdentity ( ',"username":' + JSON . stringify ( 'number 2107003446494334979 and "tenant_id":2107003446494334979' ) + ',"note":"1234567890123456789"' )
assert . equal ( accessTokenIdentity ( a ), accessTokenIdentity ( decorated ))
assert . ok ( accessTokenIdentity ( a ). includes ( '2107003446494334978' ))
})