test: add unit tests for image, utils, and credentials modules (22 cases)

This commit is contained in:
Nicolas Varrot
2026-02-13 08:11:17 +00:00
parent 3fad7b1e0a
commit e698e64bc8
3 changed files with 145 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { getStoredCredentials, storeCredentials, clearCredentials } from '../credentials';
// Mock localStorage
const store: Record<string, string> = {};
const localStorageMock = {
getItem: vi.fn((key: string) => store[key] ?? null),
setItem: vi.fn((key: string, value: string) => { store[key] = value; }),
removeItem: vi.fn((key: string) => { delete store[key]; }),
};
Object.defineProperty(globalThis, 'localStorage', { value: localStorageMock });
beforeEach(() => {
for (const key of Object.keys(store)) delete store[key];
vi.clearAllMocks();
});
describe('getStoredCredentials', () => {
it('returns null when nothing stored', () => {
expect(getStoredCredentials()).toBeNull();
});
it('returns credentials when valid JSON stored', () => {
store['pinchchat_credentials'] = JSON.stringify({ url: 'wss://gw.test', token: 'abc' });
expect(getStoredCredentials()).toEqual({ url: 'wss://gw.test', token: 'abc' });
});
it('returns null for malformed JSON', () => {
store['pinchchat_credentials'] = 'not-json';
expect(getStoredCredentials()).toBeNull();
});
it('returns null if url is missing', () => {
store['pinchchat_credentials'] = JSON.stringify({ token: 'abc' });
expect(getStoredCredentials()).toBeNull();
});
it('returns null if token is missing', () => {
store['pinchchat_credentials'] = JSON.stringify({ url: 'wss://gw' });
expect(getStoredCredentials()).toBeNull();
});
});
describe('storeCredentials', () => {
it('stores credentials as JSON', () => {
storeCredentials('wss://gw', 'tok');
expect(localStorageMock.setItem).toHaveBeenCalledWith(
'pinchchat_credentials',
JSON.stringify({ url: 'wss://gw', token: 'tok' }),
);
});
});
describe('clearCredentials', () => {
it('removes the key from localStorage', () => {
store['pinchchat_credentials'] = 'something';
clearCredentials();
expect(localStorageMock.removeItem).toHaveBeenCalledWith('pinchchat_credentials');
});
});

View File

@@ -0,0 +1,32 @@
import { describe, it, expect } from 'vitest';
import { buildImageSrc } from '../image';
describe('buildImageSrc', () => {
it('returns URL when url is provided', () => {
expect(buildImageSrc('image/png', undefined, 'https://example.com/img.png'))
.toBe('https://example.com/img.png');
});
it('prefers url over base64 data', () => {
expect(buildImageSrc('image/png', 'abc123', 'https://example.com/img.png'))
.toBe('https://example.com/img.png');
});
it('builds data URL from base64 data', () => {
expect(buildImageSrc('image/png', 'abc123'))
.toBe('data:image/png;base64,abc123');
});
it('builds data URL for jpeg', () => {
expect(buildImageSrc('image/jpeg', 'xyz'))
.toBe('data:image/jpeg;base64,xyz');
});
it('returns empty string when neither url nor data provided', () => {
expect(buildImageSrc('image/png')).toBe('');
});
it('returns empty string with undefined data and no url', () => {
expect(buildImageSrc('image/webp', undefined, undefined)).toBe('');
});
});

View File

@@ -0,0 +1,52 @@
import { describe, it, expect } from 'vitest';
import { cn, genId, genIdempotencyKey } from '../utils';
describe('cn', () => {
it('merges class names', () => {
expect(cn('foo', 'bar')).toBe('foo bar');
});
it('handles conditional classes', () => {
const showHidden = false;
expect(cn('base', showHidden && 'hidden', 'extra')).toBe('base extra');
});
it('resolves tailwind conflicts (twMerge)', () => {
// twMerge deduplicates conflicting tailwind utilities
expect(cn('p-4', 'p-2')).toBe('p-2');
});
it('handles empty input', () => {
expect(cn()).toBe('');
});
it('handles undefined and null values', () => {
expect(cn('a', undefined, null, 'b')).toBe('a b');
});
});
describe('genId', () => {
it('generates unique ids with default prefix', () => {
const a = genId();
const b = genId();
expect(a).toMatch(/^req-\d+-\d+$/);
expect(a).not.toBe(b);
});
it('uses custom prefix', () => {
expect(genId('msg')).toMatch(/^msg-\d+-\d+$/);
});
});
describe('genIdempotencyKey', () => {
it('returns a non-empty string', () => {
const key = genIdempotencyKey();
expect(key.length).toBeGreaterThan(0);
});
it('generates unique keys', () => {
const a = genIdempotencyKey();
const b = genIdempotencyKey();
expect(a).not.toBe(b);
});
});