Files
hyprcrd/public/plugins/tests/search.test.js
T
thandClaude Opus 4.6 883640e20c search: saved searches via bookmark button
Small bookmark icon in the search header bar opens a popup listing
localStorage-persisted search strings. Clicking an entry fills the
input and runs the search; the x button deletes it; "save current
search" at the bottom saves the active input (no dupes). List
persists across sessions, no server round-trip.

Tests: 6 cases covering button/popup toggle, save + recall, delete,
save-current-button, and duplicate rejection. All snapshot/restore
localStorage in try/finally so they don't leak into user data or
cross-test state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 09:09:18 +02:00

169 lines
5.6 KiB
JavaScript

import { describe, it, afterEach, expect, $, click, type, pressKey, sleep, closeAll } from './runner.js?v=4';
describe('Search', () => {
afterEach(() => closeAll());
it('opens with Ctrl+K', async () => {
pressKey('k', { ctrlKey: true });
await sleep(150);
expect($('#search')).toBeVisible();
});
it('opens with search button', async () => {
click('#search-btn');
await sleep(150);
expect($('#search')).toBeVisible();
});
it('input is focused on open', async () => {
click('#search-btn');
await sleep(150);
expect(document.activeElement).toBe($('#search-input'));
});
it('has input and results area', async () => {
click('#search-btn');
await sleep(100);
expect($('#search-input')).toExist();
expect($('#search-results')).toExist();
});
it('typing triggers results render', async () => {
click('#search-btn');
await sleep(100);
type('#search-input', 'a');
await sleep(250);
expect($('#search-results')).toExist();
});
it('closes with ESC', async () => {
click('#search-btn');
await sleep(100);
pressKey('Escape');
await sleep(150);
expect($('#search')).toBeHidden();
});
});
describe('Search: saved searches', () => {
const SAVED_KEY = 'hyprcrd-saved-searches';
afterEach(async () => {
// Close overlays and restore localStorage to avoid cross-test pollution.
document.querySelector('#search-saved-popup')?.classList.add('hidden');
await closeAll();
});
it('bookmark button and popup exist', () => {
expect($('#search-saved-btn')).toExist();
expect($('#search-saved-popup')).toExist();
expect($('#search-saved-popup').classList.contains('hidden')).toBe(true);
});
it('clicking bookmark opens the popup', async () => {
click('#search-btn');
await sleep(100);
click('#search-saved-btn');
await sleep(40);
expect($('#search-saved-popup').classList.contains('hidden')).toBe(false);
});
it('saves and recalls a search', async () => {
// Seed localStorage directly to avoid UI coupling for the save path.
const before = JSON.parse(localStorage.getItem(SAVED_KEY) || '[]');
const probe = '__test_saved_search_probe__';
try {
localStorage.setItem(SAVED_KEY, JSON.stringify([probe, ...before]));
click('#search-btn');
await sleep(100);
click('#search-saved-btn');
await sleep(60);
const popup = $('#search-saved-popup');
const rows = popup.querySelectorAll('.search-saved-row');
expect(rows.length).toBeGreaterThan(0);
// First row should be our probe.
expect(rows[0].textContent).toContain(probe);
// Click the row → fills input.
click(rows[0]);
await sleep(40);
expect($('#search-input').value).toBe(probe);
} finally {
// Restore original saved searches.
localStorage.setItem(SAVED_KEY, JSON.stringify(before));
}
});
it('deletes a saved search', async () => {
const before = JSON.parse(localStorage.getItem(SAVED_KEY) || '[]');
const probe = '__test_saved_del__';
try {
localStorage.setItem(SAVED_KEY, JSON.stringify([probe]));
click('#search-btn');
await sleep(100);
click('#search-saved-btn');
await sleep(60);
const delBtn = $('#search-saved-popup').querySelector('.search-saved-del');
expect(delBtn).toExist();
click(delBtn);
await sleep(40);
const after = JSON.parse(localStorage.getItem(SAVED_KEY) || '[]');
expect(after.includes(probe)).toBe(false);
} finally {
localStorage.setItem(SAVED_KEY, JSON.stringify(before));
}
});
it('save-current button adds input value', async () => {
const before = JSON.parse(localStorage.getItem(SAVED_KEY) || '[]');
const probe = '__test_saved_add_' + Date.now() + '__';
try {
click('#search-btn');
await sleep(100);
const inp = $('#search-input');
inp.value = probe;
inp.dispatchEvent(new Event('input', { bubbles: true }));
click('#search-saved-btn');
await sleep(40);
click('#search-saved-add');
await sleep(40);
const after = JSON.parse(localStorage.getItem(SAVED_KEY) || '[]');
expect(after.includes(probe)).toBe(true);
} finally {
localStorage.setItem(SAVED_KEY, JSON.stringify(before));
}
});
it('does not add duplicates', async () => {
const before = JSON.parse(localStorage.getItem(SAVED_KEY) || '[]');
const probe = '__test_saved_dupe__';
try {
localStorage.setItem(SAVED_KEY, JSON.stringify([probe]));
click('#search-btn');
await sleep(100);
const inp = $('#search-input');
inp.value = probe;
inp.dispatchEvent(new Event('input', { bubbles: true }));
click('#search-saved-btn');
await sleep(40);
click('#search-saved-add');
await sleep(40);
const after = JSON.parse(localStorage.getItem(SAVED_KEY) || '[]');
const count = after.filter(q => q === probe).length;
expect(count).toBe(1);
} finally {
localStorage.setItem(SAVED_KEY, JSON.stringify(before));
}
});
});