@domql/element 3.4.4 → 3.4.6
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/event/__tests__/applyAnimationFrame.test.js +114 -0
- package/event/__tests__/applyEvent.test.js +159 -0
- package/event/__tests__/applyEventUpdate.test.js +198 -0
- package/event/__tests__/applyEventsOnNode.test.js +216 -0
- package/event/__tests__/canRenderTag.test.js +50 -0
- package/event/__tests__/index.test.js +39 -0
- package/event/__tests__/initAnimationFrame.test.js +156 -0
- package/event/__tests__/registerFrameListener.test.js +97 -0
- package/event/__tests__/store.test.js +93 -0
- package/event/__tests__/triggerEventOn.test.js +195 -0
- package/event/__tests__/triggerEventOnUpdate.test.js +207 -0
- package/event/animationFrame.js +92 -0
- package/event/can.js +8 -0
- package/event/index.js +5 -0
- package/event/on.js +71 -0
- package/event/store.js +6 -0
- package/methods/set.js +73 -0
- package/methods/v2.js +83 -0
- package/mixins/attr.js +32 -0
- package/mixins/classList.js +62 -0
- package/mixins/content.js +65 -0
- package/mixins/data.js +26 -0
- package/mixins/html.js +19 -0
- package/mixins/index.js +23 -0
- package/mixins/registry.js +46 -0
- package/mixins/scope.js +23 -0
- package/mixins/state.js +18 -0
- package/mixins/style.js +25 -0
- package/mixins/text.js +31 -0
- package/package.json +13 -8
- package/render/__tests__/appendNode.test.js +53 -0
- package/render/__tests__/assignNode.test.js +151 -0
- package/render/__tests__/cacheNode.test.js +168 -0
- package/render/__tests__/createHTMLNode.test.js +118 -0
- package/render/__tests__/createNode.test.js +9 -0
- package/render/__tests__/detectTag.test.js +99 -0
- package/render/__tests__/index.test.js +56 -0
- package/render/__tests__/insertNodeAfter.test.js +111 -0
- package/render/__tests__/insertNodeBefore.test.js +65 -0
- package/render/append.js +61 -0
- package/render/cache.js +68 -0
- package/render/create.js +3 -0
- package/render/index.js +5 -0
- package/utils/applyParam.js +33 -0
- package/utils/extendUtils.js +135 -0
- package/utils/index.js +4 -0
- package/utils/propEvents.js +36 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { canRenderTag } from '../can'
|
|
2
|
+
|
|
3
|
+
// Mock the error registry
|
|
4
|
+
global.ERRORS_REGISTRY = {
|
|
5
|
+
en: {
|
|
6
|
+
HTMLInvalidTag: {
|
|
7
|
+
description: 'Invalid HTML tag provided'
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe('canRenderTag', () => {
|
|
13
|
+
describe('valid tags', () => {
|
|
14
|
+
test('should return true for div tag', () => {
|
|
15
|
+
expect(canRenderTag('div')).toBe(true)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('should default to div and return true when tag is undefined', () => {
|
|
19
|
+
expect(canRenderTag(undefined)).toBe(true)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('should default to div and return true when tag is null', () => {
|
|
23
|
+
expect(canRenderTag(null)).toBe(true)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('should return true for common HTML tags', () => {
|
|
27
|
+
const commonTags = ['p', 'span', 'button', 'input', 'a']
|
|
28
|
+
commonTags.forEach(tag => {
|
|
29
|
+
expect(canRenderTag(tag)).toBe(true)
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('should use custom error description from registry', () => {
|
|
34
|
+
// Arrange
|
|
35
|
+
global.ERRORS_REGISTRY = {
|
|
36
|
+
en: {
|
|
37
|
+
HTMLInvalidTag: {
|
|
38
|
+
description: 'Custom error description'
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Act
|
|
44
|
+
const result = canRenderTag('invalid-tag')
|
|
45
|
+
|
|
46
|
+
// Assert
|
|
47
|
+
expect(result).toBeInstanceOf(Error)
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as moduleExports from '../index'
|
|
2
|
+
|
|
3
|
+
describe('Module exports', () => {
|
|
4
|
+
// Expected exports from on.js
|
|
5
|
+
test('should export on.js functions', () => {
|
|
6
|
+
expect(moduleExports).toHaveProperty('applyEvent')
|
|
7
|
+
expect(typeof moduleExports.applyEvent).toBe('function')
|
|
8
|
+
|
|
9
|
+
expect(moduleExports).toHaveProperty('triggerEventOn')
|
|
10
|
+
expect(typeof moduleExports.triggerEventOn).toBe('function')
|
|
11
|
+
|
|
12
|
+
expect(moduleExports).toHaveProperty('applyEventUpdate')
|
|
13
|
+
expect(typeof moduleExports.applyEventUpdate).toBe('function')
|
|
14
|
+
|
|
15
|
+
expect(moduleExports).toHaveProperty('triggerEventOnUpdate')
|
|
16
|
+
expect(typeof moduleExports.triggerEventOnUpdate).toBe('function')
|
|
17
|
+
|
|
18
|
+
expect(moduleExports).toHaveProperty('applyEventsOnNode')
|
|
19
|
+
expect(typeof moduleExports.applyEventsOnNode).toBe('function')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// Expected exports from can.js
|
|
23
|
+
test('should export can.js functions', () => {
|
|
24
|
+
expect(moduleExports).toHaveProperty('canRenderTag')
|
|
25
|
+
expect(typeof moduleExports.canRenderTag).toBe('function')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// Expected exports from animationFrame.js
|
|
29
|
+
test('should export animationFrame.js functions', () => {
|
|
30
|
+
expect(moduleExports).toHaveProperty('initAnimationFrame')
|
|
31
|
+
expect(typeof moduleExports.initAnimationFrame).toBe('function')
|
|
32
|
+
|
|
33
|
+
expect(moduleExports).toHaveProperty('registerFrameListener')
|
|
34
|
+
expect(typeof moduleExports.registerFrameListener).toBe('function')
|
|
35
|
+
|
|
36
|
+
expect(moduleExports).toHaveProperty('applyAnimationFrame')
|
|
37
|
+
expect(typeof moduleExports.applyAnimationFrame).toBe('function')
|
|
38
|
+
})
|
|
39
|
+
})
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
import { initAnimationFrame } from '../animationFrame'
|
|
3
|
+
|
|
4
|
+
describe('initAnimationFrame', () => {
|
|
5
|
+
let requestAnimationFrameCallback
|
|
6
|
+
let frameListeners
|
|
7
|
+
let mockElement
|
|
8
|
+
let mockOnFrame
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
// Store callback instead of executing it immediately
|
|
12
|
+
window.requestAnimationFrame = jest.fn(cb => {
|
|
13
|
+
requestAnimationFrameCallback = cb
|
|
14
|
+
return 1 // Return a dummy frame ID
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
// Mock console.warn to avoid test output noise
|
|
18
|
+
console.warn = jest.fn()
|
|
19
|
+
|
|
20
|
+
// Create mock element with required structure
|
|
21
|
+
mockOnFrame = jest.fn()
|
|
22
|
+
mockElement = {
|
|
23
|
+
node: document.createElement('div'),
|
|
24
|
+
parent: {
|
|
25
|
+
node: document.createElement('div')
|
|
26
|
+
},
|
|
27
|
+
props: {
|
|
28
|
+
onFrame: mockOnFrame
|
|
29
|
+
},
|
|
30
|
+
onFrame: mockOnFrame, // Add direct onFrame property to the element
|
|
31
|
+
state: { foo: 'bar' },
|
|
32
|
+
context: { baz: 'qux' }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Append child to parent for contains() to work
|
|
36
|
+
mockElement.parent.node.appendChild(mockElement.node)
|
|
37
|
+
|
|
38
|
+
// Initialize frameListeners
|
|
39
|
+
frameListeners = initAnimationFrame()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
// Clean up DOM
|
|
44
|
+
if (mockElement.parent.node.parentNode) {
|
|
45
|
+
mockElement.parent.node.parentNode.removeChild(mockElement.parent.node)
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
describe('initialization', () => {
|
|
50
|
+
test('should return an empty Set', () => {
|
|
51
|
+
expect(frameListeners).toBeInstanceOf(Set)
|
|
52
|
+
expect(frameListeners.size).toBe(0)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('should request first animation frame', () => {
|
|
56
|
+
expect(window.requestAnimationFrame).toHaveBeenCalledTimes(1)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe('frame processing', () => {
|
|
61
|
+
test('should call onFrame with correct arguments when element is in DOM', () => {
|
|
62
|
+
// Arrange
|
|
63
|
+
frameListeners.add(mockElement)
|
|
64
|
+
|
|
65
|
+
// Act - trigger a single frame
|
|
66
|
+
requestAnimationFrameCallback()
|
|
67
|
+
|
|
68
|
+
// Assert
|
|
69
|
+
expect(mockOnFrame).toHaveBeenCalledWith(
|
|
70
|
+
mockElement,
|
|
71
|
+
mockElement.state,
|
|
72
|
+
mockElement.context
|
|
73
|
+
)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test('should use on.frame if available instead of onFrame', () => {
|
|
77
|
+
// Arrange
|
|
78
|
+
const onFrameHandler = jest.fn()
|
|
79
|
+
mockElement.on = { frame: onFrameHandler }
|
|
80
|
+
frameListeners.add(mockElement)
|
|
81
|
+
|
|
82
|
+
// Act - trigger a single frame
|
|
83
|
+
requestAnimationFrameCallback()
|
|
84
|
+
|
|
85
|
+
// Assert
|
|
86
|
+
expect(onFrameHandler).toHaveBeenCalledWith(
|
|
87
|
+
mockElement,
|
|
88
|
+
mockElement.state,
|
|
89
|
+
mockElement.context
|
|
90
|
+
)
|
|
91
|
+
expect(mockOnFrame).not.toHaveBeenCalled()
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('should remove element if not in DOM', () => {
|
|
95
|
+
// Arrange
|
|
96
|
+
frameListeners.add(mockElement)
|
|
97
|
+
mockElement.parent.node.removeChild(mockElement.node)
|
|
98
|
+
|
|
99
|
+
// Act - trigger a single frame
|
|
100
|
+
requestAnimationFrameCallback()
|
|
101
|
+
|
|
102
|
+
// Assert
|
|
103
|
+
expect(frameListeners.has(mockElement)).toBe(false)
|
|
104
|
+
expect(frameListeners.size).toBe(0)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
test('should catch and warn on onFrame errors', () => {
|
|
108
|
+
// Arrange
|
|
109
|
+
const error = new Error('Test error')
|
|
110
|
+
mockElement.onFrame = jest.fn(() => {
|
|
111
|
+
throw error
|
|
112
|
+
})
|
|
113
|
+
frameListeners.add(mockElement)
|
|
114
|
+
|
|
115
|
+
// Act - trigger a single frame
|
|
116
|
+
requestAnimationFrameCallback()
|
|
117
|
+
|
|
118
|
+
// Assert
|
|
119
|
+
expect(console.warn).toHaveBeenCalledWith(error)
|
|
120
|
+
// Element should still be in the set despite the error
|
|
121
|
+
expect(frameListeners.has(mockElement)).toBe(true)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test('should process multiple elements in the set', () => {
|
|
125
|
+
// Arrange
|
|
126
|
+
const mockElement2 = {
|
|
127
|
+
...mockElement,
|
|
128
|
+
node: document.createElement('div'),
|
|
129
|
+
props: { onFrame: jest.fn() },
|
|
130
|
+
onFrame: jest.fn() // Add direct onFrame property to mockElement2
|
|
131
|
+
}
|
|
132
|
+
mockElement.parent.node.appendChild(mockElement2.node)
|
|
133
|
+
|
|
134
|
+
frameListeners.add(mockElement)
|
|
135
|
+
frameListeners.add(mockElement2)
|
|
136
|
+
|
|
137
|
+
// Act - trigger a single frame
|
|
138
|
+
requestAnimationFrameCallback()
|
|
139
|
+
|
|
140
|
+
// Assert
|
|
141
|
+
expect(mockOnFrame).toHaveBeenCalled()
|
|
142
|
+
expect(mockElement2.onFrame).toHaveBeenCalled()
|
|
143
|
+
expect(frameListeners.size).toBe(2)
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
describe('animation loop', () => {
|
|
148
|
+
test('should request next animation frame after processing', () => {
|
|
149
|
+
// Act - trigger a single frame
|
|
150
|
+
requestAnimationFrameCallback()
|
|
151
|
+
|
|
152
|
+
// Assert - should have requested the next frame
|
|
153
|
+
expect(window.requestAnimationFrame).toHaveBeenCalledTimes(2)
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
})
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { registerFrameListener } from '../animationFrame'
|
|
2
|
+
|
|
3
|
+
describe('registerFrameListener', () => {
|
|
4
|
+
let mockElement
|
|
5
|
+
let mockFrameListeners
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
// Reset mockFrameListeners before each test
|
|
9
|
+
mockFrameListeners = new Set()
|
|
10
|
+
|
|
11
|
+
// Create a mock element with the required structure
|
|
12
|
+
mockElement = {
|
|
13
|
+
__ref: {
|
|
14
|
+
root: {
|
|
15
|
+
data: {
|
|
16
|
+
frameListeners: mockFrameListeners
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('successful cases', () => {
|
|
24
|
+
test('should add element to frameListeners when not already present', () => {
|
|
25
|
+
// Arrange
|
|
26
|
+
expect(mockFrameListeners.size).toBe(0)
|
|
27
|
+
|
|
28
|
+
// Act
|
|
29
|
+
registerFrameListener(mockElement)
|
|
30
|
+
|
|
31
|
+
// Assert
|
|
32
|
+
expect(mockFrameListeners.size).toBe(1)
|
|
33
|
+
expect(mockFrameListeners.has(mockElement)).toBe(true)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('should not add element to frameListeners when already present', () => {
|
|
37
|
+
// Arrange
|
|
38
|
+
mockFrameListeners.add(mockElement)
|
|
39
|
+
expect(mockFrameListeners.size).toBe(1)
|
|
40
|
+
|
|
41
|
+
// Act
|
|
42
|
+
registerFrameListener(mockElement)
|
|
43
|
+
|
|
44
|
+
// Assert
|
|
45
|
+
expect(mockFrameListeners.size).toBe(1)
|
|
46
|
+
expect(mockFrameListeners.has(mockElement)).toBe(true)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('should handle case when frameListeners is undefined', () => {
|
|
50
|
+
// Arrange
|
|
51
|
+
mockElement.__ref.root.data.frameListeners = undefined
|
|
52
|
+
|
|
53
|
+
// Act & Assert
|
|
54
|
+
expect(() => {
|
|
55
|
+
registerFrameListener(mockElement)
|
|
56
|
+
}).not.toThrow()
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe('error cases', () => {
|
|
61
|
+
test('should throw error when element is null', () => {
|
|
62
|
+
expect(() => {
|
|
63
|
+
registerFrameListener(null)
|
|
64
|
+
}).toThrow('Element reference is invalid')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('should throw error when element is undefined', () => {
|
|
68
|
+
expect(() => {
|
|
69
|
+
registerFrameListener(undefined)
|
|
70
|
+
}).toThrow('Element reference is invalid')
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test('should throw error when element.__ref is undefined', () => {
|
|
74
|
+
const invalidElement = {}
|
|
75
|
+
|
|
76
|
+
expect(() => {
|
|
77
|
+
registerFrameListener(invalidElement)
|
|
78
|
+
}).toThrow('Element reference is invalid')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('should throw error when ref.root is undefined', () => {
|
|
82
|
+
mockElement.__ref.root = undefined
|
|
83
|
+
|
|
84
|
+
expect(() => {
|
|
85
|
+
registerFrameListener(mockElement)
|
|
86
|
+
}).toThrow('Root reference is invalid')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test('should throw error when ref.root.data is undefined', () => {
|
|
90
|
+
mockElement.__ref.root.data = undefined
|
|
91
|
+
|
|
92
|
+
expect(() => {
|
|
93
|
+
registerFrameListener(mockElement)
|
|
94
|
+
}).toThrow('Data are undefined')
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
})
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import eventRegistry from '../store'
|
|
2
|
+
|
|
3
|
+
describe('eventRegistry', () => {
|
|
4
|
+
test('should have the correct initial structure', () => {
|
|
5
|
+
expect(eventRegistry).toEqual({
|
|
6
|
+
click: [],
|
|
7
|
+
render: []
|
|
8
|
+
})
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
test('should have empty arrays as initial values', () => {
|
|
12
|
+
expect(Array.isArray(eventRegistry.click)).toBe(true)
|
|
13
|
+
expect(Array.isArray(eventRegistry.render)).toBe(true)
|
|
14
|
+
expect(eventRegistry.click.length).toBe(0)
|
|
15
|
+
expect(eventRegistry.render.length).toBe(0)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('should allow adding items to click array', () => {
|
|
19
|
+
// Arrange
|
|
20
|
+
const clickHandler = () => {}
|
|
21
|
+
|
|
22
|
+
// Act
|
|
23
|
+
eventRegistry.click.push(clickHandler)
|
|
24
|
+
|
|
25
|
+
// Assert
|
|
26
|
+
expect(eventRegistry.click).toContain(clickHandler)
|
|
27
|
+
expect(eventRegistry.click.length).toBe(1)
|
|
28
|
+
|
|
29
|
+
// Cleanup
|
|
30
|
+
eventRegistry.click.length = 0
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('should allow adding items to render array', () => {
|
|
34
|
+
// Arrange
|
|
35
|
+
const renderHandler = () => {}
|
|
36
|
+
|
|
37
|
+
// Act
|
|
38
|
+
eventRegistry.render.push(renderHandler)
|
|
39
|
+
|
|
40
|
+
// Assert
|
|
41
|
+
expect(eventRegistry.render).toContain(renderHandler)
|
|
42
|
+
expect(eventRegistry.render.length).toBe(1)
|
|
43
|
+
|
|
44
|
+
// Cleanup
|
|
45
|
+
eventRegistry.render.length = 0
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('should maintain separate arrays for different events', () => {
|
|
49
|
+
// Arrange
|
|
50
|
+
const clickHandler = () => {}
|
|
51
|
+
const renderHandler = () => {}
|
|
52
|
+
|
|
53
|
+
// Act
|
|
54
|
+
eventRegistry.click.push(clickHandler)
|
|
55
|
+
eventRegistry.render.push(renderHandler)
|
|
56
|
+
|
|
57
|
+
// Assert
|
|
58
|
+
expect(eventRegistry.click).toContain(clickHandler)
|
|
59
|
+
expect(eventRegistry.click).not.toContain(renderHandler)
|
|
60
|
+
expect(eventRegistry.render).toContain(renderHandler)
|
|
61
|
+
expect(eventRegistry.render).not.toContain(clickHandler)
|
|
62
|
+
|
|
63
|
+
// Cleanup
|
|
64
|
+
eventRegistry.click.length = 0
|
|
65
|
+
eventRegistry.render.length = 0
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('should allow array operations on event arrays', () => {
|
|
69
|
+
// Test various array operations
|
|
70
|
+
const handler1 = () => {}
|
|
71
|
+
const handler2 = () => {}
|
|
72
|
+
|
|
73
|
+
// Push
|
|
74
|
+
eventRegistry.click.push(handler1)
|
|
75
|
+
expect(eventRegistry.click).toContain(handler1)
|
|
76
|
+
|
|
77
|
+
// Push multiple
|
|
78
|
+
eventRegistry.click.push(handler2)
|
|
79
|
+
expect(eventRegistry.click).toEqual([handler1, handler2])
|
|
80
|
+
|
|
81
|
+
// Pop
|
|
82
|
+
const popped = eventRegistry.click.pop()
|
|
83
|
+
expect(popped).toBe(handler2)
|
|
84
|
+
expect(eventRegistry.click).toEqual([handler1])
|
|
85
|
+
|
|
86
|
+
// Cleanup
|
|
87
|
+
eventRegistry.click.length = 0
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('should have independent arrays', () => {
|
|
91
|
+
expect(eventRegistry.click).not.toBe(eventRegistry.render)
|
|
92
|
+
})
|
|
93
|
+
})
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
import { triggerEventOn } from '../on'
|
|
3
|
+
|
|
4
|
+
describe('triggerEventOn', () => {
|
|
5
|
+
let mockElement
|
|
6
|
+
let mockEventHandler
|
|
7
|
+
let mockOptions
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
mockEventHandler = jest.fn().mockReturnValue('eventResult')
|
|
11
|
+
mockOptions = { option1: 'value1' }
|
|
12
|
+
|
|
13
|
+
mockElement = {
|
|
14
|
+
state: { elementState: 'test' },
|
|
15
|
+
context: { elementContext: 'test' },
|
|
16
|
+
on: {},
|
|
17
|
+
props: {}
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
describe('event resolution', () => {
|
|
22
|
+
test('should trigger event from on property', () => {
|
|
23
|
+
// Arrange
|
|
24
|
+
mockElement.on.click = mockEventHandler
|
|
25
|
+
|
|
26
|
+
// Act
|
|
27
|
+
const result = triggerEventOn('click', mockElement, mockOptions)
|
|
28
|
+
|
|
29
|
+
// Assert
|
|
30
|
+
expect(result).toBe('eventResult')
|
|
31
|
+
expect(mockEventHandler).toHaveBeenCalledWith(
|
|
32
|
+
mockElement,
|
|
33
|
+
mockElement.state,
|
|
34
|
+
mockElement.context,
|
|
35
|
+
mockOptions
|
|
36
|
+
)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('should trigger event from props using camelCase', () => {
|
|
40
|
+
// Arrange
|
|
41
|
+
mockElement.props.onClick = mockEventHandler
|
|
42
|
+
|
|
43
|
+
// Act
|
|
44
|
+
const result = triggerEventOn('click', mockElement, mockOptions)
|
|
45
|
+
|
|
46
|
+
// Assert
|
|
47
|
+
expect(result).toBe('eventResult')
|
|
48
|
+
expect(mockEventHandler).toHaveBeenCalledWith(
|
|
49
|
+
mockElement,
|
|
50
|
+
mockElement.state,
|
|
51
|
+
mockElement.context,
|
|
52
|
+
mockOptions
|
|
53
|
+
)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('should prioritize on property over props', () => {
|
|
57
|
+
// Arrange
|
|
58
|
+
const onEventHandler = jest.fn().mockReturnValue('onResult')
|
|
59
|
+
const propsEventHandler = jest.fn().mockReturnValue('propsResult')
|
|
60
|
+
|
|
61
|
+
mockElement.on.click = onEventHandler
|
|
62
|
+
mockElement.props.onClick = propsEventHandler
|
|
63
|
+
|
|
64
|
+
// Act
|
|
65
|
+
const result = triggerEventOn('click', mockElement, mockOptions)
|
|
66
|
+
|
|
67
|
+
// Assert
|
|
68
|
+
expect(result).toBe('onResult')
|
|
69
|
+
expect(onEventHandler).toHaveBeenCalled()
|
|
70
|
+
expect(propsEventHandler).not.toHaveBeenCalled()
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
describe('event parameters', () => {
|
|
75
|
+
test('should pass state and context correctly', () => {
|
|
76
|
+
// Arrange
|
|
77
|
+
mockElement.on.click = mockEventHandler
|
|
78
|
+
mockElement.state = { custom: 'state' }
|
|
79
|
+
mockElement.context = { custom: 'context' }
|
|
80
|
+
|
|
81
|
+
// Act
|
|
82
|
+
triggerEventOn('click', mockElement, mockOptions)
|
|
83
|
+
|
|
84
|
+
// Assert
|
|
85
|
+
expect(mockEventHandler).toHaveBeenCalledWith(
|
|
86
|
+
mockElement,
|
|
87
|
+
mockElement.state,
|
|
88
|
+
mockElement.context,
|
|
89
|
+
mockOptions
|
|
90
|
+
)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
test('should handle missing state and context', () => {
|
|
94
|
+
// Arrange
|
|
95
|
+
mockElement = {
|
|
96
|
+
on: { click: mockEventHandler }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Act
|
|
100
|
+
triggerEventOn('click', mockElement, mockOptions)
|
|
101
|
+
|
|
102
|
+
// Assert
|
|
103
|
+
expect(mockEventHandler).toHaveBeenCalledWith(
|
|
104
|
+
mockElement,
|
|
105
|
+
undefined,
|
|
106
|
+
undefined,
|
|
107
|
+
mockOptions
|
|
108
|
+
)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test('should handle missing options', () => {
|
|
112
|
+
// Arrange
|
|
113
|
+
mockElement.on.click = mockEventHandler
|
|
114
|
+
|
|
115
|
+
// Act
|
|
116
|
+
triggerEventOn('click', mockElement)
|
|
117
|
+
|
|
118
|
+
// Assert
|
|
119
|
+
expect(mockEventHandler).toHaveBeenCalledWith(
|
|
120
|
+
mockElement,
|
|
121
|
+
mockElement.state,
|
|
122
|
+
mockElement.context,
|
|
123
|
+
undefined
|
|
124
|
+
)
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
describe('event naming', () => {
|
|
129
|
+
test('should handle various event names correctly', () => {
|
|
130
|
+
const eventTests = [
|
|
131
|
+
{ input: 'mouseenter', prop: 'onMouseenter' },
|
|
132
|
+
{ input: 'mouseleave', prop: 'onMouseleave' },
|
|
133
|
+
{ input: 'submit', prop: 'onSubmit' },
|
|
134
|
+
{ input: 'change', prop: 'onChange' }
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
for (const { input, prop } of eventTests) {
|
|
138
|
+
// Arrange
|
|
139
|
+
mockElement.props[prop] = mockEventHandler
|
|
140
|
+
|
|
141
|
+
// Act
|
|
142
|
+
triggerEventOn(input, mockElement, mockOptions)
|
|
143
|
+
|
|
144
|
+
// Assert
|
|
145
|
+
expect(mockEventHandler).toHaveBeenCalledWith(
|
|
146
|
+
mockElement,
|
|
147
|
+
mockElement.state,
|
|
148
|
+
mockElement.context,
|
|
149
|
+
mockOptions
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
// Reset for next test
|
|
153
|
+
mockElement.props[prop] = undefined
|
|
154
|
+
mockEventHandler.mockClear()
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
describe('edge cases', () => {
|
|
160
|
+
test('should return undefined when no event handler exists', () => {
|
|
161
|
+
// Act
|
|
162
|
+
const result = triggerEventOn('click', mockElement, mockOptions)
|
|
163
|
+
|
|
164
|
+
// Assert
|
|
165
|
+
expect(result).toBeUndefined()
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
test('should handle error thrown in event handler', () => {
|
|
169
|
+
// Arrange
|
|
170
|
+
const error = new Error('Event handler error')
|
|
171
|
+
mockElement.on.click = jest.fn(() => {
|
|
172
|
+
throw error
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
// Act & Assert
|
|
176
|
+
expect(() => triggerEventOn('click', mockElement, mockOptions)).toThrow(
|
|
177
|
+
'Event handler error'
|
|
178
|
+
)
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
test('should handle undefined element', () => {
|
|
182
|
+
// Assert
|
|
183
|
+
expect(() => triggerEventOn('click', undefined, mockOptions)).toThrow(
|
|
184
|
+
'Element is required'
|
|
185
|
+
)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
test('should handle null element', () => {
|
|
189
|
+
// Assert
|
|
190
|
+
expect(() => triggerEventOn('click', null, mockOptions)).toThrow(
|
|
191
|
+
'Element is required'
|
|
192
|
+
)
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
})
|