fix: unify analytics and report pagination controls
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { act, render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
@@ -57,7 +57,7 @@ describe('report workbench pages', () => {
|
||||
items: [task('1'), task('2')],
|
||||
total: 2,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 25,
|
||||
});
|
||||
render(
|
||||
<MemoryRouter>
|
||||
@@ -77,6 +77,117 @@ describe('report workbench pages', () => {
|
||||
screen.getAllByRole('checkbox').forEach((checkbox) => expect(checkbox).not.toBeChecked());
|
||||
});
|
||||
|
||||
it('changes detail page size while retaining applied filters and clearing current-page selection', async () => {
|
||||
adminApi.listReportDetailsPage.mockImplementation(async ({ page, pageSize }) => ({
|
||||
items: [task(`${page}-1`), task(`${page}-2`)],
|
||||
total: 258,
|
||||
page,
|
||||
pageSize,
|
||||
}));
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/admin/report-tasks?signatureId=signature-filter&scope=pending']}>
|
||||
<AdminReportTasksPage />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
const user = userEvent.setup();
|
||||
await screen.findByText('签名1-1');
|
||||
expect(adminApi.listReportDetailsPage).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ page: 1, pageSize: 25, signatureId: 'signature-filter', status: 'pending' }),
|
||||
);
|
||||
const sizeControl = screen.getByLabelText(/^每页数量/);
|
||||
expect(sizeControl.closest('.ui-pagination')).not.toBeNull();
|
||||
await user.click(sizeControl);
|
||||
expect(screen.getAllByRole('option').map((option) => option.textContent)).toEqual([
|
||||
'10 条/页',
|
||||
'25 条/页',
|
||||
'50 条/页',
|
||||
'100 条/页',
|
||||
]);
|
||||
await user.click(screen.getByRole('option', { name: '25 条/页' }));
|
||||
await user.type(screen.getByRole('textbox', { name: '企业/应用/通道/报备对象' }), '测试企业');
|
||||
await user.click(screen.getByRole('button', { name: '查询' }));
|
||||
await user.click(screen.getByRole('button', { name: '下一页' }));
|
||||
await screen.findByText('签名2-1');
|
||||
await user.click(screen.getByRole('button', { name: '全选当页' }));
|
||||
expect(screen.getByRole('button', { name: '批量修改状态(2)' })).toBeEnabled();
|
||||
|
||||
await user.click(sizeControl);
|
||||
await user.click(screen.getByRole('option', { name: '100 条/页' }));
|
||||
await screen.findByText('签名1-1');
|
||||
expect(adminApi.listReportDetailsPage).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
keyword: '测试企业',
|
||||
signatureId: 'signature-filter',
|
||||
status: 'pending',
|
||||
}),
|
||||
);
|
||||
expect(screen.getByRole('button', { name: '批量修改状态(0)' })).toBeDisabled();
|
||||
expect(screen.getByRole('spinbutton', { name: '跳转页码' })).toHaveAttribute('max', '3');
|
||||
screen.getAllByRole('checkbox').forEach((checkbox) => expect(checkbox).not.toBeChecked());
|
||||
|
||||
for (const size of [10, 50, 25]) {
|
||||
await user.click(sizeControl);
|
||||
await user.click(screen.getByRole('option', { name: `${size} 条/页` }));
|
||||
await waitFor(() =>
|
||||
expect(adminApi.listReportDetailsPage).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ page: 1, pageSize: size, keyword: '测试企业' }),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps the latest detail page size result when an earlier request finishes last', async () => {
|
||||
const initialPage = { items: [task('old-25')], total: 258, page: 1, pageSize: 25 };
|
||||
const latestPage = { items: [task('new-100')], total: 258, page: 1, pageSize: 100 };
|
||||
let resolveInitial!: (value: typeof initialPage) => void;
|
||||
let resolveLatest!: (value: typeof latestPage) => void;
|
||||
adminApi.listReportDetailsPage
|
||||
.mockImplementationOnce(() => new Promise((resolve) => (resolveInitial = resolve)))
|
||||
.mockImplementationOnce(() => new Promise((resolve) => (resolveLatest = resolve)));
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<AdminReportTasksPage />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
const user = userEvent.setup();
|
||||
await user.click(screen.getByLabelText(/^每页数量/));
|
||||
await user.click(screen.getByRole('option', { name: '100 条/页' }));
|
||||
await waitFor(() => expect(adminApi.listReportDetailsPage).toHaveBeenCalledTimes(2));
|
||||
await act(async () => resolveLatest(latestPage));
|
||||
expect(screen.getByText('签名new-100')).toBeVisible();
|
||||
await act(async () => resolveInitial(initialPage));
|
||||
expect(screen.queryByText('签名old-25')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('签名new-100')).toBeVisible();
|
||||
expect(screen.getByLabelText(/^每页数量/)).toHaveTextContent('100 条/页');
|
||||
});
|
||||
|
||||
it('keeps the current detail request failure visible without replacing it with a stale failure', async () => {
|
||||
let rejectInitial!: (error: Error) => void;
|
||||
let rejectLatest!: (error: Error) => void;
|
||||
adminApi.listReportDetailsPage
|
||||
.mockImplementationOnce(() => new Promise((_resolve, reject) => (rejectInitial = reject)))
|
||||
.mockImplementationOnce(() => new Promise((_resolve, reject) => (rejectLatest = reject)));
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<AdminReportTasksPage />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
const user = userEvent.setup();
|
||||
await user.click(screen.getByLabelText(/^每页数量/));
|
||||
await user.click(screen.getByRole('option', { name: '100 条/页' }));
|
||||
await waitFor(() => expect(adminApi.listReportDetailsPage).toHaveBeenCalledTimes(2));
|
||||
await act(async () => rejectLatest(new Error('当前分页加载失败')));
|
||||
expect(screen.getByText('当前分页加载失败')).toBeVisible();
|
||||
await act(async () => rejectInitial(new Error('已过期的分页请求失败')));
|
||||
expect(screen.getByText('当前分页加载失败')).toBeVisible();
|
||||
expect(screen.queryByText('已过期的分页请求失败')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('uses the shared current-page selection button in the material pool heading', async () => {
|
||||
const material = {
|
||||
id: 'signature:signature-1',
|
||||
|
||||
Reference in New Issue
Block a user