Add smartMode $bindable plus onSmartSearch/onModeToggle callbacks. The toggle pill sits in the input's right slot (decorative icon moved to the left); smart mode disables the live oninput keyword search, adds maxlength=500, and submits the NL query on Enter. 4 integration specs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
82 lines
3.0 KiB
TypeScript
82 lines
3.0 KiB
TypeScript
import { describe, expect, it, vi, afterEach } from 'vitest';
|
|
import { cleanup, render } from 'vitest-browser-svelte';
|
|
import { page } from 'vitest/browser';
|
|
import SmartModeToggle from './SmartModeToggle.svelte';
|
|
import SearchFilterBar from '../SearchFilterBar.svelte';
|
|
|
|
afterEach(() => cleanup());
|
|
|
|
const SEARCH_PLACEHOLDER = 'Titel, Personen, Tags durchsuchen…';
|
|
|
|
describe('SmartModeToggle', () => {
|
|
it('renders aria-pressed="false" by default and toggles on click', async () => {
|
|
render(SmartModeToggle, { smartMode: false });
|
|
const btn = page.getByRole('button');
|
|
await expect.element(btn).toHaveAttribute('aria-pressed', 'false');
|
|
await btn.click();
|
|
await expect.element(btn).toHaveAttribute('aria-pressed', 'true');
|
|
await btn.click();
|
|
await expect.element(btn).toHaveAttribute('aria-pressed', 'false');
|
|
});
|
|
|
|
it('shows the smart label when smartMode is true', async () => {
|
|
render(SmartModeToggle, { smartMode: true });
|
|
const btn = page.getByRole('button');
|
|
await expect.element(btn).toHaveTextContent('KI');
|
|
});
|
|
|
|
it('shows the keyword label when smartMode is false', async () => {
|
|
render(SmartModeToggle, { smartMode: false });
|
|
const btn = page.getByRole('button');
|
|
await expect.element(btn).toHaveTextContent('Text');
|
|
});
|
|
|
|
it('applies the active pill style only in smart mode', async () => {
|
|
render(SmartModeToggle, { smartMode: true });
|
|
const btn = page.getByRole('button');
|
|
await expect.element(btn).toHaveClass(/bg-primary/);
|
|
});
|
|
});
|
|
|
|
describe('SmartModeToggle inside SearchFilterBar', () => {
|
|
it('adds maxlength="500" to the search input only in smart mode', async () => {
|
|
render(SearchFilterBar, { onSearch: vi.fn(), sort: 'DATE', dir: 'desc', smartMode: true });
|
|
await expect
|
|
.element(page.getByPlaceholder(SEARCH_PLACEHOLDER))
|
|
.toHaveAttribute('maxlength', '500');
|
|
});
|
|
|
|
it('omits maxlength from the search input in keyword mode', async () => {
|
|
render(SearchFilterBar, { onSearch: vi.fn(), sort: 'DATE', dir: 'desc', smartMode: false });
|
|
await expect
|
|
.element(page.getByPlaceholder(SEARCH_PLACEHOLDER))
|
|
.not.toHaveAttribute('maxlength');
|
|
});
|
|
|
|
it('does not fire the keyword search on input while in smart mode', async () => {
|
|
const onSearch = vi.fn();
|
|
render(SearchFilterBar, { onSearch, sort: 'DATE', dir: 'desc', smartMode: true });
|
|
await page.getByPlaceholder(SEARCH_PLACEHOLDER).fill('Walter im Krieg');
|
|
expect(onSearch).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('fires the smart search callback on Enter in smart mode', async () => {
|
|
const onSmartSearch = vi.fn();
|
|
render(SearchFilterBar, {
|
|
onSearch: vi.fn(),
|
|
onSmartSearch,
|
|
sort: 'DATE',
|
|
dir: 'desc',
|
|
smartMode: true
|
|
});
|
|
const input = page.getByPlaceholder(SEARCH_PLACEHOLDER);
|
|
await input.fill('Walter im Krieg');
|
|
await input.click();
|
|
// Enter submits the NL query in smart mode
|
|
(document.activeElement as HTMLElement).dispatchEvent(
|
|
new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })
|
|
);
|
|
await vi.waitFor(() => expect(onSmartSearch).toHaveBeenCalled());
|
|
});
|
|
});
|