SettingsScreen CC 23 -> below 10. Form parsing, change detection and the dark-theme check moved to utils/ with unit tests; the dark switch now reads the OS scheme instead of comparing the background colour. Adds characterization tests for the screen.
78 lines
3.1 KiB
TypeScript
78 lines
3.1 KiB
TypeScript
import { ChatMessage } from '../store/useAppStore';
|
|
import { findLastAssistantId, shouldShowTypingIndicator } from '../utils/chatSelectors';
|
|
import { buildServerConfig, isConfigChanged } from '../utils/serverConfig';
|
|
import { isDarkTheme } from '../utils/theme';
|
|
|
|
const msg = (id: string, role: ChatMessage['role'], content = 'x'): ChatMessage => ({
|
|
id,
|
|
role,
|
|
content,
|
|
timestamp: 0,
|
|
});
|
|
|
|
describe('findLastAssistantId', () => {
|
|
it('returns the most recent assistant message', () => {
|
|
expect(findLastAssistantId([msg('1', 'assistant'), msg('2', 'user'), msg('3', 'assistant')])).toBe('3');
|
|
});
|
|
|
|
it('returns null when there is no assistant message', () => {
|
|
expect(findLastAssistantId([msg('1', 'user')])).toBeNull();
|
|
expect(findLastAssistantId([])).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('shouldShowTypingIndicator', () => {
|
|
it('is true only while streaming an assistant message with no text yet', () => {
|
|
expect(shouldShowTypingIndicator([msg('1', 'user'), msg('2', 'assistant', '')], true)).toBe(true);
|
|
});
|
|
|
|
it('is false when not streaming, when text arrived, when the last message is the user, or when empty', () => {
|
|
expect(shouldShowTypingIndicator([msg('2', 'assistant', '')], false)).toBe(false);
|
|
expect(shouldShowTypingIndicator([msg('2', 'assistant', 'hi')], true)).toBe(false);
|
|
expect(shouldShowTypingIndicator([msg('1', 'user', '')], true)).toBe(false);
|
|
expect(shouldShowTypingIndicator([], true)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('buildServerConfig', () => {
|
|
it('trims the host and API key and parses the port', () => {
|
|
expect(buildServerConfig({ host: ' 10.0.0.1 ', port: '8080', apiKey: ' k ' })).toEqual({
|
|
host: '10.0.0.1',
|
|
port: 8080,
|
|
apiKey: 'k',
|
|
});
|
|
});
|
|
|
|
it('uses the defaults for blank host, invalid port and blank key', () => {
|
|
expect(buildServerConfig({ host: '', port: 'abc', apiKey: ' ' })).toEqual({
|
|
host: 'localhost',
|
|
port: 1234,
|
|
apiKey: undefined,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('isConfigChanged', () => {
|
|
const saved = { host: 'lan', port: 1234, apiKey: 'k' };
|
|
|
|
it('is false when the form matches the saved config', () => {
|
|
expect(isConfigChanged({ host: 'lan', port: '1234', apiKey: 'k' }, saved)).toBe(false);
|
|
expect(isConfigChanged({ host: 'lan', port: '1234', apiKey: '' }, { host: 'lan', port: 1234 })).toBe(false);
|
|
});
|
|
|
|
it('is true when any single field differs', () => {
|
|
expect(isConfigChanged({ host: 'other', port: '1234', apiKey: 'k' }, saved)).toBe(true);
|
|
expect(isConfigChanged({ host: 'lan', port: '99', apiKey: 'k' }, saved)).toBe(true);
|
|
expect(isConfigChanged({ host: 'lan', port: '1234', apiKey: '' }, saved)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('isDarkTheme', () => {
|
|
it('honours an explicit preference and falls back to the system scheme', () => {
|
|
expect(isDarkTheme('dark', 'light')).toBe(true);
|
|
expect(isDarkTheme('light', 'dark')).toBe(false);
|
|
expect(isDarkTheme('system', 'dark')).toBe(true);
|
|
expect(isDarkTheme('system', 'light')).toBe(false);
|
|
});
|
|
});
|