ywana-core8 0.1.103 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +4941 -324
- package/dist/index.js +42339 -0
- package/dist/index.js.map +1 -0
- package/dist/index.modern.js +37459 -31678
- package/dist/index.modern.js.map +1 -1
- package/dist/index.umd.js +39635 -34010
- package/dist/index.umd.js.map +1 -1
- package/package.json +26 -29
- package/src/Test.stories.jsx +28 -0
- package/src/desktop/Desktop.stories.jsx +110 -0
- package/src/desktop/WindowContext.js +135 -0
- package/src/desktop/WindowManager.js +355 -0
- package/src/desktop/desktop.css +55 -4
- package/src/desktop/desktop.js +312 -6
- package/src/desktop/index.js +7 -0
- package/src/desktop/window.css +229 -36
- package/src/desktop/window.js +255 -20
- package/src/desktop.backup/desktop.css +6 -0
- package/src/desktop.backup/desktop.js +13 -0
- package/src/desktop.backup/window.css +58 -0
- package/src/desktop.backup/window.js +27 -0
- package/src/html/Accordion.stories.jsx +178 -0
- package/src/html/Button.stories.jsx +175 -0
- package/src/html/Checkbox.stories.jsx +131 -0
- package/src/html/Chip.stories.jsx +189 -0
- package/src/html/Color.stories.jsx +234 -0
- package/src/html/Form.stories.jsx +271 -0
- package/src/html/Icon.stories.jsx +233 -0
- package/src/html/Progress.stories.jsx +247 -0
- package/src/html/Radio.stories.jsx +289 -0
- package/src/html/StyleTest.stories.jsx +81 -0
- package/src/html/Switch.stories.jsx +329 -0
- package/src/html/Tab.stories.jsx +239 -0
- package/src/html/Table.stories.jsx +188 -0
- package/src/html/Table2.stories.jsx +238 -0
- package/src/html/TextField2.stories.jsx +337 -0
- package/src/html/Tree.stories.jsx +285 -0
- package/src/html/accordion.example.js +0 -74
- package/src/html/accordion.js +1 -6
- package/src/html/button.js +2 -13
- package/src/html/checkbox.js +1 -9
- package/src/html/chip.js +2 -19
- package/src/html/color.js +1 -14
- package/src/html/form.js +4 -15
- package/src/html/header2.js +1 -12
- package/src/html/icon.js +1 -7
- package/src/html/index.js +1 -1
- package/src/html/list.js +1 -19
- package/src/html/menu.js +9 -5
- package/src/html/progress.js +5 -53
- package/src/html/property.js +9 -25
- package/src/html/radio.js +2 -16
- package/src/html/section.js +1 -6
- package/src/html/selector.js +2 -19
- package/src/html/switch.css +134 -100
- package/src/html/switch.example.js +46 -36
- package/src/html/switch.js +43 -192
- package/src/html/tab.js +3 -24
- package/src/html/text.js +1 -12
- package/src/html/textfield2.js +5 -42
- package/src/html/thumbnail.js +1 -12
- package/src/html/tokenfield.js +2 -21
- package/src/html/tree.js +3 -35
- package/src/index.js +1 -0
- package/__previewjs__/Wrapper.tsx +0 -14
- package/build-doc.sh +0 -10
- package/db/db.json +0 -89
- package/db/routes.json +0 -0
- package/dist/index.cjs +0 -36722
- package/dist/index.cjs.map +0 -1
- package/dist/index.css.map +0 -1
- package/doc/README.md +0 -196
- package/doc/evalulations/ACCORDION_EVALUATION.md +0 -583
- package/doc/evalulations/CHECKBOX_EVALUATION.md +0 -273
- package/doc/evalulations/CHIP_EVALUATION.md +0 -542
- package/doc/evalulations/COLOR_EVALUATION.md +0 -524
- package/doc/evalulations/COMPONENTS_EVALUATION.md +0 -477
- package/doc/evalulations/FORM_EVALUATION.md +0 -459
- package/doc/evalulations/HEADER_EVALUATION.md +0 -436
- package/doc/evalulations/ICON_EVALUATION.md +0 -254
- package/doc/evalulations/LIST_EVALUATION.md +0 -574
- package/doc/evalulations/PROGRESS_EVALUATION.md +0 -450
- package/doc/evalulations/RADIO_EVALUATION.md +0 -439
- package/doc/evalulations/RADIO_VISUAL_FIX.md +0 -183
- package/doc/evalulations/SECTION_IMPROVEMENTS.md +0 -153
- package/doc/evalulations/SWITCH_EVALUATION.md +0 -335
- package/doc/evalulations/SWITCH_VISUAL_FIX.md +0 -232
- package/doc/evalulations/TAB_EVALUATION.md +0 -626
- package/doc/evalulations/TEXTFIELD_EVALUATION.md +0 -747
- package/doc/evalulations/TOOLTIP_FIX.md +0 -157
- package/doc/evalulations/TREE_EVALUATION.md +0 -708
- package/doc/index.html +0 -0
- package/doc/package-lock.json +0 -17298
- package/doc/package.json +0 -34
- package/doc/public/index.html +0 -24
- package/doc/scripts/generate-examples.js +0 -129
- package/doc/src/App.css +0 -171
- package/doc/src/App.js +0 -114
- package/doc/src/components/ExamplePage.js +0 -129
- package/doc/src/components/WelcomePage.js +0 -84
- package/doc/src/index.css +0 -246
- package/doc/src/index.js +0 -17
- package/doc/src/theme.css +0 -256
- package/jest.config.js +0 -24
- package/preview.config.js +0 -38
- package/publish.sh +0 -6
- package/src/desktop/dektop.test.js +0 -11
- package/src/domain/CollectionAPI.test.js +0 -19
- package/src/domain/ContentEditor.test.js +0 -52
- package/src/domain2/CollectionAPI.test.js +0 -19
- package/src/domain2/CollectionContext.test.js +0 -71
- package/src/domain2/CollectionPage.test.js +0 -112
- package/src/domain2/DynamicForm.test.js +0 -47
- package/src/html/accordion.test.js +0 -37
- package/src/html/accordion.unit.test.js +0 -334
- package/src/html/button.example.new.js +0 -416
- package/src/html/button.test.js +0 -422
- package/src/html/checkbox.test.js +0 -285
- package/src/html/chip.test.js +0 -425
- package/src/html/color.example.js.backup +0 -527
- package/src/html/color.test.js +0 -377
- package/src/html/components.example.js.backup +0 -492
- package/src/html/components_enhanced.test.js +0 -581
- package/src/html/form.example.js.backup +0 -385
- package/src/html/form.test.js +0 -369
- package/src/html/header2.example.js.backup +0 -411
- package/src/html/header2.test.js +0 -377
- package/src/html/icon.example.js.backup +0 -268
- package/src/html/icon.test.js +0 -231
- package/src/html/label.test.js +0 -0
- package/src/html/list.example.js.backup +0 -404
- package/src/html/list.test.js +0 -383
- package/src/html/progress.example.js.backup +0 -424
- package/src/html/progress.test.js +0 -313
- package/src/html/property.example.js.backup +0 -553
- package/src/html/property.test.js +0 -371
- package/src/html/radio.example.js.backup +0 -389
- package/src/html/radio.test.js +0 -318
- package/src/html/section.example.js.backup +0 -99
- package/src/html/section.test.js +0 -131
- package/src/html/selector.test.js +0 -20
- package/src/html/switch.example.js.backup +0 -461
- package/src/html/switch.test.js +0 -355
- package/src/html/tab.example.js.backup +0 -446
- package/src/html/tab.test.js +0 -25
- package/src/html/tab_enhanced.test.js +0 -504
- package/src/html/table.test.js +0 -70
- package/src/html/table2.test.js +0 -582
- package/src/html/text.test.js +0 -15
- package/src/html/textfield.test.js +0 -51
- package/src/html/textfield2.example.js.backup +0 -1370
- package/src/html/textfield2.test.js +0 -950
- package/src/html/tokenfield.example.js.backup +0 -503
- package/src/html/tokenfield.test.js +0 -423
- package/src/html/tree.example.js.backup +0 -475
- package/src/html/tree.test.js +0 -43
- package/src/html/tree_enhanced.test.js +0 -495
- package/src/http/token.test.js +0 -50
- package/src/incubator/pdfViewer.js +0 -33
- package/src/incubator/wizard.test.js +0 -127
- package/src/site/site.test.js +0 -230
- package/src/site/view.test.js +0 -41
- package/src/widgets/calendar/Calendar.test.js +0 -28
- package/src/widgets/explorer/Explorer.test.js +0 -121
- package/src/widgets/ide/editor.test.js +0 -33
- package/src/widgets/kanban/Kanban.test.js +0 -78
- package/src/widgets/login/LoginBox.test.js +0 -12
- package/src/widgets/login/ResetPasswordBox.test.js +0 -34
- package/src/widgets/login/validations.test.js +0 -51
- package/src/widgets/planner/Planner.test.js +0 -60
- package/src/widgets/upload/Upload.test.js +0 -32
- package/table2.test.js +0 -454
@@ -1,581 +0,0 @@
|
|
1
|
-
import React from 'react'
|
2
|
-
import { Thumbnail } from './thumbnail'
|
3
|
-
import { MultiSelector, ToggleButton } from './selector'
|
4
|
-
import { Text, TEXTFORMATS } from './text'
|
5
|
-
|
6
|
-
// Pruebas unitarias para los componentes mejorados
|
7
|
-
describe('Enhanced Components - Thumbnail, Selector, Text', () => {
|
8
|
-
// Mock de los componentes dependientes
|
9
|
-
const mockIcon = jest.fn()
|
10
|
-
|
11
|
-
beforeEach(() => {
|
12
|
-
jest.clearAllMocks()
|
13
|
-
|
14
|
-
// Mock de componentes
|
15
|
-
jest.doMock('./icon', () => ({ Icon: mockIcon }))
|
16
|
-
|
17
|
-
// Mock de console.warn
|
18
|
-
jest.spyOn(console, 'warn').mockImplementation(() => {})
|
19
|
-
|
20
|
-
// Mock de navigator.clipboard
|
21
|
-
global.navigator = {
|
22
|
-
clipboard: {
|
23
|
-
writeText: jest.fn().mockResolvedValue(undefined)
|
24
|
-
},
|
25
|
-
language: 'en-US'
|
26
|
-
}
|
27
|
-
})
|
28
|
-
|
29
|
-
afterEach(() => {
|
30
|
-
console.warn.mockRestore()
|
31
|
-
})
|
32
|
-
|
33
|
-
// Thumbnail Component Tests
|
34
|
-
describe('Thumbnail Component', () => {
|
35
|
-
test('component exports correctly', () => {
|
36
|
-
expect(Thumbnail).toBeDefined()
|
37
|
-
expect(typeof Thumbnail).toBe('function')
|
38
|
-
})
|
39
|
-
|
40
|
-
test('component has correct PropTypes', () => {
|
41
|
-
expect(Thumbnail.propTypes).toBeDefined()
|
42
|
-
expect(Thumbnail.propTypes.src).toBeDefined()
|
43
|
-
expect(Thumbnail.propTypes.empty).toBeDefined()
|
44
|
-
expect(Thumbnail.propTypes.objectFit).toBeDefined()
|
45
|
-
expect(Thumbnail.propTypes.alt).toBeDefined()
|
46
|
-
expect(Thumbnail.propTypes.size).toBeDefined()
|
47
|
-
expect(Thumbnail.propTypes.shape).toBeDefined()
|
48
|
-
expect(Thumbnail.propTypes.clickable).toBeDefined()
|
49
|
-
expect(Thumbnail.propTypes.disabled).toBeDefined()
|
50
|
-
})
|
51
|
-
|
52
|
-
test('component has correct defaultProps', () => {
|
53
|
-
expect(Thumbnail.defaultProps).toBeDefined()
|
54
|
-
expect(Thumbnail.defaultProps.src).toBe("https://www.w3schools.com/howto/img_forest.jpg")
|
55
|
-
expect(Thumbnail.defaultProps.empty).toBe("")
|
56
|
-
expect(Thumbnail.defaultProps.objectFit).toBe("cover")
|
57
|
-
expect(Thumbnail.defaultProps.size).toBe("medium")
|
58
|
-
expect(Thumbnail.defaultProps.shape).toBe("square")
|
59
|
-
expect(Thumbnail.defaultProps.clickable).toBe(false)
|
60
|
-
expect(Thumbnail.defaultProps.disabled).toBe(false)
|
61
|
-
})
|
62
|
-
|
63
|
-
test('handles image load correctly', () => {
|
64
|
-
const mockOnLoad = jest.fn()
|
65
|
-
const mockSetImageLoaded = jest.fn()
|
66
|
-
const mockSetIsLoading = jest.fn()
|
67
|
-
const mockSetImageError = jest.fn()
|
68
|
-
|
69
|
-
const handleLoad = (event, onLoad, setImageLoaded, setIsLoading, setImageError) => {
|
70
|
-
setImageLoaded(true)
|
71
|
-
setIsLoading(false)
|
72
|
-
setImageError(false)
|
73
|
-
if (onLoad) onLoad(event)
|
74
|
-
}
|
75
|
-
|
76
|
-
const mockEvent = { target: { src: 'test.jpg' } }
|
77
|
-
handleLoad(mockEvent, mockOnLoad, mockSetImageLoaded, mockSetIsLoading, mockSetImageError)
|
78
|
-
|
79
|
-
expect(mockSetImageLoaded).toHaveBeenCalledWith(true)
|
80
|
-
expect(mockSetIsLoading).toHaveBeenCalledWith(false)
|
81
|
-
expect(mockSetImageError).toHaveBeenCalledWith(false)
|
82
|
-
expect(mockOnLoad).toHaveBeenCalledWith(mockEvent)
|
83
|
-
})
|
84
|
-
|
85
|
-
test('handles image error correctly', () => {
|
86
|
-
const mockOnError = jest.fn()
|
87
|
-
const mockSetImageError = jest.fn()
|
88
|
-
const mockSetIsLoading = jest.fn()
|
89
|
-
const mockSetImageLoaded = jest.fn()
|
90
|
-
|
91
|
-
const handleError = (event, onError, setImageError, setIsLoading, setImageLoaded) => {
|
92
|
-
setImageError(true)
|
93
|
-
setIsLoading(false)
|
94
|
-
setImageLoaded(false)
|
95
|
-
if (onError) onError(event)
|
96
|
-
}
|
97
|
-
|
98
|
-
const mockEvent = { target: { src: 'test.jpg' } }
|
99
|
-
handleError(mockEvent, mockOnError, mockSetImageError, mockSetIsLoading, mockSetImageLoaded)
|
100
|
-
|
101
|
-
expect(mockSetImageError).toHaveBeenCalledWith(true)
|
102
|
-
expect(mockSetIsLoading).toHaveBeenCalledWith(false)
|
103
|
-
expect(mockSetImageLoaded).toHaveBeenCalledWith(false)
|
104
|
-
expect(mockOnError).toHaveBeenCalledWith(mockEvent)
|
105
|
-
})
|
106
|
-
|
107
|
-
test('handles click correctly', () => {
|
108
|
-
const mockOnClick = jest.fn()
|
109
|
-
|
110
|
-
const handleClick = (event, disabled, clickable, onClick) => {
|
111
|
-
if (disabled || !clickable) return
|
112
|
-
if (onClick) onClick(event)
|
113
|
-
}
|
114
|
-
|
115
|
-
const mockEvent = { target: {} }
|
116
|
-
|
117
|
-
// Normal click
|
118
|
-
handleClick(mockEvent, false, true, mockOnClick)
|
119
|
-
expect(mockOnClick).toHaveBeenCalledWith(mockEvent)
|
120
|
-
|
121
|
-
mockOnClick.mockClear()
|
122
|
-
|
123
|
-
// Disabled state
|
124
|
-
handleClick(mockEvent, true, true, mockOnClick)
|
125
|
-
expect(mockOnClick).not.toHaveBeenCalled()
|
126
|
-
|
127
|
-
// Not clickable
|
128
|
-
handleClick(mockEvent, false, false, mockOnClick)
|
129
|
-
expect(mockOnClick).not.toHaveBeenCalled()
|
130
|
-
})
|
131
|
-
|
132
|
-
test('generates CSS classes correctly', () => {
|
133
|
-
const generateClasses = (size, shape, bordered, shadow, clickable, disabled, isLoading, imageError, imageLoaded, className) => {
|
134
|
-
return [
|
135
|
-
'thumbnail',
|
136
|
-
`thumbnail--${size}`,
|
137
|
-
`thumbnail--${shape}`,
|
138
|
-
bordered && 'thumbnail--bordered',
|
139
|
-
shadow && 'thumbnail--shadow',
|
140
|
-
clickable && 'thumbnail--clickable',
|
141
|
-
disabled && 'thumbnail--disabled',
|
142
|
-
isLoading && 'thumbnail--loading',
|
143
|
-
imageError && 'thumbnail--error',
|
144
|
-
imageLoaded && 'thumbnail--loaded',
|
145
|
-
className
|
146
|
-
].filter(Boolean).join(' ')
|
147
|
-
}
|
148
|
-
|
149
|
-
expect(generateClasses('medium', 'square', false, false, false, false, false, false, false, ''))
|
150
|
-
.toBe('thumbnail thumbnail--medium thumbnail--square')
|
151
|
-
|
152
|
-
expect(generateClasses('large', 'circle', true, true, true, true, true, true, true, 'custom'))
|
153
|
-
.toBe('thumbnail thumbnail--large thumbnail--circle thumbnail--bordered thumbnail--shadow thumbnail--clickable thumbnail--disabled thumbnail--loading thumbnail--error thumbnail--loaded custom')
|
154
|
-
})
|
155
|
-
})
|
156
|
-
|
157
|
-
// MultiSelector Component Tests
|
158
|
-
describe('MultiSelector Component', () => {
|
159
|
-
test('component exports correctly', () => {
|
160
|
-
expect(MultiSelector).toBeDefined()
|
161
|
-
expect(typeof MultiSelector).toBe('function')
|
162
|
-
})
|
163
|
-
|
164
|
-
test('component has correct PropTypes', () => {
|
165
|
-
expect(MultiSelector.propTypes).toBeDefined()
|
166
|
-
expect(MultiSelector.propTypes.options).toBeDefined()
|
167
|
-
expect(MultiSelector.propTypes.className).toBeDefined()
|
168
|
-
expect(MultiSelector.propTypes.onChange).toBeDefined()
|
169
|
-
expect(MultiSelector.propTypes.disabled).toBeDefined()
|
170
|
-
expect(MultiSelector.propTypes.maxSelections).toBeDefined()
|
171
|
-
expect(MultiSelector.propTypes.minSelections).toBeDefined()
|
172
|
-
expect(MultiSelector.propTypes.searchable).toBeDefined()
|
173
|
-
expect(MultiSelector.propTypes.variant).toBeDefined()
|
174
|
-
expect(MultiSelector.propTypes.size).toBeDefined()
|
175
|
-
})
|
176
|
-
|
177
|
-
test('component has correct defaultProps', () => {
|
178
|
-
expect(MultiSelector.defaultProps).toBeDefined()
|
179
|
-
expect(MultiSelector.defaultProps.options).toEqual([])
|
180
|
-
expect(MultiSelector.defaultProps.disabled).toBe(false)
|
181
|
-
expect(MultiSelector.defaultProps.minSelections).toBe(0)
|
182
|
-
expect(MultiSelector.defaultProps.searchable).toBe(false)
|
183
|
-
expect(MultiSelector.defaultProps.variant).toBe('default')
|
184
|
-
expect(MultiSelector.defaultProps.size).toBe('medium')
|
185
|
-
})
|
186
|
-
|
187
|
-
test('validates options prop', () => {
|
188
|
-
const validateOptions = (options) => {
|
189
|
-
if (!Array.isArray(options)) {
|
190
|
-
console.warn('MultiSelector: options prop must be an array')
|
191
|
-
}
|
192
|
-
}
|
193
|
-
|
194
|
-
validateOptions('not an array')
|
195
|
-
expect(console.warn).toHaveBeenCalledWith('MultiSelector: options prop must be an array')
|
196
|
-
|
197
|
-
console.warn.mockClear()
|
198
|
-
validateOptions([])
|
199
|
-
expect(console.warn).not.toHaveBeenCalled()
|
200
|
-
})
|
201
|
-
|
202
|
-
test('handles toggle selection correctly', () => {
|
203
|
-
const mockOnChange = jest.fn()
|
204
|
-
const mockSetSelections = jest.fn()
|
205
|
-
|
206
|
-
const toggleSelection = (value, disabled, selections, maxSelections, minSelections, onChange, setSelections) => {
|
207
|
-
if (disabled) return
|
208
|
-
|
209
|
-
const isSelected = selections.includes(value)
|
210
|
-
let next
|
211
|
-
|
212
|
-
if (isSelected) {
|
213
|
-
if (selections.length <= minSelections) {
|
214
|
-
console.warn(`MultiSelector: Cannot remove selection. Minimum ${minSelections} selections required.`)
|
215
|
-
return
|
216
|
-
}
|
217
|
-
next = selections.filter(item => item !== value)
|
218
|
-
} else {
|
219
|
-
if (maxSelections && selections.length >= maxSelections) {
|
220
|
-
console.warn(`MultiSelector: Cannot add selection. Maximum ${maxSelections} selections allowed.`)
|
221
|
-
return
|
222
|
-
}
|
223
|
-
next = selections.concat([value])
|
224
|
-
}
|
225
|
-
|
226
|
-
setSelections(next)
|
227
|
-
if (onChange) onChange(next)
|
228
|
-
}
|
229
|
-
|
230
|
-
// Normal toggle
|
231
|
-
toggleSelection('item1', false, [], null, 0, mockOnChange, mockSetSelections)
|
232
|
-
expect(mockSetSelections).toHaveBeenCalledWith(['item1'])
|
233
|
-
expect(mockOnChange).toHaveBeenCalledWith(['item1'])
|
234
|
-
|
235
|
-
mockOnChange.mockClear()
|
236
|
-
mockSetSelections.mockClear()
|
237
|
-
|
238
|
-
// Max selections reached
|
239
|
-
toggleSelection('item3', false, ['item1', 'item2'], 2, 0, mockOnChange, mockSetSelections)
|
240
|
-
expect(console.warn).toHaveBeenCalledWith('MultiSelector: Cannot add selection. Maximum 2 selections allowed.')
|
241
|
-
expect(mockSetSelections).not.toHaveBeenCalled()
|
242
|
-
|
243
|
-
console.warn.mockClear()
|
244
|
-
|
245
|
-
// Min selections required
|
246
|
-
toggleSelection('item1', false, ['item1'], null, 1, mockOnChange, mockSetSelections)
|
247
|
-
expect(console.warn).toHaveBeenCalledWith('MultiSelector: Cannot remove selection. Minimum 1 selections required.')
|
248
|
-
expect(mockSetSelections).not.toHaveBeenCalled()
|
249
|
-
})
|
250
|
-
|
251
|
-
test('handles clear all correctly', () => {
|
252
|
-
const mockOnChange = jest.fn()
|
253
|
-
const mockOnClear = jest.fn()
|
254
|
-
const mockSetSelections = jest.fn()
|
255
|
-
|
256
|
-
const handleClear = (disabled, minSelections, setSelections, onChange, onClear) => {
|
257
|
-
if (disabled || minSelections > 0) return
|
258
|
-
|
259
|
-
setSelections([])
|
260
|
-
if (onChange) onChange([])
|
261
|
-
if (onClear) onClear()
|
262
|
-
}
|
263
|
-
|
264
|
-
// Normal clear
|
265
|
-
handleClear(false, 0, mockSetSelections, mockOnChange, mockOnClear)
|
266
|
-
expect(mockSetSelections).toHaveBeenCalledWith([])
|
267
|
-
expect(mockOnChange).toHaveBeenCalledWith([])
|
268
|
-
expect(mockOnClear).toHaveBeenCalled()
|
269
|
-
|
270
|
-
mockSetSelections.mockClear()
|
271
|
-
mockOnChange.mockClear()
|
272
|
-
mockOnClear.mockClear()
|
273
|
-
|
274
|
-
// Disabled clear
|
275
|
-
handleClear(true, 0, mockSetSelections, mockOnChange, mockOnClear)
|
276
|
-
expect(mockSetSelections).not.toHaveBeenCalled()
|
277
|
-
|
278
|
-
// Min selections prevent clear
|
279
|
-
handleClear(false, 1, mockSetSelections, mockOnChange, mockOnClear)
|
280
|
-
expect(mockSetSelections).not.toHaveBeenCalled()
|
281
|
-
})
|
282
|
-
|
283
|
-
test('filters options based on search', () => {
|
284
|
-
const options = [
|
285
|
-
{ label: 'Apple', value: 'apple' },
|
286
|
-
{ label: 'Banana', value: 'banana' },
|
287
|
-
{ label: 'Cherry', value: 'cherry' }
|
288
|
-
]
|
289
|
-
|
290
|
-
const filterOptions = (options, searchable, searchTerm) => {
|
291
|
-
return searchable && searchTerm
|
292
|
-
? options.filter(option =>
|
293
|
-
option.label?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
294
|
-
option.value?.toString().toLowerCase().includes(searchTerm.toLowerCase())
|
295
|
-
)
|
296
|
-
: options
|
297
|
-
}
|
298
|
-
|
299
|
-
// No search
|
300
|
-
expect(filterOptions(options, false, 'app')).toEqual(options)
|
301
|
-
|
302
|
-
// Search enabled
|
303
|
-
expect(filterOptions(options, true, 'app')).toEqual([{ label: 'Apple', value: 'apple' }])
|
304
|
-
expect(filterOptions(options, true, 'ban')).toEqual([{ label: 'Banana', value: 'banana' }])
|
305
|
-
expect(filterOptions(options, true, '')).toEqual(options)
|
306
|
-
})
|
307
|
-
})
|
308
|
-
|
309
|
-
// ToggleButton Component Tests
|
310
|
-
describe('ToggleButton Component', () => {
|
311
|
-
test('component has correct PropTypes', () => {
|
312
|
-
expect(ToggleButton.propTypes).toBeDefined()
|
313
|
-
expect(ToggleButton.propTypes.label).toBeDefined()
|
314
|
-
expect(ToggleButton.propTypes.value).toBeDefined()
|
315
|
-
expect(ToggleButton.propTypes.selected).toBeDefined()
|
316
|
-
expect(ToggleButton.propTypes.onToggle).toBeDefined()
|
317
|
-
expect(ToggleButton.propTypes.disabled).toBeDefined()
|
318
|
-
expect(ToggleButton.propTypes.icon).toBeDefined()
|
319
|
-
expect(ToggleButton.propTypes.variant).toBeDefined()
|
320
|
-
expect(ToggleButton.propTypes.size).toBeDefined()
|
321
|
-
})
|
322
|
-
|
323
|
-
test('component has correct defaultProps', () => {
|
324
|
-
expect(ToggleButton.defaultProps).toBeDefined()
|
325
|
-
expect(ToggleButton.defaultProps.selected).toBe(false)
|
326
|
-
expect(ToggleButton.defaultProps.disabled).toBe(false)
|
327
|
-
expect(ToggleButton.defaultProps.variant).toBe('default')
|
328
|
-
expect(ToggleButton.defaultProps.size).toBe('medium')
|
329
|
-
})
|
330
|
-
|
331
|
-
test('handles toggle correctly', () => {
|
332
|
-
const mockOnToggle = jest.fn()
|
333
|
-
|
334
|
-
const handleToggle = (disabled, onToggle, value) => {
|
335
|
-
if (disabled) return
|
336
|
-
if (onToggle) onToggle(value)
|
337
|
-
}
|
338
|
-
|
339
|
-
// Normal toggle
|
340
|
-
handleToggle(false, mockOnToggle, 'test-value')
|
341
|
-
expect(mockOnToggle).toHaveBeenCalledWith('test-value')
|
342
|
-
|
343
|
-
mockOnToggle.mockClear()
|
344
|
-
|
345
|
-
// Disabled state
|
346
|
-
handleToggle(true, mockOnToggle, 'test-value')
|
347
|
-
expect(mockOnToggle).not.toHaveBeenCalled()
|
348
|
-
})
|
349
|
-
|
350
|
-
test('handles keyboard interaction correctly', () => {
|
351
|
-
const mockOnToggle = jest.fn()
|
352
|
-
|
353
|
-
const handleKeyDown = (event, disabled, onToggle, value) => {
|
354
|
-
if (disabled) return
|
355
|
-
|
356
|
-
switch (event.key) {
|
357
|
-
case 'Enter':
|
358
|
-
case ' ':
|
359
|
-
event.preventDefault()
|
360
|
-
if (onToggle) onToggle(value)
|
361
|
-
break
|
362
|
-
default:
|
363
|
-
break
|
364
|
-
}
|
365
|
-
}
|
366
|
-
|
367
|
-
const mockEvent = { preventDefault: jest.fn() }
|
368
|
-
|
369
|
-
// Enter key
|
370
|
-
handleKeyDown({ ...mockEvent, key: 'Enter' }, false, mockOnToggle, 'test-value')
|
371
|
-
expect(mockEvent.preventDefault).toHaveBeenCalled()
|
372
|
-
expect(mockOnToggle).toHaveBeenCalledWith('test-value')
|
373
|
-
|
374
|
-
mockOnToggle.mockClear()
|
375
|
-
mockEvent.preventDefault.mockClear()
|
376
|
-
|
377
|
-
// Space key
|
378
|
-
handleKeyDown({ ...mockEvent, key: ' ' }, false, mockOnToggle, 'test-value')
|
379
|
-
expect(mockEvent.preventDefault).toHaveBeenCalled()
|
380
|
-
expect(mockOnToggle).toHaveBeenCalledWith('test-value')
|
381
|
-
|
382
|
-
mockOnToggle.mockClear()
|
383
|
-
|
384
|
-
// Other key
|
385
|
-
handleKeyDown({ ...mockEvent, key: 'Tab' }, false, mockOnToggle, 'test-value')
|
386
|
-
expect(mockOnToggle).not.toHaveBeenCalled()
|
387
|
-
})
|
388
|
-
|
389
|
-
test('generates CSS classes correctly', () => {
|
390
|
-
const generateClasses = (selected, variant, size, disabled, value, className) => {
|
391
|
-
return [
|
392
|
-
'toggle-button',
|
393
|
-
selected && 'selected',
|
394
|
-
`toggle-button--${variant}`,
|
395
|
-
`toggle-button--${size}`,
|
396
|
-
disabled && 'toggle-button--disabled',
|
397
|
-
value && `toggle-button--${value}`,
|
398
|
-
className
|
399
|
-
].filter(Boolean).join(' ')
|
400
|
-
}
|
401
|
-
|
402
|
-
expect(generateClasses(false, 'default', 'medium', false, 'test', ''))
|
403
|
-
.toBe('toggle-button toggle-button--default toggle-button--medium toggle-button--test')
|
404
|
-
|
405
|
-
expect(generateClasses(true, 'outlined', 'large', true, 'test', 'custom'))
|
406
|
-
.toBe('toggle-button selected toggle-button--outlined toggle-button--large toggle-button--disabled toggle-button--test custom')
|
407
|
-
})
|
408
|
-
|
409
|
-
test('generates accessibility attributes correctly', () => {
|
410
|
-
const generateAriaAttributes = (selected, disabled, tooltip, label, value) => {
|
411
|
-
return {
|
412
|
-
'aria-pressed': selected,
|
413
|
-
'aria-disabled': disabled,
|
414
|
-
'aria-label': tooltip || (typeof label === 'string' ? label : `Toggle ${value}`),
|
415
|
-
role: 'button',
|
416
|
-
tabIndex: disabled ? -1 : 0
|
417
|
-
}
|
418
|
-
}
|
419
|
-
|
420
|
-
const result1 = generateAriaAttributes(true, false, 'Custom tooltip', 'Test Label', 'test')
|
421
|
-
expect(result1['aria-pressed']).toBe(true)
|
422
|
-
expect(result1['aria-disabled']).toBe(false)
|
423
|
-
expect(result1['aria-label']).toBe('Custom tooltip')
|
424
|
-
expect(result1.role).toBe('button')
|
425
|
-
expect(result1.tabIndex).toBe(0)
|
426
|
-
|
427
|
-
const result2 = generateAriaAttributes(false, true, null, 'Test Label', 'test')
|
428
|
-
expect(result2['aria-pressed']).toBe(false)
|
429
|
-
expect(result2['aria-disabled']).toBe(true)
|
430
|
-
expect(result2['aria-label']).toBe('Test Label')
|
431
|
-
expect(result2.tabIndex).toBe(-1)
|
432
|
-
})
|
433
|
-
})
|
434
|
-
|
435
|
-
// Text Component Tests
|
436
|
-
describe('Text Component', () => {
|
437
|
-
test('component exports correctly', () => {
|
438
|
-
expect(Text).toBeDefined()
|
439
|
-
expect(typeof Text).toBe('function')
|
440
|
-
expect(TEXTFORMATS).toBeDefined()
|
441
|
-
})
|
442
|
-
|
443
|
-
test('TEXTFORMATS contains all expected formats', () => {
|
444
|
-
expect(TEXTFORMATS.NONE).toBe('')
|
445
|
-
expect(TEXTFORMATS.NUMERIC).toBe('numeric')
|
446
|
-
expect(TEXTFORMATS.DATE).toBe('date')
|
447
|
-
expect(TEXTFORMATS.TIME).toBe('time')
|
448
|
-
expect(TEXTFORMATS.EMAIL).toBe('email')
|
449
|
-
expect(TEXTFORMATS.HTML).toBe('HTML')
|
450
|
-
expect(TEXTFORMATS.URL).toBe('URL')
|
451
|
-
expect(TEXTFORMATS.STRING).toBe('string')
|
452
|
-
expect(TEXTFORMATS.CURRENCY).toBe('currency')
|
453
|
-
expect(TEXTFORMATS.PERCENTAGE).toBe('percentage')
|
454
|
-
expect(TEXTFORMATS.PHONE).toBe('phone')
|
455
|
-
expect(TEXTFORMATS.CAPITALIZE).toBe('capitalize')
|
456
|
-
expect(TEXTFORMATS.UPPERCASE).toBe('uppercase')
|
457
|
-
expect(TEXTFORMATS.LOWERCASE).toBe('lowercase')
|
458
|
-
expect(TEXTFORMATS.TRUNCATE).toBe('truncate')
|
459
|
-
})
|
460
|
-
|
461
|
-
test('component has correct PropTypes', () => {
|
462
|
-
expect(Text.propTypes).toBeDefined()
|
463
|
-
expect(Text.propTypes.format).toBeDefined()
|
464
|
-
expect(Text.propTypes.children).toBeDefined()
|
465
|
-
expect(Text.propTypes.className).toBeDefined()
|
466
|
-
expect(Text.propTypes.size).toBeDefined()
|
467
|
-
expect(Text.propTypes.weight).toBeDefined()
|
468
|
-
expect(Text.propTypes.color).toBeDefined()
|
469
|
-
expect(Text.propTypes.copyable).toBeDefined()
|
470
|
-
expect(Text.propTypes.loading).toBeDefined()
|
471
|
-
})
|
472
|
-
|
473
|
-
test('component has correct defaultProps', () => {
|
474
|
-
expect(Text.defaultProps).toBeDefined()
|
475
|
-
expect(Text.defaultProps.format).toBe(TEXTFORMATS.HTML)
|
476
|
-
expect(Text.defaultProps.currency).toBe('USD')
|
477
|
-
expect(Text.defaultProps.loading).toBe(false)
|
478
|
-
expect(Text.defaultProps.copyable).toBe(false)
|
479
|
-
expect(Text.defaultProps.selectable).toBe(true)
|
480
|
-
expect(Text.defaultProps.as).toBe('span')
|
481
|
-
})
|
482
|
-
|
483
|
-
test('formats text correctly', () => {
|
484
|
-
// Mock Intl for consistent testing
|
485
|
-
const mockNumberFormat = jest.fn().mockImplementation(() => ({
|
486
|
-
format: jest.fn().mockReturnValue('1,234.56')
|
487
|
-
}))
|
488
|
-
global.Intl = { NumberFormat: mockNumberFormat }
|
489
|
-
|
490
|
-
const formatText = (children, format, locale = 'en-US') => {
|
491
|
-
try {
|
492
|
-
switch (format) {
|
493
|
-
case TEXTFORMATS.NUMERIC: {
|
494
|
-
const formatter = new Intl.NumberFormat(locale)
|
495
|
-
return formatter.format(Number(children))
|
496
|
-
}
|
497
|
-
case TEXTFORMATS.CAPITALIZE: {
|
498
|
-
return String(children).charAt(0).toUpperCase() + String(children).slice(1).toLowerCase()
|
499
|
-
}
|
500
|
-
case TEXTFORMATS.UPPERCASE: {
|
501
|
-
return String(children).toUpperCase()
|
502
|
-
}
|
503
|
-
case TEXTFORMATS.LOWERCASE: {
|
504
|
-
return String(children).toLowerCase()
|
505
|
-
}
|
506
|
-
case TEXTFORMATS.PHONE: {
|
507
|
-
const cleaned = String(children).replace(/\D/g, '')
|
508
|
-
if (cleaned.length === 10) {
|
509
|
-
return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6)}`
|
510
|
-
}
|
511
|
-
return String(children)
|
512
|
-
}
|
513
|
-
default: {
|
514
|
-
return String(children)
|
515
|
-
}
|
516
|
-
}
|
517
|
-
} catch (error) {
|
518
|
-
return String(children)
|
519
|
-
}
|
520
|
-
}
|
521
|
-
|
522
|
-
expect(formatText('hello world', TEXTFORMATS.CAPITALIZE)).toBe('Hello world')
|
523
|
-
expect(formatText('hello world', TEXTFORMATS.UPPERCASE)).toBe('HELLO WORLD')
|
524
|
-
expect(formatText('HELLO WORLD', TEXTFORMATS.LOWERCASE)).toBe('hello world')
|
525
|
-
expect(formatText('1234567890', TEXTFORMATS.PHONE)).toBe('(123) 456-7890')
|
526
|
-
expect(formatText('123', TEXTFORMATS.PHONE)).toBe('123')
|
527
|
-
})
|
528
|
-
|
529
|
-
test('handles copy functionality correctly', async () => {
|
530
|
-
const handleCopy = async (copyable, formattedValue) => {
|
531
|
-
if (!copyable || !formattedValue) return
|
532
|
-
|
533
|
-
try {
|
534
|
-
await navigator.clipboard.writeText(formattedValue)
|
535
|
-
} catch (error) {
|
536
|
-
console.warn('Failed to copy text:', error)
|
537
|
-
}
|
538
|
-
}
|
539
|
-
|
540
|
-
// Normal copy
|
541
|
-
await handleCopy(true, 'test text')
|
542
|
-
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('test text')
|
543
|
-
|
544
|
-
navigator.clipboard.writeText.mockClear()
|
545
|
-
|
546
|
-
// Copy disabled
|
547
|
-
await handleCopy(false, 'test text')
|
548
|
-
expect(navigator.clipboard.writeText).not.toHaveBeenCalled()
|
549
|
-
|
550
|
-
// Empty text
|
551
|
-
await handleCopy(true, '')
|
552
|
-
expect(navigator.clipboard.writeText).not.toHaveBeenCalled()
|
553
|
-
})
|
554
|
-
|
555
|
-
test('generates CSS classes correctly', () => {
|
556
|
-
const generateClasses = (size, weight, color, align, transform, decoration, truncate, loading, skeleton, copyable, selectable, className) => {
|
557
|
-
return [
|
558
|
-
'text',
|
559
|
-
size && `text--${size}`,
|
560
|
-
weight && `text--${weight}`,
|
561
|
-
color && `text--${color}`,
|
562
|
-
align && `text--${align}`,
|
563
|
-
transform && `text--${transform}`,
|
564
|
-
decoration && `text--${decoration}`,
|
565
|
-
truncate && 'text--truncate',
|
566
|
-
loading && 'text--loading',
|
567
|
-
skeleton && 'text--skeleton',
|
568
|
-
copyable && 'text--copyable',
|
569
|
-
!selectable && 'text--no-select',
|
570
|
-
className
|
571
|
-
].filter(Boolean).join(' ')
|
572
|
-
}
|
573
|
-
|
574
|
-
expect(generateClasses('md', 'bold', 'primary', 'center', 'uppercase', 'underline', true, false, false, true, true, 'custom'))
|
575
|
-
.toBe('text text--md text--bold text--primary text--center text--uppercase text--underline text--truncate text--copyable custom')
|
576
|
-
|
577
|
-
expect(generateClasses(null, null, null, null, null, null, false, true, true, false, false, ''))
|
578
|
-
.toBe('text text--loading text--skeleton text--no-select')
|
579
|
-
})
|
580
|
-
})
|
581
|
-
})
|