import assert from 'node:assert/strict'; import test from 'node:test'; import { parseAddress } from '../src/shell/addressModel.ts'; function labels(url: string, wording: 'twitter' | 'x' = 'x') { const model = parseAddress(url, wording); return model ? model.segments.map((s) => s.label) : null; } test('home', () => { assert.deepEqual(labels('https://x.com/home'), ['Home']); assert.deepEqual(labels('https://x.com/'), ['Home']); }); test('search with quoted truncated query', () => { const long = 'a'.repeat(60); const model = parseAddress(`https://x.com/search?q=${long}`, 'x'); assert.ok(model); assert.equal(model!.segments[0].label, 'Search'); const quoted = model!.segments[1]; assert.ok(quoted.quoted); assert.ok(quoted.label.length <= 42); assert.ok(quoted.label.endsWith('…"')); }); test('notifications and mentions', () => { assert.deepEqual(labels('https://x.com/notifications'), ['Notifications']); assert.deepEqual(labels('https://x.com/notifications/mentions'), ['Notifications', 'Mentions']); }); test('messages with mono last6 id', () => { const model = parseAddress('https://x.com/messages/1234567890', 'x'); assert.ok(model); assert.equal(model!.segments[0].label, 'Messages'); assert.equal(model!.segments[1].label, '…567890'); assert.ok(model!.segments[1].mono); }); test('bookmarks, lists and communities', () => { assert.deepEqual(labels('https://x.com/i/bookmarks'), ['Bookmarks']); assert.deepEqual(labels('https://x.com/i/lists/9876543210'), ['Lists', '…543210']); assert.deepEqual(labels('https://x.com/i/communities/1112223334'), ['Communities', '…223334']); }); test('explore with capitalised tab', () => { assert.deepEqual(labels('https://x.com/explore'), ['Explore']); assert.deepEqual(labels('https://x.com/explore/tabs/trending'), ['Explore', 'Trending']); }); test('settings parts are title-cased', () => { assert.deepEqual(labels('https://x.com/settings/account/username'), ['Settings', 'Account', 'Username']); }); test('user profile chip', () => { assert.deepEqual(labels('https://x.com/jack'), ['@jack']); }); test('reserved paths are not treated as usernames', () => { assert.deepEqual(labels('https://x.com/home'), ['Home']); assert.deepEqual(labels('https://x.com/explore'), ['Explore']); assert.deepEqual(labels('https://x.com/settings'), ['Settings']); assert.deepEqual(labels('https://x.com/i/bookmarks'), ['Bookmarks']); }); test('status url with mono last6 id', () => { const model = parseAddress('https://x.com/jack/status/1234567890123', 'x'); assert.ok(model); assert.deepEqual( model!.segments.map((s) => s.label), ['@jack', 'Post', '…890123'], ); assert.ok(model!.segments[2].mono); }); test('status photo suffix', () => { assert.deepEqual( labels('https://x.com/jack/status/1234567890123/photo/2'), ['@jack', 'Post', '…890123', 'Photo 2'], ); }); test('status analytics suffix', () => { assert.deepEqual( labels('https://x.com/jack/status/1234567890123/analytics'), ['@jack', 'Post', '…890123', 'Analytics'], ); }); test('user subpages', () => { assert.deepEqual(labels('https://x.com/jack/with_replies'), ['@jack', 'Replies']); assert.deepEqual(labels('https://x.com/jack/media'), ['@jack', 'Media']); assert.deepEqual(labels('https://x.com/jack/likes'), ['@jack', 'Likes']); assert.deepEqual(labels('https://x.com/jack/followers'), ['@jack', 'Followers']); assert.deepEqual(labels('https://x.com/jack/following'), ['@jack', 'Following']); }); test('twitter.com behaves the same as x.com', () => { assert.deepEqual(labels('https://twitter.com/home'), labels('https://x.com/home')); assert.deepEqual(labels('https://twitter.com/jack/status/42'), labels('https://x.com/jack/status/42')); }); test('site chip label follows wording setting', () => { assert.equal(parseAddress('https://x.com/home', 'x')!.site.label, 'X'); assert.equal(parseAddress('https://x.com/home', 'twitter')!.site.label, 'Twitter'); }); test('http url is flagged insecure', () => { const model = parseAddress('http://x.com/home', 'x'); assert.ok(model); assert.equal(model!.insecure, true); assert.equal(parseAddress('https://x.com/home', 'x')!.insecure, false); }); test('other hosts show hostname without www and truncated path parts', () => { const model = parseAddress('https://www.example.com/some/very/long/path/segment/name/that/is/too/long', 'x'); assert.ok(model); assert.equal(model!.site.kind, 'host'); assert.equal(model!.site.label, 'example.com'); assert.ok(model!.segments[0].label.length <= 24); }); test('non-empty query on other hosts shows a trailing chip', () => { const model = parseAddress('https://example.com/path?x=1', 'x'); assert.ok(model); assert.equal(model!.segments[model!.segments.length - 1].label, '?…'); }); test('about and file schemes and invalid urls are unparsable', () => { assert.equal(parseAddress('about:blank', 'x'), null); assert.equal(parseAddress('file:///etc/passwd', 'x'), null); assert.equal(parseAddress('not a url', 'x'), null); });