import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; // Mock next-intl vi.mock('next-intl', () => ({ useTranslations: () => (key: string) => { const map: Record = { 'search.placeholder': 'Suchen...', }; return map[key] ?? key; }, })); // Must import after mocks import { SearchWidget } from './search-widget'; const DEFAULT_PROVIDERS = [ { id: 'google', name: 'Google', urlTemplate: 'https://www.google.com/search?q={query}', isDefault: true }, { id: 'bing', name: 'Bing', urlTemplate: 'https://www.bing.com/search?q={query}', isDefault: true }, { id: 'ddg', name: 'DuckDuckGo', urlTemplate: 'https://duckduckgo.com/?q={query}', isDefault: true }, ]; describe('SearchWidget', () => { let windowOpenSpy: ReturnType; beforeEach(() => { windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null); // Mock fetch to return default providers vi.spyOn(globalThis, 'fetch').mockResolvedValue({ ok: true, json: async () => DEFAULT_PROVIDERS, } as Response); }); afterEach(() => { vi.restoreAllMocks(); }); it('renders provider dropdown, input, and search button', async () => { render( , ); await waitFor(() => { expect(screen.getByRole('combobox')).toBeInTheDocument(); }); expect(screen.getByPlaceholderText('Suchen...')).toBeInTheDocument(); expect(screen.getByRole('button')).toBeInTheDocument(); }); it('selecting Google and submitting "hello" opens correct URL in new tab', async () => { render( , ); await waitFor(() => { expect(screen.getByRole('combobox')).toBeInTheDocument(); }); // Select Google (should be default) const select = screen.getByRole('combobox'); fireEvent.change(select, { target: { value: 'google' } }); // Type query const input = screen.getByPlaceholderText('Suchen...'); fireEvent.change(input, { target: { value: 'hello' } }); // Click search button fireEvent.click(screen.getByRole('button')); expect(windowOpenSpy).toHaveBeenCalledWith( 'https://www.google.com/search?q=hello', '_blank', 'noopener,noreferrer', ); }); it('Enter key in input triggers search', async () => { render( , ); await waitFor(() => { expect(screen.getByRole('combobox')).toBeInTheDocument(); }); const input = screen.getByPlaceholderText('Suchen...'); fireEvent.change(input, { target: { value: 'hello' } }); fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' }); expect(windowOpenSpy).toHaveBeenCalledWith( 'https://www.google.com/search?q=hello', '_blank', 'noopener,noreferrer', ); }); it('encodes special characters in query', async () => { render( , ); await waitFor(() => { expect(screen.getByRole('combobox')).toBeInTheDocument(); }); const input = screen.getByPlaceholderText('Suchen...'); fireEvent.change(input, { target: { value: 'hello world & foo' } }); fireEvent.click(screen.getByRole('button')); expect(windowOpenSpy).toHaveBeenCalledWith( 'https://www.google.com/search?q=hello%20world%20%26%20foo', '_blank', 'noopener,noreferrer', ); }); it('does not open window when query is empty', async () => { render( , ); await waitFor(() => { expect(screen.getByRole('combobox')).toBeInTheDocument(); }); fireEvent.click(screen.getByRole('button')); expect(windowOpenSpy).not.toHaveBeenCalled(); }); });