64 lines
3.8 KiB
TypeScript
64 lines
3.8 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { applySuggestion, buildSearchUrl, describeQuery, hasOperators, normalizeQuery, suggest, tokenAt } from '../src/core/searchOperators.ts';
|
|
import { toUrl } from '../src/shell/searchInput.ts';
|
|
import { buildItems } from '../src/shell/paletteModel.ts';
|
|
|
|
test('operator detection', () => {
|
|
for (const q of ['from:@jack hello', 'to:x', '@nasa', 'since:2024-01-01', 'cats filter:media', 'dogs -filter:replies', 'min_faves:100', 'lang:tr', 'list:123', 'url:github.com', '"exact phrase"', 'a OR b'])
|
|
assert.ok(hasOperators(q), q);
|
|
for (const q of ['hello world', 'from:', 'email me@', 'or maybe'])
|
|
assert.ok(!hasOperators(q), q);
|
|
});
|
|
|
|
test('from:@x is normalized and opens Latest with src=typed_query', () => {
|
|
assert.equal(normalizeQuery(' from:@jack hi -to:@x '), 'from:jack hi -to:x');
|
|
assert.equal(buildSearchUrl('from:@jack hello'), 'https://x.com/search?q=from%3Ajack%20hello&src=typed_query&f=live');
|
|
assert.equal(buildSearchUrl('plain words'), 'https://x.com/search?q=plain%20words&src=typed_query');
|
|
});
|
|
|
|
test('address bar input: operators search X, URLs and domains navigate', () => {
|
|
assert.equal(toUrl('from:@x cats'), 'https://x.com/search?q=from%3Ax%20cats&src=typed_query&f=live');
|
|
assert.equal(toUrl('url:github.com'), 'https://x.com/search?q=url%3Agithub.com&src=typed_query&f=live');
|
|
assert.equal(toUrl('github.com'), 'https://github.com');
|
|
assert.equal(toUrl('https://x.com/home'), 'https://x.com/home');
|
|
assert.equal(toUrl('just words'), 'https://x.com/search?q=just%20words');
|
|
});
|
|
|
|
test('palette: an operator query searches Latest and offers completions for the token', () => {
|
|
const context = { tabs: [], profiles: [], activeProfile: 'default' };
|
|
const items = buildItems(context, 'from:@jack');
|
|
assert.deepEqual(items.at(-1)!.action, { type: 'open', url: 'https://x.com/search?q=from%3Ajack&src=typed_query&f=live' });
|
|
const partial = buildItems(context, 'cats fil');
|
|
const complete = partial.filter(item => item.action.type === 'complete');
|
|
assert.ok(complete.some(item => item.action.type === 'complete' && item.action.text === 'cats filter:media '));
|
|
});
|
|
|
|
test('tokenAt finds the caret token', () => {
|
|
assert.deepEqual(tokenAt('cats fro dogs', 8), { start: 5, end: 8, text: 'fro' });
|
|
assert.deepEqual(tokenAt('cats ', 5), { start: 5, end: 5, text: '' });
|
|
});
|
|
|
|
test('suggest: partial operators, dates, languages and numbers', () => {
|
|
assert.deepEqual(suggest('fil', 3).map(s => s.insert), ['filter:media', 'filter:images', 'filter:videos', 'filter:links', 'filter:replies']);
|
|
assert.deepEqual(suggest('-fil', 4).map(s => s.insert), ['-filter:replies']);
|
|
const now = new Date(2026, 8, 27);
|
|
assert.deepEqual(suggest('since:', 6, now).map(s => s.insert).slice(0, 2), ['since:2026-09-27', 'since:2026-09-20']);
|
|
assert.deepEqual(suggest('lang:t', 6).map(s => s.insert), ['lang:tr']);
|
|
assert.deepEqual(suggest('min_faves:1', 11).map(s => s.insert), ['min_faves:10', 'min_faves:100', 'min_faves:1000', 'min_faves:10000']);
|
|
assert.ok(suggest('', 0).length > 0);
|
|
assert.deepEqual(suggest('from:jack', 9), []);
|
|
});
|
|
|
|
test('applySuggestion replaces the token and places the caret', () => {
|
|
assert.deepEqual(applySuggestion('cats fil', 8, 'filter:media'), { text: 'cats filter:media ', caret: 18 });
|
|
assert.deepEqual(applySuggestion('cats fr', 7, 'from:'), { text: 'cats from:', caret: 10 });
|
|
assert.deepEqual(applySuggestion('cats ', 5, '""'), { text: 'cats ""', caret: 6 });
|
|
assert.deepEqual(applySuggestion('cats ', 5, 'OR'), { text: 'cats OR ', caret: 8 });
|
|
});
|
|
|
|
test('describeQuery marks operators', () => {
|
|
assert.deepEqual(describeQuery('from:@a cats -dogs "big cat"'), [
|
|
{ text: 'from:a', operator: true }, { text: 'cats', operator: false }, { text: '-dogs', operator: true }, { text: '"big cat"', operator: true },
|
|
]);
|
|
});
|