feat(client): chat timeline renders name_changed + icon_changed system messages
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { SystemMessage } from './SystemMessage';
|
||||
import type { DmChannel, MessageWithUser, User } from '@backspace/shared';
|
||||
|
||||
// SpaceInviteCard is unrelated to the cases under test but is imported by
|
||||
// SystemMessage; stub its store hooks so the import graph resolves cleanly.
|
||||
vi.mock('../../stores/spaceStore', () => ({
|
||||
useSpaceStore: (selector: (s: unknown) => unknown) =>
|
||||
selector({ joinByCode: vi.fn() }),
|
||||
getApiForOrigin: vi.fn(),
|
||||
}));
|
||||
vi.mock('../../api/client', () => ({
|
||||
api: {},
|
||||
createApiClient: vi.fn(),
|
||||
}));
|
||||
|
||||
const actor: User = {
|
||||
id: 'U1',
|
||||
username: 'jannis',
|
||||
displayName: 'Jannis',
|
||||
avatar: null,
|
||||
banner: null,
|
||||
accentColor: null,
|
||||
avatarColor: 'mint',
|
||||
bio: null,
|
||||
status: 'online',
|
||||
customStatus: null,
|
||||
isAdmin: false,
|
||||
createdAt: 0,
|
||||
homeUserId: null,
|
||||
homeInstance: null,
|
||||
replicatedInstances: [],
|
||||
};
|
||||
|
||||
function buildMessage(content: object, userId = 'U1'): MessageWithUser {
|
||||
return {
|
||||
id: 'M1',
|
||||
channelId: '',
|
||||
userId,
|
||||
user: actor,
|
||||
content: JSON.stringify(content),
|
||||
type: 'system',
|
||||
createdAt: 1,
|
||||
editedAt: null,
|
||||
replyToId: null,
|
||||
replyTo: null,
|
||||
attachments: [],
|
||||
embeds: [],
|
||||
reactions: [],
|
||||
mentions: [],
|
||||
everyoneMentioned: false,
|
||||
pinnedAt: null,
|
||||
} as unknown as MessageWithUser;
|
||||
}
|
||||
|
||||
const dm: Pick<DmChannel, 'members'> = { members: [actor] };
|
||||
|
||||
function renderSM(message: MessageWithUser, dmArg: Pick<DmChannel, 'members'> | null) {
|
||||
return render(
|
||||
<MemoryRouter>
|
||||
<SystemMessage message={message} dm={dmArg} />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
}
|
||||
|
||||
describe('SystemMessage — name_changed', () => {
|
||||
it('newName="Cool Group" with resolvable actor → "✎ Jannis renamed the group to \\"Cool Group\\""', () => {
|
||||
const msg = buildMessage({ event: 'name_changed', oldName: null, newName: 'Cool Group' });
|
||||
renderSM(msg, dm);
|
||||
expect(screen.getByText('✎')).toBeDefined();
|
||||
expect(screen.getByText(/Jannis renamed the group to "Cool Group"/)).toBeDefined();
|
||||
});
|
||||
|
||||
it('newName=null (cleared) with resolvable actor → "✎ Jannis cleared the group name"', () => {
|
||||
const msg = buildMessage({ event: 'name_changed', oldName: 'Old', newName: null });
|
||||
renderSM(msg, dm);
|
||||
expect(screen.getByText('✎')).toBeDefined();
|
||||
expect(screen.getByText(/Jannis cleared the group name/)).toBeDefined();
|
||||
});
|
||||
|
||||
it('unresolvable actor (member missing from roster) → "✎ Unknown renamed …"', () => {
|
||||
const msg = buildMessage({ event: 'name_changed', oldName: null, newName: 'X' }, 'GHOST');
|
||||
renderSM(msg, dm); // dm.members has only U1, not GHOST
|
||||
expect(screen.getByText(/Unknown renamed the group to "X"/)).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('SystemMessage — icon_changed', () => {
|
||||
it('resolvable actor → "🖼 Jannis updated the group icon"', () => {
|
||||
const msg = buildMessage({ event: 'icon_changed' });
|
||||
renderSM(msg, dm);
|
||||
// The 🖼 character is U+1F5BC (FRAME WITH PICTURE), not 🖼️ (with VS-16).
|
||||
expect(screen.getByText('\u{1F5BC}')).toBeDefined();
|
||||
expect(screen.getByText(/Jannis updated the group icon/)).toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user