mirror of
https://github.com/ant-design/ant-design.git
synced 2024-12-21 04:48:02 +08:00
1981 lines
58 KiB
TypeScript
1981 lines
58 KiB
TypeScript
import React from 'react';
|
|
|
|
import type { TableProps } from '..';
|
|
import Table from '..';
|
|
import { resetWarned } from '../../_util/warning';
|
|
import { act, fireEvent, render } from '../../../tests/utils';
|
|
import ConfigProvider from '../../config-provider';
|
|
import type { TableRowSelection } from '../interface';
|
|
|
|
describe('Table.rowSelection', () => {
|
|
window.requestAnimationFrame = (callback) => window.setTimeout(callback, 16);
|
|
window.cancelAnimationFrame = window.clearTimeout;
|
|
|
|
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
|
|
afterEach(() => {
|
|
errorSpy.mockReset();
|
|
});
|
|
|
|
afterAll(() => {
|
|
errorSpy.mockRestore();
|
|
});
|
|
|
|
const columns: TableProps['columns'] = [
|
|
{
|
|
title: 'Name',
|
|
dataIndex: 'name',
|
|
},
|
|
];
|
|
|
|
const data = [
|
|
{ key: 0, name: 'Jack' },
|
|
{ key: 1, name: 'Lucy' },
|
|
{ key: 2, name: 'Tom' },
|
|
{ key: 3, name: 'Jerry' },
|
|
];
|
|
|
|
function createTable(props: TableProps<any> = {}) {
|
|
return <Table columns={columns} dataSource={data} rowSelection={{}} {...props} />;
|
|
}
|
|
|
|
function renderedNames(container: ReturnType<typeof render>['container']) {
|
|
const namesList: Node['textContent'][] = [];
|
|
container
|
|
?.querySelector('.ant-table-tbody')
|
|
?.querySelectorAll<HTMLTableRowElement>('tr')
|
|
?.forEach((tr) => {
|
|
namesList.push(tr?.querySelectorAll<HTMLTableCellElement>('td')?.[1]?.textContent);
|
|
});
|
|
return namesList;
|
|
}
|
|
|
|
const getSelections = (container: HTMLElement) => {
|
|
const keys: React.Key[] = [];
|
|
container.querySelectorAll<HTMLTableRowElement>('.ant-table-tbody tr').forEach((row) => {
|
|
const key = row.getAttribute('data-row-key');
|
|
if (key && row.querySelector<HTMLInputElement>('input')?.checked) {
|
|
if (Number.isNaN(Number(key))) {
|
|
// rowKey
|
|
keys.push(key);
|
|
} else {
|
|
keys.push(Number(key));
|
|
}
|
|
}
|
|
});
|
|
return keys;
|
|
};
|
|
|
|
const getIndeterminateSelection = (container: HTMLElement) => {
|
|
const keys: React.Key[] = [];
|
|
container.querySelectorAll<HTMLTableRowElement>('.ant-table-tbody tr').forEach((row) => {
|
|
const key = row.getAttribute('data-row-key');
|
|
if (key && row.querySelector<HTMLElement>('.ant-checkbox-indeterminate')) {
|
|
if (Number.isNaN(Number(key))) {
|
|
// rowKey
|
|
keys.push(key);
|
|
} else {
|
|
keys.push(Number(key));
|
|
}
|
|
}
|
|
});
|
|
return keys;
|
|
};
|
|
|
|
it('select default row', () => {
|
|
const { container } = render(createTable({ rowSelection: { defaultSelectedRowKeys: [0] } }));
|
|
const checkboxes = container.querySelectorAll<HTMLInputElement>('input[type="checkbox"]');
|
|
expect(getSelections(container)).toEqual([0]);
|
|
|
|
fireEvent.click(checkboxes[1]);
|
|
expect(getSelections(container)).toEqual([]);
|
|
|
|
fireEvent.click(checkboxes[0]);
|
|
expect(getSelections(container)).toEqual([0, 1, 2, 3]);
|
|
|
|
fireEvent.click(checkboxes[0]);
|
|
expect(getSelections(container)).toEqual([]);
|
|
});
|
|
|
|
it('select by checkbox', () => {
|
|
const { container } = render(createTable());
|
|
const checkboxes = container.querySelectorAll('input[type="checkbox"]');
|
|
|
|
fireEvent.click(checkboxes[0]);
|
|
expect(getSelections(container)).toEqual([0, 1, 2, 3]);
|
|
|
|
fireEvent.click(checkboxes[1]);
|
|
expect(getSelections(container)).toEqual([1, 2, 3]);
|
|
|
|
fireEvent.click(checkboxes[1]);
|
|
expect(getSelections(container)).toEqual([0, 1, 2, 3]);
|
|
});
|
|
|
|
it('select by radio', () => {
|
|
const { container } = render(createTable({ rowSelection: { type: 'radio' } }));
|
|
const radios = container.querySelectorAll('input[type="radio"]');
|
|
|
|
expect(radios.length).toBe(4);
|
|
fireEvent.click(radios[0]);
|
|
expect(getSelections(container)).toEqual([0]);
|
|
|
|
fireEvent.click(radios[radios.length - 1]);
|
|
expect(getSelections(container)).toEqual([3]);
|
|
});
|
|
|
|
it('pass getCheckboxProps to checkbox', () => {
|
|
const rowSelection = {
|
|
getCheckboxProps: (record: any) => ({
|
|
disabled: record.name === 'Lucy',
|
|
indeterminate: record.name === 'Tom',
|
|
name: record.name,
|
|
}),
|
|
};
|
|
|
|
const { container } = render(createTable({ rowSelection }));
|
|
const checkboxes = container.querySelectorAll<HTMLInputElement>('input[type="checkbox"]');
|
|
|
|
expect(checkboxes[1].disabled).toBe(false);
|
|
expect(checkboxes[1].name).toEqual(data[0].name);
|
|
expect(checkboxes[2].disabled).toBe(true);
|
|
expect(checkboxes[2].name).toEqual(data[1].name);
|
|
|
|
expect(getIndeterminateSelection(container)).toEqual([2]);
|
|
});
|
|
|
|
it("make getCheckboxProps's `indeterminate` override selectedRowKeys' effect", () => {
|
|
const rowSelection: TableProps<any>['rowSelection'] = {
|
|
getCheckboxProps: (record) => ({
|
|
disabled: record.name === 'Lucy',
|
|
indeterminate: record.name === 'Tom',
|
|
name: record.name,
|
|
}),
|
|
selectedRowKeys: [2],
|
|
};
|
|
|
|
const { container } = render(createTable({ rowSelection }));
|
|
expect(getIndeterminateSelection(container)).toEqual([2]);
|
|
});
|
|
|
|
it('works with pagination', () => {
|
|
const { container } = render(createTable({ pagination: { pageSize: 2 } }));
|
|
|
|
const pagers = container.querySelectorAll('.ant-pagination-item');
|
|
const checkboxAll = container.querySelector<HTMLInputElement>('input[type="checkbox"]');
|
|
|
|
const objectContaining: { checked?: boolean; indeterminate?: boolean } = {};
|
|
fireEvent.click(checkboxAll!);
|
|
objectContaining.checked = checkboxAll?.checked; // true
|
|
objectContaining.indeterminate = getIndeterminateSelection(container).length > 0; // false
|
|
expect.objectContaining(objectContaining);
|
|
|
|
fireEvent.click(pagers[1]);
|
|
objectContaining.checked = checkboxAll?.checked; // false
|
|
objectContaining.indeterminate = getIndeterminateSelection(container).length > 0; // false
|
|
expect.objectContaining(objectContaining);
|
|
|
|
fireEvent.click(pagers[0]);
|
|
objectContaining.checked = checkboxAll?.checked; // true
|
|
objectContaining.indeterminate = getIndeterminateSelection(container).length > 0; // false
|
|
expect.objectContaining(objectContaining);
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/4020
|
|
it('handles defaultChecked', () => {
|
|
resetWarned();
|
|
const rowSelection = {
|
|
getCheckboxProps: (record) => ({
|
|
defaultChecked: record.key === 0,
|
|
}),
|
|
} as TableRowSelection<any>;
|
|
|
|
render(createTable({ rowSelection }));
|
|
|
|
expect(errorSpy).toHaveBeenCalledWith(
|
|
'Warning: [antd: Table] Do not set `checked` or `defaultChecked` in `getCheckboxProps`. Please use `selectedRowKeys` instead.',
|
|
);
|
|
});
|
|
|
|
it('can be controlled', () => {
|
|
const { container, rerender } = render(createTable({ rowSelection: { selectedRowKeys: [0] } }));
|
|
|
|
expect(getSelections(container)).toEqual([0]);
|
|
|
|
rerender(createTable({ rowSelection: { selectedRowKeys: [1] } }));
|
|
|
|
expect(getSelections(container)).toEqual([1]);
|
|
});
|
|
|
|
it('fires change & select events', () => {
|
|
const order: string[] = [];
|
|
const handleChange = jest.fn().mockImplementation(() => {
|
|
order.push('onChange');
|
|
});
|
|
const handleSelect = jest.fn().mockImplementation(() => {
|
|
order.push('onSelect');
|
|
});
|
|
const rowSelection = {
|
|
onChange: handleChange,
|
|
onSelect: handleSelect,
|
|
};
|
|
const { container } = render(createTable({ rowSelection }));
|
|
|
|
fireEvent.click(container.querySelectorAll('input[type="checkbox"]')[4]);
|
|
|
|
expect(handleChange).toHaveBeenCalledWith([3], [{ key: 3, name: 'Jerry' }], {
|
|
type: 'single',
|
|
});
|
|
expect(handleSelect.mock.calls.length).toBe(1);
|
|
expect(handleSelect.mock.calls[0][0]).toEqual({ key: 3, name: 'Jerry' });
|
|
expect(handleSelect.mock.calls[0][1]).toBe(true);
|
|
expect(handleSelect.mock.calls[0][2]).toEqual([{ key: 3, name: 'Jerry' }]);
|
|
expect(handleSelect.mock.calls[0][3].type).toBe('click');
|
|
expect(order).toEqual(['onSelect', 'onChange']);
|
|
});
|
|
|
|
it('fires selectMulti event', () => {
|
|
const order: string[] = [];
|
|
const handleSelectMulti = jest.fn().mockImplementation(() => {
|
|
order.push('onSelectMultiple');
|
|
});
|
|
const handleSelect = jest.fn().mockImplementation(() => {
|
|
order.push('onSelect');
|
|
});
|
|
const handleChange = jest.fn().mockImplementation(() => {
|
|
order.push('onChange');
|
|
});
|
|
const rowSelection = {
|
|
onChange: handleChange,
|
|
onSelect: handleSelect,
|
|
onSelectMultiple: handleSelectMulti,
|
|
};
|
|
const { container } = render(createTable({ rowSelection }));
|
|
fireEvent.click(container.querySelectorAll('tbody input[type="checkbox"]')[0], {
|
|
shiftKey: true,
|
|
});
|
|
|
|
expect(handleSelect).toHaveBeenCalled();
|
|
expect(handleChange).toHaveBeenLastCalledWith([0], [{ key: 0, name: 'Jack' }], {
|
|
type: 'single',
|
|
});
|
|
|
|
fireEvent.click(container.querySelectorAll('tbody input[type="checkbox"]')[2], {
|
|
shiftKey: true,
|
|
});
|
|
|
|
expect(handleSelectMulti).toHaveBeenCalledWith(
|
|
true,
|
|
[data[0], data[1], data[2]],
|
|
[data[1], data[2]],
|
|
);
|
|
expect(handleChange).toHaveBeenLastCalledWith(
|
|
[0, 1, 2],
|
|
[
|
|
{ key: 0, name: 'Jack' },
|
|
{ key: 1, name: 'Lucy' },
|
|
{ key: 2, name: 'Tom' },
|
|
],
|
|
{ type: 'multiple' },
|
|
);
|
|
|
|
fireEvent.click(container.querySelectorAll('tbody input[type="checkbox"]')[0], {
|
|
shiftKey: true,
|
|
});
|
|
expect(handleSelectMulti).toHaveBeenCalledWith(false, [], [data[0], data[1], data[2]]);
|
|
expect(handleChange).toHaveBeenLastCalledWith([], [], { type: 'multiple' });
|
|
|
|
expect(order).toEqual([
|
|
'onSelect',
|
|
'onChange',
|
|
'onSelectMultiple',
|
|
'onChange',
|
|
'onSelectMultiple',
|
|
'onChange',
|
|
]);
|
|
});
|
|
|
|
it('reset last select key after deselect', async () => {
|
|
jest.useFakeTimers();
|
|
const onChange = jest.fn();
|
|
|
|
const { container } = render(
|
|
createTable({
|
|
checkbox: true,
|
|
rowSelection: {
|
|
selections: [Table.SELECTION_NONE],
|
|
onChange: (keys) => onChange(keys),
|
|
},
|
|
} as TableProps<any>),
|
|
);
|
|
|
|
const last = () => {
|
|
const elements = container.querySelectorAll('td input');
|
|
return elements[elements.length - 1];
|
|
};
|
|
|
|
const first = () => {
|
|
const elements = container.querySelectorAll('td input');
|
|
return elements[0];
|
|
};
|
|
|
|
fireEvent.click(first());
|
|
expect(onChange).toHaveBeenLastCalledWith([0]);
|
|
fireEvent.click(last());
|
|
expect(onChange).toHaveBeenLastCalledWith([0, 3]);
|
|
fireEvent.click(last());
|
|
expect(onChange).toHaveBeenLastCalledWith([0]);
|
|
fireEvent.click(last(), {
|
|
shiftKey: true,
|
|
});
|
|
expect(onChange).toHaveBeenLastCalledWith([0, 3]);
|
|
|
|
jest.useRealTimers();
|
|
});
|
|
|
|
it('reset last select key after bulk operations', async () => {
|
|
jest.useFakeTimers();
|
|
const onChange = jest.fn();
|
|
|
|
const { container, baseElement } = render(
|
|
createTable({
|
|
checkbox: true,
|
|
rowSelection: {
|
|
selections: [Table.SELECTION_NONE],
|
|
onChange: (keys) => onChange(keys),
|
|
},
|
|
} as TableProps<any>),
|
|
);
|
|
|
|
const last = () => {
|
|
const elements = container.querySelectorAll('td input');
|
|
return elements[elements.length - 1];
|
|
};
|
|
|
|
const first = () => {
|
|
const elements = container.querySelectorAll('td input');
|
|
return elements[0];
|
|
};
|
|
|
|
const allElement = () => container.querySelector('th input');
|
|
|
|
// Multiple select normal
|
|
fireEvent.click(last());
|
|
expect(onChange).toHaveBeenLastCalledWith([3]);
|
|
fireEvent.click(first(), {
|
|
shiftKey: true,
|
|
});
|
|
expect(onChange).toHaveBeenLastCalledWith([3, 0, 1, 2]);
|
|
fireEvent.click(allElement()!);
|
|
expect(onChange).toHaveBeenLastCalledWith([]);
|
|
|
|
// Reset last select key when select all
|
|
fireEvent.click(last());
|
|
expect(onChange).toHaveBeenLastCalledWith([3]);
|
|
fireEvent.click(allElement()!);
|
|
fireEvent.click(allElement()!);
|
|
expect(onChange).toHaveBeenLastCalledWith([]);
|
|
fireEvent.click(first(), {
|
|
shiftKey: true,
|
|
});
|
|
expect(onChange).toHaveBeenLastCalledWith([0]);
|
|
|
|
// Reset last select key when bulk operations
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
fireEvent.click(baseElement.querySelector('li.ant-dropdown-menu-item')!);
|
|
expect(onChange).toHaveBeenLastCalledWith([]);
|
|
fireEvent.click(first(), {
|
|
shiftKey: true,
|
|
});
|
|
expect(onChange).toHaveBeenLastCalledWith([0]);
|
|
|
|
jest.useRealTimers();
|
|
});
|
|
|
|
it('fires selectAll event', () => {
|
|
const order: string[] = [];
|
|
const handleSelectAll = jest.fn().mockImplementation(() => {
|
|
order.push('onSelectAll');
|
|
});
|
|
const handleChange = jest.fn().mockImplementation(() => {
|
|
order.push('onChange');
|
|
});
|
|
const rowSelection = {
|
|
onChange: handleChange,
|
|
onSelectAll: handleSelectAll,
|
|
};
|
|
const { container } = render(createTable({ rowSelection }));
|
|
|
|
const checkAll = container.querySelector('input[type="checkbox"]');
|
|
|
|
fireEvent.click(checkAll!);
|
|
expect(handleSelectAll).toHaveBeenCalledWith(true, data, data);
|
|
|
|
expect(order).toEqual(['onSelectAll', 'onChange']);
|
|
|
|
fireEvent.click(checkAll!);
|
|
expect(handleSelectAll).toHaveBeenCalledWith(false, [], data);
|
|
});
|
|
|
|
it('works with selectAll option inside selection menu', () => {
|
|
jest.useFakeTimers();
|
|
const handleChange = jest.fn();
|
|
const rowSelection = {
|
|
onChange: handleChange,
|
|
selections: true,
|
|
};
|
|
const { container } = render(createTable({ rowSelection }));
|
|
|
|
// Open
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
fireEvent.click(container.querySelectorAll('.ant-dropdown-menu-item')[0]);
|
|
|
|
expect(handleChange.mock.calls[0][0]).toEqual([0, 1, 2, 3]);
|
|
});
|
|
|
|
it('render with default selection correctly', () => {
|
|
jest.useFakeTimers();
|
|
const rowSelection = {
|
|
selections: true,
|
|
};
|
|
const { container } = render(createTable({ rowSelection }));
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
expect(container.querySelector('.ant-dropdown')).toMatchSnapshot();
|
|
});
|
|
|
|
it('fires selectInvert event', () => {
|
|
jest.useFakeTimers();
|
|
|
|
const order: string[] = [];
|
|
const handleSelectInvert = jest.fn().mockImplementation(() => {
|
|
order.push('onSelectInvert');
|
|
});
|
|
const handleChange = jest.fn().mockImplementation(() => {
|
|
order.push('onChange');
|
|
});
|
|
const rowSelection = {
|
|
onChange: handleChange,
|
|
onSelectInvert: handleSelectInvert,
|
|
selections: true,
|
|
};
|
|
const { container } = render(createTable({ rowSelection }));
|
|
|
|
fireEvent.click(container.querySelectorAll('.ant-checkbox')[1]);
|
|
// Open
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
fireEvent.click(container.querySelectorAll('li.ant-dropdown-menu-item')[1]);
|
|
|
|
expect(handleSelectInvert).toHaveBeenCalledWith([1, 2, 3]);
|
|
expect(order).toEqual(['onChange', 'onSelectInvert', 'onChange']);
|
|
|
|
jest.useRealTimers();
|
|
});
|
|
|
|
it('fires selectNone event', () => {
|
|
jest.useFakeTimers();
|
|
const order: string[] = [];
|
|
const handleChange = jest.fn().mockImplementation(() => {
|
|
order.push('onChange');
|
|
});
|
|
const handleSelectNone = jest.fn().mockImplementation(() => {
|
|
order.push('onSelectNone');
|
|
});
|
|
const rowSelection = {
|
|
onChange: handleChange,
|
|
onSelectNone: handleSelectNone,
|
|
selections: true,
|
|
};
|
|
const { container } = render(createTable({ rowSelection }));
|
|
|
|
fireEvent.click(container.querySelectorAll('.ant-checkbox')[1]);
|
|
// Open
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
const dropdownMenuItems = container.querySelectorAll('.ant-dropdown-menu-item');
|
|
fireEvent.click(dropdownMenuItems[dropdownMenuItems.length - 1]);
|
|
|
|
expect(handleSelectNone).toHaveBeenCalled();
|
|
expect(order).toEqual(['onChange', 'onSelectNone', 'onChange']);
|
|
});
|
|
|
|
it('fires selection event', () => {
|
|
jest.useFakeTimers();
|
|
const handleSelectOdd = jest.fn();
|
|
const handleSelectEven = jest.fn();
|
|
const rowSelection = {
|
|
selections: [
|
|
Table.SELECTION_ALL,
|
|
Table.SELECTION_INVERT,
|
|
{
|
|
key: 'odd',
|
|
text: '奇数项',
|
|
onSelect: handleSelectOdd,
|
|
},
|
|
{
|
|
key: 'even',
|
|
text: '偶数项',
|
|
onSelect: handleSelectEven,
|
|
},
|
|
],
|
|
};
|
|
const { container } = render(createTable({ rowSelection }));
|
|
|
|
// Open
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
const dropdownMenuItems = container.querySelectorAll('.ant-dropdown-menu-item');
|
|
|
|
expect(dropdownMenuItems.length).toBe(4);
|
|
|
|
fireEvent.click(dropdownMenuItems[2]);
|
|
expect(handleSelectOdd).toHaveBeenCalledWith([0, 1, 2, 3]);
|
|
|
|
fireEvent.click(dropdownMenuItems[3]);
|
|
expect(handleSelectEven).toHaveBeenCalledWith([0, 1, 2, 3]);
|
|
});
|
|
|
|
describe('preset selection options', () => {
|
|
const presetData = [
|
|
{ key: 0, name: 'Jack' },
|
|
{ key: 1, name: 'Lucy', disabled: true },
|
|
{ key: 2, name: 'Tom' },
|
|
];
|
|
|
|
const getCheckboxProps = (record: any) => record;
|
|
|
|
it('SELECTION_ALL', () => {
|
|
jest.useFakeTimers();
|
|
const onChange = jest.fn();
|
|
const { container } = render(
|
|
createTable({
|
|
dataSource: presetData,
|
|
rowSelection: {
|
|
onChange,
|
|
defaultSelectedRowKeys: [2],
|
|
getCheckboxProps,
|
|
selections: [Table.SELECTION_ALL],
|
|
},
|
|
}),
|
|
);
|
|
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
fireEvent.click(container.querySelector('li.ant-dropdown-menu-item')!);
|
|
expect(onChange).toHaveBeenCalledWith([0, 2], expect.anything(), { type: 'all' });
|
|
});
|
|
|
|
it('SELECTION_INVERT', () => {
|
|
jest.useFakeTimers();
|
|
const onChange = jest.fn();
|
|
const { container } = render(
|
|
createTable({
|
|
dataSource: presetData,
|
|
rowSelection: {
|
|
onChange,
|
|
defaultSelectedRowKeys: [2],
|
|
getCheckboxProps,
|
|
selections: [Table.SELECTION_INVERT],
|
|
},
|
|
}),
|
|
);
|
|
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
fireEvent.click(container.querySelector('li.ant-dropdown-menu-item')!);
|
|
|
|
expect(onChange).toHaveBeenCalledWith([0], expect.anything(), { type: 'invert' });
|
|
});
|
|
|
|
it('SELECTION_NONE', () => {
|
|
jest.useFakeTimers();
|
|
const onChange = jest.fn();
|
|
const { container } = render(
|
|
createTable({
|
|
dataSource: presetData,
|
|
rowSelection: {
|
|
onChange,
|
|
defaultSelectedRowKeys: [1, 2],
|
|
getCheckboxProps,
|
|
selections: [Table.SELECTION_NONE],
|
|
},
|
|
}),
|
|
);
|
|
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
fireEvent.click(container.querySelector('li.ant-dropdown-menu-item')!);
|
|
|
|
expect(onChange).toHaveBeenCalledWith([1], expect.anything(), { type: 'none' });
|
|
});
|
|
});
|
|
|
|
it('could hide selectAll checkbox and custom selection', () => {
|
|
const rowSelection = {
|
|
hideSelectAll: true,
|
|
};
|
|
const { container } = render(createTable({ rowSelection }));
|
|
expect(container.querySelector('.ant-selection')).toBeFalsy();
|
|
});
|
|
|
|
it('handle custom selection onSelect correctly when hide default selection options', () => {
|
|
jest.useFakeTimers();
|
|
const handleSelectOdd = jest.fn();
|
|
const handleSelectEven = jest.fn();
|
|
const rowSelection = {
|
|
selections: [
|
|
{
|
|
key: 'odd',
|
|
text: '奇数项',
|
|
onSelect: handleSelectOdd,
|
|
},
|
|
{
|
|
key: 'even',
|
|
text: '偶数项',
|
|
onSelect: handleSelectEven,
|
|
},
|
|
],
|
|
};
|
|
const { container } = render(createTable({ rowSelection }));
|
|
|
|
// Open
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
const dropdownMenuItems = container.querySelectorAll('li.ant-dropdown-menu-item');
|
|
expect(dropdownMenuItems.length).toBe(2);
|
|
|
|
fireEvent.click(dropdownMenuItems[0]);
|
|
expect(handleSelectOdd).toHaveBeenCalledWith([0, 1, 2, 3]);
|
|
|
|
fireEvent.click(dropdownMenuItems[1]);
|
|
expect(handleSelectEven).toHaveBeenCalledWith([0, 1, 2, 3]);
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/4245
|
|
it('handles disabled checkbox correctly when dataSource changes', () => {
|
|
const rowSelection: TableProps<any>['rowSelection'] = {
|
|
getCheckboxProps: (record) => ({ disabled: record.disabled }),
|
|
};
|
|
const { container, rerender } = render(createTable({ rowSelection }));
|
|
const newData = [
|
|
{ key: 0, name: 'Jack', disabled: true },
|
|
{ key: 1, name: 'Lucy', disabled: true },
|
|
];
|
|
|
|
rerender(createTable({ rowSelection, dataSource: newData }));
|
|
container.querySelectorAll('input').forEach((checkbox) => {
|
|
expect(checkbox.disabled).toBe(true);
|
|
});
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/4245
|
|
it('should allow dynamic getCheckboxProps', () => {
|
|
const { container, rerender } = render(
|
|
<Table
|
|
columns={columns}
|
|
dataSource={data}
|
|
rowSelection={{
|
|
getCheckboxProps: (record) => ({ disabled: record.name === 'Jack' }),
|
|
}}
|
|
/>,
|
|
);
|
|
|
|
let checkboxList = container.querySelectorAll('input');
|
|
expect(checkboxList[1]).toHaveAttribute('disabled');
|
|
expect(checkboxList[2]).not.toHaveAttribute('disabled');
|
|
|
|
rerender(
|
|
<Table
|
|
columns={columns}
|
|
dataSource={data}
|
|
rowSelection={{
|
|
getCheckboxProps: (record) => ({ disabled: record.name === 'Lucy' }),
|
|
}}
|
|
/>,
|
|
);
|
|
checkboxList = container.querySelectorAll('input');
|
|
expect(checkboxList[1]).not.toHaveAttribute('disabled');
|
|
expect(checkboxList[2]).toHaveAttribute('disabled');
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/4779
|
|
it('should not switch pagination when select record', () => {
|
|
const newData: Record<'key' | 'name', string>[] = [];
|
|
for (let i = 0; i < 20; i += 1) {
|
|
newData.push({
|
|
key: i.toString(),
|
|
name: i.toString(),
|
|
});
|
|
}
|
|
const { container } = render(
|
|
createTable({
|
|
rowSelection: {},
|
|
dataSource: newData,
|
|
}),
|
|
);
|
|
fireEvent.click(container.querySelectorAll('.ant-pagination-item')[1]); // switch to second page
|
|
fireEvent.click(container.querySelector('.ant-checkbox')!);
|
|
|
|
expect(renderedNames(container)).toEqual([
|
|
'10',
|
|
'11',
|
|
'12',
|
|
'13',
|
|
'14',
|
|
'15',
|
|
'16',
|
|
'17',
|
|
'18',
|
|
'19',
|
|
]);
|
|
});
|
|
|
|
it('highlight selected row', () => {
|
|
const { container } = render(createTable());
|
|
|
|
fireEvent.click(container.querySelectorAll('input')[1]);
|
|
expect(
|
|
container.querySelectorAll('tbody tr')[0].className.includes('ant-table-row-selected'),
|
|
).toBe(true);
|
|
});
|
|
|
|
it('fix selection column on the left', () => {
|
|
const { container } = render(
|
|
createTable({
|
|
rowSelection: { fixed: true },
|
|
scroll: { x: 903 },
|
|
}),
|
|
);
|
|
|
|
expect(container.querySelector('.ant-table-selection-column')).toHaveClass(
|
|
'ant-table-cell-fix-left',
|
|
);
|
|
});
|
|
|
|
it('fix expand on th left when selection column fixed on the left', () => {
|
|
const { container } = render(
|
|
createTable({
|
|
expandable: {
|
|
expandedRowRender() {
|
|
return <div />;
|
|
},
|
|
},
|
|
rowSelection: { fixed: true },
|
|
scroll: { x: 903 },
|
|
}),
|
|
);
|
|
|
|
expect(container.querySelector('.ant-table-selection-column')).toHaveClass(
|
|
'ant-table-cell-fix-left',
|
|
);
|
|
});
|
|
|
|
it('fix selection column on the left when any other column is fixed', () => {
|
|
const { container } = render(
|
|
createTable({
|
|
rowSelection: {},
|
|
columns: [
|
|
{
|
|
title: 'Name',
|
|
dataIndex: 'name',
|
|
fixed: 'left',
|
|
},
|
|
],
|
|
scroll: { x: 903 },
|
|
}),
|
|
);
|
|
|
|
expect(container.querySelector('.ant-table-selection-column')).toHaveClass(
|
|
'ant-table-cell-fix-left',
|
|
);
|
|
});
|
|
|
|
it('use column as selection column when key is `selection-column`', () => {
|
|
const { asFragment } = render(
|
|
createTable({
|
|
rowSelection: {},
|
|
columns: [
|
|
{
|
|
title: 'Name',
|
|
dataIndex: 'name',
|
|
key: 'selection-column',
|
|
},
|
|
],
|
|
}),
|
|
);
|
|
|
|
expect(asFragment().firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/10629
|
|
it('should keep all checked state when remove item from dataSource', () => {
|
|
const { container, rerender } = render(
|
|
<Table
|
|
rowSelection={{
|
|
selectedRowKeys: [0, 1, 2, 3],
|
|
}}
|
|
columns={columns}
|
|
dataSource={data}
|
|
/>,
|
|
);
|
|
const checkboxes = container.querySelectorAll('.ant-checkbox');
|
|
expect(checkboxes.length).toBe(5);
|
|
checkboxes.forEach((checkbox) => {
|
|
expect(checkbox.querySelector('input')?.checked).toBe(true);
|
|
expect(checkbox.className.includes('ant-checkbox-indeterminate')).toBe(false);
|
|
});
|
|
|
|
rerender(
|
|
<Table
|
|
rowSelection={{
|
|
selectedRowKeys: [1, 2, 3],
|
|
}}
|
|
columns={columns}
|
|
dataSource={data.slice(1)}
|
|
/>,
|
|
);
|
|
|
|
expect(container.querySelectorAll('.ant-checkbox').length).toBe(4);
|
|
container.querySelectorAll('.ant-checkbox').forEach((checkbox) => {
|
|
expect(checkbox.querySelector('input')?.checked).toBe(true);
|
|
expect(checkbox.className.includes('ant-checkbox-indeterminate')).toBe(false);
|
|
});
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/11042
|
|
it('add columnTitle for rowSelection', () => {
|
|
const { container, rerender } = render(
|
|
<Table columns={columns} dataSource={data} rowSelection={{ columnTitle: '多选' }} />,
|
|
);
|
|
expect(container.querySelector('thead tr th')?.textContent).toBe('多选');
|
|
rerender(
|
|
<Table
|
|
columns={columns}
|
|
dataSource={data}
|
|
rowSelection={{
|
|
type: 'radio',
|
|
columnTitle: '单选',
|
|
}}
|
|
/>,
|
|
);
|
|
expect(container.querySelector('thead tr th')?.textContent).toBe('单选');
|
|
});
|
|
|
|
it('columnTitle for rowSelection to be renderProps', () => {
|
|
const { container } = render(
|
|
<Table
|
|
columns={columns}
|
|
dataSource={data}
|
|
rowSelection={{
|
|
columnTitle: (originalNode) =>
|
|
React.cloneElement(originalNode as any, {
|
|
'data-testid': 'selection-checkbox',
|
|
children: '多选',
|
|
}),
|
|
}}
|
|
/>,
|
|
);
|
|
|
|
expect(container.querySelector('thead tr th')?.textContent).toBe('多选');
|
|
expect(container.querySelector('thead tr th input')?.getAttribute('data-testid')).toBe(
|
|
'selection-checkbox',
|
|
);
|
|
|
|
fireEvent.click(container.querySelector('thead tr th input')!);
|
|
container.querySelectorAll('.ant-checkbox').forEach((checkbox) => {
|
|
expect(checkbox.querySelector('input')?.checked).toBe(true);
|
|
expect(checkbox.className.includes('ant-checkbox-indeterminate')).toBe(false);
|
|
});
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/11384
|
|
it('should keep item even if in filter', () => {
|
|
const filterColumns: TableProps['columns'] = [
|
|
{
|
|
title: 'Name',
|
|
dataIndex: 'name',
|
|
filters: [
|
|
{
|
|
text: 'Jack',
|
|
value: 'Jack',
|
|
},
|
|
{
|
|
text: 'Lucy',
|
|
value: 'Lucy',
|
|
},
|
|
],
|
|
filterDropdownOpen: true,
|
|
onFilter: (value: any, record: any) => record.name.indexOf(value) === 0,
|
|
},
|
|
];
|
|
|
|
const onChange = jest.fn();
|
|
const rowSelection = {
|
|
onChange,
|
|
};
|
|
|
|
const { container } = render(
|
|
<Table columns={filterColumns} dataSource={data} rowSelection={rowSelection} />,
|
|
);
|
|
|
|
function clickFilter(indexList: number[]) {
|
|
indexList.forEach((index) => {
|
|
// wrapper.find('.ant-dropdown-menu-item .ant-checkbox-wrapper').at(index).simulate('click');
|
|
fireEvent.click(
|
|
container.querySelectorAll('.ant-dropdown-menu-item .ant-checkbox-wrapper')[index],
|
|
);
|
|
});
|
|
// wrapper.find('.ant-table-filter-dropdown-btns .ant-btn-color-primary.ant-btn-variant-solid').simulate('click');
|
|
fireEvent.click(
|
|
container.querySelector(
|
|
'.ant-table-filter-dropdown-btns .ant-btn-color-primary.ant-btn-variant-solid',
|
|
)!,
|
|
);
|
|
}
|
|
|
|
function clickItem() {
|
|
fireEvent.click(
|
|
container.querySelectorAll('tbody .ant-table-selection-column .ant-checkbox-input')[0],
|
|
);
|
|
// wrapper
|
|
// .find('tbody .ant-table-selection-column .ant-checkbox-input')
|
|
// .at(0)
|
|
// .simulate('change', {
|
|
// target: { checked: true },
|
|
// });
|
|
}
|
|
|
|
// Check Jack
|
|
clickFilter([0]);
|
|
expect(container.querySelectorAll('tbody tr').length).toBe(1);
|
|
clickItem();
|
|
expect(onChange.mock.calls[0][0].length).toBe(1);
|
|
expect(onChange.mock.calls[0][1].length).toBe(1);
|
|
|
|
// Check Lucy
|
|
clickFilter([0, 1]);
|
|
expect(container.querySelectorAll('tbody tr').length).toBe(1);
|
|
clickItem();
|
|
expect(onChange.mock.calls[1][0].length).toBe(2);
|
|
expect(onChange.mock.calls[1][1].length).toBe(2);
|
|
});
|
|
|
|
it('render correctly when set childrenColumnName', () => {
|
|
const newData = [
|
|
{
|
|
key: 1,
|
|
name: 'Jack',
|
|
children: [
|
|
{
|
|
key: 11,
|
|
name: 'John Brown',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
key: 2,
|
|
name: 'Lucy',
|
|
children: [
|
|
{
|
|
key: 21,
|
|
name: 'Lucy Brown',
|
|
},
|
|
],
|
|
},
|
|
];
|
|
const { container } = render(
|
|
<Table columns={columns} dataSource={newData} childrenColumnName="test" rowSelection={{}} />,
|
|
);
|
|
const checkboxes = container.querySelectorAll('input');
|
|
const objectContaining: { checked?: boolean; indeterminate?: boolean } = {};
|
|
fireEvent.click(checkboxes[1]);
|
|
objectContaining.checked = checkboxes[0].checked; // false
|
|
objectContaining.indeterminate = getIndeterminateSelection(container).length > 0; // true
|
|
expect.objectContaining(objectContaining);
|
|
|
|
fireEvent.click(checkboxes[2]);
|
|
objectContaining.checked = checkboxes[0].checked; // true
|
|
objectContaining.indeterminate = getIndeterminateSelection(container).length > 0; // false
|
|
expect.objectContaining(objectContaining);
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/16614
|
|
it('should get selectedRows correctly when set childrenColumnName', () => {
|
|
const onChange = jest.fn();
|
|
const newData = [
|
|
{
|
|
key: 1,
|
|
name: 'Jack',
|
|
list: [
|
|
{
|
|
key: 11,
|
|
name: 'John Brown',
|
|
},
|
|
],
|
|
},
|
|
];
|
|
const { container } = render(
|
|
<Table
|
|
columns={columns}
|
|
dataSource={newData}
|
|
childrenColumnName="list"
|
|
rowSelection={{ onChange }}
|
|
expandedRowKeys={[1]}
|
|
/>,
|
|
);
|
|
const checkboxes = container.querySelectorAll('input');
|
|
|
|
fireEvent.click(checkboxes[2]);
|
|
|
|
expect(onChange).toHaveBeenLastCalledWith([11], [newData[0].list[0]], { type: 'single' });
|
|
onChange.mockReset();
|
|
|
|
fireEvent.click(checkboxes[1]);
|
|
const item0 = newData[0];
|
|
expect(onChange).toHaveBeenLastCalledWith([11, 1], [newData[0].list[0], item0], {
|
|
type: 'single',
|
|
});
|
|
});
|
|
|
|
it('clear selection className when remove `rowSelection`', () => {
|
|
const dataSource = [
|
|
{ id: 1, name: 'Hello', age: 10 },
|
|
{ id: 2, name: 'World', age: 30 },
|
|
];
|
|
|
|
const { container, rerender } = render(
|
|
<Table
|
|
columns={columns}
|
|
dataSource={dataSource}
|
|
rowSelection={{}}
|
|
expandedRowRender={() => null}
|
|
rowKey="id"
|
|
/>,
|
|
);
|
|
const checkboxes = container.querySelectorAll('input');
|
|
fireEvent.click(checkboxes[1]);
|
|
|
|
expect(container.querySelectorAll('tr.ant-table-row-selected').length).toBe(1);
|
|
|
|
rerender(
|
|
<Table
|
|
columns={columns}
|
|
dataSource={dataSource}
|
|
rowSelection={null as unknown as TableRowSelection<any>}
|
|
expandedRowRender={() => null}
|
|
rowKey="id"
|
|
/>,
|
|
);
|
|
|
|
expect(container.querySelectorAll('tr.ant-table-row-selected').length).toBe(0);
|
|
});
|
|
|
|
it('select by checkbox to trigger stopPropagation', () => {
|
|
const { container } = render(createTable());
|
|
expect(() => {
|
|
fireEvent.click(container.querySelectorAll('span')[10]);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('all disabled should not make select all checked', () => {
|
|
const { container } = render(
|
|
createTable({
|
|
rowSelection: {
|
|
getCheckboxProps: () => ({ disabled: true }),
|
|
},
|
|
}),
|
|
);
|
|
|
|
expect(
|
|
container.querySelector<HTMLInputElement>('thead .ant-checkbox-input')?.disabled,
|
|
).toBeTruthy();
|
|
expect(
|
|
container.querySelector<HTMLInputElement>('thead .ant-checkbox-input')?.checked,
|
|
).toBeFalsy();
|
|
});
|
|
|
|
it('should make select all checked when each item is checked and disabled', () => {
|
|
const { container } = render(
|
|
createTable({
|
|
rowSelection: {
|
|
selectedRowKeys: [0, 1, 2, 3],
|
|
getCheckboxProps: () => ({
|
|
disabled: true,
|
|
}),
|
|
},
|
|
}),
|
|
);
|
|
|
|
expect(
|
|
container.querySelector<HTMLInputElement>('thead .ant-checkbox-input')?.disabled,
|
|
).toBeTruthy();
|
|
expect(
|
|
container.querySelector<HTMLInputElement>('thead .ant-checkbox-input')?.checked,
|
|
).toBeTruthy();
|
|
});
|
|
|
|
it('should make select all indeterminate when each item is disabled and some item is checked', () => {
|
|
const { container } = render(
|
|
createTable({
|
|
rowSelection: {
|
|
selectedRowKeys: [0],
|
|
getCheckboxProps: () => ({
|
|
disabled: true,
|
|
}),
|
|
},
|
|
}),
|
|
);
|
|
|
|
expect(
|
|
container.querySelector<HTMLInputElement>('thead .ant-checkbox-input')?.disabled,
|
|
).toBeTruthy();
|
|
expect(
|
|
container.querySelector<HTMLInputElement>('thead .ant-checkbox-input')?.checked,
|
|
).toBeFalsy();
|
|
expect(
|
|
container.querySelector('thead .ant-checkbox-indeterminate.ant-checkbox-disabled'),
|
|
).toBeTruthy();
|
|
});
|
|
|
|
it('should make select all checked when each item is checked and some item is disabled', () => {
|
|
const { container } = render(
|
|
createTable({
|
|
rowSelection: {
|
|
selectedRowKeys: [0, 1, 2, 3],
|
|
getCheckboxProps: (record) => ({
|
|
disabled: record.key === 0,
|
|
}),
|
|
},
|
|
}),
|
|
);
|
|
|
|
expect(
|
|
container.querySelector<HTMLInputElement>('thead .ant-checkbox-input')?.disabled,
|
|
).toBeFalsy();
|
|
expect(
|
|
container.querySelector<HTMLInputElement>('thead .ant-checkbox-input')?.checked,
|
|
).toBeTruthy();
|
|
});
|
|
|
|
it('should not make select all checked when some item is checked and disabled', () => {
|
|
const { container } = render(
|
|
createTable({
|
|
rowSelection: {
|
|
selectedRowKeys: [1],
|
|
getCheckboxProps: (record) => ({
|
|
disabled: record.key === 0,
|
|
}),
|
|
},
|
|
}),
|
|
);
|
|
|
|
expect(
|
|
container.querySelector<HTMLInputElement>('thead .ant-checkbox-input')?.disabled,
|
|
).toBeFalsy();
|
|
expect(
|
|
container.querySelector<HTMLInputElement>('thead .ant-checkbox-input')?.checked,
|
|
).toBeFalsy();
|
|
expect(container.querySelector('thead .ant-checkbox-indeterminate')).toBeTruthy();
|
|
});
|
|
|
|
it('should onRowClick not called when checkbox clicked', () => {
|
|
const onRowClick = jest.fn();
|
|
|
|
const { container } = render(
|
|
createTable({
|
|
onRow: () => ({
|
|
onClick: onRowClick,
|
|
}),
|
|
}),
|
|
);
|
|
const checkboxes = container.querySelectorAll('input');
|
|
fireEvent.click(checkboxes[checkboxes.length - 1]);
|
|
|
|
expect(onRowClick).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should support getPopupContainer', () => {
|
|
const rowSelection = {
|
|
selections: true,
|
|
};
|
|
const getPopupContainer = jest.fn((node) => node);
|
|
const { container } = render(
|
|
createTable({
|
|
rowSelection,
|
|
getPopupContainer,
|
|
}),
|
|
);
|
|
jest.useFakeTimers();
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
expect(container.firstChild).toMatchSnapshot();
|
|
expect(getPopupContainer).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should support getPopupContainer from ConfigProvider', () => {
|
|
const rowSelection = {
|
|
selections: true,
|
|
};
|
|
const { container } = render(
|
|
<ConfigProvider getPopupContainer={(node) => node?.parentNode as HTMLElement}>
|
|
{createTable({
|
|
rowSelection,
|
|
})}
|
|
</ConfigProvider>,
|
|
);
|
|
jest.useFakeTimers();
|
|
fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')!);
|
|
act(() => {
|
|
jest.runAllTimers();
|
|
});
|
|
expect(container.firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('Table selection should check', () => {
|
|
const onChange = jest.fn();
|
|
const { container } = render(
|
|
<Table
|
|
dataSource={[{ name: 'light', sub: [{ name: 'bamboo' }] }]}
|
|
expandable={{ expandedRowKeys: ['light'], childrenColumnName: 'sub' }}
|
|
rowSelection={{ onChange }}
|
|
rowKey="name"
|
|
/>,
|
|
);
|
|
|
|
const checkboxes = container.querySelectorAll('input');
|
|
fireEvent.click(checkboxes[checkboxes.length - 1]);
|
|
|
|
expect(onChange.mock.calls[0][1]).toEqual([expect.objectContaining({ name: 'bamboo' })]);
|
|
});
|
|
|
|
it('support onCell', () => {
|
|
const onCell = jest.fn().mockReturnValue({ rowSpan: 4 });
|
|
const { container } = render(
|
|
createTable({
|
|
rowSelection: {
|
|
onCell,
|
|
},
|
|
}),
|
|
);
|
|
expect(onCell).toHaveBeenCalledTimes(8);
|
|
expect(container.querySelectorAll("td[rowspan='4']").length).toBe(4);
|
|
});
|
|
|
|
describe('supports children', () => {
|
|
const dataWithChildren = [
|
|
{ key: 0, name: 'Jack' },
|
|
{ key: 1, name: 'Lucy' },
|
|
{ key: 2, name: 'Tom' },
|
|
{
|
|
key: 3,
|
|
name: 'Jerry',
|
|
children: [
|
|
{
|
|
key: 4,
|
|
name: 'Jerry Jack',
|
|
},
|
|
{
|
|
key: 5,
|
|
name: 'Jerry Lucy',
|
|
},
|
|
{
|
|
key: 6,
|
|
name: 'Jerry Tom',
|
|
children: [
|
|
{
|
|
key: 7,
|
|
name: 'Jerry Tom Jack',
|
|
},
|
|
{
|
|
key: 8,
|
|
name: 'Jerry Tom Lucy',
|
|
},
|
|
{
|
|
key: 9,
|
|
name: 'Jerry Tom Tom',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
];
|
|
describe('supports checkStrictly', () => {
|
|
it('use data entity key', () => {
|
|
const onChange = jest.fn();
|
|
|
|
const table = createTable({
|
|
dataSource: dataWithChildren,
|
|
defaultExpandAllRows: true,
|
|
rowSelection: {
|
|
checkStrictly: false,
|
|
onChange,
|
|
},
|
|
});
|
|
const { container } = render(table);
|
|
const checkboxes = container.querySelectorAll('input');
|
|
|
|
fireEvent.click(checkboxes[4]);
|
|
|
|
expect(getSelections(container)).toEqual([3, 4, 5, 6, 7, 8, 9]);
|
|
expect(getIndeterminateSelection(container)).toEqual([]);
|
|
expect(onChange.mock.calls[0][0]).toEqual([3, 4, 5, 6, 7, 8, 9]);
|
|
|
|
fireEvent.click(checkboxes[7]);
|
|
|
|
expect(getSelections(container)).toEqual([4, 5]);
|
|
expect(getIndeterminateSelection(container)).toEqual([3]);
|
|
expect(onChange.mock.calls[1][0]).toEqual([4, 5]);
|
|
});
|
|
it('use function rowkey', () => {
|
|
const onChange = jest.fn();
|
|
const table = createTable({
|
|
dataSource: dataWithChildren,
|
|
defaultExpandAllRows: true,
|
|
rowSelection: {
|
|
checkStrictly: false,
|
|
onChange,
|
|
},
|
|
rowKey: (entity) => entity.name,
|
|
});
|
|
const { container } = render(table);
|
|
const checkboxes = container.querySelectorAll('input');
|
|
|
|
fireEvent.click(checkboxes[4]);
|
|
expect(getSelections(container)).toEqual([
|
|
'Jerry',
|
|
'Jerry Jack',
|
|
'Jerry Lucy',
|
|
'Jerry Tom',
|
|
'Jerry Tom Jack',
|
|
'Jerry Tom Lucy',
|
|
'Jerry Tom Tom',
|
|
]);
|
|
expect(getIndeterminateSelection(container)).toEqual([]);
|
|
expect(onChange.mock.calls[0][0]).toEqual([
|
|
'Jerry',
|
|
'Jerry Jack',
|
|
'Jerry Lucy',
|
|
'Jerry Tom',
|
|
'Jerry Tom Jack',
|
|
'Jerry Tom Lucy',
|
|
'Jerry Tom Tom',
|
|
]);
|
|
|
|
fireEvent.click(checkboxes[7]);
|
|
expect(getSelections(container)).toEqual(['Jerry Jack', 'Jerry Lucy']);
|
|
expect(getIndeterminateSelection(container)).toEqual(['Jerry']);
|
|
expect(onChange.mock.calls[1][0]).toEqual(['Jerry Jack', 'Jerry Lucy']);
|
|
});
|
|
it('use string rowkey', () => {
|
|
const onChange = jest.fn();
|
|
const table = createTable({
|
|
dataSource: dataWithChildren,
|
|
defaultExpandAllRows: true,
|
|
rowSelection: {
|
|
checkStrictly: false,
|
|
onChange,
|
|
},
|
|
rowKey: 'name',
|
|
});
|
|
const { container } = render(table);
|
|
const checkboxes = container.querySelectorAll('input');
|
|
|
|
fireEvent.click(checkboxes[4]);
|
|
expect(getSelections(container)).toEqual([
|
|
'Jerry',
|
|
'Jerry Jack',
|
|
'Jerry Lucy',
|
|
'Jerry Tom',
|
|
'Jerry Tom Jack',
|
|
'Jerry Tom Lucy',
|
|
'Jerry Tom Tom',
|
|
]);
|
|
expect(getIndeterminateSelection(container)).toEqual([]);
|
|
expect(onChange.mock.calls[0][0]).toEqual([
|
|
'Jerry',
|
|
'Jerry Jack',
|
|
'Jerry Lucy',
|
|
'Jerry Tom',
|
|
'Jerry Tom Jack',
|
|
'Jerry Tom Lucy',
|
|
'Jerry Tom Tom',
|
|
]);
|
|
|
|
fireEvent.click(checkboxes[7]);
|
|
expect(getSelections(container)).toEqual(['Jerry Jack', 'Jerry Lucy']);
|
|
expect(getIndeterminateSelection(container)).toEqual(['Jerry']);
|
|
expect(onChange.mock.calls[1][0]).toEqual(['Jerry Jack', 'Jerry Lucy']);
|
|
});
|
|
it('initialized correctly', () => {
|
|
const table = createTable({
|
|
dataSource: dataWithChildren,
|
|
defaultExpandAllRows: true,
|
|
rowSelection: {
|
|
checkStrictly: false,
|
|
selectedRowKeys: [7, 8, 9],
|
|
},
|
|
rowKey: 'key',
|
|
});
|
|
const { container } = render(table);
|
|
expect(getSelections(container)).toEqual([6, 7, 8, 9]);
|
|
expect(getIndeterminateSelection(container)).toEqual([3]);
|
|
});
|
|
it('works with disabled checkbox', () => {
|
|
const onChange = jest.fn();
|
|
|
|
const table = createTable({
|
|
dataSource: dataWithChildren,
|
|
defaultExpandAllRows: true,
|
|
rowSelection: {
|
|
checkStrictly: false,
|
|
onChange,
|
|
getCheckboxProps(record) {
|
|
return {
|
|
disabled: record.name === 'Jerry Tom',
|
|
};
|
|
},
|
|
},
|
|
});
|
|
const { container } = render(table);
|
|
|
|
const checkboxes = container.querySelectorAll('input');
|
|
|
|
fireEvent.click(checkboxes[10]);
|
|
fireEvent.click(checkboxes[4]);
|
|
|
|
expect(getSelections(container).sort()).toEqual([3, 4, 5, 9]);
|
|
expect(getIndeterminateSelection(container)).toEqual([]);
|
|
expect(Array.from(onChange.mock.calls[1][0]).sort()).toEqual([3, 4, 5, 9]);
|
|
|
|
fireEvent.click(checkboxes[4]);
|
|
expect(getSelections(container)).toEqual([9]);
|
|
expect(getIndeterminateSelection(container)).toEqual([]);
|
|
expect(onChange.mock.calls[2][0]).toEqual([9]);
|
|
});
|
|
it('works with disabled checkbox and function rowkey', () => {
|
|
const onChange = jest.fn();
|
|
|
|
const table = createTable({
|
|
dataSource: dataWithChildren,
|
|
defaultExpandAllRows: true,
|
|
rowSelection: {
|
|
checkStrictly: false,
|
|
onChange,
|
|
getCheckboxProps(record) {
|
|
return {
|
|
disabled: record.name === 'Jerry Tom',
|
|
};
|
|
},
|
|
},
|
|
rowKey: (entity) => entity.name,
|
|
});
|
|
const { container } = render(table);
|
|
const checkboxes = container.querySelectorAll('input');
|
|
|
|
fireEvent.click(checkboxes[10]);
|
|
fireEvent.click(checkboxes[4]);
|
|
expect(getSelections(container)).toEqual([
|
|
'Jerry',
|
|
'Jerry Jack',
|
|
'Jerry Lucy',
|
|
'Jerry Tom Tom',
|
|
]);
|
|
expect(getIndeterminateSelection(container)).toEqual([]);
|
|
expect(Array.from(onChange.mock.calls[1][0]).sort()).toEqual([
|
|
'Jerry',
|
|
'Jerry Jack',
|
|
'Jerry Lucy',
|
|
'Jerry Tom Tom',
|
|
]);
|
|
|
|
fireEvent.click(checkboxes[4]);
|
|
expect(getSelections(container)).toEqual(['Jerry Tom Tom']);
|
|
expect(getIndeterminateSelection(container)).toEqual([]);
|
|
expect(onChange.mock.calls[2][0]).toEqual(['Jerry Tom Tom']);
|
|
});
|
|
it('works with disabled checkbox and string rowkey', () => {
|
|
const onChange = jest.fn();
|
|
|
|
const table = createTable({
|
|
dataSource: dataWithChildren,
|
|
defaultExpandAllRows: true,
|
|
rowSelection: {
|
|
checkStrictly: false,
|
|
onChange,
|
|
getCheckboxProps(record) {
|
|
return {
|
|
disabled: record.name === 'Jerry Tom',
|
|
};
|
|
},
|
|
},
|
|
rowKey: 'name',
|
|
});
|
|
const { container } = render(table);
|
|
const checkboxes = container.querySelectorAll('input');
|
|
|
|
fireEvent.click(checkboxes[10]);
|
|
fireEvent.click(checkboxes[4]);
|
|
expect(getSelections(container)).toEqual([
|
|
'Jerry',
|
|
'Jerry Jack',
|
|
'Jerry Lucy',
|
|
'Jerry Tom Tom',
|
|
]);
|
|
expect(getIndeterminateSelection(container)).toEqual([]);
|
|
expect(Array.from(onChange.mock.calls[1][0]).sort()).toEqual([
|
|
'Jerry',
|
|
'Jerry Jack',
|
|
'Jerry Lucy',
|
|
'Jerry Tom Tom',
|
|
]);
|
|
|
|
fireEvent.click(checkboxes[4]);
|
|
expect(getSelections(container)).toEqual(['Jerry Tom Tom']);
|
|
expect(getIndeterminateSelection(container)).toEqual([]);
|
|
expect(onChange.mock.calls[2][0]).toEqual(['Jerry Tom Tom']);
|
|
});
|
|
|
|
it('should support `childrenColumnName`', () => {
|
|
const onChange = jest.fn();
|
|
|
|
const table = createTable({
|
|
dataSource: [
|
|
{
|
|
key: 0,
|
|
name: 'Jack',
|
|
childList: [
|
|
{ key: 1, name: 'Light' },
|
|
{ key: 2, name: 'Bamboo' },
|
|
],
|
|
},
|
|
],
|
|
expandable: {
|
|
childrenColumnName: 'childList',
|
|
defaultExpandAllRows: true,
|
|
},
|
|
rowSelection: {
|
|
checkStrictly: false,
|
|
onChange,
|
|
},
|
|
});
|
|
const { container } = render(table);
|
|
const checkboxes = container.querySelectorAll('input');
|
|
expect(checkboxes).toHaveLength(1 + 3);
|
|
|
|
fireEvent.click(checkboxes[1]);
|
|
expect(getSelections(container)).toEqual([0, 1, 2]);
|
|
});
|
|
});
|
|
it('warns when set `indeterminate` using `rowSelection.getCheckboxProps` is not allowed with tree structured data.', () => {
|
|
resetWarned();
|
|
render(
|
|
createTable({
|
|
dataSource: dataWithChildren,
|
|
defaultExpandAllRows: true,
|
|
rowSelection: {
|
|
checkStrictly: false,
|
|
getCheckboxProps() {
|
|
return {
|
|
indeterminate: true,
|
|
};
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
expect(errorSpy).toHaveBeenCalledWith(
|
|
'Warning: [antd: Table] set `indeterminate` using `rowSelection.getCheckboxProps` is not allowed with tree structured dataSource.',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('cache with selected keys', () => {
|
|
it('default not cache', () => {
|
|
const onChange = jest.fn();
|
|
const { container, rerender } = render(
|
|
<Table
|
|
dataSource={[{ name: 'light' }, { name: 'bamboo' }]}
|
|
rowSelection={{ onChange }}
|
|
rowKey="name"
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(container.querySelector('tbody input')!);
|
|
expect(onChange).toHaveBeenCalledWith(['light'], [{ name: 'light' }], { type: 'single' });
|
|
rerender(
|
|
<Table dataSource={[{ name: 'bamboo' }]} rowSelection={{ onChange }} rowKey="name" />,
|
|
);
|
|
fireEvent.click(container.querySelector('tbody input')!);
|
|
expect(onChange).toHaveBeenCalledWith(['bamboo'], [{ name: 'bamboo' }], { type: 'single' });
|
|
});
|
|
|
|
it('cache with preserveSelectedRowKeys', () => {
|
|
const onChange = jest.fn();
|
|
const { container, rerender } = render(
|
|
<Table
|
|
dataSource={[{ name: 'light' }, { name: 'bamboo' }]}
|
|
rowSelection={{ onChange, preserveSelectedRowKeys: true }}
|
|
rowKey="name"
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(container.querySelector('tbody input')!);
|
|
expect(onChange).toHaveBeenCalledWith(['light'], [{ name: 'light' }], { type: 'single' });
|
|
|
|
rerender(
|
|
<Table
|
|
dataSource={[{ name: 'bamboo' }]}
|
|
rowSelection={{ onChange, preserveSelectedRowKeys: true }}
|
|
rowKey="name"
|
|
/>,
|
|
);
|
|
fireEvent.click(container.querySelector('tbody input')!);
|
|
expect(onChange).toHaveBeenCalledWith(
|
|
['light', 'bamboo'],
|
|
[{ name: 'light' }, { name: 'bamboo' }],
|
|
{ type: 'single' },
|
|
);
|
|
});
|
|
|
|
it('cache with preserveSelectedRowKeys and checkStrictly false', () => {
|
|
const onChange = jest.fn();
|
|
const { container, rerender } = render(
|
|
<Table
|
|
dataSource={[{ name: 'light' }, { name: 'bamboo' }]}
|
|
rowSelection={{ onChange, preserveSelectedRowKeys: true, checkStrictly: false }}
|
|
rowKey="name"
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(container.querySelector('tbody input')!);
|
|
expect(onChange).toHaveBeenCalledWith(['light'], [{ name: 'light' }], { type: 'single' });
|
|
|
|
rerender(
|
|
<Table
|
|
dataSource={[{ name: 'bamboo' }]}
|
|
rowSelection={{ onChange, preserveSelectedRowKeys: true, checkStrictly: false }}
|
|
rowKey="name"
|
|
/>,
|
|
);
|
|
fireEvent.click(container.querySelector('tbody input')!);
|
|
expect(onChange).toHaveBeenCalledWith(
|
|
['light', 'bamboo'],
|
|
[{ name: 'light' }, { name: 'bamboo' }],
|
|
{ type: 'single' },
|
|
);
|
|
});
|
|
|
|
it('treeData cache with preserveSelectedRowKeys and checkStrictly false', () => {
|
|
const onChange = jest.fn();
|
|
const treeDataColumns = [
|
|
{
|
|
title: 'Name',
|
|
dataIndex: 'name',
|
|
key: 'name',
|
|
},
|
|
];
|
|
const { container, rerender } = render(
|
|
<Table
|
|
expandable={{
|
|
defaultExpandAllRows: true,
|
|
}}
|
|
columns={treeDataColumns}
|
|
dataSource={[
|
|
{
|
|
key: 1,
|
|
name: 'a',
|
|
children: [
|
|
{
|
|
key: 11,
|
|
name: 'b',
|
|
},
|
|
{
|
|
key: 12,
|
|
name: 'c',
|
|
children: [
|
|
{
|
|
key: 121,
|
|
name: 'd',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
key: 2,
|
|
name: 'e',
|
|
},
|
|
]}
|
|
rowSelection={{ onChange, preserveSelectedRowKeys: true, checkStrictly: false }}
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(container.querySelector('th input')!);
|
|
expect(onChange).toHaveBeenCalledWith(
|
|
[1, 11, 12, 121, 2],
|
|
[
|
|
{
|
|
key: 1,
|
|
name: 'a',
|
|
children: [
|
|
{
|
|
key: 11,
|
|
name: 'b',
|
|
},
|
|
{
|
|
key: 12,
|
|
name: 'c',
|
|
children: [
|
|
{
|
|
key: 121,
|
|
name: 'd',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{ key: 11, name: 'b' },
|
|
{ key: 12, name: 'c', children: [{ key: 121, name: 'd' }] },
|
|
{ key: 121, name: 'd' },
|
|
{ key: 2, name: 'e' },
|
|
],
|
|
{ type: 'all' },
|
|
);
|
|
|
|
rerender(
|
|
<Table
|
|
expandable={{
|
|
defaultExpandAllRows: true,
|
|
}}
|
|
columns={treeDataColumns}
|
|
dataSource={[
|
|
{
|
|
key: 1,
|
|
name: 'a',
|
|
children: [
|
|
{
|
|
key: 11,
|
|
name: 'b',
|
|
},
|
|
{
|
|
key: 12,
|
|
name: 'c',
|
|
children: [
|
|
{
|
|
key: 121,
|
|
name: 'd',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
]}
|
|
rowSelection={{ onChange, preserveSelectedRowKeys: true, checkStrictly: false }}
|
|
/>,
|
|
);
|
|
fireEvent.click(container.querySelectorAll('tbody input[type="checkbox"]')[1]);
|
|
expect(onChange).toHaveBeenCalledWith(
|
|
[12, 121, 2],
|
|
[
|
|
{ key: 12, name: 'c', children: [{ key: 121, name: 'd' }] },
|
|
{ key: 121, name: 'd' },
|
|
{ key: 2, name: 'e' },
|
|
],
|
|
{ type: 'single' },
|
|
);
|
|
expect(getIndeterminateSelection(container)).toEqual([1]);
|
|
});
|
|
|
|
it('works with receive selectedRowKeys from [] to undefined', () => {
|
|
const onChange = jest.fn();
|
|
const dataSource = [{ name: 'Jack' }];
|
|
const { container, rerender } = render(
|
|
<Table
|
|
dataSource={dataSource}
|
|
rowSelection={{ onChange, selectedRowKeys: [0] }}
|
|
rowKey="name"
|
|
/>,
|
|
);
|
|
|
|
rerender(
|
|
<Table
|
|
dataSource={dataSource}
|
|
rowSelection={{ onChange, selectedRowKeys: undefined }}
|
|
rowKey="name"
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(container.querySelector('tbody input')!);
|
|
expect(onChange).toHaveBeenCalledWith(['Jack'], [{ name: 'Jack' }], { type: 'single' });
|
|
});
|
|
|
|
it('works with selectionType radio receive selectedRowKeys from [] to undefined', () => {
|
|
const onChange = jest.fn();
|
|
const dataSource = [{ name: 'Jack' }];
|
|
const { container, rerender } = render(
|
|
<Table
|
|
dataSource={dataSource}
|
|
rowSelection={{ onChange, selectedRowKeys: [0], type: 'radio' }}
|
|
rowKey="name"
|
|
/>,
|
|
);
|
|
rerender(
|
|
<Table
|
|
dataSource={dataSource}
|
|
rowSelection={{ onChange, selectedRowKeys: undefined, type: 'radio' }}
|
|
rowKey="name"
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(container.querySelector('tbody input')!);
|
|
expect(onChange).toHaveBeenCalledWith(['Jack'], [{ name: 'Jack' }], { type: 'single' });
|
|
});
|
|
|
|
it('selectedRows ant selectedKeys should keep sync in initial state', () => {
|
|
const dataSource = [{ name: 'Jack' }, { name: 'Tom' }, { name: 'Lucy' }, { name: 'John' }];
|
|
const onChange = jest.fn();
|
|
const rowSelection = {
|
|
preserveSelectedRowKeys: true,
|
|
onChange,
|
|
selectedRowKeys: ['Jack'],
|
|
};
|
|
const { container, rerender } = render(
|
|
<Table
|
|
dataSource={dataSource.slice(0, 2)}
|
|
rowSelection={rowSelection}
|
|
rowKey="name"
|
|
columns={[
|
|
{
|
|
title: 'Name',
|
|
dataIndex: 'name',
|
|
key: 'name',
|
|
},
|
|
]}
|
|
/>,
|
|
);
|
|
|
|
rerender(
|
|
<Table
|
|
dataSource={dataSource.slice(2, 4)}
|
|
rowSelection={rowSelection}
|
|
rowKey="name"
|
|
columns={[{ title: 'Name', dataIndex: 'name', key: 'name' }]}
|
|
/>,
|
|
);
|
|
fireEvent.click(container.querySelector('tbody input')!);
|
|
expect(onChange).toHaveBeenCalledWith(
|
|
['Jack', 'Lucy'],
|
|
[{ name: 'Jack' }, { name: 'Lucy' }],
|
|
{ type: 'single' },
|
|
);
|
|
});
|
|
});
|
|
|
|
it('should trigger both custom and internal checkbox events', () => {
|
|
const onClickMock = jest.fn();
|
|
const onChangeMock = jest.fn();
|
|
|
|
const getCheckboxProps = () => ({
|
|
onClick: onClickMock,
|
|
onChange: onChangeMock,
|
|
});
|
|
|
|
const { container } = render(
|
|
<Table
|
|
rowSelection={{
|
|
type: 'checkbox',
|
|
getCheckboxProps,
|
|
}}
|
|
columns={columns}
|
|
dataSource={data}
|
|
/>,
|
|
);
|
|
|
|
const firstRowCheckbox = container.querySelector('tbody tr:first-child input[type="checkbox"]');
|
|
expect(firstRowCheckbox).toBeTruthy();
|
|
|
|
fireEvent.click(firstRowCheckbox!);
|
|
|
|
expect(onClickMock).toHaveBeenCalled();
|
|
expect(onClickMock.mock.calls.length).toBe(1);
|
|
|
|
expect(onChangeMock).toHaveBeenCalled();
|
|
expect(onChangeMock.mock.calls.length).toBe(1);
|
|
|
|
const changeEvent = onChangeMock.mock.calls[0][0];
|
|
expect(changeEvent).toHaveProperty('target');
|
|
expect(changeEvent.target).toHaveProperty('checked');
|
|
});
|
|
|
|
it('should trigger both custom and internal radio events', () => {
|
|
const onClickMock = jest.fn();
|
|
const onChangeMock = jest.fn();
|
|
|
|
const getCheckboxProps = () => ({
|
|
onClick: onClickMock,
|
|
onChange: onChangeMock,
|
|
});
|
|
|
|
const { container } = render(
|
|
<Table
|
|
rowSelection={{
|
|
type: 'radio',
|
|
getCheckboxProps,
|
|
}}
|
|
columns={columns}
|
|
dataSource={data}
|
|
/>,
|
|
);
|
|
|
|
const firstRowRadio = container.querySelector('tbody tr:first-child input[type="radio"]');
|
|
expect(firstRowRadio).toBeTruthy();
|
|
|
|
fireEvent.click(firstRowRadio!);
|
|
|
|
expect(onClickMock).toHaveBeenCalled();
|
|
expect(onClickMock.mock.calls.length).toBe(1);
|
|
|
|
expect(onChangeMock).toHaveBeenCalled();
|
|
expect(onChangeMock.mock.calls.length).toBe(1);
|
|
|
|
const changeEvent = onChangeMock.mock.calls[0][0];
|
|
expect(changeEvent).toHaveProperty('target');
|
|
expect(changeEvent.target).toHaveProperty('checked');
|
|
});
|
|
});
|