You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
3.5 KiB
TypeScript
72 lines
3.5 KiB
TypeScript
// apps/hq/test/module-access.test.ts — D28: module directory + portals quick-list.
|
|
import { describe, it, expect } from 'vitest'
|
|
import { openDb } from '../src/db'
|
|
import { seedIfEmpty } from '../src/seed'
|
|
import { createClient } from '../src/repos-clients'
|
|
import { createModule, assignModule, setModuleFieldValues, setModulePassword, moduleDirectory, listPortals } from '../src/repos-modules'
|
|
|
|
const KEY = '0'.repeat(64) // valid 32-byte hex key for the test's encryption
|
|
|
|
describe('moduleDirectory (D28)', () => {
|
|
it('returns the fieldSpec and every active client with its values', async () => {
|
|
const db = openDb(':memory:'); await seedIfEmpty(db)
|
|
const m = await createModule(db, 'u1', {
|
|
code: 'RTGS', name: 'RTGS', sac: '998314', allowedKinds: ['yearly'],
|
|
fieldSpec: [
|
|
{ key: 'ip', label: 'IP', type: 'text' },
|
|
{ key: 'portal_url', label: 'Portal URL', type: 'text' },
|
|
{ key: 'admin_password', label: 'Admin password', type: 'secret' },
|
|
],
|
|
})
|
|
const a = await createClient(db, 'u1', { name: 'Alpha Bank', stateCode: '32' })
|
|
const b = await createClient(db, 'u1', { name: 'Beta Bank', stateCode: '32' })
|
|
const cmA = await assignModule(db, 'u1', { clientId: a.id, moduleId: m.id, kind: 'yearly' })
|
|
await assignModule(db, 'u1', { clientId: b.id, moduleId: m.id, kind: 'yearly' })
|
|
await setModuleFieldValues(db, 'u1', cmA.id, { ip: '10.0.0.1', portal_url: 'https://rtgs.example/login' })
|
|
|
|
const dir = await moduleDirectory(db, m.id)
|
|
expect(dir).not.toBeNull()
|
|
expect(dir!.code).toBe('RTGS')
|
|
expect(dir!.fieldSpec.length).toBe(3)
|
|
expect(dir!.total).toBe(2)
|
|
const rowA = dir!.rows.find((r) => r.clientName === 'Alpha Bank')!
|
|
expect(rowA.fieldValues.ip).toBe('10.0.0.1')
|
|
expect(rowA.fieldValues.portal_url).toBe('https://rtgs.example/login')
|
|
})
|
|
|
|
it('is null for an unknown module', async () => {
|
|
const db = openDb(':memory:'); await seedIfEmpty(db)
|
|
expect(await moduleDirectory(db, 'nope')).toBeNull()
|
|
})
|
|
})
|
|
|
|
describe('listPortals (D28)', () => {
|
|
it('lists only subscriptions with a login and surfaces URL fields (never the password)', async () => {
|
|
const db = openDb(':memory:'); await seedIfEmpty(db)
|
|
const m = await createModule(db, 'u1', {
|
|
code: 'RECOVERX', name: 'RecoverX', sac: '998314', allowedKinds: ['yearly'],
|
|
fieldSpec: [
|
|
{ key: 'portal_url', label: 'Portal URL', type: 'text' },
|
|
{ key: 'note', label: 'Note', type: 'text' },
|
|
],
|
|
})
|
|
const a = await createClient(db, 'u1', { name: 'Alpha', stateCode: '32' })
|
|
const b = await createClient(db, 'u1', { name: 'Beta', stateCode: '32' })
|
|
const cmA = await assignModule(db, 'u1', { clientId: a.id, moduleId: m.id, kind: 'yearly' })
|
|
const cmB = await assignModule(db, 'u1', { clientId: b.id, moduleId: m.id, kind: 'yearly' })
|
|
// Alpha has a URL + a stored password; Beta has only a note → no login → excluded.
|
|
await setModuleFieldValues(db, 'u1', cmA.id, { portal_url: 'https://recoverx.example' })
|
|
await setModulePassword(db, 'u1', cmA.id, 'secret', KEY)
|
|
await setModuleFieldValues(db, 'u1', cmB.id, { note: 'nothing here' })
|
|
|
|
const portals = await listPortals(db)
|
|
expect(portals.length).toBe(1)
|
|
const p = portals[0]!
|
|
expect(p.clientName).toBe('Alpha')
|
|
expect(p.hasPassword).toBe(true)
|
|
expect(p.links.map((l) => l.url)).toContain('https://recoverx.example')
|
|
// the password itself is never in the payload
|
|
expect(JSON.stringify(p)).not.toContain('secret')
|
|
})
|
|
})
|