Files
hyprcrd/public/plugins/tests/terminal.test.js
T
2026-04-14 19:32:17 +02:00

197 lines
6.2 KiB
JavaScript

import { describe, it, afterEach, expect, $, click, pressKey, sleep, closeAll, csrf } from './runner.js?v=4';
import { state } from '../../js/modules/state.js';
function termToggle() {
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'T', shiftKey: true, bubbles: true }));
}
function termExec(cmd) {
const input = document.getElementById('hterm-input');
if (!input) return;
input.value = cmd;
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
}
function termOutput() {
return document.getElementById('hterm-output')?.textContent || '';
}
async function makeCard(title, body = '') {
return fetch('api/cards', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrf() },
body: JSON.stringify({ title, body, color: '#38bdf8' }),
}).then(r => r.json());
}
describe('Terminal: Toggle', () => {
afterEach(async () => {
document.getElementById('hterm')?.classList.add('hidden');
await closeAll();
});
it('panel exists but is hidden', () => {
const panel = document.getElementById('hterm');
expect(panel).toExist();
expect(panel.classList.contains('hidden')).toBe(true);
});
it('Shift+T opens the terminal', async () => {
termToggle();
await sleep(50);
expect(document.getElementById('hterm').classList.contains('hidden')).toBe(false);
});
it('Shift+T again closes it', async () => {
termToggle();
await sleep(50);
termToggle();
await sleep(50);
expect(document.getElementById('hterm').classList.contains('hidden')).toBe(true);
});
it('ESC closes the terminal', async () => {
termToggle();
await sleep(50);
const input = document.getElementById('hterm-input');
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
await sleep(50);
expect(document.getElementById('hterm').classList.contains('hidden')).toBe(true);
});
});
describe('Terminal: Commands', () => {
afterEach(async () => {
document.getElementById('hterm')?.classList.add('hidden');
document.getElementById('hterm-output').innerHTML = '';
await closeAll();
});
it('help lists commands', async () => {
termToggle();
await sleep(50);
termExec('help');
await sleep(50);
const out = termOutput();
expect(out).toContain('help');
expect(out).toContain('new');
expect(out).toContain('search');
});
it('count shows numbers', async () => {
termToggle();
await sleep(50);
termExec('count');
await sleep(50);
expect(termOutput()).toContain('cards');
expect(termOutput()).toContain('buckets');
});
it('version shows version string', async () => {
termToggle();
await sleep(50);
termExec('version');
await sleep(50);
expect(termOutput()).toContain('v');
});
it('unknown command shows error', async () => {
termToggle();
await sleep(50);
termExec('xyznonexistent');
await sleep(50);
expect(termOutput()).toContain('unknown command');
});
it('tags lists existing tags', async () => {
await makeCard('__term_tag_test__', '#alpha #beta');
await window._reloadAll?.();
await sleep(200);
termToggle();
await sleep(50);
termExec('tags');
await sleep(50);
expect(termOutput()).toContain('#alpha');
expect(termOutput()).toContain('#beta');
});
it('find matches cards by title', async () => {
await makeCard('__term_find_me__', 'findable body');
await window._reloadAll?.();
await sleep(200);
termToggle();
await sleep(50);
termExec('find __term_find_me__');
await sleep(50);
expect(termOutput()).toContain('__term_find_me__');
});
it('go switches to bucket', async () => {
termToggle();
await sleep(50);
termExec('go all');
await sleep(100);
expect(String(state.activeBucket)).toBe('all');
});
it('new creates a card', async () => {
termToggle();
await sleep(50);
termExec('new __term_new_card__');
// termExec fires off an async API call + full reload; poll rather
// than sleeping a fixed amount so slow machines don't flake.
const start = Date.now();
while (!termOutput().includes('created') && Date.now() - start < 3000) {
await sleep(50);
}
expect(termOutput()).toContain('created');
const cards = await fetch('api/cards').then(r => r.json());
expect(cards.some(c => c.title === '__term_new_card__')).toBe(true);
});
it('clear empties output', async () => {
termToggle();
await sleep(50);
termExec('help');
await sleep(50);
expect(termOutput().length).toBeGreaterThan(10);
termExec('clear');
await sleep(50);
expect(document.getElementById('hterm-output').children.length).toBe(0);
});
});
describe('Terminal: Tab Completion', () => {
afterEach(async () => {
document.getElementById('hterm')?.classList.add('hidden');
document.getElementById('hterm-output').innerHTML = '';
await closeAll();
});
it('Tab completes unique command', async () => {
termToggle();
await sleep(50);
const input = document.getElementById('hterm-input');
input.value = 'vers';
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true }));
await sleep(50);
expect(input.value).toBe('version ');
});
it('Tab shows multiple matches', async () => {
termToggle();
await sleep(50);
const input = document.getElementById('hterm-input');
input.value = 'c';
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true }));
await sleep(50);
const out = termOutput();
expect(out).toContain('clear');
expect(out).toContain('count');
expect(out).toContain('calendar');
expect(out).toContain('color');
});
});