Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled
- Updated personalization.db.test.ts to use mockClient for query calls in addWatchedItem tests. - Simplified error handling in shopping.db.test.ts, ensuring clearer error messages. - Added comprehensive tests for VoiceAssistant component, including rendering and interaction tests. - Introduced useModal hook with tests to manage modal state effectively. - Created deals.db.test.ts to test deals repository functionality with mocked database interactions. - Implemented error handling tests for custom error classes in errors.db.test.ts. - Developed googleGeocodingService.server.test.ts to validate geocoding service behavior with mocked fetch.
106 lines
3.8 KiB
TypeScript
106 lines
3.8 KiB
TypeScript
// src/features/voice-assistant/VoiceAssistant.test.tsx
|
|
import React from 'react';
|
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { VoiceAssistant } from './VoiceAssistant';
|
|
import * as aiApiClient from '../../services/aiApiClient';
|
|
|
|
// Mock dependencies to isolate the component
|
|
vi.mock('../../services/aiApiClient', () => ({
|
|
startVoiceSession: vi.fn(),
|
|
}));
|
|
vi.mock('../../services/logger.client', () => ({
|
|
logger: {
|
|
info: vi.fn(),
|
|
debug: vi.fn(),
|
|
error: vi.fn(),
|
|
},
|
|
}));
|
|
vi.mock('../../components/icons/MicrophoneIcon', () => ({
|
|
MicrophoneIcon: () => <div data-testid="mic-icon" />,
|
|
}));
|
|
vi.mock('../../components/icons/XMarkIcon', () => ({
|
|
XMarkIcon: () => <div data-testid="x-icon" />,
|
|
}));
|
|
|
|
// Mock browser APIs that are not available in JSDOM
|
|
Object.defineProperty(window, 'AudioContext', {
|
|
writable: true,
|
|
value: vi.fn().mockImplementation(() => ({
|
|
createMediaStreamSource: vi.fn(() => ({
|
|
connect: vi.fn(),
|
|
})),
|
|
createScriptProcessor: vi.fn(() => ({
|
|
connect: vi.fn(),
|
|
disconnect: vi.fn(),
|
|
})),
|
|
close: vi.fn(),
|
|
})),
|
|
});
|
|
|
|
Object.defineProperty(navigator, 'mediaDevices', {
|
|
writable: true,
|
|
value: {
|
|
getUserMedia: vi.fn(),
|
|
},
|
|
});
|
|
|
|
describe('VoiceAssistant Component', () => {
|
|
const mockOnClose = vi.fn();
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('should not render when isOpen is false', () => {
|
|
const { container } = render(<VoiceAssistant isOpen={false} onClose={mockOnClose} />);
|
|
expect(container.firstChild).toBeNull();
|
|
});
|
|
|
|
it('should render correctly when isOpen is true', () => {
|
|
render(<VoiceAssistant isOpen={true} onClose={mockOnClose} />);
|
|
|
|
expect(screen.getByRole('heading', { name: /voice assistant/i })).toBeInTheDocument();
|
|
expect(screen.getByText('Click the mic to start')).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: /close/i })).toBeInTheDocument();
|
|
expect(screen.getByTestId('mic-icon')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should call onClose when the close button is clicked', () => {
|
|
render(<VoiceAssistant isOpen={true} onClose={mockOnClose} />);
|
|
fireEvent.click(screen.getByRole('button', { name: /close/i }));
|
|
expect(mockOnClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should call onClose when the overlay is clicked', () => {
|
|
render(<VoiceAssistant isOpen={true} onClose={mockOnClose} />);
|
|
// The overlay is the root div of the modal
|
|
fireEvent.click(screen.getByRole('dialog').parentElement!);
|
|
expect(mockOnClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should not call onClose when the modal content is clicked', () => {
|
|
render(<VoiceAssistant isOpen={true} onClose={mockOnClose} />);
|
|
fireEvent.click(screen.getByRole('heading', { name: /voice assistant/i }));
|
|
expect(mockOnClose).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call startVoiceSession when the microphone button is clicked in idle state', () => {
|
|
render(<VoiceAssistant isOpen={true} onClose={mockOnClose} />);
|
|
const micButton = screen.getByRole('button', { name: '' }); // The main button has no text
|
|
fireEvent.click(micButton);
|
|
expect(aiApiClient.startVoiceSession).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should display history and current transcripts', () => {
|
|
render(<VoiceAssistant isOpen={true} onClose={mockOnClose} />);
|
|
|
|
// This test is a bit more involved as it requires manipulating internal state.
|
|
// For a simple test, we can check that the container for history exists.
|
|
// A more advanced test would involve mocking the `startVoiceSession` callbacks.
|
|
const historyContainer = screen.getByRole('heading', { name: /voice assistant/i }).parentElement?.nextElementSibling;
|
|
expect(historyContainer).toBeInTheDocument();
|
|
expect(historyContainer).toBeEmptyDOMElement(); // Initially empty
|
|
});
|
|
});
|