@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,1159 +0,0 @@
|
|
|
1
|
-
import { Box, Paper, useTheme } from '@mui/material';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
|
-
import { Heart, Pause,Play, Settings, Star } from 'lucide-react';
|
|
4
|
-
import React, { useState } from 'react';
|
|
5
|
-
import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
|
|
6
|
-
|
|
7
|
-
import { Toggle } from './Toggle';
|
|
8
|
-
|
|
9
|
-
const meta: Meta<typeof Toggle> = {
|
|
10
|
-
title: 'Form/Toggle/Tests',
|
|
11
|
-
component: Toggle,
|
|
12
|
-
parameters: {
|
|
13
|
-
layout: 'centered',
|
|
14
|
-
chromatic: { disableSnapshot: false },
|
|
15
|
-
docs: { source: { type: 'code' } },
|
|
16
|
-
},
|
|
17
|
-
tags: ['autodocs', 'test', 'component:Toggle'],
|
|
18
|
-
};
|
|
19
|
-
export default meta;
|
|
20
|
-
export type Story = StoryObj<typeof meta>;
|
|
21
|
-
|
|
22
|
-
// Basic Interaction Tests
|
|
23
|
-
export const BasicInteraction: Story = {
|
|
24
|
-
render: function BasicInteractionRender() {
|
|
25
|
-
const [selected, setSelected] = useState(false);
|
|
26
|
-
const handleChange = fn(() => setSelected(!selected));
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<div data-testid="basic-interaction-container">
|
|
30
|
-
<Toggle
|
|
31
|
-
data-testid="basic-toggle"
|
|
32
|
-
selected={selected}
|
|
33
|
-
onChange={handleChange}
|
|
34
|
-
value="test-toggle"
|
|
35
|
-
>
|
|
36
|
-
Click Me
|
|
37
|
-
</Toggle>
|
|
38
|
-
<div data-testid="selection-state" aria-live="polite">
|
|
39
|
-
{selected ? 'Selected' : 'Not Selected'}
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
);
|
|
43
|
-
},
|
|
44
|
-
play: async ({ canvasElement }) => {
|
|
45
|
-
const canvas = within(canvasElement);
|
|
46
|
-
const toggle = canvas.getByTestId('basic-toggle');
|
|
47
|
-
const stateDiv = canvas.getByTestId('selection-state');
|
|
48
|
-
|
|
49
|
-
// Verify initial state
|
|
50
|
-
expect(stateDiv).toHaveTextContent('Not Selected');
|
|
51
|
-
expect(toggle).toHaveAttribute('aria-pressed', 'false');
|
|
52
|
-
|
|
53
|
-
// Click to select
|
|
54
|
-
await userEvent.click(toggle);
|
|
55
|
-
await waitFor(() => {
|
|
56
|
-
expect(stateDiv).toHaveTextContent('Selected');
|
|
57
|
-
expect(toggle).toHaveAttribute('aria-pressed', 'true');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Click to deselect
|
|
61
|
-
await userEvent.click(toggle);
|
|
62
|
-
await waitFor(() => {
|
|
63
|
-
expect(stateDiv).toHaveTextContent('Not Selected');
|
|
64
|
-
expect(toggle).toHaveAttribute('aria-pressed', 'false');
|
|
65
|
-
});
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
// Form Interaction Tests
|
|
70
|
-
export const FormInteraction: Story = {
|
|
71
|
-
render: function FormInteractionRender() {
|
|
72
|
-
const [formData, setFormData] = useState({
|
|
73
|
-
notifications: false,
|
|
74
|
-
marketing: true,
|
|
75
|
-
newsletter: false,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const handleSubmit = fn((e: React.FormEvent) => {
|
|
79
|
-
e.preventDefault();
|
|
80
|
-
// Form submitted with data: formData
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<form onSubmit={handleSubmit} data-testid="toggle-form">
|
|
85
|
-
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, minWidth: 300 }}>
|
|
86
|
-
<Toggle
|
|
87
|
-
data-testid="notifications-toggle"
|
|
88
|
-
selected={formData.notifications}
|
|
89
|
-
onChange={() =>
|
|
90
|
-
setFormData((prev) => ({ ...prev, notifications: !prev.notifications }))
|
|
91
|
-
}
|
|
92
|
-
value="notifications"
|
|
93
|
-
icon={<Star size={16} />}
|
|
94
|
-
>
|
|
95
|
-
Notifications
|
|
96
|
-
</Toggle>
|
|
97
|
-
|
|
98
|
-
<Toggle
|
|
99
|
-
data-testid="marketing-toggle"
|
|
100
|
-
selected={formData.marketing}
|
|
101
|
-
onChange={() => setFormData((prev) => ({ ...prev, marketing: !prev.marketing }))}
|
|
102
|
-
value="marketing"
|
|
103
|
-
variant="outline"
|
|
104
|
-
color="secondary"
|
|
105
|
-
>
|
|
106
|
-
Marketing Emails
|
|
107
|
-
</Toggle>
|
|
108
|
-
|
|
109
|
-
<Toggle
|
|
110
|
-
data-testid="newsletter-toggle"
|
|
111
|
-
selected={formData.newsletter}
|
|
112
|
-
onChange={() => setFormData((prev) => ({ ...prev, newsletter: !prev.newsletter }))}
|
|
113
|
-
value="newsletter"
|
|
114
|
-
variant="soft"
|
|
115
|
-
color="success"
|
|
116
|
-
>
|
|
117
|
-
Newsletter
|
|
118
|
-
</Toggle>
|
|
119
|
-
|
|
120
|
-
<button type="submit" data-testid="submit-button">
|
|
121
|
-
Save Preferences
|
|
122
|
-
</button>
|
|
123
|
-
|
|
124
|
-
<div data-testid="form-state" aria-live="polite">
|
|
125
|
-
{JSON.stringify(formData)}
|
|
126
|
-
</div>
|
|
127
|
-
</Box>
|
|
128
|
-
</form>
|
|
129
|
-
);
|
|
130
|
-
},
|
|
131
|
-
play: async ({ canvasElement }) => {
|
|
132
|
-
const canvas = within(canvasElement);
|
|
133
|
-
const notificationsToggle = canvas.getByTestId('notifications-toggle');
|
|
134
|
-
const marketingToggle = canvas.getByTestId('marketing-toggle');
|
|
135
|
-
const newsletterToggle = canvas.getByTestId('newsletter-toggle');
|
|
136
|
-
const submitButton = canvas.getByTestId('submit-button');
|
|
137
|
-
const formState = canvas.getByTestId('form-state');
|
|
138
|
-
|
|
139
|
-
// Verify initial form state
|
|
140
|
-
expect(formState).toHaveTextContent(
|
|
141
|
-
'{"notifications":false,"marketing":true,"newsletter":false}',
|
|
142
|
-
);
|
|
143
|
-
expect(notificationsToggle).toHaveAttribute('aria-pressed', 'false');
|
|
144
|
-
expect(marketingToggle).toHaveAttribute('aria-pressed', 'true');
|
|
145
|
-
expect(newsletterToggle).toHaveAttribute('aria-pressed', 'false');
|
|
146
|
-
|
|
147
|
-
// Toggle notifications on
|
|
148
|
-
await userEvent.click(notificationsToggle);
|
|
149
|
-
await waitFor(() => {
|
|
150
|
-
expect(formState).toHaveTextContent(
|
|
151
|
-
'{"notifications":true,"marketing":true,"newsletter":false}',
|
|
152
|
-
);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// Toggle marketing off
|
|
156
|
-
await userEvent.click(marketingToggle);
|
|
157
|
-
await waitFor(() => {
|
|
158
|
-
expect(formState).toHaveTextContent(
|
|
159
|
-
'{"notifications":true,"marketing":false,"newsletter":false}',
|
|
160
|
-
);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// Toggle newsletter on
|
|
164
|
-
await userEvent.click(newsletterToggle);
|
|
165
|
-
await waitFor(() => {
|
|
166
|
-
expect(formState).toHaveTextContent(
|
|
167
|
-
'{"notifications":true,"marketing":false,"newsletter":true}',
|
|
168
|
-
);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// Test form submission
|
|
172
|
-
await userEvent.click(submitButton);
|
|
173
|
-
// Verify no errors occurred
|
|
174
|
-
expect(formState).toBeInTheDocument();
|
|
175
|
-
},
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
// Keyboard Navigation Tests
|
|
179
|
-
export const KeyboardNavigation: Story = {
|
|
180
|
-
render: function KeyboardNavigationRender() {
|
|
181
|
-
const [selectedStates, setSelectedStates] = useState({
|
|
182
|
-
toggle1: false,
|
|
183
|
-
toggle2: false,
|
|
184
|
-
toggle3: false,
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
return (
|
|
188
|
-
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, minWidth: 300 }}>
|
|
189
|
-
<div
|
|
190
|
-
data-testid="keyboard-instructions"
|
|
191
|
-
role="region"
|
|
192
|
-
aria-label="Keyboard Navigation Test"
|
|
193
|
-
>
|
|
194
|
-
Use Tab to navigate, Space/Enter to toggle
|
|
195
|
-
</div>
|
|
196
|
-
|
|
197
|
-
<Toggle
|
|
198
|
-
data-testid="keyboard-toggle-1"
|
|
199
|
-
selected={selectedStates.toggle1}
|
|
200
|
-
onChange={() => setSelectedStates((prev) => ({ ...prev, toggle1: !prev.toggle1 }))}
|
|
201
|
-
value="toggle1"
|
|
202
|
-
>
|
|
203
|
-
First Toggle
|
|
204
|
-
</Toggle>
|
|
205
|
-
|
|
206
|
-
<Toggle
|
|
207
|
-
data-testid="keyboard-toggle-2"
|
|
208
|
-
selected={selectedStates.toggle2}
|
|
209
|
-
onChange={() => setSelectedStates((prev) => ({ ...prev, toggle2: !prev.toggle2 }))}
|
|
210
|
-
value="toggle2"
|
|
211
|
-
variant="outline"
|
|
212
|
-
>
|
|
213
|
-
Second Toggle
|
|
214
|
-
</Toggle>
|
|
215
|
-
|
|
216
|
-
<Toggle
|
|
217
|
-
data-testid="keyboard-toggle-3"
|
|
218
|
-
selected={selectedStates.toggle3}
|
|
219
|
-
onChange={() => setSelectedStates((prev) => ({ ...prev, toggle3: !prev.toggle3 }))}
|
|
220
|
-
value="toggle3"
|
|
221
|
-
disabled
|
|
222
|
-
>
|
|
223
|
-
Disabled Toggle
|
|
224
|
-
</Toggle>
|
|
225
|
-
|
|
226
|
-
<div data-testid="keyboard-state" aria-live="polite">
|
|
227
|
-
{JSON.stringify(selectedStates)}
|
|
228
|
-
</div>
|
|
229
|
-
</Box>
|
|
230
|
-
);
|
|
231
|
-
},
|
|
232
|
-
play: async ({ canvasElement }) => {
|
|
233
|
-
const canvas = within(canvasElement);
|
|
234
|
-
const toggle1 = canvas.getByTestId('keyboard-toggle-1');
|
|
235
|
-
const toggle2 = canvas.getByTestId('keyboard-toggle-2');
|
|
236
|
-
const toggle3 = canvas.getByTestId('keyboard-toggle-3');
|
|
237
|
-
const stateDiv = canvas.getByTestId('keyboard-state');
|
|
238
|
-
|
|
239
|
-
// Test Tab navigation
|
|
240
|
-
await userEvent.click(toggle1);
|
|
241
|
-
await waitFor(() => expect(toggle1).toHaveFocus());
|
|
242
|
-
|
|
243
|
-
await userEvent.tab();
|
|
244
|
-
await waitFor(() => expect(toggle2).toHaveFocus());
|
|
245
|
-
|
|
246
|
-
// Disabled toggle won't receive focus as it has tabindex="-1"
|
|
247
|
-
// This is expected behavior for disabled MUI ToggleButtons
|
|
248
|
-
await userEvent.tab();
|
|
249
|
-
// Focus should skip the disabled toggle
|
|
250
|
-
await waitFor(() => expect(document.activeElement).not.toBe(toggle3));
|
|
251
|
-
|
|
252
|
-
// Test Space key activation
|
|
253
|
-
await userEvent.click(toggle1);
|
|
254
|
-
expect(stateDiv).toHaveTextContent('{"toggle1":false,"toggle2":false,"toggle3":false}');
|
|
255
|
-
|
|
256
|
-
await userEvent.keyboard(' ');
|
|
257
|
-
await waitFor(() => {
|
|
258
|
-
expect(stateDiv).toHaveTextContent('{"toggle1":true,"toggle2":false,"toggle3":false}');
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
// Test Enter key activation
|
|
262
|
-
await userEvent.click(toggle2);
|
|
263
|
-
await userEvent.keyboard('{Enter}');
|
|
264
|
-
await waitFor(() => {
|
|
265
|
-
expect(stateDiv).toHaveTextContent('{"toggle1":true,"toggle2":true,"toggle3":false}');
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// Test disabled toggle doesn't respond
|
|
269
|
-
await userEvent.click(toggle3);
|
|
270
|
-
await userEvent.keyboard(' ');
|
|
271
|
-
await userEvent.keyboard('{Enter}');
|
|
272
|
-
// State should remain unchanged
|
|
273
|
-
expect(stateDiv).toHaveTextContent('{"toggle1":true,"toggle2":true,"toggle3":false}');
|
|
274
|
-
},
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
// Screen Reader Tests
|
|
278
|
-
export const ScreenReader: Story = {
|
|
279
|
-
render: function ScreenReaderRender() {
|
|
280
|
-
const [settings, setSettings] = useState({
|
|
281
|
-
darkMode: false,
|
|
282
|
-
highContrast: false,
|
|
283
|
-
screenReader: true,
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
return (
|
|
287
|
-
<Box
|
|
288
|
-
sx={{ display: 'flex', flexDirection: 'column', gap: 2, minWidth: 300 }}
|
|
289
|
-
role="group"
|
|
290
|
-
aria-labelledby="accessibility-settings"
|
|
291
|
-
>
|
|
292
|
-
<h3 id="accessibility-settings">Accessibility Settings</h3>
|
|
293
|
-
|
|
294
|
-
<Toggle
|
|
295
|
-
data-testid="dark-mode-toggle"
|
|
296
|
-
selected={settings.darkMode}
|
|
297
|
-
onChange={() => setSettings((prev) => ({ ...prev, darkMode: !prev.darkMode }))}
|
|
298
|
-
value="darkMode"
|
|
299
|
-
aria-describedby="dark-mode-description"
|
|
300
|
-
>
|
|
301
|
-
Dark Mode
|
|
302
|
-
</Toggle>
|
|
303
|
-
<div id="dark-mode-description" className="sr-only">
|
|
304
|
-
Enable dark theme for reduced eye strain
|
|
305
|
-
</div>
|
|
306
|
-
|
|
307
|
-
<Toggle
|
|
308
|
-
data-testid="high-contrast-toggle"
|
|
309
|
-
selected={settings.highContrast}
|
|
310
|
-
onChange={() => setSettings((prev) => ({ ...prev, highContrast: !prev.highContrast }))}
|
|
311
|
-
value="highContrast"
|
|
312
|
-
aria-describedby="high-contrast-description"
|
|
313
|
-
variant="outline"
|
|
314
|
-
>
|
|
315
|
-
High Contrast
|
|
316
|
-
</Toggle>
|
|
317
|
-
<div id="high-contrast-description" className="sr-only">
|
|
318
|
-
Increase contrast for better visibility
|
|
319
|
-
</div>
|
|
320
|
-
|
|
321
|
-
<Toggle
|
|
322
|
-
data-testid="screen-reader-toggle"
|
|
323
|
-
selected={settings.screenReader}
|
|
324
|
-
onChange={() => setSettings((prev) => ({ ...prev, screenReader: !prev.screenReader }))}
|
|
325
|
-
value="screenReader"
|
|
326
|
-
aria-describedby="screen-reader-description"
|
|
327
|
-
variant="soft"
|
|
328
|
-
color="success"
|
|
329
|
-
>
|
|
330
|
-
Screen Reader Support
|
|
331
|
-
</Toggle>
|
|
332
|
-
<div id="screen-reader-description" className="sr-only">
|
|
333
|
-
Enable enhanced screen reader compatibility
|
|
334
|
-
</div>
|
|
335
|
-
|
|
336
|
-
<div data-testid="accessibility-status" role="status" aria-live="polite" aria-atomic="true">
|
|
337
|
-
Settings:{' '}
|
|
338
|
-
{Object.entries(settings)
|
|
339
|
-
.filter(([, enabled]) => enabled)
|
|
340
|
-
.map(([key]) => key)
|
|
341
|
-
.join(', ') || 'None selected'}
|
|
342
|
-
</div>
|
|
343
|
-
</Box>
|
|
344
|
-
);
|
|
345
|
-
},
|
|
346
|
-
play: async ({ canvasElement }) => {
|
|
347
|
-
const canvas = within(canvasElement);
|
|
348
|
-
const darkModeToggle = canvas.getByTestId('dark-mode-toggle');
|
|
349
|
-
const highContrastToggle = canvas.getByTestId('high-contrast-toggle');
|
|
350
|
-
const screenReaderToggle = canvas.getByTestId('screen-reader-toggle');
|
|
351
|
-
const statusDiv = canvas.getByTestId('accessibility-status');
|
|
352
|
-
|
|
353
|
-
// Verify ARIA attributes
|
|
354
|
-
// MUI ToggleButton uses role="button" internally
|
|
355
|
-
expect(darkModeToggle).toHaveAttribute('aria-pressed', 'false');
|
|
356
|
-
expect(darkModeToggle).toHaveAttribute('aria-describedby', 'dark-mode-description');
|
|
357
|
-
|
|
358
|
-
expect(highContrastToggle).toHaveAttribute('aria-pressed', 'false');
|
|
359
|
-
expect(screenReaderToggle).toHaveAttribute('aria-pressed', 'true');
|
|
360
|
-
|
|
361
|
-
// Test status updates
|
|
362
|
-
expect(statusDiv).toHaveTextContent('Settings: screenReader');
|
|
363
|
-
|
|
364
|
-
await userEvent.click(darkModeToggle);
|
|
365
|
-
await waitFor(() => {
|
|
366
|
-
expect(darkModeToggle).toHaveAttribute('aria-pressed', 'true');
|
|
367
|
-
expect(statusDiv).toHaveTextContent('Settings: darkMode, screenReader');
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
await userEvent.click(highContrastToggle);
|
|
371
|
-
await waitFor(() => {
|
|
372
|
-
expect(statusDiv).toHaveTextContent('Settings: darkMode, highContrast, screenReader');
|
|
373
|
-
});
|
|
374
|
-
},
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
// Focus Management Tests
|
|
378
|
-
export const FocusManagement: Story = {
|
|
379
|
-
render: function FocusManagementRender() {
|
|
380
|
-
const [activeToggle, setActiveToggle] = useState<string | null>(null);
|
|
381
|
-
const [toggleStates, setToggleStates] = useState({
|
|
382
|
-
media: false,
|
|
383
|
-
social: false,
|
|
384
|
-
notifications: false,
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
const handleFocus = (toggleName: string) => {
|
|
388
|
-
setActiveToggle(toggleName);
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
const handleBlur = () => {
|
|
392
|
-
setActiveToggle(null);
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
return (
|
|
396
|
-
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, minWidth: 300 }}>
|
|
397
|
-
<div data-testid="focus-indicator" aria-live="polite">
|
|
398
|
-
Focused: {activeToggle || 'None'}
|
|
399
|
-
</div>
|
|
400
|
-
|
|
401
|
-
<Toggle
|
|
402
|
-
data-testid="media-toggle"
|
|
403
|
-
selected={toggleStates.media}
|
|
404
|
-
onChange={() => setToggleStates((prev) => ({ ...prev, media: !prev.media }))}
|
|
405
|
-
onFocus={() => handleFocus('Media Controls')}
|
|
406
|
-
onBlur={handleBlur}
|
|
407
|
-
value="media"
|
|
408
|
-
icon={<Play size={16} />}
|
|
409
|
-
>
|
|
410
|
-
Media Controls
|
|
411
|
-
</Toggle>
|
|
412
|
-
|
|
413
|
-
<Toggle
|
|
414
|
-
data-testid="social-toggle"
|
|
415
|
-
selected={toggleStates.social}
|
|
416
|
-
onChange={() => setToggleStates((prev) => ({ ...prev, social: !prev.social }))}
|
|
417
|
-
onFocus={() => handleFocus('Social Sharing')}
|
|
418
|
-
onBlur={handleBlur}
|
|
419
|
-
value="social"
|
|
420
|
-
variant="outline"
|
|
421
|
-
color="secondary"
|
|
422
|
-
icon={<Heart size={16} />}
|
|
423
|
-
>
|
|
424
|
-
Social Sharing
|
|
425
|
-
</Toggle>
|
|
426
|
-
|
|
427
|
-
<Toggle
|
|
428
|
-
data-testid="notifications-toggle"
|
|
429
|
-
selected={toggleStates.notifications}
|
|
430
|
-
onChange={() =>
|
|
431
|
-
setToggleStates((prev) => ({ ...prev, notifications: !prev.notifications }))
|
|
432
|
-
}
|
|
433
|
-
onFocus={() => handleFocus('Notifications')}
|
|
434
|
-
onBlur={handleBlur}
|
|
435
|
-
value="notifications"
|
|
436
|
-
variant="soft"
|
|
437
|
-
color="warning"
|
|
438
|
-
>
|
|
439
|
-
Notifications
|
|
440
|
-
</Toggle>
|
|
441
|
-
|
|
442
|
-
<div data-testid="toggle-states">{JSON.stringify(toggleStates)}</div>
|
|
443
|
-
</Box>
|
|
444
|
-
);
|
|
445
|
-
},
|
|
446
|
-
play: async ({ canvasElement }) => {
|
|
447
|
-
const canvas = within(canvasElement);
|
|
448
|
-
const mediaToggle = canvas.getByTestId('media-toggle');
|
|
449
|
-
const socialToggle = canvas.getByTestId('social-toggle');
|
|
450
|
-
const notificationsToggle = canvas.getByTestId('notifications-toggle');
|
|
451
|
-
const focusIndicator = canvas.getByTestId('focus-indicator');
|
|
452
|
-
|
|
453
|
-
// Test focus events
|
|
454
|
-
expect(focusIndicator).toHaveTextContent('Focused: None');
|
|
455
|
-
|
|
456
|
-
await userEvent.click(mediaToggle);
|
|
457
|
-
await userEvent.click(mediaToggle);
|
|
458
|
-
await waitFor(() => waitFor(() => {
|
|
459
|
-
expect(focusIndicator).toHaveTextContent('Focused: Media Controls');
|
|
460
|
-
}))
|
|
461
|
-
|
|
462
|
-
await userEvent.click(socialToggle);
|
|
463
|
-
await waitFor(() => waitFor(() => {
|
|
464
|
-
expect(focusIndicator).toHaveTextContent('Focused: Social Sharing');
|
|
465
|
-
}))
|
|
466
|
-
|
|
467
|
-
await userEvent.click(notificationsToggle);
|
|
468
|
-
await waitFor(() => waitFor(() => {
|
|
469
|
-
expect(focusIndicator).toHaveTextContent('Focused: Notifications');
|
|
470
|
-
}))
|
|
471
|
-
|
|
472
|
-
// Test blur by clicking outside
|
|
473
|
-
await userEvent.click(focusIndicator);
|
|
474
|
-
await waitFor(() => {
|
|
475
|
-
expect(focusIndicator).toHaveTextContent('Focused: None');
|
|
476
|
-
});
|
|
477
|
-
},
|
|
478
|
-
};
|
|
479
|
-
|
|
480
|
-
// Responsive Design Tests
|
|
481
|
-
export const ResponsiveDesign: Story = {
|
|
482
|
-
render: function ResponsiveDesignRender() {
|
|
483
|
-
const [mobileSelected, setMobileSelected] = useState(false);
|
|
484
|
-
const [tabletSelected, setTabletSelected] = useState(false);
|
|
485
|
-
const [desktopSelected, setDesktopSelected] = useState(false);
|
|
486
|
-
|
|
487
|
-
return (
|
|
488
|
-
<Box data-testid="responsive-container">
|
|
489
|
-
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, mb: 3 }}>
|
|
490
|
-
<h4>Mobile View (xs)</h4>
|
|
491
|
-
<Box sx={{ width: 320, border: '1px solid #ccc', p: 2 }}>
|
|
492
|
-
<Toggle
|
|
493
|
-
data-testid="mobile-toggle"
|
|
494
|
-
selected={mobileSelected}
|
|
495
|
-
onChange={() => setMobileSelected(!mobileSelected)}
|
|
496
|
-
size="sm"
|
|
497
|
-
fullWidth
|
|
498
|
-
value="mobile"
|
|
499
|
-
>
|
|
500
|
-
Mobile Toggle
|
|
501
|
-
</Toggle>
|
|
502
|
-
</Box>
|
|
503
|
-
</Box>
|
|
504
|
-
|
|
505
|
-
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, mb: 3 }}>
|
|
506
|
-
<h4>Tablet View (md)</h4>
|
|
507
|
-
<Box sx={{ width: 768, border: '1px solid #ccc', p: 2 }}>
|
|
508
|
-
<Toggle
|
|
509
|
-
data-testid="tablet-toggle"
|
|
510
|
-
selected={tabletSelected}
|
|
511
|
-
onChange={() => setTabletSelected(!tabletSelected)}
|
|
512
|
-
size="md"
|
|
513
|
-
value="tablet"
|
|
514
|
-
icon={<Star size={16} />}
|
|
515
|
-
>
|
|
516
|
-
Tablet Toggle
|
|
517
|
-
</Toggle>
|
|
518
|
-
</Box>
|
|
519
|
-
</Box>
|
|
520
|
-
|
|
521
|
-
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, mb: 3 }}>
|
|
522
|
-
<h4>Desktop View (lg)</h4>
|
|
523
|
-
<Box sx={{ width: 1024, border: '1px solid #ccc', p: 2 }}>
|
|
524
|
-
<Toggle
|
|
525
|
-
data-testid="desktop-toggle"
|
|
526
|
-
selected={desktopSelected}
|
|
527
|
-
onChange={() => setDesktopSelected(!desktopSelected)}
|
|
528
|
-
size="lg"
|
|
529
|
-
value="desktop"
|
|
530
|
-
variant="outline"
|
|
531
|
-
color="primary"
|
|
532
|
-
icon={<Settings size={18} />}
|
|
533
|
-
>
|
|
534
|
-
Desktop Toggle
|
|
535
|
-
</Toggle>
|
|
536
|
-
</Box>
|
|
537
|
-
</Box>
|
|
538
|
-
|
|
539
|
-
<div data-testid="responsive-state">
|
|
540
|
-
Mobile: {mobileSelected.toString()}, Tablet: {tabletSelected.toString()}, Desktop:{' '}
|
|
541
|
-
{desktopSelected.toString()}
|
|
542
|
-
</div>
|
|
543
|
-
</Box>
|
|
544
|
-
);
|
|
545
|
-
},
|
|
546
|
-
parameters: {
|
|
547
|
-
viewport: {
|
|
548
|
-
viewports: {
|
|
549
|
-
mobile: { name: 'Mobile', styles: { width: '375px', height: '667px' } },
|
|
550
|
-
tablet: { name: 'Tablet', styles: { width: '768px', height: '1024px' } },
|
|
551
|
-
desktop: { name: 'Desktop', styles: { width: '1024px', height: '768px' } },
|
|
552
|
-
},
|
|
553
|
-
defaultViewport: 'desktop',
|
|
554
|
-
},
|
|
555
|
-
},
|
|
556
|
-
play: async ({ canvasElement }) => {
|
|
557
|
-
const canvas = within(canvasElement);
|
|
558
|
-
const mobileToggle = canvas.getByTestId('mobile-toggle');
|
|
559
|
-
const tabletToggle = canvas.getByTestId('tablet-toggle');
|
|
560
|
-
const desktopToggle = canvas.getByTestId('desktop-toggle');
|
|
561
|
-
const stateDiv = canvas.getByTestId('responsive-state');
|
|
562
|
-
|
|
563
|
-
// Test toggles work in all viewport sizes
|
|
564
|
-
expect(stateDiv).toHaveTextContent('Mobile: false, Tablet: false, Desktop: false');
|
|
565
|
-
|
|
566
|
-
await userEvent.click(mobileToggle);
|
|
567
|
-
await waitFor(() => {
|
|
568
|
-
expect(stateDiv).toHaveTextContent('Mobile: true, Tablet: false, Desktop: false');
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
await userEvent.click(tabletToggle);
|
|
572
|
-
await waitFor(() => {
|
|
573
|
-
expect(stateDiv).toHaveTextContent('Mobile: true, Tablet: true, Desktop: false');
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
await userEvent.click(desktopToggle);
|
|
577
|
-
await waitFor(() => {
|
|
578
|
-
expect(stateDiv).toHaveTextContent('Mobile: true, Tablet: true, Desktop: true');
|
|
579
|
-
});
|
|
580
|
-
},
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
// Theme Variations Tests
|
|
584
|
-
export const ThemeVariations: Story = {
|
|
585
|
-
render: function ThemeVariationsRender() {
|
|
586
|
-
const theme = useTheme();
|
|
587
|
-
const [selected, setSelected] = useState(false);
|
|
588
|
-
|
|
589
|
-
return (
|
|
590
|
-
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
|
591
|
-
<div data-testid="theme-info">Current theme mode: {theme.palette.mode}</div>
|
|
592
|
-
|
|
593
|
-
<Paper elevation={0} sx={{ p: 2, backgroundColor: 'background.default' }}>
|
|
594
|
-
<h4>Light Theme</h4>
|
|
595
|
-
<Toggle
|
|
596
|
-
data-testid="light-theme-toggle"
|
|
597
|
-
selected={selected}
|
|
598
|
-
onChange={() => setSelected(!selected)}
|
|
599
|
-
value="light"
|
|
600
|
-
>
|
|
601
|
-
Light Theme Toggle
|
|
602
|
-
</Toggle>
|
|
603
|
-
</Paper>
|
|
604
|
-
|
|
605
|
-
<Paper elevation={2} sx={{ p: 2, backgroundColor: 'background.paper' }}>
|
|
606
|
-
<h4>Paper Background</h4>
|
|
607
|
-
<Toggle
|
|
608
|
-
data-testid="paper-theme-toggle"
|
|
609
|
-
selected={selected}
|
|
610
|
-
onChange={() => setSelected(!selected)}
|
|
611
|
-
value="paper"
|
|
612
|
-
variant="outline"
|
|
613
|
-
color="secondary"
|
|
614
|
-
>
|
|
615
|
-
Paper Theme Toggle
|
|
616
|
-
</Toggle>
|
|
617
|
-
</Paper>
|
|
618
|
-
|
|
619
|
-
<Box
|
|
620
|
-
sx={{
|
|
621
|
-
p: 2,
|
|
622
|
-
backgroundColor: 'primary.main',
|
|
623
|
-
color: 'primary.contrastText',
|
|
624
|
-
borderRadius: 1,
|
|
625
|
-
}}
|
|
626
|
-
>
|
|
627
|
-
<h4>Primary Background</h4>
|
|
628
|
-
<Toggle
|
|
629
|
-
data-testid="primary-theme-toggle"
|
|
630
|
-
selected={selected}
|
|
631
|
-
onChange={() => setSelected(!selected)}
|
|
632
|
-
value="primary"
|
|
633
|
-
variant="soft"
|
|
634
|
-
color="secondary"
|
|
635
|
-
>
|
|
636
|
-
Contrast Toggle
|
|
637
|
-
</Toggle>
|
|
638
|
-
</Box>
|
|
639
|
-
|
|
640
|
-
<div data-testid="theme-state">Selected: {selected.toString()}</div>
|
|
641
|
-
</Box>
|
|
642
|
-
);
|
|
643
|
-
},
|
|
644
|
-
play: async ({ canvasElement }) => {
|
|
645
|
-
const canvas = within(canvasElement);
|
|
646
|
-
const lightToggle = canvas.getByTestId('light-theme-toggle');
|
|
647
|
-
const paperToggle = canvas.getByTestId('paper-theme-toggle');
|
|
648
|
-
const primaryToggle = canvas.getByTestId('primary-theme-toggle');
|
|
649
|
-
const stateDiv = canvas.getByTestId('theme-state');
|
|
650
|
-
|
|
651
|
-
// Test all theme variants work
|
|
652
|
-
expect(stateDiv).toHaveTextContent('Selected: false');
|
|
653
|
-
|
|
654
|
-
await userEvent.click(lightToggle);
|
|
655
|
-
await waitFor(() => {
|
|
656
|
-
expect(stateDiv).toHaveTextContent('Selected: true');
|
|
657
|
-
});
|
|
658
|
-
|
|
659
|
-
// Test other toggles sync with state
|
|
660
|
-
await userEvent.click(paperToggle);
|
|
661
|
-
await waitFor(() => {
|
|
662
|
-
expect(stateDiv).toHaveTextContent('Selected: false');
|
|
663
|
-
});
|
|
664
|
-
|
|
665
|
-
await userEvent.click(primaryToggle);
|
|
666
|
-
await waitFor(() => {
|
|
667
|
-
expect(stateDiv).toHaveTextContent('Selected: true');
|
|
668
|
-
});
|
|
669
|
-
},
|
|
670
|
-
};
|
|
671
|
-
|
|
672
|
-
// Visual States Tests
|
|
673
|
-
export const VisualStates: Story = {
|
|
674
|
-
render: function VisualStatesRender() {
|
|
675
|
-
const [states, setStates] = useState({
|
|
676
|
-
normal: false,
|
|
677
|
-
hover: false,
|
|
678
|
-
focus: false,
|
|
679
|
-
active: false,
|
|
680
|
-
selected: true,
|
|
681
|
-
disabled: false,
|
|
682
|
-
});
|
|
683
|
-
|
|
684
|
-
return (
|
|
685
|
-
<Box
|
|
686
|
-
sx={{
|
|
687
|
-
display: 'grid',
|
|
688
|
-
gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
|
|
689
|
-
gap: 2,
|
|
690
|
-
}}
|
|
691
|
-
>
|
|
692
|
-
<Box>
|
|
693
|
-
<h4>Normal State</h4>
|
|
694
|
-
<Toggle
|
|
695
|
-
data-testid="normal-toggle"
|
|
696
|
-
selected={states.normal}
|
|
697
|
-
onChange={() => setStates((prev) => ({ ...prev, normal: !prev.normal }))}
|
|
698
|
-
value="normal"
|
|
699
|
-
>
|
|
700
|
-
Normal Toggle
|
|
701
|
-
</Toggle>
|
|
702
|
-
</Box>
|
|
703
|
-
|
|
704
|
-
<Box>
|
|
705
|
-
<h4>Hover State</h4>
|
|
706
|
-
<Toggle
|
|
707
|
-
data-testid="hover-toggle"
|
|
708
|
-
selected={states.hover}
|
|
709
|
-
onChange={() => setStates((prev) => ({ ...prev, hover: !prev.hover }))}
|
|
710
|
-
value="hover"
|
|
711
|
-
color="secondary"
|
|
712
|
-
>
|
|
713
|
-
Hover Toggle
|
|
714
|
-
</Toggle>
|
|
715
|
-
</Box>
|
|
716
|
-
|
|
717
|
-
<Box>
|
|
718
|
-
<h4>Focus State</h4>
|
|
719
|
-
<Toggle
|
|
720
|
-
data-testid="focus-toggle"
|
|
721
|
-
selected={states.focus}
|
|
722
|
-
onChange={() => setStates((prev) => ({ ...prev, focus: !prev.focus }))}
|
|
723
|
-
value="focus"
|
|
724
|
-
variant="outline"
|
|
725
|
-
color="success"
|
|
726
|
-
>
|
|
727
|
-
Focus Toggle
|
|
728
|
-
</Toggle>
|
|
729
|
-
</Box>
|
|
730
|
-
|
|
731
|
-
<Box>
|
|
732
|
-
<h4>Selected State</h4>
|
|
733
|
-
<Toggle
|
|
734
|
-
data-testid="selected-toggle"
|
|
735
|
-
selected={states.selected}
|
|
736
|
-
onChange={() => setStates((prev) => ({ ...prev, selected: !prev.selected }))}
|
|
737
|
-
value="selected"
|
|
738
|
-
color="warning"
|
|
739
|
-
>
|
|
740
|
-
Selected Toggle
|
|
741
|
-
</Toggle>
|
|
742
|
-
</Box>
|
|
743
|
-
|
|
744
|
-
<Box>
|
|
745
|
-
<h4>Disabled State</h4>
|
|
746
|
-
<Toggle
|
|
747
|
-
data-testid="disabled-toggle"
|
|
748
|
-
selected={states.disabled}
|
|
749
|
-
disabled
|
|
750
|
-
value="disabled"
|
|
751
|
-
>
|
|
752
|
-
Disabled Toggle
|
|
753
|
-
</Toggle>
|
|
754
|
-
</Box>
|
|
755
|
-
|
|
756
|
-
<Box>
|
|
757
|
-
<h4>Glass Effect</h4>
|
|
758
|
-
<Toggle data-testid="glass-toggle" selected={false} glass value="glass" color="primary">
|
|
759
|
-
Glass Toggle
|
|
760
|
-
</Toggle>
|
|
761
|
-
</Box>
|
|
762
|
-
|
|
763
|
-
<div data-testid="visual-states">{JSON.stringify(states)}</div>
|
|
764
|
-
</Box>
|
|
765
|
-
);
|
|
766
|
-
},
|
|
767
|
-
play: async ({ canvasElement }) => {
|
|
768
|
-
const canvas = within(canvasElement);
|
|
769
|
-
const normalToggle = canvas.getByTestId('normal-toggle');
|
|
770
|
-
const hoverToggle = canvas.getByTestId('hover-toggle');
|
|
771
|
-
const focusToggle = canvas.getByTestId('focus-toggle');
|
|
772
|
-
const selectedToggle = canvas.getByTestId('selected-toggle');
|
|
773
|
-
const disabledToggle = canvas.getByTestId('disabled-toggle');
|
|
774
|
-
const glassToggle = canvas.getByTestId('glass-toggle');
|
|
775
|
-
|
|
776
|
-
// Test visual states render correctly
|
|
777
|
-
expect(normalToggle).toBeInTheDocument();
|
|
778
|
-
expect(hoverToggle).toBeInTheDocument();
|
|
779
|
-
expect(focusToggle).toBeInTheDocument();
|
|
780
|
-
expect(selectedToggle).toHaveAttribute('aria-pressed', 'true');
|
|
781
|
-
expect(disabledToggle).toBeDisabled();
|
|
782
|
-
expect(glassToggle).toBeInTheDocument();
|
|
783
|
-
|
|
784
|
-
// Test interactions
|
|
785
|
-
await userEvent.click(normalToggle);
|
|
786
|
-
expect(normalToggle).toHaveAttribute('aria-pressed', 'true');
|
|
787
|
-
|
|
788
|
-
// Test hover simulation
|
|
789
|
-
await userEvent.hover(hoverToggle);
|
|
790
|
-
await userEvent.click(hoverToggle);
|
|
791
|
-
expect(hoverToggle).toHaveAttribute('aria-pressed', 'true');
|
|
792
|
-
|
|
793
|
-
// Test focus
|
|
794
|
-
await userEvent.click(focusToggle);
|
|
795
|
-
await waitFor(() => expect(focusToggle).toHaveFocus());
|
|
796
|
-
await userEvent.keyboard(' ');
|
|
797
|
-
expect(focusToggle).toHaveAttribute('aria-pressed', 'true');
|
|
798
|
-
},
|
|
799
|
-
};
|
|
800
|
-
|
|
801
|
-
// Performance Tests
|
|
802
|
-
export const Performance: Story = {
|
|
803
|
-
render: function PerformanceRender() {
|
|
804
|
-
const [toggles, setToggles] = useState(
|
|
805
|
-
Array(50)
|
|
806
|
-
.fill(false)
|
|
807
|
-
.map((_, index) => ({ id: index, selected: false })),
|
|
808
|
-
);
|
|
809
|
-
|
|
810
|
-
const toggleHandler = fn((id: number) => {
|
|
811
|
-
setToggles((prev) =>
|
|
812
|
-
prev.map((toggle) =>
|
|
813
|
-
toggle.id === id ? { ...toggle, selected: !toggle.selected } : toggle,
|
|
814
|
-
),
|
|
815
|
-
);
|
|
816
|
-
});
|
|
817
|
-
|
|
818
|
-
return (
|
|
819
|
-
<Box data-testid="performance-container">
|
|
820
|
-
<div data-testid="performance-info">Rendering {toggles.length} Toggle components</div>
|
|
821
|
-
|
|
822
|
-
<Box
|
|
823
|
-
sx={{
|
|
824
|
-
display: 'grid',
|
|
825
|
-
gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))',
|
|
826
|
-
gap: 1,
|
|
827
|
-
maxHeight: 400,
|
|
828
|
-
overflowY: 'auto',
|
|
829
|
-
}}
|
|
830
|
-
>
|
|
831
|
-
{toggles.map((toggle) => (
|
|
832
|
-
<Toggle
|
|
833
|
-
key={toggle.id}
|
|
834
|
-
data-testid={`perf-toggle-${toggle.id}`}
|
|
835
|
-
selected={toggle.selected}
|
|
836
|
-
onChange={() => toggleHandler(toggle.id)}
|
|
837
|
-
value={`toggle-${toggle.id}`}
|
|
838
|
-
size="sm"
|
|
839
|
-
>
|
|
840
|
-
#{toggle.id}
|
|
841
|
-
</Toggle>
|
|
842
|
-
))}
|
|
843
|
-
</Box>
|
|
844
|
-
|
|
845
|
-
<div data-testid="selected-count">Selected: {toggles.filter((t) => t.selected).length}</div>
|
|
846
|
-
</Box>
|
|
847
|
-
);
|
|
848
|
-
},
|
|
849
|
-
play: async ({ canvasElement }) => {
|
|
850
|
-
const canvas = within(canvasElement);
|
|
851
|
-
const performanceInfo = canvas.getByTestId('performance-info');
|
|
852
|
-
const selectedCount = canvas.getByTestId('selected-count');
|
|
853
|
-
|
|
854
|
-
// Verify all toggles rendered
|
|
855
|
-
expect(performanceInfo).toHaveTextContent('Rendering 50 Toggle components');
|
|
856
|
-
expect(selectedCount).toHaveTextContent('Selected: 0');
|
|
857
|
-
|
|
858
|
-
// Test rapid interactions
|
|
859
|
-
const firstToggle = canvas.getByTestId('perf-toggle-0');
|
|
860
|
-
const secondToggle = canvas.getByTestId('perf-toggle-1');
|
|
861
|
-
const thirdToggle = canvas.getByTestId('perf-toggle-2');
|
|
862
|
-
|
|
863
|
-
await userEvent.click(firstToggle);
|
|
864
|
-
await userEvent.click(secondToggle);
|
|
865
|
-
await userEvent.click(thirdToggle);
|
|
866
|
-
|
|
867
|
-
await waitFor(() => {
|
|
868
|
-
expect(selectedCount).toHaveTextContent('Selected: 3');
|
|
869
|
-
});
|
|
870
|
-
},
|
|
871
|
-
};
|
|
872
|
-
|
|
873
|
-
// Edge Cases Tests
|
|
874
|
-
export const EdgeCases: Story = {
|
|
875
|
-
render: function EdgeCasesRender() {
|
|
876
|
-
const [states, setStates] = useState({
|
|
877
|
-
empty: false,
|
|
878
|
-
longText: false,
|
|
879
|
-
specialChars: false,
|
|
880
|
-
numbers: false,
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
return (
|
|
884
|
-
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, maxWidth: 600 }}>
|
|
885
|
-
<h4>Edge Cases Testing</h4>
|
|
886
|
-
|
|
887
|
-
<Box>
|
|
888
|
-
<h5>Empty Content</h5>
|
|
889
|
-
<Toggle
|
|
890
|
-
data-testid="empty-toggle"
|
|
891
|
-
selected={states.empty}
|
|
892
|
-
onChange={() => setStates((prev) => ({ ...prev, empty: !prev.empty }))}
|
|
893
|
-
value=""
|
|
894
|
-
icon={<Star size={16} />}
|
|
895
|
-
/>
|
|
896
|
-
</Box>
|
|
897
|
-
|
|
898
|
-
<Box>
|
|
899
|
-
<h5>Very Long Text</h5>
|
|
900
|
-
<Toggle
|
|
901
|
-
data-testid="long-text-toggle"
|
|
902
|
-
selected={states.longText}
|
|
903
|
-
onChange={() => setStates((prev) => ({ ...prev, longText: !prev.longText }))}
|
|
904
|
-
value="very-long-text"
|
|
905
|
-
sx={{ maxWidth: 300 }}
|
|
906
|
-
>
|
|
907
|
-
This is a very long toggle button text that should wrap properly and maintain good
|
|
908
|
-
usability even when the content exceeds normal expectations
|
|
909
|
-
</Toggle>
|
|
910
|
-
</Box>
|
|
911
|
-
|
|
912
|
-
<Box>
|
|
913
|
-
<h5>Special Characters & Emojis</h5>
|
|
914
|
-
<Toggle
|
|
915
|
-
data-testid="special-chars-toggle"
|
|
916
|
-
selected={states.specialChars}
|
|
917
|
-
onChange={() => setStates((prev) => ({ ...prev, specialChars: !prev.specialChars }))}
|
|
918
|
-
value="special-chars"
|
|
919
|
-
>
|
|
920
|
-
🌟 Special & "Chars" <>&{'{}'} 测试 العربية
|
|
921
|
-
</Toggle>
|
|
922
|
-
</Box>
|
|
923
|
-
|
|
924
|
-
<Box>
|
|
925
|
-
<h5>Numeric Values</h5>
|
|
926
|
-
<Toggle
|
|
927
|
-
data-testid="numeric-toggle"
|
|
928
|
-
selected={states.numbers}
|
|
929
|
-
onChange={() => setStates((prev) => ({ ...prev, numbers: !prev.numbers }))}
|
|
930
|
-
value={42}
|
|
931
|
-
>
|
|
932
|
-
Numeric Value: 42
|
|
933
|
-
</Toggle>
|
|
934
|
-
</Box>
|
|
935
|
-
|
|
936
|
-
<div data-testid="edge-cases-state">{JSON.stringify(states)}</div>
|
|
937
|
-
</Box>
|
|
938
|
-
);
|
|
939
|
-
},
|
|
940
|
-
play: async ({ canvasElement }) => {
|
|
941
|
-
const canvas = within(canvasElement);
|
|
942
|
-
const emptyToggle = canvas.getByTestId('empty-toggle');
|
|
943
|
-
const longTextToggle = canvas.getByTestId('long-text-toggle');
|
|
944
|
-
const specialCharsToggle = canvas.getByTestId('special-chars-toggle');
|
|
945
|
-
const numericToggle = canvas.getByTestId('numeric-toggle');
|
|
946
|
-
const stateDiv = canvas.getByTestId('edge-cases-state');
|
|
947
|
-
|
|
948
|
-
// Test empty content toggle (icon only)
|
|
949
|
-
expect(emptyToggle).toBeInTheDocument();
|
|
950
|
-
await userEvent.click(emptyToggle);
|
|
951
|
-
await waitFor(() => {
|
|
952
|
-
expect(stateDiv).toHaveTextContent('"empty":true');
|
|
953
|
-
});
|
|
954
|
-
|
|
955
|
-
// Test long text toggle
|
|
956
|
-
expect(longTextToggle).toBeInTheDocument();
|
|
957
|
-
await userEvent.click(longTextToggle);
|
|
958
|
-
await waitFor(() => {
|
|
959
|
-
expect(stateDiv).toHaveTextContent('"longText":true');
|
|
960
|
-
});
|
|
961
|
-
|
|
962
|
-
// Test special characters
|
|
963
|
-
expect(specialCharsToggle).toHaveTextContent('🌟 Special & "Chars" <>&{} 测试 العربية');
|
|
964
|
-
await userEvent.click(specialCharsToggle);
|
|
965
|
-
await waitFor(() => {
|
|
966
|
-
expect(stateDiv).toHaveTextContent('"specialChars":true');
|
|
967
|
-
});
|
|
968
|
-
|
|
969
|
-
// Test numeric value
|
|
970
|
-
expect(numericToggle).toHaveTextContent('Numeric Value: 42');
|
|
971
|
-
await userEvent.click(numericToggle);
|
|
972
|
-
await waitFor(() => {
|
|
973
|
-
expect(stateDiv).toHaveTextContent('"numbers":true');
|
|
974
|
-
});
|
|
975
|
-
},
|
|
976
|
-
};
|
|
977
|
-
|
|
978
|
-
// Integration Tests
|
|
979
|
-
export const Integration: Story = {
|
|
980
|
-
render: function IntegrationRender() {
|
|
981
|
-
const [preferences, setPreferences] = useState({
|
|
982
|
-
theme: 'light',
|
|
983
|
-
notifications: true,
|
|
984
|
-
autoSave: false,
|
|
985
|
-
analytics: false,
|
|
986
|
-
});
|
|
987
|
-
|
|
988
|
-
const [player, setPlayer] = useState({
|
|
989
|
-
isPlaying: false,
|
|
990
|
-
isMuted: false,
|
|
991
|
-
repeat: false,
|
|
992
|
-
});
|
|
993
|
-
|
|
994
|
-
return (
|
|
995
|
-
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
|
996
|
-
<Box>
|
|
997
|
-
<h4>User Preferences Integration</h4>
|
|
998
|
-
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 2 }}>
|
|
999
|
-
<Toggle
|
|
1000
|
-
data-testid="theme-toggle"
|
|
1001
|
-
selected={preferences.theme === 'dark'}
|
|
1002
|
-
onChange={() =>
|
|
1003
|
-
setPreferences((prev) => ({
|
|
1004
|
-
...prev,
|
|
1005
|
-
theme: prev.theme === 'light' ? 'dark' : 'light',
|
|
1006
|
-
}))
|
|
1007
|
-
}
|
|
1008
|
-
value="theme"
|
|
1009
|
-
variant="outline"
|
|
1010
|
-
color="neutral"
|
|
1011
|
-
>
|
|
1012
|
-
Dark Mode
|
|
1013
|
-
</Toggle>
|
|
1014
|
-
|
|
1015
|
-
<Toggle
|
|
1016
|
-
data-testid="notifications-pref-toggle"
|
|
1017
|
-
selected={preferences.notifications}
|
|
1018
|
-
onChange={() =>
|
|
1019
|
-
setPreferences((prev) => ({
|
|
1020
|
-
...prev,
|
|
1021
|
-
notifications: !prev.notifications,
|
|
1022
|
-
}))
|
|
1023
|
-
}
|
|
1024
|
-
value="notifications"
|
|
1025
|
-
color="warning"
|
|
1026
|
-
>
|
|
1027
|
-
Notifications
|
|
1028
|
-
</Toggle>
|
|
1029
|
-
|
|
1030
|
-
<Toggle
|
|
1031
|
-
data-testid="autosave-toggle"
|
|
1032
|
-
selected={preferences.autoSave}
|
|
1033
|
-
onChange={() =>
|
|
1034
|
-
setPreferences((prev) => ({
|
|
1035
|
-
...prev,
|
|
1036
|
-
autoSave: !prev.autoSave,
|
|
1037
|
-
}))
|
|
1038
|
-
}
|
|
1039
|
-
value="autoSave"
|
|
1040
|
-
variant="soft"
|
|
1041
|
-
color="success"
|
|
1042
|
-
>
|
|
1043
|
-
Auto Save
|
|
1044
|
-
</Toggle>
|
|
1045
|
-
|
|
1046
|
-
<Toggle
|
|
1047
|
-
data-testid="analytics-toggle"
|
|
1048
|
-
selected={preferences.analytics}
|
|
1049
|
-
onChange={() =>
|
|
1050
|
-
setPreferences((prev) => ({
|
|
1051
|
-
...prev,
|
|
1052
|
-
analytics: !prev.analytics,
|
|
1053
|
-
}))
|
|
1054
|
-
}
|
|
1055
|
-
value="analytics"
|
|
1056
|
-
variant="soft"
|
|
1057
|
-
color="secondary"
|
|
1058
|
-
>
|
|
1059
|
-
Analytics
|
|
1060
|
-
</Toggle>
|
|
1061
|
-
</Box>
|
|
1062
|
-
</Box>
|
|
1063
|
-
|
|
1064
|
-
<Box>
|
|
1065
|
-
<h4>Media Player Integration</h4>
|
|
1066
|
-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
|
1067
|
-
<Toggle
|
|
1068
|
-
data-testid="play-pause-toggle"
|
|
1069
|
-
selected={player.isPlaying}
|
|
1070
|
-
onChange={() =>
|
|
1071
|
-
setPlayer((prev) => ({
|
|
1072
|
-
...prev,
|
|
1073
|
-
isPlaying: !prev.isPlaying,
|
|
1074
|
-
}))
|
|
1075
|
-
}
|
|
1076
|
-
value="playPause"
|
|
1077
|
-
icon={player.isPlaying ? <Pause size={16} /> : <Play size={16} />}
|
|
1078
|
-
color="primary"
|
|
1079
|
-
size="lg"
|
|
1080
|
-
/>
|
|
1081
|
-
|
|
1082
|
-
<Toggle
|
|
1083
|
-
data-testid="mute-toggle"
|
|
1084
|
-
selected={player.isMuted}
|
|
1085
|
-
onChange={() =>
|
|
1086
|
-
setPlayer((prev) => ({
|
|
1087
|
-
...prev,
|
|
1088
|
-
isMuted: !prev.isMuted,
|
|
1089
|
-
}))
|
|
1090
|
-
}
|
|
1091
|
-
value="mute"
|
|
1092
|
-
variant="outline"
|
|
1093
|
-
color="secondary"
|
|
1094
|
-
>
|
|
1095
|
-
{player.isMuted ? 'Unmute' : 'Mute'}
|
|
1096
|
-
</Toggle>
|
|
1097
|
-
|
|
1098
|
-
<Toggle
|
|
1099
|
-
data-testid="repeat-toggle"
|
|
1100
|
-
selected={player.repeat}
|
|
1101
|
-
onChange={() =>
|
|
1102
|
-
setPlayer((prev) => ({
|
|
1103
|
-
...prev,
|
|
1104
|
-
repeat: !prev.repeat,
|
|
1105
|
-
}))
|
|
1106
|
-
}
|
|
1107
|
-
value="repeat"
|
|
1108
|
-
variant="soft"
|
|
1109
|
-
color="neutral"
|
|
1110
|
-
>
|
|
1111
|
-
Repeat
|
|
1112
|
-
</Toggle>
|
|
1113
|
-
</Box>
|
|
1114
|
-
</Box>
|
|
1115
|
-
|
|
1116
|
-
<div data-testid="integration-state">
|
|
1117
|
-
Preferences: {JSON.stringify(preferences)}
|
|
1118
|
-
Player: {JSON.stringify(player)}
|
|
1119
|
-
</div>
|
|
1120
|
-
</Box>
|
|
1121
|
-
);
|
|
1122
|
-
},
|
|
1123
|
-
play: async ({ canvasElement }) => {
|
|
1124
|
-
const canvas = within(canvasElement);
|
|
1125
|
-
const themeToggle = canvas.getByTestId('theme-toggle');
|
|
1126
|
-
const notificationsToggle = canvas.getByTestId('notifications-pref-toggle');
|
|
1127
|
-
const playToggle = canvas.getByTestId('play-pause-toggle');
|
|
1128
|
-
const muteToggle = canvas.getByTestId('mute-toggle');
|
|
1129
|
-
const stateDiv = canvas.getByTestId('integration-state');
|
|
1130
|
-
|
|
1131
|
-
// Test integration between multiple toggle components
|
|
1132
|
-
expect(stateDiv.textContent).toContain('theme":"light');
|
|
1133
|
-
expect(stateDiv.textContent).toContain('notifications":true');
|
|
1134
|
-
expect(stateDiv.textContent).toContain('isPlaying":false');
|
|
1135
|
-
|
|
1136
|
-
// Test theme toggle affects preferences
|
|
1137
|
-
await userEvent.click(themeToggle);
|
|
1138
|
-
await waitFor(() => {
|
|
1139
|
-
expect(stateDiv.textContent).toContain('theme":"dark');
|
|
1140
|
-
});
|
|
1141
|
-
|
|
1142
|
-
// Test notifications toggle
|
|
1143
|
-
await userEvent.click(notificationsToggle);
|
|
1144
|
-
await waitFor(() => {
|
|
1145
|
-
expect(stateDiv.textContent).toContain('notifications":false');
|
|
1146
|
-
});
|
|
1147
|
-
|
|
1148
|
-
// Test media player controls
|
|
1149
|
-
await userEvent.click(playToggle);
|
|
1150
|
-
await waitFor(() => {
|
|
1151
|
-
expect(stateDiv.textContent).toContain('isPlaying":true');
|
|
1152
|
-
});
|
|
1153
|
-
|
|
1154
|
-
await userEvent.click(muteToggle);
|
|
1155
|
-
await waitFor(() => {
|
|
1156
|
-
expect(stateDiv.textContent).toContain('isMuted":true');
|
|
1157
|
-
});
|
|
1158
|
-
},
|
|
1159
|
-
};
|