/* @vitest-environment jsdom */ import { act, fireEvent, render, screen, waitFor, within, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { afterEach, beforeEach, expect, test, vi } from 'vitest'; import { getAdminAssetReadUrl, listAdminEditorAssets, } from '../api/adminApiClient'; import type { AdminEditorAssetListResponse, AdminEditorAssetPayload, } from '../api/adminApiTypes'; import { AdminEditorAssetQueryPage } from './AdminEditorAssetQueryPage'; vi.mock('../api/adminApiClient', () => ({ formatAdminApiError: vi.fn((error: unknown) => error instanceof Error ? error.message : '请求失败', ), getAdminAssetReadUrl: vi.fn(), isAdminApiError: vi.fn( (error: unknown) => typeof error === 'object' && error !== null && 'status' in error && typeof error.status === 'number', ), listAdminEditorAssets: vi.fn(), })); interface MockIntersectionObserverController { enter: (target: Element) => void; isObserved: (target: Element) => boolean; } function installIntersectionObserverMock(): MockIntersectionObserverController { const observed = new Map< Element, { callback: IntersectionObserverCallback; observer: IntersectionObserver; } >(); class MockIntersectionObserver implements IntersectionObserver { readonly root = null; readonly rootMargin: string; readonly thresholds = [0]; private readonly targets = new Set(); constructor( private readonly callback: IntersectionObserverCallback, options: IntersectionObserverInit = {}, ) { this.rootMargin = options.rootMargin ?? '0px'; } observe(target: Element) { this.targets.add(target); observed.set(target, { callback: this.callback, observer: this as unknown as IntersectionObserver, }); } unobserve(target: Element) { this.targets.delete(target); observed.delete(target); } disconnect() { this.targets.forEach((target) => observed.delete(target)); this.targets.clear(); } takeRecords() { return []; } } vi.stubGlobal('IntersectionObserver', MockIntersectionObserver); return { enter(target) { const record = observed.get(target); if (!record) { throw new Error('目标缩略图尚未进入 IntersectionObserver'); } act(() => { record.callback( [ { isIntersecting: true, target, } as IntersectionObserverEntry, ], record.observer, ); }); }, isObserved(target) { return observed.has(target); }, }; } vi.mock('../components/AdminUserReferenceButton', () => ({ AdminUserReferenceButton: ({ userId, publicUserCode, }: { userId?: string; publicUserCode?: string | null; }) => (