@transferwise/components 0.0.0-experimental-4b8556a → 0.0.0-experimental-3064bdb
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/alert/Alert.js +52 -49
- package/build/alert/Alert.js.map +1 -1
- package/build/alert/Alert.mjs +53 -50
- package/build/alert/Alert.mjs.map +1 -1
- package/build/i18n/en.json +2 -0
- package/build/i18n/en.json.js +2 -0
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +2 -0
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/main.css +214 -0
- package/build/styles/main.css +214 -0
- package/build/styles/table/Table.css +214 -0
- package/build/types/alert/Alert.d.ts +3 -1
- package/build/types/alert/Alert.d.ts.map +1 -1
- package/build/types/table/Table.d.ts +23 -0
- package/build/types/table/Table.d.ts.map +1 -0
- package/build/types/table/Table.messages.d.ts +12 -0
- package/build/types/table/Table.messages.d.ts.map +1 -0
- package/build/types/table/TableCell.d.ts +37 -0
- package/build/types/table/TableCell.d.ts.map +1 -0
- package/build/types/table/TableHeader.d.ts +12 -0
- package/build/types/table/TableHeader.d.ts.map +1 -0
- package/build/types/table/TableRow.d.ts +17 -0
- package/build/types/table/TableRow.d.ts.map +1 -0
- package/build/types/table/TableStatusText.d.ts +9 -0
- package/build/types/table/TableStatusText.d.ts.map +1 -0
- package/build/types/table/index.d.ts +6 -0
- package/build/types/table/index.d.ts.map +1 -0
- package/build/types/uploadInput/UploadInput.d.ts +0 -9
- package/build/types/uploadInput/UploadInput.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts +1 -3
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItemLink.d.ts.map +1 -1
- package/build/uploadInput/UploadInput.js +51 -57
- package/build/uploadInput/UploadInput.js.map +1 -1
- package/build/uploadInput/UploadInput.mjs +51 -57
- package/build/uploadInput/UploadInput.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.js +3 -8
- package/build/uploadInput/uploadItem/UploadItem.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.mjs +3 -8
- package/build/uploadInput/uploadItem/UploadItem.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItemLink.js +0 -1
- package/build/uploadInput/uploadItem/UploadItemLink.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItemLink.mjs +0 -1
- package/build/uploadInput/uploadItem/UploadItemLink.mjs.map +1 -1
- package/package.json +3 -3
- package/src/alert/Alert.spec.tsx +20 -0
- package/src/alert/Alert.story.tsx +50 -2
- package/src/alert/Alert.tsx +57 -50
- package/src/i18n/en.json +2 -0
- package/src/main.css +214 -0
- package/src/main.less +1 -0
- package/src/table/Table.css +214 -0
- package/src/table/Table.less +253 -0
- package/src/table/Table.messages.ts +12 -0
- package/src/table/Table.spec.tsx +87 -0
- package/src/table/Table.story.tsx +352 -0
- package/src/table/Table.tsx +121 -0
- package/src/table/TableCell.spec.tsx +298 -0
- package/src/table/TableCell.tsx +153 -0
- package/src/table/TableHeader.spec.tsx +58 -0
- package/src/table/TableHeader.tsx +50 -0
- package/src/table/TableRow.spec.tsx +104 -0
- package/src/table/TableRow.tsx +62 -0
- package/src/table/TableStatusText.spec.tsx +53 -0
- package/src/table/TableStatusText.tsx +35 -0
- package/src/table/index.ts +11 -0
- package/src/uploadInput/UploadInput.spec.tsx +6 -150
- package/src/uploadInput/UploadInput.tsx +60 -83
- package/src/uploadInput/uploadItem/UploadItem.tsx +6 -12
- package/src/uploadInput/uploadItem/UploadItemLink.tsx +1 -9
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { render, screen, within } from '@testing-library/react';
|
|
2
|
+
import TableRow, { TableRowType, TableRowClickableType } from './TableRow';
|
|
3
|
+
import { IntlProvider } from 'react-intl';
|
|
4
|
+
import { userEvent } from '@testing-library/user-event';
|
|
5
|
+
|
|
6
|
+
describe('TableRow Component', () => {
|
|
7
|
+
const mockData = {
|
|
8
|
+
rowContent: [{ content: { text: 'Cell content 1' } }, { content: { text: 'Cell content 2' } }],
|
|
9
|
+
} satisfies TableRowType;
|
|
10
|
+
|
|
11
|
+
const mockDataClickable = {
|
|
12
|
+
id: 1,
|
|
13
|
+
rowContent: mockData.rowContent,
|
|
14
|
+
} satisfies TableRowClickableType;
|
|
15
|
+
|
|
16
|
+
const handleClick = jest.fn();
|
|
17
|
+
|
|
18
|
+
const renderWithIntl = (component: React.ReactElement) => {
|
|
19
|
+
return render(<IntlProvider locale="en">{component}</IntlProvider>);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
it('renders without crashing', () => {
|
|
23
|
+
renderWithIntl(<TableRow />);
|
|
24
|
+
expect(screen.getByTestId('np-table-row')).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('renders children when data is not provided', () => {
|
|
28
|
+
renderWithIntl(
|
|
29
|
+
<TableRow>
|
|
30
|
+
<td>Cell text</td>
|
|
31
|
+
</TableRow>,
|
|
32
|
+
);
|
|
33
|
+
expect(screen.getByText('Cell text')).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('renders TableCell components when data is provided', () => {
|
|
37
|
+
renderWithIntl(<TableRow rowData={mockData} />);
|
|
38
|
+
expect(screen.getByText('Cell content 1')).toBeInTheDocument();
|
|
39
|
+
expect(screen.getByText('Cell content 2')).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('renders correct number of TableCell components', () => {
|
|
43
|
+
renderWithIntl(<TableRow rowData={mockData} />);
|
|
44
|
+
expect(screen.getAllByRole('cell')).toHaveLength(mockData.rowContent.length);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('renders correct number of TableCell components with chevron when clickable', () => {
|
|
48
|
+
renderWithIntl(<TableRow rowData={mockDataClickable} onRowClick={handleClick} />);
|
|
49
|
+
expect(screen.getAllByRole('cell')).toHaveLength(mockDataClickable.rowContent.length + 1);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('renders a separator row when hasSeparator is passed', () => {
|
|
53
|
+
renderWithIntl(<TableRow rowData={mockData} hasSeparator />);
|
|
54
|
+
expect(screen.getAllByTestId('np-table-row')).toHaveLength(1);
|
|
55
|
+
expect(screen.getAllByTestId('np-table-row--separator')).toHaveLength(1);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('renders correct colSpan for separator row', () => {
|
|
59
|
+
renderWithIntl(<TableRow rowData={mockData} hasSeparator />);
|
|
60
|
+
const separatorCell = within(screen.getByTestId('np-table-row--separator')).getByRole('cell');
|
|
61
|
+
expect(separatorCell).toHaveAttribute('colSpan', mockData.rowContent.length.toString());
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('renders correct colSpan for separator row with clickable row', () => {
|
|
65
|
+
renderWithIntl(<TableRow rowData={mockDataClickable} hasSeparator onRowClick={handleClick} />);
|
|
66
|
+
const separatorCell = within(screen.getByTestId('np-table-row--separator')).getByRole('cell');
|
|
67
|
+
expect(separatorCell).toHaveAttribute(
|
|
68
|
+
'colSpan',
|
|
69
|
+
(mockDataClickable.rowContent.length + 1).toString(),
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('does not render separator row when hasSeparator is false', () => {
|
|
74
|
+
renderWithIntl(<TableRow rowData={mockData} />);
|
|
75
|
+
expect(screen.queryByTestId('np-table-row--separator')).not.toBeInTheDocument();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('does not call onRowClick when row is not clickable', async () => {
|
|
79
|
+
renderWithIntl(<TableRow rowData={mockData} />);
|
|
80
|
+
await userEvent.click(screen.getByTestId('np-table-row'));
|
|
81
|
+
expect(handleClick).not.toHaveBeenCalled();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('applies the np-table-row--clickable class when row is clickable', () => {
|
|
85
|
+
renderWithIntl(<TableRow rowData={mockDataClickable} onRowClick={handleClick} />);
|
|
86
|
+
expect(screen.getAllByTestId('np-table-row')[0]).toHaveClass('np-table-row--clickable');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('calls onRowClick when row is clicked', async () => {
|
|
90
|
+
renderWithIntl(<TableRow rowData={mockDataClickable} onRowClick={handleClick} />);
|
|
91
|
+
await userEvent.click(screen.getByTestId('np-table-row'));
|
|
92
|
+
expect(handleClick).toHaveBeenCalledWith(mockDataClickable);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('renders a chevron icon when row is clickable', () => {
|
|
96
|
+
renderWithIntl(<TableRow rowData={mockDataClickable} onRowClick={handleClick} />);
|
|
97
|
+
expect(screen.getByTestId('chevron-up-icon')).toBeInTheDocument();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('does not render a chevron icon when row is not clickable', () => {
|
|
101
|
+
renderWithIntl(<TableRow rowData={mockData} />);
|
|
102
|
+
expect(screen.queryByTestId('chevron-up-icon')).not.toBeInTheDocument();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import TableCell, { TableCellProps } from './TableCell';
|
|
3
|
+
import Chevron from '../chevron';
|
|
4
|
+
import { Position } from '../common';
|
|
5
|
+
import clsx from 'clsx';
|
|
6
|
+
|
|
7
|
+
export interface TableRowType {
|
|
8
|
+
rowContent?: TableCellProps[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface TableRowClickableType extends TableRowType {
|
|
12
|
+
id: number | string; // `id` is mandatory for clickable rows
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface TableRowProps {
|
|
16
|
+
rowData?: TableRowType | TableRowClickableType;
|
|
17
|
+
hasSeparator?: boolean;
|
|
18
|
+
children?: React.ReactNode;
|
|
19
|
+
onRowClick?: (rowData: TableRowType | TableRowClickableType) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const TableRow = ({ rowData, hasSeparator = false, children, onRowClick }: TableRowProps) => {
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<tr
|
|
26
|
+
className={clsx('np-table-row', { 'np-table-row--clickable': !!onRowClick })}
|
|
27
|
+
data-testid="np-table-row"
|
|
28
|
+
onClick={onRowClick && rowData ? () => onRowClick(rowData) : undefined}
|
|
29
|
+
>
|
|
30
|
+
{rowData?.rowContent
|
|
31
|
+
? rowData?.rowContent?.map((cellItem, index) => {
|
|
32
|
+
return (
|
|
33
|
+
<TableCell
|
|
34
|
+
key={(
|
|
35
|
+
cellItem.content?.text ?? cellItem.content?.primaryText?.toString()
|
|
36
|
+
)?.concat(index.toString())}
|
|
37
|
+
{...cellItem}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
})
|
|
41
|
+
: children}
|
|
42
|
+
{onRowClick && (
|
|
43
|
+
<TableCell>
|
|
44
|
+
<Chevron orientation={Position.RIGHT} />
|
|
45
|
+
</TableCell>
|
|
46
|
+
)}
|
|
47
|
+
</tr>
|
|
48
|
+
{hasSeparator && (
|
|
49
|
+
<tr className="np-table-row np-table-row--separator" data-testid="np-table-row--separator">
|
|
50
|
+
<TableCell
|
|
51
|
+
hasSeparator
|
|
52
|
+
colSpan={
|
|
53
|
+
onRowClick ? Number(rowData?.rowContent?.length) + 1 : rowData?.rowContent?.length
|
|
54
|
+
}
|
|
55
|
+
/>
|
|
56
|
+
</tr>
|
|
57
|
+
)}
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default TableRow;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import TableStatusText, { TableStatusTextProps } from './TableStatusText';
|
|
3
|
+
|
|
4
|
+
describe('TableStatusText Component', () => {
|
|
5
|
+
const renderComponent = (props: Partial<TableStatusTextProps> = {}) => {
|
|
6
|
+
const defaultProps: TableStatusTextProps = {
|
|
7
|
+
text: 'Status Text',
|
|
8
|
+
...props,
|
|
9
|
+
};
|
|
10
|
+
return render(<TableStatusText {...defaultProps} />);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
it('renders the text and applies the default class', () => {
|
|
14
|
+
renderComponent();
|
|
15
|
+
expect(screen.getByText('Status Text')).toBeInTheDocument();
|
|
16
|
+
expect(screen.getByText('Status Text')).toHaveClass('np-text-body-default');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('applies the custom class name', () => {
|
|
20
|
+
renderComponent({ className: 'custom-class' });
|
|
21
|
+
expect(screen.getByText('Status Text')).toHaveClass('custom-class');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('applies the typography class when typography is `large-bold`', () => {
|
|
25
|
+
renderComponent({ typography: 'large-bold' });
|
|
26
|
+
expect(screen.getByText('Status Text')).toHaveClass('np-text-body-large-bold');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('applies the default typography class when typography is not provided', () => {
|
|
30
|
+
renderComponent();
|
|
31
|
+
expect(screen.getByText('Status Text')).toHaveClass('np-text-body-default');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('applies the typography and status classes, renders the error icon when status is error', () => {
|
|
35
|
+
renderComponent({ status: 'error' });
|
|
36
|
+
expect(screen.getByText('Status Text')).toHaveClass('np-text-body-large-bold');
|
|
37
|
+
expect(screen.getByText('Status Text')).toHaveClass('np-table-content--error');
|
|
38
|
+
expect(screen.getByTestId('alert-icon')).toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('does not render any icon when status is not provided', () => {
|
|
42
|
+
renderComponent();
|
|
43
|
+
expect(screen.queryByTestId('check-icon')).not.toBeInTheDocument();
|
|
44
|
+
expect(screen.queryByTestId('alert-icon')).not.toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('applies the typography and status classes, renders the success icon when status is success', () => {
|
|
48
|
+
renderComponent({ status: 'success' });
|
|
49
|
+
expect(screen.getByText('Status Text')).toHaveClass('np-text-body-large-bold');
|
|
50
|
+
expect(screen.getByText('Status Text')).toHaveClass('np-table-content--success');
|
|
51
|
+
expect(screen.getByTestId('check-icon')).toBeInTheDocument();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AlertCircle, CheckCircle } from '@transferwise/icons';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
|
|
4
|
+
export interface TableStatusTextProps {
|
|
5
|
+
text: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
status?: 'success' | 'error';
|
|
8
|
+
typography?: 'default' | 'large-bold';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const TableStatusText: React.FC<TableStatusTextProps> = ({
|
|
12
|
+
text,
|
|
13
|
+
status,
|
|
14
|
+
className,
|
|
15
|
+
typography = 'default',
|
|
16
|
+
}: TableStatusTextProps) => {
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
className={clsx(
|
|
20
|
+
className,
|
|
21
|
+
`np-text-body-${(status ?? typography === 'large-bold') ? 'large-bold' : 'default'}`,
|
|
22
|
+
{
|
|
23
|
+
'np-table-content--success': status === 'success',
|
|
24
|
+
'np-table-content--error': status === 'error',
|
|
25
|
+
},
|
|
26
|
+
)}
|
|
27
|
+
>
|
|
28
|
+
{text}
|
|
29
|
+
{status === 'success' && <CheckCircle className="tw-icon--status" data-testid="check-icon" />}
|
|
30
|
+
{status === 'error' && <AlertCircle className="tw-icon--status" data-testid="alert-icon" />}
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default TableStatusText;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { default } from './Table';
|
|
2
|
+
export type { TableProps } from './Table';
|
|
3
|
+
export type { TableRowType, TableRowClickableType } from './TableRow';
|
|
4
|
+
export type { TableHeaderType } from './TableHeader';
|
|
5
|
+
export type {
|
|
6
|
+
LeadingContentType,
|
|
7
|
+
TextContentType,
|
|
8
|
+
CurrencyContentType,
|
|
9
|
+
StatusContentType,
|
|
10
|
+
TableCellProps,
|
|
11
|
+
} from './TableCell';
|
|
@@ -12,36 +12,6 @@ import { TEST_IDS as UPLOAD_ITEM_TEST_IDS } from './uploadItem/UploadItem';
|
|
|
12
12
|
|
|
13
13
|
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTimeAsync });
|
|
14
14
|
|
|
15
|
-
const deleteFileAndWaitForFocus = async (fileToDeleteTestId: string, nextFocusTestId: string) => {
|
|
16
|
-
const fileToDelete = screen.getByTestId(fileToDeleteTestId);
|
|
17
|
-
const nextFocus = screen.getByTestId(nextFocusTestId);
|
|
18
|
-
|
|
19
|
-
await act(async () => {
|
|
20
|
-
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
21
|
-
await jest.runOnlyPendingTimersAsync();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
await act(async () => {
|
|
25
|
-
const removeButton = screen.queryByText('Remove');
|
|
26
|
-
if (removeButton) {
|
|
27
|
-
removeButton.click();
|
|
28
|
-
await jest.runOnlyPendingTimersAsync();
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
await waitFor(() => {
|
|
33
|
-
expect(screen.queryByTestId(fileToDeleteTestId)).not.toBeInTheDocument();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
await act(async () => {
|
|
37
|
-
await jest.runOnlyPendingTimersAsync();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
await waitFor(() => {
|
|
41
|
-
expect(nextFocus).toHaveFocus();
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
|
|
45
15
|
mockMatchMedia();
|
|
46
16
|
|
|
47
17
|
describe('UploadInput', () => {
|
|
@@ -169,21 +139,15 @@ describe('UploadInput', () => {
|
|
|
169
139
|
onFilesChange,
|
|
170
140
|
});
|
|
171
141
|
|
|
172
|
-
const fileToDelete = screen.
|
|
142
|
+
const fileToDelete = screen.getAllByTestId(UPLOAD_ITEM_TEST_IDS.uploadItem)[0];
|
|
143
|
+
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
173
144
|
await act(async () => {
|
|
174
|
-
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
175
145
|
await jest.runOnlyPendingTimersAsync();
|
|
176
146
|
});
|
|
177
147
|
|
|
178
|
-
|
|
179
|
-
screen.getByText('Remove').click();
|
|
180
|
-
await jest.runOnlyPendingTimersAsync();
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
await waitFor(() => {
|
|
184
|
-
expect(screen.queryByTestId('1-uploadItem')).not.toBeInTheDocument();
|
|
185
|
-
});
|
|
148
|
+
screen.getByText('Remove').click();
|
|
186
149
|
|
|
150
|
+
await waitForElementToBeRemoved(fileToDelete);
|
|
187
151
|
expect(props.onDeleteFile).toHaveBeenCalledWith(files[0].id);
|
|
188
152
|
|
|
189
153
|
expect(onFilesChange).toHaveBeenCalledTimes(2);
|
|
@@ -226,9 +190,9 @@ describe('UploadInput', () => {
|
|
|
226
190
|
onFilesChange,
|
|
227
191
|
});
|
|
228
192
|
|
|
229
|
-
const fileToDelete = screen.
|
|
193
|
+
const fileToDelete = screen.getAllByTestId(UPLOAD_ITEM_TEST_IDS.uploadItem)[0];
|
|
194
|
+
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
230
195
|
await act(async () => {
|
|
231
|
-
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
232
196
|
await jest.runOnlyPendingTimersAsync();
|
|
233
197
|
});
|
|
234
198
|
|
|
@@ -248,114 +212,6 @@ describe('UploadInput', () => {
|
|
|
248
212
|
|
|
249
213
|
expect(screen.queryByLabelText('Remove file ', { exact: false })).not.toBeInTheDocument();
|
|
250
214
|
});
|
|
251
|
-
|
|
252
|
-
it('should focus the next item after a file is deleted', async () => {
|
|
253
|
-
const files = [
|
|
254
|
-
{
|
|
255
|
-
id: 1,
|
|
256
|
-
filename: 'Sales-2024-invoice.pdf',
|
|
257
|
-
status: Status.DONE,
|
|
258
|
-
},
|
|
259
|
-
{
|
|
260
|
-
id: 2,
|
|
261
|
-
filename: 'CoWork-0317-invoice.pdf',
|
|
262
|
-
status: Status.DONE,
|
|
263
|
-
},
|
|
264
|
-
{
|
|
265
|
-
id: 3,
|
|
266
|
-
filename: 'purchase-receipt.pdf',
|
|
267
|
-
status: Status.DONE,
|
|
268
|
-
},
|
|
269
|
-
];
|
|
270
|
-
|
|
271
|
-
renderComponent({
|
|
272
|
-
...props,
|
|
273
|
-
files,
|
|
274
|
-
multiple: true,
|
|
275
|
-
onFilesChange,
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
await deleteFileAndWaitForFocus('1-uploadItem', '2-action');
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
it('should focus the upload input after the last file is deleted', async () => {
|
|
282
|
-
const files = [
|
|
283
|
-
{
|
|
284
|
-
id: 1,
|
|
285
|
-
filename: 'Sales-2024-invoice.pdf',
|
|
286
|
-
status: Status.DONE,
|
|
287
|
-
},
|
|
288
|
-
{
|
|
289
|
-
id: 2,
|
|
290
|
-
filename: 'CoWork-0317-invoice.pdf',
|
|
291
|
-
status: Status.DONE,
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
id: 3,
|
|
295
|
-
filename: 'purchase-receipt.pdf',
|
|
296
|
-
status: Status.DONE,
|
|
297
|
-
},
|
|
298
|
-
];
|
|
299
|
-
|
|
300
|
-
renderComponent({
|
|
301
|
-
...props,
|
|
302
|
-
files,
|
|
303
|
-
multiple: true,
|
|
304
|
-
onFilesChange,
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
await deleteFileAndWaitForFocus('3-uploadItem', 'uploadInput');
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
it('should focus the upload input after the only file is deleted', async () => {
|
|
311
|
-
const singleFile = [
|
|
312
|
-
{
|
|
313
|
-
id: 3,
|
|
314
|
-
filename: 'purchase-receipt.pdf',
|
|
315
|
-
status: Status.DONE,
|
|
316
|
-
},
|
|
317
|
-
];
|
|
318
|
-
|
|
319
|
-
renderComponent({
|
|
320
|
-
...props,
|
|
321
|
-
files: singleFile,
|
|
322
|
-
multiple: true,
|
|
323
|
-
onFilesChange,
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
await deleteFileAndWaitForFocus('3-uploadItem', 'uploadInput');
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
it('should focus the third item, then the second and finally upload input', async () => {
|
|
330
|
-
const filesWithFailed = [
|
|
331
|
-
{
|
|
332
|
-
id: 1,
|
|
333
|
-
filename: 'Sales-2024-invoice.pdf',
|
|
334
|
-
status: Status.DONE,
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
id: 2,
|
|
338
|
-
filename: 'CoWork-0317-invoice.pdf',
|
|
339
|
-
status: Status.FAILED,
|
|
340
|
-
},
|
|
341
|
-
{
|
|
342
|
-
id: 3,
|
|
343
|
-
filename: 'purchase-receipt.pdf',
|
|
344
|
-
status: Status.DONE,
|
|
345
|
-
},
|
|
346
|
-
];
|
|
347
|
-
|
|
348
|
-
renderComponent({
|
|
349
|
-
...props,
|
|
350
|
-
files: filesWithFailed,
|
|
351
|
-
multiple: true,
|
|
352
|
-
onFilesChange,
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
await deleteFileAndWaitForFocus('3-uploadItem', 'uploadInput');
|
|
356
|
-
await deleteFileAndWaitForFocus('1-uploadItem', '2-action');
|
|
357
|
-
await deleteFileAndWaitForFocus('2-uploadItem', 'uploadInput');
|
|
358
|
-
});
|
|
359
215
|
});
|
|
360
216
|
|
|
361
217
|
describe('Max File Upload limit', () => {
|