// The pure derivations over the client's own session state: what counts as a // served pending interaction, what a title or a preview becomes, which // conversation is on screen, and whether a queued alert is still owed. import { test } from 'node:test' import assert from 'node:assert/strict' import { isOnScreen, preview, questionText, servedPendingKind, stillWorth, titleOf, } from '../../src/client/core/session.js' test('only the three interaction kinds the Harness renders are served', () => { assert.equal(servedPendingKind({ kind: 'approval' }), 'approval') assert.equal(servedPendingKind({ kind: 'question' }), 'question') assert.equal(servedPendingKind({ kind: 'plan-review' }), 'plan-review') assert.equal(servedPendingKind({ kind: 'something-else' }), undefined) assert.equal(servedPendingKind({ kind: 42 }), undefined) assert.equal(servedPendingKind(undefined), undefined) assert.equal(servedPendingKind(null), undefined) assert.equal(servedPendingKind('approval'), undefined) }) test('a preview collapses whitespace and never exceeds one popup line', () => { assert.equal(preview(' a\n\t b '), 'a b') assert.equal(preview(undefined), '') assert.equal(preview('x'.repeat(80)), 'x'.repeat(80)) assert.equal(preview('x'.repeat(81)), `${'x'.repeat(79)}…`) }) test('the first question text is read across every shape the client publishes', () => { assert.equal(questionText({ questions: [{ question: '继续吗?' }] }), '继续吗?') assert.equal(questionText({ questions: [{ text: '继续吗?' }] }), '继续吗?') assert.equal(questionText({ question: '继续吗?' }), '继续吗?') assert.equal(questionText({ prompt: '继续吗?' }), '继续吗?') assert.equal(questionText({ displayReason: { text: '继续吗?' } }), '继续吗?') assert.equal(questionText({ reason: { text: '继续吗?' } }), '继续吗?') assert.equal(questionText({}), '') assert.equal(questionText(null), '') assert.equal(questionText('继续吗?'), '') }) test('a session title falls back to its identity', () => { assert.equal(titleOf({ title: ' 会话 A ' }, 'abcdef123456'), '会话 A') assert.equal(titleOf({ title: '' }, 'abcdef123456'), 'abcdef12') assert.equal(titleOf(undefined, 'abcdef123456'), 'abcdef12') assert.equal(titleOf({ title: 42 }, 'abcdef123456'), 'abcdef12') }) test('the conversation on screen is the one the main view retains', () => { const list = { byId: { a: { retainedBy: { mainView: 1 } }, b: { retainedBy: { mainView: 0 } } } } assert.equal(isOnScreen('a', list), true) assert.equal(isOnScreen('b', list), false) assert.equal(isOnScreen('c', list), false) assert.equal(isOnScreen('a', undefined), false) }) test('a queued alert is dropped when its conversation resumed inside the settle window', () => { const candidate = { kind: 'completion', sessionId: 'a', test: false } const live = (byId, status) => ({ list: { byId }, status }) assert.equal(stillWorth(candidate, { list: undefined, status: undefined }), true) assert.equal(stillWorth(candidate, live({ a: { running: false } })), true) assert.equal(stillWorth(candidate, live({})), true) assert.equal(stillWorth(candidate, live({ a: { running: true } })), false) // The per-session selector wins over the list summary, which still carries the // pre-transition flag. assert.equal(stillWorth(candidate, { list: { byId: { a: { running: true } } }, status: new Map([['a', { running: false }]]) }), true) // A test alert is owed no matter what the live state says. assert.equal(stillWorth({ ...candidate, test: true }, live({ a: { running: true } })), true) })