nitro-v36-with-renderer-v36
/
src /
components /
room /
widgets /
avatar-info /
menu /
AvatarInfoWidgetOwnAvatarView.classic.test.tsx
AvatarInfoWidgetOwnAvatarView.classic.test.tsx 6.4 Ko
Télécharger le fichier
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
import { type ReactNode } from 'react';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { AvatarInfoWidgetOwnAvatarView } from './AvatarInfoWidgetOwnAvatarView';
const mocks = vi.hoisted(() => ({
config: new Map<string, unknown>(),
createLinkEvent: vi.fn(),
effectId: 0,
handItemBlocked: false,
hasClub: true,
hasVip: true,
posture: 'std',
sendDanceMessage: vi.fn(),
sendExpressionMessage: vi.fn(),
sendPostureMessage: vi.fn(),
sendSignMessage: vi.fn(),
showInspectButton: true
}));
afterEach(() => {
cleanup();
vi.clearAllMocks();
mocks.config.clear();
mocks.effectId = 0;
mocks.handItemBlocked = false;
mocks.hasClub = true;
mocks.hasVip = true;
mocks.posture = 'std';
mocks.showInspectButton = true;
});
vi.mock('@octane/renderer', () => ({
AvatarAction: { POSTURE_STAND: 'std', POSTURE_SWIM: 'swim' },
AvatarExpressionEnum: {
BLOW: { ordinal: 2 },
EXPRESSION_67: { ordinal: 67 },
IDLE: { ordinal: 3 },
LAUGH: { ordinal: 4 },
WAVE: { ordinal: 1 }
},
CreateLinkEvent: mocks.createLinkEvent,
GetRoomEngine: () => ({ activeRoomHasHanditemControlBlocked: mocks.handItemBlocked }),
RoomControllerLevel: { GUEST: 0 },
RoomObjectCategory: { UNIT: 100 },
RoomObjectVariable: { FIGURE_EFFECT: 'figure_effect' },
RoomUnitDropHandItemComposer: class {}
}));
vi.mock('../../../../../api', () => ({
DispatchUiEvent: vi.fn(),
GetCanStandUp: () => false,
GetConfigurationValue: (key: string, fallback: unknown) => (mocks.config.has(key) ? mocks.config.get(key) : fallback),
GetOwnPosture: () => mocks.posture,
GetOwnRoomObject: () => ({ model: { getValue: () => mocks.effectId } }),
GetUserProfile: vi.fn(),
HasHabboClub: () => mocks.hasClub,
HasHabboVip: () => mocks.hasVip,
IsRidingHorse: () => false,
LocalizeText: (key: string) => key,
localizeWithFallback: (_key: string, fallback: string) => fallback,
PostureTypeEnum: { POSTURE_SIT: 'sit', POSTURE_STAND: 'stand' },
SendMessageComposer: vi.fn()
}));
vi.mock('../../../../../events', () => ({ HelpNameChangeEvent: class {} }));
vi.mock('../../../../../hooks', () => ({
useRoom: () => ({
roomSession: {
sendDanceMessage: mocks.sendDanceMessage,
sendExpressionMessage: mocks.sendExpressionMessage,
sendPostureMessage: mocks.sendPostureMessage,
sendSignMessage: mocks.sendSignMessage
}
}),
useAvatarEffects: () => ({ effects: [], activeEffectType: 0 }),
useWiredTools: () => ({ openInspectionForUser: vi.fn(), showInspectButton: mocks.showInspectButton })
}));
vi.mock('../../context-menu/ContextMenuView', () => ({
ContextMenuView: ({
children,
classNames = [],
freezePositionOnHover,
maximumVerticalLeadRatio,
tallAvatarOffset
}: {
children: ReactNode;
classNames?: string[];
freezePositionOnHover?: boolean;
maximumVerticalLeadRatio?: number;
tallAvatarOffset?: number;
}) => (
<div
className={classNames.join(' ')}
data-freeze-position-on-hover={String(freezePositionOnHover)}
data-maximum-vertical-lead-ratio={maximumVerticalLeadRatio}
data-tall-avatar-offset={tallAvatarOffset}
>
{children}
</div>
)
}));
const avatarInfo = {
allowNameChange: true,
amIAnyRoomController: false,
amIOwner: true,
carryItem: 7,
name: 'tester',
roomControllerLevel: 0,
roomIndex: 7,
userType: 1,
webID: 42
} as any;
const renderMenu = (onClose = vi.fn(), isDancing = false) =>
render(<AvatarInfoWidgetOwnAvatarView avatarInfo={avatarInfo} isDancing={isDancing} setIsDecorating={vi.fn()} onClose={onClose} />);
const getActionLabels = () => Array.from(document.querySelector('.air-avatar-menu-buttons').children).map((element) => element.textContent);
describe('AIR own-avatar menu', () => {
it('uses the own-menu variant, AIR anchor rules, XML row order, and then Polaris extras', () => {
renderMenu();
const menu = document.querySelector('.octane-avatar-action-menu--own');
expect(menu).toHaveClass('octane-avatar-action-menu');
expect(menu).toHaveAttribute('data-tall-avatar-offset', '25');
expect(menu).toHaveAttribute('data-maximum-vertical-lead-ratio', '0.05');
expect(menu).toHaveAttribute('data-freeze-position-on-hover', 'true');
expect(getActionLabels()).toEqual([
'widget.avatar.change_name',
'widget.avatar.decorate',
'widget.memenu.myclothes',
'infostand.link.expressions',
'widget.memenu.dance',
'infostand.show.signs',
'avatar.widget.drop_hand_item',
'infostand.button.wired_inspect',
'Custom nickname',
'Badge leaderboard'
]);
expect(screen.queryByText('product.type.effect')).not.toBeInTheDocument();
// Effects are bought in the catalogue and worn from the inventory, so the menu has no Effects entry.
expect(screen.queryByText('widget.memenu.effects')).not.toBeInTheDocument();
});
it('keeps the retained AIR and Polaris actions wired', () => {
const onClose = vi.fn();
renderMenu(onClose);
fireEvent.click(screen.getByText('widget.memenu.myclothes'));
fireEvent.click(screen.getByText('Custom nickname'));
fireEvent.click(screen.getByText('Badge leaderboard'));
expect(mocks.createLinkEvent).toHaveBeenCalledWith('avatar-editor/show');
expect(mocks.createLinkEvent).not.toHaveBeenCalledWith('avatar-effects/show');
expect(mocks.createLinkEvent).toHaveBeenCalledWith('customize/show');
expect(mocks.createLinkEvent).toHaveBeenCalledWith('badge-leaderboard/show');
expect(onClose).toHaveBeenCalledTimes(3);
});
it('hides drop hand item while the room blocks hand items (ConfigurationItemStates)', () => {
mocks.handItemBlocked = true;
renderMenu();
expect(screen.queryByText('avatar.widget.drop_hand_item')).toBeNull();
cleanup();
mocks.handItemBlocked = false;
renderMenu();
expect(screen.getByText('avatar.widget.drop_hand_item')).toBeInTheDocument();
});
});
