ywana-core8 0.1.103 → 0.2.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/dist/index.css +4941 -324
- package/dist/index.js +42338 -0
- package/dist/index.js.map +1 -0
- package/dist/index.modern.js +37458 -31678
- package/dist/index.modern.js.map +1 -1
- package/dist/index.umd.js +39634 -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 +254 -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,12 +0,0 @@
|
|
1
|
-
import React from 'react'
|
2
|
-
import { LoginBox } from './LoginBox'
|
3
|
-
import { ForgetUserPasswordAction } from './actions'
|
4
|
-
|
5
|
-
const LoginBoxTest = (prop) => {
|
6
|
-
|
7
|
-
return (
|
8
|
-
<LoginBox message="Error">
|
9
|
-
<ForgetUserPasswordAction icon={false} />
|
10
|
-
</LoginBox>
|
11
|
-
)
|
12
|
-
}
|
@@ -1,34 +0,0 @@
|
|
1
|
-
import React, { useState } from 'react'
|
2
|
-
import { ResetPasswordBox } from './ResetPasswordBox'
|
3
|
-
|
4
|
-
/**
|
5
|
-
* Reset Password Box
|
6
|
-
*/
|
7
|
-
export const ResetPasswordBoxTest = (prop) => {
|
8
|
-
|
9
|
-
const config = {
|
10
|
-
userRequired: true,
|
11
|
-
oldPwdRequired: true,
|
12
|
-
lang: 'EN',
|
13
|
-
onOK: (form) => {
|
14
|
-
console.log('onOK', form)
|
15
|
-
},
|
16
|
-
onClose: () => {
|
17
|
-
console.log('onClose')
|
18
|
-
}
|
19
|
-
}
|
20
|
-
return (
|
21
|
-
<ResetPasswordBox {...config} >
|
22
|
-
<div>
|
23
|
-
<h5>Your password must contain</h5>
|
24
|
-
<ul>
|
25
|
-
<li>At least 8 characters</li>
|
26
|
-
<li>At least one uppercase letter</li>
|
27
|
-
<li>At least one lowercase letter</li>
|
28
|
-
<li>At least one number</li>
|
29
|
-
<li>At least one special character</li>
|
30
|
-
</ul>
|
31
|
-
</div>
|
32
|
-
</ResetPasswordBox>
|
33
|
-
)
|
34
|
-
}
|
@@ -1,51 +0,0 @@
|
|
1
|
-
const validations = require('./validations');
|
2
|
-
const { validatePassword } = validations;
|
3
|
-
|
4
|
-
describe('validatePassword', () => {
|
5
|
-
test('debería devolver un error si la longitud es menor a 15 caracteres', () => {
|
6
|
-
const [isValid, error] = validatePassword('Abc123!');
|
7
|
-
expect(isValid).toBe(false);
|
8
|
-
expect(error).toBe('La contraseña debe tener entre 15 y 50 caracteres.');
|
9
|
-
});
|
10
|
-
|
11
|
-
test('debería devolver un error si la longitud es mayor a 50 caracteres', () => {
|
12
|
-
const [isValid, error] = validatePassword('A'.repeat(51) + '1!aB');
|
13
|
-
expect(isValid).toBe(false);
|
14
|
-
expect(error).toBe('La contraseña debe tener entre 15 y 50 caracteres.');
|
15
|
-
});
|
16
|
-
|
17
|
-
test('debería devolver un error si no contiene letras', () => {
|
18
|
-
const [isValid, error] = validatePassword('1234567890!@#$%^&*()');
|
19
|
-
expect(isValid).toBe(false);
|
20
|
-
expect(error).toBe('La contraseña debe contener al menos una letra (A-Z o a-z).');
|
21
|
-
});
|
22
|
-
|
23
|
-
test('debería devolver un error si no contiene números', () => {
|
24
|
-
const [isValid, error] = validatePassword('Aaaaaaaa!aaaaaaa');
|
25
|
-
expect(isValid).toBe(false);
|
26
|
-
expect(error).toBe('La contraseña debe contener al menos un número (0-9).');
|
27
|
-
});
|
28
|
-
|
29
|
-
test('debería devolver un error si no contiene minúsculas', () => {
|
30
|
-
const [isValid, error] = validatePassword('AAAAAAAAAAAAA1!');
|
31
|
-
expect(isValid).toBe(false);
|
32
|
-
expect(error).toBe('La contraseña debe contener al menos una letra en minúscula (a-z).');
|
33
|
-
});
|
34
|
-
|
35
|
-
test('debería devolver un error si no contiene mayúsculas', () => {
|
36
|
-
const [isValid, error] = validatePassword('aaaaaaaaaaaaa1!');
|
37
|
-
expect(isValid).toBe(false);
|
38
|
-
expect(error).toBe('La contraseña debe contener al menos una letra en mayúscula (A-Z).');
|
39
|
-
});
|
40
|
-
|
41
|
-
test('debería devolver un error si no contiene un carácter especial', () => {
|
42
|
-
const [isValid, error] = validatePassword('Aaaaaaaa1Aaaaaaaa');
|
43
|
-
expect(isValid).toBe(false);
|
44
|
-
expect(error).toBe('La contraseña debe contener al menos un carácter especial (< > + & ! ? * - _ % . : =).');
|
45
|
-
});
|
46
|
-
|
47
|
-
test('debería devolver true si la contraseña es válida', () => {
|
48
|
-
const [isValid, error] = validatePassword('Aaaaaaaa1Aaaaa!a');
|
49
|
-
expect(isValid).toBe(true);
|
50
|
-
});
|
51
|
-
});
|
@@ -1,60 +0,0 @@
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
2
|
-
import { Planner } from './Planner'
|
3
|
-
|
4
|
-
const EventCard = (props) => {
|
5
|
-
const { event = {} } = props
|
6
|
-
const { id, title, color } = event
|
7
|
-
|
8
|
-
function drag(ev) {
|
9
|
-
ev.dataTransfer.setData("text", id);
|
10
|
-
}
|
11
|
-
|
12
|
-
let style = { backgroundColor: "red", color: "white" }
|
13
|
-
return (
|
14
|
-
<div draggable onDragStart={drag} id={id} className={`event-card`} style={style}>
|
15
|
-
{title}
|
16
|
-
</div>
|
17
|
-
)
|
18
|
-
}
|
19
|
-
|
20
|
-
const PlannerTest = (prop) => {
|
21
|
-
|
22
|
-
const [event, setEvent] = useState()
|
23
|
-
|
24
|
-
useEffect(() => {
|
25
|
-
setEvent("3")
|
26
|
-
}, [])
|
27
|
-
|
28
|
-
const lanes = [
|
29
|
-
{ id: "lane1", label: "Lane 1" },
|
30
|
-
{ id: "lane2", label: "Lane 2" },
|
31
|
-
{ id: "lane3", label: "Lane 3" },
|
32
|
-
{ id: "lane4", label: "Lane 4" },
|
33
|
-
{ id: "lane5", label: "Lane 5" },
|
34
|
-
{ id: "lane6", label: "Lane 6" },
|
35
|
-
{ id: "lane7", label: "Lane 7" },
|
36
|
-
]
|
37
|
-
|
38
|
-
const events = [
|
39
|
-
{ id: "3", lane: "lane1", date: "2022-04-04", color: "yellow", title: "Event One", Renderer: EventCard },
|
40
|
-
{ id: "1", lane: "lane1", date: "2022-04-05", color: "red", title: "Event One", Renderer: EventCard },
|
41
|
-
{ id: "2", lane: "lane1", date: "2022-04-06", color: "blue", title: "Event One", Renderer: EventCard },
|
42
|
-
{ id: "4", lane: "lane1", date: "2022-03-07", color: "red", title: "Event One", Renderer: EventCard },
|
43
|
-
]
|
44
|
-
|
45
|
-
|
46
|
-
return (
|
47
|
-
<Planner
|
48
|
-
title="Planner 1"
|
49
|
-
lanes={lanes}
|
50
|
-
events={events}
|
51
|
-
navigation={true}
|
52
|
-
//onSelectCell={console.log}
|
53
|
-
//onChange={(data) => console.log('D&D', data)}
|
54
|
-
config = {{ range: "week" }}
|
55
|
-
>
|
56
|
-
|
57
|
-
</Planner>
|
58
|
-
|
59
|
-
)
|
60
|
-
}
|
@@ -1,32 +0,0 @@
|
|
1
|
-
import React from 'react'
|
2
|
-
import { UploadArea } from './UploadArea'
|
3
|
-
import { Uploader } from './Uploader'
|
4
|
-
import { UploadProgress } from './UploadProgress'
|
5
|
-
import { UPLOAD_STATES } from './UploadStates'
|
6
|
-
|
7
|
-
const UploadAreaTest = (props) => {
|
8
|
-
return (
|
9
|
-
<div style={{ padding: "1rem" }}>
|
10
|
-
<UploadArea icon="cloud_upload" label="UploadArea Test" disabled={true} />
|
11
|
-
</div>
|
12
|
-
)
|
13
|
-
}
|
14
|
-
|
15
|
-
const UploadProgressTest = (prop) => {
|
16
|
-
const files = [
|
17
|
-
{ icon: "image", fileName: "fileName1", uploadState: UPLOAD_STATES.RUNNING, progress: () => { return 50 } },
|
18
|
-
{ icon: "image", fileName: "fileName4", uploadState: UPLOAD_STATES.SUCCESS, progress: () => { return 70 } },
|
19
|
-
{ icon: "description", fileName: "fileName2", uploadState: UPLOAD_STATES.ERROR, progress: () => { return 70 }, uploadError: "Unknow error" },
|
20
|
-
]
|
21
|
-
return (
|
22
|
-
<UploadProgress files={files} />
|
23
|
-
)
|
24
|
-
}
|
25
|
-
|
26
|
-
const UploaderTest = (prop) => {
|
27
|
-
return (
|
28
|
-
<div style={{ padding: "1rem" }}>
|
29
|
-
<Uploader view="icon" icon="cloud_upload" target="https://maso.developxp.com/kiosk/api/upload" />
|
30
|
-
</div>
|
31
|
-
)
|
32
|
-
}
|
package/table2.test.js
DELETED
@@ -1,454 +0,0 @@
|
|
1
|
-
import React from 'react'
|
2
|
-
import { DataTable2 } from './table2'
|
3
|
-
|
4
|
-
// Pruebas unitarias para el componente DataTable2 mejorado
|
5
|
-
describe('Enhanced DataTable2 Component', () => {
|
6
|
-
// Mock de los componentes dependientes
|
7
|
-
const mockIcon = jest.fn()
|
8
|
-
const mockText = jest.fn()
|
9
|
-
const mockCheckBox = jest.fn()
|
10
|
-
const mockTextField = jest.fn()
|
11
|
-
const mockDropDown = jest.fn()
|
12
|
-
const mockEmptyMessage = jest.fn()
|
13
|
-
|
14
|
-
beforeEach(() => {
|
15
|
-
jest.clearAllMocks()
|
16
|
-
|
17
|
-
// Mock de componentes
|
18
|
-
jest.doMock('./icon', () => ({ Icon: mockIcon }))
|
19
|
-
jest.doMock('./text', () => ({ Text: mockText }))
|
20
|
-
jest.doMock('./checkbox', () => ({ CheckBox: mockCheckBox }))
|
21
|
-
jest.doMock('./textfield', () => ({ TextField: mockTextField, DropDown: mockDropDown }))
|
22
|
-
jest.doMock('../widgets/empty/EmptyMessage', () => ({ EmptyMessage: mockEmptyMessage }))
|
23
|
-
|
24
|
-
// Mock de console.warn
|
25
|
-
jest.spyOn(console, 'warn').mockImplementation(() => {})
|
26
|
-
|
27
|
-
// Mock de navigator.clipboard
|
28
|
-
global.navigator = {
|
29
|
-
clipboard: {
|
30
|
-
writeText: jest.fn().mockResolvedValue(undefined)
|
31
|
-
},
|
32
|
-
userLanguage: 'en-US',
|
33
|
-
language: 'en-US'
|
34
|
-
}
|
35
|
-
|
36
|
-
// Mock de URL.createObjectURL
|
37
|
-
global.URL = {
|
38
|
-
createObjectURL: jest.fn().mockReturnValue('mock-url'),
|
39
|
-
revokeObjectURL: jest.fn()
|
40
|
-
}
|
41
|
-
|
42
|
-
// Mock de Blob
|
43
|
-
global.Blob = jest.fn().mockImplementation((content, options) => ({
|
44
|
-
content,
|
45
|
-
options
|
46
|
-
}))
|
47
|
-
|
48
|
-
// Mock de document.createElement
|
49
|
-
const mockAnchor = {
|
50
|
-
href: '',
|
51
|
-
download: '',
|
52
|
-
click: jest.fn()
|
53
|
-
}
|
54
|
-
jest.spyOn(document, 'createElement').mockReturnValue(mockAnchor)
|
55
|
-
})
|
56
|
-
|
57
|
-
afterEach(() => {
|
58
|
-
console.warn.mockRestore()
|
59
|
-
document.createElement.mockRestore()
|
60
|
-
})
|
61
|
-
|
62
|
-
// DataTable2 Component Tests
|
63
|
-
describe('DataTable2 Component', () => {
|
64
|
-
const mockColumns = [
|
65
|
-
{ id: 'name', label: 'Name', type: 'String', sortable: true },
|
66
|
-
{ id: 'age', label: 'Age', type: 'Number', sortable: true },
|
67
|
-
{ id: 'email', label: 'Email', type: 'String', filterable: true }
|
68
|
-
]
|
69
|
-
|
70
|
-
const mockRows = [
|
71
|
-
{ id: 1, name: 'John Doe', age: 30, email: 'john@example.com' },
|
72
|
-
{ id: 2, name: 'Jane Smith', age: 25, email: 'jane@example.com' },
|
73
|
-
{ id: 3, name: 'Bob Johnson', age: 35, email: 'bob@example.com' }
|
74
|
-
]
|
75
|
-
|
76
|
-
test('component exports correctly', () => {
|
77
|
-
expect(DataTable2).toBeDefined()
|
78
|
-
expect(typeof DataTable2).toBe('function')
|
79
|
-
})
|
80
|
-
|
81
|
-
test('component has correct PropTypes', () => {
|
82
|
-
expect(DataTable2.propTypes).toBeDefined()
|
83
|
-
expect(DataTable2.propTypes.columns).toBeDefined()
|
84
|
-
expect(DataTable2.propTypes.rows).toBeDefined()
|
85
|
-
expect(DataTable2.propTypes.onRowSelection).toBeDefined()
|
86
|
-
expect(DataTable2.propTypes.onSort).toBeDefined()
|
87
|
-
expect(DataTable2.propTypes.onCheckAll).toBeDefined()
|
88
|
-
expect(DataTable2.propTypes.editable).toBeDefined()
|
89
|
-
expect(DataTable2.propTypes.outlined).toBeDefined()
|
90
|
-
expect(DataTable2.propTypes.expanded).toBeDefined()
|
91
|
-
expect(DataTable2.propTypes.multisort).toBeDefined()
|
92
|
-
expect(DataTable2.propTypes.filterable).toBeDefined()
|
93
|
-
// New props
|
94
|
-
expect(DataTable2.propTypes.loading).toBeDefined()
|
95
|
-
expect(DataTable2.propTypes.skeleton).toBeDefined()
|
96
|
-
expect(DataTable2.propTypes.searchable).toBeDefined()
|
97
|
-
expect(DataTable2.propTypes.exportable).toBeDefined()
|
98
|
-
expect(DataTable2.propTypes.virtualScrolling).toBeDefined()
|
99
|
-
})
|
100
|
-
|
101
|
-
test('component has correct defaultProps', () => {
|
102
|
-
expect(DataTable2.defaultProps).toBeDefined()
|
103
|
-
expect(DataTable2.defaultProps.columns).toEqual([])
|
104
|
-
expect(DataTable2.defaultProps.rows).toEqual([])
|
105
|
-
expect(DataTable2.defaultProps.expanded).toBe(false)
|
106
|
-
expect(DataTable2.defaultProps.emptyMessage).toBe("No Results Found")
|
107
|
-
expect(DataTable2.defaultProps.emptyIcon).toBe("search_off")
|
108
|
-
expect(DataTable2.defaultProps.multisort).toBe(false)
|
109
|
-
expect(DataTable2.defaultProps.filterable).toBe(false)
|
110
|
-
// New defaults
|
111
|
-
expect(DataTable2.defaultProps.loading).toBe(false)
|
112
|
-
expect(DataTable2.defaultProps.skeleton).toBe(false)
|
113
|
-
expect(DataTable2.defaultProps.striped).toBe(false)
|
114
|
-
expect(DataTable2.defaultProps.hover).toBe(true)
|
115
|
-
expect(DataTable2.defaultProps.responsive).toBe(true)
|
116
|
-
expect(DataTable2.defaultProps.stickyHeader).toBe(true)
|
117
|
-
expect(DataTable2.defaultProps.selectionMode).toBe('single')
|
118
|
-
expect(DataTable2.defaultProps.sortMode).toBe('single')
|
119
|
-
})
|
120
|
-
|
121
|
-
test('validates props correctly', () => {
|
122
|
-
const validateProps = (columns, rows, virtualScrolling, pageSize) => {
|
123
|
-
if (!Array.isArray(columns)) {
|
124
|
-
console.warn('DataTable2: columns prop must be an array')
|
125
|
-
}
|
126
|
-
if (!Array.isArray(rows)) {
|
127
|
-
console.warn('DataTable2: rows prop must be an array')
|
128
|
-
}
|
129
|
-
if (virtualScrolling && !pageSize) {
|
130
|
-
console.warn('DataTable2: pageSize is required when virtualScrolling is enabled')
|
131
|
-
}
|
132
|
-
}
|
133
|
-
|
134
|
-
// Invalid columns prop
|
135
|
-
validateProps('not an array', [], false, null)
|
136
|
-
expect(console.warn).toHaveBeenCalledWith('DataTable2: columns prop must be an array')
|
137
|
-
|
138
|
-
console.warn.mockClear()
|
139
|
-
|
140
|
-
// Invalid rows prop
|
141
|
-
validateProps([], 'not an array', false, null)
|
142
|
-
expect(console.warn).toHaveBeenCalledWith('DataTable2: rows prop must be an array')
|
143
|
-
|
144
|
-
console.warn.mockClear()
|
145
|
-
|
146
|
-
// Virtual scrolling without pageSize
|
147
|
-
validateProps([], [], true, null)
|
148
|
-
expect(console.warn).toHaveBeenCalledWith('DataTable2: pageSize is required when virtualScrolling is enabled')
|
149
|
-
|
150
|
-
console.warn.mockClear()
|
151
|
-
|
152
|
-
// Valid props
|
153
|
-
validateProps(mockColumns, mockRows, false, null)
|
154
|
-
expect(console.warn).not.toHaveBeenCalled()
|
155
|
-
})
|
156
|
-
|
157
|
-
test('handles sort correctly (maintaining original behavior)', () => {
|
158
|
-
const changeSort = (id, sortDir, sortMode, multisort, setSortDir) => {
|
159
|
-
if (sortMode === 'none') return
|
160
|
-
|
161
|
-
if (sortMode === 'multiple' || multisort) {
|
162
|
-
const nextDir = sortDir[id] ? sortDir[id] * -1 : 1
|
163
|
-
const next = Object.assign({}, sortDir, { [id]: nextDir })
|
164
|
-
setSortDir(next)
|
165
|
-
} else {
|
166
|
-
const nextDir = sortDir[id] ? sortDir[id] * -1 : 1
|
167
|
-
setSortDir({ [id]: nextDir })
|
168
|
-
}
|
169
|
-
}
|
170
|
-
|
171
|
-
const mockSetSortDir = jest.fn()
|
172
|
-
|
173
|
-
// Single sort mode
|
174
|
-
changeSort('name', {}, 'single', false, mockSetSortDir)
|
175
|
-
expect(mockSetSortDir).toHaveBeenCalledWith({ name: 1 })
|
176
|
-
|
177
|
-
mockSetSortDir.mockClear()
|
178
|
-
|
179
|
-
// Multiple sort mode
|
180
|
-
changeSort('age', { name: 1 }, 'multiple', false, mockSetSortDir)
|
181
|
-
expect(mockSetSortDir).toHaveBeenCalledWith({ name: 1, age: 1 })
|
182
|
-
|
183
|
-
mockSetSortDir.mockClear()
|
184
|
-
|
185
|
-
// Reverse sort
|
186
|
-
changeSort('name', { name: 1 }, 'single', false, mockSetSortDir)
|
187
|
-
expect(mockSetSortDir).toHaveBeenCalledWith({ name: -1 })
|
188
|
-
|
189
|
-
mockSetSortDir.mockClear()
|
190
|
-
|
191
|
-
// No sort mode
|
192
|
-
changeSort('name', {}, 'none', false, mockSetSortDir)
|
193
|
-
expect(mockSetSortDir).not.toHaveBeenCalled()
|
194
|
-
})
|
195
|
-
|
196
|
-
test('handles multiSort correctly (maintaining original logic)', () => {
|
197
|
-
const multiSort = (array, sortObject = {}) => {
|
198
|
-
const sortKeys = Object.keys(sortObject);
|
199
|
-
|
200
|
-
if (!sortKeys.length) {
|
201
|
-
return array;
|
202
|
-
}
|
203
|
-
|
204
|
-
const keySort = (a, b, direction) => {
|
205
|
-
direction = direction !== null ? direction : 1;
|
206
|
-
|
207
|
-
// check if a and b are numbers and compare as numbers
|
208
|
-
if (!isNaN(a) && !isNaN(b)) {
|
209
|
-
a = Number(a);
|
210
|
-
b = Number(b);
|
211
|
-
}
|
212
|
-
|
213
|
-
// If b > a, multiply by -1 to get the reverse direction.
|
214
|
-
return a > b ? direction : -1 * direction;
|
215
|
-
};
|
216
|
-
|
217
|
-
return array.sort((a, b) => {
|
218
|
-
let sorted = 0;
|
219
|
-
let index = 0;
|
220
|
-
|
221
|
-
// Loop until sorted (-1 or 1) or until the sort keys have been processed.
|
222
|
-
while (sorted === 0 && index < sortKeys.length) {
|
223
|
-
const key = sortKeys[index];
|
224
|
-
if (key) {
|
225
|
-
const direction = sortObject[key];
|
226
|
-
sorted = keySort(a[key], b[key], direction);
|
227
|
-
index++;
|
228
|
-
}
|
229
|
-
}
|
230
|
-
|
231
|
-
return sorted;
|
232
|
-
});
|
233
|
-
};
|
234
|
-
|
235
|
-
const testData = [
|
236
|
-
{ name: 'Charlie', age: 30 },
|
237
|
-
{ name: 'Alice', age: 25 },
|
238
|
-
{ name: 'Bob', age: 35 }
|
239
|
-
]
|
240
|
-
|
241
|
-
// No sort
|
242
|
-
expect(multiSort([...testData], {})).toEqual(testData)
|
243
|
-
|
244
|
-
// Sort by name ascending
|
245
|
-
const sortedByName = multiSort([...testData], { name: 1 })
|
246
|
-
expect(sortedByName[0].name).toBe('Alice')
|
247
|
-
expect(sortedByName[1].name).toBe('Bob')
|
248
|
-
expect(sortedByName[2].name).toBe('Charlie')
|
249
|
-
|
250
|
-
// Sort by age descending
|
251
|
-
const sortedByAge = multiSort([...testData], { age: -1 })
|
252
|
-
expect(sortedByAge[0].age).toBe(35)
|
253
|
-
expect(sortedByAge[1].age).toBe(30)
|
254
|
-
expect(sortedByAge[2].age).toBe(25)
|
255
|
-
|
256
|
-
// Multi-sort: name asc, then age desc
|
257
|
-
const multiSorted = multiSort([...testData], { name: 1, age: -1 })
|
258
|
-
expect(multiSorted[0].name).toBe('Alice')
|
259
|
-
})
|
260
|
-
|
261
|
-
test('handles row selection correctly (maintaining original behavior)', () => {
|
262
|
-
const mockOnRowSelection = jest.fn()
|
263
|
-
const mockOnRowClick = jest.fn()
|
264
|
-
|
265
|
-
const select = (row, event, selectedRows, selectionMode, setSelectedRows, onRowSelection, onRowClick) => {
|
266
|
-
if (event.target.id !== "checked") {
|
267
|
-
// Enhanced selection logic
|
268
|
-
if (selectionMode === 'multiple') {
|
269
|
-
const newSelected = new Set(selectedRows)
|
270
|
-
if (newSelected.has(row.id)) {
|
271
|
-
newSelected.delete(row.id)
|
272
|
-
} else {
|
273
|
-
newSelected.add(row.id)
|
274
|
-
}
|
275
|
-
setSelectedRows(newSelected)
|
276
|
-
} else if (selectionMode === 'single') {
|
277
|
-
setSelectedRows(new Set([row.id]))
|
278
|
-
}
|
279
|
-
|
280
|
-
// Call original callback
|
281
|
-
if (onRowSelection) onRowSelection(row, event)
|
282
|
-
if (onRowClick) onRowClick(row, event)
|
283
|
-
}
|
284
|
-
}
|
285
|
-
|
286
|
-
const mockSetSelectedRows = jest.fn()
|
287
|
-
const mockEvent = { target: { id: 'not-checked' } }
|
288
|
-
const mockRow = { id: 1, name: 'Test' }
|
289
|
-
|
290
|
-
// Single selection
|
291
|
-
select(mockRow, mockEvent, new Set(), 'single', mockSetSelectedRows, mockOnRowSelection, mockOnRowClick)
|
292
|
-
expect(mockSetSelectedRows).toHaveBeenCalledWith(new Set([1]))
|
293
|
-
expect(mockOnRowSelection).toHaveBeenCalledWith(mockRow, mockEvent)
|
294
|
-
expect(mockOnRowClick).toHaveBeenCalledWith(mockRow, mockEvent)
|
295
|
-
|
296
|
-
mockSetSelectedRows.mockClear()
|
297
|
-
mockOnRowSelection.mockClear()
|
298
|
-
mockOnRowClick.mockClear()
|
299
|
-
|
300
|
-
// Multiple selection - add
|
301
|
-
select(mockRow, mockEvent, new Set(), 'multiple', mockSetSelectedRows, mockOnRowSelection, mockOnRowClick)
|
302
|
-
expect(mockSetSelectedRows).toHaveBeenCalledWith(new Set([1]))
|
303
|
-
|
304
|
-
// Multiple selection - remove
|
305
|
-
select(mockRow, mockEvent, new Set([1]), 'multiple', mockSetSelectedRows, mockOnRowSelection, mockOnRowClick)
|
306
|
-
expect(mockSetSelectedRows).toHaveBeenCalledWith(new Set())
|
307
|
-
|
308
|
-
// Checkbox click (should not trigger selection)
|
309
|
-
const checkboxEvent = { target: { id: 'checked' } }
|
310
|
-
select(mockRow, checkboxEvent, new Set(), 'single', mockSetSelectedRows, mockOnRowSelection, mockOnRowClick)
|
311
|
-
expect(mockOnRowSelection).not.toHaveBeenCalled()
|
312
|
-
})
|
313
|
-
|
314
|
-
test('handles check all correctly (maintaining original behavior)', () => {
|
315
|
-
const mockOnCheckAll = jest.fn()
|
316
|
-
|
317
|
-
const checkAll = (id, value, rows, selectionMode, setAllChecked, setSelectedRows, onCheckAll) => {
|
318
|
-
const ids = rows.map(row => row.id)
|
319
|
-
setAllChecked(value)
|
320
|
-
|
321
|
-
if (selectionMode === 'multiple') {
|
322
|
-
if (value) {
|
323
|
-
setSelectedRows(new Set(ids))
|
324
|
-
} else {
|
325
|
-
setSelectedRows(new Set())
|
326
|
-
}
|
327
|
-
}
|
328
|
-
|
329
|
-
if (onCheckAll) onCheckAll(ids, value)
|
330
|
-
}
|
331
|
-
|
332
|
-
const mockSetAllChecked = jest.fn()
|
333
|
-
const mockSetSelectedRows = jest.fn()
|
334
|
-
|
335
|
-
// Check all
|
336
|
-
checkAll('checked', true, mockRows, 'multiple', mockSetAllChecked, mockSetSelectedRows, mockOnCheckAll)
|
337
|
-
expect(mockSetAllChecked).toHaveBeenCalledWith(true)
|
338
|
-
expect(mockSetSelectedRows).toHaveBeenCalledWith(new Set([1, 2, 3]))
|
339
|
-
expect(mockOnCheckAll).toHaveBeenCalledWith([1, 2, 3], true)
|
340
|
-
|
341
|
-
mockSetAllChecked.mockClear()
|
342
|
-
mockSetSelectedRows.mockClear()
|
343
|
-
mockOnCheckAll.mockClear()
|
344
|
-
|
345
|
-
// Uncheck all
|
346
|
-
checkAll('checked', false, mockRows, 'multiple', mockSetAllChecked, mockSetSelectedRows, mockOnCheckAll)
|
347
|
-
expect(mockSetAllChecked).toHaveBeenCalledWith(false)
|
348
|
-
expect(mockSetSelectedRows).toHaveBeenCalledWith(new Set())
|
349
|
-
expect(mockOnCheckAll).toHaveBeenCalledWith([1, 2, 3], false)
|
350
|
-
})
|
351
|
-
|
352
|
-
test('handles search functionality', () => {
|
353
|
-
const searchRows = (rows, searchTerm, searchable, columns) => {
|
354
|
-
if (!searchTerm || !searchable) return rows
|
355
|
-
|
356
|
-
return rows.filter(row => {
|
357
|
-
return columns.some(column => {
|
358
|
-
const value = row[column.id]
|
359
|
-
if (value == null) return false
|
360
|
-
return String(value).toLowerCase().includes(searchTerm.toLowerCase())
|
361
|
-
})
|
362
|
-
})
|
363
|
-
}
|
364
|
-
|
365
|
-
// No search term
|
366
|
-
expect(searchRows(mockRows, '', true, mockColumns)).toEqual(mockRows)
|
367
|
-
|
368
|
-
// Search disabled
|
369
|
-
expect(searchRows(mockRows, 'john', false, mockColumns)).toEqual(mockRows)
|
370
|
-
|
371
|
-
// Search for 'john'
|
372
|
-
const johnResults = searchRows(mockRows, 'john', true, mockColumns)
|
373
|
-
expect(johnResults).toHaveLength(2) // John Doe and Bob Johnson
|
374
|
-
expect(johnResults.map(r => r.name)).toEqual(['John Doe', 'Bob Johnson'])
|
375
|
-
|
376
|
-
// Search for email
|
377
|
-
const emailResults = searchRows(mockRows, 'jane@', true, mockColumns)
|
378
|
-
expect(emailResults).toHaveLength(1)
|
379
|
-
expect(emailResults[0].name).toBe('Jane Smith')
|
380
|
-
|
381
|
-
// No results
|
382
|
-
const noResults = searchRows(mockRows, 'xyz', true, mockColumns)
|
383
|
-
expect(noResults).toHaveLength(0)
|
384
|
-
})
|
385
|
-
|
386
|
-
test('handles export functionality', () => {
|
387
|
-
const handleExport = (processedRows, columns, onExport) => {
|
388
|
-
if (onExport) {
|
389
|
-
onExport(processedRows, columns)
|
390
|
-
} else {
|
391
|
-
// Default CSV export
|
392
|
-
const csvContent = [
|
393
|
-
columns.map(col => col.label || col.id).join(','),
|
394
|
-
...processedRows.map(row =>
|
395
|
-
columns.map(col => {
|
396
|
-
const value = row[col.id]
|
397
|
-
return typeof value === 'string' ? `"${value}"` : value
|
398
|
-
}).join(',')
|
399
|
-
)
|
400
|
-
].join('\n')
|
401
|
-
|
402
|
-
const blob = new Blob([csvContent], { type: 'text/csv' })
|
403
|
-
const url = URL.createObjectURL(blob)
|
404
|
-
const a = document.createElement('a')
|
405
|
-
a.href = url
|
406
|
-
a.download = 'table-export.csv'
|
407
|
-
a.click()
|
408
|
-
URL.revokeObjectURL(url)
|
409
|
-
}
|
410
|
-
}
|
411
|
-
|
412
|
-
const mockOnExport = jest.fn()
|
413
|
-
|
414
|
-
// Custom export
|
415
|
-
handleExport(mockRows, mockColumns, mockOnExport)
|
416
|
-
expect(mockOnExport).toHaveBeenCalledWith(mockRows, mockColumns)
|
417
|
-
|
418
|
-
mockOnExport.mockClear()
|
419
|
-
|
420
|
-
// Default CSV export
|
421
|
-
handleExport(mockRows, mockColumns, null)
|
422
|
-
expect(Blob).toHaveBeenCalledWith([expect.stringContaining('Name,Age,Email')], { type: 'text/csv' })
|
423
|
-
expect(URL.createObjectURL).toHaveBeenCalled()
|
424
|
-
expect(document.createElement).toHaveBeenCalledWith('a')
|
425
|
-
})
|
426
|
-
|
427
|
-
test('generates CSS classes correctly', () => {
|
428
|
-
const generateClasses = (outlined, striped, compact, bordered, hover, rowHeight, density, theme, responsive, isLoading, skeleton, className) => {
|
429
|
-
return [
|
430
|
-
'datatable8', // Maintain original class for compatibility
|
431
|
-
'datatable2', // New class for v2 features
|
432
|
-
outlined && 'outlined',
|
433
|
-
striped && 'datatable2--striped',
|
434
|
-
compact && 'datatable2--compact',
|
435
|
-
bordered && 'datatable2--bordered',
|
436
|
-
!hover && 'datatable2--no-hover',
|
437
|
-
`datatable2--${rowHeight}`,
|
438
|
-
`datatable2--${density}`,
|
439
|
-
`datatable2--${theme}`,
|
440
|
-
responsive && 'datatable2--responsive',
|
441
|
-
isLoading && 'datatable2--loading',
|
442
|
-
skeleton && 'datatable2--skeleton',
|
443
|
-
className
|
444
|
-
].filter(Boolean).join(' ')
|
445
|
-
}
|
446
|
-
|
447
|
-
expect(generateClasses(false, false, false, false, true, 'medium', 'normal', 'default', true, false, false, ''))
|
448
|
-
.toBe('datatable8 datatable2 datatable2--medium datatable2--normal datatable2--default datatable2--responsive')
|
449
|
-
|
450
|
-
expect(generateClasses(true, true, true, true, false, 'large', 'comfortable', 'dark', false, true, true, 'custom'))
|
451
|
-
.toBe('datatable8 datatable2 outlined datatable2--striped datatable2--compact datatable2--bordered datatable2--no-hover datatable2--large datatable2--comfortable datatable2--dark datatable2--loading datatable2--skeleton custom')
|
452
|
-
})
|
453
|
-
})
|
454
|
-
})
|