@12-apps/ui 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/package.json +17 -9
  2. package/src/button/index.ts +1 -0
  3. package/src/social-login-button/index.ts +1 -0
  4. package/src/{social-login-button.tsx → social-login-button/social-login-button.tsx} +5 -5
  5. package/src/user-avatar/index.ts +1 -0
  6. package/src/{user-avatar.tsx → user-avatar/user-avatar.tsx} +4 -4
  7. package/eslint.config.js +0 -89
  8. package/src/__tests__/data-grid.test.tsx +0 -125
  9. package/src/__tests__/package-wiring.test.ts +0 -41
  10. package/src/__tests__/setup.ts +0 -1
  11. package/src/__tests__/social-login-button.test.tsx +0 -186
  12. package/src/__tests__/user-avatar.test.tsx +0 -195
  13. package/src/__tests__/viewport.test.ts +0 -50
  14. package/src/components/command/__tests__/command.test.tsx +0 -112
  15. package/src/components/data-display/Alert/Alert.stories.tsx +0 -559
  16. package/src/components/data-display/Alert/Alert.test.stories.tsx +0 -707
  17. package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +0 -362
  18. package/src/components/data-display/AlertDialog/AlertDialog.test.stories.tsx +0 -763
  19. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.stories.tsx +0 -230
  20. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +0 -270
  21. package/src/components/data-display/Avatar/Avatar.stories.tsx +0 -721
  22. package/src/components/data-display/Avatar/Avatar.test.stories.tsx +0 -822
  23. package/src/components/data-display/Badge/Badge.stories.tsx +0 -1134
  24. package/src/components/data-display/Badge/Badge.test.stories.tsx +0 -1194
  25. package/src/components/data-display/Banner/Banner.stories.tsx +0 -528
  26. package/src/components/data-display/Banner/Banner.test.stories.tsx +0 -511
  27. package/src/components/data-display/Carousel/Carousel.stories.tsx +0 -607
  28. package/src/components/data-display/Carousel/Carousel.test.stories.tsx +0 -701
  29. package/src/components/data-display/Chart/Chart.stories.tsx +0 -568
  30. package/src/components/data-display/Chart/Chart.test.stories.tsx +0 -174
  31. package/src/components/data-display/Chart/SpecChart.stories.tsx +0 -150
  32. package/src/components/data-display/Chart/SpecChart.test.stories.tsx +0 -56
  33. package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +0 -60
  34. package/src/components/data-display/Chart/__tests__/chart-format.test.ts +0 -43
  35. package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +0 -119
  36. package/src/components/data-display/Chip/Chip.stories.tsx +0 -252
  37. package/src/components/data-display/Chip/Chip.test.stories.tsx +0 -266
  38. package/src/components/data-display/DataGrid/DataGrid.stories.tsx +0 -515
  39. package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +0 -653
  40. package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +0 -271
  41. package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +0 -134
  42. package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +0 -83
  43. package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +0 -115
  44. package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +0 -53
  45. package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +0 -114
  46. package/src/components/data-display/DataViews/base-card.stories.tsx +0 -136
  47. package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +0 -254
  48. package/src/components/data-display/EmptyState/EmptyState.stories.tsx +0 -282
  49. package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +0 -441
  50. package/src/components/data-display/ErrorState/ErrorState.stories.tsx +0 -110
  51. package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +0 -133
  52. package/src/components/data-display/HoverCard/HoverCard.stories.tsx +0 -650
  53. package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +0 -929
  54. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.stories.tsx +0 -411
  55. package/src/components/data-display/LazyImage/LazyImage.stories.tsx +0 -387
  56. package/src/components/data-display/Lightbox/Lightbox.stories.tsx +0 -315
  57. package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +0 -598
  58. package/src/components/data-display/LoadingState/LoadingState.stories.tsx +0 -124
  59. package/src/components/data-display/LoadingState/LoadingState.test.stories.tsx +0 -99
  60. package/src/components/data-display/MapPreview/MapPreview.stories.tsx +0 -458
  61. package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +0 -394
  62. package/src/components/data-display/Popover/Popover.stories.tsx +0 -295
  63. package/src/components/data-display/Popover/Popover.test.stories.tsx +0 -1162
  64. package/src/components/data-display/Progress/Progress.stories.tsx +0 -481
  65. package/src/components/data-display/Progress/Progress.test.stories.tsx +0 -2070
  66. package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +0 -160
  67. package/src/components/data-display/SectionOnboarding/SectionOnboarding.test.stories.tsx +0 -190
  68. package/src/components/data-display/Sheet/Sheet.stories.tsx +0 -883
  69. package/src/components/data-display/Sheet/Sheet.test.stories.tsx +0 -1105
  70. package/src/components/data-display/StatCard/StatCard.stories.tsx +0 -167
  71. package/src/components/data-display/StatCard/StatCard.test.stories.tsx +0 -240
  72. package/src/components/data-display/Stepper/Stepper.stories.tsx +0 -540
  73. package/src/components/data-display/Stepper/Stepper.test.stories.tsx +0 -600
  74. package/src/components/data-display/Table/Table.stories.tsx +0 -803
  75. package/src/components/data-display/Table/Table.test.stories.tsx +0 -369
  76. package/src/components/data-display/Timeline/Timeline.stories.tsx +0 -442
  77. package/src/components/data-display/Timeline/Timeline.test.stories.tsx +0 -930
  78. package/src/components/data-display/TimingDiagram/TimingDiagram.stories.tsx +0 -475
  79. package/src/components/data-display/TimingDiagram/TimingDiagram.test.stories.tsx +0 -734
  80. package/src/components/data-display/Tooltip/Tooltip.stories.tsx +0 -468
  81. package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +0 -1154
  82. package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +0 -146
  83. package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +0 -114
  84. package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +0 -288
  85. package/src/components/feedback/Dialog/Dialog.stories.tsx +0 -833
  86. package/src/components/feedback/Dialog/Dialog.test.stories.tsx +0 -964
  87. package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +0 -66
  88. package/src/components/feedback/Modal/Modal.stories.tsx +0 -765
  89. package/src/components/feedback/Modal/Modal.test.stories.tsx +0 -251
  90. package/src/components/feedback/Sonner/Sonner.stories.tsx +0 -698
  91. package/src/components/feedback/Sonner/Sonner.test.stories.tsx +0 -896
  92. package/src/components/feedback/StackedModal/StackedModal.stories.tsx +0 -1783
  93. package/src/components/feedback/StackedModal/StackedModal.test.stories.tsx +0 -973
  94. package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +0 -104
  95. package/src/components/feedback/Toast/Toast.stories.tsx +0 -548
  96. package/src/components/feedback/Toast/Toast.test.stories.tsx +0 -834
  97. package/src/components/feedback/TutorialOverlay/TutorialOverlay.stories.tsx +0 -691
  98. package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +0 -634
  99. package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +0 -665
  100. package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +0 -727
  101. package/src/components/form/Autocomplete/Autocomplete.stories.tsx +0 -715
  102. package/src/components/form/Autocomplete/Autocomplete.test.stories.tsx +0 -825
  103. package/src/components/form/Button/Button.stories.tsx +0 -365
  104. package/src/components/form/Button/Button.test.stories.tsx +0 -607
  105. package/src/components/form/Calendar/Calendar.stories.tsx +0 -349
  106. package/src/components/form/Calendar/Calendar.test.stories.tsx +0 -464
  107. package/src/components/form/CepField/CepField.stories.tsx +0 -138
  108. package/src/components/form/CepField/CepField.test.stories.tsx +0 -281
  109. package/src/components/form/Checkbox/Checkbox.stories.tsx +0 -265
  110. package/src/components/form/Checkbox/Checkbox.test.stories.tsx +0 -181
  111. package/src/components/form/CodeEditor/CodeEditor.stories.tsx +0 -871
  112. package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +0 -574
  113. package/src/components/form/Command/Command.stories.tsx +0 -580
  114. package/src/components/form/Command/Command.test.stories.tsx +0 -215
  115. package/src/components/form/CreatableSelect/CreatableSelect.stories.tsx +0 -112
  116. package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +0 -134
  117. package/src/components/form/Form/Form.stories.tsx +0 -687
  118. package/src/components/form/Form/Form.test.stories.tsx +0 -601
  119. package/src/components/form/Input/Input.stories.tsx +0 -260
  120. package/src/components/form/Input/Input.test.stories.tsx +0 -1191
  121. package/src/components/form/InputOTP/InputOTP.stories.tsx +0 -774
  122. package/src/components/form/InputOTP/InputOTP.test.stories.tsx +0 -588
  123. package/src/components/form/Label/Label.stories.tsx +0 -473
  124. package/src/components/form/Label/Label.test.stories.tsx +0 -915
  125. package/src/components/form/Menubar/Menubar.stories.tsx +0 -472
  126. package/src/components/form/Menubar/Menubar.test.stories.tsx +0 -584
  127. package/src/components/form/PasswordStrength/PasswordStrength.stories.tsx +0 -562
  128. package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +0 -327
  129. package/src/components/form/PhoneInput/PhoneInput.stories.tsx +0 -495
  130. package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +0 -666
  131. package/src/components/form/RadioGroup/RadioGroup.stories.tsx +0 -518
  132. package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +0 -685
  133. package/src/components/form/RichTextEditor/RichTextEditor.stories.tsx +0 -261
  134. package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +0 -491
  135. package/src/components/form/SearchPalette/SearchPalette.stories.tsx +0 -135
  136. package/src/components/form/Select/Select.stories.tsx +0 -364
  137. package/src/components/form/Select/Select.test.stories.tsx +0 -985
  138. package/src/components/form/Slider/Slider.stories.tsx +0 -418
  139. package/src/components/form/Slider/Slider.test.stories.tsx +0 -1042
  140. package/src/components/form/Switch/Switch.stories.tsx +0 -697
  141. package/src/components/form/Switch/Switch.test.stories.tsx +0 -597
  142. package/src/components/form/Textarea/Textarea.stories.tsx +0 -473
  143. package/src/components/form/Textarea/Textarea.test.stories.tsx +0 -702
  144. package/src/components/form/Toggle/Toggle.stories.tsx +0 -638
  145. package/src/components/form/Toggle/Toggle.test.stories.tsx +0 -1159
  146. package/src/components/form/ToggleGroup/ToggleGroup.stories.tsx +0 -617
  147. package/src/components/form/ToggleGroup/ToggleGroup.test.stories.tsx +0 -915
  148. package/src/components/form/UploadButton/UploadButton.stories.tsx +0 -367
  149. package/src/components/form/UploadButton/UploadButton.test.stories.tsx +0 -573
  150. package/src/components/form/total-form/total-form.test.tsx +0 -214
  151. package/src/components/layout/Accordion/Accordion.stories.tsx +0 -694
  152. package/src/components/layout/Accordion/Accordion.test.stories.tsx +0 -1344
  153. package/src/components/layout/Card/Card.stories.tsx +0 -591
  154. package/src/components/layout/Card/Card.test.stories.tsx +0 -1134
  155. package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +0 -92
  156. package/src/components/layout/Collapsible/Collapsible.stories.tsx +0 -180
  157. package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +0 -308
  158. package/src/components/layout/Container/Container.stories.tsx +0 -557
  159. package/src/components/layout/Container/Container.test.stories.tsx +0 -745
  160. package/src/components/layout/ContentToolbar/ContentToolbar.stories.tsx +0 -129
  161. package/src/components/layout/ContentToolbar/ContentToolbar.test.stories.tsx +0 -251
  162. package/src/components/layout/ContentToolbar/__tests__/ColumnsMenu.test.tsx +0 -39
  163. package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +0 -131
  164. package/src/components/layout/ContentToolbar/__tests__/SavedViewsMenu.test.tsx +0 -99
  165. package/src/components/layout/Dashboard/Dashboard.stories.tsx +0 -104
  166. package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +0 -190
  167. package/src/components/layout/Drawer/Drawer.stories.tsx +0 -658
  168. package/src/components/layout/Drawer/Drawer.test.stories.tsx +0 -1343
  169. package/src/components/layout/Resizable/Resizable.stories.tsx +0 -1039
  170. package/src/components/layout/Resizable/Resizable.test.stories.tsx +0 -754
  171. package/src/components/layout/ScrollArea/ScrollArea.stories.tsx +0 -651
  172. package/src/components/layout/ScrollArea/ScrollArea.test.stories.tsx +0 -619
  173. package/src/components/layout/Separator/Separator.stories.tsx +0 -563
  174. package/src/components/layout/Separator/Separator.test.stories.tsx +0 -518
  175. package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +0 -192
  176. package/src/components/layout/SettingsLayout/SettingsLayout.test.stories.tsx +0 -175
  177. package/src/components/layout/Sidebar/Sidebar.stories.tsx +0 -609
  178. package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +0 -1324
  179. package/src/components/layout/Skeleton/Skeleton.stories.tsx +0 -689
  180. package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +0 -521
  181. package/src/components/layout/Spacer/Spacer.stories.tsx +0 -502
  182. package/src/components/layout/Spacer/Spacer.test.stories.tsx +0 -474
  183. package/src/components/layout/TableFilter/TableFilter.stories.tsx +0 -82
  184. package/src/components/layout/TableFilter/TableFilter.test.stories.tsx +0 -87
  185. package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +0 -638
  186. package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +0 -1008
  187. package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +0 -386
  188. package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +0 -435
  189. package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +0 -614
  190. package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +0 -845
  191. package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +0 -578
  192. package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +0 -660
  193. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +0 -516
  194. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +0 -935
  195. package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +0 -501
  196. package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +0 -453
  197. package/src/components/navigation/Pagination/Pagination.stories.tsx +0 -602
  198. package/src/components/navigation/Pagination/Pagination.test.stories.tsx +0 -520
  199. package/src/components/navigation/Tabs/Tabs.stories.tsx +0 -1004
  200. package/src/components/navigation/Tabs/Tabs.test.stories.tsx +0 -1225
  201. package/src/components/typography/Blockquote/Blockquote.stories.tsx +0 -359
  202. package/src/components/typography/Blockquote/Blockquote.test.stories.tsx +0 -432
  203. package/src/components/typography/Code/Code.stories.tsx +0 -686
  204. package/src/components/typography/Code/Code.test.stories.tsx +0 -703
  205. package/src/components/typography/Heading/Heading.stories.tsx +0 -451
  206. package/src/components/typography/Heading/Heading.test.stories.tsx +0 -830
  207. package/src/components/typography/Paragraph/Paragraph.stories.tsx +0 -280
  208. package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +0 -231
  209. package/src/components/typography/Text/Text.stories.tsx +0 -359
  210. package/src/components/typography/Text/Text.test.stories.tsx +0 -759
  211. package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +0 -945
  212. package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +0 -603
  213. package/src/components/utility/AspectRatio/AspectRatio.stories.tsx +0 -414
  214. package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +0 -859
  215. package/src/components/utility/InfiniteScroll/InfiniteScroll.stories.tsx +0 -620
  216. package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +0 -361
  217. package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +0 -118
  218. package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +0 -83
  219. package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +0 -65
  220. package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +0 -271
  221. package/src/components/utility/Portal/Portal.stories.tsx +0 -340
  222. package/src/components/utility/Portal/Portal.test.stories.tsx +0 -2086
  223. package/src/components/utility/Transition/Transition.stories.tsx +0 -493
  224. package/src/components/utility/Transition/Transition.test.stories.tsx +0 -854
  225. package/src/components/utility/VirtualList/VirtualList.stories.tsx +0 -1073
  226. package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +0 -1085
  227. package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +0 -431
  228. package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +0 -364
  229. /package/src/{button.tsx → button/button.tsx} +0 -0
