mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-07-17 17:21:48 +00:00
Add '/' shortcut to focus search box
This commit is contained in:
@@ -1,22 +1,221 @@
|
||||
import {expect, test} from '@playwright/test';
|
||||
import {setupGedcomRoute} from './helpers';
|
||||
|
||||
test.describe('Search functionality', () => {
|
||||
test.describe('Search functionality and global shortcut', () => {
|
||||
test.beforeEach(async ({context}) => {
|
||||
await setupGedcomRoute(context);
|
||||
});
|
||||
|
||||
test('Search works', async ({page}) => {
|
||||
test('Search works and shortcut "/" focuses and selects all text', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/#/view?url=https://example.org/family.ged');
|
||||
await expect(page.locator('#content')).not.toContainText('Chike');
|
||||
|
||||
const searchInput = page.getByPlaceholder('Search for people');
|
||||
const searchInput = page.getByPlaceholder('Search for people', {
|
||||
exact: false,
|
||||
});
|
||||
await expect(searchInput).toBeVisible();
|
||||
|
||||
// Fill some text, blur, and press '/'
|
||||
await searchInput.fill('Test Query');
|
||||
await searchInput.blur();
|
||||
await expect(searchInput).not.toBeFocused();
|
||||
|
||||
await page.keyboard.press('/');
|
||||
await expect(searchInput).toBeFocused();
|
||||
|
||||
// Assert that all text is selected
|
||||
const isTextSelected = await searchInput.evaluate(
|
||||
(el: HTMLInputElement) => {
|
||||
return el.selectionStart === 0 && el.selectionEnd === el.value.length;
|
||||
},
|
||||
);
|
||||
expect(isTextSelected).toBe(true);
|
||||
|
||||
// Perform search
|
||||
await searchInput.fill('chik');
|
||||
|
||||
// Wait for the debounced suggestion panel to render.
|
||||
await expect(page.locator('.results')).toContainText('Chike');
|
||||
|
||||
await searchInput.press('Enter');
|
||||
await expect(page.locator('#content')).toContainText('Chike');
|
||||
});
|
||||
|
||||
test('Viewport switching: Search query is preserved when resizing between desktop and mobile', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.setViewportSize({width: 1200, height: 800});
|
||||
await page.goto('/#/view?url=https://example.org/family.ged');
|
||||
|
||||
const desktopInput = page.getByPlaceholder("Search for people (press '/')");
|
||||
await desktopInput.fill('chik');
|
||||
await expect(page.locator('.results')).toContainText('Chike');
|
||||
|
||||
// Resize to mobile viewport
|
||||
await page.setViewportSize({width: 500, height: 800});
|
||||
const mobileInput = page.getByPlaceholder('Search for people', {
|
||||
exact: true,
|
||||
});
|
||||
await expect(mobileInput).toBeVisible();
|
||||
await expect(mobileInput).toHaveValue('chik');
|
||||
await expect(page.locator('.results')).toContainText('Chike');
|
||||
});
|
||||
|
||||
test('Collision safety: Typing "/" inside an active modal input types "/" and does not trigger shortcut', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/#/view?url=https://example.org/family.ged');
|
||||
|
||||
await page.getByText('Open', {exact: true}).click();
|
||||
await page.getByText('Load from URL').click();
|
||||
|
||||
const modalInput = page.getByPlaceholder('https://');
|
||||
await expect(modalInput).toBeVisible();
|
||||
await expect(modalInput).toBeFocused();
|
||||
|
||||
await page.keyboard.type('http://test/data');
|
||||
await expect(modalInput).toHaveValue('http://test/data');
|
||||
|
||||
const searchInput = page.getByPlaceholder('Search for people', {
|
||||
exact: false,
|
||||
});
|
||||
await expect(searchInput).not.toBeFocused();
|
||||
});
|
||||
|
||||
test('Modal safety: Pressing "/" while a modal is open does not steal focus even if modal input is blurred', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/#/view?url=https://example.org/family.ged');
|
||||
|
||||
await page.getByText('Open', {exact: true}).click();
|
||||
await page.getByText('Load from URL').click();
|
||||
|
||||
const modalInput = page.getByPlaceholder('https://');
|
||||
await expect(modalInput).toBeVisible();
|
||||
await modalInput.blur();
|
||||
|
||||
await page.keyboard.press('/');
|
||||
|
||||
const searchInput = page.getByPlaceholder('Search for people', {
|
||||
exact: false,
|
||||
});
|
||||
await expect(searchInput).not.toBeFocused();
|
||||
});
|
||||
|
||||
test('Form control protection: Pressing "/" while focused on a button does not steal focus', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/#/view?url=https://example.org/family.ged');
|
||||
|
||||
await page.getByText('Open', {exact: true}).click();
|
||||
await page.getByText('Load from URL').click();
|
||||
|
||||
const cancelButton = page.getByRole('button', {name: 'Cancel'});
|
||||
await cancelButton.focus();
|
||||
await expect(cancelButton).toBeFocused();
|
||||
|
||||
await page.keyboard.press('/');
|
||||
|
||||
await expect(cancelButton).toBeFocused();
|
||||
const searchInput = page.getByPlaceholder('Search for people', {
|
||||
exact: false,
|
||||
});
|
||||
await expect(searchInput).not.toBeFocused();
|
||||
});
|
||||
|
||||
test('Modifier exclusion: Modifier combinations do not trigger the shortcut', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/#/view?url=https://example.org/family.ged');
|
||||
|
||||
const searchInput = page.getByPlaceholder('Search for people', {
|
||||
exact: false,
|
||||
});
|
||||
await expect(searchInput).not.toBeFocused();
|
||||
|
||||
await page.keyboard.press('Control+/');
|
||||
await expect(searchInput).not.toBeFocused();
|
||||
|
||||
await page.keyboard.press('Alt+/');
|
||||
await expect(searchInput).not.toBeFocused();
|
||||
|
||||
await page.keyboard.press('Meta+/');
|
||||
await expect(searchInput).not.toBeFocused();
|
||||
});
|
||||
|
||||
test('Landing page safety: Pressing "/" on landing page has no effect and doesn\'t throw errors', async ({
|
||||
page,
|
||||
}) => {
|
||||
const errors: string[] = [];
|
||||
page.on('pageerror', (err) => {
|
||||
errors.push(err.message);
|
||||
});
|
||||
page.on('console', (msg) => {
|
||||
if (msg.type() === 'error' && !msg.text().includes('Warning:')) {
|
||||
errors.push(msg.text());
|
||||
}
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
await page.keyboard.press('/');
|
||||
|
||||
expect(errors).toEqual([]);
|
||||
});
|
||||
|
||||
test('Question mark safety: Pressing "?" (Shift+/) does not trigger search shortcut', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/#/view?url=https://example.org/family.ged');
|
||||
const searchInput = page.getByPlaceholder('Search for people', {
|
||||
exact: false,
|
||||
});
|
||||
await expect(searchInput).not.toBeFocused();
|
||||
|
||||
await page.keyboard.press('?');
|
||||
await expect(searchInput).not.toBeFocused();
|
||||
});
|
||||
|
||||
test('Dropdown menu interaction: Pressing "/" while dropdown is open focuses search bar', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/#/view?url=https://example.org/family.ged');
|
||||
|
||||
await page.getByText('View', {exact: true}).click();
|
||||
await expect(page.getByText('Hourglass chart')).toBeVisible();
|
||||
|
||||
await page.keyboard.press('/');
|
||||
|
||||
const searchInput = page.getByPlaceholder('Search for people', {
|
||||
exact: false,
|
||||
});
|
||||
await expect(searchInput).toBeFocused();
|
||||
});
|
||||
|
||||
test('Combobox wrapper interaction: Clicking inside search bar wrapper and pressing "/" focuses input', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/#/view?url=https://example.org/family.ged');
|
||||
|
||||
const searchInput = page.getByPlaceholder('Search for people', {
|
||||
exact: false,
|
||||
});
|
||||
await page.locator('.ui.search').first().click();
|
||||
await searchInput.blur();
|
||||
|
||||
await page.keyboard.press('/');
|
||||
await expect(searchInput).toBeFocused();
|
||||
});
|
||||
|
||||
test('AltGr compatibility: Control+Alt+/ triggers the shortcut', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/#/view?url=https://example.org/family.ged');
|
||||
const searchInput = page.getByPlaceholder('Search for people', {
|
||||
exact: false,
|
||||
});
|
||||
await expect(searchInput).toBeVisible();
|
||||
|
||||
await page.keyboard.press('Control+Alt+/');
|
||||
await expect(searchInput).toBeFocused();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user