213 lines
6.7 KiB
TypeScript
213 lines
6.7 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import React, { act } from 'react';
|
|
import { createRoot, type Root } from 'react-dom/client';
|
|
import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
|
|
import { ListView } from '../../src/prototypes/vehicle-management/components/ListView';
|
|
import { EMPTY_FILTERS, type VehicleRecord } from '../../src/prototypes/vehicle-management/types';
|
|
|
|
let root: Root | undefined;
|
|
let container: HTMLDivElement | undefined;
|
|
const matchMediaMock = vi.fn();
|
|
|
|
function setMobileViewport(matches: boolean) {
|
|
matchMediaMock.mockReturnValue({
|
|
matches,
|
|
addEventListener: vi.fn(),
|
|
removeEventListener: vi.fn(),
|
|
});
|
|
}
|
|
|
|
function buttonsByAccessibleName(scope: ParentNode, name: string): HTMLButtonElement[] {
|
|
return Array.from(scope.querySelectorAll<HTMLButtonElement>('button')).filter((button) => {
|
|
const accessibleName = button.getAttribute('aria-label') ?? button.textContent?.trim();
|
|
return accessibleName === name;
|
|
});
|
|
}
|
|
|
|
beforeAll(() => {
|
|
(
|
|
globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }
|
|
).IS_REACT_ACT_ENVIRONMENT = true;
|
|
window.matchMedia = matchMediaMock;
|
|
setMobileViewport(false);
|
|
});
|
|
|
|
afterEach(() => {
|
|
if (root) act(() => root?.unmount());
|
|
container?.remove();
|
|
document.querySelectorAll('.vm-op-dropdown').forEach((menu) => menu.remove());
|
|
root = undefined;
|
|
container = undefined;
|
|
});
|
|
|
|
describe('vehicle ListView operation column', () => {
|
|
it('keeps vehicle edit inside more and dispatches the selected row', async () => {
|
|
setMobileViewport(false);
|
|
const row = {
|
|
id: 'vehicle-1',
|
|
plateNo: '沪A12345',
|
|
vin: 'VIN123',
|
|
brand: '测试品牌',
|
|
model: '测试车型',
|
|
} as VehicleRecord;
|
|
const onOpenDetail = vi.fn();
|
|
const onEdit = vi.fn();
|
|
const onOps = vi.fn();
|
|
|
|
container = document.createElement('div');
|
|
document.body.appendChild(container);
|
|
root = createRoot(container);
|
|
await act(async () => {
|
|
root?.render(
|
|
<ListView
|
|
records={[row]}
|
|
kpiCounts={{
|
|
all: 1,
|
|
lease: 0,
|
|
logistics: 0,
|
|
stock: 0,
|
|
nonOperating: 0,
|
|
exit: 0,
|
|
licenseAbnormal: 0,
|
|
insuranceAbnormal: 0,
|
|
}}
|
|
kpiTab="all"
|
|
onKpiChange={vi.fn()}
|
|
pendingFilters={EMPTY_FILTERS}
|
|
appliedFilters={EMPTY_FILTERS}
|
|
onPendingChange={vi.fn()}
|
|
onSearch={vi.fn()}
|
|
onReset={vi.fn()}
|
|
filtered={[row]}
|
|
insuranceMap={new Map()}
|
|
onOpenDetail={onOpenDetail}
|
|
onExport={vi.fn()}
|
|
onImportOpen={vi.fn()}
|
|
onOps={onOps}
|
|
onOperateCity={vi.fn()}
|
|
onMap={vi.fn()}
|
|
onEdit={onEdit}
|
|
onToast={vi.fn()}
|
|
page={1}
|
|
pageSize={10}
|
|
onPageChange={vi.fn()}
|
|
onPageSizeChange={vi.fn()}
|
|
/>,
|
|
);
|
|
});
|
|
|
|
const view = container.querySelector<HTMLButtonElement>('[aria-label="查看"]');
|
|
const edit = container.querySelector<HTMLButtonElement>('[aria-label="编辑"]');
|
|
const more = container.querySelector<HTMLButtonElement>('[aria-label="更多操作"]');
|
|
expect(view).not.toBeNull();
|
|
expect(edit).toBeNull();
|
|
expect(more).not.toBeNull();
|
|
|
|
await act(async () => {
|
|
view?.click();
|
|
more?.click();
|
|
});
|
|
const menuEdit = Array.from(
|
|
document.body.querySelectorAll<HTMLButtonElement>('.vm-op-dropdown button'),
|
|
).find((button) => button.textContent?.trim() === '编辑');
|
|
expect(menuEdit).not.toBeNull();
|
|
await act(async () => menuEdit?.click());
|
|
|
|
await act(async () => more?.click());
|
|
const owner = Array.from(
|
|
document.body.querySelectorAll<HTMLButtonElement>('.vm-op-dropdown button'),
|
|
).find((button) => button.textContent?.includes('设置运维负责人'));
|
|
expect(owner).not.toBeNull();
|
|
await act(async () => owner?.click());
|
|
|
|
expect(onOpenDetail).toHaveBeenCalledWith(row);
|
|
expect(onEdit).toHaveBeenCalledWith(row);
|
|
expect(onOps).toHaveBeenCalledWith(row);
|
|
});
|
|
|
|
it('renders one mobile action set and dispatches the mobile row', async () => {
|
|
setMobileViewport(true);
|
|
const mobileRow = {
|
|
id: 'vehicle-mobile-1',
|
|
plateNo: '沪B54321',
|
|
vin: 'VIN-MOBILE',
|
|
brand: '移动品牌',
|
|
model: '移动车型',
|
|
} as VehicleRecord;
|
|
const onOpenDetail = vi.fn();
|
|
const onEdit = vi.fn();
|
|
const onOps = vi.fn();
|
|
|
|
container = document.createElement('div');
|
|
document.body.appendChild(container);
|
|
root = createRoot(container);
|
|
await act(async () => {
|
|
root?.render(
|
|
<ListView
|
|
records={[mobileRow]}
|
|
kpiCounts={{
|
|
all: 1,
|
|
lease: 0,
|
|
logistics: 0,
|
|
stock: 0,
|
|
nonOperating: 0,
|
|
exit: 0,
|
|
licenseAbnormal: 0,
|
|
insuranceAbnormal: 0,
|
|
}}
|
|
kpiTab="all"
|
|
onKpiChange={vi.fn()}
|
|
pendingFilters={EMPTY_FILTERS}
|
|
appliedFilters={EMPTY_FILTERS}
|
|
onPendingChange={vi.fn()}
|
|
onSearch={vi.fn()}
|
|
onReset={vi.fn()}
|
|
filtered={[mobileRow]}
|
|
insuranceMap={new Map()}
|
|
onOpenDetail={onOpenDetail}
|
|
onExport={vi.fn()}
|
|
onImportOpen={vi.fn()}
|
|
onOps={onOps}
|
|
onOperateCity={vi.fn()}
|
|
onMap={vi.fn()}
|
|
onEdit={onEdit}
|
|
onToast={vi.fn()}
|
|
page={1}
|
|
pageSize={10}
|
|
onPageChange={vi.fn()}
|
|
onPageSizeChange={vi.fn()}
|
|
/>,
|
|
);
|
|
});
|
|
|
|
const viewButtons = buttonsByAccessibleName(container, '查看');
|
|
const editButtons = buttonsByAccessibleName(container, '编辑');
|
|
const moreButtons = buttonsByAccessibleName(container, '更多操作');
|
|
expect(viewButtons).toHaveLength(1);
|
|
expect(editButtons).toHaveLength(0);
|
|
expect(moreButtons).toHaveLength(1);
|
|
|
|
await act(async () => {
|
|
viewButtons[0].click();
|
|
moreButtons[0].click();
|
|
});
|
|
|
|
const menuEditButtons = buttonsByAccessibleName(document.body, '编辑');
|
|
expect(menuEditButtons).toHaveLength(1);
|
|
await act(async () => menuEditButtons[0].click());
|
|
|
|
await act(async () => moreButtons[0].click());
|
|
const ownerButtons = buttonsByAccessibleName(document.body, '设置运维负责人');
|
|
expect(ownerButtons).toHaveLength(1);
|
|
await act(async () => ownerButtons[0].click());
|
|
|
|
expect(onOpenDetail).toHaveBeenCalledTimes(1);
|
|
expect(onOpenDetail).toHaveBeenCalledWith(mobileRow);
|
|
expect(onEdit).toHaveBeenCalledTimes(1);
|
|
expect(onEdit).toHaveBeenCalledWith(mobileRow);
|
|
expect(onOps).toHaveBeenCalledTimes(1);
|
|
expect(onOps).toHaveBeenCalledWith(mobileRow);
|
|
});
|
|
});
|