@@ -1,915 +0,0 @@
1
- import InfoIcon from '@mui/icons-material/Info';
2
- import { Box, Stack,TextField } from '@mui/material';
3
- import type { Meta, StoryObj } from '@storybook/react-vite';
4
- import React from 'react';
5
- import { expect, fireEvent, fn,userEvent, waitFor, within } from 'storybook/test';
6
-
7
- import { Label } from './Label';
8
-
9
- const meta: Meta<typeof Label> = {
10
- title: 'Form/Label/Tests',
11
- component: Label,
12
- parameters: {
13
- layout: 'centered',
14
- chromatic: { disableSnapshot: false },
15
- },
16
- tags: ['autodocs', 'test', 'component:Label'],
17
- };
18
-
19
- export default meta;
20
- type Story = StoryObj<typeof meta>;
21
-
22
- // ====================================
23
- // TestId Tests
24
- // ====================================
25
-
26
- export const DataTestIdVerification: Story = {
27
- name: '🔍 Data TestId Verification',
28
- args: {
29
- children: 'Test Label',
30
- dataTestId: 'custom-label-testid',
31
- },
32
- play: async ({ canvasElement, step }) => {
33
- const canvas = within(canvasElement);
34
-
35
- await step('Verify dataTestId prop applies to label element', async () => {
36
- const label = canvas.getByTestId('custom-label-testid');
37
- await expect(label).toBeInTheDocument();
38
- await expect(label.tagName.toLowerCase()).toBe('label');
39
- await expect(label).toHaveTextContent('Test Label');
40
- });
41
-
42
- await step('Verify dataTestId works with all variants', async () => {
43
- const label = canvas.getByTestId('custom-label-testid');
44
- await expect(label).toHaveAttribute('data-testid', 'custom-label-testid');
45
- });
46
- },
47
- };
48
-
49
- export const DataTestIdWithSrOnly: Story = {
50
- name: '🔍 Data TestId with Screen Reader Only',
51
- args: {
52
- children: 'SR Only Label',
53
- dataTestId: 'sr-only-testid',
54
- srOnly: true,
55
- },
56
- play: async ({ canvasElement, step }) => {
57
- const canvas = within(canvasElement);
58
-
59
- await step('Verify dataTestId applies to srOnly label', async () => {
60
- const label = canvas.getByTestId('sr-only-testid');
61
- await expect(label).toBeInTheDocument();
62
- await expect(label.tagName.toLowerCase()).toBe('label');
63
-
64
- const computedStyle = window.getComputedStyle(label);
65
- await expect(computedStyle.position).toBe('absolute');
66
- await expect(computedStyle.width).toBe('1px');
67
- await expect(computedStyle.height).toBe('1px');
68
- });
69
- },
70
- };
71
-
72
- // ====================================
73
- // Interaction Tests
74
- // ====================================
75
-
76
- export const BasicInteraction: Story = {
77
- name: '🧪 Basic Interaction Test',
78
- args: {
79
- children: 'Interactive Label',
80
- htmlFor: 'test-input',
81
- onClick: fn(),
82
- 'data-testid': 'interactive-label',
83
- },
84
- play: async ({ canvasElement, step, args }) => {
85
- const canvas = within(canvasElement);
86
-
87
- await step('Initial render verification', async () => {
88
- const label = canvas.getByTestId('interactive-label');
89
- await expect(label).toBeInTheDocument();
90
- await expect(label).toHaveTextContent('Interactive Label');
91
- });
92
-
93
- await step('Click interaction', async () => {
94
- const label = canvas.getByTestId('interactive-label');
95
- await userEvent.click(label);
96
- await expect(args.onClick).toHaveBeenCalledTimes(1);
97
- });
98
-
99
- await step('Hover interaction', async () => {
100
- const label = canvas.getByTestId('interactive-label');
101
- await userEvent.hover(label);
102
- // Visual state should change (verified through visual regression)
103
- await userEvent.unhover(label);
104
- });
105
-
106
- await step('Verify htmlFor attribute', async () => {
107
- const label = canvas.getByTestId('interactive-label');
108
- await expect(label).toHaveAttribute('for', 'test-input');
109
- });
110
- },
111
- };
112
-
113
- export const RequiredFieldTest: Story = {
114
- name: '📝 Required Field Test',
115
- args: {
116
- children: 'Required Field',
117
- required: true,
118
- asteriskPlacement: 'end',
119
- 'data-testid': 'required-label',
120
- },
121
- play: async ({ canvasElement, step }) => {
122
- const canvas = within(canvasElement);
123
-
124
- await step('Verify required asterisk is present', async () => {
125
- const label = canvas.getByTestId('required-label');
126
- await expect(label).toBeInTheDocument();
127
-
128
- // Check for asterisk
129
- const asterisk = within(label).getByText('*');
130
- await expect(asterisk).toBeInTheDocument();
131
-
132
- // Verify asterisk color (should be error color)
133
- const computedStyle = window.getComputedStyle(asterisk);
134
- await expect(computedStyle.color).toContain('rgb');
135
- });
136
-
137
- await step('Test asterisk placement at start', async () => {
138
- // This would require prop change - verified through separate story
139
- const label = canvas.getByTestId('required-label');
140
- await expect(label.textContent).toContain('*');
141
- });
142
- },
143
- };
144
-
145
- export const StateChangeTest: Story = {
146
- name: '🔄 State Change Test',
147
- render: function StateChangeComponent() {
148
- const [state, setState] = React.useState<'normal' | 'disabled' | 'error' | 'loading'>('normal');
149
-
150
- return (
151
- <Stack spacing={2}>
152
- <Label
153
- disabled={state === 'disabled'}
154
- error={state === 'error'}
155
- loading={state === 'loading'}
156
- data-testid="stateful-label"
157
- >
158
- Stateful Label
159
- </Label>
160
- <Stack direction="row" spacing={1}>
161
- <button onClick={() => setState('normal')}>Normal</button>
162
- <button onClick={() => setState('disabled')}>Disabled</button>
163
- <button onClick={() => setState('error')}>Error</button>
164
- <button onClick={() => setState('loading')}>Loading</button>
165
- </Stack>
166
- </Stack>
167
- );
168
- },
169
- play: async ({ canvasElement, step }) => {
170
- const canvas = within(canvasElement);
171
-
172
- await step('Verify initial normal state', async () => {
173
- const label = canvas.getByTestId('stateful-label');
174
- await expect(label).toBeInTheDocument();
175
- await expect(label).not.toHaveStyle({ opacity: '0.5' });
176
- });
177
-
178
- await step('Change to disabled state', async () => {
179
- const disabledButton = canvas.getByRole('button', { name: 'Disabled' });
180
- await userEvent.click(disabledButton);
181
-
182
- const label = canvas.getByTestId('stateful-label');
183
- const computedStyle = window.getComputedStyle(label);
184
- // Disabled state should have different color
185
- await expect(computedStyle.color).toBeDefined();
186
- });
187
-
188
- await step('Change to error state', async () => {
189
- const errorButton = canvas.getByRole('button', { name: 'Error' });
190
- await userEvent.click(errorButton);
191
-
192
- const label = canvas.getByTestId('stateful-label');
193
- const computedStyle = window.getComputedStyle(label);
194
- // Error state should have error color
195
- await expect(computedStyle.color).toBeDefined();
196
- });
197
-
198
- await step('Change to loading state', async () => {
199
- const loadingButton = canvas.getByRole('button', { name: 'Loading' });
200
- await userEvent.click(loadingButton);
201
-
202
- await waitFor(() => {
203
- const spinner = canvas.queryByRole('progressbar');
204
- expect(spinner).toBeInTheDocument();
205
- });
206
- });
207
- },
208
- };
209
-
210
- // ====================================
211
- // Accessibility Tests
212
- // ====================================
213
-
214
- export const KeyboardNavigation: Story = {
215
- name: '⌨️ Keyboard Navigation Test',
216
- render: () => (
217
- <Stack spacing={2}>
218
- <Label htmlFor="input-1" onClick={fn()} data-testid="first-label" tabIndex={0}>
219
- First Label
220
- </Label>
221
- <TextField id="input-1" data-testid="first-input" />
222
-
223
- <Label htmlFor="input-2" onClick={fn()} data-testid="second-label" tabIndex={0}>
224
- Second Label
225
- </Label>
226
- <TextField id="input-2" data-testid="second-input" />
227
- </Stack>
228
- ),
229
- parameters: {
230
- a11y: {
231
- element: '#storybook-root',
232
- config: {
233
- rules: [
234
- { id: 'color-contrast', enabled: true },
235
- { id: 'label', enabled: true },
236
- { id: 'aria-valid-attr-value', enabled: true },
237
- ],
238
- },
239
- },
240
- },
241
- play: async ({ canvasElement, step }) => {
242
- const canvas = within(canvasElement);
243
-
244
- await step('Tab navigation forward', async () => {
245
- const firstLabel = canvas.getByTestId('first-label');
246
- const firstInputContainer = canvas.getByTestId('first-input');
247
- const firstInput = firstInputContainer.querySelector('input');
248
-
249
- // Focus first label
250
- await userEvent.click(firstLabel);
251
- await waitFor(() => expect(firstLabel).toHaveFocus());
252
-
253
- // Tab to input
254
- await userEvent.tab();
255
- await waitFor(() => expect(firstInput).toHaveFocus());
256
- });
257
-
258
- await step('Tab navigation backward', async () => {
259
- await userEvent.tab({ shift: true });
260
- const firstLabel = canvas.getByTestId('first-label');
261
- await waitFor(() => expect(firstLabel).toHaveFocus());
262
- });
263
-
264
- await step('Enter key activation on clickable label', async () => {
265
- const firstLabel = canvas.getByTestId('first-label');
266
- await userEvent.click(firstLabel);
267
- await userEvent.keyboard('{Enter}');
268
- // Verify click handler would be called
269
- });
270
- },
271
- };
272
-
273
- export const ScreenReaderTest: Story = {
274
- name: '🔊 Screen Reader Test',
275
- args: {
276
- children: 'Accessible Label',
277
- htmlFor: 'accessible-input',
278
- required: true,
279
- helperText: 'This field is required',
280
- tooltip: 'Additional information about this field',
281
- 'aria-label': 'Accessible form label',
282
- 'aria-describedby': 'helper-text',
283
- 'data-testid': 'accessible-label',
284
- },
285
- render: (args) => (
286
- <Stack spacing={1}>
287
- <Label {...args} />
288
- <TextField id="accessible-input" aria-describedby="helper-text" />
289
- <span id="helper-text" style={{ display: 'none' }}>
290
- This field is required for accessibility
291
- </span>
292
- </Stack>
293
- ),
294
- play: async ({ canvasElement, step }) => {
295
- const canvas = within(canvasElement);
296
-
297
- await step('Verify ARIA attributes', async () => {
298
- const label = canvas.getByTestId('accessible-label');
299
- await expect(label).toHaveAttribute('aria-label', 'Accessible form label');
300
- await expect(label).toHaveAttribute('aria-describedby', 'helper-text');
301
- });
302
-
303
- await step('Verify htmlFor association', async () => {
304
- const label = canvas.getByTestId('accessible-label');
305
- await expect(label.tagName.toLowerCase()).toBe('label');
306
- await expect(label).toHaveAttribute('for', 'accessible-input');
307
- });
308
-
309
- await step('Verify helper text presence', async () => {
310
- const helperText = canvas.getByText('This field is required');
311
- await expect(helperText).toBeInTheDocument();
312
- });
313
-
314
- await step('Verify screen reader only label', async () => {
315
- const srDescription = canvas.getByText('This field is required for accessibility');
316
- await expect(srDescription).toBeInTheDocument();
317
- await expect(srDescription).toHaveStyle({ display: 'none' });
318
- });
319
- },
320
- };
321
-
322
- export const ScreenReaderOnlyTest: Story = {
323
- name: '👁️‍🗨️ Screen Reader Only Test',
324
- args: {
325
- children: 'This label is only for screen readers',
326
- srOnly: true,
327
- htmlFor: 'sr-only-input',
328
- 'data-testid': 'sr-only-label',
329
- },
330
- render: (args) => (
331
- <Box>
332
- <Label {...args} />
333
- <TextField id="sr-only-input" placeholder="Field with screen reader only label" fullWidth />
334
- </Box>
335
- ),
336
- play: async ({ canvasElement, step }) => {
337
- const canvas = within(canvasElement);
338
-
339
- await step('Verify label is visually hidden', async () => {
340
- // The label should be in the document but visually hidden
341
- const hiddenLabel = canvas.getByText('This label is only for screen readers');
342
- await expect(hiddenLabel).toBeInTheDocument();
343
-
344
- // For srOnly labels, the text is inside a label element with special styles
345
- // Get the parent label element which should have the srOnly styles
346
- const labelElement = hiddenLabel.parentElement;
347
-
348
- if (labelElement && labelElement.tagName === 'LABEL') {
349
- const computedStyle = window.getComputedStyle(labelElement);
350
- // The srOnly label should be absolutely positioned
351
- await expect(computedStyle.position).toBe('absolute');
352
- // Check for visually hidden styles - srOnly uses 1px width/height
353
- const widthValue = computedStyle.width;
354
- const heightValue = computedStyle.height;
355
- // MUI Box with sx might return '1px' as string
356
- await expect(widthValue).toBe('1px');
357
- await expect(heightValue).toBe('1px');
358
- } else {
359
- // If the direct parent isn't the label, find it
360
- const label = hiddenLabel.closest('label');
361
- if (label) {
362
- const computedStyle = window.getComputedStyle(label);
363
- await expect(computedStyle.position).toBe('absolute');
364
- }
365
- }
366
- });
367
-
368
- await step('Verify input association', async () => {
369
- const input = canvas.getByPlaceholderText('Field with screen reader only label');
370
- await expect(input).toBeInTheDocument();
371
- await expect(input).toHaveAttribute('id', 'sr-only-input');
372
- });
373
- },
374
- };
375
-
376
- // ====================================
377
- // Visual Tests
378
- // ====================================
379
-
380
- export const ResponsiveDesign: Story = {
381
- name: '📱 Responsive Design Test',
382
- render: () => (
383
- <Stack spacing={2} sx={{ width: '100%' }}>
384
- <Label size="xs" variant="filled">
385
- Extra Small Label
386
- </Label>
387
- <Label size="sm" variant="outlined">
388
- Small Label
389
- </Label>
390
- <Label size="md" variant="glass">
391
- Medium Label
392
- </Label>
393
- <Label size="lg" variant="gradient" color="primary">
394
- Large Label
395
- </Label>
396
- <Label size="xl" variant="default">
397
- Extra Large Label
398
- </Label>
399
- </Stack>
400
- ),
401
- parameters: {
402
- viewport: {
403
- viewports: {
404
- mobile: {
405
- name: 'Mobile',
406
- styles: { width: '375px', height: '667px' },
407
- type: 'mobile',
408
- },
409
- tablet: {
410
- name: 'Tablet',
411
- styles: { width: '768px', height: '1024px' },
412
- type: 'tablet',
413
- },
414
- desktop: {
415
- name: 'Desktop',
416
- styles: { width: '1920px', height: '1080px' },
417
- type: 'desktop',
418
- },
419
- },
420
- defaultViewport: 'mobile',
421
- },
422
- chromatic: {
423
- viewports: [375, 768, 1920],
424
- delay: 300,
425
- },
426
- },
427
- play: async ({ canvasElement, step }) => {
428
- const canvas = within(canvasElement);
429
-
430
- await step('Verify all size variants render', async () => {
431
- await expect(canvas.getByText('Extra Small Label')).toBeInTheDocument();
432
- await expect(canvas.getByText('Small Label')).toBeInTheDocument();
433
- await expect(canvas.getByText('Medium Label')).toBeInTheDocument();
434
- await expect(canvas.getByText('Large Label')).toBeInTheDocument();
435
- await expect(canvas.getByText('Extra Large Label')).toBeInTheDocument();
436
- });
437
-
438
- await step('Verify responsive sizing', async () => {
439
- const labels = canvas.getAllByText(/Label/);
440
- labels.forEach((label) => {
441
- const computedStyle = window.getComputedStyle(label);
442
- expect(parseFloat(computedStyle.fontSize)).toBeGreaterThan(0);
443
- });
444
- });
445
- },
446
- };
447
-
448
- export const ThemeVariations: Story = {
449
- name: '🎨 Theme Variations Test',
450
- render: () => (
451
- <Stack spacing={2}>
452
- <Box sx={{ p: 2, backgroundColor: '#ffffff' }}>
453
- <Label color="primary">Light Theme Primary</Label>
454
- </Box>
455
- <Box sx={{ p: 2, backgroundColor: '#1a1a1a' }}>
456
- <Label color="primary">Dark Theme Primary</Label>
457
- </Box>
458
- <Label variant="glass" glow>
459
- Glass with Glow
460
- </Label>
461
- <Label variant="gradient" color="secondary">
462
- Gradient Secondary
463
- </Label>
464
- </Stack>
465
- ),
466
- parameters: {
467
- backgrounds: {
468
- default: 'light',
469
- values: [
470
- { name: 'light', value: '#ffffff' },
471
- { name: 'dark', value: '#1a1a1a' },
472
- ],
473
- },
474
- },
475
- play: async ({ canvasElement, step }) => {
476
- const canvas = within(canvasElement);
477
-
478
- await step('Verify theme-aware rendering', async () => {
479
- const labels = canvas.getAllByText(/Theme/);
480
- labels.forEach((label) => {
481
- const computedStyle = window.getComputedStyle(label);
482
- expect(computedStyle.color).toBeDefined();
483
- });
484
- });
485
-
486
- await step('Verify glass effect', async () => {
487
- const glassLabel = canvas.getByText('Glass with Glow');
488
- const computedStyle = window.getComputedStyle(glassLabel);
489
- // Glass effect uses backdrop-filter
490
- expect(computedStyle.backdropFilter || computedStyle.webkitBackdropFilter).toBeDefined();
491
- });
492
- },
493
- };
494
-
495
- export const VisualStates: Story = {
496
- name: '👁️ Visual States Test',
497
- render: function VisualStatesComponent() {
498
- const [hovered, setHovered] = React.useState(false);
499
- const [active, setActive] = React.useState(false);
500
-
501
- return (
502
- <Stack spacing={2}>
503
- <Label data-testid="normal-label">Normal State</Label>
504
-
505
- <Label
506
- data-testid="hover-label"
507
- variant="filled"
508
- color="primary"
509
- onMouseEnter={() => setHovered(true)}
510
- onMouseLeave={() => setHovered(false)}
511
- style={{ transform: hovered ? 'scale(1.02)' : 'scale(1)' }}
512
- >
513
- Hover State (hover me)
514
- </Label>
515
-
516
- <Label
517
- data-testid="active-label"
518
- variant="outlined"
519
- onClick={() => setActive(!active)}
520
- className={active ? 'active' : ''}
521
- >
522
- Active State (click me)
523
- </Label>
524
-
525
- <Label disabled data-testid="disabled-label">
526
- Disabled State
527
- </Label>
528
-
529
- <Label loading data-testid="loading-label">
530
- Loading State
531
- </Label>
532
-
533
- <Label error data-testid="error-label">
534
- Error State
535
- </Label>
536
-
537
- <Label glow pulse data-testid="animated-label">
538
- Animated State
539
- </Label>
540
- </Stack>
541
- );
542
- },
543
- play: async ({ canvasElement, step }) => {
544
- const canvas = within(canvasElement);
545
-
546
- await step('Default state', async () => {
547
- const label = canvas.getByTestId('normal-label');
548
- await expect(label).toHaveStyle({ opacity: '1' });
549
- });
550
-
551
- await step('Hover state', async () => {
552
- const label = canvas.getByTestId('hover-label');
553
- await userEvent.hover(label);
554
- await waitFor(() => {
555
- // Browsers may convert scale() to matrix(), so we check for either format
556
- const computedStyle = window.getComputedStyle(label);
557
- const transform = computedStyle.transform;
558
- const isScaled =
559
- transform === 'scale(1.02)' || transform === 'matrix(1.02, 0, 0, 1.02, 0, 0)';
560
- expect(isScaled).toBe(true);
561
- });
562
- await userEvent.unhover(label);
563
- });
564
-
565
- await step('Active state', async () => {
566
- const label = canvas.getByTestId('active-label');
567
- await userEvent.click(label);
568
- await expect(label).toHaveClass('active');
569
- });
570
-
571
- await step('Disabled state', async () => {
572
- const label = canvas.getByTestId('disabled-label');
573
- const computedStyle = window.getComputedStyle(label);
574
- // Disabled labels should have reduced opacity or different color
575
- expect(computedStyle.color).toBeDefined();
576
- });
577
-
578
- await step('Loading state', async () => {
579
- const label = canvas.getByTestId('loading-label');
580
- const spinner = within(label.parentElement!).queryByRole('progressbar');
581
- await expect(spinner).toBeInTheDocument();
582
- });
583
-
584
- await step('Error state', async () => {
585
- const label = canvas.getByTestId('error-label');
586
- const computedStyle = window.getComputedStyle(label);
587
- // Error state should have error color
588
- expect(computedStyle.color).toContain('rgb');
589
- });
590
- },
591
- };
592
-
593
- // ====================================
594
- // Performance Tests
595
- // ====================================
596
-
597
- export const PerformanceTest: Story = {
598
- name: '⚡ Performance Test',
599
- render: () => {
600
- const labels = Array.from({ length: 100 }, (_, i) => ({
601
- id: i,
602
- text: `Label ${i}`,
603
- variant: (['default', 'filled', 'outlined', 'glass', 'gradient'] as const)[i % 5],
604
- color: (['primary', 'secondary', 'success', 'error', 'warning'] as const)[i % 5],
605
- }));
606
-
607
- return (
608
- <Box sx={{ maxHeight: 400, overflow: 'auto' }} data-testid="scroll-container">
609
- <Stack spacing={1}>
610
- {labels.map((label) => (
611
- <Label
612
- key={label.id}
613
- variant={label.variant}
614
- color={label.color}
615
- data-testid={`label-${label.id}`}
616
- >
617
- {label.text}
618
- </Label>
619
- ))}
620
- </Stack>
621
- </Box>
622
- );
623
- },
624
- play: async ({ canvasElement, step }) => {
625
- const canvas = within(canvasElement);
626
-
627
- await step('Measure render time', async () => {
628
- const startTime = window.performance.now();
629
- const labels = canvas.getAllByTestId(/label-\d+/);
630
- const endTime = window.performance.now();
631
-
632
- const renderTime = endTime - startTime;
633
- // Log render time for debugging (commented out for production)
634
- // console.log(`Render time for ${labels.length} labels: ${renderTime}ms`);
635
-
636
- // Assert reasonable render time
637
- await expect(renderTime).toBeLessThan(1000);
638
- await expect(labels).toHaveLength(100);
639
- });
640
-
641
- await step('Test scroll performance', async () => {
642
- const scrollContainer = canvas.getByTestId('scroll-container');
643
-
644
- // Scrolling is the one thing this story is about, so it has to move the
645
- // container; what it must not do is assert a pixel offset, which depends
646
- // on the viewport the story happens to render in.
647
- // eslint-disable-next-line test-flakiness/no-viewport-dependent -- the subject under test is scrolling itself
648
- scrollContainer.scrollTop = scrollContainer.scrollHeight;
649
- fireEvent.scroll(scrollContainer);
650
-
651
- // The labels are not virtualised, so scrolling must leave every one of
652
- // them mounted — which is what the old toBeInTheDocument() on the
653
- // container itself could never have caught, since the container was
654
- // already there before the loop ran.
655
- await waitFor(() => {
656
- expect(canvas.getAllByTestId(/^label-\d+$/)).toHaveLength(100);
657
- });
658
- });
659
- },
660
- };
661
-
662
- // ====================================
663
- // Edge Cases Tests
664
- // ====================================
665
-
666
- export const EdgeCases: Story = {
667
- name: '🔧 Edge Cases Test',
668
- render: () => (
669
- <Stack spacing={2}>
670
- <Box sx={{ width: 200 }}>
671
- <Label truncate data-testid="truncate-label">
672
- This is a very long label text that should be truncated when it exceeds the container
673
- width
674
- </Label>
675
- </Box>
676
-
677
- <Label data-testid="empty-label"></Label>
678
-
679
- <Label data-testid="special-chars">{`Label with special chars: !@#$%^&*()_+{}|:"<>?`}</Label>
680
-
681
- <Label
682
- data-testid="multiple-props"
683
- variant="gradient"
684
- color="primary"
685
- size="lg"
686
- weight="bold"
687
- transform="uppercase"
688
- glow
689
- pulse
690
- ripple
691
- required
692
- icon={<InfoIcon />}
693
- tooltip="Complex tooltip"
694
- helperText="Complex helper text"
695
- >
696
- All Props Label
697
- </Label>
698
-
699
- <Label nowrap data-testid="nowrap-label">
700
- {`This label has nowrap and will not break to a new line even if it's very long`}
701
- </Label>
702
- </Stack>
703
- ),
704
- play: async ({ canvasElement, step }) => {
705
- const canvas = within(canvasElement);
706
-
707
- await step('Text truncation handling', async () => {
708
- const label = canvas.getByTestId('truncate-label');
709
- const computedStyle = window.getComputedStyle(label);
710
- // The truncate prop should apply text-overflow: ellipsis
711
- await expect(computedStyle.textOverflow).toBe('ellipsis');
712
- // Overflow should be hidden for truncation to work
713
- await expect(['hidden', 'clip']).toContain(computedStyle.overflow);
714
- });
715
-
716
- await step('Empty content handling', async () => {
717
- const label = canvas.getByTestId('empty-label');
718
- await expect(label).toBeInTheDocument();
719
- await expect(label.textContent).toBe('');
720
- });
721
-
722
- await step('Special characters handling', async () => {
723
- const label = canvas.getByTestId('special-chars');
724
- await expect(label).toHaveTextContent('!@#$%^&*()_+{}|:"<>?');
725
- });
726
-
727
- await step('Multiple props combination', async () => {
728
- const label = canvas.getByTestId('multiple-props');
729
- await expect(label).toBeInTheDocument();
730
-
731
- // Check for required asterisk
732
- const asterisk = within(label.parentElement!).getByText('*');
733
- await expect(asterisk).toBeInTheDocument();
734
-
735
- // Check for icon
736
- const icon = label.querySelector('svg');
737
- await expect(icon).toBeInTheDocument();
738
- });
739
-
740
- await step('No wrap handling', async () => {
741
- const label = canvas.getByTestId('nowrap-label');
742
- const computedStyle = window.getComputedStyle(label);
743
- await expect(computedStyle.whiteSpace).toBe('nowrap');
744
- });
745
- },
746
- };
747
-
748
- // ====================================
749
- // Integration Tests
750
- // ====================================
751
-
752
- export const FormIntegration: Story = {
753
- name: '🔗 Form Integration Test',
754
- render: function FormIntegrationComponent() {
755
- const [email, setEmail] = React.useState('');
756
- const [password, setPassword] = React.useState('');
757
- const [errors, setErrors] = React.useState<{ email?: string; password?: string }>({});
758
-
759
- const handleSubmit = (e: React.FormEvent) => {
760
- e.preventDefault();
761
- const newErrors: typeof errors = {};
762
-
763
- if (!email) newErrors.email = 'Email is required';
764
- if (!password) newErrors.password = 'Password is required';
765
-
766
- setErrors(newErrors);
767
-
768
- if (Object.keys(newErrors).length === 0) {
769
- window.alert('Form submitted successfully!');
770
- }
771
- };
772
-
773
- return (
774
- <form onSubmit={handleSubmit}>
775
- <Stack spacing={2}>
776
- <Box>
777
- <Label
778
- htmlFor="email-field"
779
- required
780
- error={!!errors.email}
781
- helperText={errors.email}
782
- data-testid="email-label"
783
- >
784
- Email Address
785
- </Label>
786
- <TextField
787
- id="email-field"
788
- fullWidth
789
- value={email}
790
- onChange={(e) => setEmail(e.target.value)}
791
- error={!!errors.email}
792
- size="small"
793
- sx={{ mt: 1 }}
794
- data-testid="email-input"
795
- />
796
- </Box>
797
-
798
- <Box>
799
- <Label
800
- htmlFor="password-field"
801
- required
802
- error={!!errors.password}
803
- helperText={errors.password}
804
- data-testid="password-label"
805
- >
806
- Password
807
- </Label>
808
- <TextField
809
- id="password-field"
810
- type="password"
811
- fullWidth
812
- value={password}
813
- onChange={(e) => setPassword(e.target.value)}
814
- error={!!errors.password}
815
- size="small"
816
- sx={{ mt: 1 }}
817
- data-testid="password-input"
818
- />
819
- </Box>
820
-
821
- <button type="submit" data-testid="submit-button">
822
- Submit
823
- </button>
824
- </Stack>
825
- </form>
826
- );
827
- },
828
- play: async ({ canvasElement, step }) => {
829
- const canvas = within(canvasElement);
830
-
831
- await step('Initial form state', async () => {
832
- const emailLabel = canvas.getByTestId('email-label');
833
- const passwordLabel = canvas.getByTestId('password-label');
834
-
835
- await expect(emailLabel).toBeInTheDocument();
836
- await expect(passwordLabel).toBeInTheDocument();
837
-
838
- // Both should show required asterisks
839
- const asterisks = canvas.getAllByText('*');
840
- await expect(asterisks).toHaveLength(2);
841
- });
842
-
843
- await step('Submit empty form shows errors', async () => {
844
- const submitButton = canvas.getByTestId('submit-button');
845
- await userEvent.click(submitButton);
846
-
847
- await waitFor(() => {
848
- const emailError = canvas.getByText('Email is required');
849
- const passwordError = canvas.getByText('Password is required');
850
- expect(emailError).toBeInTheDocument();
851
- expect(passwordError).toBeInTheDocument();
852
- });
853
- });
854
-
855
- await step('Fill form and submit', async () => {
856
- const emailInputContainer = canvas.getByTestId('email-input');
857
- const passwordInputContainer = canvas.getByTestId('password-input');
858
-
859
- // Get the actual input elements within the MUI TextFields
860
- const emailInput = emailInputContainer.querySelector('input') as HTMLInputElement;
861
- const passwordInput = passwordInputContainer.querySelector('input') as HTMLInputElement;
862
-
863
- await userEvent.clear(emailInput);
864
- await userEvent.type(emailInput, 'test@example.com');
865
-
866
- await userEvent.clear(passwordInput);
867
- await userEvent.type(passwordInput, 'password123');
868
-
869
- const submitButton = canvas.getByTestId('submit-button');
870
- await userEvent.click(submitButton);
871
-
872
- // Form should submit successfully (alert would show)
873
- });
874
- },
875
- };
876
-
877
- export const TooltipIntegration: Story = {
878
- name: '💡 Tooltip Integration Test',
879
- args: {
880
- children: 'Hover for more info',
881
- tooltip: 'This is additional information about the label',
882
- icon: <InfoIcon fontSize="small" />,
883
- iconPosition: 'end',
884
- 'data-testid': 'tooltip-label',
885
- },
886
- play: async ({ canvasElement, step }) => {
887
- const canvas = within(canvasElement);
888
-
889
- await step('Verify label with icon renders', async () => {
890
- const label = canvas.getByTestId('tooltip-label');
891
- await expect(label).toBeInTheDocument();
892
-
893
- const icon = label.querySelector('svg');
894
- await expect(icon).toBeInTheDocument();
895
- });
896
-
897
- await step('Tooltip appears on hover', async () => {
898
- const label = canvas.getByTestId('tooltip-label');
899
-
900
- await userEvent.hover(label);
901
-
902
- // MUI tooltips appear in a portal, so we need to search in the whole document
903
- await waitFor(
904
- () => {
905
- const tooltip = document.querySelector('[role="tooltip"]');
906
- expect(tooltip).toBeInTheDocument();
907
- expect(tooltip).toHaveTextContent('This is additional information about the label');
908
- },
909
- { timeout: 3000 },
910
- );
911
-
912
- await userEvent.unhover(label);
913
- });
914
- },
915
- };