79 lines
4.8 KiB
TypeScript
79 lines
4.8 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { buildItems, type PaletteContext } from '../src/shell/paletteModel.ts';
|
|
import { X_COLUMN_KINDS, columnTitle, parseColumnValue, xColumnUrl } from '../src/shell/xColumns.ts';
|
|
import { columnUrl, normalizeDecks } from '../../../waybetter/packages/shell/src/deckModel.ts';
|
|
|
|
test('deck columns: every kind loads an x.com page', () => {
|
|
assert.equal(xColumnUrl({ kind: 'home' }), 'https://x.com/home');
|
|
assert.equal(xColumnUrl({ kind: 'following' }), 'https://x.com/home', 'Following is X’s home tab, selected by a navigation-only click');
|
|
assert.equal(xColumnUrl({ kind: 'notifications' }), 'https://x.com/notifications');
|
|
assert.equal(xColumnUrl({ kind: 'mentions' }), 'https://x.com/notifications/mentions');
|
|
assert.equal(xColumnUrl({ kind: 'bookmarks' }), 'https://x.com/i/bookmarks');
|
|
assert.equal(xColumnUrl({ kind: 'list', value: '1234' }), 'https://x.com/i/lists/1234');
|
|
assert.equal(xColumnUrl({ kind: 'user', value: 'playfishies' }), 'https://x.com/playfishies');
|
|
assert.equal(xColumnUrl({ kind: 'search', value: 'from:me filter:media' }), 'https://x.com/search?q=from%3Ame%20filter%3Amedia&f=live');
|
|
for (const bad of [{ kind: 'list', value: 'abc' }, { kind: 'user', value: 'not a handle' }, { kind: 'search' }, { kind: 'rocket' }]) {
|
|
assert.equal(xColumnUrl(bad), null, JSON.stringify(bad));
|
|
}
|
|
for (const kind of X_COLUMN_KINDS) {
|
|
const value = kind === 'list' ? '1' : kind === 'user' ? 'x' : kind === 'search' ? 'q' : undefined;
|
|
assert.ok(columnUrl(value ? { kind, value } : { kind }, xColumnUrl)?.startsWith('https://x.com/'), kind);
|
|
}
|
|
});
|
|
|
|
test('deck columns: typed values are parsed per kind', () => {
|
|
assert.equal(parseColumnValue('user', '@playfishies'), 'playfishies');
|
|
assert.equal(parseColumnValue('user', 'https://x.com/CRTkafa/status/1'), 'CRTkafa');
|
|
assert.equal(parseColumnValue('user', 'twitter.com/nope nope'), null);
|
|
assert.equal(parseColumnValue('list', 'https://x.com/i/lists/1590000000000000001'), '1590000000000000001');
|
|
assert.equal(parseColumnValue('list', '42'), '42');
|
|
assert.equal(parseColumnValue('list', 'https://x.com/i/lists/abc'), null);
|
|
assert.equal(parseColumnValue('search', ' wayBetter from:@playfishies '), 'wayBetter from:playfishies');
|
|
assert.equal(parseColumnValue('search', ' '), null);
|
|
assert.equal(parseColumnValue('home', 'ignored'), '');
|
|
});
|
|
|
|
test('deck columns: header titles', () => {
|
|
assert.deepEqual(columnTitle({ kind: 'notifications' }), { title: 'Notifications' });
|
|
assert.deepEqual(columnTitle({ kind: 'user', value: 'playfishies' }), { title: '@playfishies', detail: 'Profile' });
|
|
assert.deepEqual(columnTitle({ kind: 'search', value: 'gm' }), { title: 'gm', detail: 'Search · Latest' });
|
|
assert.deepEqual(columnTitle({ kind: 'home' }, 'Main feed'), { title: 'Main feed', detail: 'Home' });
|
|
});
|
|
|
|
test('deck storage: X kinds only, removed accounts fall back to the default', () => {
|
|
const [deck] = normalizeDecks([{ id: 'd1', name: 'Deck', columns: [
|
|
{ id: 'a', tabId: 'ka', profile: 'pgone', source: { kind: 'home' } },
|
|
{ id: 'b', tabId: 'kb', profile: 'default', source: { kind: 'dms' } },
|
|
] }], { kinds: X_COLUMN_KINDS, profiles: ['default'], fallbackProfile: 'default' });
|
|
assert.deepEqual(deck!.columns.map(c => [c.id, c.profile]), [['a', 'default']], 'no DM columns');
|
|
});
|
|
|
|
const base: PaletteContext = {
|
|
tabs: [{ id: 't1', title: 'Home / X', url: 'https://x.com/home' }],
|
|
profiles: [{ id: 'default', name: 'Main' }],
|
|
activeProfile: 'default',
|
|
};
|
|
|
|
test('palette: the Deck group only navigates', () => {
|
|
const none = buildItems({ ...base, decks: [] }, '').filter(item => item.group === 'Deck');
|
|
assert.deepEqual(none.map(item => item.action), [{ type: 'deck' }]);
|
|
const context: PaletteContext = {
|
|
...base,
|
|
decks: [
|
|
{ id: 'd1', name: 'Monitor', columns: [{ id: 'c1', title: 'Home', profile: 'default' }, { id: 'c2', title: 'Mentions', profile: 'default' }] },
|
|
{ id: 'd2', name: 'Launch', columns: [] },
|
|
],
|
|
activeDeck: 'd1',
|
|
};
|
|
const deck = buildItems(context, '').filter(item => item.group === 'Deck');
|
|
assert.deepEqual(deck.map(item => item.action.type), ['deck', 'deck-add', 'deck-focus', 'deck-focus', 'deck-new']);
|
|
assert.deepEqual(deck[0]!.action, { type: 'deck', deckId: 'd2' }, 'switch to the other deck');
|
|
assert.deepEqual(deck[2]!.action, { type: 'deck-focus', deckId: 'd1', columnId: 'c1' });
|
|
assert.equal(deck[2]!.hint, 'Alt+1');
|
|
for (const item of deck) assert.ok(['deck', 'deck-add', 'deck-focus', 'deck-new'].includes(item.action.type), 'navigation only');
|
|
const found = buildItems(context, 'mentions');
|
|
assert.ok(found.some(item => item.id === 'deck-focus:c2'), 'columns are searchable');
|
|
const power = buildItems(context, 'tweetdeck');
|
|
assert.ok(power.some(item => item.group === 'Deck'));
|
|
});
|