import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import type { User } from '@backspace/shared'; // Stub AudioManager — pulled in transitively via spaceStore from useCanonicalUserView. vi.mock('../../audio/AudioManager', () => ({ AudioManager: { getInstance: vi.fn().mockReturnValue({ setOutputDevice: vi.fn(), setVolume: vi.fn(), }), }, })); // Force desktop rendering in ContextMenuRenderer (mobile path triggers // document-level long-press listeners we don't need here). // DmMemberRow now anchors the profile popout itself via // `useUIStore.getState().openUserProfile(...)`, so we expose a real `getState` // hook that the test below asserts against. const openUserProfileMock = vi.fn(); const uiStoreState = { isMobile: false, openUserProfile: openUserProfileMock }; vi.mock('../../stores/uiStore', () => ({ useUIStore: Object.assign( (selector: (s: typeof uiStoreState) => unknown) => selector(uiStoreState), { getState: () => uiStoreState, setState: vi.fn(), subscribe: vi.fn(), }, ), })); import { DmMemberRow, type DmMemberRowAction } from './DmMemberRow'; import { ContextMenuRenderer } from '../ui/ContextMenuRenderer'; import { useContextMenuStore } from '../../stores/contextMenuStore'; function makeUser(overrides: Partial = {}): User { return { id: 'u-1', username: 'alice', displayName: 'Alice', avatar: null, banner: null, accentColor: null, avatarColor: null, bio: null, status: 'online', customStatus: null, isAdmin: false, createdAt: 0, homeInstance: null, homeUserId: null, replicatedInstances: [], ...overrides, }; } beforeEach(() => { // Make sure each test starts with no menu open. act(() => { useContextMenuStore.getState().close(); }); openUserProfileMock.mockClear(); }); function renderRow(props: Partial[0]> = {}) { const onMenuAction = vi.fn<(action: DmMemberRowAction, member: User) => void>(); const member = props.member ?? makeUser(); const utils = render( <> , ); return { ...utils, onMenuAction, member }; } function openMenuByContextMenu(target: HTMLElement) { fireEvent.contextMenu(target, { clientX: 100, clientY: 100 }); } function getMenuLabels(): string[] { // Menu items render as