UNPKG

@lobehub/chat

Version:

Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.

199 lines (161 loc) • 6.37 kB
import { describe, expect, it } from 'vitest'; import { ImageGenerationTopic } from '@/types/generation'; import { GenerationTopicDispatch, generationTopicReducer } from './reducer'; describe('generationTopicReducer', () => { let state: ImageGenerationTopic[]; beforeEach(() => { state = []; }); describe('addTopic', () => { it('should add a new topic to the state', () => { const newTopic: Partial<ImageGenerationTopic> & { id: string } = { id: 'gt_new_topic', title: 'New Topic', }; const payload: GenerationTopicDispatch = { type: 'addTopic', value: newTopic }; const newState = generationTopicReducer(state, payload); expect(newState).toHaveLength(1); expect(newState[0]).toMatchObject(newTopic); expect(newState[0].createdAt).toBeInstanceOf(Date); expect(newState[0].updatedAt).toBeInstanceOf(Date); }); it('should prepend the new topic to the beginning of the array', () => { const initialTopic: ImageGenerationTopic = { id: 'gt_initial_topic', title: 'Initial Topic', createdAt: new Date('2023-01-01'), updatedAt: new Date('2023-01-01'), }; state = [initialTopic]; const newTopic: Partial<ImageGenerationTopic> & { id: string } = { id: 'gt_new_topic', title: 'New Topic', }; const payload: GenerationTopicDispatch = { type: 'addTopic', value: newTopic }; const newState = generationTopicReducer(state, payload); expect(newState).toHaveLength(2); expect(newState[0].id).toBe('gt_new_topic'); expect(newState[1].id).toBe('gt_initial_topic'); }); }); describe('updateTopic', () => { beforeEach(() => { state = [ { id: 'gt_topic_to_update', title: 'Original Title', coverUrl: 'original_url', createdAt: new Date('2023-01-01'), updatedAt: new Date('2023-01-01'), }, ]; }); it('should update the title of a specific topic', () => { const payload: GenerationTopicDispatch = { type: 'updateTopic', id: 'gt_topic_to_update', value: { title: 'Updated Title' }, }; const newState = generationTopicReducer(state, payload); expect(newState[0].title).toBe('Updated Title'); expect(newState[0].coverUrl).toBe('original_url'); // Should not change expect(newState[0].updatedAt.valueOf()).toBeGreaterThan(state[0].updatedAt.valueOf()); }); it('should update the coverUrl of a specific topic', () => { const payload: GenerationTopicDispatch = { type: 'updateTopic', id: 'gt_topic_to_update', value: { coverUrl: 'updated_url' }, }; const newState = generationTopicReducer(state, payload); expect(newState[0].coverUrl).toBe('updated_url'); expect(newState[0].title).toBe('Original Title'); // Should not change }); it('should not change state if topic id is not found', () => { const payload: GenerationTopicDispatch = { type: 'updateTopic', id: 'gt_non_existent_topic', value: { title: 'Updated Title' }, }; const newState = generationTopicReducer(state, payload); expect(newState).toEqual(state); }); }); describe('deleteTopic', () => { beforeEach(() => { state = [ { id: 'gt_topic_1', title: 'Topic 1', createdAt: new Date(), updatedAt: new Date(), }, { id: 'gt_topic_2', title: 'Topic 2', createdAt: new Date(), updatedAt: new Date(), }, ]; }); it('should delete the specified topic from the state', () => { const payload: GenerationTopicDispatch = { type: 'deleteTopic', id: 'gt_topic_1' }; const newState = generationTopicReducer(state, payload); expect(newState).toHaveLength(1); expect(newState.find((t) => t.id === 'gt_topic_1')).toBeUndefined(); expect(newState[0].id).toBe('gt_topic_2'); }); it('should not modify state if topic id is not found', () => { const payload: GenerationTopicDispatch = { type: 'deleteTopic', id: 'gt_non_existent' }; const newState = generationTopicReducer(state, payload); expect(newState).toHaveLength(2); expect(newState).toEqual(state); }); }); describe('default case', () => { it('should return the original state for an unknown action type', () => { const payload = { type: 'unknown' } as any; const newState = generationTopicReducer(state, payload); expect(newState).toBe(state); }); }); describe('immutability', () => { it('should return a new state object for addTopic', () => { const payload: GenerationTopicDispatch = { type: 'addTopic', value: { id: 'test', title: 'Test' }, }; const newState = generationTopicReducer(state, payload); expect(newState).not.toBe(state); }); it('should return a new state object for updateTopic', () => { state = [{ id: 'test', title: 'Test', createdAt: new Date(), updatedAt: new Date() }]; const payload: GenerationTopicDispatch = { type: 'updateTopic', id: 'test', value: { title: 'Updated' }, }; const newState = generationTopicReducer(state, payload); expect(newState).not.toBe(state); }); it('should return a new state object for deleteTopic', () => { state = [{ id: 'test', title: 'Test', createdAt: new Date(), updatedAt: new Date() }]; const payload: GenerationTopicDispatch = { type: 'deleteTopic', id: 'test' }; const newState = generationTopicReducer(state, payload); expect(newState).not.toBe(state); }); it('should not modify the original state object', () => { const date = new Date(); const originalState = [{ id: 'a', title: 'A', createdAt: date, updatedAt: date }]; const stateCopy = [{ id: 'a', title: 'A', createdAt: date, updatedAt: date }]; const stateRef = originalState; const payload: GenerationTopicDispatch = { type: 'addTopic', value: { id: 'b', title: 'B' }, }; generationTopicReducer(originalState, payload); expect(originalState).toEqual(stateCopy); expect(originalState).toBe(stateRef); }); }); });