mirror of
https://github.com/ant-design/ant-design.git
synced 2024-12-23 23:18:36 +08:00
7410b536b4
* feat: Descriptions support row * feat: review * feat: snap * feat: test * feat: review * feat: review * feat: test * feat: test * feat: add calc span * feat: snap * feat: block * feat: test change block * feat: doc * feat: doc * feat: test * feat: empty text test * feat: row > block * feat: remove block * feat: filled * feat: fiiled 逻辑修正 最后一个始终补齐 * feat: doc * feat: review * feat: review * feat: review
419 lines
14 KiB
TypeScript
419 lines
14 KiB
TypeScript
import React from 'react';
|
|
import MockDate from 'mockdate';
|
|
|
|
import Descriptions from '..';
|
|
import { resetWarned } from '../../_util/warning';
|
|
import mountTest from '../../../tests/shared/mountTest';
|
|
import { render } from '../../../tests/utils';
|
|
import ConfigProvider from '../../config-provider';
|
|
|
|
describe('Descriptions', () => {
|
|
mountTest(Descriptions);
|
|
|
|
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
|
|
afterEach(() => {
|
|
MockDate.reset();
|
|
errorSpy.mockReset();
|
|
});
|
|
|
|
afterAll(() => {
|
|
errorSpy.mockRestore();
|
|
});
|
|
|
|
it('when max-width: 575px, column=1', () => {
|
|
const wrapper = render(
|
|
<Descriptions>
|
|
<Descriptions.Item label="Product">Cloud Database</Descriptions.Item>
|
|
<Descriptions.Item label="Billing">Prepaid</Descriptions.Item>
|
|
<Descriptions.Item label="time">18:00:00</Descriptions.Item>
|
|
<Descriptions.Item label="Amount">$80.00</Descriptions.Item>
|
|
<Descriptions.Item>No-Label</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper.container.querySelectorAll('tr')).toHaveLength(5);
|
|
expect(wrapper.container.querySelectorAll('.ant-descriptions-item-label')).toHaveLength(4);
|
|
wrapper.unmount();
|
|
});
|
|
|
|
it('when max-width: 575px, column=2', () => {
|
|
const wrapper = render(
|
|
<Descriptions column={{ xs: 2 }}>
|
|
<Descriptions.Item label="Product">Cloud Database</Descriptions.Item>
|
|
<Descriptions.Item label="Billing">Prepaid</Descriptions.Item>
|
|
<Descriptions.Item label="time">18:00:00</Descriptions.Item>
|
|
<Descriptions.Item label="Amount">$80.00</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper.container.querySelectorAll('tr')).toHaveLength(2);
|
|
wrapper.unmount();
|
|
});
|
|
|
|
it('when max-width: 575px, column=2, span=2', () => {
|
|
const { container } = render(
|
|
<Descriptions
|
|
column={{ xs: 2 }}
|
|
items={[
|
|
{
|
|
label: 'Product',
|
|
children: 'Cloud Database',
|
|
span: { xs: 2 },
|
|
},
|
|
{
|
|
label: 'Billing',
|
|
children: 'Prepaid',
|
|
span: { xs: 1 },
|
|
},
|
|
{
|
|
label: 'Time',
|
|
children: '18:00:00',
|
|
span: { xs: 1 },
|
|
},
|
|
]}
|
|
/>,
|
|
);
|
|
|
|
expect(container.querySelectorAll('.ant-descriptions-item')[0]).toHaveAttribute('colSpan', '2');
|
|
expect(container.querySelectorAll('.ant-descriptions-item')[1]).toHaveAttribute('colSpan', '1');
|
|
expect(container.querySelectorAll('.ant-descriptions-item')[2]).toHaveAttribute('colSpan', '1');
|
|
});
|
|
|
|
it('span = filled', () => {
|
|
const { container } = render(
|
|
<Descriptions
|
|
column={3}
|
|
items={[
|
|
{ label: '0', children: '', span: 2 },
|
|
{ label: '1', children: '' },
|
|
{ label: '2', children: '' },
|
|
{ label: '3', children: '', span: 'filled' },
|
|
{ label: '4', children: '', span: 'filled' },
|
|
{ label: '5', children: '' },
|
|
{ label: '6', children: '', span: 1 },
|
|
]}
|
|
/>,
|
|
);
|
|
expect(container.querySelectorAll('.ant-descriptions-item')[0]).toHaveAttribute('colSpan', '2');
|
|
expect(container.querySelectorAll('.ant-descriptions-item')[1]).toHaveAttribute('colSpan', '1');
|
|
expect(container.querySelectorAll('.ant-descriptions-item')[2]).toHaveAttribute('colSpan', '1');
|
|
expect(container.querySelectorAll('.ant-descriptions-item')[3]).toHaveAttribute('colSpan', '2');
|
|
expect(container.querySelectorAll('.ant-descriptions-item')[4]).toHaveAttribute('colSpan', '3');
|
|
expect(container.querySelectorAll('.ant-descriptions-item')[5]).toHaveAttribute('colSpan', '1');
|
|
expect(container.querySelectorAll('.ant-descriptions-item')[6]).toHaveAttribute('colSpan', '2');
|
|
});
|
|
|
|
it('column is number', () => {
|
|
const wrapper = render(
|
|
<Descriptions column={3}>
|
|
<Descriptions.Item label="Product">Cloud Database</Descriptions.Item>
|
|
<Descriptions.Item label="Billing">Prepaid</Descriptions.Item>
|
|
<Descriptions.Item label="time">18:00:00</Descriptions.Item>
|
|
<Descriptions.Item label="Amount">$80.00</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper.container.firstChild).toMatchSnapshot();
|
|
wrapper.unmount();
|
|
});
|
|
|
|
it('when typeof column is object', () => {
|
|
const wrapper = render(
|
|
<Descriptions column={{ xs: 8, sm: 16, md: 24 }}>
|
|
<Descriptions.Item label="Product">Cloud Database</Descriptions.Item>
|
|
<Descriptions.Item label="Billing">Prepaid</Descriptions.Item>
|
|
<Descriptions.Item label="time">18:00:00</Descriptions.Item>
|
|
<Descriptions.Item label="Amount">$80.00</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(
|
|
Array.from(wrapper.container.querySelectorAll('td'))
|
|
.map((i) => Number(i.getAttribute('colspan')))
|
|
.filter(Boolean)
|
|
.reduce((total, cur) => total + cur, 0),
|
|
).toBe(8);
|
|
wrapper.unmount();
|
|
});
|
|
|
|
it('warning if exceed the row span', () => {
|
|
resetWarned();
|
|
|
|
render(
|
|
<Descriptions column={3}>
|
|
<Descriptions.Item label="Product" span={2}>
|
|
Cloud Database
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="Billing" span={2}>
|
|
Prepaid
|
|
</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(errorSpy).toHaveBeenCalledWith(
|
|
'Warning: [antd: Descriptions] Sum of column `span` in a line not match `column` of Descriptions.',
|
|
);
|
|
});
|
|
|
|
it('when item is rendered conditionally', () => {
|
|
const hasDiscount = false;
|
|
const wrapper = render(
|
|
<Descriptions>
|
|
<Descriptions.Item label="Product">Cloud Database</Descriptions.Item>
|
|
<Descriptions.Item label="Billing">Prepaid</Descriptions.Item>
|
|
<Descriptions.Item label="time">18:00:00</Descriptions.Item>
|
|
<Descriptions.Item label="Amount">$80.00</Descriptions.Item>
|
|
{hasDiscount && <Descriptions.Item label="Discount">$20.00</Descriptions.Item>}
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper.container.firstChild).toMatchSnapshot();
|
|
wrapper.unmount();
|
|
});
|
|
|
|
it('vertical layout', () => {
|
|
const wrapper = render(
|
|
<Descriptions layout="vertical">
|
|
<Descriptions.Item label="Product">Cloud Database</Descriptions.Item>
|
|
<Descriptions.Item label="Billing">Prepaid</Descriptions.Item>
|
|
<Descriptions.Item label="time">18:00:00</Descriptions.Item>
|
|
<Descriptions.Item label="Amount">$80.00</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper.container.firstChild).toMatchSnapshot();
|
|
wrapper.unmount();
|
|
});
|
|
|
|
it('Descriptions.Item support className', () => {
|
|
const wrapper = render(
|
|
<Descriptions>
|
|
<Descriptions.Item label="Product" className="my-class">
|
|
Cloud Database
|
|
</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper.container.firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('Descriptions support colon', () => {
|
|
const wrapper = render(
|
|
<Descriptions colon={false}>
|
|
<Descriptions.Item label="Product">Cloud Database</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper.container.firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('Descriptions support style', () => {
|
|
const wrapper = render(
|
|
<Descriptions style={{ backgroundColor: '#e8e8e8' }}>
|
|
<Descriptions.Item>Cloud Database</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper.container.firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('Descriptions support id', () => {
|
|
const wrapper = render(
|
|
<Descriptions id="descriptions">
|
|
<Descriptions.Item>Cloud Database</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
const descriptionItemsElement = wrapper.container.querySelector('#descriptions');
|
|
expect(descriptionItemsElement).not.toBeNull();
|
|
});
|
|
|
|
it('keep key', () => {
|
|
render(
|
|
<Descriptions>
|
|
<Descriptions.Item key="bamboo">1</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(jest.spyOn(document, 'createElement')).not.toHaveBeenCalled();
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/19887
|
|
it('should work with React Fragment', () => {
|
|
if (!React.Fragment) {
|
|
return;
|
|
}
|
|
const wrapper = render(
|
|
<Descriptions>
|
|
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
|
<>
|
|
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
|
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
|
</>
|
|
</Descriptions>,
|
|
);
|
|
|
|
expect(wrapper.container.firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/20255
|
|
it('columns 5 with customize', () => {
|
|
const wrapper = render(
|
|
<Descriptions layout="vertical" column={4}>
|
|
{/* 1 1 1 1 */}
|
|
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
|
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
|
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
|
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
|
{/* 2 2 */}
|
|
<Descriptions.Item label="bamboo" span={2}>
|
|
bamboo
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="bamboo" span={2}>
|
|
bamboo
|
|
</Descriptions.Item>
|
|
{/* 3 1 */}
|
|
<Descriptions.Item label="bamboo" span={3}>
|
|
bamboo
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
|
|
function matchSpan(rowIndex: number, spans: number[]) {
|
|
const trs = Array.from(wrapper.container.querySelectorAll('tr')).at(rowIndex);
|
|
const tds = Array.from(trs?.querySelectorAll('th')!);
|
|
expect(tds).toHaveLength(spans.length);
|
|
tds.forEach((td, index) => {
|
|
expect(Number(td.getAttribute('colSpan'))).toEqual(spans[index]);
|
|
});
|
|
}
|
|
|
|
matchSpan(0, [1, 1, 1, 1]);
|
|
matchSpan(2, [2, 2]);
|
|
matchSpan(4, [3, 1]);
|
|
});
|
|
|
|
it('number value should render correct', () => {
|
|
const wrapper = render(
|
|
<Descriptions bordered>
|
|
<Descriptions.Item label={0}>0</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper.container.querySelector('th')).toHaveClass('ant-descriptions-item-label');
|
|
expect(wrapper.container.querySelector('td')).toHaveClass('ant-descriptions-item-content');
|
|
});
|
|
|
|
it('Descriptions support extra', () => {
|
|
const wrapper1 = render(
|
|
<Descriptions extra="Edit">
|
|
<Descriptions.Item label="UserName">Zhou Maomao</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
const wrapper2 = render(
|
|
<Descriptions>
|
|
<Descriptions.Item label="UserName">Zhou Maomao</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper1.container.querySelector('.ant-descriptions-extra')).toBeTruthy();
|
|
expect(wrapper2.container.querySelector('.ant-descriptions-extra')).toBeFalsy();
|
|
});
|
|
|
|
it('number 0 should render correct', () => {
|
|
const wrapper = render(
|
|
<Descriptions>
|
|
<Descriptions.Item label={0} labelStyle={{ color: 'red' }} contentStyle={{ color: 'red' }}>
|
|
{0}
|
|
</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(wrapper.container.firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('should pass data-* and accessibility attributes', () => {
|
|
const { getByTestId } = render(
|
|
<Descriptions data-testid="test-id" data-id="12345" aria-describedby="some-label">
|
|
<Descriptions.Item label="banana">banana</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
const container = getByTestId('test-id');
|
|
expect(container).toHaveAttribute('data-id', '12345');
|
|
expect(container).toHaveAttribute('aria-describedby', 'some-label');
|
|
});
|
|
|
|
it('Descriptions should inherit the size from ConfigProvider if the componentSize is set', () => {
|
|
const { container } = render(
|
|
<ConfigProvider componentSize="small">
|
|
<Descriptions bordered>
|
|
<Descriptions.Item label="small">small</Descriptions.Item>
|
|
</Descriptions>
|
|
</ConfigProvider>,
|
|
);
|
|
expect(container.querySelectorAll('.ant-descriptions-small')).toHaveLength(1);
|
|
});
|
|
|
|
it('should items work', () => {
|
|
const { container } = render(
|
|
<Descriptions
|
|
items={[
|
|
{
|
|
key: '1',
|
|
label: 'UserName',
|
|
children: 'Zhou Maomao',
|
|
},
|
|
{
|
|
key: '2',
|
|
label: 'Telephone',
|
|
children: '1810000000',
|
|
},
|
|
{
|
|
key: '3',
|
|
label: 'Live',
|
|
children: 'Hangzhou, Zhejiang',
|
|
},
|
|
]}
|
|
/>,
|
|
);
|
|
expect(container.querySelector('.ant-descriptions-item')).toBeTruthy();
|
|
expect(container.querySelectorAll('.ant-descriptions-item')).toHaveLength(3);
|
|
expect(container).toMatchSnapshot();
|
|
});
|
|
|
|
it('Descriptions nested within an Item are unaffected by the external borderless style', () => {
|
|
const { container } = render(
|
|
<Descriptions bordered>
|
|
<Descriptions.Item>
|
|
<Descriptions bordered={false} />
|
|
</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
|
|
const nestDesc = container.querySelectorAll('.ant-descriptions')[1];
|
|
const view = nestDesc.querySelector('.ant-descriptions-view');
|
|
expect(getComputedStyle(view!).border).toBeFalsy();
|
|
});
|
|
|
|
it('Should Descriptions not throw react key prop error in jsx mode', () => {
|
|
render(
|
|
<Descriptions title="User Info">
|
|
<Descriptions.Item key="1" label="UserName">
|
|
Zhou Maomao
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="Telephone">1810000000</Descriptions.Item>
|
|
</Descriptions>,
|
|
);
|
|
expect(errorSpy).not.toHaveBeenCalledWith(
|
|
expect.stringContaining('`key` is not a prop'),
|
|
expect.anything(),
|
|
expect.anything(),
|
|
);
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/47151
|
|
it('should has .ant-descriptions-item-content className when children is falsy', () => {
|
|
const wrapper = render(
|
|
<Descriptions
|
|
bordered
|
|
items={[
|
|
{
|
|
key: '1',
|
|
label: null,
|
|
children: null,
|
|
},
|
|
]}
|
|
/>,
|
|
);
|
|
expect(wrapper.container.querySelectorAll('.ant-descriptions-item-label')).toHaveLength(1);
|
|
expect(wrapper.container.querySelectorAll('.ant-descriptions-item-content')).toHaveLength(1);
|
|
});
|
|
});
|