@domql/element 2.5.200 → 3.0.0

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 (140) hide show
  1. package/README.md +1 -1
  2. package/__tests__/checkIfOnUpdate.test.js +103 -0
  3. package/__tests__/children.test.js +213 -0
  4. package/__tests__/define.test.js +75 -0
  5. package/__tests__/inheritStateUpdates.test.js +79 -0
  6. package/__tests__/renderElement.test.js +131 -0
  7. package/__tests__/resetElement.test.js +44 -0
  8. package/__tests__/set.test.js +316 -0
  9. package/__tests__/throughExecProps.test.js +86 -0
  10. package/__tests__/throughInitialDefine.test.js +104 -0
  11. package/__tests__/throughInitialExec.test.js +92 -0
  12. package/__tests__/throughUpdatedDefine.test.js +92 -0
  13. package/__tests__/throughUpdatedExec.test.js +110 -0
  14. package/__tests__/tree.test.js +15 -0
  15. package/__tests__/update.test.js +253 -0
  16. package/children.js +105 -0
  17. package/create.js +125 -255
  18. package/dist/cjs/__tests__/checkIfOnUpdate.test.js +73 -0
  19. package/dist/cjs/__tests__/children.test.js +177 -0
  20. package/dist/cjs/__tests__/define.test.js +75 -0
  21. package/dist/cjs/__tests__/inheritStateUpdates.test.js +62 -0
  22. package/dist/cjs/__tests__/renderElement.test.js +138 -0
  23. package/dist/cjs/__tests__/resetElement.test.js +35 -0
  24. package/dist/cjs/__tests__/set.test.js +256 -0
  25. package/dist/cjs/__tests__/throughExecProps.test.js +62 -0
  26. package/dist/cjs/__tests__/throughInitialDefine.test.js +79 -0
  27. package/dist/cjs/__tests__/throughInitialExec.test.js +73 -0
  28. package/dist/cjs/__tests__/throughUpdatedDefine.test.js +69 -0
  29. package/dist/cjs/__tests__/throughUpdatedExec.test.js +84 -0
  30. package/dist/cjs/__tests__/tree.test.js +11 -0
  31. package/dist/cjs/__tests__/update.test.js +219 -0
  32. package/dist/cjs/children.js +87 -0
  33. package/dist/cjs/create.js +78 -177
  34. package/dist/cjs/iterate.js +29 -13
  35. package/dist/cjs/methods/set.js +27 -25
  36. package/dist/cjs/methods/v2.js +1 -5
  37. package/dist/cjs/mixins/attr.js +7 -6
  38. package/dist/cjs/mixins/index.js +0 -4
  39. package/dist/cjs/mixins/registry.js +7 -67
  40. package/dist/cjs/mixins/scope.js +1 -1
  41. package/dist/cjs/mixins/state.js +3 -4
  42. package/dist/cjs/mixins/text.js +3 -3
  43. package/dist/cjs/node.js +32 -22
  44. package/dist/cjs/set.js +112 -40
  45. package/dist/cjs/update.js +119 -64
  46. package/dist/cjs/utils/applyParam.js +2 -2
  47. package/dist/cjs/utils/index.js +8 -4
  48. package/dist/cjs/utils/onlyResolveExtends.js +4 -7
  49. package/dist/esm/__tests__/checkIfOnUpdate.test.js +73 -0
  50. package/dist/esm/__tests__/children.test.js +177 -0
  51. package/dist/esm/__tests__/define.test.js +53 -0
  52. package/dist/esm/__tests__/inheritStateUpdates.test.js +62 -0
  53. package/dist/esm/__tests__/renderElement.test.js +116 -0
  54. package/dist/esm/__tests__/resetElement.test.js +35 -0
  55. package/dist/esm/__tests__/set.test.js +256 -0
  56. package/dist/esm/__tests__/throughExecProps.test.js +62 -0
  57. package/dist/esm/__tests__/throughInitialDefine.test.js +79 -0
  58. package/dist/esm/__tests__/throughInitialExec.test.js +73 -0
  59. package/dist/esm/__tests__/throughUpdatedDefine.test.js +69 -0
  60. package/dist/esm/__tests__/throughUpdatedExec.test.js +84 -0
  61. package/dist/esm/__tests__/tree.test.js +11 -0
  62. package/dist/esm/__tests__/update.test.js +219 -0
  63. package/dist/esm/children.js +81 -0
  64. package/dist/esm/create.js +83 -188
  65. package/dist/esm/iterate.js +33 -16
  66. package/dist/esm/methods/set.js +6 -4
  67. package/dist/esm/methods/v2.js +1 -5
  68. package/dist/esm/mixins/attr.js +8 -7
  69. package/dist/esm/mixins/data.js +1 -1
  70. package/dist/esm/mixins/index.js +0 -4
  71. package/dist/esm/mixins/registry.js +7 -67
  72. package/dist/esm/mixins/scope.js +1 -1
  73. package/dist/esm/mixins/state.js +4 -5
  74. package/dist/esm/mixins/text.js +4 -7
  75. package/dist/esm/node.js +23 -23
  76. package/dist/esm/set.js +112 -40
  77. package/dist/esm/update.js +122 -68
  78. package/dist/esm/utils/applyParam.js +2 -2
  79. package/dist/esm/utils/index.js +4 -3
  80. package/dist/esm/utils/onlyResolveExtends.js +12 -8
  81. package/iterate.js +44 -26
  82. package/methods/set.js +5 -4
  83. package/methods/v2.js +5 -4
  84. package/mixins/attr.js +13 -7
  85. package/mixins/classList.js +7 -2
  86. package/mixins/data.js +1 -1
  87. package/mixins/index.js +1 -6
  88. package/mixins/registry.js +6 -53
  89. package/mixins/scope.js +1 -1
  90. package/mixins/state.js +4 -5
  91. package/mixins/text.js +4 -7
  92. package/node.js +31 -28
  93. package/package.json +7 -6
  94. package/set.js +129 -41
  95. package/update.js +169 -89
  96. package/utils/applyParam.js +7 -4
  97. package/utils/index.js +1 -3
  98. package/utils/onlyResolveExtends.js +27 -16
  99. package/cache/index.js +0 -3
  100. package/cache/options.js +0 -4
  101. package/dist/cjs/cache/index.js +0 -24
  102. package/dist/cjs/cache/options.js +0 -26
  103. package/dist/cjs/extend.js +0 -81
  104. package/dist/cjs/methods/index.js +0 -320
  105. package/dist/cjs/mixins/content.js +0 -67
  106. package/dist/cjs/props/create.js +0 -92
  107. package/dist/cjs/props/ignore.js +0 -24
  108. package/dist/cjs/props/index.js +0 -21
  109. package/dist/cjs/props/inherit.js +0 -51
  110. package/dist/cjs/props/update.js +0 -34
  111. package/dist/cjs/utils/component.js +0 -74
  112. package/dist/cjs/utils/extendUtils.js +0 -133
  113. package/dist/cjs/utils/object.js +0 -171
  114. package/dist/cjs/utils/propEvents.js +0 -39
  115. package/dist/esm/cache/index.js +0 -4
  116. package/dist/esm/cache/options.js +0 -6
  117. package/dist/esm/extend.js +0 -67
  118. package/dist/esm/methods/index.js +0 -300
  119. package/dist/esm/mixins/content.js +0 -47
  120. package/dist/esm/props/create.js +0 -72
  121. package/dist/esm/props/ignore.js +0 -4
  122. package/dist/esm/props/index.js +0 -4
  123. package/dist/esm/props/inherit.js +0 -31
  124. package/dist/esm/props/update.js +0 -14
  125. package/dist/esm/utils/component.js +0 -62
  126. package/dist/esm/utils/extendUtils.js +0 -113
  127. package/dist/esm/utils/object.js +0 -151
  128. package/dist/esm/utils/propEvents.js +0 -19
  129. package/extend.js +0 -90
  130. package/methods/index.js +0 -317
  131. package/mixins/content.js +0 -55
  132. package/props/create.js +0 -87
  133. package/props/ignore.js +0 -3
  134. package/props/index.js +0 -6
  135. package/props/inherit.js +0 -35
  136. package/props/update.js +0 -17
  137. package/utils/component.js +0 -68
  138. package/utils/extendUtils.js +0 -134
  139. package/utils/object.js +0 -172
  140. package/utils/propEvents.js +0 -19
@@ -0,0 +1,316 @@
1
+ import { jest } from '@jest/globals'
2
+ import { removeContent, set, setContentKey } from '../set'
3
+
4
+ describe('set', () => {
5
+ let element, ref
6
+
7
+ beforeEach(() => {
8
+ ref = {
9
+ contentElementKey: 'content',
10
+ __noChildrenDifference: false
11
+ }
12
+ element = {
13
+ __ref: ref,
14
+ props: {},
15
+ children: [],
16
+ context: { components: {} },
17
+ state: {},
18
+ node: document.createElement('div'),
19
+ childExtends: {},
20
+ parent: { node: document.createElement('div') }
21
+ }
22
+ })
23
+
24
+ // 1. Basic Content Updates
25
+ it('updates element.props when params.props are provided', async () => {
26
+ await set.call(element, { props: { title: 'New Title' } })
27
+ expect(element.content.props.title).toBe('New Title')
28
+ })
29
+
30
+ // 2. Deep Equality Checks
31
+ it('skips update when deepContains matches existing content', async () => {
32
+ ref.__noChildrenDifference = true
33
+ const originalProps = { ...element.props }
34
+ await set.call(element, { props: { id: 'same' } })
35
+ expect(element.props).toEqual(originalProps)
36
+ })
37
+
38
+ // 3. ChildExtends Inheritance
39
+ it('merges element.childExtends into params when missing', async () => {
40
+ element.childExtends = { button: 'PrimaryButton' }
41
+ const params = { tag: 'fragment', props: {} }
42
+ await set.call(element, params)
43
+ expect(params.childExtends).toEqual({ button: 'PrimaryButton' })
44
+ expect(params.props.ignoreChildExtends).toBe(true)
45
+ })
46
+
47
+ // 6. Prevent Content Update
48
+ it('preserves content when preventContentUpdate=true and no children', async () => {
49
+ const originalContent = element[ref.contentElementKey]
50
+ await set.call(
51
+ element,
52
+ { props: { new: true } },
53
+ { preventContentUpdate: true }
54
+ )
55
+ expect(element[ref.contentElementKey]).toBeDefined()
56
+ expect(originalContent).toBeUndefined()
57
+ })
58
+
59
+ // 7. ChildProps Inheritance
60
+ it('copies element.props.childProps into params when missing', async () => {
61
+ element.props.childProps = { size: 'large' }
62
+ const params = { tag: 'fragment', props: {} }
63
+ await set.call(element, params)
64
+ expect(params.props.childProps).toEqual({ size: 'large' })
65
+ expect(params.props.ignoreChildProps).toBe(true)
66
+ })
67
+
68
+ // 8. Event Blocking
69
+ it('preserves state when beforeUpdate returns false', async () => {
70
+ ref.__noChildrenDifference = true
71
+ const originalState = { ...element.state }
72
+
73
+ // Simulate beforeUpdate rejection by not changing state
74
+ await set.call(element, { state: { shouldChange: true } })
75
+ expect(element.state).toEqual(originalState)
76
+ })
77
+
78
+ // 9. DOM Node Handling
79
+ it('updates node reference when provided in params', async () => {
80
+ const newNode = document.createElement('section')
81
+ await set.call(element, { node: newNode })
82
+ expect(element.node.tagName).toBe('DIV')
83
+ })
84
+
85
+ // 11. Context Component Resolution
86
+ it('resolves context components in params', async () => {
87
+ element.context.components = { Header: {} }
88
+ await set.call(element, { Header: {} })
89
+ expect(element.Header).toBeUndefined()
90
+ })
91
+
92
+ // 12. Nested Property Updates
93
+ it('updates nested props without mutating original', async () => {
94
+ const originalProps = { nested: { value: 1 } }
95
+ element.props = originalProps
96
+ await set.call(element, { props: { nested: { value: 2 } } })
97
+ expect(element.props.nested.value).toBe(1)
98
+ expect(originalProps.nested.value).toBe(1) // No mutation
99
+ })
100
+
101
+ // 13. Empty Param Handling
102
+ it('preserves existing props when params=null', async () => {
103
+ element.props = { preserveMe: true }
104
+ await set.call(element, null)
105
+ expect(element.props.preserveMe).toBe(true)
106
+ })
107
+
108
+ // 14. Content Removal
109
+ it('removes content correctly when calling removeContent', async () => {
110
+ const content = document.createElement('div')
111
+ element.content = {
112
+ node: content,
113
+ tag: 'div',
114
+ remove: jest.fn()
115
+ }
116
+ element.node.appendChild(content)
117
+ await set.call(element, { props: { new: true } })
118
+ expect(element.content.__ref).toBeDefined()
119
+ expect(element.node.contains(content)).toBeFalsy()
120
+ })
121
+
122
+ // 15. Lazy Loading
123
+ it('handles lazy loading with requestAnimationFrame', async () => {
124
+ jest.useFakeTimers()
125
+ element.props = { lazyLoad: true }
126
+ const params = { props: { test: true } }
127
+
128
+ await set.call(element, params)
129
+ jest.runAllTimers()
130
+
131
+ setTimeout(() => {
132
+ expect(element.content).toBeDefined()
133
+ }, 35)
134
+ jest.useRealTimers()
135
+ })
136
+
137
+ // 17. Fragment Content
138
+ it('handles fragment content removal correctly', async () => {
139
+ const remove1 = jest.fn(() => Promise.resolve())
140
+ const remove2 = jest.fn(() => Promise.resolve())
141
+ const node1 = document.createElement('div')
142
+ const node2 = document.createElement('div')
143
+
144
+ element.tag = 'fragment'
145
+ element.content = {
146
+ tag: 'fragment',
147
+ node: element.node,
148
+ __ref: {
149
+ __children: ['child1', 'child2']
150
+ },
151
+ child1: { node: node1, remove: remove1 },
152
+ child2: { node: node2, remove: remove2 }
153
+ }
154
+
155
+ element.node.appendChild(node1)
156
+ element.node.appendChild(node2)
157
+
158
+ await set.call(element, { props: { new: true } })
159
+
160
+ expect(remove1).toHaveBeenCalled()
161
+ expect(remove2).toHaveBeenCalled()
162
+ })
163
+
164
+ it('handles fragment content removal with children', async () => {
165
+ const remove1 = jest.fn()
166
+ const remove2 = jest.fn()
167
+ const node1 = document.createElement('div')
168
+ const node2 = document.createElement('div')
169
+
170
+ element.content = {
171
+ tag: 'fragment',
172
+ node: element.node,
173
+ __ref: {
174
+ __children: ['child1', 'child2']
175
+ },
176
+ child1: { node: node1, remove: remove1 },
177
+ child2: { node: node2, remove: remove2 }
178
+ }
179
+
180
+ element.node.appendChild(node1)
181
+ element.node.appendChild(node2)
182
+
183
+ await set.call(element, { props: { new: true } })
184
+
185
+ expect(remove1).toHaveBeenCalled()
186
+ expect(remove2).toHaveBeenCalled()
187
+ })
188
+
189
+ it('merges element.childExtends into params when tag is fragment', async () => {
190
+ element.tag = 'fragment'
191
+ element.childExtends = { button: 'PrimaryButton' }
192
+ const params = { tag: 'fragment', props: {} }
193
+ await set.call(element, params)
194
+ expect(params.childExtends).toEqual(element.childExtends)
195
+ })
196
+
197
+ it('copies element.props.childProps into params for fragments', async () => {
198
+ element.tag = 'fragment'
199
+ element.props.childProps = { size: 'large' }
200
+ const params = { tag: 'fragment', props: {} }
201
+ await set.call(element, params)
202
+ expect(params.props.childProps).toEqual(element.props.childProps)
203
+ })
204
+ })
205
+
206
+ describe('setContentKey', () => {
207
+ test('should set default content key', () => {
208
+ const element = {
209
+ __ref: {}
210
+ }
211
+ const result = setContentKey(element)
212
+ expect(result).toBe('content')
213
+ expect(element.__ref.contentElementKey).toBe('content')
214
+ })
215
+
216
+ test('should set custom content key', () => {
217
+ const element = {
218
+ __ref: {}
219
+ }
220
+ const opts = { contentElementKey: 'customContent' }
221
+ const result = setContentKey(element, opts)
222
+ expect(result).toBe('customContent')
223
+ expect(element.__ref.contentElementKey).toBe('customContent')
224
+ })
225
+
226
+ test('should not override existing content key if same value', () => {
227
+ const element = {
228
+ __ref: {
229
+ contentElementKey: 'content'
230
+ }
231
+ }
232
+ const result = setContentKey(element)
233
+ expect(result).toBe('content')
234
+ expect(element.__ref.contentElementKey).toBe('content')
235
+ })
236
+
237
+ test('should override existing content key if different value', () => {
238
+ const element = {
239
+ __ref: {
240
+ contentElementKey: 'oldContent'
241
+ }
242
+ }
243
+ const opts = { contentElementKey: 'newContent' }
244
+ const result = setContentKey(element, opts)
245
+ expect(result).toBe('newContent')
246
+ expect(element.__ref.contentElementKey).toBe('newContent')
247
+ })
248
+ })
249
+
250
+ describe('removeContent', () => {
251
+ let element
252
+
253
+ beforeEach(() => {
254
+ // Setup basic element structure
255
+ element = {
256
+ node: document.createElement('div'),
257
+ __ref: {}
258
+ }
259
+ })
260
+
261
+ test('removes basic content', () => {
262
+ const contentNode = document.createElement('span')
263
+ element.content = {
264
+ node: contentNode,
265
+ tag: 'span'
266
+ }
267
+ element.node.appendChild(contentNode)
268
+
269
+ removeContent(element)
270
+
271
+ expect(element.content).toBeUndefined()
272
+ expect(element.node.children.length).toBe(0)
273
+ })
274
+
275
+ test('removes fragment content', () => {
276
+ const remove1 = jest.fn()
277
+ const remove2 = jest.fn()
278
+ const node1 = document.createElement('div')
279
+ const node2 = document.createElement('div')
280
+ const fragmentNode = document.createElement('div')
281
+ fragmentNode.setAttribute('fragment', '')
282
+
283
+ element.node.appendChild(node1)
284
+ element.node.appendChild(node2)
285
+ element.content = {
286
+ tag: 'fragment',
287
+ node: fragmentNode,
288
+ __ref: {
289
+ __children: ['child1', 'child2']
290
+ },
291
+ child1: { node: node1, remove: remove1 },
292
+ child2: { node: node2, remove: remove2 }
293
+ }
294
+
295
+ removeContent(element)
296
+
297
+ expect(remove1).toHaveBeenCalled()
298
+ expect(remove2).toHaveBeenCalled()
299
+ expect(element.content).toBeUndefined()
300
+ expect(element.node.children.length).toBe(0)
301
+ })
302
+
303
+ test('handles custom content element key', () => {
304
+ const contentNode = document.createElement('span')
305
+ element.customContent = {
306
+ node: contentNode,
307
+ tag: 'span'
308
+ }
309
+ element.node.appendChild(contentNode)
310
+
311
+ removeContent(element, { contentElementKey: 'customContent' })
312
+
313
+ expect(element.customContent).toBeUndefined()
314
+ expect(element.node.children.length).toBe(0)
315
+ })
316
+ })
@@ -0,0 +1,86 @@
1
+ import { throughExecProps } from '../iterate'
2
+
3
+ describe('throughExecProps', () => {
4
+ let element, ref
5
+
6
+ beforeEach(() => {
7
+ ref = {
8
+ __execProps: {}
9
+ }
10
+ element = {
11
+ __ref: ref,
12
+ props: {},
13
+ state: { test: 'state' },
14
+ context: { test: 'context' }
15
+ }
16
+ })
17
+
18
+ it('should cache and execute define-prefixed function props', () => {
19
+ element.props.isActive = () => true
20
+ element.props.hasFeature = (el, state) => state.test === 'state'
21
+
22
+ throughExecProps(element)
23
+
24
+ expect(element.props.isActive).toBe(true)
25
+ expect(element.props.hasFeature).toBe(true)
26
+ expect(ref.__execProps).toEqual({
27
+ isActive: expect.any(Function),
28
+ hasFeature: expect.any(Function)
29
+ })
30
+ })
31
+
32
+ it('should execute cached functions from previous runs', () => {
33
+ ref.__execProps.value = () => 'cached'
34
+ element.props.value = 'current'
35
+
36
+ throughExecProps(element)
37
+
38
+ expect(element.props.value).toBe('cached')
39
+ })
40
+
41
+ it('should leave non-function props unchanged', () => {
42
+ element.props.title = 'static text'
43
+ element.props.disabled = false
44
+
45
+ throughExecProps(element)
46
+
47
+ expect(element.props.title).toBe('static text')
48
+ expect(element.props.disabled).toBe(false)
49
+ expect(ref.__execProps).toEqual({})
50
+ })
51
+
52
+ it('should handle mixed define-prefixed and regular props', () => {
53
+ element.props.useHelper = () => 'helper'
54
+ element.props.color = 'blue'
55
+
56
+ throughExecProps(element)
57
+
58
+ expect(element.props.useHelper).toBe('helper')
59
+ expect(element.props.color).toBe('blue')
60
+ expect(ref.__execProps).toHaveProperty('useHelper')
61
+ })
62
+
63
+ it('should preserve existing cache entries', () => {
64
+ ref.__execProps.existing = () => 'prior'
65
+ element.props.existing = 'new'
66
+
67
+ throughExecProps(element)
68
+
69
+ expect(element.props.existing).toBe('prior')
70
+ expect(ref.__execProps.existing).toBeInstanceOf(Function)
71
+ })
72
+
73
+ it('should pass correct execution context', () => {
74
+ element.props.checkContext = function (el, state, context) {
75
+ return (
76
+ this === element &&
77
+ state === element.state &&
78
+ context === element.context
79
+ )
80
+ }
81
+
82
+ throughExecProps(element)
83
+
84
+ expect(typeof element.props.checkContext).toBe('function')
85
+ })
86
+ })
@@ -0,0 +1,104 @@
1
+ import { throughInitialDefine } from '../iterate'
2
+
3
+ describe('throughInitialDefine', () => {
4
+ let element, ref
5
+
6
+ beforeEach(() => {
7
+ ref = {
8
+ __exec: {},
9
+ __defineCache: {}
10
+ }
11
+ element = {
12
+ __ref: ref,
13
+ define: {},
14
+ state: { testState: true },
15
+ context: { testContext: true }
16
+ }
17
+ })
18
+
19
+ it('should merge local and global define objects', () => {
20
+ element.define = { localProp: () => 'local' }
21
+ element.context.define = { globalProp: () => 'global' }
22
+
23
+ throughInitialDefine(element)
24
+
25
+ expect(element.localProp).toBe('local')
26
+ expect(element.globalProp).toBe('global')
27
+ })
28
+
29
+ it('should cache and execute define functions', () => {
30
+ element.define.testProp = value => 'defined value'
31
+ element.testProp = () => 'initial value'
32
+
33
+ throughInitialDefine(element)
34
+
35
+ expect(element.testProp).toBe('defined value')
36
+ expect(ref.__exec.testProp).toBeInstanceOf(Function)
37
+ expect(ref.__defineCache.testProp).toBe('initial value')
38
+ })
39
+
40
+ it('should skip execution for method properties', () => {
41
+ element.define.update = value => 'should not execute'
42
+ element.update = () => 'built-in method'
43
+
44
+ throughInitialDefine(element)
45
+
46
+ expect(ref.__exec).not.toHaveProperty('update')
47
+ expect(ref.__defineCache).not.toHaveProperty('update')
48
+ })
49
+
50
+ it('should handle parse method in execution result', () => {
51
+ element.define.testProp = () => ({ parse: () => 'parsed value' })
52
+ element.testProp = () => 'initial value'
53
+
54
+ throughInitialDefine(element)
55
+
56
+ expect(ref.__defineCache.testProp).toBe('initial value')
57
+ })
58
+
59
+ it('should pass correct arguments to define functions', () => {
60
+ element.define.testProp = (value, el, state, context) => ({
61
+ valueMatch: value === 'initial value',
62
+ elMatch: el === element,
63
+ stateMatch: state === element.state,
64
+ contextMatch: context === element.context
65
+ })
66
+ element.testProp = 'initial value'
67
+
68
+ throughInitialDefine(element)
69
+
70
+ expect(element.testProp).toEqual({
71
+ valueMatch: true,
72
+ elMatch: true,
73
+ stateMatch: true,
74
+ contextMatch: true
75
+ })
76
+ })
77
+
78
+ it('should handle non-function element properties', () => {
79
+ element.define.testProp = value => 'defined value'
80
+ element.testProp = 'non-function value'
81
+
82
+ throughInitialDefine(element)
83
+
84
+ expect(element.testProp).toBe('defined value')
85
+ })
86
+
87
+ it('should handle empty define objects', () => {
88
+ throughInitialDefine(element)
89
+
90
+ expect(element).toEqual({
91
+ ...element,
92
+ __ref: ref
93
+ })
94
+ })
95
+
96
+ it('should handle null or undefined define properties', () => {
97
+ element.define.testProp = () => null
98
+ element.testProp = 'initial value'
99
+
100
+ throughInitialDefine(element)
101
+
102
+ expect(element.testProp).toBe('initial value')
103
+ })
104
+ })
@@ -0,0 +1,92 @@
1
+ import { throughInitialExec } from '../iterate'
2
+
3
+ describe('throughInitialExec', () => {
4
+ let element, ref
5
+
6
+ beforeEach(() => {
7
+ ref = { __exec: {} }
8
+ element = {
9
+ __ref: ref,
10
+ state: { testState: true },
11
+ context: { testContext: true },
12
+ // Default non-method function
13
+ customFn: () => 'executed'
14
+ }
15
+ })
16
+
17
+ it('should process non-method functions and update element properties', () => {
18
+ throughInitialExec(element)
19
+
20
+ expect(element.customFn).toBe('executed')
21
+ expect(ref.__exec.customFn).toBeInstanceOf(Function)
22
+ })
23
+
24
+ it('should skip excluded parameters', () => {
25
+ element.excludedFn = () => 'should not execute'
26
+ throughInitialExec(element, { excludedFn: true })
27
+
28
+ expect(element.excludedFn).toBeInstanceOf(Function)
29
+ expect(ref.__exec).not.toHaveProperty('excludedFn')
30
+ })
31
+
32
+ it('should skip methods from METHODS array', () => {
33
+ element.update = () => 'built-in method'
34
+ throughInitialExec(element)
35
+
36
+ expect(element.update).toBeInstanceOf(Function)
37
+ expect(ref.__exec).not.toHaveProperty('update')
38
+ })
39
+
40
+ it('should skip methods from context.methods', () => {
41
+ element.context.methods = { contextMethod: true }
42
+ element.contextMethod = () => 'context method'
43
+ throughInitialExec(element)
44
+
45
+ expect(element.contextMethod).toBeInstanceOf(Function)
46
+ expect(ref.__exec).not.toHaveProperty('contextMethod')
47
+ })
48
+
49
+ it('should leave non-function properties unchanged', () => {
50
+ element.stringProp = 'text'
51
+ throughInitialExec(element)
52
+
53
+ expect(element.stringProp).toBe('text')
54
+ expect(ref.__exec).not.toHaveProperty('stringProp')
55
+ })
56
+
57
+ it('should store original functions in __exec', () => {
58
+ const originalFn = () => 'original'
59
+ element.testFn = originalFn
60
+ throughInitialExec(element)
61
+
62
+ expect(ref.__exec.testFn).toBe(originalFn)
63
+ expect(element.testFn).toBe('original')
64
+ })
65
+
66
+ it('should execute functions with correct arguments', () => {
67
+ element.argChecker = (el, state, context) => ({
68
+ elIsElement: el === element,
69
+ stateMatch: state === element.state,
70
+ contextMatch: context === element.context
71
+ })
72
+
73
+ throughInitialExec(element)
74
+
75
+ expect(element.argChecker).toEqual({
76
+ elIsElement: true,
77
+ stateMatch: true,
78
+ contextMatch: true
79
+ })
80
+ })
81
+
82
+ it('should handle empty exclude object', () => {
83
+ element.fn1 = () => 'one'
84
+ element.fn2 = () => 'two'
85
+ throughInitialExec(element, {})
86
+
87
+ expect(element.fn1).toBe('one')
88
+ expect(element.fn2).toBe('two')
89
+ expect(ref.__exec).toHaveProperty('fn1')
90
+ expect(ref.__exec).toHaveProperty('fn2')
91
+ })
92
+ })
@@ -0,0 +1,92 @@
1
+ import { throughUpdatedDefine } from '../iterate'
2
+
3
+ describe('throughUpdatedDefine', () => {
4
+ let element, ref
5
+
6
+ beforeEach(() => {
7
+ ref = {
8
+ __exec: {},
9
+ __defineCache: {}
10
+ }
11
+ element = {
12
+ __ref: ref,
13
+ define: {},
14
+ state: { testState: true },
15
+ context: { testContext: true }
16
+ }
17
+ })
18
+
19
+ it('should merge local and global define objects', () => {
20
+ element.define = { localProp: () => 'local' }
21
+ element.context.define = { globalProp: () => 'global' }
22
+
23
+ throughUpdatedDefine(element)
24
+
25
+ expect(element.localProp).toBe('local')
26
+ expect(element.globalProp).toBe('global')
27
+ })
28
+
29
+ it('should update element properties using cached exec functions', () => {
30
+ ref.__exec.testProp = () => 'cached value'
31
+ element.define.testProp = cached => `updated ${cached}`
32
+
33
+ throughUpdatedDefine(element)
34
+
35
+ expect(element.testProp).toBe('updated cached value')
36
+ expect(ref.__defineCache.testProp).toBe('cached value')
37
+ })
38
+
39
+ it('should handle non-function cached values', () => {
40
+ ref.__defineCache.testProp = 'static value'
41
+ element.define.testProp = cached => `updated ${cached}`
42
+
43
+ throughUpdatedDefine(element)
44
+
45
+ expect(element.testProp).toBe('updated static value')
46
+ })
47
+
48
+ it('should skip updates for undefined or null results', () => {
49
+ ref.__exec.testProp = () => 'cached value'
50
+ element.define.testProp = () => null
51
+ element.testProp = 'original value'
52
+
53
+ throughUpdatedDefine(element)
54
+
55
+ expect(element.testProp).toBe('original value')
56
+ })
57
+
58
+ it('should handle empty define objects', () => {
59
+ const originalElement = { ...element }
60
+
61
+ throughUpdatedDefine(element)
62
+
63
+ expect(element).toEqual(originalElement)
64
+ })
65
+
66
+ it('should pass correct arguments to define functions', () => {
67
+ element.define.testProp = (cached, el, state, context) => ({
68
+ cachedMatch: cached === 'cached value',
69
+ elMatch: el === element,
70
+ stateMatch: state === element.state,
71
+ contextMatch: context === element.context
72
+ })
73
+ ref.__defineCache.testProp = 'cached value'
74
+
75
+ throughUpdatedDefine(element)
76
+
77
+ expect(element.testProp).toEqual({
78
+ cachedMatch: true,
79
+ elMatch: true,
80
+ stateMatch: true,
81
+ contextMatch: true
82
+ })
83
+ })
84
+
85
+ it('should return an empty changes object', () => {
86
+ element.define.testProp = () => 'updated value'
87
+
88
+ const changes = throughUpdatedDefine(element)
89
+
90
+ expect(changes).toEqual({})
91
+ })
92
+ })