Neutral sample account names in tests, check scripts and the site's demo UI
The framework moves to 0e344ee.
This commit is contained in:
parent
83f8c363b4
commit
4c6817ecb5
42 changed files with 136 additions and 136 deletions
|
|
@ -16,7 +16,7 @@ const settings: ProfileSettings = normalizeProfiles({
|
|||
active: 'default',
|
||||
profiles: [
|
||||
{ id: 'default', name: 'Main', color: '#1d9bf0', account: { handle: 'CRTkafa', name: 'CRT kafa', signedIn: true } },
|
||||
{ id: 'pwork1', name: 'Work', color: '#7856ff', account: { handle: 'playfishies', name: 'Fishies', signedIn: true } },
|
||||
{ id: 'pwork1', name: 'Work', color: '#7856ff', account: { handle: 'otheraccount', name: 'Sample', signedIn: true } },
|
||||
{ id: 'pout01', name: 'Old', color: '#f91880', account: { handle: 'oldone', name: 'Old', signedIn: false } },
|
||||
{ id: 'pnew01', name: 'New account', color: '#00ba7c' },
|
||||
],
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ class El {
|
|||
const EDITOR = { 'data-testid': 'tweetTextarea_0', role: 'textbox', contenteditable: 'true' };
|
||||
|
||||
/** X's page with the account button and one composer (editor, toolbar with Post). */
|
||||
function composerPage(handle = 'fishies') {
|
||||
function composerPage(handle = 'sample') {
|
||||
const block = new El('div', { 'data-block': 'true' });
|
||||
const editor = new El('div', EDITOR, new El('div', { 'data-contents': 'true' }, block));
|
||||
const postButton = new El('button', { 'data-testid': 'tweetButtonInline' }, 'Post');
|
||||
|
|
@ -366,16 +366,16 @@ test('length meter: counts the way X counts', () => {
|
|||
});
|
||||
|
||||
test('"Posting as": one colour per account, whatever the case of the handle', () => {
|
||||
assert.equal(accountHue('Fishies'), accountHue('fishies'));
|
||||
assert.notEqual(accountHue('fishies'), accountHue('someone'));
|
||||
for (const handle of ['a', 'fishies', 'someone_else', 'A_15_char_handl']) {
|
||||
assert.equal(accountHue('Sample'), accountHue('sample'));
|
||||
assert.notEqual(accountHue('sample'), accountHue('someone'));
|
||||
for (const handle of ['a', 'sample', 'someone_else', 'A_15_char_handl']) {
|
||||
const hue = accountHue(handle);
|
||||
assert.ok(Number.isInteger(hue) && hue >= 0 && hue < 360, handle);
|
||||
}
|
||||
});
|
||||
|
||||
test('"Posting as" and the length meter: one line above the toolbar, kept current, gone without a trace', () => {
|
||||
const page = composerPage('fishies');
|
||||
const page = composerPage('sample');
|
||||
const before = page.body.html();
|
||||
const env = composeEnv(page);
|
||||
const idle = env.listeners();
|
||||
|
|
@ -385,10 +385,10 @@ test('"Posting as" and the length meter: one line above the toolbar, kept curren
|
|||
const bar = page.toolbar.previousElementSibling!;
|
||||
assert.ok(bar.hasAttribute('data-bt-compose-bar'), 'the line is right above X\'s toolbar');
|
||||
const chip = bar.querySelector('[data-bt-compose-chip]')!;
|
||||
assert.equal(chip.textContent, 'Posting as @fishies');
|
||||
assert.equal(chip.getAttribute('data-bt-compose-chip'), 'fishies');
|
||||
assert.equal(chip.style.props['--bt-compose-hue'], String(accountHue('fishies')));
|
||||
assert.match(chip.title, /@fishies/);
|
||||
assert.equal(chip.textContent, 'Posting as @sample');
|
||||
assert.equal(chip.getAttribute('data-bt-compose-chip'), 'sample');
|
||||
assert.equal(chip.style.props['--bt-compose-hue'], String(accountHue('sample')));
|
||||
assert.match(chip.title, /@sample/);
|
||||
assert.equal(bar.querySelector('[data-bt-compose-meter]'), null, 'an empty composer has nothing to measure');
|
||||
// Typing: the meter follows, in the same line.
|
||||
page.block.textContent = 'hello https://example.com/a/long/link';
|
||||
|
|
@ -442,7 +442,7 @@ test('"Posting as" and the length meter: one line above the toolbar, kept curren
|
|||
env.registry.setFlags(only({}));
|
||||
second.remove();
|
||||
page.block.textContent = '';
|
||||
page.avatar.setAttribute('data-testid', 'UserAvatar-Container-fishies');
|
||||
page.avatar.setAttribute('data-testid', 'UserAvatar-Container-sample');
|
||||
assert.equal(page.body.html(), before);
|
||||
assert.deepEqual(env.live(), []);
|
||||
assert.equal(env.listeners(), idle);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { asPreview, isBareCard, previewable } from '../src/areas/chat/linkPrevie
|
|||
|
||||
test('link previews: only plain https links to hosts that are not X\'s own', () => {
|
||||
assert.equal(previewable('https://www.youtube.com/watch?v=dQw4w9WgXcQ'), 'https://www.youtube.com/watch?v=dQw4w9WgXcQ');
|
||||
assert.equal(previewable('https://fishies.lol/'), 'https://fishies.lol/');
|
||||
assert.equal(previewable('https://example.org/'), 'https://example.org/');
|
||||
for (const bad of [
|
||||
'http://example.com/', 'https://user:pw@example.com/', 'https://example.com:8443/', 'https://192.168.0.1/', 'https://[::1]/',
|
||||
'https://intranet/', 'https://x.com/a/status/1', 'https://t.co/abc', 'https://pbs.twimg.com/media/a.jpg', 'javascript:alert(1)', '/i/chat/1-2', '', null,
|
||||
|
|
@ -16,7 +16,7 @@ test('link previews: only plain https links to hosts that are not X\'s own', ()
|
|||
});
|
||||
|
||||
test('link previews: a native answer is checked again: plain fields, capped, data: images of four types, an 11-character video id', () => {
|
||||
const good = asPreview({ url: 'https://fishies.lol/', site: 'Fishies', title: 'The social aquarium', description: 'x'.repeat(400), image: 'data:image/png;base64,iVBORw0KGgo=' });
|
||||
const good = asPreview({ url: 'https://example.org/', site: 'Sample', title: 'The social aquarium', description: 'x'.repeat(400), image: 'data:image/png;base64,iVBORw0KGgo=' });
|
||||
assert.ok(good);
|
||||
assert.equal(good.description.length, 300);
|
||||
assert.equal(good.image, 'data:image/png;base64,iVBORw0KGgo=');
|
||||
|
|
@ -37,7 +37,7 @@ test('link previews: a native answer is checked again: plain fields, capped, dat
|
|||
test('link previews: X\'s bare card (a host name and an icon) is replaced; a card with its own picture or a sentence is not', () => {
|
||||
const anchor = (text: string, media = false) => ({ textContent: text, querySelector: () => (media ? {} : null) }) as unknown as Element;
|
||||
assert.equal(isBareCard(anchor('www.youtube.com')), true);
|
||||
assert.equal(isBareCard(anchor('fishies.lol')), true);
|
||||
assert.equal(isBareCard(anchor('example.org')), true);
|
||||
assert.equal(isBareCard(anchor('www.youtube.com', true)), false);
|
||||
assert.equal(isBareCard(anchor('watch this video')), false);
|
||||
assert.equal(isBareCard(anchor('www.youtube.com/watch?v=jNQXAC9IVRw')), false, 'a link in the text (live 2026-10-10) stays');
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { CLICK_GUARD_MS, QUEUE_MAX_MS, installClickGuard, installMutationGate }
|
|||
// Clicks reach the window capture listener first (the guard), then X's handler, like in the page.
|
||||
|
||||
const POST = '2103816196386852995', USER = '2086263555364691968';
|
||||
const BASE = 'https://x.com/playfishies/status/' + POST;
|
||||
const BASE = 'https://x.com/otheraccount/status/' + POST;
|
||||
|
||||
function clock() {
|
||||
let now = 0, seq = 0;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ test('deck columns: every kind loads an x.com page', () => {
|
|||
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: 'user', value: 'otheraccount' }), 'https://x.com/otheraccount');
|
||||
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));
|
||||
|
|
@ -23,20 +23,20 @@ test('deck columns: every kind loads an x.com page', () => {
|
|||
});
|
||||
|
||||
test('deck columns: typed values are parsed per kind', () => {
|
||||
assert.equal(parseColumnValue('user', '@playfishies'), 'playfishies');
|
||||
assert.equal(parseColumnValue('user', '@otheraccount'), 'otheraccount');
|
||||
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', ' wayBetter from:@otheraccount '), 'wayBetter from:otheraccount');
|
||||
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: 'user', value: 'otheraccount' }), { title: '@otheraccount', 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' });
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import { besideGroup, type GroupBox } from '../src/shell/paneModel.ts';
|
|||
|
||||
test('posts, profiles, hashtags, searches, lists and communities are routable', () => {
|
||||
for (const [path, search] of [
|
||||
['/playfishies/status/1840000000000000000', ''],
|
||||
['/playfishies/status/1840000000000000000/quotes', ''],
|
||||
['/otheraccount/status/1840000000000000000', ''],
|
||||
['/otheraccount/status/1840000000000000000/quotes', ''],
|
||||
['/CRTkafa', ''],
|
||||
['/CRTkafa/', ''],
|
||||
['/CRTkafa/media', ''],
|
||||
|
|
@ -20,9 +20,9 @@ test('posts, profiles, hashtags, searches, lists and communities are routable',
|
|||
|
||||
test('media viewers, X navigation pages and actions stay in place', () => {
|
||||
for (const [path, search] of [
|
||||
['/playfishies/status/1840000000000000000/photo/1', ''],
|
||||
['/playfishies/status/1840000000000000000/video/1', ''],
|
||||
['/playfishies/status/1840000000000000000/analytics', ''],
|
||||
['/otheraccount/status/1840000000000000000/photo/1', ''],
|
||||
['/otheraccount/status/1840000000000000000/video/1', ''],
|
||||
['/otheraccount/status/1840000000000000000/analytics', ''],
|
||||
['/home', ''], ['/explore', ''], ['/notifications', ''], ['/messages', ''], ['/settings', ''], ['/i/bookmarks', ''],
|
||||
['/compose/post', ''], ['/i/chat/123', ''], ['/search', ''], ['/logout', ''], ['/', ''],
|
||||
['/waytoolonghandlename_x', ''], ['/i/spaces/1', ''],
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ function env() {
|
|||
const fetch = (async (input: unknown) => String(input).includes('/live_pipeline/events')
|
||||
? new Response(stream, { status: 200, headers: { 'content-type': 'text/event-stream' } })
|
||||
: new Response('{}')) as typeof globalThis.fetch;
|
||||
const win = { fetch, location: { href: `https://x.com/playfishies/status/${POST}` }, XMLHttpRequest: FakeXHR as unknown as typeof XMLHttpRequest };
|
||||
const win = { fetch, location: { href: `https://x.com/otheraccount/status/${POST}` }, XMLHttpRequest: FakeXHR as unknown as typeof XMLHttpRequest };
|
||||
const send = (op: 'FavoriteTweet' | 'UnfavoriteTweet', id = POST) => {
|
||||
const xhr = new win.XMLHttpRequest();
|
||||
xhr.open('POST', `/i/api/graphql/q/${op}`);
|
||||
|
|
|
|||
|
|
@ -52,15 +52,15 @@ test('an account seen natively survives normalization; forged or broken ones do
|
|||
const settings = normalizeProfiles({
|
||||
active: 'default',
|
||||
profiles: [
|
||||
{ id: 'default', name: 'Fishies', color: '#1d9bf0', account: { handle: 'playfishies', name: 'Fishies', avatar: 'https://pbs.twimg.com/profile_images/1/a_x96.jpg', signedIn: true } },
|
||||
{ id: 'default', name: 'Sample', color: '#1d9bf0', account: { handle: 'otheraccount', name: 'Sample', avatar: 'https://pbs.twimg.com/profile_images/1/a_x96.jpg', signedIn: true } },
|
||||
{ id: 'p1', name: 'x', color: '#f91880', account: { handle: 'bad handle!', name: 'x', signedIn: true } },
|
||||
{ id: 'p2', name: 'y', color: '#00ba7c', account: { handle: 'CRTkafa', name: 'CRT', avatar: 'https://evil.test/a.png', signedIn: false } },
|
||||
],
|
||||
});
|
||||
assert.equal(settings.profiles[0]!.account?.handle, 'playfishies');
|
||||
assert.equal(settings.profiles[0]!.account?.handle, 'otheraccount');
|
||||
assert.equal(settings.profiles[1]!.account, undefined);
|
||||
assert.equal(settings.profiles[2]!.account?.avatar, undefined);
|
||||
assert.deepEqual(accountLabel(settings.profiles[0]!), { title: 'Fishies', detail: '@playfishies', state: 'signed-in' });
|
||||
assert.deepEqual(accountLabel(settings.profiles[0]!), { title: 'Sample', detail: '@otheraccount', state: 'signed-in' });
|
||||
assert.deepEqual(accountLabel(settings.profiles[2]!), { title: 'CRT', detail: '@CRTkafa · signed out', state: 'signed-out' });
|
||||
assert.equal(accountLabel(settings.profiles[1]!).state, 'new');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import {
|
|||
|
||||
const U = '2086263555364691968';
|
||||
const OTHER = '1790000000000000001';
|
||||
const BASE = 'https://x.com/playfishies';
|
||||
const BASE = 'https://x.com/otheraccount';
|
||||
|
||||
// Shapes as X sends them (live 2026-09-28): GraphQL user result (UserByScreenName, URT timelines)
|
||||
// and a REST 1.1 user object (friendships/create.json, friends/following/list.json).
|
||||
const gqlUser = (id: string, following: boolean, followers = 21) => ({
|
||||
__typename: 'User', rest_id: id, follow_request_sent: false, privacy: { protected: false },
|
||||
core: { name: 'Fishies', screen_name: 'playfishies' },
|
||||
core: { name: 'Sample', screen_name: 'otheraccount' },
|
||||
relationship_counts: { followers, following: 31 },
|
||||
relationship_perspectives: { followed_by: true, following, live_following: false, blocking: false, muting: false, blocked_by: false },
|
||||
});
|
||||
|
|
@ -93,11 +93,11 @@ test('strip: GraphQL and REST user objects of the listed users only', () => {
|
|||
assert.equal('relationship_perspectives' in mine, false);
|
||||
assert.equal('follow_request_sent' in mine, false);
|
||||
assert.deepEqual(mine.relationship_counts, { following: 31 });
|
||||
assert.deepEqual(mine.core, { name: 'Fishies', screen_name: 'playfishies' }, 'other fields untouched');
|
||||
assert.deepEqual(mine.core, { name: 'Sample', screen_name: 'otheraccount' }, 'other fields untouched');
|
||||
assert.deepEqual(other, gqlUser(OTHER, false), 'other users untouched');
|
||||
const rest = { id: 1, id_str: U, screen_name: 'playfishies', following: false, followers_count: 21, follow_request_sent: false, followed_by: true, legacy: { following: false, followers_count: 21, name: 'x' } };
|
||||
const rest = { id: 1, id_str: U, screen_name: 'otheraccount', following: false, followers_count: 21, follow_request_sent: false, followed_by: true, legacy: { following: false, followers_count: 21, name: 'x' } };
|
||||
assert.equal(stripRelationship([rest], new Set([`follow:${U}`])), 1);
|
||||
assert.deepEqual(rest, { id: 1, id_str: U, screen_name: 'playfishies', followed_by: true, legacy: { name: 'x' } });
|
||||
assert.deepEqual(rest, { id: 1, id_str: U, screen_name: 'otheraccount', followed_by: true, legacy: { name: 'x' } });
|
||||
assert.equal(stripRelationship({ id_str: U, name: 'no relationship fields' }, new Set([`follow:${U}`])), 0);
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue