@12-apps/ui 1.5.0 → 1.5.2
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/package.json +17 -9
- package/src/button/index.ts +1 -0
- package/src/social-login-button/index.ts +1 -0
- package/src/{social-login-button.tsx → social-login-button/social-login-button.tsx} +5 -5
- package/src/user-avatar/index.ts +1 -0
- package/src/{user-avatar.tsx → user-avatar/user-avatar.tsx} +4 -4
- package/eslint.config.js +0 -89
- package/src/__tests__/data-grid.test.tsx +0 -125
- package/src/__tests__/package-wiring.test.ts +0 -41
- package/src/__tests__/setup.ts +0 -1
- package/src/__tests__/social-login-button.test.tsx +0 -186
- package/src/__tests__/user-avatar.test.tsx +0 -195
- package/src/__tests__/viewport.test.ts +0 -50
- package/src/components/command/__tests__/command.test.tsx +0 -112
- package/src/components/data-display/Alert/Alert.stories.tsx +0 -559
- package/src/components/data-display/Alert/Alert.test.stories.tsx +0 -707
- package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +0 -362
- package/src/components/data-display/AlertDialog/AlertDialog.test.stories.tsx +0 -763
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.stories.tsx +0 -230
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +0 -270
- package/src/components/data-display/Avatar/Avatar.stories.tsx +0 -721
- package/src/components/data-display/Avatar/Avatar.test.stories.tsx +0 -822
- package/src/components/data-display/Badge/Badge.stories.tsx +0 -1134
- package/src/components/data-display/Badge/Badge.test.stories.tsx +0 -1194
- package/src/components/data-display/Banner/Banner.stories.tsx +0 -528
- package/src/components/data-display/Banner/Banner.test.stories.tsx +0 -511
- package/src/components/data-display/Carousel/Carousel.stories.tsx +0 -607
- package/src/components/data-display/Carousel/Carousel.test.stories.tsx +0 -701
- package/src/components/data-display/Chart/Chart.stories.tsx +0 -568
- package/src/components/data-display/Chart/Chart.test.stories.tsx +0 -174
- package/src/components/data-display/Chart/SpecChart.stories.tsx +0 -150
- package/src/components/data-display/Chart/SpecChart.test.stories.tsx +0 -56
- package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +0 -60
- package/src/components/data-display/Chart/__tests__/chart-format.test.ts +0 -43
- package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +0 -119
- package/src/components/data-display/Chip/Chip.stories.tsx +0 -252
- package/src/components/data-display/Chip/Chip.test.stories.tsx +0 -266
- package/src/components/data-display/DataGrid/DataGrid.stories.tsx +0 -515
- package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +0 -653
- package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +0 -271
- package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +0 -134
- package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +0 -83
- package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +0 -115
- package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +0 -53
- package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +0 -114
- package/src/components/data-display/DataViews/base-card.stories.tsx +0 -136
- package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +0 -254
- package/src/components/data-display/EmptyState/EmptyState.stories.tsx +0 -282
- package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +0 -441
- package/src/components/data-display/ErrorState/ErrorState.stories.tsx +0 -110
- package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +0 -133
- package/src/components/data-display/HoverCard/HoverCard.stories.tsx +0 -650
- package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +0 -929
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.stories.tsx +0 -411
- package/src/components/data-display/LazyImage/LazyImage.stories.tsx +0 -387
- package/src/components/data-display/Lightbox/Lightbox.stories.tsx +0 -315
- package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +0 -598
- package/src/components/data-display/LoadingState/LoadingState.stories.tsx +0 -124
- package/src/components/data-display/LoadingState/LoadingState.test.stories.tsx +0 -99
- package/src/components/data-display/MapPreview/MapPreview.stories.tsx +0 -458
- package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +0 -394
- package/src/components/data-display/Popover/Popover.stories.tsx +0 -295
- package/src/components/data-display/Popover/Popover.test.stories.tsx +0 -1162
- package/src/components/data-display/Progress/Progress.stories.tsx +0 -481
- package/src/components/data-display/Progress/Progress.test.stories.tsx +0 -2070
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +0 -160
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.test.stories.tsx +0 -190
- package/src/components/data-display/Sheet/Sheet.stories.tsx +0 -883
- package/src/components/data-display/Sheet/Sheet.test.stories.tsx +0 -1105
- package/src/components/data-display/StatCard/StatCard.stories.tsx +0 -167
- package/src/components/data-display/StatCard/StatCard.test.stories.tsx +0 -240
- package/src/components/data-display/Stepper/Stepper.stories.tsx +0 -540
- package/src/components/data-display/Stepper/Stepper.test.stories.tsx +0 -600
- package/src/components/data-display/Table/Table.stories.tsx +0 -803
- package/src/components/data-display/Table/Table.test.stories.tsx +0 -369
- package/src/components/data-display/Timeline/Timeline.stories.tsx +0 -442
- package/src/components/data-display/Timeline/Timeline.test.stories.tsx +0 -930
- package/src/components/data-display/TimingDiagram/TimingDiagram.stories.tsx +0 -475
- package/src/components/data-display/TimingDiagram/TimingDiagram.test.stories.tsx +0 -734
- package/src/components/data-display/Tooltip/Tooltip.stories.tsx +0 -468
- package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +0 -1154
- package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +0 -146
- package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +0 -114
- package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +0 -288
- package/src/components/feedback/Dialog/Dialog.stories.tsx +0 -833
- package/src/components/feedback/Dialog/Dialog.test.stories.tsx +0 -964
- package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +0 -66
- package/src/components/feedback/Modal/Modal.stories.tsx +0 -765
- package/src/components/feedback/Modal/Modal.test.stories.tsx +0 -251
- package/src/components/feedback/Sonner/Sonner.stories.tsx +0 -698
- package/src/components/feedback/Sonner/Sonner.test.stories.tsx +0 -896
- package/src/components/feedback/StackedModal/StackedModal.stories.tsx +0 -1783
- package/src/components/feedback/StackedModal/StackedModal.test.stories.tsx +0 -973
- package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +0 -104
- package/src/components/feedback/Toast/Toast.stories.tsx +0 -548
- package/src/components/feedback/Toast/Toast.test.stories.tsx +0 -834
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.stories.tsx +0 -691
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +0 -634
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +0 -665
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +0 -727
- package/src/components/form/Autocomplete/Autocomplete.stories.tsx +0 -715
- package/src/components/form/Autocomplete/Autocomplete.test.stories.tsx +0 -825
- package/src/components/form/Button/Button.stories.tsx +0 -365
- package/src/components/form/Button/Button.test.stories.tsx +0 -607
- package/src/components/form/Calendar/Calendar.stories.tsx +0 -349
- package/src/components/form/Calendar/Calendar.test.stories.tsx +0 -464
- package/src/components/form/CepField/CepField.stories.tsx +0 -138
- package/src/components/form/CepField/CepField.test.stories.tsx +0 -281
- package/src/components/form/Checkbox/Checkbox.stories.tsx +0 -265
- package/src/components/form/Checkbox/Checkbox.test.stories.tsx +0 -181
- package/src/components/form/CodeEditor/CodeEditor.stories.tsx +0 -871
- package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +0 -574
- package/src/components/form/Command/Command.stories.tsx +0 -580
- package/src/components/form/Command/Command.test.stories.tsx +0 -215
- package/src/components/form/CreatableSelect/CreatableSelect.stories.tsx +0 -112
- package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +0 -134
- package/src/components/form/Form/Form.stories.tsx +0 -687
- package/src/components/form/Form/Form.test.stories.tsx +0 -601
- package/src/components/form/Input/Input.stories.tsx +0 -260
- package/src/components/form/Input/Input.test.stories.tsx +0 -1191
- package/src/components/form/InputOTP/InputOTP.stories.tsx +0 -774
- package/src/components/form/InputOTP/InputOTP.test.stories.tsx +0 -588
- package/src/components/form/Label/Label.stories.tsx +0 -473
- package/src/components/form/Label/Label.test.stories.tsx +0 -915
- package/src/components/form/Menubar/Menubar.stories.tsx +0 -472
- package/src/components/form/Menubar/Menubar.test.stories.tsx +0 -584
- package/src/components/form/PasswordStrength/PasswordStrength.stories.tsx +0 -562
- package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +0 -327
- package/src/components/form/PhoneInput/PhoneInput.stories.tsx +0 -495
- package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +0 -666
- package/src/components/form/RadioGroup/RadioGroup.stories.tsx +0 -518
- package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +0 -685
- package/src/components/form/RichTextEditor/RichTextEditor.stories.tsx +0 -261
- package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +0 -491
- package/src/components/form/SearchPalette/SearchPalette.stories.tsx +0 -135
- package/src/components/form/Select/Select.stories.tsx +0 -364
- package/src/components/form/Select/Select.test.stories.tsx +0 -985
- package/src/components/form/Slider/Slider.stories.tsx +0 -418
- package/src/components/form/Slider/Slider.test.stories.tsx +0 -1042
- package/src/components/form/Switch/Switch.stories.tsx +0 -697
- package/src/components/form/Switch/Switch.test.stories.tsx +0 -597
- package/src/components/form/Textarea/Textarea.stories.tsx +0 -473
- package/src/components/form/Textarea/Textarea.test.stories.tsx +0 -702
- package/src/components/form/Toggle/Toggle.stories.tsx +0 -638
- package/src/components/form/Toggle/Toggle.test.stories.tsx +0 -1159
- package/src/components/form/ToggleGroup/ToggleGroup.stories.tsx +0 -617
- package/src/components/form/ToggleGroup/ToggleGroup.test.stories.tsx +0 -915
- package/src/components/form/UploadButton/UploadButton.stories.tsx +0 -367
- package/src/components/form/UploadButton/UploadButton.test.stories.tsx +0 -573
- package/src/components/form/total-form/total-form.test.tsx +0 -214
- package/src/components/layout/Accordion/Accordion.stories.tsx +0 -694
- package/src/components/layout/Accordion/Accordion.test.stories.tsx +0 -1344
- package/src/components/layout/Card/Card.stories.tsx +0 -591
- package/src/components/layout/Card/Card.test.stories.tsx +0 -1134
- package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +0 -92
- package/src/components/layout/Collapsible/Collapsible.stories.tsx +0 -180
- package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +0 -308
- package/src/components/layout/Container/Container.stories.tsx +0 -557
- package/src/components/layout/Container/Container.test.stories.tsx +0 -745
- package/src/components/layout/ContentToolbar/ContentToolbar.stories.tsx +0 -129
- package/src/components/layout/ContentToolbar/ContentToolbar.test.stories.tsx +0 -251
- package/src/components/layout/ContentToolbar/__tests__/ColumnsMenu.test.tsx +0 -39
- package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +0 -131
- package/src/components/layout/ContentToolbar/__tests__/SavedViewsMenu.test.tsx +0 -99
- package/src/components/layout/Dashboard/Dashboard.stories.tsx +0 -104
- package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +0 -190
- package/src/components/layout/Drawer/Drawer.stories.tsx +0 -658
- package/src/components/layout/Drawer/Drawer.test.stories.tsx +0 -1343
- package/src/components/layout/Resizable/Resizable.stories.tsx +0 -1039
- package/src/components/layout/Resizable/Resizable.test.stories.tsx +0 -754
- package/src/components/layout/ScrollArea/ScrollArea.stories.tsx +0 -651
- package/src/components/layout/ScrollArea/ScrollArea.test.stories.tsx +0 -619
- package/src/components/layout/Separator/Separator.stories.tsx +0 -563
- package/src/components/layout/Separator/Separator.test.stories.tsx +0 -518
- package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +0 -192
- package/src/components/layout/SettingsLayout/SettingsLayout.test.stories.tsx +0 -175
- package/src/components/layout/Sidebar/Sidebar.stories.tsx +0 -609
- package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +0 -1324
- package/src/components/layout/Skeleton/Skeleton.stories.tsx +0 -689
- package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +0 -521
- package/src/components/layout/Spacer/Spacer.stories.tsx +0 -502
- package/src/components/layout/Spacer/Spacer.test.stories.tsx +0 -474
- package/src/components/layout/TableFilter/TableFilter.stories.tsx +0 -82
- package/src/components/layout/TableFilter/TableFilter.test.stories.tsx +0 -87
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +0 -638
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +0 -1008
- package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +0 -386
- package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +0 -435
- package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +0 -614
- package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +0 -845
- package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +0 -578
- package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +0 -660
- package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +0 -516
- package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +0 -935
- package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +0 -501
- package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +0 -453
- package/src/components/navigation/Pagination/Pagination.stories.tsx +0 -602
- package/src/components/navigation/Pagination/Pagination.test.stories.tsx +0 -520
- package/src/components/navigation/Tabs/Tabs.stories.tsx +0 -1004
- package/src/components/navigation/Tabs/Tabs.test.stories.tsx +0 -1225
- package/src/components/typography/Blockquote/Blockquote.stories.tsx +0 -359
- package/src/components/typography/Blockquote/Blockquote.test.stories.tsx +0 -432
- package/src/components/typography/Code/Code.stories.tsx +0 -686
- package/src/components/typography/Code/Code.test.stories.tsx +0 -703
- package/src/components/typography/Heading/Heading.stories.tsx +0 -451
- package/src/components/typography/Heading/Heading.test.stories.tsx +0 -830
- package/src/components/typography/Paragraph/Paragraph.stories.tsx +0 -280
- package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +0 -231
- package/src/components/typography/Text/Text.stories.tsx +0 -359
- package/src/components/typography/Text/Text.test.stories.tsx +0 -759
- package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +0 -945
- package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +0 -603
- package/src/components/utility/AspectRatio/AspectRatio.stories.tsx +0 -414
- package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +0 -859
- package/src/components/utility/InfiniteScroll/InfiniteScroll.stories.tsx +0 -620
- package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +0 -361
- package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +0 -118
- package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +0 -83
- package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +0 -65
- package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +0 -271
- package/src/components/utility/Portal/Portal.stories.tsx +0 -340
- package/src/components/utility/Portal/Portal.test.stories.tsx +0 -2086
- package/src/components/utility/Transition/Transition.stories.tsx +0 -493
- package/src/components/utility/Transition/Transition.test.stories.tsx +0 -854
- package/src/components/utility/VirtualList/VirtualList.stories.tsx +0 -1073
- package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +0 -1085
- package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +0 -431
- package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +0 -364
- /package/src/{button.tsx → button/button.tsx} +0 -0
|
@@ -1,573 +0,0 @@
|
|
|
1
|
-
import { Box, FormControl, FormLabel } from '@mui/material';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
|
-
import { expect, fn,userEvent, waitFor, within } from 'storybook/test';
|
|
4
|
-
|
|
5
|
-
import React from 'react';
|
|
6
|
-
|
|
7
|
-
import { UploadButton } from './UploadButton';
|
|
8
|
-
|
|
9
|
-
const meta: Meta<typeof UploadButton> = {
|
|
10
|
-
title: 'Form/UploadButton/Tests',
|
|
11
|
-
component: UploadButton,
|
|
12
|
-
parameters: {
|
|
13
|
-
layout: 'centered',
|
|
14
|
-
chromatic: { disableSnapshot: false },
|
|
15
|
-
},
|
|
16
|
-
tags: ['autodocs', 'test', 'component:UploadButton'],
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export default meta;
|
|
20
|
-
type Story = StoryObj<typeof meta>;
|
|
21
|
-
|
|
22
|
-
// Test file creation helper
|
|
23
|
-
const createTestFile = (
|
|
24
|
-
name: string = 'test.txt',
|
|
25
|
-
type: string = 'text/plain',
|
|
26
|
-
size: number = 1024,
|
|
27
|
-
): globalThis.File => {
|
|
28
|
-
const content = 'test content'.repeat(Math.ceil(size / 12)); // Repeat to reach desired size
|
|
29
|
-
return new globalThis.File([content], name, { type });
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const BasicInteraction: Story = {
|
|
33
|
-
args: {
|
|
34
|
-
onSelect: fn(),
|
|
35
|
-
label: 'Upload File',
|
|
36
|
-
'data-testid': 'upload-button',
|
|
37
|
-
},
|
|
38
|
-
play: async ({ canvasElement, args }) => {
|
|
39
|
-
const canvas = within(canvasElement);
|
|
40
|
-
const uploadButton = canvas.getByRole('button', { name: /upload file/i });
|
|
41
|
-
|
|
42
|
-
// Test button is present and clickable
|
|
43
|
-
await expect(uploadButton).toBeInTheDocument();
|
|
44
|
-
await expect(uploadButton).toBeEnabled();
|
|
45
|
-
|
|
46
|
-
// Test button click
|
|
47
|
-
await userEvent.click(uploadButton);
|
|
48
|
-
|
|
49
|
-
// Test hidden file input is present
|
|
50
|
-
const fileInput = canvasElement.querySelector('input[type="file"]') as HTMLInputElement;
|
|
51
|
-
await expect(fileInput).toBeInTheDocument();
|
|
52
|
-
await expect(fileInput).toHaveStyle({ display: 'none' });
|
|
53
|
-
|
|
54
|
-
// Simulate file selection by manually triggering the onChange event
|
|
55
|
-
const testFile = createTestFile();
|
|
56
|
-
|
|
57
|
-
// Create a proper FileList
|
|
58
|
-
const dataTransfer = new globalThis.DataTransfer();
|
|
59
|
-
dataTransfer.items.add(testFile);
|
|
60
|
-
fileInput.files = dataTransfer.files;
|
|
61
|
-
|
|
62
|
-
// Trigger change event
|
|
63
|
-
const changeEvent = new globalThis.Event('change', { bubbles: true });
|
|
64
|
-
fileInput.dispatchEvent(changeEvent);
|
|
65
|
-
|
|
66
|
-
// Verify onSelect was called
|
|
67
|
-
await waitFor(() => {
|
|
68
|
-
expect(args.onSelect).toHaveBeenCalledWith(testFile);
|
|
69
|
-
});
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export const FormInteraction: Story = {
|
|
74
|
-
render: (args) => (
|
|
75
|
-
<FormControl component="fieldset">
|
|
76
|
-
<FormLabel component="legend">File Upload</FormLabel>
|
|
77
|
-
<UploadButton {...args} />
|
|
78
|
-
</FormControl>
|
|
79
|
-
),
|
|
80
|
-
args: {
|
|
81
|
-
onSelect: fn(),
|
|
82
|
-
helperText: 'Select a file to upload',
|
|
83
|
-
},
|
|
84
|
-
play: async ({ canvasElement, args }) => {
|
|
85
|
-
const canvas = within(canvasElement);
|
|
86
|
-
const formLabel = canvas.getByText('File Upload');
|
|
87
|
-
const uploadButton = canvas.getByRole('button');
|
|
88
|
-
const helperText = canvas.getByText('Select a file to upload');
|
|
89
|
-
|
|
90
|
-
// Test form structure
|
|
91
|
-
await expect(formLabel).toBeInTheDocument();
|
|
92
|
-
await expect(uploadButton).toBeInTheDocument();
|
|
93
|
-
await expect(helperText).toBeInTheDocument();
|
|
94
|
-
|
|
95
|
-
// Test file upload in form context
|
|
96
|
-
const fileInput = canvasElement.querySelector('input[type="file"]') as HTMLInputElement;
|
|
97
|
-
const testFile = createTestFile('form-test.pdf', 'application/pdf');
|
|
98
|
-
|
|
99
|
-
if (fileInput) {
|
|
100
|
-
// Create a proper FileList
|
|
101
|
-
const dataTransfer = new globalThis.DataTransfer();
|
|
102
|
-
dataTransfer.items.add(testFile);
|
|
103
|
-
fileInput.files = dataTransfer.files;
|
|
104
|
-
|
|
105
|
-
// Trigger change event
|
|
106
|
-
const changeEvent = new globalThis.Event('change', { bubbles: true });
|
|
107
|
-
fileInput.dispatchEvent(changeEvent);
|
|
108
|
-
|
|
109
|
-
await waitFor(() => {
|
|
110
|
-
expect(args.onSelect).toHaveBeenCalledWith(testFile);
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
export const StateChangeTest: Story = {
|
|
117
|
-
args: {
|
|
118
|
-
onSelect: fn(),
|
|
119
|
-
onUpload: fn().mockImplementation(async () => {
|
|
120
|
-
await new Promise((resolve) => globalThis.setTimeout(resolve, 100));
|
|
121
|
-
}),
|
|
122
|
-
},
|
|
123
|
-
play: async ({ canvasElement, args }) => {
|
|
124
|
-
const canvas = within(canvasElement);
|
|
125
|
-
const uploadButton = canvas.getByRole('button');
|
|
126
|
-
|
|
127
|
-
// Test initial state
|
|
128
|
-
await expect(uploadButton).toBeEnabled();
|
|
129
|
-
await expect(uploadButton).toHaveTextContent(/upload file/i);
|
|
130
|
-
|
|
131
|
-
// Simulate file upload with progress
|
|
132
|
-
const fileInput = canvasElement.querySelector('input[type="file"]') as HTMLInputElement;
|
|
133
|
-
const testFile = createTestFile();
|
|
134
|
-
|
|
135
|
-
if (fileInput) {
|
|
136
|
-
// Create a proper FileList
|
|
137
|
-
const dataTransfer = new globalThis.DataTransfer();
|
|
138
|
-
dataTransfer.items.add(testFile);
|
|
139
|
-
fileInput.files = dataTransfer.files;
|
|
140
|
-
|
|
141
|
-
// Trigger change event
|
|
142
|
-
const changeEvent = new globalThis.Event('change', { bubbles: true });
|
|
143
|
-
fileInput.dispatchEvent(changeEvent);
|
|
144
|
-
|
|
145
|
-
// Verify onSelect called
|
|
146
|
-
await waitFor(() => {
|
|
147
|
-
expect(args.onSelect).toHaveBeenCalledWith(testFile);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
// If onUpload is provided, check upload state changes
|
|
151
|
-
if (args.onUpload) {
|
|
152
|
-
await waitFor(
|
|
153
|
-
() => {
|
|
154
|
-
const button = canvas.getByRole('button');
|
|
155
|
-
expect(button).toHaveTextContent(/uploading/i);
|
|
156
|
-
},
|
|
157
|
-
{ timeout: 1000 },
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
// Wait for upload to complete
|
|
161
|
-
await waitFor(
|
|
162
|
-
() => {
|
|
163
|
-
expect(args.onUpload).toHaveBeenCalledWith(testFile);
|
|
164
|
-
},
|
|
165
|
-
{ timeout: 2000 },
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
export const KeyboardNavigation: Story = {
|
|
173
|
-
args: {
|
|
174
|
-
onSelect: fn(),
|
|
175
|
-
},
|
|
176
|
-
play: async ({ canvasElement }) => {
|
|
177
|
-
const canvas = within(canvasElement);
|
|
178
|
-
const uploadButton = canvas.getByRole('button');
|
|
179
|
-
|
|
180
|
-
// Test keyboard navigation. Focus is driven with `tab()` and awaited via
|
|
181
|
-
// waitFor: a bare `.focus()` plus an immediate assertion races the browser's
|
|
182
|
-
// own focus handling.
|
|
183
|
-
await userEvent.tab();
|
|
184
|
-
await waitFor(() => expect(uploadButton).toHaveFocus());
|
|
185
|
-
|
|
186
|
-
// Test Enter key activation
|
|
187
|
-
await userEvent.keyboard('{Enter}');
|
|
188
|
-
|
|
189
|
-
// Test Space key activation
|
|
190
|
-
await userEvent.keyboard(' ');
|
|
191
|
-
|
|
192
|
-
// Test tab navigation
|
|
193
|
-
await userEvent.keyboard('{Tab}');
|
|
194
|
-
|
|
195
|
-
// Verify button maintains accessibility
|
|
196
|
-
await expect(uploadButton).toHaveAttribute('type', 'button');
|
|
197
|
-
},
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
export const ScreenReaderTest: Story = {
|
|
201
|
-
args: {
|
|
202
|
-
onSelect: fn(),
|
|
203
|
-
helperText: 'Maximum file size is 5MB',
|
|
204
|
-
'aria-label': 'Upload your document',
|
|
205
|
-
},
|
|
206
|
-
play: async ({ canvasElement }) => {
|
|
207
|
-
const canvas = within(canvasElement);
|
|
208
|
-
const uploadButton = canvas.getByRole('button');
|
|
209
|
-
const helperText = canvas.getByText('Maximum file size is 5MB');
|
|
210
|
-
|
|
211
|
-
// Test ARIA attributes
|
|
212
|
-
await expect(uploadButton).toHaveAccessibleName();
|
|
213
|
-
await expect(helperText).toBeInTheDocument();
|
|
214
|
-
|
|
215
|
-
// Test describedby relationship
|
|
216
|
-
const helperId = helperText.getAttribute('id');
|
|
217
|
-
if (helperId) {
|
|
218
|
-
const button = uploadButton;
|
|
219
|
-
await expect(button).toHaveAttribute('aria-describedby', expect.stringContaining(helperId));
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Test hidden file input accessibility
|
|
223
|
-
const fileInput = canvasElement.querySelector('input[type="file"]');
|
|
224
|
-
await expect(fileInput).toHaveAttribute('aria-hidden', 'true');
|
|
225
|
-
},
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
export const FocusManagement: Story = {
|
|
229
|
-
args: {
|
|
230
|
-
onSelect: fn(),
|
|
231
|
-
disabled: false,
|
|
232
|
-
},
|
|
233
|
-
play: async ({ canvasElement }) => {
|
|
234
|
-
const canvas = within(canvasElement);
|
|
235
|
-
const uploadButton = canvas.getByRole('button');
|
|
236
|
-
|
|
237
|
-
// Test focus management
|
|
238
|
-
await userEvent.tab();
|
|
239
|
-
await waitFor(() => expect(uploadButton).toHaveFocus());
|
|
240
|
-
|
|
241
|
-
// Test focus styles
|
|
242
|
-
await expect(uploadButton).toBeVisible();
|
|
243
|
-
|
|
244
|
-
// Test disabled state focus
|
|
245
|
-
// Note: This would need to be tested with a separate story for disabled state
|
|
246
|
-
await expect(uploadButton).toBeEnabled();
|
|
247
|
-
},
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
export const ResponsiveDesign: Story = {
|
|
251
|
-
args: {
|
|
252
|
-
onSelect: fn(),
|
|
253
|
-
},
|
|
254
|
-
parameters: {
|
|
255
|
-
viewport: { defaultViewport: 'mobile1' },
|
|
256
|
-
},
|
|
257
|
-
play: async ({ canvasElement }) => {
|
|
258
|
-
const canvas = within(canvasElement);
|
|
259
|
-
const uploadButton = canvas.getByRole('button');
|
|
260
|
-
|
|
261
|
-
// Test mobile viewport
|
|
262
|
-
await expect(uploadButton).toBeInTheDocument();
|
|
263
|
-
await expect(uploadButton).toBeVisible();
|
|
264
|
-
|
|
265
|
-
// Test button is clickable on mobile
|
|
266
|
-
await userEvent.click(uploadButton);
|
|
267
|
-
},
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
export const ThemeVariations: Story = {
|
|
271
|
-
parameters: {
|
|
272
|
-
backgrounds: { default: 'dark' },
|
|
273
|
-
},
|
|
274
|
-
args: {
|
|
275
|
-
onSelect: fn(),
|
|
276
|
-
},
|
|
277
|
-
play: async ({ canvasElement }) => {
|
|
278
|
-
const canvas = within(canvasElement);
|
|
279
|
-
const uploadButton = canvas.getByRole('button');
|
|
280
|
-
|
|
281
|
-
// Test dark theme visibility
|
|
282
|
-
await expect(uploadButton).toBeVisible();
|
|
283
|
-
await expect(uploadButton).toBeEnabled();
|
|
284
|
-
|
|
285
|
-
// Test contrast in dark mode
|
|
286
|
-
const styles = globalThis.getComputedStyle(uploadButton);
|
|
287
|
-
await expect(styles).toBeDefined();
|
|
288
|
-
},
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
export const VisualStates: Story = {
|
|
292
|
-
render: () => (
|
|
293
|
-
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
294
|
-
<UploadButton onSelect={fn()} label="Default" />
|
|
295
|
-
<UploadButton onSelect={fn()} variant="outline" label="Outline" />
|
|
296
|
-
<UploadButton onSelect={fn()} variant="ghost" label="Ghost" />
|
|
297
|
-
<UploadButton onSelect={fn()} variant="dropzone" label="Dropzone" />
|
|
298
|
-
<UploadButton onSelect={fn()} disabled label="Disabled" />
|
|
299
|
-
<UploadButton onSelect={fn()} uploading progress={50} label="Uploading" />
|
|
300
|
-
<UploadButton onSelect={fn()} errorText="Error state" label="Error" />
|
|
301
|
-
</Box>
|
|
302
|
-
),
|
|
303
|
-
play: async ({ canvasElement }) => {
|
|
304
|
-
const canvas = within(canvasElement);
|
|
305
|
-
const buttons = canvas.getAllByRole('button');
|
|
306
|
-
|
|
307
|
-
// Test all variants are rendered (6 MUI buttons + 1 dropzone div)
|
|
308
|
-
await expect(buttons).toHaveLength(7);
|
|
309
|
-
|
|
310
|
-
// Test each variant is visible
|
|
311
|
-
for (const button of buttons) {
|
|
312
|
-
await expect(button).toBeVisible();
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// Test disabled state
|
|
316
|
-
const disabledButton = canvas.getByRole('button', { name: /disabled/i });
|
|
317
|
-
await expect(disabledButton).toBeDisabled();
|
|
318
|
-
|
|
319
|
-
// Test error text
|
|
320
|
-
const errorText = canvas.getByText('Error state');
|
|
321
|
-
await expect(errorText).toBeInTheDocument();
|
|
322
|
-
},
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
export const PerformanceTest: Story = {
|
|
326
|
-
args: {
|
|
327
|
-
onSelect: fn(),
|
|
328
|
-
},
|
|
329
|
-
play: async ({ canvasElement, args }) => {
|
|
330
|
-
const canvas = within(canvasElement);
|
|
331
|
-
const uploadButton = canvas.getByRole('button');
|
|
332
|
-
|
|
333
|
-
const startTime = globalThis.performance.now();
|
|
334
|
-
|
|
335
|
-
// Test rapid clicks
|
|
336
|
-
for (let i = 0; i < 5; i++) {
|
|
337
|
-
await userEvent.click(uploadButton);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const endTime = globalThis.performance.now();
|
|
341
|
-
const duration = endTime - startTime;
|
|
342
|
-
|
|
343
|
-
// Performance should be reasonable (less than 1 second for 5 clicks)
|
|
344
|
-
await expect(duration).toBeLessThan(1000);
|
|
345
|
-
|
|
346
|
-
// Test file handling performance
|
|
347
|
-
const fileInput = canvasElement.querySelector('input[type="file"]') as HTMLInputElement;
|
|
348
|
-
const largeFile = createTestFile('large.txt', 'text/plain', 1024 * 1024); // 1MB
|
|
349
|
-
|
|
350
|
-
if (fileInput) {
|
|
351
|
-
const uploadStart = globalThis.performance.now();
|
|
352
|
-
await userEvent.upload(fileInput, largeFile);
|
|
353
|
-
const uploadEnd = globalThis.performance.now();
|
|
354
|
-
|
|
355
|
-
await expect(uploadEnd - uploadStart).toBeLessThan(500);
|
|
356
|
-
await expect(args.onSelect).toHaveBeenCalledWith(largeFile);
|
|
357
|
-
}
|
|
358
|
-
},
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
export const EdgeCases: Story = {
|
|
362
|
-
args: {
|
|
363
|
-
onSelect: fn(),
|
|
364
|
-
maxSizeMB: 1,
|
|
365
|
-
accept: 'image/*',
|
|
366
|
-
validate: (file: globalThis.File) => {
|
|
367
|
-
if (file.name.length > 50) {
|
|
368
|
-
return 'File name too long';
|
|
369
|
-
}
|
|
370
|
-
return null;
|
|
371
|
-
},
|
|
372
|
-
},
|
|
373
|
-
play: async ({ canvasElement, args }) => {
|
|
374
|
-
const canvas = within(canvasElement);
|
|
375
|
-
const fileInput = canvasElement.querySelector('input[type="file"]') as HTMLInputElement;
|
|
376
|
-
|
|
377
|
-
if (fileInput) {
|
|
378
|
-
// Test file too large
|
|
379
|
-
const largeFile = createTestFile('large.jpg', 'image/jpeg', 2 * 1024 * 1024); // 2MB
|
|
380
|
-
await userEvent.upload(fileInput, largeFile);
|
|
381
|
-
|
|
382
|
-
await waitFor(() => {
|
|
383
|
-
const errorTexts = canvas.queryAllByText(/file size must be less than/i);
|
|
384
|
-
expect(errorTexts.length).toBeGreaterThan(0);
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
// Clear the input for next test
|
|
388
|
-
Object.defineProperty(fileInput, 'value', { value: '', configurable: true });
|
|
389
|
-
Object.defineProperty(fileInput, 'files', { value: [], configurable: true });
|
|
390
|
-
|
|
391
|
-
// Test custom validation
|
|
392
|
-
const longNameFile = createTestFile(`${'a'.repeat(60) }.jpg`, 'image/jpeg', 500 * 1024);
|
|
393
|
-
await userEvent.upload(fileInput, longNameFile);
|
|
394
|
-
|
|
395
|
-
await waitFor(() => {
|
|
396
|
-
const errorTexts = canvas.queryAllByText(/file name too long/i);
|
|
397
|
-
expect(errorTexts.length).toBeGreaterThan(0);
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
// Test valid file
|
|
401
|
-
Object.defineProperty(fileInput, 'value', { value: '', configurable: true });
|
|
402
|
-
Object.defineProperty(fileInput, 'files', { value: [], configurable: true });
|
|
403
|
-
|
|
404
|
-
const validFile = createTestFile('valid.jpg', 'image/jpeg', 500 * 1024);
|
|
405
|
-
await userEvent.upload(fileInput, validFile);
|
|
406
|
-
|
|
407
|
-
await waitFor(() => {
|
|
408
|
-
expect(args.onSelect).toHaveBeenCalledWith(validFile);
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
},
|
|
412
|
-
};
|
|
413
|
-
|
|
414
|
-
export const IntegrationTest: Story = {
|
|
415
|
-
render: () => (
|
|
416
|
-
<Box component="form" role="form" sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
417
|
-
<UploadButton
|
|
418
|
-
onSelect={fn()}
|
|
419
|
-
helperText="Select your profile image"
|
|
420
|
-
accept="image/*"
|
|
421
|
-
maxSizeMB={2}
|
|
422
|
-
/>
|
|
423
|
-
<UploadButton
|
|
424
|
-
variant="dropzone"
|
|
425
|
-
onSelect={fn()}
|
|
426
|
-
helperText="Drop your document here"
|
|
427
|
-
accept=".pdf,.doc,.docx"
|
|
428
|
-
/>
|
|
429
|
-
</Box>
|
|
430
|
-
),
|
|
431
|
-
play: async ({ canvasElement }) => {
|
|
432
|
-
const canvas = within(canvasElement);
|
|
433
|
-
const form = canvas.getByRole('form');
|
|
434
|
-
const buttons = canvas.getAllByRole('button');
|
|
435
|
-
const helperTexts = [
|
|
436
|
-
canvas.getByText('Select your profile image'),
|
|
437
|
-
canvas.getByText('Drop your document here'),
|
|
438
|
-
];
|
|
439
|
-
|
|
440
|
-
// Test form integration
|
|
441
|
-
await expect(form).toBeInTheDocument();
|
|
442
|
-
await expect(buttons).toHaveLength(2);
|
|
443
|
-
await expect(helperTexts).toHaveLength(2);
|
|
444
|
-
|
|
445
|
-
// Test different file inputs in same form
|
|
446
|
-
const fileInputs = Array.from(canvasElement.querySelectorAll('input[type="file"]'));
|
|
447
|
-
await expect(fileInputs.length).toBeGreaterThanOrEqual(2);
|
|
448
|
-
|
|
449
|
-
// Test each input has different accept attributes
|
|
450
|
-
const imageInput = fileInputs.find((input) => input.getAttribute('accept') === 'image/*');
|
|
451
|
-
const documentInput = fileInputs.find(
|
|
452
|
-
(input) => input.getAttribute('accept') === '.pdf,.doc,.docx',
|
|
453
|
-
);
|
|
454
|
-
|
|
455
|
-
await expect(imageInput).toBeInTheDocument();
|
|
456
|
-
await expect(documentInput).toBeInTheDocument();
|
|
457
|
-
},
|
|
458
|
-
};
|
|
459
|
-
|
|
460
|
-
/**
|
|
461
|
-
* Multi-file mode hands the whole selection over at once. Single-file callers
|
|
462
|
-
* are untouched — they neither set `multiple` nor pass `onSelectMany`.
|
|
463
|
-
*/
|
|
464
|
-
export const MultipleFilesGoToOnSelectMany: Story = {
|
|
465
|
-
render: function MultipleStory() {
|
|
466
|
-
const [names, setNames] = React.useState<string[]>([]);
|
|
467
|
-
return (
|
|
468
|
-
<Box>
|
|
469
|
-
<UploadButton
|
|
470
|
-
variant="dropzone"
|
|
471
|
-
multiple
|
|
472
|
-
accept=".xml"
|
|
473
|
-
onSelect={fn()}
|
|
474
|
-
onSelectMany={(files) => setNames(files.map((file) => file.name))}
|
|
475
|
-
data-testid="multi-dropzone"
|
|
476
|
-
/>
|
|
477
|
-
<span data-testid="picked">{names.join(',')}</span>
|
|
478
|
-
</Box>
|
|
479
|
-
);
|
|
480
|
-
},
|
|
481
|
-
play: async ({ canvasElement }) => {
|
|
482
|
-
const canvas = within(canvasElement);
|
|
483
|
-
const input = canvasElement.querySelector('input[type="file"]') as HTMLInputElement;
|
|
484
|
-
|
|
485
|
-
// `multiple` reaches the real input, so the OS picker allows a selection.
|
|
486
|
-
await expect(input).toHaveAttribute('multiple');
|
|
487
|
-
|
|
488
|
-
await userEvent.upload(input, [
|
|
489
|
-
new File(['<nfeProc/>'], 'a.xml', { type: 'text/xml' }),
|
|
490
|
-
new File(['<nfeProc/>'], 'b.xml', { type: 'text/xml' }),
|
|
491
|
-
]);
|
|
492
|
-
|
|
493
|
-
await waitFor(() => expect(canvas.getByTestId('picked')).toHaveTextContent('a.xml,b.xml'));
|
|
494
|
-
},
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
/**
|
|
498
|
-
* A rejected file does not cost the caller the valid ones beside it: the error
|
|
499
|
-
* is surfaced AND the good files are handed over. Dropping a folder that also
|
|
500
|
-
* holds a PDF should still import the XMLs.
|
|
501
|
-
*/
|
|
502
|
-
export const RejectedFilesDoNotBlockTheRest: Story = {
|
|
503
|
-
render: function PartialStory() {
|
|
504
|
-
const [names, setNames] = React.useState<string[]>([]);
|
|
505
|
-
return (
|
|
506
|
-
<Box>
|
|
507
|
-
<UploadButton
|
|
508
|
-
variant="dropzone"
|
|
509
|
-
multiple
|
|
510
|
-
onSelect={fn()}
|
|
511
|
-
onSelectMany={(files) => setNames(files.map((file) => file.name))}
|
|
512
|
-
validate={(file) => (file.name.endsWith('.xml') ? null : 'Somente arquivos XML.')}
|
|
513
|
-
data-testid="partial-dropzone"
|
|
514
|
-
/>
|
|
515
|
-
<span data-testid="accepted">{names.join(',')}</span>
|
|
516
|
-
</Box>
|
|
517
|
-
);
|
|
518
|
-
},
|
|
519
|
-
play: async ({ canvasElement }) => {
|
|
520
|
-
const canvas = within(canvasElement);
|
|
521
|
-
const input = canvasElement.querySelector('input[type="file"]') as HTMLInputElement;
|
|
522
|
-
|
|
523
|
-
await userEvent.upload(input, [
|
|
524
|
-
new File(['<nfeProc/>'], 'nota.xml', { type: 'text/xml' }),
|
|
525
|
-
new File(['%PDF'], 'danfe.pdf', { type: 'application/pdf' }),
|
|
526
|
-
]);
|
|
527
|
-
|
|
528
|
-
// The XML still arrives…
|
|
529
|
-
await waitFor(() => expect(canvas.getByTestId('accepted')).toHaveTextContent('nota.xml'));
|
|
530
|
-
// …and the rejection is reported rather than swallowed.
|
|
531
|
-
await waitFor(() => expect(canvas.getByText('Somente arquivos XML.')).toBeInTheDocument());
|
|
532
|
-
},
|
|
533
|
-
};
|
|
534
|
-
|
|
535
|
-
/**
|
|
536
|
-
* `onUpload` means the same thing in both modes. It ran only for single files
|
|
537
|
-
* once, which made it a silent no-op for a multi-file caller — nothing failed,
|
|
538
|
-
* nothing uploaded.
|
|
539
|
-
*/
|
|
540
|
-
export const MultipleFilesStillRunOnUpload: Story = {
|
|
541
|
-
render: function MultiUploadStory() {
|
|
542
|
-
const [uploaded, setUploaded] = React.useState<string[]>([]);
|
|
543
|
-
return (
|
|
544
|
-
<Box>
|
|
545
|
-
<UploadButton
|
|
546
|
-
variant="dropzone"
|
|
547
|
-
multiple
|
|
548
|
-
onSelect={fn()}
|
|
549
|
-
onSelectMany={fn()}
|
|
550
|
-
onUpload={async (file) => {
|
|
551
|
-
setUploaded((prev) => [...prev, file.name]);
|
|
552
|
-
}}
|
|
553
|
-
data-testid="multi-upload-dropzone"
|
|
554
|
-
/>
|
|
555
|
-
<span data-testid="uploaded">{uploaded.join(',')}</span>
|
|
556
|
-
</Box>
|
|
557
|
-
);
|
|
558
|
-
},
|
|
559
|
-
play: async ({ canvasElement }) => {
|
|
560
|
-
const canvas = within(canvasElement);
|
|
561
|
-
const input = canvasElement.querySelector('input[type="file"]') as HTMLInputElement;
|
|
562
|
-
|
|
563
|
-
await userEvent.upload(input, [
|
|
564
|
-
new File(['a'], 'a.xml', { type: 'text/xml' }),
|
|
565
|
-
new File(['b'], 'b.xml', { type: 'text/xml' }),
|
|
566
|
-
]);
|
|
567
|
-
|
|
568
|
-
// Every accepted file goes through the upload path, in order.
|
|
569
|
-
await waitFor(() => expect(canvas.getByTestId('uploaded')).toHaveTextContent('a.xml,b.xml'), {
|
|
570
|
-
timeout: 5000,
|
|
571
|
-
});
|
|
572
|
-
},
|
|
573
|
-
};
|