97c13809f5
- SearchWidget: provider selection, window.open with encoded query, Enter key trigger - NoteWidget: debounced autosave, rapid typing collapse, AbortController usage Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
132 lines
3.9 KiB
TypeScript
132 lines
3.9 KiB
TypeScript
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<string, string> = {
|
|
'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<typeof vi.spyOn>;
|
|
|
|
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(
|
|
<SearchWidget instanceId="test-1" config={{}} isEditMode={false} />,
|
|
);
|
|
|
|
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(
|
|
<SearchWidget instanceId="test-1" config={{}} isEditMode={false} />,
|
|
);
|
|
|
|
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(
|
|
<SearchWidget instanceId="test-1" config={{}} isEditMode={false} />,
|
|
);
|
|
|
|
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(
|
|
<SearchWidget instanceId="test-1" config={{}} isEditMode={false} />,
|
|
);
|
|
|
|
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(
|
|
<SearchWidget instanceId="test-1" config={{}} isEditMode={false} />,
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByRole('combobox')).toBeInTheDocument();
|
|
});
|
|
|
|
fireEvent.click(screen.getByRole('button'));
|
|
|
|
expect(windowOpenSpy).not.toHaveBeenCalled();
|
|
});
|
|
});
|