@12-apps/ui 1.5.0 → 1.5.1
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 +16 -8
- 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,1343 +0,0 @@
|
|
|
1
|
-
import Dashboard from '@mui/icons-material/Dashboard';
|
|
2
|
-
import Home from '@mui/icons-material/Home';
|
|
3
|
-
import MenuIcon from '@mui/icons-material/Menu';
|
|
4
|
-
import Person from '@mui/icons-material/Person';
|
|
5
|
-
import Settings from '@mui/icons-material/Settings';
|
|
6
|
-
import {
|
|
7
|
-
Box,
|
|
8
|
-
Button,
|
|
9
|
-
IconButton,
|
|
10
|
-
List,
|
|
11
|
-
ListItemButton,
|
|
12
|
-
ListItemIcon,
|
|
13
|
-
ListItemText,
|
|
14
|
-
Stack,
|
|
15
|
-
Typography,
|
|
16
|
-
} from '@mui/material';
|
|
17
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
18
|
-
import { useState } from 'react';
|
|
19
|
-
import { expect, fn,userEvent, waitFor, within } from 'storybook/test';
|
|
20
|
-
|
|
21
|
-
import { Drawer, DrawerContent,DrawerHeader } from './Drawer';
|
|
22
|
-
|
|
23
|
-
const meta: Meta<typeof Drawer> = {
|
|
24
|
-
title: 'Layout/Drawer/Tests',
|
|
25
|
-
component: Drawer,
|
|
26
|
-
parameters: {
|
|
27
|
-
layout: 'fullscreen',
|
|
28
|
-
chromatic: { disableSnapshot: false },
|
|
29
|
-
},
|
|
30
|
-
tags: ['autodocs', 'test', 'component:Drawer'],
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export default meta;
|
|
34
|
-
type Story = StoryObj<typeof meta>;
|
|
35
|
-
|
|
36
|
-
// Basic Interaction Tests
|
|
37
|
-
export const BasicInteraction: Story = {
|
|
38
|
-
name: '🧪 Basic Interaction',
|
|
39
|
-
render: () => {
|
|
40
|
-
const BasicInteractionComponent = () => {
|
|
41
|
-
const [open, setOpen] = useState(false);
|
|
42
|
-
const [interactionState, setInteractionState] = useState('closed');
|
|
43
|
-
const handleOpen = fn(() => {
|
|
44
|
-
setOpen(true);
|
|
45
|
-
setInteractionState('opened');
|
|
46
|
-
});
|
|
47
|
-
const handleClose = fn(() => {
|
|
48
|
-
setOpen(false);
|
|
49
|
-
setInteractionState('closed');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<Box sx={{ height: '100vh', position: 'relative' }}>
|
|
54
|
-
<Button
|
|
55
|
-
data-testid="open-drawer-button"
|
|
56
|
-
onClick={handleOpen}
|
|
57
|
-
sx={{ position: 'fixed', top: 16, left: 16, zIndex: 1300 }}
|
|
58
|
-
>
|
|
59
|
-
Open Drawer
|
|
60
|
-
</Button>
|
|
61
|
-
<Typography data-testid="interaction-state" sx={{ position: 'fixed', top: 60, left: 16 }}>
|
|
62
|
-
State: {interactionState}
|
|
63
|
-
</Typography>
|
|
64
|
-
<Drawer open={open} onClose={handleClose} data-testid="drawer">
|
|
65
|
-
<DrawerHeader onClose={handleClose}>
|
|
66
|
-
<Typography variant="h6">Test Drawer</Typography>
|
|
67
|
-
</DrawerHeader>
|
|
68
|
-
<DrawerContent>
|
|
69
|
-
<List>
|
|
70
|
-
<ListItemButton data-testid="nav-item-home">
|
|
71
|
-
<ListItemIcon>
|
|
72
|
-
<Home />
|
|
73
|
-
</ListItemIcon>
|
|
74
|
-
<ListItemText primary="Home" />
|
|
75
|
-
</ListItemButton>
|
|
76
|
-
<ListItemButton data-testid="nav-item-settings">
|
|
77
|
-
<ListItemIcon>
|
|
78
|
-
<Settings />
|
|
79
|
-
</ListItemIcon>
|
|
80
|
-
<ListItemText primary="Settings" />
|
|
81
|
-
</ListItemButton>
|
|
82
|
-
</List>
|
|
83
|
-
</DrawerContent>
|
|
84
|
-
</Drawer>
|
|
85
|
-
</Box>
|
|
86
|
-
);
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
return <BasicInteractionComponent />;
|
|
90
|
-
},
|
|
91
|
-
play: async ({ canvasElement }) => {
|
|
92
|
-
const canvas = within(canvasElement);
|
|
93
|
-
|
|
94
|
-
// Test drawer opens
|
|
95
|
-
const openButton = canvas.getByTestId('open-drawer-button');
|
|
96
|
-
expect(openButton).toBeInTheDocument();
|
|
97
|
-
|
|
98
|
-
// Verify initial state
|
|
99
|
-
const stateIndicator = canvas.getByTestId('interaction-state');
|
|
100
|
-
expect(stateIndicator).toHaveTextContent('State: closed');
|
|
101
|
-
|
|
102
|
-
await userEvent.click(openButton);
|
|
103
|
-
|
|
104
|
-
// Verify state change after opening
|
|
105
|
-
await waitFor(() => {
|
|
106
|
-
expect(stateIndicator).toHaveTextContent('State: opened');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// Test that MUI backdrop is rendered (drawer is open)
|
|
110
|
-
await waitFor(() => {
|
|
111
|
-
const backdrop = document.querySelector('.MuiBackdrop-root');
|
|
112
|
-
expect(backdrop).toBeInTheDocument();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Test ESC key closes drawer
|
|
116
|
-
await userEvent.keyboard('{Escape}');
|
|
117
|
-
|
|
118
|
-
await waitFor(() => {
|
|
119
|
-
expect(stateIndicator).toHaveTextContent('State: closed');
|
|
120
|
-
});
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
// Keyboard Navigation Tests
|
|
125
|
-
export const KeyboardNavigation: Story = {
|
|
126
|
-
name: '⌨️ Keyboard Navigation',
|
|
127
|
-
render: () => {
|
|
128
|
-
const KeyboardNavigationComponent = () => {
|
|
129
|
-
const [open, setOpen] = useState(false);
|
|
130
|
-
const [keyboardState, setKeyboardState] = useState('ready');
|
|
131
|
-
const handleOpen = fn(() => setOpen(true));
|
|
132
|
-
const handleClose = fn(() => {
|
|
133
|
-
setOpen(false);
|
|
134
|
-
setKeyboardState('closed-by-escape');
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
return (
|
|
138
|
-
<Box sx={{ height: '100vh', position: 'relative' }}>
|
|
139
|
-
<Button
|
|
140
|
-
data-testid="kbd-open-button"
|
|
141
|
-
onClick={handleOpen}
|
|
142
|
-
sx={{ position: 'fixed', top: 16, left: 16, zIndex: 1300 }}
|
|
143
|
-
>
|
|
144
|
-
Open for Keyboard Test
|
|
145
|
-
</Button>
|
|
146
|
-
<Typography data-testid="keyboard-state" sx={{ position: 'fixed', top: 60, left: 16 }}>
|
|
147
|
-
Keyboard State: {keyboardState}
|
|
148
|
-
</Typography>
|
|
149
|
-
<Drawer open={open} onClose={handleClose} data-testid="keyboard-drawer">
|
|
150
|
-
<DrawerHeader onClose={handleClose}>
|
|
151
|
-
<Typography variant="h6">Keyboard Navigation</Typography>
|
|
152
|
-
</DrawerHeader>
|
|
153
|
-
<DrawerContent>
|
|
154
|
-
<List>
|
|
155
|
-
<ListItemButton data-testid="kbd-nav-home">
|
|
156
|
-
<ListItemIcon>
|
|
157
|
-
<Home />
|
|
158
|
-
</ListItemIcon>
|
|
159
|
-
<ListItemText primary="Home" />
|
|
160
|
-
</ListItemButton>
|
|
161
|
-
<ListItemButton data-testid="kbd-nav-dashboard">
|
|
162
|
-
<ListItemIcon>
|
|
163
|
-
<Dashboard />
|
|
164
|
-
</ListItemIcon>
|
|
165
|
-
<ListItemText primary="Dashboard" />
|
|
166
|
-
</ListItemButton>
|
|
167
|
-
<ListItemButton data-testid="kbd-nav-settings">
|
|
168
|
-
<ListItemIcon>
|
|
169
|
-
<Settings />
|
|
170
|
-
</ListItemIcon>
|
|
171
|
-
<ListItemText primary="Settings" />
|
|
172
|
-
</ListItemButton>
|
|
173
|
-
<ListItemButton data-testid="kbd-nav-profile">
|
|
174
|
-
<ListItemIcon>
|
|
175
|
-
<Person />
|
|
176
|
-
</ListItemIcon>
|
|
177
|
-
<ListItemText primary="Profile" />
|
|
178
|
-
</ListItemButton>
|
|
179
|
-
</List>
|
|
180
|
-
</DrawerContent>
|
|
181
|
-
</Drawer>
|
|
182
|
-
</Box>
|
|
183
|
-
);
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
return <KeyboardNavigationComponent />;
|
|
187
|
-
},
|
|
188
|
-
play: async ({ canvasElement }) => {
|
|
189
|
-
const canvas = within(canvasElement);
|
|
190
|
-
|
|
191
|
-
// Test opening drawer
|
|
192
|
-
const openButton = canvas.getByTestId('kbd-open-button');
|
|
193
|
-
expect(openButton).toBeInTheDocument();
|
|
194
|
-
|
|
195
|
-
await userEvent.click(openButton);
|
|
196
|
-
|
|
197
|
-
// Test that backdrop appears (drawer is open)
|
|
198
|
-
await waitFor(() => {
|
|
199
|
-
const backdrop = document.querySelector('.MuiBackdrop-root');
|
|
200
|
-
expect(backdrop).toBeInTheDocument();
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// Test Escape key closes drawer
|
|
204
|
-
await userEvent.keyboard('{Escape}');
|
|
205
|
-
|
|
206
|
-
await waitFor(() => {
|
|
207
|
-
const stateIndicator = canvas.getByTestId('keyboard-state');
|
|
208
|
-
expect(stateIndicator).toHaveTextContent('Keyboard State: closed-by-escape');
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
// Verify drawer is closed (no backdrop)
|
|
212
|
-
await waitFor(() => {
|
|
213
|
-
const backdrop = document.querySelector('.MuiBackdrop-root');
|
|
214
|
-
expect(backdrop).not.toBeInTheDocument();
|
|
215
|
-
});
|
|
216
|
-
},
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
// Screen Reader Accessibility Tests
|
|
220
|
-
export const ScreenReader: Story = {
|
|
221
|
-
name: '🔊 Screen Reader',
|
|
222
|
-
render: () => {
|
|
223
|
-
const ScreenReaderComponent = () => {
|
|
224
|
-
const [open, setOpen] = useState(true);
|
|
225
|
-
|
|
226
|
-
return (
|
|
227
|
-
<Box sx={{ height: '100vh', position: 'relative' }}>
|
|
228
|
-
<Drawer
|
|
229
|
-
open={open}
|
|
230
|
-
onClose={() => setOpen(false)}
|
|
231
|
-
data-testid="sr-drawer"
|
|
232
|
-
aria-labelledby="drawer-title"
|
|
233
|
-
role="navigation"
|
|
234
|
-
>
|
|
235
|
-
<DrawerHeader onClose={() => setOpen(false)}>
|
|
236
|
-
<Typography id="drawer-title" variant="h6">
|
|
237
|
-
Main Navigation
|
|
238
|
-
</Typography>
|
|
239
|
-
</DrawerHeader>
|
|
240
|
-
<DrawerContent>
|
|
241
|
-
<List role="menu" aria-labelledby="drawer-title">
|
|
242
|
-
<ListItemButton role="menuitem" data-testid="sr-nav-home">
|
|
243
|
-
<ListItemIcon aria-hidden="true">
|
|
244
|
-
<Home />
|
|
245
|
-
</ListItemIcon>
|
|
246
|
-
<ListItemText primary="Home" />
|
|
247
|
-
</ListItemButton>
|
|
248
|
-
<ListItemButton role="menuitem" data-testid="sr-nav-dashboard">
|
|
249
|
-
<ListItemIcon aria-hidden="true">
|
|
250
|
-
<Dashboard />
|
|
251
|
-
</ListItemIcon>
|
|
252
|
-
<ListItemText primary="Dashboard" />
|
|
253
|
-
</ListItemButton>
|
|
254
|
-
<ListItemButton role="menuitem" data-testid="sr-nav-settings">
|
|
255
|
-
<ListItemIcon aria-hidden="true">
|
|
256
|
-
<Settings />
|
|
257
|
-
</ListItemIcon>
|
|
258
|
-
<ListItemText primary="Settings" />
|
|
259
|
-
</ListItemButton>
|
|
260
|
-
</List>
|
|
261
|
-
</DrawerContent>
|
|
262
|
-
</Drawer>
|
|
263
|
-
</Box>
|
|
264
|
-
);
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
return <ScreenReaderComponent />;
|
|
268
|
-
},
|
|
269
|
-
play: async () => {
|
|
270
|
-
// Wait for drawer to be rendered (check for backdrop first, then content)
|
|
271
|
-
await waitFor(
|
|
272
|
-
() => {
|
|
273
|
-
const backdrop = document.querySelector('.MuiBackdrop-root');
|
|
274
|
-
expect(backdrop).toBeInTheDocument();
|
|
275
|
-
},
|
|
276
|
-
{ timeout: 5000 },
|
|
277
|
-
);
|
|
278
|
-
|
|
279
|
-
await waitFor(
|
|
280
|
-
() => {
|
|
281
|
-
const title = document.querySelector('h6');
|
|
282
|
-
expect(title).toBeInTheDocument();
|
|
283
|
-
expect(title).toHaveTextContent('Main Navigation');
|
|
284
|
-
},
|
|
285
|
-
{ timeout: 5000 },
|
|
286
|
-
);
|
|
287
|
-
|
|
288
|
-
// Test ARIA attributes on the drawer (look in document since MUI renders in portal)
|
|
289
|
-
const drawer = document.querySelector('[data-testid="sr-drawer"]');
|
|
290
|
-
expect(drawer).toBeInTheDocument();
|
|
291
|
-
expect(drawer).toHaveAttribute('role', 'navigation');
|
|
292
|
-
expect(drawer).toHaveAttribute('aria-labelledby', 'drawer-title');
|
|
293
|
-
|
|
294
|
-
// Test drawer title
|
|
295
|
-
const title = document.querySelector('#drawer-title');
|
|
296
|
-
expect(title).toBeInTheDocument();
|
|
297
|
-
expect(title).toHaveTextContent('Main Navigation');
|
|
298
|
-
|
|
299
|
-
// Test navigation list
|
|
300
|
-
const navList = document.querySelector('[role="menu"]');
|
|
301
|
-
expect(navList).toBeInTheDocument();
|
|
302
|
-
expect(navList).toHaveAttribute('aria-labelledby', 'drawer-title');
|
|
303
|
-
|
|
304
|
-
// Test menu items
|
|
305
|
-
const menuItems = document.querySelectorAll('[role="menuitem"]');
|
|
306
|
-
expect(menuItems).toHaveLength(3);
|
|
307
|
-
|
|
308
|
-
// Test icons are hidden from screen readers
|
|
309
|
-
const icons = document.querySelectorAll('[aria-hidden="true"]');
|
|
310
|
-
expect(icons.length).toBeGreaterThan(0);
|
|
311
|
-
|
|
312
|
-
// Test close button accessibility
|
|
313
|
-
const closeButton = document.querySelector('button[aria-label*="close" i]');
|
|
314
|
-
expect(closeButton).toBeInTheDocument();
|
|
315
|
-
},
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
// Focus Management Tests
|
|
319
|
-
export const FocusManagement: Story = {
|
|
320
|
-
name: '🎯 Focus Management',
|
|
321
|
-
render: () => {
|
|
322
|
-
const FocusManagementComponent = () => {
|
|
323
|
-
const [open, setOpen] = useState(false);
|
|
324
|
-
|
|
325
|
-
return (
|
|
326
|
-
<Box sx={{ height: '100vh', position: 'relative' }}>
|
|
327
|
-
<Button
|
|
328
|
-
data-testid="focus-open-button"
|
|
329
|
-
onClick={() => setOpen(true)}
|
|
330
|
-
sx={{ position: 'fixed', top: 16, left: 16, zIndex: 1300 }}
|
|
331
|
-
>
|
|
332
|
-
Open Drawer
|
|
333
|
-
</Button>
|
|
334
|
-
<Drawer
|
|
335
|
-
open={open}
|
|
336
|
-
onClose={() => setOpen(false)}
|
|
337
|
-
data-testid="focus-drawer"
|
|
338
|
-
keepMounted={false}
|
|
339
|
-
>
|
|
340
|
-
<DrawerHeader onClose={() => setOpen(false)}>
|
|
341
|
-
<Typography variant="h6">Focus Test</Typography>
|
|
342
|
-
</DrawerHeader>
|
|
343
|
-
<DrawerContent>
|
|
344
|
-
<List>
|
|
345
|
-
<ListItemButton data-testid="focus-first-item">
|
|
346
|
-
<ListItemIcon>
|
|
347
|
-
<Home />
|
|
348
|
-
</ListItemIcon>
|
|
349
|
-
<ListItemText primary="First Item" />
|
|
350
|
-
</ListItemButton>
|
|
351
|
-
<ListItemButton data-testid="focus-second-item">
|
|
352
|
-
<ListItemIcon>
|
|
353
|
-
<Dashboard />
|
|
354
|
-
</ListItemIcon>
|
|
355
|
-
<ListItemText primary="Second Item" />
|
|
356
|
-
</ListItemButton>
|
|
357
|
-
</List>
|
|
358
|
-
</DrawerContent>
|
|
359
|
-
</Drawer>
|
|
360
|
-
<Box sx={{ p: 3, pt: 10 }}>
|
|
361
|
-
<Button data-testid="focus-main-button">Main Content Button</Button>
|
|
362
|
-
</Box>
|
|
363
|
-
</Box>
|
|
364
|
-
);
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
return <FocusManagementComponent />;
|
|
368
|
-
},
|
|
369
|
-
play: async ({ canvasElement }) => {
|
|
370
|
-
const canvas = within(canvasElement);
|
|
371
|
-
|
|
372
|
-
// Test initial focus on main content
|
|
373
|
-
const mainButton = canvas.getByTestId('focus-main-button');
|
|
374
|
-
const openButton = canvas.getByTestId('focus-open-button');
|
|
375
|
-
|
|
376
|
-
// Click to focus rather than calling .focus(): the button carries no handler,
|
|
377
|
-
// so a click only moves focus — and it is how a user would land there. This
|
|
378
|
-
// is the starting point the "focus returns on close" check below relies on.
|
|
379
|
-
await userEvent.click(mainButton);
|
|
380
|
-
await waitFor(() => expect(document.activeElement).toBe(mainButton));
|
|
381
|
-
|
|
382
|
-
// Open drawer
|
|
383
|
-
await userEvent.click(openButton);
|
|
384
|
-
|
|
385
|
-
await waitFor(() => {
|
|
386
|
-
const drawerContent = document.querySelector('h6');
|
|
387
|
-
expect(drawerContent).toBeInTheDocument();
|
|
388
|
-
expect(drawerContent).toHaveTextContent('Focus Test');
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
// Test focus trap within drawer
|
|
392
|
-
const firstItem = document.querySelector('[data-testid="focus-first-item"]');
|
|
393
|
-
const secondItem = document.querySelector('[data-testid="focus-second-item"]');
|
|
394
|
-
const closeButton = document.querySelector('button[aria-label*="close" i]');
|
|
395
|
-
|
|
396
|
-
// Tab through drawer elements
|
|
397
|
-
expect(firstItem).toBeInTheDocument();
|
|
398
|
-
expect(secondItem).toBeInTheDocument();
|
|
399
|
-
expect(closeButton).toBeInTheDocument();
|
|
400
|
-
|
|
401
|
-
await userEvent.click(firstItem);
|
|
402
|
-
await waitFor(() => expect(document.activeElement).toBe(firstItem));
|
|
403
|
-
|
|
404
|
-
await userEvent.tab();
|
|
405
|
-
await waitFor(() => expect(document.activeElement).toBe(secondItem));
|
|
406
|
-
|
|
407
|
-
await userEvent.tab();
|
|
408
|
-
await waitFor(() => expect(document.activeElement).toBe(closeButton));
|
|
409
|
-
|
|
410
|
-
// Close drawer and verify focus returns
|
|
411
|
-
await userEvent.click(closeButton);
|
|
412
|
-
|
|
413
|
-
await waitFor(() => {
|
|
414
|
-
expect(document.querySelector('h6')).not.toBeInTheDocument();
|
|
415
|
-
});
|
|
416
|
-
},
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
// Responsive Design Tests
|
|
420
|
-
export const ResponsiveDesign: Story = {
|
|
421
|
-
name: '📱 Responsive Design',
|
|
422
|
-
render: () => {
|
|
423
|
-
const ResponsiveComponent = () => {
|
|
424
|
-
const [open, setOpen] = useState(true);
|
|
425
|
-
|
|
426
|
-
return (
|
|
427
|
-
<Box sx={{ height: '100vh', position: 'relative' }}>
|
|
428
|
-
<Drawer
|
|
429
|
-
open={open}
|
|
430
|
-
onClose={() => setOpen(false)}
|
|
431
|
-
data-testid="responsive-drawer"
|
|
432
|
-
width={280}
|
|
433
|
-
>
|
|
434
|
-
<DrawerHeader onClose={() => setOpen(false)}>
|
|
435
|
-
<Typography variant="h6">Responsive Drawer</Typography>
|
|
436
|
-
</DrawerHeader>
|
|
437
|
-
<DrawerContent>
|
|
438
|
-
<Typography variant="body2" sx={{ p: 2 }}>
|
|
439
|
-
This drawer should adapt to different screen sizes.
|
|
440
|
-
</Typography>
|
|
441
|
-
<List>
|
|
442
|
-
<ListItemButton>
|
|
443
|
-
<ListItemIcon>
|
|
444
|
-
<Home />
|
|
445
|
-
</ListItemIcon>
|
|
446
|
-
<ListItemText primary="Home" />
|
|
447
|
-
</ListItemButton>
|
|
448
|
-
<ListItemButton>
|
|
449
|
-
<ListItemIcon>
|
|
450
|
-
<Settings />
|
|
451
|
-
</ListItemIcon>
|
|
452
|
-
<ListItemText primary="Settings" />
|
|
453
|
-
</ListItemButton>
|
|
454
|
-
</List>
|
|
455
|
-
</DrawerContent>
|
|
456
|
-
</Drawer>
|
|
457
|
-
</Box>
|
|
458
|
-
);
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
return <ResponsiveComponent />;
|
|
462
|
-
},
|
|
463
|
-
parameters: {
|
|
464
|
-
viewport: {
|
|
465
|
-
viewports: {
|
|
466
|
-
mobile: { name: 'Mobile', styles: { width: '375px', height: '667px' } },
|
|
467
|
-
tablet: { name: 'Tablet', styles: { width: '768px', height: '1024px' } },
|
|
468
|
-
desktop: { name: 'Desktop', styles: { width: '1024px', height: '768px' } },
|
|
469
|
-
},
|
|
470
|
-
},
|
|
471
|
-
},
|
|
472
|
-
play: async () => {
|
|
473
|
-
// Wait for drawer to be rendered
|
|
474
|
-
await waitFor(
|
|
475
|
-
() => {
|
|
476
|
-
const backdrop = document.querySelector('.MuiBackdrop-root');
|
|
477
|
-
expect(backdrop).toBeInTheDocument();
|
|
478
|
-
},
|
|
479
|
-
{ timeout: 5000 },
|
|
480
|
-
);
|
|
481
|
-
|
|
482
|
-
// Test drawer renders properly (look in document since MUI renders in portal)
|
|
483
|
-
const drawer = document.querySelector('[data-testid="responsive-drawer"]');
|
|
484
|
-
expect(drawer).toBeInTheDocument();
|
|
485
|
-
const drawerPaper = drawer.querySelector('.MuiDrawer-paper');
|
|
486
|
-
expect(drawerPaper).toBeInTheDocument();
|
|
487
|
-
|
|
488
|
-
// Test drawer content is accessible (look in document since it's in portal)
|
|
489
|
-
await waitFor(() => {
|
|
490
|
-
const title = document.querySelector('h6');
|
|
491
|
-
expect(title).toBeInTheDocument();
|
|
492
|
-
expect(title).toHaveTextContent('Responsive Drawer');
|
|
493
|
-
});
|
|
494
|
-
|
|
495
|
-
const description = Array.from(document.querySelectorAll('*')).find((el) =>
|
|
496
|
-
el.textContent?.includes('This drawer should adapt to different screen sizes'),
|
|
497
|
-
);
|
|
498
|
-
expect(description).toBeInTheDocument();
|
|
499
|
-
|
|
500
|
-
// Test navigation items are present
|
|
501
|
-
const homeItem = Array.from(document.querySelectorAll('*')).find(
|
|
502
|
-
(el) => el.textContent === 'Home',
|
|
503
|
-
);
|
|
504
|
-
const settingsItem = Array.from(document.querySelectorAll('*')).find(
|
|
505
|
-
(el) => el.textContent === 'Settings',
|
|
506
|
-
);
|
|
507
|
-
|
|
508
|
-
expect(homeItem).toBeInTheDocument();
|
|
509
|
-
expect(settingsItem).toBeInTheDocument();
|
|
510
|
-
},
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
// Theme Variations Tests
|
|
514
|
-
export const ThemeVariations: Story = {
|
|
515
|
-
name: '🎨 Theme Variations',
|
|
516
|
-
render: () => {
|
|
517
|
-
const ThemeVariationsComponent = () => {
|
|
518
|
-
const [openDrawers, setOpenDrawers] = useState({
|
|
519
|
-
default: true,
|
|
520
|
-
glass: false,
|
|
521
|
-
});
|
|
522
|
-
|
|
523
|
-
const toggleDrawer = (type: keyof typeof openDrawers) => {
|
|
524
|
-
setOpenDrawers((prev) => ({ ...prev, [type]: !prev[type] }));
|
|
525
|
-
};
|
|
526
|
-
|
|
527
|
-
return (
|
|
528
|
-
<Box sx={{ height: '100vh', position: 'relative' }}>
|
|
529
|
-
<Stack direction="row" spacing={2} sx={{ p: 2, zIndex: 1300, position: 'relative' }}>
|
|
530
|
-
<Button
|
|
531
|
-
variant="outlined"
|
|
532
|
-
onClick={() => toggleDrawer('glass')}
|
|
533
|
-
data-testid="theme-glass-button"
|
|
534
|
-
>
|
|
535
|
-
Toggle Glass Theme
|
|
536
|
-
</Button>
|
|
537
|
-
</Stack>
|
|
538
|
-
|
|
539
|
-
{/* Default Theme Drawer */}
|
|
540
|
-
<Drawer
|
|
541
|
-
open={openDrawers.default}
|
|
542
|
-
onClose={() => toggleDrawer('default')}
|
|
543
|
-
data-testid="theme-default-drawer"
|
|
544
|
-
width={280}
|
|
545
|
-
>
|
|
546
|
-
<DrawerHeader onClose={() => toggleDrawer('default')}>
|
|
547
|
-
<Typography variant="h6">Default Theme</Typography>
|
|
548
|
-
</DrawerHeader>
|
|
549
|
-
<DrawerContent>
|
|
550
|
-
<Typography variant="body2" sx={{ p: 2 }}>
|
|
551
|
-
This drawer uses the default theme styling.
|
|
552
|
-
</Typography>
|
|
553
|
-
<List>
|
|
554
|
-
<ListItemButton>
|
|
555
|
-
<ListItemIcon>
|
|
556
|
-
<Home />
|
|
557
|
-
</ListItemIcon>
|
|
558
|
-
<ListItemText primary="Home" />
|
|
559
|
-
</ListItemButton>
|
|
560
|
-
</List>
|
|
561
|
-
</DrawerContent>
|
|
562
|
-
</Drawer>
|
|
563
|
-
|
|
564
|
-
{/* Glass Theme Drawer */}
|
|
565
|
-
<Drawer
|
|
566
|
-
open={openDrawers.glass}
|
|
567
|
-
onClose={() => toggleDrawer('glass')}
|
|
568
|
-
data-testid="theme-glass-drawer"
|
|
569
|
-
variant="glass"
|
|
570
|
-
width={300}
|
|
571
|
-
>
|
|
572
|
-
<DrawerHeader onClose={() => toggleDrawer('glass')}>
|
|
573
|
-
<Typography variant="h6">Glass Theme</Typography>
|
|
574
|
-
</DrawerHeader>
|
|
575
|
-
<DrawerContent>
|
|
576
|
-
<Typography variant="body2" sx={{ p: 2 }}>
|
|
577
|
-
This drawer uses glass morphism styling with backdrop blur.
|
|
578
|
-
</Typography>
|
|
579
|
-
<List>
|
|
580
|
-
<ListItemButton>
|
|
581
|
-
<ListItemIcon>
|
|
582
|
-
<Settings />
|
|
583
|
-
</ListItemIcon>
|
|
584
|
-
<ListItemText primary="Settings" />
|
|
585
|
-
</ListItemButton>
|
|
586
|
-
</List>
|
|
587
|
-
</DrawerContent>
|
|
588
|
-
</Drawer>
|
|
589
|
-
</Box>
|
|
590
|
-
);
|
|
591
|
-
};
|
|
592
|
-
|
|
593
|
-
return <ThemeVariationsComponent />;
|
|
594
|
-
},
|
|
595
|
-
play: async ({ canvasElement }) => {
|
|
596
|
-
const canvas = within(canvasElement);
|
|
597
|
-
|
|
598
|
-
// Wait for default theme drawer to render
|
|
599
|
-
await waitFor(
|
|
600
|
-
() => {
|
|
601
|
-
const backdrop = document.querySelector('.MuiBackdrop-root');
|
|
602
|
-
expect(backdrop).toBeInTheDocument();
|
|
603
|
-
},
|
|
604
|
-
{ timeout: 5000 },
|
|
605
|
-
);
|
|
606
|
-
|
|
607
|
-
// Test default theme drawer (look in document since MUI renders in portal)
|
|
608
|
-
const defaultDrawer = document.querySelector('[data-testid="theme-default-drawer"]');
|
|
609
|
-
expect(defaultDrawer).toBeInTheDocument();
|
|
610
|
-
|
|
611
|
-
await waitFor(() => {
|
|
612
|
-
const defaultTitle = document.querySelector('h6');
|
|
613
|
-
expect(defaultTitle).toBeInTheDocument();
|
|
614
|
-
expect(defaultTitle).toHaveTextContent('Default Theme');
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
// Test glass theme toggle
|
|
618
|
-
const glassButton = canvas.getByTestId('theme-glass-button');
|
|
619
|
-
await userEvent.click(glassButton);
|
|
620
|
-
|
|
621
|
-
await waitFor(() => {
|
|
622
|
-
const glassDrawer = document.querySelector('[data-testid="theme-glass-drawer"]');
|
|
623
|
-
expect(glassDrawer).toBeInTheDocument();
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
await waitFor(() => {
|
|
627
|
-
const glassDrawer = document.querySelector('[data-testid="theme-glass-drawer"]');
|
|
628
|
-
expect(glassDrawer).toBeInTheDocument();
|
|
629
|
-
const glassTitle = glassDrawer.querySelector('h6');
|
|
630
|
-
expect(glassTitle).toBeInTheDocument();
|
|
631
|
-
expect(glassTitle).toHaveTextContent('Glass Theme');
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
// Test glass drawer styling
|
|
635
|
-
const glassDrawerElement = document.querySelector('[data-testid="theme-glass-drawer"]');
|
|
636
|
-
const glassDrawerPaper = glassDrawerElement.querySelector('.MuiDrawer-paper');
|
|
637
|
-
expect(glassDrawerPaper).toBeInTheDocument();
|
|
638
|
-
},
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
// Visual States Tests
|
|
642
|
-
export const VisualStates: Story = {
|
|
643
|
-
name: '👁️ Visual States',
|
|
644
|
-
render: () => {
|
|
645
|
-
const VisualStatesComponent = () => {
|
|
646
|
-
const [states, setStates] = useState({
|
|
647
|
-
left: true,
|
|
648
|
-
right: false,
|
|
649
|
-
top: false,
|
|
650
|
-
bottom: false,
|
|
651
|
-
});
|
|
652
|
-
|
|
653
|
-
const toggleState = (state: keyof typeof states) => {
|
|
654
|
-
setStates((prev) => ({ ...prev, [state]: !prev[state] }));
|
|
655
|
-
};
|
|
656
|
-
|
|
657
|
-
return (
|
|
658
|
-
<Box sx={{ height: '100vh', position: 'relative' }}>
|
|
659
|
-
<Stack direction="row" spacing={1} sx={{ p: 2, zIndex: 1300, position: 'relative' }}>
|
|
660
|
-
<Button
|
|
661
|
-
size="small"
|
|
662
|
-
onClick={() => toggleState('right')}
|
|
663
|
-
data-testid="visual-right-btn"
|
|
664
|
-
>
|
|
665
|
-
Right
|
|
666
|
-
</Button>
|
|
667
|
-
<Button size="small" onClick={() => toggleState('top')} data-testid="visual-top-btn">
|
|
668
|
-
Top
|
|
669
|
-
</Button>
|
|
670
|
-
<Button
|
|
671
|
-
size="small"
|
|
672
|
-
onClick={() => toggleState('bottom')}
|
|
673
|
-
data-testid="visual-bottom-btn"
|
|
674
|
-
>
|
|
675
|
-
Bottom
|
|
676
|
-
</Button>
|
|
677
|
-
</Stack>
|
|
678
|
-
|
|
679
|
-
{/* Left Drawer */}
|
|
680
|
-
<Drawer
|
|
681
|
-
open={states.left}
|
|
682
|
-
onClose={() => toggleState('left')}
|
|
683
|
-
variant="left"
|
|
684
|
-
data-testid="visual-left-drawer"
|
|
685
|
-
>
|
|
686
|
-
<DrawerHeader onClose={() => toggleState('left')}>
|
|
687
|
-
<Typography variant="h6">Left Drawer</Typography>
|
|
688
|
-
</DrawerHeader>
|
|
689
|
-
<DrawerContent>
|
|
690
|
-
<Typography variant="body2">Left side content</Typography>
|
|
691
|
-
</DrawerContent>
|
|
692
|
-
</Drawer>
|
|
693
|
-
|
|
694
|
-
{/* Right Drawer */}
|
|
695
|
-
<Drawer
|
|
696
|
-
open={states.right}
|
|
697
|
-
onClose={() => toggleState('right')}
|
|
698
|
-
variant="right"
|
|
699
|
-
data-testid="visual-right-drawer"
|
|
700
|
-
>
|
|
701
|
-
<DrawerHeader onClose={() => toggleState('right')}>
|
|
702
|
-
<Typography variant="h6">Right Drawer</Typography>
|
|
703
|
-
</DrawerHeader>
|
|
704
|
-
<DrawerContent>
|
|
705
|
-
<Typography variant="body2">Right side content</Typography>
|
|
706
|
-
</DrawerContent>
|
|
707
|
-
</Drawer>
|
|
708
|
-
|
|
709
|
-
{/* Top Drawer */}
|
|
710
|
-
<Drawer
|
|
711
|
-
open={states.top}
|
|
712
|
-
onClose={() => toggleState('top')}
|
|
713
|
-
variant="top"
|
|
714
|
-
height={200}
|
|
715
|
-
data-testid="visual-top-drawer"
|
|
716
|
-
>
|
|
717
|
-
<DrawerHeader onClose={() => toggleState('top')}>
|
|
718
|
-
<Typography variant="h6">Top Drawer</Typography>
|
|
719
|
-
</DrawerHeader>
|
|
720
|
-
<DrawerContent>
|
|
721
|
-
<Typography variant="body2">Top content</Typography>
|
|
722
|
-
</DrawerContent>
|
|
723
|
-
</Drawer>
|
|
724
|
-
|
|
725
|
-
{/* Bottom Drawer */}
|
|
726
|
-
<Drawer
|
|
727
|
-
open={states.bottom}
|
|
728
|
-
onClose={() => toggleState('bottom')}
|
|
729
|
-
variant="bottom"
|
|
730
|
-
height={200}
|
|
731
|
-
data-testid="visual-bottom-drawer"
|
|
732
|
-
>
|
|
733
|
-
<DrawerHeader onClose={() => toggleState('bottom')}>
|
|
734
|
-
<Typography variant="h6">Bottom Drawer</Typography>
|
|
735
|
-
</DrawerHeader>
|
|
736
|
-
<DrawerContent>
|
|
737
|
-
<Typography variant="body2">Bottom content</Typography>
|
|
738
|
-
</DrawerContent>
|
|
739
|
-
</Drawer>
|
|
740
|
-
</Box>
|
|
741
|
-
);
|
|
742
|
-
};
|
|
743
|
-
|
|
744
|
-
return <VisualStatesComponent />;
|
|
745
|
-
},
|
|
746
|
-
play: async ({ canvasElement }) => {
|
|
747
|
-
const canvas = within(canvasElement);
|
|
748
|
-
|
|
749
|
-
// Wait for left drawer to render (initially open)
|
|
750
|
-
await waitFor(
|
|
751
|
-
() => {
|
|
752
|
-
const backdrop = document.querySelector('.MuiBackdrop-root');
|
|
753
|
-
expect(backdrop).toBeInTheDocument();
|
|
754
|
-
},
|
|
755
|
-
{ timeout: 5000 },
|
|
756
|
-
);
|
|
757
|
-
|
|
758
|
-
// Test left drawer (initially open) - look in document since MUI renders in portal
|
|
759
|
-
const leftDrawer = document.querySelector('[data-testid="visual-left-drawer"]');
|
|
760
|
-
expect(leftDrawer).toBeInTheDocument();
|
|
761
|
-
|
|
762
|
-
await waitFor(() => {
|
|
763
|
-
const leftTitle = leftDrawer.querySelector('h6');
|
|
764
|
-
expect(leftTitle).toBeInTheDocument();
|
|
765
|
-
expect(leftTitle).toHaveTextContent('Left Drawer');
|
|
766
|
-
});
|
|
767
|
-
|
|
768
|
-
// Test right drawer toggle
|
|
769
|
-
const rightButton = canvas.getByTestId('visual-right-btn');
|
|
770
|
-
await userEvent.click(rightButton);
|
|
771
|
-
|
|
772
|
-
await waitFor(() => {
|
|
773
|
-
const rightDrawer = document.querySelector('[data-testid="visual-right-drawer"]');
|
|
774
|
-
expect(rightDrawer).toBeInTheDocument();
|
|
775
|
-
const rightTitle = rightDrawer.querySelector('h6');
|
|
776
|
-
expect(rightTitle).toBeInTheDocument();
|
|
777
|
-
expect(rightTitle).toHaveTextContent('Right Drawer');
|
|
778
|
-
});
|
|
779
|
-
|
|
780
|
-
// Test top drawer toggle
|
|
781
|
-
const topButton = canvas.getByTestId('visual-top-btn');
|
|
782
|
-
await userEvent.click(topButton);
|
|
783
|
-
|
|
784
|
-
await waitFor(() => {
|
|
785
|
-
const topDrawer = document.querySelector('[data-testid="visual-top-drawer"]');
|
|
786
|
-
expect(topDrawer).toBeInTheDocument();
|
|
787
|
-
const topTitle = topDrawer.querySelector('h6');
|
|
788
|
-
expect(topTitle).toBeInTheDocument();
|
|
789
|
-
expect(topTitle).toHaveTextContent('Top Drawer');
|
|
790
|
-
});
|
|
791
|
-
|
|
792
|
-
// Test bottom drawer toggle
|
|
793
|
-
const bottomButton = canvas.getByTestId('visual-bottom-btn');
|
|
794
|
-
await userEvent.click(bottomButton);
|
|
795
|
-
|
|
796
|
-
await waitFor(() => {
|
|
797
|
-
const bottomDrawer = document.querySelector('[data-testid="visual-bottom-drawer"]');
|
|
798
|
-
expect(bottomDrawer).toBeInTheDocument();
|
|
799
|
-
const bottomTitle = bottomDrawer.querySelector('h6');
|
|
800
|
-
expect(bottomTitle).toBeInTheDocument();
|
|
801
|
-
expect(bottomTitle).toHaveTextContent('Bottom Drawer');
|
|
802
|
-
});
|
|
803
|
-
},
|
|
804
|
-
};
|
|
805
|
-
|
|
806
|
-
// Performance Tests
|
|
807
|
-
export const Performance: Story = {
|
|
808
|
-
name: '⚡ Performance',
|
|
809
|
-
render: () => {
|
|
810
|
-
const PerformanceComponent = () => {
|
|
811
|
-
const [open, setOpen] = useState(true);
|
|
812
|
-
const [itemCount, setItemCount] = useState(50);
|
|
813
|
-
|
|
814
|
-
// Generate large list of items
|
|
815
|
-
const items = Array.from({ length: itemCount }, (_, i) => ({
|
|
816
|
-
id: i,
|
|
817
|
-
label: `Item ${i + 1}`,
|
|
818
|
-
icon: i % 3 === 0 ? <Home /> : i % 3 === 1 ? <Settings /> : <Person />,
|
|
819
|
-
}));
|
|
820
|
-
|
|
821
|
-
return (
|
|
822
|
-
<Box sx={{ height: '100vh', position: 'relative' }}>
|
|
823
|
-
<Stack direction="row" spacing={2} sx={{ p: 2, zIndex: 1300, position: 'relative' }}>
|
|
824
|
-
<Button size="small" onClick={() => setItemCount(100)} data-testid="perf-100-items">
|
|
825
|
-
100 Items
|
|
826
|
-
</Button>
|
|
827
|
-
<Button size="small" onClick={() => setItemCount(200)} data-testid="perf-200-items">
|
|
828
|
-
200 Items
|
|
829
|
-
</Button>
|
|
830
|
-
</Stack>
|
|
831
|
-
|
|
832
|
-
<Drawer
|
|
833
|
-
open={open}
|
|
834
|
-
onClose={() => setOpen(false)}
|
|
835
|
-
data-testid="performance-drawer"
|
|
836
|
-
keepMounted={true}
|
|
837
|
-
>
|
|
838
|
-
<DrawerHeader onClose={() => setOpen(false)}>
|
|
839
|
-
<Typography variant="h6">Performance Test ({itemCount} items)</Typography>
|
|
840
|
-
</DrawerHeader>
|
|
841
|
-
<DrawerContent>
|
|
842
|
-
<List data-testid="performance-list">
|
|
843
|
-
{items.map((item) => (
|
|
844
|
-
<ListItemButton key={item.id} data-testid={`perf-item-${item.id}`}>
|
|
845
|
-
<ListItemIcon>{item.icon}</ListItemIcon>
|
|
846
|
-
<ListItemText primary={item.label} />
|
|
847
|
-
</ListItemButton>
|
|
848
|
-
))}
|
|
849
|
-
</List>
|
|
850
|
-
</DrawerContent>
|
|
851
|
-
</Drawer>
|
|
852
|
-
</Box>
|
|
853
|
-
);
|
|
854
|
-
};
|
|
855
|
-
|
|
856
|
-
return <PerformanceComponent />;
|
|
857
|
-
},
|
|
858
|
-
play: async ({ canvasElement }) => {
|
|
859
|
-
const canvas = within(canvasElement);
|
|
860
|
-
|
|
861
|
-
// Wait for performance drawer to render
|
|
862
|
-
await waitFor(
|
|
863
|
-
() => {
|
|
864
|
-
const backdrop = document.querySelector('.MuiBackdrop-root');
|
|
865
|
-
expect(backdrop).toBeInTheDocument();
|
|
866
|
-
},
|
|
867
|
-
{ timeout: 5000 },
|
|
868
|
-
);
|
|
869
|
-
|
|
870
|
-
// Test initial render performance (look in document since MUI renders in portal)
|
|
871
|
-
const performanceDrawer = document.querySelector('[data-testid="performance-drawer"]');
|
|
872
|
-
expect(performanceDrawer).toBeInTheDocument();
|
|
873
|
-
|
|
874
|
-
const performanceList = document.querySelector('[data-testid="performance-list"]');
|
|
875
|
-
expect(performanceList).toBeInTheDocument();
|
|
876
|
-
|
|
877
|
-
// Test that initial items are rendered
|
|
878
|
-
const firstItem = document.querySelector('[data-testid="perf-item-0"]');
|
|
879
|
-
const lastItem = document.querySelector('[data-testid="perf-item-49"]');
|
|
880
|
-
expect(firstItem).toBeInTheDocument();
|
|
881
|
-
expect(lastItem).toBeInTheDocument();
|
|
882
|
-
|
|
883
|
-
// Test performance with more items
|
|
884
|
-
const button100 = canvas.getByTestId('perf-100-items');
|
|
885
|
-
await userEvent.click(button100);
|
|
886
|
-
|
|
887
|
-
await waitFor(() => {
|
|
888
|
-
const title = performanceDrawer.querySelector('h6');
|
|
889
|
-
expect(title).toBeInTheDocument();
|
|
890
|
-
expect(title).toHaveTextContent('Performance Test (100 items)');
|
|
891
|
-
});
|
|
892
|
-
|
|
893
|
-
// Verify new items are rendered
|
|
894
|
-
await waitFor(() => {
|
|
895
|
-
const item99 = document.querySelector('[data-testid="perf-item-99"]');
|
|
896
|
-
expect(item99).toBeInTheDocument();
|
|
897
|
-
});
|
|
898
|
-
|
|
899
|
-
// Scrolling is not asserted here: setting scrollTop and reading it back only
|
|
900
|
-
// confirms the DOM stored the value, and how far the list can actually scroll
|
|
901
|
-
// depends on the runner's window height. The meaningful part of this story is
|
|
902
|
-
// that all 100 items rendered, which is asserted above.
|
|
903
|
-
},
|
|
904
|
-
};
|
|
905
|
-
|
|
906
|
-
// Edge Cases Tests
|
|
907
|
-
export const EdgeCases: Story = {
|
|
908
|
-
name: '🧩 Edge Cases',
|
|
909
|
-
render: () => {
|
|
910
|
-
const EdgeCasesComponent = () => {
|
|
911
|
-
const [states, setStates] = useState({
|
|
912
|
-
empty: true,
|
|
913
|
-
noHeader: false,
|
|
914
|
-
longContent: false,
|
|
915
|
-
persistent: false,
|
|
916
|
-
});
|
|
917
|
-
|
|
918
|
-
const toggleState = (state: keyof typeof states) => {
|
|
919
|
-
setStates((prev) => ({ ...prev, [state]: !prev[state] }));
|
|
920
|
-
};
|
|
921
|
-
|
|
922
|
-
const longText =
|
|
923
|
-
'This is a very long text content that should test how the drawer handles overflow content. '.repeat(
|
|
924
|
-
20,
|
|
925
|
-
);
|
|
926
|
-
|
|
927
|
-
return (
|
|
928
|
-
<Box sx={{ height: '100vh', position: 'relative' }}>
|
|
929
|
-
<Stack
|
|
930
|
-
direction="row"
|
|
931
|
-
spacing={1}
|
|
932
|
-
sx={{ p: 1, zIndex: 1300, position: 'relative', flexWrap: 'wrap' }}
|
|
933
|
-
>
|
|
934
|
-
<Button
|
|
935
|
-
size="small"
|
|
936
|
-
onClick={() => toggleState('noHeader')}
|
|
937
|
-
data-testid="edge-no-header"
|
|
938
|
-
>
|
|
939
|
-
No Header
|
|
940
|
-
</Button>
|
|
941
|
-
<Button
|
|
942
|
-
size="small"
|
|
943
|
-
onClick={() => toggleState('longContent')}
|
|
944
|
-
data-testid="edge-long-content"
|
|
945
|
-
>
|
|
946
|
-
Long Content
|
|
947
|
-
</Button>
|
|
948
|
-
<Button
|
|
949
|
-
size="small"
|
|
950
|
-
onClick={() => toggleState('persistent')}
|
|
951
|
-
data-testid="edge-persistent"
|
|
952
|
-
>
|
|
953
|
-
Persistent
|
|
954
|
-
</Button>
|
|
955
|
-
</Stack>
|
|
956
|
-
|
|
957
|
-
{/* Empty Drawer */}
|
|
958
|
-
<Drawer
|
|
959
|
-
open={states.empty}
|
|
960
|
-
onClose={() => toggleState('empty')}
|
|
961
|
-
data-testid="edge-empty-drawer"
|
|
962
|
-
>
|
|
963
|
-
<DrawerHeader onClose={() => toggleState('empty')}>
|
|
964
|
-
<Typography variant="h6">Empty Drawer</Typography>
|
|
965
|
-
</DrawerHeader>
|
|
966
|
-
<DrawerContent>{/* Intentionally empty content */}</DrawerContent>
|
|
967
|
-
</Drawer>
|
|
968
|
-
|
|
969
|
-
{/* No Header Drawer */}
|
|
970
|
-
<Drawer
|
|
971
|
-
open={states.noHeader}
|
|
972
|
-
onClose={() => toggleState('noHeader')}
|
|
973
|
-
data-testid="edge-no-header-drawer"
|
|
974
|
-
>
|
|
975
|
-
<DrawerContent>
|
|
976
|
-
<Box sx={{ p: 2 }}>
|
|
977
|
-
<Typography variant="h6">No Header</Typography>
|
|
978
|
-
<Typography variant="body2">This drawer has no header component.</Typography>
|
|
979
|
-
</Box>
|
|
980
|
-
</DrawerContent>
|
|
981
|
-
</Drawer>
|
|
982
|
-
|
|
983
|
-
{/* Long Content Drawer */}
|
|
984
|
-
<Drawer
|
|
985
|
-
open={states.longContent}
|
|
986
|
-
onClose={() => toggleState('longContent')}
|
|
987
|
-
data-testid="edge-long-content-drawer"
|
|
988
|
-
>
|
|
989
|
-
<DrawerHeader onClose={() => toggleState('longContent')}>
|
|
990
|
-
<Typography variant="h6">Long Content</Typography>
|
|
991
|
-
</DrawerHeader>
|
|
992
|
-
<DrawerContent>
|
|
993
|
-
<Typography variant="body2" data-testid="edge-long-text">
|
|
994
|
-
{longText}
|
|
995
|
-
</Typography>
|
|
996
|
-
</DrawerContent>
|
|
997
|
-
</Drawer>
|
|
998
|
-
|
|
999
|
-
{/* Persistent Drawer */}
|
|
1000
|
-
<Drawer
|
|
1001
|
-
open={states.persistent}
|
|
1002
|
-
onClose={() => toggleState('persistent')}
|
|
1003
|
-
data-testid="edge-persistent-drawer"
|
|
1004
|
-
persistent={true}
|
|
1005
|
-
>
|
|
1006
|
-
<DrawerHeader>
|
|
1007
|
-
<Typography variant="h6">Persistent Drawer</Typography>
|
|
1008
|
-
</DrawerHeader>
|
|
1009
|
-
<DrawerContent>
|
|
1010
|
-
<Typography variant="body2">
|
|
1011
|
-
This is a persistent drawer without backdrop click-to-close.
|
|
1012
|
-
</Typography>
|
|
1013
|
-
<Button
|
|
1014
|
-
onClick={() => toggleState('persistent')}
|
|
1015
|
-
data-testid="edge-persistent-close"
|
|
1016
|
-
sx={{ mt: 2 }}
|
|
1017
|
-
>
|
|
1018
|
-
Close Manually
|
|
1019
|
-
</Button>
|
|
1020
|
-
</DrawerContent>
|
|
1021
|
-
</Drawer>
|
|
1022
|
-
</Box>
|
|
1023
|
-
);
|
|
1024
|
-
};
|
|
1025
|
-
|
|
1026
|
-
return <EdgeCasesComponent />;
|
|
1027
|
-
},
|
|
1028
|
-
play: async ({ canvasElement }) => {
|
|
1029
|
-
const canvas = within(canvasElement);
|
|
1030
|
-
|
|
1031
|
-
// Wait for empty drawer to render
|
|
1032
|
-
await waitFor(
|
|
1033
|
-
() => {
|
|
1034
|
-
const backdrop = document.querySelector('.MuiBackdrop-root');
|
|
1035
|
-
expect(backdrop).toBeInTheDocument();
|
|
1036
|
-
},
|
|
1037
|
-
{ timeout: 5000 },
|
|
1038
|
-
);
|
|
1039
|
-
|
|
1040
|
-
// Test empty drawer (look in document since MUI renders in portal)
|
|
1041
|
-
const emptyDrawer = document.querySelector('[data-testid="edge-empty-drawer"]');
|
|
1042
|
-
expect(emptyDrawer).toBeInTheDocument();
|
|
1043
|
-
|
|
1044
|
-
await waitFor(() => {
|
|
1045
|
-
const emptyTitle = emptyDrawer.querySelector('h6');
|
|
1046
|
-
expect(emptyTitle).toBeInTheDocument();
|
|
1047
|
-
expect(emptyTitle).toHaveTextContent('Empty Drawer');
|
|
1048
|
-
});
|
|
1049
|
-
|
|
1050
|
-
// Test no header drawer
|
|
1051
|
-
const noHeaderButton = canvas.getByTestId('edge-no-header');
|
|
1052
|
-
await userEvent.click(noHeaderButton);
|
|
1053
|
-
|
|
1054
|
-
await waitFor(() => {
|
|
1055
|
-
const noHeaderDrawer = document.querySelector('[data-testid="edge-no-header-drawer"]');
|
|
1056
|
-
expect(noHeaderDrawer).toBeInTheDocument();
|
|
1057
|
-
const noHeaderText = Array.from(document.querySelectorAll('*')).find(
|
|
1058
|
-
(el) => el.textContent === 'No Header',
|
|
1059
|
-
);
|
|
1060
|
-
expect(noHeaderText).toBeInTheDocument();
|
|
1061
|
-
});
|
|
1062
|
-
|
|
1063
|
-
// Test long content drawer
|
|
1064
|
-
const longContentButton = canvas.getByTestId('edge-long-content');
|
|
1065
|
-
await userEvent.click(longContentButton);
|
|
1066
|
-
|
|
1067
|
-
await waitFor(() => {
|
|
1068
|
-
const longContentDrawer = document.querySelector('[data-testid="edge-long-content-drawer"]');
|
|
1069
|
-
expect(longContentDrawer).toBeInTheDocument();
|
|
1070
|
-
const longText = document.querySelector('[data-testid="edge-long-text"]');
|
|
1071
|
-
expect(longText).toBeInTheDocument();
|
|
1072
|
-
expect(longText.textContent?.length).toBeGreaterThan(100);
|
|
1073
|
-
});
|
|
1074
|
-
|
|
1075
|
-
// Test persistent drawer
|
|
1076
|
-
const persistentButton = canvas.getByTestId('edge-persistent');
|
|
1077
|
-
await userEvent.click(persistentButton);
|
|
1078
|
-
|
|
1079
|
-
await waitFor(() => {
|
|
1080
|
-
const persistentDrawer = document.querySelector('[data-testid="edge-persistent-drawer"]');
|
|
1081
|
-
expect(persistentDrawer).toBeInTheDocument();
|
|
1082
|
-
const persistentTitle = persistentDrawer.querySelector('h6');
|
|
1083
|
-
expect(persistentTitle).toBeInTheDocument();
|
|
1084
|
-
expect(persistentTitle).toHaveTextContent('Persistent Drawer');
|
|
1085
|
-
});
|
|
1086
|
-
|
|
1087
|
-
// Test manual close for persistent drawer
|
|
1088
|
-
const manualCloseButton = canvas.getByTestId('edge-persistent-close');
|
|
1089
|
-
await userEvent.click(manualCloseButton);
|
|
1090
|
-
|
|
1091
|
-
await waitFor(() => {
|
|
1092
|
-
const persistentDrawer = document.querySelector('[data-testid="edge-persistent-drawer"]');
|
|
1093
|
-
// For persistent drawers, check if it's hidden rather than removed from DOM
|
|
1094
|
-
if (persistentDrawer) {
|
|
1095
|
-
const drawerPaper = persistentDrawer.querySelector('.MuiDrawer-paper');
|
|
1096
|
-
const isHidden =
|
|
1097
|
-
drawerPaper &&
|
|
1098
|
-
(drawerPaper.style.visibility === 'hidden' ||
|
|
1099
|
-
drawerPaper.style.transform.includes('translateX(-'));
|
|
1100
|
-
expect(isHidden).toBe(true);
|
|
1101
|
-
} else {
|
|
1102
|
-
expect(persistentDrawer).not.toBeInTheDocument();
|
|
1103
|
-
}
|
|
1104
|
-
});
|
|
1105
|
-
},
|
|
1106
|
-
};
|
|
1107
|
-
|
|
1108
|
-
// Integration Tests
|
|
1109
|
-
export const Integration: Story = {
|
|
1110
|
-
name: '🔗 Integration',
|
|
1111
|
-
render: () => {
|
|
1112
|
-
const IntegrationComponent = () => {
|
|
1113
|
-
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
1114
|
-
const [selectedPage, setSelectedPage] = useState('home');
|
|
1115
|
-
const [notifications, setNotifications] = useState(3);
|
|
1116
|
-
|
|
1117
|
-
const handleNavigation = (page: string) => {
|
|
1118
|
-
setSelectedPage(page);
|
|
1119
|
-
if (page === 'notifications') {
|
|
1120
|
-
setNotifications(0);
|
|
1121
|
-
}
|
|
1122
|
-
};
|
|
1123
|
-
|
|
1124
|
-
return (
|
|
1125
|
-
<Box sx={{ display: 'flex', height: '100vh' }}>
|
|
1126
|
-
{/* Main Drawer */}
|
|
1127
|
-
<Drawer
|
|
1128
|
-
open={drawerOpen}
|
|
1129
|
-
onClose={() => setDrawerOpen(false)}
|
|
1130
|
-
data-testid="integration-main-drawer"
|
|
1131
|
-
persistent={false}
|
|
1132
|
-
>
|
|
1133
|
-
<DrawerHeader onClose={() => setDrawerOpen(false)}>
|
|
1134
|
-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
|
1135
|
-
<Box
|
|
1136
|
-
sx={{
|
|
1137
|
-
width: 32,
|
|
1138
|
-
height: 32,
|
|
1139
|
-
borderRadius: '50%',
|
|
1140
|
-
bgcolor: 'primary.main',
|
|
1141
|
-
display: 'flex',
|
|
1142
|
-
alignItems: 'center',
|
|
1143
|
-
justifyContent: 'center',
|
|
1144
|
-
color: 'white',
|
|
1145
|
-
fontSize: '0.875rem',
|
|
1146
|
-
fontWeight: 'bold',
|
|
1147
|
-
}}
|
|
1148
|
-
>
|
|
1149
|
-
A
|
|
1150
|
-
</Box>
|
|
1151
|
-
<Typography variant="h6">App Name</Typography>
|
|
1152
|
-
</Box>
|
|
1153
|
-
</DrawerHeader>
|
|
1154
|
-
<DrawerContent>
|
|
1155
|
-
<List>
|
|
1156
|
-
<ListItemButton
|
|
1157
|
-
selected={selectedPage === 'home'}
|
|
1158
|
-
onClick={() => handleNavigation('home')}
|
|
1159
|
-
data-testid="integration-nav-home"
|
|
1160
|
-
>
|
|
1161
|
-
<ListItemIcon>
|
|
1162
|
-
<Home />
|
|
1163
|
-
</ListItemIcon>
|
|
1164
|
-
<ListItemText primary="Home" />
|
|
1165
|
-
</ListItemButton>
|
|
1166
|
-
<ListItemButton
|
|
1167
|
-
selected={selectedPage === 'dashboard'}
|
|
1168
|
-
onClick={() => handleNavigation('dashboard')}
|
|
1169
|
-
data-testid="integration-nav-dashboard"
|
|
1170
|
-
>
|
|
1171
|
-
<ListItemIcon>
|
|
1172
|
-
<Dashboard />
|
|
1173
|
-
</ListItemIcon>
|
|
1174
|
-
<ListItemText primary="Dashboard" />
|
|
1175
|
-
</ListItemButton>
|
|
1176
|
-
<ListItemButton
|
|
1177
|
-
selected={selectedPage === 'notifications'}
|
|
1178
|
-
onClick={() => handleNavigation('notifications')}
|
|
1179
|
-
data-testid="integration-nav-notifications"
|
|
1180
|
-
>
|
|
1181
|
-
<ListItemIcon>
|
|
1182
|
-
<Box sx={{ position: 'relative' }}>
|
|
1183
|
-
<Settings />
|
|
1184
|
-
{notifications > 0 && (
|
|
1185
|
-
<Box
|
|
1186
|
-
sx={{
|
|
1187
|
-
position: 'absolute',
|
|
1188
|
-
top: -4,
|
|
1189
|
-
right: -4,
|
|
1190
|
-
width: 16,
|
|
1191
|
-
height: 16,
|
|
1192
|
-
borderRadius: '50%',
|
|
1193
|
-
bgcolor: 'error.main',
|
|
1194
|
-
color: 'white',
|
|
1195
|
-
display: 'flex',
|
|
1196
|
-
alignItems: 'center',
|
|
1197
|
-
justifyContent: 'center',
|
|
1198
|
-
fontSize: '0.75rem',
|
|
1199
|
-
}}
|
|
1200
|
-
>
|
|
1201
|
-
{notifications}
|
|
1202
|
-
</Box>
|
|
1203
|
-
)}
|
|
1204
|
-
</Box>
|
|
1205
|
-
</ListItemIcon>
|
|
1206
|
-
<ListItemText
|
|
1207
|
-
primary="Notifications"
|
|
1208
|
-
secondary={notifications > 0 ? `${notifications} new` : 'No new notifications'}
|
|
1209
|
-
/>
|
|
1210
|
-
</ListItemButton>
|
|
1211
|
-
</List>
|
|
1212
|
-
</DrawerContent>
|
|
1213
|
-
</Drawer>
|
|
1214
|
-
|
|
1215
|
-
{/* Main Content Area */}
|
|
1216
|
-
<Box component="main" sx={{ flexGrow: 1, display: 'flex', flexDirection: 'column' }}>
|
|
1217
|
-
{/* App Bar */}
|
|
1218
|
-
<Box
|
|
1219
|
-
sx={{
|
|
1220
|
-
p: 2,
|
|
1221
|
-
borderBottom: 1,
|
|
1222
|
-
borderColor: 'divider',
|
|
1223
|
-
display: 'flex',
|
|
1224
|
-
alignItems: 'center',
|
|
1225
|
-
gap: 2,
|
|
1226
|
-
}}
|
|
1227
|
-
>
|
|
1228
|
-
<IconButton
|
|
1229
|
-
onClick={() => setDrawerOpen(!drawerOpen)}
|
|
1230
|
-
data-testid="integration-menu-button"
|
|
1231
|
-
>
|
|
1232
|
-
<MenuIcon />
|
|
1233
|
-
</IconButton>
|
|
1234
|
-
<Typography variant="h6" sx={{ flexGrow: 1 }}>
|
|
1235
|
-
{selectedPage.charAt(0).toUpperCase() + selectedPage.slice(1)}
|
|
1236
|
-
</Typography>
|
|
1237
|
-
{notifications > 0 && (
|
|
1238
|
-
<Box
|
|
1239
|
-
sx={{
|
|
1240
|
-
bgcolor: 'error.main',
|
|
1241
|
-
color: 'white',
|
|
1242
|
-
borderRadius: 1,
|
|
1243
|
-
px: 1,
|
|
1244
|
-
py: 0.5,
|
|
1245
|
-
fontSize: '0.75rem',
|
|
1246
|
-
}}
|
|
1247
|
-
>
|
|
1248
|
-
{notifications} notifications
|
|
1249
|
-
</Box>
|
|
1250
|
-
)}
|
|
1251
|
-
</Box>
|
|
1252
|
-
|
|
1253
|
-
{/* Page Content */}
|
|
1254
|
-
<Box sx={{ p: 3, flex: 1 }} data-testid="integration-main-content">
|
|
1255
|
-
<Typography variant="h4" gutterBottom>
|
|
1256
|
-
{selectedPage === 'home' && 'Welcome Home'}
|
|
1257
|
-
{selectedPage === 'dashboard' && 'Dashboard Overview'}
|
|
1258
|
-
{selectedPage === 'notifications' && 'Notification Center'}
|
|
1259
|
-
</Typography>
|
|
1260
|
-
<Typography variant="body1">
|
|
1261
|
-
This is the {selectedPage} page content. The drawer integrates with the main
|
|
1262
|
-
application navigation and state management.
|
|
1263
|
-
</Typography>
|
|
1264
|
-
{selectedPage === 'notifications' && (
|
|
1265
|
-
<Typography variant="body2" sx={{ mt: 2, fontStyle: 'italic' }}>
|
|
1266
|
-
All notifications have been marked as read.
|
|
1267
|
-
</Typography>
|
|
1268
|
-
)}
|
|
1269
|
-
</Box>
|
|
1270
|
-
</Box>
|
|
1271
|
-
</Box>
|
|
1272
|
-
);
|
|
1273
|
-
};
|
|
1274
|
-
|
|
1275
|
-
return <IntegrationComponent />;
|
|
1276
|
-
},
|
|
1277
|
-
play: async ({ canvasElement }) => {
|
|
1278
|
-
const canvas = within(canvasElement);
|
|
1279
|
-
|
|
1280
|
-
// Test initial state
|
|
1281
|
-
expect(canvas.getByText('Welcome Home')).toBeInTheDocument();
|
|
1282
|
-
|
|
1283
|
-
// Test drawer opening
|
|
1284
|
-
const menuButton = canvas.getByTestId('integration-menu-button');
|
|
1285
|
-
await userEvent.click(menuButton);
|
|
1286
|
-
|
|
1287
|
-
await waitFor(() => {
|
|
1288
|
-
const drawer = document.querySelector('[data-testid="integration-main-drawer"]');
|
|
1289
|
-
expect(drawer).toBeInTheDocument();
|
|
1290
|
-
const appName = Array.from(document.querySelectorAll('*')).find(
|
|
1291
|
-
(el) => el.textContent === 'App Name',
|
|
1292
|
-
);
|
|
1293
|
-
expect(appName).toBeInTheDocument();
|
|
1294
|
-
});
|
|
1295
|
-
|
|
1296
|
-
// Test navigation to dashboard
|
|
1297
|
-
const dashboardItem = document.querySelector('[data-testid="integration-nav-dashboard"]');
|
|
1298
|
-
await userEvent.click(dashboardItem);
|
|
1299
|
-
|
|
1300
|
-
await waitFor(() => {
|
|
1301
|
-
const dashboardOverview = canvas.getByText('Dashboard Overview');
|
|
1302
|
-
expect(dashboardOverview).toBeInTheDocument();
|
|
1303
|
-
});
|
|
1304
|
-
|
|
1305
|
-
// Test notification badge functionality
|
|
1306
|
-
const notificationsItem = document.querySelector(
|
|
1307
|
-
'[data-testid="integration-nav-notifications"]',
|
|
1308
|
-
);
|
|
1309
|
-
|
|
1310
|
-
// Should show notification badge
|
|
1311
|
-
const notificationBadge = Array.from(document.querySelectorAll('*')).find(
|
|
1312
|
-
(el) => el.textContent === '3',
|
|
1313
|
-
);
|
|
1314
|
-
expect(notificationBadge).toBeInTheDocument();
|
|
1315
|
-
|
|
1316
|
-
await userEvent.click(notificationsItem);
|
|
1317
|
-
|
|
1318
|
-
await waitFor(() => {
|
|
1319
|
-
const notificationCenter = canvas.getByText('Notification Center');
|
|
1320
|
-
expect(notificationCenter).toBeInTheDocument();
|
|
1321
|
-
const notificationMessage = canvas.getByText('All notifications have been marked as read.');
|
|
1322
|
-
expect(notificationMessage).toBeInTheDocument();
|
|
1323
|
-
});
|
|
1324
|
-
|
|
1325
|
-
// Notification badge should be cleared
|
|
1326
|
-
await waitFor(() => {
|
|
1327
|
-
const notificationText = canvas.queryByText('3 notifications');
|
|
1328
|
-
expect(notificationText).not.toBeInTheDocument();
|
|
1329
|
-
});
|
|
1330
|
-
|
|
1331
|
-
// Test drawer closing
|
|
1332
|
-
const closeButton = document.querySelector('button[aria-label*="close" i]');
|
|
1333
|
-
await userEvent.click(closeButton);
|
|
1334
|
-
|
|
1335
|
-
await waitFor(() => {
|
|
1336
|
-
const appName = Array.from(document.querySelectorAll('*')).find(
|
|
1337
|
-
(el) => el.textContent === 'App Name',
|
|
1338
|
-
);
|
|
1339
|
-
// appName should be undefined (not found) when drawer is closed
|
|
1340
|
-
expect(appName).toBeUndefined();
|
|
1341
|
-
});
|
|
1342
|
-
},
|
|
1343
|
-
};
|