5180 fichiers 38.5 Mo 0 téléchargements 404 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / friends / views / messenger / FriendsMessengerAvatarHeads.test.tsx
FriendsMessengerAvatarHeads.test.tsx 9.8 Ko Télécharger le fichier
/* @vitest-environment jsdom */

import { AddLinkEventTracker, GetAvatarRenderManager, GetSessionDataManager } from '@octane/renderer';
import { act, cleanup, fireEvent, render, waitFor } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { MessengerFriend, MessengerThread } from '../../../../api';
import { useFriends, useHelp, useMessenger, useTranslation } from '../../../../hooks';
import { useHabbiconCatalog } from '../../../../hooks/habbicons/useHabbiconCatalog';
import { FriendsMessengerView } from './FriendsMessengerView';
import { FriendsMessengerThreadGroup } from './messenger-thread/FriendsMessengerThreadGroup';

vi.mock('../../../../hooks', () => ({
    useFriends: vi.fn(),
    useHelp: vi.fn(),
    useMessenger: vi.fn(),
    useTranslation: vi.fn()
}));

// Avatar tests control the catalogue dependency just like the messenger and
// friends hooks; the real shared hook requires the application registry.
vi.mock('../../../../hooks/habbicons/useHabbiconCatalog', () => ({
    useHabbiconCatalog: vi.fn()
}));

vi.mock('../../../../common/layout/avatarImageCrop', async (importOriginal) => ({
    ...(await importOriginal<typeof import('../../../../common/layout/avatarImageCrop')>()),
    cropTransparentImageUrl: vi.fn(async () => 'data:image/png;base64,cropped')
}));

vi.mock('../../StaffChatFrankIconView', () => ({
    StaffChatFrankIconView: (props: { className?: string; size: number }) => (
        <div className={`staff-chat-frank-icon ${props.className || ''}`.trim()} data-size={props.size} />
    )
}));

const figure = 'hd-180-1.ch-210-66.lg-270-82.sh-290-80';

const makeFriend = (id = 42, name = 'Lorenzo') => {
    const friend = new MessengerFriend();

    friend.id = id;
    friend.name = name;
    friend.gender = 0;
    friend.figure = figure;
    friend.online = true;

    return friend;
};

const makeThread = (friend: MessengerFriend) => {
    const thread = new MessengerThread(friend);

    thread.addMessage(friend.id, 'Ciao');

    return thread;
};

