@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,896 +0,0 @@
|
|
|
1
|
-
import { Box,Button, Stack, TextField } from '@mui/material';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import { expect, userEvent, waitFor,within } from 'storybook/test';
|
|
5
|
-
|
|
6
|
-
import { SonnerProvider, useSonner } from './Sonner';
|
|
7
|
-
|
|
8
|
-
const meta: Meta<typeof SonnerProvider> = {
|
|
9
|
-
title: 'Feedback/Sonner/Tests',
|
|
10
|
-
component: SonnerProvider,
|
|
11
|
-
parameters: {
|
|
12
|
-
layout: 'padded',
|
|
13
|
-
docs: {
|
|
14
|
-
description: {
|
|
15
|
-
component: 'Comprehensive test stories for Sonner toast component',
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
tags: ['autodocs', 'test', 'component:Sonner'],
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export default meta;
|
|
23
|
-
type Story = StoryObj<typeof meta>;
|
|
24
|
-
|
|
25
|
-
// Test wrapper component with toast functionality
|
|
26
|
-
const TestWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
|
27
|
-
<SonnerProvider>{children}</SonnerProvider>
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
// Basic interaction test component
|
|
31
|
-
const BasicInteractionTest: React.FC = () => {
|
|
32
|
-
const { toast, success, error, warning, info, loading, dismiss } = useSonner();
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<Stack spacing={2} data-testid="basic-interaction">
|
|
36
|
-
<Button data-testid="basic-toast-btn" onClick={() => toast('Basic toast message')}>
|
|
37
|
-
Basic Toast
|
|
38
|
-
</Button>
|
|
39
|
-
<Button data-testid="success-toast-btn" onClick={() => success('Success message')}>
|
|
40
|
-
Success Toast
|
|
41
|
-
</Button>
|
|
42
|
-
<Button data-testid="error-toast-btn" onClick={() => error('Error message')}>
|
|
43
|
-
Error Toast
|
|
44
|
-
</Button>
|
|
45
|
-
<Button data-testid="warning-toast-btn" onClick={() => warning('Warning message')}>
|
|
46
|
-
Warning Toast
|
|
47
|
-
</Button>
|
|
48
|
-
<Button data-testid="info-toast-btn" onClick={() => info('Info message')}>
|
|
49
|
-
Info Toast
|
|
50
|
-
</Button>
|
|
51
|
-
<Button data-testid="loading-toast-btn" onClick={() => loading('Loading...')}>
|
|
52
|
-
Loading Toast
|
|
53
|
-
</Button>
|
|
54
|
-
<Button data-testid="dismiss-all-btn" onClick={() => dismiss()}>
|
|
55
|
-
Dismiss All
|
|
56
|
-
</Button>
|
|
57
|
-
</Stack>
|
|
58
|
-
);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// Form interaction test component
|
|
62
|
-
const FormInteractionTest: React.FC = () => {
|
|
63
|
-
const { success, error } = useSonner();
|
|
64
|
-
const [value, setValue] = React.useState('');
|
|
65
|
-
|
|
66
|
-
const handleSubmit = () => {
|
|
67
|
-
if (value.trim()) {
|
|
68
|
-
success('Form submitted successfully!');
|
|
69
|
-
setValue('');
|
|
70
|
-
} else {
|
|
71
|
-
error('Please enter a value');
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
return (
|
|
76
|
-
<Box data-testid="form-interaction">
|
|
77
|
-
<Stack spacing={2}>
|
|
78
|
-
<TextField
|
|
79
|
-
data-testid="form-input"
|
|
80
|
-
value={value}
|
|
81
|
-
onChange={(e) => setValue(e.target.value)}
|
|
82
|
-
placeholder="Enter some text"
|
|
83
|
-
onKeyDown={(e) => e.key === 'Enter' && handleSubmit()}
|
|
84
|
-
/>
|
|
85
|
-
<Button data-testid="submit-btn" onClick={handleSubmit}>
|
|
86
|
-
Submit
|
|
87
|
-
</Button>
|
|
88
|
-
</Stack>
|
|
89
|
-
</Box>
|
|
90
|
-
);
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// Keyboard navigation test component
|
|
94
|
-
const KeyboardNavigationTest: React.FC = () => {
|
|
95
|
-
const { toast, dismiss } = useSonner();
|
|
96
|
-
|
|
97
|
-
React.useEffect(() => {
|
|
98
|
-
const handleKeyDown = (e: globalThis.KeyboardEvent) => {
|
|
99
|
-
if (e.key === 't' && e.ctrlKey) {
|
|
100
|
-
e.preventDefault();
|
|
101
|
-
toast('Triggered by Ctrl+T');
|
|
102
|
-
}
|
|
103
|
-
if (e.key === 'Escape') {
|
|
104
|
-
dismiss();
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
window.addEventListener('keydown', handleKeyDown);
|
|
109
|
-
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
110
|
-
}, [toast, dismiss]);
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<Box data-testid="keyboard-navigation">
|
|
114
|
-
<Stack spacing={2}>
|
|
115
|
-
<Button data-testid="show-toast-btn" onClick={() => toast('Toast for keyboard test')}>
|
|
116
|
-
Show Toast
|
|
117
|
-
</Button>
|
|
118
|
-
<p>Press Ctrl+T to show toast, Esc to dismiss</p>
|
|
119
|
-
</Stack>
|
|
120
|
-
</Box>
|
|
121
|
-
);
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
// Screen reader test component
|
|
125
|
-
const ScreenReaderTest: React.FC = () => {
|
|
126
|
-
const { toast } = useSonner();
|
|
127
|
-
|
|
128
|
-
return (
|
|
129
|
-
<Box data-testid="screen-reader">
|
|
130
|
-
<Button
|
|
131
|
-
data-testid="accessible-toast-btn"
|
|
132
|
-
onClick={() => toast('Screen reader accessible toast')}
|
|
133
|
-
aria-label="Show accessible toast notification"
|
|
134
|
-
>
|
|
135
|
-
Accessible Toast
|
|
136
|
-
</Button>
|
|
137
|
-
</Box>
|
|
138
|
-
);
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
// Focus management test component
|
|
142
|
-
const FocusManagementTest: React.FC = () => {
|
|
143
|
-
const { toast } = useSonner();
|
|
144
|
-
const buttonRef = React.useRef<HTMLButtonElement>(null);
|
|
145
|
-
|
|
146
|
-
const handleToast = () => {
|
|
147
|
-
toast('Focus management test', {
|
|
148
|
-
action: {
|
|
149
|
-
label: 'Focus Button',
|
|
150
|
-
onClick: () => {
|
|
151
|
-
buttonRef.current?.focus();
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
return (
|
|
158
|
-
<Box data-testid="focus-management">
|
|
159
|
-
<Stack spacing={2}>
|
|
160
|
-
<Button data-testid="focus-toast-btn" onClick={handleToast}>
|
|
161
|
-
Show Toast with Action
|
|
162
|
-
</Button>
|
|
163
|
-
<Button ref={buttonRef} data-testid="focus-target-btn">
|
|
164
|
-
Focus Target
|
|
165
|
-
</Button>
|
|
166
|
-
</Stack>
|
|
167
|
-
</Box>
|
|
168
|
-
);
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
// Responsive design test component
|
|
172
|
-
const ResponsiveDesignTest: React.FC = () => {
|
|
173
|
-
const { toast } = useSonner();
|
|
174
|
-
|
|
175
|
-
return (
|
|
176
|
-
<Box data-testid="responsive-design">
|
|
177
|
-
<Button
|
|
178
|
-
data-testid="responsive-toast-btn"
|
|
179
|
-
onClick={() => toast('Responsive design test message that is quite long to test wrapping')}
|
|
180
|
-
>
|
|
181
|
-
Test Responsive Toast
|
|
182
|
-
</Button>
|
|
183
|
-
</Box>
|
|
184
|
-
);
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
// Theme variations test component
|
|
188
|
-
const ThemeVariationsTest: React.FC = () => {
|
|
189
|
-
const { toast } = useSonner();
|
|
190
|
-
|
|
191
|
-
return (
|
|
192
|
-
<Box data-testid="theme-variations">
|
|
193
|
-
<Stack spacing={2}>
|
|
194
|
-
<Button
|
|
195
|
-
data-testid="default-theme-btn"
|
|
196
|
-
onClick={() => toast('Default theme toast', { variant: 'default' })}
|
|
197
|
-
>
|
|
198
|
-
Default Theme
|
|
199
|
-
</Button>
|
|
200
|
-
<Button
|
|
201
|
-
data-testid="glass-theme-btn"
|
|
202
|
-
onClick={() => toast('Glass theme toast', { variant: 'glass' })}
|
|
203
|
-
>
|
|
204
|
-
Glass Theme
|
|
205
|
-
</Button>
|
|
206
|
-
<Button
|
|
207
|
-
data-testid="minimal-theme-btn"
|
|
208
|
-
onClick={() => toast('Minimal theme toast', { variant: 'minimal' })}
|
|
209
|
-
>
|
|
210
|
-
Minimal Theme
|
|
211
|
-
</Button>
|
|
212
|
-
</Stack>
|
|
213
|
-
</Box>
|
|
214
|
-
);
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
// Visual states test component
|
|
218
|
-
const VisualStatesTest: React.FC = () => {
|
|
219
|
-
const { toast, success, error } = useSonner();
|
|
220
|
-
|
|
221
|
-
return (
|
|
222
|
-
<Box data-testid="visual-states">
|
|
223
|
-
<Stack spacing={2}>
|
|
224
|
-
<Button
|
|
225
|
-
data-testid="persistent-toast-btn"
|
|
226
|
-
onClick={() => toast('Persistent toast', { persistent: true })}
|
|
227
|
-
>
|
|
228
|
-
Persistent Toast
|
|
229
|
-
</Button>
|
|
230
|
-
<Button
|
|
231
|
-
data-testid="important-toast-btn"
|
|
232
|
-
onClick={() => success('Important success', { important: true })}
|
|
233
|
-
>
|
|
234
|
-
Important Success
|
|
235
|
-
</Button>
|
|
236
|
-
<Button
|
|
237
|
-
data-testid="with-description-btn"
|
|
238
|
-
onClick={() =>
|
|
239
|
-
error('Error with description', {
|
|
240
|
-
description: 'This is a detailed description of the error',
|
|
241
|
-
})
|
|
242
|
-
}
|
|
243
|
-
>
|
|
244
|
-
With Description
|
|
245
|
-
</Button>
|
|
246
|
-
</Stack>
|
|
247
|
-
</Box>
|
|
248
|
-
);
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
// Performance test component
|
|
252
|
-
const PerformanceTest: React.FC = () => {
|
|
253
|
-
const { toast, dismiss } = useSonner();
|
|
254
|
-
|
|
255
|
-
const handleManyToasts = () => {
|
|
256
|
-
const startTime = Date.now();
|
|
257
|
-
for (let i = 0; i < 10; i++) {
|
|
258
|
-
toast(`Toast ${i + 1}`);
|
|
259
|
-
}
|
|
260
|
-
const endTime = Date.now();
|
|
261
|
-
window.setTimeout(() => {
|
|
262
|
-
toast(`Created 10 toasts in ${endTime - startTime}ms`);
|
|
263
|
-
}, 100);
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
return (
|
|
267
|
-
<Box data-testid="performance">
|
|
268
|
-
<Stack spacing={2}>
|
|
269
|
-
<Button data-testid="many-toasts-btn" onClick={handleManyToasts}>
|
|
270
|
-
Create Many Toasts
|
|
271
|
-
</Button>
|
|
272
|
-
<Button data-testid="clear-toasts-btn" onClick={() => dismiss()}>
|
|
273
|
-
Clear All
|
|
274
|
-
</Button>
|
|
275
|
-
</Stack>
|
|
276
|
-
</Box>
|
|
277
|
-
);
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
// Edge cases test component
|
|
281
|
-
const EdgeCasesTest: React.FC = () => {
|
|
282
|
-
const { toast, promise } = useSonner();
|
|
283
|
-
|
|
284
|
-
const handleEmptyToast = () => {
|
|
285
|
-
toast('');
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
const handleLongToast = () => {
|
|
289
|
-
toast(
|
|
290
|
-
'This is a very long toast message that should test how the component handles extensive text content that might overflow or wrap to multiple lines in the toast notification container',
|
|
291
|
-
);
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
const handlePromiseToast = () => {
|
|
295
|
-
const testPromise = new Promise((resolve) => {
|
|
296
|
-
window.setTimeout(() => resolve('Success!'), 2000);
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
promise(testPromise, {
|
|
300
|
-
loading: 'Processing...',
|
|
301
|
-
success: 'Promise resolved!',
|
|
302
|
-
error: 'Promise failed!',
|
|
303
|
-
});
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
return (
|
|
307
|
-
<Box data-testid="edge-cases">
|
|
308
|
-
<Stack spacing={2}>
|
|
309
|
-
<Button data-testid="empty-toast-btn" onClick={handleEmptyToast}>
|
|
310
|
-
Empty Toast
|
|
311
|
-
</Button>
|
|
312
|
-
<Button data-testid="long-toast-btn" onClick={handleLongToast}>
|
|
313
|
-
Long Message
|
|
314
|
-
</Button>
|
|
315
|
-
<Button data-testid="promise-toast-btn" onClick={handlePromiseToast}>
|
|
316
|
-
Promise Toast
|
|
317
|
-
</Button>
|
|
318
|
-
</Stack>
|
|
319
|
-
</Box>
|
|
320
|
-
);
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
// Integration test component
|
|
324
|
-
const IntegrationTest: React.FC = () => {
|
|
325
|
-
const { toast, success, error, dismiss } = useSonner();
|
|
326
|
-
const [step, setStep] = React.useState(0);
|
|
327
|
-
|
|
328
|
-
const runIntegrationTest = async () => {
|
|
329
|
-
setStep(1);
|
|
330
|
-
toast('Step 1: Starting integration test');
|
|
331
|
-
|
|
332
|
-
window.setTimeout(() => {
|
|
333
|
-
setStep(2);
|
|
334
|
-
success('Step 2: First action completed');
|
|
335
|
-
}, 1000);
|
|
336
|
-
|
|
337
|
-
window.setTimeout(() => {
|
|
338
|
-
setStep(3);
|
|
339
|
-
error('Step 3: Simulated error occurred');
|
|
340
|
-
}, 2000);
|
|
341
|
-
|
|
342
|
-
window.setTimeout(() => {
|
|
343
|
-
setStep(4);
|
|
344
|
-
dismiss();
|
|
345
|
-
success('Step 4: Integration test completed');
|
|
346
|
-
setStep(0);
|
|
347
|
-
}, 3000);
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
return (
|
|
351
|
-
<Box data-testid="integration">
|
|
352
|
-
<Stack spacing={2}>
|
|
353
|
-
<Button data-testid="integration-test-btn" onClick={runIntegrationTest} disabled={step > 0}>
|
|
354
|
-
Run Integration Test {step > 0 && `(Step ${step}/4)`}
|
|
355
|
-
</Button>
|
|
356
|
-
</Stack>
|
|
357
|
-
</Box>
|
|
358
|
-
);
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
// Test stories
|
|
362
|
-
export const BasicInteraction: Story = {
|
|
363
|
-
render: () => (
|
|
364
|
-
<TestWrapper>
|
|
365
|
-
<BasicInteractionTest />
|
|
366
|
-
</TestWrapper>
|
|
367
|
-
),
|
|
368
|
-
play: async ({ canvasElement, step }) => {
|
|
369
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
370
|
-
const localCanvas = within(canvasElement);
|
|
371
|
-
|
|
372
|
-
await step('Test basic toast', async () => {
|
|
373
|
-
const basicBtn = localCanvas.getByTestId('basic-toast-btn');
|
|
374
|
-
await userEvent.click(basicBtn);
|
|
375
|
-
|
|
376
|
-
// Verify toast appears in the DOM
|
|
377
|
-
await waitFor(() => {
|
|
378
|
-
expect(canvas.getByText('Basic toast message')).toBeInTheDocument();
|
|
379
|
-
});
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
await step('Test success toast with icon', async () => {
|
|
383
|
-
const successBtn = localCanvas.getByTestId('success-toast-btn');
|
|
384
|
-
await userEvent.click(successBtn);
|
|
385
|
-
|
|
386
|
-
await waitFor(() => {
|
|
387
|
-
expect(canvas.getByText('Success message')).toBeInTheDocument();
|
|
388
|
-
// Check for success icon (CheckCircle)
|
|
389
|
-
const toasts = canvas.getAllByText(/Success message|Basic toast message/);
|
|
390
|
-
expect(toasts.length).toBeGreaterThan(0);
|
|
391
|
-
});
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
await step('Test error toast', async () => {
|
|
395
|
-
const errorBtn = localCanvas.getByTestId('error-toast-btn');
|
|
396
|
-
await userEvent.click(errorBtn);
|
|
397
|
-
|
|
398
|
-
await waitFor(() => {
|
|
399
|
-
expect(canvas.getByText('Error message')).toBeInTheDocument();
|
|
400
|
-
});
|
|
401
|
-
});
|
|
402
|
-
|
|
403
|
-
await step('Test dismiss all functionality', async () => {
|
|
404
|
-
const dismissBtn = localCanvas.getByTestId('dismiss-all-btn');
|
|
405
|
-
await userEvent.click(dismissBtn);
|
|
406
|
-
|
|
407
|
-
// Wait for toasts to disappear with animation
|
|
408
|
-
await waitFor(
|
|
409
|
-
() => {
|
|
410
|
-
expect(canvas.queryByText('Basic toast message')).not.toBeInTheDocument();
|
|
411
|
-
expect(canvas.queryByText('Success message')).not.toBeInTheDocument();
|
|
412
|
-
expect(canvas.queryByText('Error message')).not.toBeInTheDocument();
|
|
413
|
-
},
|
|
414
|
-
{ timeout: 2000 },
|
|
415
|
-
);
|
|
416
|
-
});
|
|
417
|
-
},
|
|
418
|
-
};
|
|
419
|
-
|
|
420
|
-
export const FormInteraction: Story = {
|
|
421
|
-
render: () => (
|
|
422
|
-
<TestWrapper>
|
|
423
|
-
<FormInteractionTest />
|
|
424
|
-
</TestWrapper>
|
|
425
|
-
),
|
|
426
|
-
play: async ({ canvasElement, step }) => {
|
|
427
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
428
|
-
const localCanvas = within(canvasElement);
|
|
429
|
-
|
|
430
|
-
const submitBtn = localCanvas.getByTestId('submit-btn');
|
|
431
|
-
|
|
432
|
-
await step('Test empty submission - should show error toast', async () => {
|
|
433
|
-
await userEvent.click(submitBtn);
|
|
434
|
-
|
|
435
|
-
await waitFor(() => {
|
|
436
|
-
expect(canvas.getByText('Please enter a value')).toBeInTheDocument();
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
// Wait a bit for the error toast to be visible
|
|
440
|
-
await new Promise((resolve) => window.setTimeout(resolve, 500));
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
await step('Test valid submission - should show success toast', async () => {
|
|
444
|
-
// Find the actual MUI input element inside the TextField
|
|
445
|
-
const inputField = localCanvas.getByTestId('form-input');
|
|
446
|
-
const actualInput = inputField.querySelector('input');
|
|
447
|
-
expect(actualInput).not.toBeNull();
|
|
448
|
-
|
|
449
|
-
// Type directly in the input element
|
|
450
|
-
await userEvent.type(actualInput!, 'Test input');
|
|
451
|
-
|
|
452
|
-
// Wait for the form to be ready and submit
|
|
453
|
-
await new Promise(resolve => window.setTimeout(resolve, 100));
|
|
454
|
-
await userEvent.click(submitBtn);
|
|
455
|
-
|
|
456
|
-
// Check that success toast appears
|
|
457
|
-
await waitFor(() => {
|
|
458
|
-
expect(canvas.getByText('Form submitted successfully!')).toBeInTheDocument();
|
|
459
|
-
}, { timeout: 2000 });
|
|
460
|
-
|
|
461
|
-
// Verify input was cleared after successful submission
|
|
462
|
-
await waitFor(() => {
|
|
463
|
-
if (actualInput) {
|
|
464
|
-
expect(actualInput.value).toBe('');
|
|
465
|
-
}
|
|
466
|
-
});
|
|
467
|
-
});
|
|
468
|
-
},
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
export const KeyboardNavigation: Story = {
|
|
472
|
-
render: () => (
|
|
473
|
-
<TestWrapper>
|
|
474
|
-
<KeyboardNavigationTest />
|
|
475
|
-
</TestWrapper>
|
|
476
|
-
),
|
|
477
|
-
play: async ({ canvasElement, step }) => {
|
|
478
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
479
|
-
const localCanvas = within(canvasElement);
|
|
480
|
-
|
|
481
|
-
await step('Show toast and verify keyboard navigation', async () => {
|
|
482
|
-
const showBtn = localCanvas.getByTestId('show-toast-btn');
|
|
483
|
-
await userEvent.click(showBtn);
|
|
484
|
-
|
|
485
|
-
// Verify toast appears
|
|
486
|
-
await waitFor(() => {
|
|
487
|
-
expect(canvas.getByText('Toast for keyboard test')).toBeInTheDocument();
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
// Test Escape key dismissal
|
|
491
|
-
await userEvent.keyboard('{Escape}');
|
|
492
|
-
|
|
493
|
-
// Verify toast is dismissed
|
|
494
|
-
await waitFor(
|
|
495
|
-
() => {
|
|
496
|
-
expect(canvas.queryByText('Toast for keyboard test')).not.toBeInTheDocument();
|
|
497
|
-
},
|
|
498
|
-
{ timeout: 1000 },
|
|
499
|
-
);
|
|
500
|
-
});
|
|
501
|
-
},
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
export const ScreenReader: Story = {
|
|
505
|
-
render: () => (
|
|
506
|
-
<TestWrapper>
|
|
507
|
-
<ScreenReaderTest />
|
|
508
|
-
</TestWrapper>
|
|
509
|
-
),
|
|
510
|
-
play: async ({ canvasElement, step }) => {
|
|
511
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
512
|
-
const localCanvas = within(canvasElement);
|
|
513
|
-
|
|
514
|
-
await step('Verify accessibility attributes and screen reader support', async () => {
|
|
515
|
-
const accessibleBtn = localCanvas.getByTestId('accessible-toast-btn');
|
|
516
|
-
expect(accessibleBtn).toHaveAttribute('aria-label', 'Show accessible toast notification');
|
|
517
|
-
|
|
518
|
-
await userEvent.click(accessibleBtn);
|
|
519
|
-
|
|
520
|
-
// Verify toast appears with proper ARIA attributes
|
|
521
|
-
await waitFor(() => {
|
|
522
|
-
const toast = canvas.getByText('Screen reader accessible toast');
|
|
523
|
-
expect(toast).toBeInTheDocument();
|
|
524
|
-
// Toast container should have proper role for screen readers
|
|
525
|
-
const toastContainer = toast.closest('[role="status"], [role="alert"]');
|
|
526
|
-
expect(toastContainer || toast.parentElement).toBeInTheDocument();
|
|
527
|
-
});
|
|
528
|
-
});
|
|
529
|
-
},
|
|
530
|
-
};
|
|
531
|
-
|
|
532
|
-
export const FocusManagement: Story = {
|
|
533
|
-
render: () => (
|
|
534
|
-
<TestWrapper>
|
|
535
|
-
<FocusManagementTest />
|
|
536
|
-
</TestWrapper>
|
|
537
|
-
),
|
|
538
|
-
play: async ({ canvasElement, step }) => {
|
|
539
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
540
|
-
const localCanvas = within(canvasElement);
|
|
541
|
-
|
|
542
|
-
await step('Test focus management with action buttons', async () => {
|
|
543
|
-
const focusBtn = localCanvas.getByTestId('focus-toast-btn');
|
|
544
|
-
const targetBtn = localCanvas.getByTestId('focus-target-btn');
|
|
545
|
-
|
|
546
|
-
await userEvent.click(focusBtn);
|
|
547
|
-
|
|
548
|
-
// Verify toast appears with action button
|
|
549
|
-
await waitFor(() => {
|
|
550
|
-
expect(canvas.getByText('Focus management test')).toBeInTheDocument();
|
|
551
|
-
expect(canvas.getByText('Focus Button')).toBeInTheDocument();
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
// Click the action button in the toast
|
|
555
|
-
const actionBtn = canvas.getByText('Focus Button');
|
|
556
|
-
await userEvent.click(actionBtn);
|
|
557
|
-
|
|
558
|
-
// Verify focus moved to target button
|
|
559
|
-
await waitFor(() => {
|
|
560
|
-
expect(targetBtn).toHaveFocus();
|
|
561
|
-
});
|
|
562
|
-
});
|
|
563
|
-
},
|
|
564
|
-
};
|
|
565
|
-
|
|
566
|
-
export const ResponsiveDesign: Story = {
|
|
567
|
-
render: () => (
|
|
568
|
-
<TestWrapper>
|
|
569
|
-
<ResponsiveDesignTest />
|
|
570
|
-
</TestWrapper>
|
|
571
|
-
),
|
|
572
|
-
parameters: {
|
|
573
|
-
viewport: { defaultViewport: 'mobile1' },
|
|
574
|
-
},
|
|
575
|
-
play: async ({ canvasElement, step }) => {
|
|
576
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
577
|
-
const localCanvas = within(canvasElement);
|
|
578
|
-
|
|
579
|
-
await step('Test responsive design and text wrapping', async () => {
|
|
580
|
-
const responsiveBtn = localCanvas.getByTestId('responsive-toast-btn');
|
|
581
|
-
await userEvent.click(responsiveBtn);
|
|
582
|
-
|
|
583
|
-
// Verify long text wraps properly
|
|
584
|
-
await waitFor(() => {
|
|
585
|
-
const toast = canvas.getByText(
|
|
586
|
-
'Responsive design test message that is quite long to test wrapping',
|
|
587
|
-
);
|
|
588
|
-
expect(toast).toBeInTheDocument();
|
|
589
|
-
|
|
590
|
-
// Check toast has max width constraint
|
|
591
|
-
const toastContainer = toast.closest('[class*="MuiBox"]');
|
|
592
|
-
if (toastContainer) {
|
|
593
|
-
const styles = window.getComputedStyle(toastContainer);
|
|
594
|
-
const maxWidth = styles.maxWidth;
|
|
595
|
-
if (maxWidth && maxWidth !== 'none') {
|
|
596
|
-
const parsedWidth = parseInt(maxWidth);
|
|
597
|
-
if (!isNaN(parsedWidth)) {
|
|
598
|
-
expect(parsedWidth).toBeLessThanOrEqual(400);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
});
|
|
603
|
-
});
|
|
604
|
-
},
|
|
605
|
-
};
|
|
606
|
-
|
|
607
|
-
export const ThemeVariations: Story = {
|
|
608
|
-
render: () => (
|
|
609
|
-
<TestWrapper>
|
|
610
|
-
<ThemeVariationsTest />
|
|
611
|
-
</TestWrapper>
|
|
612
|
-
),
|
|
613
|
-
play: async ({ canvasElement, step }) => {
|
|
614
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
615
|
-
const localCanvas = within(canvasElement);
|
|
616
|
-
|
|
617
|
-
await step('Test default theme', async () => {
|
|
618
|
-
const defaultBtn = localCanvas.getByTestId('default-theme-btn');
|
|
619
|
-
await userEvent.click(defaultBtn);
|
|
620
|
-
|
|
621
|
-
await waitFor(() => {
|
|
622
|
-
expect(canvas.getByText('Default theme toast')).toBeInTheDocument();
|
|
623
|
-
});
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
await step('Test glass theme with backdrop filter', async () => {
|
|
627
|
-
const glassBtn = localCanvas.getByTestId('glass-theme-btn');
|
|
628
|
-
await userEvent.click(glassBtn);
|
|
629
|
-
|
|
630
|
-
await waitFor(() => {
|
|
631
|
-
const glassToast = canvas.getByText('Glass theme toast');
|
|
632
|
-
expect(glassToast).toBeInTheDocument();
|
|
633
|
-
// Glass effect should have backdrop filter - check parent container with role
|
|
634
|
-
const toastContainer = glassToast.closest('[role="status"], [role="alert"]');
|
|
635
|
-
expect(toastContainer).toBeInTheDocument();
|
|
636
|
-
|
|
637
|
-
if (toastContainer) {
|
|
638
|
-
const styles = window.getComputedStyle(toastContainer);
|
|
639
|
-
const backdropFilter = styles.backdropFilter || (styles as CSSStyleDeclaration & Record<string, string>).webkitBackdropFilter;
|
|
640
|
-
|
|
641
|
-
// Glass variant should have glass characteristics - check multiple possible indicators
|
|
642
|
-
const hasBlur = backdropFilter && backdropFilter !== 'none' && backdropFilter.includes('blur');
|
|
643
|
-
const hasTransparentBg = styles.backgroundColor && (styles.backgroundColor.includes('rgba') ||
|
|
644
|
-
parseFloat(styles.opacity || '1') < 1);
|
|
645
|
-
const hasGlassBorder = styles.border && styles.border.includes('rgba');
|
|
646
|
-
|
|
647
|
-
// At least one glass effect should be present
|
|
648
|
-
const hasGlassEffect = hasBlur || hasTransparentBg || hasGlassBorder;
|
|
649
|
-
expect(hasGlassEffect).toBeTruthy();
|
|
650
|
-
}
|
|
651
|
-
});
|
|
652
|
-
});
|
|
653
|
-
|
|
654
|
-
await step('Test minimal theme and toast stacking', async () => {
|
|
655
|
-
const minimalBtn = localCanvas.getByTestId('minimal-theme-btn');
|
|
656
|
-
await userEvent.click(minimalBtn);
|
|
657
|
-
|
|
658
|
-
await waitFor(() => {
|
|
659
|
-
const minimalToast = canvas.getByText('Minimal theme toast');
|
|
660
|
-
expect(minimalToast).toBeInTheDocument();
|
|
661
|
-
});
|
|
662
|
-
|
|
663
|
-
// Verify multiple toasts are stacked
|
|
664
|
-
await waitFor(() => {
|
|
665
|
-
const allToasts = canvas.getAllByText(/theme toast/);
|
|
666
|
-
expect(allToasts.length).toBeGreaterThanOrEqual(3);
|
|
667
|
-
});
|
|
668
|
-
});
|
|
669
|
-
},
|
|
670
|
-
};
|
|
671
|
-
|
|
672
|
-
export const VisualStates: Story = {
|
|
673
|
-
render: () => (
|
|
674
|
-
<TestWrapper>
|
|
675
|
-
<VisualStatesTest />
|
|
676
|
-
</TestWrapper>
|
|
677
|
-
),
|
|
678
|
-
play: async ({ canvasElement, step }) => {
|
|
679
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
680
|
-
const localCanvas = within(canvasElement);
|
|
681
|
-
|
|
682
|
-
await step('Test persistent toast', async () => {
|
|
683
|
-
const persistentBtn = localCanvas.getByTestId('persistent-toast-btn');
|
|
684
|
-
await userEvent.click(persistentBtn);
|
|
685
|
-
|
|
686
|
-
await waitFor(() => {
|
|
687
|
-
expect(canvas.getByText('Persistent toast')).toBeInTheDocument();
|
|
688
|
-
});
|
|
689
|
-
});
|
|
690
|
-
|
|
691
|
-
await step('Test important toast styling', async () => {
|
|
692
|
-
const importantBtn = localCanvas.getByTestId('important-toast-btn');
|
|
693
|
-
await userEvent.click(importantBtn);
|
|
694
|
-
|
|
695
|
-
await waitFor(() => {
|
|
696
|
-
const importantToast = canvas.getByText('Important success');
|
|
697
|
-
expect(importantToast).toBeInTheDocument();
|
|
698
|
-
const styles = window.getComputedStyle(importantToast);
|
|
699
|
-
expect(parseInt(styles.fontWeight)).toBeGreaterThanOrEqual(600);
|
|
700
|
-
});
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
await step('Test toast with description', async () => {
|
|
704
|
-
const descriptionBtn = localCanvas.getByTestId('with-description-btn');
|
|
705
|
-
await userEvent.click(descriptionBtn);
|
|
706
|
-
|
|
707
|
-
await waitFor(() => {
|
|
708
|
-
expect(canvas.getByText('Error with description')).toBeInTheDocument();
|
|
709
|
-
expect(canvas.getByText('This is a detailed description of the error')).toBeInTheDocument();
|
|
710
|
-
});
|
|
711
|
-
});
|
|
712
|
-
|
|
713
|
-
await step('Verify persistent toast remains visible', async () => {
|
|
714
|
-
// Wait to verify persistent toast is still there after 2 seconds (reduced from 5 seconds)
|
|
715
|
-
await new Promise((resolve) => window.setTimeout(resolve, 2000));
|
|
716
|
-
expect(canvas.getByText('Persistent toast')).toBeInTheDocument();
|
|
717
|
-
});
|
|
718
|
-
},
|
|
719
|
-
};
|
|
720
|
-
|
|
721
|
-
export const Performance: Story = {
|
|
722
|
-
render: () => (
|
|
723
|
-
<TestWrapper>
|
|
724
|
-
<PerformanceTest />
|
|
725
|
-
</TestWrapper>
|
|
726
|
-
),
|
|
727
|
-
play: async ({ canvasElement, step }) => {
|
|
728
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
729
|
-
const localCanvas = within(canvasElement);
|
|
730
|
-
|
|
731
|
-
await step('Test performance with many toasts', async () => {
|
|
732
|
-
const manyToastsBtn = localCanvas.getByTestId('many-toasts-btn');
|
|
733
|
-
await userEvent.click(manyToastsBtn);
|
|
734
|
-
|
|
735
|
-
// Verify multiple toasts are created - check for any toast content
|
|
736
|
-
await waitFor(() => {
|
|
737
|
-
// Check for any of the created toasts (may be limited by max visible toasts)
|
|
738
|
-
const toastElements = canvasElement.ownerDocument.querySelectorAll('[role="status"], [role="alert"]');
|
|
739
|
-
expect(toastElements.length).toBeGreaterThan(0);
|
|
740
|
-
});
|
|
741
|
-
|
|
742
|
-
// Look for some of the toast messages that should exist
|
|
743
|
-
await waitFor(() => {
|
|
744
|
-
const hasToast1 = canvas.queryByText('Toast 1');
|
|
745
|
-
const hasToast10 = canvas.queryByText('Toast 10');
|
|
746
|
-
const hasToast5 = canvas.queryByText('Toast 5');
|
|
747
|
-
// At least one of the toasts should be visible
|
|
748
|
-
expect(hasToast1 || hasToast5 || hasToast10).toBeTruthy();
|
|
749
|
-
});
|
|
750
|
-
|
|
751
|
-
// Verify performance message appears (this is created after a timeout)
|
|
752
|
-
await waitFor(() => {
|
|
753
|
-
const perfMessage = canvas.queryByText(/Created 10 toasts in \d+ms/);
|
|
754
|
-
expect(perfMessage).toBeTruthy();
|
|
755
|
-
}, { timeout: 1000 });
|
|
756
|
-
});
|
|
757
|
-
|
|
758
|
-
await step('Clear all toasts and verify cleanup', async () => {
|
|
759
|
-
const clearBtn = localCanvas.getByTestId('clear-toasts-btn');
|
|
760
|
-
await userEvent.click(clearBtn);
|
|
761
|
-
|
|
762
|
-
// Verify all toasts are dismissed
|
|
763
|
-
await waitFor(
|
|
764
|
-
() => {
|
|
765
|
-
expect(canvas.queryByText('Toast 1')).not.toBeInTheDocument();
|
|
766
|
-
expect(canvas.queryByText('Toast 10')).not.toBeInTheDocument();
|
|
767
|
-
},
|
|
768
|
-
{ timeout: 2000 },
|
|
769
|
-
);
|
|
770
|
-
});
|
|
771
|
-
},
|
|
772
|
-
};
|
|
773
|
-
|
|
774
|
-
export const EdgeCases: Story = {
|
|
775
|
-
render: () => (
|
|
776
|
-
<TestWrapper>
|
|
777
|
-
<EdgeCasesTest />
|
|
778
|
-
</TestWrapper>
|
|
779
|
-
),
|
|
780
|
-
play: async ({ canvasElement, step }) => {
|
|
781
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
782
|
-
const localCanvas = within(canvasElement);
|
|
783
|
-
|
|
784
|
-
await step('Test empty toast', async () => {
|
|
785
|
-
const emptyBtn = localCanvas.getByTestId('empty-toast-btn');
|
|
786
|
-
await userEvent.click(emptyBtn);
|
|
787
|
-
|
|
788
|
-
// Empty toast might not have text, check for toast container presence
|
|
789
|
-
await waitFor(() => {
|
|
790
|
-
// Check if any toast containers exist by looking for elements with Collapse class
|
|
791
|
-
const toastElements = canvasElement.ownerDocument.querySelectorAll('[class*="Collapse"]');
|
|
792
|
-
expect(toastElements.length).toBeGreaterThan(0);
|
|
793
|
-
});
|
|
794
|
-
});
|
|
795
|
-
|
|
796
|
-
await step('Test long message toast', async () => {
|
|
797
|
-
const longBtn = localCanvas.getByTestId('long-toast-btn');
|
|
798
|
-
await userEvent.click(longBtn);
|
|
799
|
-
|
|
800
|
-
await waitFor(() => {
|
|
801
|
-
const longToast = canvas.getByText(/This is a very long toast message/);
|
|
802
|
-
expect(longToast).toBeInTheDocument();
|
|
803
|
-
// Verify toast has proper text wrapping constraints
|
|
804
|
-
const toastContainer = longToast.closest('[role="status"], [role="alert"]');
|
|
805
|
-
if (toastContainer) {
|
|
806
|
-
const styles = window.getComputedStyle(toastContainer);
|
|
807
|
-
// Check that container has max width constraint for proper wrapping
|
|
808
|
-
const maxWidth = styles.maxWidth;
|
|
809
|
-
expect(maxWidth).toBeTruthy();
|
|
810
|
-
expect(maxWidth).not.toBe('none');
|
|
811
|
-
}
|
|
812
|
-
});
|
|
813
|
-
});
|
|
814
|
-
|
|
815
|
-
await step('Test promise toast lifecycle', async () => {
|
|
816
|
-
const promiseBtn = localCanvas.getByTestId('promise-toast-btn');
|
|
817
|
-
await userEvent.click(promiseBtn);
|
|
818
|
-
|
|
819
|
-
// First, loading toast should appear
|
|
820
|
-
await waitFor(() => {
|
|
821
|
-
expect(canvas.getByText('Processing...')).toBeInTheDocument();
|
|
822
|
-
});
|
|
823
|
-
|
|
824
|
-
// After 2 seconds, success toast should replace loading
|
|
825
|
-
await waitFor(
|
|
826
|
-
() => {
|
|
827
|
-
expect(canvas.queryByText('Processing...')).not.toBeInTheDocument();
|
|
828
|
-
expect(canvas.getByText('Promise resolved!')).toBeInTheDocument();
|
|
829
|
-
},
|
|
830
|
-
{ timeout: 3000 },
|
|
831
|
-
);
|
|
832
|
-
});
|
|
833
|
-
},
|
|
834
|
-
};
|
|
835
|
-
|
|
836
|
-
export const Integration: Story = {
|
|
837
|
-
render: () => (
|
|
838
|
-
<TestWrapper>
|
|
839
|
-
<IntegrationTest />
|
|
840
|
-
</TestWrapper>
|
|
841
|
-
),
|
|
842
|
-
play: async ({ canvasElement, step }) => {
|
|
843
|
-
const canvas = within(canvasElement.ownerDocument.body);
|
|
844
|
-
const localCanvas = within(canvasElement);
|
|
845
|
-
|
|
846
|
-
await step('Run multi-step integration test', async () => {
|
|
847
|
-
const integrationBtn = localCanvas.getByTestId('integration-test-btn');
|
|
848
|
-
await userEvent.click(integrationBtn);
|
|
849
|
-
|
|
850
|
-
// Step 1: Starting toast
|
|
851
|
-
await waitFor(() => {
|
|
852
|
-
expect(canvas.getByText('Step 1: Starting integration test')).toBeInTheDocument();
|
|
853
|
-
expect(integrationBtn).toHaveTextContent('Run Integration Test (Step 1/4)');
|
|
854
|
-
});
|
|
855
|
-
|
|
856
|
-
// Step 2: Success toast
|
|
857
|
-
await waitFor(
|
|
858
|
-
() => {
|
|
859
|
-
expect(canvas.getByText('Step 2: First action completed')).toBeInTheDocument();
|
|
860
|
-
expect(integrationBtn).toHaveTextContent('Run Integration Test (Step 2/4)');
|
|
861
|
-
},
|
|
862
|
-
{ timeout: 2000 },
|
|
863
|
-
);
|
|
864
|
-
|
|
865
|
-
// Step 3: Error toast
|
|
866
|
-
await waitFor(
|
|
867
|
-
() => {
|
|
868
|
-
expect(canvas.getByText('Step 3: Simulated error occurred')).toBeInTheDocument();
|
|
869
|
-
expect(integrationBtn).toHaveTextContent('Run Integration Test (Step 3/4)');
|
|
870
|
-
},
|
|
871
|
-
{ timeout: 3000 },
|
|
872
|
-
);
|
|
873
|
-
|
|
874
|
-
// Step 4: Completion - wait longer for all steps to complete
|
|
875
|
-
await waitFor(
|
|
876
|
-
() => {
|
|
877
|
-
// Button should be re-enabled after completion
|
|
878
|
-
expect(integrationBtn).not.toBeDisabled();
|
|
879
|
-
expect(integrationBtn).toHaveTextContent('Run Integration Test');
|
|
880
|
-
},
|
|
881
|
-
{ timeout: 5000 },
|
|
882
|
-
);
|
|
883
|
-
|
|
884
|
-
// Check that final completion toast appeared (might be transient)
|
|
885
|
-
await waitFor(
|
|
886
|
-
() => {
|
|
887
|
-
const completionToast = canvas.queryByText('Step 4: Integration test completed');
|
|
888
|
-
// Test passes if either the toast is visible or the test has completed (button re-enabled)
|
|
889
|
-
const testCompleted = !integrationBtn.disabled && integrationBtn.textContent === 'Run Integration Test';
|
|
890
|
-
expect(completionToast || testCompleted).toBeTruthy();
|
|
891
|
-
},
|
|
892
|
-
{ timeout: 1000 },
|
|
893
|
-
);
|
|
894
|
-
});
|
|
895
|
-
},
|
|
896
|
-
};
|