Files
client-web/src/api/session.test.mjs
T

91 lines
3.7 KiB
JavaScript

import assert from 'node:assert/strict'
import test from 'node:test'
import {
accessTokenIdentity,
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(), '')
})
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))
})
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'))
})