describe('Messenger avatar heads', () => {
    const friend = makeFriend();

    beforeEach(() => {
        vi.mocked(useHabbiconCatalog).mockReturnValue({
            enabled: false,
            baseUrl: '',
            entries: [],
            ownedEntries: [],
            sets: [],
            ownedSets: [],
            recentIds: [],
            favoriteIds: [],
            lastUsedCollectionId: 0,
            loaded: false,
            assetError: false,
            bookVisible: false,
            setBookVisible: vi.fn(),
            purchase: null,
            setPurchase: vi.fn(),
            pending: null,
            error: '',
            refresh: vi.fn(),
            retry: vi.fn(),
            unseenCount: 0,
            isUnseen: () => false,
            clearUnseen: vi.fn(),
            getInfo: vi.fn(),
            toggleFavorite: vi.fn(),
            claim: vi.fn(),
            buy: vi.fn()
        });

        vi.mocked(AddLinkEventTracker).mockClear();
        vi.mocked(GetAvatarRenderManager).mockReturnValue({
            createAvatarImage: () => ({
                setDirection: vi.fn(),
                processAsImageUrl: () => 'data:image/png;base64,raw',
                isPlaceholder: () => false,
                dispose: vi.fn()
            })
        } as unknown as ReturnType<typeof GetAvatarRenderManager>);
        vi.mocked(GetSessionDataManager).mockReturnValue({
            userId: 7,
            userName: 'Simoleo',
            figure
        } as ReturnType<typeof GetSessionDataManager>);
        vi.mocked(useFriends).mockReturnValue({ getFriend: () => friend } as unknown as ReturnType<typeof useFriends>);
        vi.mocked(useHelp).mockReturnValue({ report: vi.fn() } as unknown as ReturnType<typeof useHelp>);
        vi.mocked(useTranslation).mockReturnValue({
            settings: { enabled: false },
            translateOutgoing: vi.fn()
        } as unknown as ReturnType<typeof useTranslation>);
    });

    afterEach(cleanup);

    it('uses a tightly cropped head in each conversation tab', () => {
        const thread = makeThread(friend);

        vi.mocked(useMessenger).mockReturnValue({
            visibleThreads: [thread],
            activeThread: null,
            getMessageThread: () => thread,
            sendMessage: vi.fn(),
            setActiveThreadId: vi.fn(),
            closeThread: vi.fn(),
            typingUserIds: [],
            sendTypingStatus: vi.fn()
        } as unknown as ReturnType<typeof useMessenger>);

        render(<FriendsMessengerView />);

        const tracker = vi.mocked(AddLinkEventTracker).mock.calls[0][0];

        act(() => tracker.linkReceived('friends-messenger/open'));

        const avatar = document.querySelector<HTMLElement>('.messenger-avatar-tab .avatar-image');

        expect(avatar).not.toBeNull();
        expect(avatar).toHaveClass('compact-head');
        expect(avatar).toHaveStyle({ backgroundSize: '35px 35px' });
        // jsdom 30.1.3 reports `center` as `50% 50%`; both mean the same position.
        expect(['center', 'center center', '50% 50%']).toContain((avatar as HTMLElement).style.backgroundPosition);
    });

    it('uses the AIR avatar crop on the right side of incoming messages', () => {
        const thread = makeThread(friend);
        const { container } = render(<FriendsMessengerThreadGroup thread={thread} group={thread.groups[0]} />);
        const avatar = container.querySelector<HTMLElement>('.message-avatar .avatar-image');
        const row = container.querySelector<HTMLElement>('.messenger-message-row');

        expect(avatar).not.toBeNull();
        expect(avatar).not.toHaveClass('compact-head');
        expect(row.lastElementChild).toHaveClass('message-avatar');
    });

    it('uses the AIR avatar crop on the left side of sent messages', () => {
        const thread = new MessengerThread(friend);

        thread.addMessage(7, 'Ciao Lorenzo');

        const { container } = render(<FriendsMessengerThreadGroup thread={thread} group={thread.groups[0]} />);
        const avatar = container.querySelector<HTMLElement>('.messenger-message-row.own .message-avatar .avatar-image');
        const row = container.querySelector<HTMLElement>('.messenger-message-row.own');

        expect(avatar).not.toBeNull();
        expect(avatar).not.toHaveClass('compact-head');
        expect(row.firstElementChild).toHaveClass('message-avatar');
    });

    it('uses the seven-avatar viewport with working overflow controls', async () => {
        const friends = Array.from({ length: 8 }, (_, index) => makeFriend(index + 1, `Friend ${index + 1}`));
        const threads = friends.map(makeThread);

        vi.mocked(useFriends).mockReturnValue({ getFriend: (id: number) => friends.find((entry) => entry.id === id) } as unknown as ReturnType<
            typeof useFriends
        >);
        vi.mocked(useMessenger).mockReturnValue({
            visibleThreads: threads,
            activeThread: threads[0],
            getMessageThread: (id: number) => threads.find((thread) => thread.participant.id === id),
            sendMessage: vi.fn(),
            setActiveThreadId: vi.fn(),
            closeThread: vi.fn(),
            typingUserIds: [],
            sendTypingStatus: vi.fn()
        } as unknown as ReturnType<typeof useMessenger>);

        render(<FriendsMessengerView />);

        const tracker = vi.mocked(AddLinkEventTracker).mock.calls[0][0];
        act(() => tracker.linkReceived('friends-messenger/open'));

        expect(document.querySelector('.messenger-window')).not.toBeNull();
        expect(document.querySelectorAll('.messenger-avatar-tab')).toHaveLength(7);
        expect(document.querySelectorAll('.messenger-avatar-tab[role="tab"]')).toHaveLength(7);
        expect(document.querySelectorAll('.messenger-avatar-bar[role="tablist"]')).toHaveLength(1);
        expect(document.querySelectorAll('.messenger-avatar-tab[aria-selected="true"]')).toHaveLength(1);
        expect(document.querySelector<HTMLButtonElement>('[data-action="scroll-left"]')).toBeDisabled();
        expect(document.querySelector<HTMLButtonElement>('[data-action="scroll-right"]')).not.toBeDisabled();

        fireEvent.click(document.querySelector<HTMLButtonElement>('[data-action="scroll-right"]'));

        await waitFor(() => expect(document.querySelector('[data-participant-id="8"]')).not.toBeNull());
        expect(document.querySelector('[data-participant-id="1"]')).toBeNull();
    });

    it('renders the dedicated Frank face and no user actions for Staff Chat', () => {
        const staff = makeFriend(-1, 'Staff Chat');
        staff.figure = 'ADM';
        const thread = makeThread(staff);

        vi.mocked(useFriends).mockReturnValue({ getFriend: () => staff } as unknown as ReturnType<typeof useFriends>);
        vi.mocked(useMessenger).mockReturnValue({
            visibleThreads: [thread],
            activeThread: thread,
            getMessageThread: () => thread,
            sendMessage: vi.fn(),
            setActiveThreadId: vi.fn(),
            closeThread: vi.fn(),
            typingUserIds: [],
            sendTypingStatus: vi.fn()
        } as unknown as ReturnType<typeof useMessenger>);

        render(<FriendsMessengerView />);

        const tracker = vi.mocked(AddLinkEventTracker).mock.calls[0][0];
        act(() => tracker.linkReceived('friends-messenger/open'));

        expect(document.querySelector('.messenger-avatar-tab .staff-chat-frank-icon.staff-chat-frank')).toHaveAttribute('data-size', '35');
        expect(document.querySelector('.messenger-avatar-tab .avatar-image')).toBeNull();
        expect(document.querySelector('.messenger-actions .follow')).toBeNull();
        expect(document.querySelector('.messenger-actions .profile')).toBeNull();
        expect(document.querySelector('.messenger-actions .danger')).toBeNull();
        expect(document.querySelector('.messenger-actions .close-btn')).not.toBeNull();
    });
});
15Sujets
1Dépôts
20Membres
3En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser