glass-easel 0.2.0 → 0.3.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 (197) hide show
  1. package/.eslintignore +4 -0
  2. package/dist/glass_easel.all.js +2 -2
  3. package/dist/glass_easel.all.js.map +1 -1
  4. package/dist/glass_easel.d.ts +2546 -0
  5. package/dist/glass_easel.domlike.global.js +2 -2
  6. package/dist/glass_easel.domlike.global.js.map +1 -1
  7. package/guide/zh_CN/appendix/backend_protocol.md +164 -74
  8. package/jest.unit.config.js +7 -4
  9. package/package.json +7 -5
  10. package/rollup.config.ts +101 -0
  11. package/src/backend/backend_protocol.ts +26 -345
  12. package/src/backend/composed_backend_protocol.ts +10 -264
  13. package/src/backend/current_window_backend_context.ts +478 -0
  14. package/src/backend/domlike_backend_protocol.ts +9 -498
  15. package/src/backend/empty_backend.ts +265 -0
  16. package/src/backend/empty_composed_backend.ts +245 -0
  17. package/src/backend/index.ts +18 -0
  18. package/src/backend/suggested_backend_protocol.ts +62 -11
  19. package/src/behavior.ts +131 -442
  20. package/src/class_list.ts +328 -222
  21. package/src/component.ts +349 -184
  22. package/src/component_params.ts +54 -25
  23. package/src/component_space.ts +36 -15
  24. package/src/data_path.ts +22 -34
  25. package/src/data_proxy.ts +334 -27
  26. package/src/devtool.ts +89 -0
  27. package/src/element.ts +667 -285
  28. package/src/element_iterator.ts +9 -4
  29. package/src/event.ts +39 -20
  30. package/src/external_shadow_tree.ts +2 -2
  31. package/src/func_arr.ts +55 -101
  32. package/src/global_options.ts +18 -42
  33. package/src/index.ts +72 -73
  34. package/src/mutation_observer.ts +10 -7
  35. package/src/native_node.ts +79 -35
  36. package/src/node.ts +23 -30
  37. package/src/relation.ts +101 -12
  38. package/src/render.ts +5 -3
  39. package/src/selector.ts +9 -7
  40. package/src/shadow_root.ts +96 -240
  41. package/src/template_engine.ts +10 -7
  42. package/src/text_node.ts +43 -19
  43. package/src/tmpl/index.ts +38 -30
  44. package/src/tmpl/native_rendering.ts +14 -21
  45. package/src/tmpl/proc_gen_wrapper.ts +189 -151
  46. package/src/tmpl/proc_gen_wrapper_dom.ts +10 -8
  47. package/src/tmpl/range_list_diff.ts +30 -9
  48. package/src/trait_behaviors.ts +1 -1
  49. package/src/type_symbol.ts +36 -0
  50. package/src/virtual_node.ts +26 -13
  51. package/src/warning.ts +119 -0
  52. package/tests/base/composed_backend.ts +143 -142
  53. package/tests/base/env.ts +76 -3
  54. package/tests/base/match.ts +24 -22
  55. package/tests/base/shadow_backend.ts +917 -0
  56. package/tests/core/backend.test.ts +53 -1
  57. package/tests/core/behavior.test.ts +1 -1
  58. package/tests/core/data_update.test.ts +135 -0
  59. package/tests/core/misc.test.ts +91 -21
  60. package/tests/core/placeholder.test.ts +66 -25
  61. package/tests/core/slot.test.ts +161 -23
  62. package/tests/legacy/component.test.js +152 -78
  63. package/tests/legacy/data_path.test.js +19 -19
  64. package/tests/legacy/data_proxy.test.js +14 -7
  65. package/tests/legacy/external.test.js +8 -8
  66. package/tests/legacy/mutation_observer.test.js +7 -5
  67. package/tests/legacy/slot.test.js +2 -3
  68. package/tests/legacy/virtual.test.js +258 -25
  69. package/tests/tmpl/binding_map.test.ts +201 -195
  70. package/tests/tmpl/event.test.ts +138 -23
  71. package/tests/tmpl/expression.test.ts +15 -15
  72. package/tests/tmpl/lvalue.test.ts +101 -0
  73. package/tests/tmpl/structure.test.ts +486 -43
  74. package/tests/types/chaining.test.ts +27 -30
  75. package/tests/types/createElement.test.ts +5 -4
  76. package/tests/types/definition.test.ts +11 -14
  77. package/tsconfig.json +1 -3
  78. package/dist/glass_easel.all.d.ts +0 -1
  79. package/dist/glass_easel.domlike.global.d.ts +0 -1
  80. package/dist/index.d.ts +0 -1
  81. package/dist/index.js +0 -1
  82. package/dist/types/src/backend/backend_protocol.d.ts +0 -141
  83. package/dist/types/src/backend/backend_protocol.d.ts.map +0 -1
  84. package/dist/types/src/backend/composed_backend_protocol.d.ts +0 -102
  85. package/dist/types/src/backend/composed_backend_protocol.d.ts.map +0 -1
  86. package/dist/types/src/backend/domlike_backend_protocol.d.ts +0 -100
  87. package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +0 -1
  88. package/dist/types/src/backend/mode.d.ts +0 -65
  89. package/dist/types/src/backend/mode.d.ts.map +0 -1
  90. package/dist/types/src/backend/suggested_backend_protocol.d.ts +0 -30
  91. package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +0 -1
  92. package/dist/types/src/behavior.d.ts +0 -434
  93. package/dist/types/src/behavior.d.ts.map +0 -1
  94. package/dist/types/src/class_list.d.ts +0 -83
  95. package/dist/types/src/class_list.d.ts.map +0 -1
  96. package/dist/types/src/component.d.ts +0 -325
  97. package/dist/types/src/component.d.ts.map +0 -1
  98. package/dist/types/src/component_params.d.ts +0 -236
  99. package/dist/types/src/component_params.d.ts.map +0 -1
  100. package/dist/types/src/component_space.d.ts +0 -211
  101. package/dist/types/src/component_space.d.ts.map +0 -1
  102. package/dist/types/src/data_path.d.ts +0 -5
  103. package/dist/types/src/data_path.d.ts.map +0 -1
  104. package/dist/types/src/data_proxy.d.ts +0 -107
  105. package/dist/types/src/data_proxy.d.ts.map +0 -1
  106. package/dist/types/src/data_utils.d.ts +0 -3
  107. package/dist/types/src/data_utils.d.ts.map +0 -1
  108. package/dist/types/src/element.d.ts +0 -365
  109. package/dist/types/src/element.d.ts.map +0 -1
  110. package/dist/types/src/element_iterator.d.ts +0 -43
  111. package/dist/types/src/element_iterator.d.ts.map +0 -1
  112. package/dist/types/src/event.d.ts +0 -105
  113. package/dist/types/src/event.d.ts.map +0 -1
  114. package/dist/types/src/external_shadow_tree.d.ts +0 -20
  115. package/dist/types/src/external_shadow_tree.d.ts.map +0 -1
  116. package/dist/types/src/func_arr.d.ts +0 -39
  117. package/dist/types/src/func_arr.d.ts.map +0 -1
  118. package/dist/types/src/global_options.d.ts +0 -120
  119. package/dist/types/src/global_options.d.ts.map +0 -1
  120. package/dist/types/src/index.d.ts +0 -43
  121. package/dist/types/src/index.d.ts.map +0 -1
  122. package/dist/types/src/mutation_observer.d.ts +0 -79
  123. package/dist/types/src/mutation_observer.d.ts.map +0 -1
  124. package/dist/types/src/native_node.d.ts +0 -11
  125. package/dist/types/src/native_node.d.ts.map +0 -1
  126. package/dist/types/src/node.d.ts +0 -48
  127. package/dist/types/src/node.d.ts.map +0 -1
  128. package/dist/types/src/relation.d.ts +0 -46
  129. package/dist/types/src/relation.d.ts.map +0 -1
  130. package/dist/types/src/render.d.ts +0 -3
  131. package/dist/types/src/render.d.ts.map +0 -1
  132. package/dist/types/src/selector.d.ts +0 -32
  133. package/dist/types/src/selector.d.ts.map +0 -1
  134. package/dist/types/src/shadow_root.d.ts +0 -174
  135. package/dist/types/src/shadow_root.d.ts.map +0 -1
  136. package/dist/types/src/template_engine.d.ts +0 -56
  137. package/dist/types/src/template_engine.d.ts.map +0 -1
  138. package/dist/types/src/text_node.d.ts +0 -44
  139. package/dist/types/src/text_node.d.ts.map +0 -1
  140. package/dist/types/src/tmpl/index.d.ts +0 -19
  141. package/dist/types/src/tmpl/index.d.ts.map +0 -1
  142. package/dist/types/src/tmpl/native_rendering.d.ts +0 -45
  143. package/dist/types/src/tmpl/native_rendering.d.ts.map +0 -1
  144. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +0 -89
  145. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +0 -1
  146. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +0 -50
  147. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +0 -1
  148. package/dist/types/src/tmpl/range_list_diff.d.ts +0 -19
  149. package/dist/types/src/tmpl/range_list_diff.d.ts.map +0 -1
  150. package/dist/types/src/trait_behaviors.d.ts +0 -38
  151. package/dist/types/src/trait_behaviors.d.ts.map +0 -1
  152. package/dist/types/src/virtual_node.d.ts +0 -10
  153. package/dist/types/src/virtual_node.d.ts.map +0 -1
  154. package/dist/types/tests/backend/domlike.test.d.ts +0 -2
  155. package/dist/types/tests/backend/domlike.test.d.ts.map +0 -1
  156. package/dist/types/tests/base/composed_backend.d.ts +0 -123
  157. package/dist/types/tests/base/composed_backend.d.ts.map +0 -1
  158. package/dist/types/tests/base/env.d.ts +0 -30
  159. package/dist/types/tests/base/env.d.ts.map +0 -1
  160. package/dist/types/tests/base/match.d.ts +0 -9
  161. package/dist/types/tests/base/match.d.ts.map +0 -1
  162. package/dist/types/tests/core/backend.test.d.ts +0 -2
  163. package/dist/types/tests/core/backend.test.d.ts.map +0 -1
  164. package/dist/types/tests/core/behavior.test.d.ts +0 -2
  165. package/dist/types/tests/core/behavior.test.d.ts.map +0 -1
  166. package/dist/types/tests/core/component_space.test.d.ts +0 -2
  167. package/dist/types/tests/core/component_space.test.d.ts.map +0 -1
  168. package/dist/types/tests/core/data_update.test.d.ts +0 -2
  169. package/dist/types/tests/core/data_update.test.d.ts.map +0 -1
  170. package/dist/types/tests/core/misc.test.d.ts +0 -2
  171. package/dist/types/tests/core/misc.test.d.ts.map +0 -1
  172. package/dist/types/tests/core/placeholder.test.d.ts +0 -2
  173. package/dist/types/tests/core/placeholder.test.d.ts.map +0 -1
  174. package/dist/types/tests/core/slot.test.d.ts +0 -2
  175. package/dist/types/tests/core/slot.test.d.ts.map +0 -1
  176. package/dist/types/tests/core/trait_behaviors.test.d.ts +0 -2
  177. package/dist/types/tests/core/trait_behaviors.test.d.ts.map +0 -1
  178. package/dist/types/tests/tmpl/binding_map.test.d.ts +0 -2
  179. package/dist/types/tests/tmpl/binding_map.test.d.ts.map +0 -1
  180. package/dist/types/tests/tmpl/event.test.d.ts +0 -2
  181. package/dist/types/tests/tmpl/event.test.d.ts.map +0 -1
  182. package/dist/types/tests/tmpl/expression.test.d.ts +0 -2
  183. package/dist/types/tests/tmpl/expression.test.d.ts.map +0 -1
  184. package/dist/types/tests/tmpl/lvalue.test.d.ts +0 -2
  185. package/dist/types/tests/tmpl/lvalue.test.d.ts.map +0 -1
  186. package/dist/types/tests/tmpl/native_rendering.test.d.ts +0 -2
  187. package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +0 -1
  188. package/dist/types/tests/tmpl/structure.test.d.ts +0 -2
  189. package/dist/types/tests/tmpl/structure.test.d.ts.map +0 -1
  190. package/dist/types/tests/types/chaining.test.d.ts +0 -2
  191. package/dist/types/tests/types/chaining.test.d.ts.map +0 -1
  192. package/dist/types/tests/types/createElement.test.d.ts +0 -2
  193. package/dist/types/tests/types/createElement.test.d.ts.map +0 -1
  194. package/dist/types/tests/types/definition.test.d.ts +0 -2
  195. package/dist/types/tests/types/definition.test.d.ts.map +0 -1
  196. package/webpack.config.js +0 -275
  197. /package/src/backend/{mode.ts → shared.ts} +0 -0
@@ -1,4 +1,11 @@
1
- import { tmpl, multiTmpl, domBackend, execWithWarn } from '../base/env'
1
+ import {
2
+ tmpl,
3
+ multiTmpl,
4
+ domBackend,
5
+ execWithWarn,
6
+ composedBackend,
7
+ shadowBackend,
8
+ } from '../base/env'
2
9
  import { virtual as matchElementWithDom } from '../base/match'
3
10
  import * as glassEasel from '../../src'
4
11
 
@@ -7,7 +14,7 @@ const domHtml = (elem: glassEasel.Element): string => {
7
14
  return domElem.innerHTML
8
15
  }
9
16
 
10
- describe('node tree structure', () => {
17
+ const testCases = (testBackend: glassEasel.GeneralBackendContext) => {
11
18
  test('basic tree building', () => {
12
19
  const def = glassEasel
13
20
  .registerElement({
@@ -18,8 +25,9 @@ describe('node tree structure', () => {
18
25
  `),
19
26
  })
20
27
  .general()
21
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
28
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
22
29
  expect(domHtml(elem)).toBe('<div style="font-weight: bold"><span>Hello world!</span></div>')
30
+ matchElementWithDom(elem)
23
31
  })
24
32
 
25
33
  test('basic data binding', () => {
@@ -36,13 +44,15 @@ describe('node tree structure', () => {
36
44
  },
37
45
  })
38
46
  .general()
39
- const elem = glassEasel.Component.createWithContext('root', def, domBackend).general()
47
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend).general()
40
48
  expect(domHtml(elem)).toBe('<div class="123"><span>abc</span></div>')
49
+ matchElementWithDom(elem)
41
50
  elem.setData({
42
51
  a: true,
43
52
  c: false,
44
53
  })
45
54
  expect(domHtml(elem)).toBe('<div class="true"><span>false</span></div>')
55
+ matchElementWithDom(elem)
46
56
  })
47
57
 
48
58
  test('if blocks', () => {
@@ -62,20 +72,24 @@ describe('node tree structure', () => {
62
72
  },
63
73
  })
64
74
  .general()
65
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
75
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
66
76
  expect(domHtml(elem)).toBe('<div>c</div><div>f</div>')
77
+ matchElementWithDom(elem)
67
78
  elem.setData({
68
79
  cond1: true,
69
80
  })
70
81
  expect(domHtml(elem)).toBe('<div>a</div><div>c</div><div>d</div>')
82
+ matchElementWithDom(elem)
71
83
  elem.setData({
72
84
  cond2: 1,
73
85
  })
74
86
  expect(domHtml(elem)).toBe('<div>a</div><div>b</div><div>d</div>')
87
+ matchElementWithDom(elem)
75
88
  elem.setData({
76
89
  cond1: null,
77
90
  })
78
91
  expect(domHtml(elem)).toBe('<div>b</div><div>e</div>')
92
+ matchElementWithDom(elem)
79
93
  })
80
94
 
81
95
  test('if blocks in template-is', () => {
@@ -98,17 +112,49 @@ describe('node tree structure', () => {
98
112
  },
99
113
  })
100
114
  .general()
101
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
115
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
102
116
  expect(domHtml(elem)).toBe('<div>456</div>')
117
+ matchElementWithDom(elem)
103
118
  elem.setData({
104
119
  cond: true,
105
120
  })
106
121
  expect(domHtml(elem)).toBe('<div>123</div>')
122
+ matchElementWithDom(elem)
107
123
  elem.setData({
108
124
  cond: false,
109
125
  c: 789,
110
126
  })
111
127
  expect(domHtml(elem)).toBe('<div>789</div>')
128
+ matchElementWithDom(elem)
129
+ })
130
+
131
+ test('if blocks in include', () => {
132
+ const def = glassEasel
133
+ .registerElement({
134
+ template: multiTmpl({
135
+ '': '<include wx:if="{{!cond}}" src="./a.wxml" />',
136
+ a: '<div>{{a}}</div>',
137
+ }),
138
+ data: {
139
+ cond: false,
140
+ a: 123,
141
+ },
142
+ })
143
+ .general()
144
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
145
+ expect(domHtml(elem)).toBe('<div>123</div>')
146
+ matchElementWithDom(elem)
147
+ elem.setData({
148
+ cond: true,
149
+ })
150
+ expect(domHtml(elem)).toBe('')
151
+ matchElementWithDom(elem)
152
+ elem.setData({
153
+ cond: false,
154
+ a: 456,
155
+ })
156
+ expect(domHtml(elem)).toBe('<div>456</div>')
157
+ matchElementWithDom(elem)
112
158
  })
113
159
 
114
160
  test('if blocks in slot', () => {
@@ -147,7 +193,7 @@ describe('node tree structure', () => {
147
193
  },
148
194
  })
149
195
  .general()
150
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
196
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
151
197
  const child = elem.getShadowRoot()!.getElementById('c')!.asInstanceOf(childComp)!
152
198
  expect(domHtml(elem)).toBe('<child><div>A</div></child>')
153
199
  matchElementWithDom(elem)
@@ -195,9 +241,10 @@ describe('node tree structure', () => {
195
241
  },
196
242
  })
197
243
  .general()
198
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
244
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
199
245
  glassEasel.Element.pretendAttached(elem)
200
246
  expect(domHtml(elem)).toBe('<div><x-c>0</x-c></div><div><x-c>1</x-c></div>')
247
+ matchElementWithDom(elem)
201
248
  expect(ops).toEqual([
202
249
  [-1, '10'],
203
250
  [-1, '20'],
@@ -207,6 +254,7 @@ describe('node tree structure', () => {
207
254
  list: [20, 10],
208
255
  })
209
256
  expect(domHtml(elem)).toBe('<div><x-c>0</x-c></div><div><x-c>1</x-c></div>')
257
+ matchElementWithDom(elem)
210
258
  expect(ops).toEqual([])
211
259
  ops.length = 0
212
260
  elem.setData({
@@ -215,6 +263,7 @@ describe('node tree structure', () => {
215
263
  expect(domHtml(elem)).toBe(
216
264
  '<div><x-c>0</x-c></div><div><x-c>1</x-c></div><div><x-c>2</x-c></div><div><x-c>3</x-c></div>',
217
265
  )
266
+ matchElementWithDom(elem)
218
267
  expect(ops).toEqual([
219
268
  [-1, '50'],
220
269
  [-1, '60'],
@@ -224,6 +273,7 @@ describe('node tree structure', () => {
224
273
  list: [50],
225
274
  })
226
275
  expect(domHtml(elem)).toBe('<div><x-c>0</x-c></div>')
276
+ matchElementWithDom(elem)
227
277
  expect(ops).toEqual([
228
278
  [-2, '40'],
229
279
  [-2, '50'],
@@ -267,7 +317,7 @@ describe('node tree structure', () => {
267
317
  },
268
318
  })
269
319
  .general()
270
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
320
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
271
321
  const listBlock = elem.getShadowRoot()!.childNodes[0] as glassEasel.VirtualNode
272
322
  const checkIndex = () => {
273
323
  for (let i = 0; i < listBlock.childNodes.length; i += 1) {
@@ -277,6 +327,7 @@ describe('node tree structure', () => {
277
327
  }
278
328
  glassEasel.Element.pretendAttached(elem)
279
329
  expect(domHtml(elem)).toBe('<x-c>10</x-c><x-c>20</x-c>')
330
+ matchElementWithDom(elem)
280
331
  checkIndex()
281
332
  expect(ops).toEqual([
282
333
  [-1, 'a:10'],
@@ -293,6 +344,7 @@ describe('node tree structure', () => {
293
344
  ],
294
345
  })
295
346
  expect(domHtml(elem)).toBe('<x-c>30</x-c><x-c>40</x-c><x-c>50</x-c><x-c>60</x-c><x-c>70</x-c>')
347
+ matchElementWithDom(elem)
296
348
  checkIndex()
297
349
  expect(ops).toEqual([
298
350
  [-1, 'c:30'],
@@ -310,6 +362,7 @@ describe('node tree structure', () => {
310
362
  ],
311
363
  })
312
364
  expect(domHtml(elem)).toBe('<x-c>30</x-c><x-c>60</x-c><x-c>40</x-c><x-c>50</x-c><x-c>70</x-c>')
365
+ matchElementWithDom(elem)
313
366
  checkIndex()
314
367
  expect(ops).toEqual([[-3, 'b:60']])
315
368
  ops.length = 0
@@ -323,6 +376,7 @@ describe('node tree structure', () => {
323
376
  ],
324
377
  })
325
378
  expect(domHtml(elem)).toBe('<x-c>30</x-c><x-c>40</x-c><x-c>50</x-c><x-c>60</x-c><x-c>70</x-c>')
379
+ matchElementWithDom(elem)
326
380
  checkIndex()
327
381
  expect(ops).toEqual([[-3, 'a:40']])
328
382
  ops.length = 0
@@ -336,6 +390,7 @@ describe('node tree structure', () => {
336
390
  ],
337
391
  })
338
392
  expect(domHtml(elem)).toBe('<x-c>30</x-c><x-c>40</x-c><x-c>50</x-c><x-c>60</x-c><x-c>70</x-c>')
393
+ matchElementWithDom(elem)
339
394
  checkIndex()
340
395
  expect(ops).toEqual([])
341
396
  ops.length = 0
@@ -346,6 +401,7 @@ describe('node tree structure', () => {
346
401
  ],
347
402
  })
348
403
  expect(domHtml(elem)).toBe('<x-c>80</x-c><x-c>90</x-c>')
404
+ matchElementWithDom(elem)
349
405
  checkIndex()
350
406
  expect(ops).toEqual([
351
407
  [-2, 'c:30'],
@@ -370,7 +426,7 @@ describe('node tree structure', () => {
370
426
  },
371
427
  })
372
428
  .general()
373
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
429
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
374
430
  expect(
375
431
  (elem.getShadowRoot()!.getElementById('a0')!.childNodes[0] as glassEasel.TextNode)
376
432
  .textContent,
@@ -441,9 +497,10 @@ describe('node tree structure', () => {
441
497
  },
442
498
  })
443
499
  .general()
444
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
500
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
445
501
  glassEasel.Element.pretendAttached(elem)
446
502
  expect(domHtml(elem)).toBe('<div><x-c>a</x-c></div><div><x-c>b</x-c></div>')
503
+ matchElementWithDom(elem)
447
504
  expect(ops).toEqual([
448
505
  [-1, 'a:10'],
449
506
  [-1, 'b:20'],
@@ -453,6 +510,7 @@ describe('node tree structure', () => {
453
510
  list: { a: 20, b: 10 },
454
511
  })
455
512
  expect(domHtml(elem)).toBe('<div><x-c>a</x-c></div><div><x-c>b</x-c></div>')
513
+ matchElementWithDom(elem)
456
514
  expect(ops).toEqual([])
457
515
  ops.length = 0
458
516
  elem.setData({
@@ -466,6 +524,7 @@ describe('node tree structure', () => {
466
524
  expect(domHtml(elem)).toBe(
467
525
  '<div><x-c>a</x-c></div><div><x-c>b</x-c></div><div><x-c>c</x-c></div><div><x-c>d</x-c></div>',
468
526
  )
527
+ matchElementWithDom(elem)
469
528
  expect(ops).toEqual([
470
529
  [-1, 'c:50'],
471
530
  [-1, 'd:60'],
@@ -475,6 +534,7 @@ describe('node tree structure', () => {
475
534
  list: { c: 50 },
476
535
  })
477
536
  expect(domHtml(elem)).toBe('<div><x-c>c</x-c></div>')
537
+ matchElementWithDom(elem)
478
538
  expect(ops).toEqual([
479
539
  [-2, 'b:40'],
480
540
  [-2, 'c:50'],
@@ -514,7 +574,7 @@ describe('node tree structure', () => {
514
574
  >,
515
575
  },
516
576
  })
517
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
577
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
518
578
  const listBlock = elem.getShadowRoot()!.childNodes[0] as glassEasel.VirtualNode
519
579
  const checkIndex = () => {
520
580
  const keys = Object.keys(elem.data.list)
@@ -525,6 +585,7 @@ describe('node tree structure', () => {
525
585
  }
526
586
  glassEasel.Element.pretendAttached(elem)
527
587
  expect(domHtml(elem)).toBe('<x-c>10</x-c><x-c>20</x-c>')
588
+ matchElementWithDom(elem)
528
589
  checkIndex()
529
590
  expect(ops).toEqual([
530
591
  [-1, 'a:10'],
@@ -544,6 +605,7 @@ describe('node tree structure', () => {
544
605
  expect(domHtml(elem)).toBe(
545
606
  '<x-c>30</x-c><x-c>40</x-c><x-c>50</x-c><x-c>60</x-c><x-c>70</x-c><x-c>80</x-c>',
546
607
  )
608
+ matchElementWithDom(elem)
547
609
  checkIndex()
548
610
  expect(ops).toEqual([
549
611
  [-1, 'c:30'],
@@ -565,6 +627,7 @@ describe('node tree structure', () => {
565
627
  expect(domHtml(elem)).toBe(
566
628
  '<x-c>50</x-c><x-c>60</x-c><x-c>70</x-c><x-c>80</x-c><x-c>30</x-c><x-c>40</x-c>',
567
629
  )
630
+ matchElementWithDom(elem)
568
631
  checkIndex()
569
632
  expect(ops).toEqual([
570
633
  [-2, 'c:30'],
@@ -583,6 +646,7 @@ describe('node tree structure', () => {
583
646
  },
584
647
  })
585
648
  expect(domHtml(elem)).toBe('<x-c>10</x-c><x-c>20</x-c><x-c>30</x-c><x-c>40</x-c><x-c>50</x-c>')
649
+ matchElementWithDom(elem)
586
650
  checkIndex()
587
651
  expect(ops).toEqual([
588
652
  [-3, 'g:30'],
@@ -604,6 +668,7 @@ describe('node tree structure', () => {
604
668
  expect(domHtml(elem)).toBe(
605
669
  '<x-c>10</x-c><x-c>20</x-c><x-c>30</x-c><x-c>40</x-c><x-c>50</x-c><x-c>60</x-c><x-c>70</x-c>',
606
670
  )
671
+ matchElementWithDom(elem)
607
672
  checkIndex()
608
673
  expect(ops).toEqual([
609
674
  [-3, 'a:40'],
@@ -625,6 +690,7 @@ describe('node tree structure', () => {
625
690
  expect(domHtml(elem)).toBe(
626
691
  '<x-c>60</x-c><x-c>50</x-c><x-c>40</x-c><x-c>30</x-c><x-c>20</x-c><x-c>10</x-c>',
627
692
  )
693
+ matchElementWithDom(elem)
628
694
  checkIndex()
629
695
  expect(ops).toEqual([
630
696
  [-3, 'h:70'],
@@ -648,6 +714,7 @@ describe('node tree structure', () => {
648
714
  expect(domHtml(elem)).toBe(
649
715
  '<x-c>80</x-c><x-c>70</x-c><x-c>60</x-c><x-c>50</x-c><x-c>40</x-c><x-c>30</x-c><x-c>20</x-c><x-c>10</x-c>',
650
716
  )
717
+ matchElementWithDom(elem)
651
718
  checkIndex()
652
719
  expect(ops).toEqual([
653
720
  [-3, 'f:40'],
@@ -692,10 +759,11 @@ describe('node tree structure', () => {
692
759
  })
693
760
  .general()
694
761
  const elem = execWithWarn(1, () =>
695
- glassEasel.Component.createWithContext('root', def, domBackend),
762
+ glassEasel.Component.createWithContext('root', def, testBackend),
696
763
  )
697
764
  glassEasel.Element.pretendAttached(elem)
698
765
  expect(domHtml(elem)).toBe('<x-c>x</x-c>')
766
+ matchElementWithDom(elem)
699
767
  expect(ops).toEqual([[-1, 'x']])
700
768
  ops.length = 0
701
769
  execWithWarn(1, () => {
@@ -704,6 +772,7 @@ describe('node tree structure', () => {
704
772
  })
705
773
  })
706
774
  expect(domHtml(elem)).toBe('<x-c>a</x-c><x-c>b</x-c><x-c>c</x-c>')
775
+ matchElementWithDom(elem)
707
776
  expect(ops).toEqual([
708
777
  [-2, 'x'],
709
778
  [-1, 'a'],
@@ -717,6 +786,7 @@ describe('node tree structure', () => {
717
786
  })
718
787
  })
719
788
  expect(domHtml(elem)).toBe('<x-c>c</x-c><x-c>a</x-c><x-c>b</x-c>')
789
+ matchElementWithDom(elem)
720
790
  ops.length = 0
721
791
  execWithWarn(1, () => {
722
792
  elem.setData({
@@ -724,6 +794,7 @@ describe('node tree structure', () => {
724
794
  })
725
795
  })
726
796
  expect(domHtml(elem)).toBe('')
797
+ matchElementWithDom(elem)
727
798
  expect(ops).toEqual([
728
799
  [-2, 'c'],
729
800
  [-2, 'a'],
@@ -743,12 +814,53 @@ describe('node tree structure', () => {
743
814
  })
744
815
  .general()
745
816
  const elem = execWithWarn(1, () =>
746
- glassEasel.Component.createWithContext('root', def, domBackend),
817
+ glassEasel.Component.createWithContext('root', def, testBackend),
747
818
  )
748
819
  glassEasel.Element.pretendAttached(elem)
749
820
  expect(domHtml(elem)).toBe('<span>0</span><span>1</span><span>2</span>')
821
+ matchElementWithDom(elem)
750
822
  execWithWarn(1, () => elem.setData({ n: 2 }))
751
823
  expect(domHtml(elem)).toBe('<span>0</span><span>1</span>')
824
+ matchElementWithDom(elem)
825
+ })
826
+
827
+ test('slot inside for blocks', () => {
828
+ const x = glassEasel.registerElement({})
829
+ const def = glassEasel.registerElement({
830
+ using: { x },
831
+ template: tmpl(`
832
+ <x>
833
+ <block wx:for="{{n}}">
834
+ <s>{{item}}</s>
835
+ </block>
836
+ </x>
837
+ `),
838
+ data: { n: [0, 1, 2] },
839
+ })
840
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
841
+ glassEasel.Element.pretendAttached(elem)
842
+ expect(domHtml(elem)).toBe('<x><s>0</s><s>1</s><s>2</s></x>')
843
+ matchElementWithDom(elem)
844
+ elem.spliceArrayDataOnPath(['n'], 3, 0, [3, 4])
845
+ elem.applyDataUpdates()
846
+ expect(domHtml(elem)).toBe('<x><s>0</s><s>1</s><s>2</s><s>3</s><s>4</s></x>')
847
+ matchElementWithDom(elem)
848
+ elem.spliceArrayDataOnPath(['n'], 0, 0, [5, 6])
849
+ elem.applyDataUpdates()
850
+ expect(domHtml(elem)).toBe('<x><s>5</s><s>6</s><s>0</s><s>1</s><s>2</s><s>3</s><s>4</s></x>')
851
+ matchElementWithDom(elem)
852
+ elem.spliceArrayDataOnPath(['n'], 2, 3, [7, 8])
853
+ elem.applyDataUpdates()
854
+ expect(domHtml(elem)).toBe('<x><s>5</s><s>6</s><s>7</s><s>8</s><s>3</s><s>4</s></x>')
855
+ matchElementWithDom(elem)
856
+ elem.spliceArrayDataOnPath(['n'], 0, 3, [])
857
+ elem.applyDataUpdates()
858
+ expect(domHtml(elem)).toBe('<x><s>8</s><s>3</s><s>4</s></x>')
859
+ matchElementWithDom(elem)
860
+ elem.spliceArrayDataOnPath(['n'], 1, 2, [])
861
+ elem.applyDataUpdates()
862
+ expect(domHtml(elem)).toBe('<x><s>8</s></x>')
863
+ matchElementWithDom(elem)
752
864
  })
753
865
 
754
866
  test('template include', () => {
@@ -763,10 +875,12 @@ describe('node tree structure', () => {
763
875
  },
764
876
  })
765
877
  .general()
766
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
878
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
767
879
  expect(domHtml(elem)).toBe('<div>123</div>')
880
+ matchElementWithDom(elem)
768
881
  elem.setData({ a: 456 })
769
882
  expect(domHtml(elem)).toBe('<div>456</div>')
883
+ matchElementWithDom(elem)
770
884
  })
771
885
 
772
886
  test('template undefined include', () => {
@@ -780,8 +894,9 @@ describe('node tree structure', () => {
780
894
  },
781
895
  })
782
896
  .general()
783
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
897
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
784
898
  expect(domHtml(elem)).toBe('<div></div>')
899
+ matchElementWithDom(elem)
785
900
  })
786
901
 
787
902
  test('template-name data', () => {
@@ -809,10 +924,12 @@ describe('node tree structure', () => {
809
924
  },
810
925
  })
811
926
  .general()
812
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
927
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
813
928
  expect(domHtml(elem)).toBe('<div><span>0:123</span><span>2:789</span></div>')
929
+ matchElementWithDom(elem)
814
930
  elem.setData({ 'arr[0].shown': false })
815
931
  expect(domHtml(elem)).toBe('<div><span>2:789</span></div>')
932
+ matchElementWithDom(elem)
816
933
  elem.setData({
817
934
  arr: [
818
935
  { shown: false, data: 789 },
@@ -820,6 +937,7 @@ describe('node tree structure', () => {
820
937
  ],
821
938
  })
822
939
  expect(domHtml(elem)).toBe('<div><span>1:456</span></div>')
940
+ matchElementWithDom(elem)
823
941
  })
824
942
 
825
943
  test('template-name data shortcut', () => {
@@ -849,12 +967,15 @@ describe('node tree structure', () => {
849
967
  },
850
968
  })
851
969
  .general()
852
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
970
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
853
971
  expect(domHtml(elem)).toBe('<div><span>123</span></div><div><span>123</span></div>')
972
+ matchElementWithDom(elem)
854
973
  elem.setData({ obj: { a: 456 } })
855
974
  expect(domHtml(elem)).toBe('<div><span>456</span></div><div><span>456</span></div>')
975
+ matchElementWithDom(elem)
856
976
  elem.setData({ 'obj.a': 789 })
857
977
  expect(domHtml(elem)).toBe('<div><span>789</span></div><div><span>789</span></div>')
978
+ matchElementWithDom(elem)
858
979
  })
859
980
 
860
981
  test('template-name data cascaded passing', () => {
@@ -876,12 +997,15 @@ describe('node tree structure', () => {
876
997
  },
877
998
  })
878
999
  .general()
879
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1000
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
880
1001
  expect(domHtml(elem)).toBe('<div><span>123</span></div>')
1002
+ matchElementWithDom(elem)
881
1003
  elem.setData({ obj: { a: 456 } })
882
1004
  expect(domHtml(elem)).toBe('<div><span>456</span></div>')
1005
+ matchElementWithDom(elem)
883
1006
  elem.setData({ 'obj.a': 789 })
884
1007
  expect(domHtml(elem)).toBe('<div><span>789</span></div>')
1008
+ matchElementWithDom(elem)
885
1009
  })
886
1010
 
887
1011
  test('static template-is', () => {
@@ -902,14 +1026,18 @@ describe('node tree structure', () => {
902
1026
  },
903
1027
  })
904
1028
  .general()
905
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1029
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
906
1030
  expect(domHtml(elem)).toBe('<div><span>345</span></div>')
1031
+ matchElementWithDom(elem)
907
1032
  elem.setData({ b: { a: 200, d: 7 } })
908
1033
  expect(domHtml(elem)).toBe('<div><span>247</span></div>')
1034
+ matchElementWithDom(elem)
909
1035
  elem.setData({ 'b.a': 100 })
910
1036
  expect(domHtml(elem)).toBe('<div><span>147</span></div>')
1037
+ matchElementWithDom(elem)
911
1038
  elem.setData({ 'b.hidden': true })
912
1039
  expect(domHtml(elem)).toBe('<div></div>')
1040
+ matchElementWithDom(elem)
913
1041
  })
914
1042
 
915
1043
  test('dynamic template-is', () => {
@@ -935,16 +1063,21 @@ describe('node tree structure', () => {
935
1063
  methods: {},
936
1064
  })
937
1065
  .general()
938
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1066
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
939
1067
  expect(domHtml(elem)).toBe('<div></div>')
1068
+ matchElementWithDom(elem)
940
1069
  elem.setData({ childType: 'A' })
941
1070
  expect(domHtml(elem)).toBe('<div><span>123</span></div>')
1071
+ matchElementWithDom(elem)
942
1072
  elem.setData({ childType: 'B' })
943
1073
  expect(domHtml(elem)).toBe('<div><span>456</span></div>')
1074
+ matchElementWithDom(elem)
944
1075
  elem.setData({ a: 0 })
945
1076
  expect(domHtml(elem)).toBe('<div><span>456</span></div>')
1077
+ matchElementWithDom(elem)
946
1078
  elem.setData({ b: 789 })
947
1079
  expect(domHtml(elem)).toBe('<div><span>789</span></div>')
1080
+ matchElementWithDom(elem)
948
1081
  })
949
1082
 
950
1083
  test('template-is inside for block', () => {
@@ -972,16 +1105,21 @@ describe('node tree structure', () => {
972
1105
  methods: {},
973
1106
  })
974
1107
  .general()
975
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1108
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
976
1109
  expect(domHtml(elem)).toBe('<div></div>')
1110
+ matchElementWithDom(elem)
977
1111
  elem.setData({ list: [1, 2] })
978
1112
  expect(domHtml(elem)).toBe('<div><span>0:123</span><span>1:456</span></div>')
1113
+ matchElementWithDom(elem)
979
1114
  elem.setData({ list: [2, 1, 1] })
980
1115
  expect(domHtml(elem)).toBe('<div><span>0:456</span><span>1:123</span><span>2:123</span></div>')
1116
+ matchElementWithDom(elem)
981
1117
  elem.setData({ a: 0 })
982
1118
  expect(domHtml(elem)).toBe('<div><span>0:456</span><span>1:0</span><span>2:0</span></div>')
1119
+ matchElementWithDom(elem)
983
1120
  elem.setData({ b: 789 })
984
1121
  expect(domHtml(elem)).toBe('<div><span>0:789</span><span>1:0</span><span>2:0</span></div>')
1122
+ matchElementWithDom(elem)
985
1123
  })
986
1124
 
987
1125
  test('undefined template-is', () => {
@@ -997,8 +1135,9 @@ describe('node tree structure', () => {
997
1135
  },
998
1136
  })
999
1137
  .general()
1000
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1138
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1001
1139
  expect(domHtml(elem)).toBe('<div></div>')
1140
+ matchElementWithDom(elem)
1002
1141
  })
1003
1142
 
1004
1143
  test('cascaded template', () => {
@@ -1028,11 +1167,13 @@ describe('node tree structure', () => {
1028
1167
  },
1029
1168
  })
1030
1169
  .general()
1031
- const elem = glassEasel.Component.createWithContext('root', def, domBackend).asInstanceOf(def)!
1170
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend).asInstanceOf(def)!
1032
1171
  expect(domHtml(elem)).toBe('<div>key: A</div><div>value: a</div>')
1172
+ matchElementWithDom(elem)
1033
1173
 
1034
1174
  elem.setData({ 'c.i': 'B' })
1035
1175
  expect(domHtml(elem)).toBe('<div>key: B</div><div>value: b</div>')
1176
+ matchElementWithDom(elem)
1036
1177
  })
1037
1178
 
1038
1179
  test('custom scripts', () => {
@@ -1055,8 +1196,9 @@ describe('node tree structure', () => {
1055
1196
  data: {},
1056
1197
  })
1057
1198
  .general()
1058
- const elem = glassEasel.Component.createWithContext('root', def, domBackend).asInstanceOf(def)!
1199
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend).asInstanceOf(def)!
1059
1200
  expect(domHtml(elem)).toBe('<div>6</div>')
1201
+ matchElementWithDom(elem)
1060
1202
  })
1061
1203
 
1062
1204
  test('custom inline scripts', () => {
@@ -1076,8 +1218,9 @@ describe('node tree structure', () => {
1076
1218
  data: {},
1077
1219
  })
1078
1220
  .general()
1079
- const elem = glassEasel.Component.createWithContext('root', def, domBackend).asInstanceOf(def)!
1221
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend).asInstanceOf(def)!
1080
1222
  expect(domHtml(elem)).toBe('<div>6</div>')
1223
+ matchElementWithDom(elem)
1081
1224
  })
1082
1225
 
1083
1226
  test('custom scripts across files', () => {
@@ -1104,8 +1247,28 @@ describe('node tree structure', () => {
1104
1247
  data: {},
1105
1248
  })
1106
1249
  .general()
1107
- const elem = glassEasel.Component.createWithContext('root', def, domBackend).asInstanceOf(def)!
1250
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend).asInstanceOf(def)!
1108
1251
  expect(domHtml(elem)).toBe('<div>-1 3</div>')
1252
+ matchElementWithDom(elem)
1253
+ })
1254
+
1255
+ test('custom scripts with template', () => {
1256
+ const def = glassEasel
1257
+ .registerElement({
1258
+ template: tmpl(`
1259
+ <wxs module="a">module.exports={ foo: 'foo' }</wxs>
1260
+ <template name="test">
1261
+ <div>{{a.foo}}</div>
1262
+ </template>
1263
+ <template is="test" data="{{ a: { foo: 'bar' } }}" />
1264
+ <div>{{a.foo}}</div>
1265
+ `),
1266
+ data: {},
1267
+ })
1268
+ .general()
1269
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend).asInstanceOf(def)!
1270
+ expect(domHtml(elem)).toBe('<div>foo</div><div>foo</div>')
1271
+ matchElementWithDom(elem)
1109
1272
  })
1110
1273
 
1111
1274
  test('block slot', () => {
@@ -1134,7 +1297,7 @@ describe('node tree structure', () => {
1134
1297
  },
1135
1298
  })
1136
1299
  .general()
1137
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1300
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1138
1301
  glassEasel.Element.pretendAttached(elem)
1139
1302
  expect(domHtml(elem)).toBe('<child-comp><div>123</div></child-comp>')
1140
1303
  matchElementWithDom(elem)
@@ -1153,9 +1316,10 @@ describe('node tree structure', () => {
1153
1316
  `),
1154
1317
  })
1155
1318
  .general()
1156
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1319
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1157
1320
  glassEasel.Element.pretendAttached(elem)
1158
1321
  expect(domHtml(elem)).toBe('<div></div>')
1322
+ matchElementWithDom(elem)
1159
1323
  })
1160
1324
 
1161
1325
  test('dataset name cases', () => {
@@ -1166,9 +1330,10 @@ describe('node tree structure', () => {
1166
1330
  `),
1167
1331
  })
1168
1332
  .general()
1169
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1333
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1170
1334
  glassEasel.Element.pretendAttached(elem)
1171
1335
  expect(domHtml(elem)).toBe('<div></div>')
1336
+ matchElementWithDom(elem)
1172
1337
  expect(elem.getShadowRoot()!.childNodes[0]!.asElement()!.dataset.camelcase).toBe(123)
1173
1338
  })
1174
1339
 
@@ -1180,9 +1345,43 @@ describe('node tree structure', () => {
1180
1345
  `),
1181
1346
  })
1182
1347
  .general()
1183
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1348
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1184
1349
  glassEasel.Element.pretendAttached(elem)
1185
1350
  expect(domHtml(elem)).toBe('<div hidden=""></div>')
1351
+ matchElementWithDom(elem)
1352
+ })
1353
+
1354
+ test('attribute types', () => {
1355
+ const def = glassEasel
1356
+ .registerElement({
1357
+ template: tmpl(`
1358
+ <div
1359
+ a="{{true}}"
1360
+ b="{{false}}"
1361
+ c="{{null}}"
1362
+ d="{{undefined}}"
1363
+ e="{{arr}}"
1364
+ f="{{obj}}"
1365
+ g="{{0}}"
1366
+ h="{{NaN}}"
1367
+ i="{{infinity}}"
1368
+ j
1369
+ ></div>
1370
+ `),
1371
+ data: {
1372
+ arr: [],
1373
+ obj: {},
1374
+ NaN,
1375
+ infinity: Infinity,
1376
+ },
1377
+ })
1378
+ .general()
1379
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1380
+ glassEasel.Element.pretendAttached(elem)
1381
+ expect(domHtml(elem)).toBe(
1382
+ '<div a="" c="" d="" e="" f="[object Object]" g="0" h="NaN" i="Infinity" j=""></div>',
1383
+ )
1384
+ matchElementWithDom(elem)
1186
1385
  })
1187
1386
 
1188
1387
  test('property name cases', () => {
@@ -1201,7 +1400,7 @@ describe('node tree structure', () => {
1201
1400
  `),
1202
1401
  })
1203
1402
  .general()
1204
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1403
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1205
1404
  glassEasel.Element.pretendAttached(elem)
1206
1405
  expect(elem.getShadowRoot()!.childNodes[0]!.asInstanceOf(subComp)!.data.propName).toBe('abc')
1207
1406
  })
@@ -1218,14 +1417,16 @@ describe('node tree structure', () => {
1218
1417
  },
1219
1418
  })
1220
1419
  .general()
1221
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1420
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1222
1421
  glassEasel.Element.pretendAttached(elem)
1223
1422
  expect(domHtml(elem)).toBe('<a href="abc"></a>')
1423
+ matchElementWithDom(elem)
1224
1424
  elem.setData({
1225
1425
  hidden: true,
1226
1426
  url: '',
1227
1427
  })
1228
1428
  expect(domHtml(elem)).toBe('<a href="" hidden=""></a>')
1429
+ matchElementWithDom(elem)
1229
1430
  })
1230
1431
 
1231
1432
  test('setting element id', () => {
@@ -1239,9 +1440,10 @@ describe('node tree structure', () => {
1239
1440
  },
1240
1441
  })
1241
1442
  .general()
1242
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1443
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1243
1444
  glassEasel.Element.pretendAttached(elem)
1244
1445
  expect(domHtml(elem)).toBe('<div>123</div>')
1446
+ matchElementWithDom(elem)
1245
1447
  expect(domHtml(elem.getShadowRoot()!.getElementById('abc')!)).toBe('123')
1246
1448
  elem.setData({
1247
1449
  d: 'def',
@@ -1272,7 +1474,7 @@ describe('node tree structure', () => {
1272
1474
  `),
1273
1475
  })
1274
1476
  .general()
1275
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1477
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1276
1478
  glassEasel.Element.pretendAttached(elem)
1277
1479
  expect(domHtml(elem)).toBe('<sub-comp><div></div><span></span></sub-comp>')
1278
1480
  matchElementWithDom(elem)
@@ -1316,7 +1518,7 @@ describe('node tree structure', () => {
1316
1518
  `),
1317
1519
  })
1318
1520
  .general()
1319
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1521
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1320
1522
  const subElem = (elem.$.sub as glassEasel.GeneralComponent).asInstanceOf(subComp)!
1321
1523
  glassEasel.Element.pretendAttached(elem)
1322
1524
  expect(domHtml(elem)).toBe('<sub-comp><a></a><b></b><c><s></s></c></sub-comp>')
@@ -1378,9 +1580,10 @@ describe('node tree structure', () => {
1378
1580
  },
1379
1581
  })
1380
1582
  .general()
1381
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1583
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1382
1584
  glassEasel.Element.pretendAttached(elem)
1383
1585
  expect(domHtml(elem)).toBe('<div><span></span></div>')
1586
+ matchElementWithDom(elem)
1384
1587
  const child = elem.getShadowRoot()!.getElementById('child')!
1385
1588
  child.triggerEvent('customEv')
1386
1589
  const ev = ops.shift() as glassEasel.ShadowedEvent<any>
@@ -1410,7 +1613,7 @@ describe('node tree structure', () => {
1410
1613
  },
1411
1614
  })
1412
1615
  .general()
1413
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1616
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1414
1617
  glassEasel.Element.pretendAttached(elem)
1415
1618
  const child = elem.getShadowRoot()!.getElementById('child')!
1416
1619
  child.triggerEvent('customEv')
@@ -1430,9 +1633,94 @@ describe('node tree structure', () => {
1430
1633
  ops = []
1431
1634
  })
1432
1635
 
1433
- test('setting external classes', () => {
1636
+ test('setting properties', () => {
1637
+ const cs = new glassEasel.ComponentSpace()
1638
+ const subComp = cs.defineComponent({
1639
+ template: tmpl(`
1640
+ <div class="{{style}} a-{{propA + 1}}"></div>
1641
+ `),
1642
+ properties: {
1643
+ style: String,
1644
+ propA: Number,
1645
+ },
1646
+ })
1647
+ const def = cs
1648
+ .defineComponent({
1649
+ using: {
1650
+ 'sub-comp': subComp.general(),
1651
+ },
1652
+ template: tmpl(`
1653
+ <sub-comp style="abc" prop-a="3" />
1654
+ `),
1655
+ })
1656
+ .general()
1657
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1658
+ glassEasel.Element.pretendAttached(elem)
1659
+ expect(domHtml(elem)).toBe('<sub-comp><div class="abc a-4"></div></sub-comp>')
1660
+ matchElementWithDom(elem)
1661
+ })
1662
+
1663
+ test('setting array as classNames', () => {
1434
1664
  const cs = new glassEasel.ComponentSpace()
1435
1665
  const ssm = cs.styleScopeManager
1666
+ const subComp = cs.defineComponent({
1667
+ externalClasses: ['ext-class'],
1668
+ template: tmpl(`
1669
+ <div class="inner ext-class"></div>
1670
+ `),
1671
+ })
1672
+ const def = cs
1673
+ .defineComponent({
1674
+ options: {
1675
+ styleScope: ssm.register('p'),
1676
+ },
1677
+ using: {
1678
+ 'sub-comp': subComp.general(),
1679
+ },
1680
+ data: () => ({
1681
+ classes: 'static',
1682
+ extClass: 'a-class',
1683
+ }),
1684
+ template: tmpl(`
1685
+ <sub-comp class="{{classes}}" ext-class="{{extClass}}" />
1686
+ `),
1687
+ })
1688
+ .general()
1689
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1690
+ glassEasel.Element.pretendAttached(elem)
1691
+ expect(domHtml(elem)).toBe(
1692
+ '<sub-comp class="p--static"><div class="inner p--a-class"></div></sub-comp>',
1693
+ )
1694
+ matchElementWithDom(elem)
1695
+ elem.setData({
1696
+ classes: ['static', 'dynamic'],
1697
+ })
1698
+ expect(domHtml(elem)).toBe(
1699
+ '<sub-comp class="p--static p--dynamic"><div class="inner p--a-class"></div></sub-comp>',
1700
+ )
1701
+ matchElementWithDom(elem)
1702
+ elem.setData({
1703
+ classes: '',
1704
+ extClass: ['a-class', 'dynamic'],
1705
+ })
1706
+ expect(domHtml(elem)).toBe(
1707
+ '<sub-comp class=""><div class="inner p--a-class p--dynamic"></div></sub-comp>',
1708
+ )
1709
+ matchElementWithDom(elem)
1710
+ elem.setData({
1711
+ extClass: 'static',
1712
+ })
1713
+ expect(domHtml(elem)).toBe('<sub-comp class=""><div class="inner p--static"></div></sub-comp>')
1714
+ matchElementWithDom(elem)
1715
+ })
1716
+
1717
+ test('setting external classes', () => {
1718
+ const cs = new glassEasel.ComponentSpace(
1719
+ undefined,
1720
+ undefined,
1721
+ glassEasel.getDefaultComponentSpace().styleScopeManager,
1722
+ )
1723
+ const ssm = cs.styleScopeManager
1436
1724
  const subComp = cs.defineComponent({
1437
1725
  externalClasses: ['class', 'ext-class'],
1438
1726
  template: tmpl(`
@@ -1455,23 +1743,93 @@ describe('node tree structure', () => {
1455
1743
  `),
1456
1744
  })
1457
1745
  .general()
1458
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1746
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1459
1747
  glassEasel.Element.pretendAttached(elem)
1460
1748
  expect(domHtml(elem)).toBe(
1461
1749
  '<sub-comp class="p--static"><div class="p--static p--a-class"></div></sub-comp>',
1462
1750
  )
1751
+ matchElementWithDom(elem)
1463
1752
  elem.setData({
1464
1753
  dynamic: 'dynamic',
1465
1754
  })
1466
1755
  expect(domHtml(elem)).toBe(
1467
- '<sub-comp class="p--static p--dynamic"><div class="p--static p--dynamic p--a-class"></div></sub-comp>',
1756
+ '<sub-comp class="p--static p--dynamic"><div class="p--static p--a-class p--dynamic"></div></sub-comp>',
1468
1757
  )
1758
+ matchElementWithDom(elem)
1469
1759
  elem.setData({
1470
1760
  dynamic: '',
1471
1761
  })
1472
1762
  expect(domHtml(elem)).toBe(
1473
1763
  '<sub-comp class="p--static"><div class="p--static p--a-class"></div></sub-comp>',
1474
1764
  )
1765
+ matchElementWithDom(elem)
1766
+ })
1767
+
1768
+ test('setting nested external classes', () => {
1769
+ const cs = new glassEasel.ComponentSpace(
1770
+ undefined,
1771
+ undefined,
1772
+ glassEasel.getDefaultComponentSpace().styleScopeManager,
1773
+ )
1774
+ const ssm = cs.styleScopeManager
1775
+ const subComp = cs.defineComponent({
1776
+ externalClasses: ['class', 'ext-class'],
1777
+ template: tmpl(`
1778
+ <div class="class ext-class"></div>
1779
+ `),
1780
+ })
1781
+ const def = cs
1782
+ .defineComponent({
1783
+ options: {
1784
+ styleScope: ssm.register('p'),
1785
+ },
1786
+ using: {
1787
+ sub: subComp.general(),
1788
+ },
1789
+ properties: {
1790
+ dynamic: String,
1791
+ },
1792
+ externalClasses: ['a-class'],
1793
+ template: tmpl(`
1794
+ <sub class="static {{ dynamic || '' }}" ext-class="a-class" />
1795
+ `),
1796
+ })
1797
+ .general()
1798
+ const parent = cs.defineComponent({
1799
+ options: {
1800
+ styleScope: ssm.register('pp'),
1801
+ extraStyleScope: glassEasel.StyleScopeManager.globalScope(),
1802
+ },
1803
+ using: {
1804
+ def,
1805
+ },
1806
+ data: {
1807
+ dynamic1: '',
1808
+ dynamic2: '',
1809
+ },
1810
+ template: tmpl(`<def dynamic="{{dynamic1}}" a-class="root {{dynamic2}}" />`),
1811
+ })
1812
+ const elem = glassEasel.Component.createWithContext('root', parent, testBackend)
1813
+ glassEasel.Element.pretendAttached(elem)
1814
+ expect(domHtml(elem)).toBe(
1815
+ '<def><sub class="p--static"><div class="p--static root pp--root"></div></sub></def>',
1816
+ )
1817
+ matchElementWithDom(elem)
1818
+ elem.setData({
1819
+ dynamic1: 'dynamic',
1820
+ })
1821
+ expect(domHtml(elem)).toBe(
1822
+ '<def><sub class="p--static p--dynamic"><div class="p--static root pp--root p--dynamic"></div></sub></def>',
1823
+ )
1824
+ matchElementWithDom(elem)
1825
+ elem.setData({
1826
+ dynamic1: '',
1827
+ dynamic2: 'dynamic',
1828
+ })
1829
+ expect(domHtml(elem)).toBe(
1830
+ '<def><sub class="p--static"><div class="p--static root pp--root dynamic pp--dynamic"></div></sub></def>',
1831
+ )
1832
+ matchElementWithDom(elem)
1475
1833
  })
1476
1834
 
1477
1835
  test('pass object to child components', () => {
@@ -1506,9 +1864,10 @@ describe('node tree structure', () => {
1506
1864
  },
1507
1865
  })
1508
1866
  .general()
1509
- const elem = glassEasel.Component.createWithContext('root', def, domBackend)
1867
+ const elem = glassEasel.Component.createWithContext('root', def, testBackend)
1510
1868
  glassEasel.Element.pretendAttached(elem)
1511
1869
  expect(domHtml(elem)).toBe('<sub-comp><div class="a1"></div></sub-comp>')
1870
+ matchElementWithDom(elem)
1512
1871
  expect(ops).toBe(1)
1513
1872
  elem.setData({
1514
1873
  'obj.b': 'b1',
@@ -1522,6 +1881,90 @@ describe('node tree structure', () => {
1522
1881
  obj: { a: 'a2' },
1523
1882
  })
1524
1883
  expect(domHtml(elem)).toBe('<sub-comp><div class="a2"></div></sub-comp>')
1884
+ matchElementWithDom(elem)
1525
1885
  expect(ops).toBe(3)
1526
1886
  })
1527
- })
1887
+
1888
+ test('recursive component', () => {
1889
+ const cs = new glassEasel.ComponentSpace()
1890
+ cs.updateComponentOptions({
1891
+ writeFieldsToNode: false,
1892
+ })
1893
+ type INode = {
1894
+ className: string
1895
+ childNodes: INode[]
1896
+ before?: string
1897
+ after?: string
1898
+ }
1899
+ const Node = cs
1900
+ .define('node')
1901
+ .options({
1902
+ virtualHost: true,
1903
+ dataDeepCopy: glassEasel.DeepCopyKind.None,
1904
+ propertyPassingDeepCopy: glassEasel.DeepCopyKind.None,
1905
+ })
1906
+ .property('childNodes', {
1907
+ type: Array,
1908
+ default: () => [] as INode[],
1909
+ })
1910
+ .externalClasses(['class'])
1911
+ .template(
1912
+ tmpl(`
1913
+ <div class="class">
1914
+ <block wx:for="{{childNodes}}">
1915
+ <block wx:if="{{item.before}}">{{item.before}}</block>
1916
+ <node child-nodes="{{item.childNodes}}" class="{{item.className}}" />
1917
+ <block wx:if="{{item.after}}">{{item.after}}</block>
1918
+ </block>
1919
+ </div>
1920
+ `),
1921
+ )
1922
+ .registerComponent()
1923
+ cs.setGlobalUsingComponent('node', Node.general())
1924
+ const Parent = cs
1925
+ .define()
1926
+ .usingComponents({ node: Node })
1927
+ .options({
1928
+ dataDeepCopy: glassEasel.DeepCopyKind.None,
1929
+ propertyPassingDeepCopy: glassEasel.DeepCopyKind.None,
1930
+ })
1931
+ .template(
1932
+ tmpl(`
1933
+ <node child-nodes="{{node.childNodes}}" class="{{node.className}}" />
1934
+ `),
1935
+ )
1936
+ .data(() => ({
1937
+ node: {
1938
+ className: 'root',
1939
+ childNodes: [
1940
+ {
1941
+ className: 'c1',
1942
+ childNodes: [
1943
+ {
1944
+ className: 'c11',
1945
+ childNodes: [],
1946
+ before: '[',
1947
+ after: ']',
1948
+ },
1949
+ ],
1950
+ },
1951
+ {
1952
+ className: 'c2',
1953
+ childNodes: [],
1954
+ },
1955
+ ],
1956
+ } satisfies INode,
1957
+ }))
1958
+ .registerComponent()
1959
+ const elem = glassEasel.Component.createWithContext('root', Parent, testBackend)
1960
+ glassEasel.Element.pretendAttached(elem)
1961
+ expect(domHtml(elem)).toBe(
1962
+ '<div class="root"><div class="c1">[<div class="c11"></div>]</div><div class="c2"></div></div>',
1963
+ )
1964
+ matchElementWithDom(elem)
1965
+ })
1966
+ }
1967
+
1968
+ describe('node tree structure (DOM backend)', () => testCases(domBackend))
1969
+ describe('node tree structure (shadow backend)', () => testCases(shadowBackend))
1970
+ describe('node tree structure (composed backend)', () => testCases(composedBackend))