glass-easel 0.1.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 (237) hide show
  1. package/README.md +40 -0
  2. package/dist/glass_easel.all.d.ts +1 -0
  3. package/dist/glass_easel.all.js +2 -0
  4. package/dist/glass_easel.all.js.map +1 -0
  5. package/dist/glass_easel.domlike.global.d.ts +1 -0
  6. package/dist/glass_easel.domlike.global.js +2 -0
  7. package/dist/glass_easel.domlike.global.js.map +1 -0
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.js +1 -0
  10. package/dist/types/src/backend/backend_protocol.d.ts +119 -0
  11. package/dist/types/src/backend/backend_protocol.d.ts.map +1 -0
  12. package/dist/types/src/backend/composed_backend_protocol.d.ts +90 -0
  13. package/dist/types/src/backend/composed_backend_protocol.d.ts.map +1 -0
  14. package/dist/types/src/backend/domlike_backend_protocol.d.ts +76 -0
  15. package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +1 -0
  16. package/dist/types/src/backend/mode.d.ts +46 -0
  17. package/dist/types/src/backend/mode.d.ts.map +1 -0
  18. package/dist/types/src/backend/suggested_backend_protocol.d.ts +30 -0
  19. package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +1 -0
  20. package/dist/types/src/behavior.d.ts +428 -0
  21. package/dist/types/src/behavior.d.ts.map +1 -0
  22. package/dist/types/src/class_list.d.ts +79 -0
  23. package/dist/types/src/class_list.d.ts.map +1 -0
  24. package/dist/types/src/component.d.ts +291 -0
  25. package/dist/types/src/component.d.ts.map +1 -0
  26. package/dist/types/src/component_params.d.ts +239 -0
  27. package/dist/types/src/component_params.d.ts.map +1 -0
  28. package/dist/types/src/component_space.d.ts +164 -0
  29. package/dist/types/src/component_space.d.ts.map +1 -0
  30. package/dist/types/src/data_path.d.ts +5 -0
  31. package/dist/types/src/data_path.d.ts.map +1 -0
  32. package/dist/types/src/data_proxy.d.ts +107 -0
  33. package/dist/types/src/data_proxy.d.ts.map +1 -0
  34. package/dist/types/src/data_utils.d.ts +3 -0
  35. package/dist/types/src/data_utils.d.ts.map +1 -0
  36. package/dist/types/src/element.d.ts +275 -0
  37. package/dist/types/src/element.d.ts.map +1 -0
  38. package/dist/types/src/element_iterator.d.ts +43 -0
  39. package/dist/types/src/element_iterator.d.ts.map +1 -0
  40. package/dist/types/src/event.d.ts +104 -0
  41. package/dist/types/src/event.d.ts.map +1 -0
  42. package/dist/types/src/external_shadow_tree.d.ts +20 -0
  43. package/dist/types/src/external_shadow_tree.d.ts.map +1 -0
  44. package/dist/types/src/func_arr.d.ts +39 -0
  45. package/dist/types/src/func_arr.d.ts.map +1 -0
  46. package/dist/types/src/global_options.d.ts +111 -0
  47. package/dist/types/src/global_options.d.ts.map +1 -0
  48. package/dist/types/src/index.d.ts +43 -0
  49. package/dist/types/src/index.d.ts.map +1 -0
  50. package/dist/types/src/mutation_observer.d.ts +79 -0
  51. package/dist/types/src/mutation_observer.d.ts.map +1 -0
  52. package/dist/types/src/native_node.d.ts +8 -0
  53. package/dist/types/src/native_node.d.ts.map +1 -0
  54. package/dist/types/src/node.d.ts +49 -0
  55. package/dist/types/src/node.d.ts.map +1 -0
  56. package/dist/types/src/relation.d.ts +47 -0
  57. package/dist/types/src/relation.d.ts.map +1 -0
  58. package/dist/types/src/render.d.ts +3 -0
  59. package/dist/types/src/render.d.ts.map +1 -0
  60. package/dist/types/src/selector.d.ts +32 -0
  61. package/dist/types/src/selector.d.ts.map +1 -0
  62. package/dist/types/src/shadow_root.d.ts +136 -0
  63. package/dist/types/src/shadow_root.d.ts.map +1 -0
  64. package/dist/types/src/template_engine.d.ts +18 -0
  65. package/dist/types/src/template_engine.d.ts.map +1 -0
  66. package/dist/types/src/text_node.d.ts +32 -0
  67. package/dist/types/src/text_node.d.ts.map +1 -0
  68. package/dist/types/src/tmpl/index.d.ts +18 -0
  69. package/dist/types/src/tmpl/index.d.ts.map +1 -0
  70. package/dist/types/src/tmpl/native_rendering.d.ts +45 -0
  71. package/dist/types/src/tmpl/native_rendering.d.ts.map +1 -0
  72. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +80 -0
  73. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +1 -0
  74. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +50 -0
  75. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +1 -0
  76. package/dist/types/src/tmpl/range_list_diff.d.ts +19 -0
  77. package/dist/types/src/tmpl/range_list_diff.d.ts.map +1 -0
  78. package/dist/types/src/trait_behaviors.d.ts +38 -0
  79. package/dist/types/src/trait_behaviors.d.ts.map +1 -0
  80. package/dist/types/src/virtual_node.d.ts +10 -0
  81. package/dist/types/src/virtual_node.d.ts.map +1 -0
  82. package/dist/types/tests/backend/domlike.test.d.ts +2 -0
  83. package/dist/types/tests/backend/domlike.test.d.ts.map +1 -0
  84. package/dist/types/tests/base/env.d.ts +29 -0
  85. package/dist/types/tests/base/env.d.ts.map +1 -0
  86. package/dist/types/tests/base/match.d.ts +9 -0
  87. package/dist/types/tests/base/match.d.ts.map +1 -0
  88. package/dist/types/tests/core/backend.test.d.ts +2 -0
  89. package/dist/types/tests/core/backend.test.d.ts.map +1 -0
  90. package/dist/types/tests/core/behavior.test.d.ts +2 -0
  91. package/dist/types/tests/core/behavior.test.d.ts.map +1 -0
  92. package/dist/types/tests/core/component_space.test.d.ts +2 -0
  93. package/dist/types/tests/core/component_space.test.d.ts.map +1 -0
  94. package/dist/types/tests/core/data_update.test.d.ts +2 -0
  95. package/dist/types/tests/core/data_update.test.d.ts.map +1 -0
  96. package/dist/types/tests/core/misc.test.d.ts +2 -0
  97. package/dist/types/tests/core/misc.test.d.ts.map +1 -0
  98. package/dist/types/tests/core/placeholder.test.d.ts +2 -0
  99. package/dist/types/tests/core/placeholder.test.d.ts.map +1 -0
  100. package/dist/types/tests/core/slot.test.d.ts +2 -0
  101. package/dist/types/tests/core/slot.test.d.ts.map +1 -0
  102. package/dist/types/tests/core/trait_behaviors.test.d.ts +2 -0
  103. package/dist/types/tests/core/trait_behaviors.test.d.ts.map +1 -0
  104. package/dist/types/tests/tmpl/binding_map.test.d.ts +2 -0
  105. package/dist/types/tests/tmpl/binding_map.test.d.ts.map +1 -0
  106. package/dist/types/tests/tmpl/event.test.d.ts +2 -0
  107. package/dist/types/tests/tmpl/event.test.d.ts.map +1 -0
  108. package/dist/types/tests/tmpl/expression.test.d.ts +2 -0
  109. package/dist/types/tests/tmpl/expression.test.d.ts.map +1 -0
  110. package/dist/types/tests/tmpl/lvalue.test.d.ts +2 -0
  111. package/dist/types/tests/tmpl/lvalue.test.d.ts.map +1 -0
  112. package/dist/types/tests/tmpl/native_rendering.test.d.ts +2 -0
  113. package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +1 -0
  114. package/dist/types/tests/tmpl/structure.test.d.ts +2 -0
  115. package/dist/types/tests/tmpl/structure.test.d.ts.map +1 -0
  116. package/dist/types/tests/types/chaining.test.d.ts +2 -0
  117. package/dist/types/tests/types/chaining.test.d.ts.map +1 -0
  118. package/dist/types/tests/types/createElement.test.d.ts +2 -0
  119. package/dist/types/tests/types/createElement.test.d.ts.map +1 -0
  120. package/dist/types/tests/types/definition.test.d.ts +2 -0
  121. package/dist/types/tests/types/definition.test.d.ts.map +1 -0
  122. package/guide/zh_CN/advanced/binding_map_update.md +32 -0
  123. package/guide/zh_CN/advanced/build_args.md +28 -0
  124. package/guide/zh_CN/advanced/component_filter.md +70 -0
  125. package/guide/zh_CN/advanced/component_space.md +124 -0
  126. package/guide/zh_CN/advanced/custom_backend.md +53 -0
  127. package/guide/zh_CN/advanced/error_listener.md +32 -0
  128. package/guide/zh_CN/advanced/external_component.md +73 -0
  129. package/guide/zh_CN/advanced/template_engine.md +61 -0
  130. package/guide/zh_CN/appendix/backend_protocol.md +501 -0
  131. package/guide/zh_CN/appendix/list_diff_algorithm.md +406 -0
  132. package/guide/zh_CN/basic/beginning.md +94 -0
  133. package/guide/zh_CN/basic/component.md +156 -0
  134. package/guide/zh_CN/basic/event.md +169 -0
  135. package/guide/zh_CN/basic/lifetime.md +66 -0
  136. package/guide/zh_CN/basic/method.md +62 -0
  137. package/guide/zh_CN/basic/template.md +135 -0
  138. package/guide/zh_CN/data_management/advanced_update.md +170 -0
  139. package/guide/zh_CN/data_management/data_deep_copy.md +157 -0
  140. package/guide/zh_CN/data_management/data_observer.md +154 -0
  141. package/guide/zh_CN/data_management/property_early_init.md +31 -0
  142. package/guide/zh_CN/data_management/pure_data_pattern.md +21 -0
  143. package/guide/zh_CN/index.md +93 -0
  144. package/guide/zh_CN/interaction/behavior.md +52 -0
  145. package/guide/zh_CN/interaction/component_path.md +37 -0
  146. package/guide/zh_CN/interaction/generic.md +73 -0
  147. package/guide/zh_CN/interaction/placeholder.md +40 -0
  148. package/guide/zh_CN/interaction/relation.md +151 -0
  149. package/guide/zh_CN/interaction/slot.md +137 -0
  150. package/guide/zh_CN/interaction/template_import.md +94 -0
  151. package/guide/zh_CN/interaction/trait_behavior.md +117 -0
  152. package/guide/zh_CN/styling/external_class.md +46 -0
  153. package/guide/zh_CN/styling/style_isolation.md +54 -0
  154. package/guide/zh_CN/styling/virtual_host.md +52 -0
  155. package/guide/zh_CN/tree/element_iterator.md +54 -0
  156. package/guide/zh_CN/tree/mutation_observer.md +52 -0
  157. package/guide/zh_CN/tree/node_tree.md +142 -0
  158. package/guide/zh_CN/tree/node_tree_modification.md +78 -0
  159. package/guide/zh_CN/tree/selector.md +66 -0
  160. package/jest.config.js +6 -0
  161. package/jest.dts.config.js +9 -0
  162. package/jest.unit.config.js +14 -0
  163. package/package.json +28 -0
  164. package/src/backend/backend_protocol.ts +313 -0
  165. package/src/backend/composed_backend_protocol.ts +252 -0
  166. package/src/backend/domlike_backend_protocol.ts +370 -0
  167. package/src/backend/mode.ts +51 -0
  168. package/src/backend/suggested_backend_protocol.ts +83 -0
  169. package/src/behavior.ts +1655 -0
  170. package/src/bootstrap_dom_dev.js +22 -0
  171. package/src/class_list.ts +376 -0
  172. package/src/component.ts +1309 -0
  173. package/src/component_params.ts +461 -0
  174. package/src/component_space.ts +547 -0
  175. package/src/data_path.ts +225 -0
  176. package/src/data_proxy.ts +670 -0
  177. package/src/data_utils.ts +50 -0
  178. package/src/element.ts +1966 -0
  179. package/src/element_iterator.ts +158 -0
  180. package/src/event.ts +401 -0
  181. package/src/external_shadow_tree.ts +27 -0
  182. package/src/func_arr.ts +198 -0
  183. package/src/global_options.ts +242 -0
  184. package/src/index.ts +187 -0
  185. package/src/mutation_observer.ts +252 -0
  186. package/src/native_node.ts +74 -0
  187. package/src/node.ts +174 -0
  188. package/src/relation.ts +380 -0
  189. package/src/render.ts +25 -0
  190. package/src/selector.ts +218 -0
  191. package/src/shadow_root.ts +766 -0
  192. package/src/template_engine.ts +45 -0
  193. package/src/text_node.ts +149 -0
  194. package/src/tmpl/index.ts +199 -0
  195. package/src/tmpl/native_rendering.ts +175 -0
  196. package/src/tmpl/proc_gen_wrapper.ts +954 -0
  197. package/src/tmpl/proc_gen_wrapper_dom.ts +230 -0
  198. package/src/tmpl/range_list_diff.ts +443 -0
  199. package/src/trait_behaviors.ts +51 -0
  200. package/src/virtual_node.ts +51 -0
  201. package/tests/backend/domlike.test.ts +254 -0
  202. package/tests/base/env.ts +78 -0
  203. package/tests/base/match.ts +185 -0
  204. package/tests/core/backend.test.ts +144 -0
  205. package/tests/core/behavior.test.ts +546 -0
  206. package/tests/core/component_space.test.ts +212 -0
  207. package/tests/core/data_update.test.ts +461 -0
  208. package/tests/core/misc.test.ts +339 -0
  209. package/tests/core/placeholder.test.ts +180 -0
  210. package/tests/core/slot.test.ts +1495 -0
  211. package/tests/core/trait_behaviors.test.ts +153 -0
  212. package/tests/legacy/README.md +3 -0
  213. package/tests/legacy/behavior.test.js +293 -0
  214. package/tests/legacy/component.test.js +1247 -0
  215. package/tests/legacy/data_path.test.js +149 -0
  216. package/tests/legacy/data_proxy.test.js +759 -0
  217. package/tests/legacy/element_iterator.test.js +148 -0
  218. package/tests/legacy/event.test.js +849 -0
  219. package/tests/legacy/external.test.js +510 -0
  220. package/tests/legacy/extra_info.test.js +109 -0
  221. package/tests/legacy/generics.test.js +176 -0
  222. package/tests/legacy/mutation_observer.test.js +210 -0
  223. package/tests/legacy/relation.test.js +517 -0
  224. package/tests/legacy/selector.test.js +263 -0
  225. package/tests/legacy/slot.test.js +915 -0
  226. package/tests/legacy/virtual.test.js +394 -0
  227. package/tests/tmpl/binding_map.test.ts +208 -0
  228. package/tests/tmpl/event.test.ts +206 -0
  229. package/tests/tmpl/expression.test.ts +429 -0
  230. package/tests/tmpl/lvalue.test.ts +160 -0
  231. package/tests/tmpl/native_rendering.test.ts +155 -0
  232. package/tests/tmpl/structure.test.ts +998 -0
  233. package/tests/types/chaining.test.ts +614 -0
  234. package/tests/types/createElement.test.ts +82 -0
  235. package/tests/types/definition.test.ts +442 -0
  236. package/tsconfig.json +11 -0
  237. package/webpack.config.js +270 -0
@@ -0,0 +1,212 @@
1
+ import * as glassEasel from '../../src'
2
+ import {
3
+ composedBackend, tmpl,
4
+ } from '../base/env'
5
+
6
+ describe('Component Space', () => {
7
+ test('update and get component options', () => {
8
+ const cs = new glassEasel.ComponentSpace()
9
+ const fakeTmplEngine = {} as glassEasel.templateEngine.TemplateEngine
10
+ cs.updateComponentOptions({
11
+ templateEngine: fakeTmplEngine,
12
+ })
13
+ expect(cs.getComponentOptions().templateEngine).toBe(fakeTmplEngine)
14
+ })
15
+
16
+ test('create with default component specified', () => {
17
+ const cs = new glassEasel.ComponentSpace('def')
18
+ const def = cs.defineComponent({ is: 'def' })
19
+ expect(cs.getDefaultComponent()).toBe(def)
20
+ expect(cs.isDefaultComponent(def)).toBe(true)
21
+ expect(cs.getComponentByUrl('not/found', '')).toBe(def)
22
+ })
23
+
24
+ test('search component with relative and absolute paths', () => {
25
+ const cs = new glassEasel.ComponentSpace()
26
+ const def = cs.defineComponent({ is: 'a/comp' })
27
+ expect(cs.getComponentByUrl('comp', 'a/test')).toBe(def)
28
+ expect(cs.getComponentByUrl('./comp', 'a/test')).toBe(def)
29
+ expect(cs.getComponentByUrl('../a/comp', 'a/test')).toBe(def)
30
+ expect(cs.getComponentByUrl('../a/./comp', 'a/test')).toBe(def)
31
+ expect(cs.getComponentByUrl('../../a/comp', 'a/test')).toBe(def)
32
+ expect(cs.getComponentByUrl('/a/comp', 'a/test')).toBe(def)
33
+ expect(cs.getComponentByUrl('/a/../a/comp', 'a/test')).toBe(def)
34
+ expect(cs.getComponentByUrlWithoutDefault('/comp', 'a/test')).toBe(null)
35
+ })
36
+
37
+ test('create with base space', () => {
38
+ const baseCs = new glassEasel.ComponentSpace()
39
+ const baseBeh = baseCs.defineBehavior({ is: 'base/beh/inner' })
40
+ baseCs.exportBehavior('base/beh', 'base/beh/inner')
41
+ const baseComp = baseCs.defineComponent({ is: 'base/comp/inner' })
42
+ baseCs.exportComponent('base/comp', 'base/comp/inner')
43
+ const cs = new glassEasel.ComponentSpace('', baseCs)
44
+ const baseBeh2 = baseCs.defineBehavior({ is: 'base/beh/inner2' })
45
+ baseCs.exportBehavior('base/beh2', 'base/beh/inner2')
46
+ const baseComp2 = baseCs.defineComponent({ is: 'base/comp/inner2' })
47
+ baseCs.exportComponent('base/comp2', 'base/comp/inner2')
48
+ expect(cs.getBehaviorByUrl('base/beh', '')).toBe(baseBeh)
49
+ expect(baseCs.getBehaviorByUrl('base/beh/inner2', '')).toBe(baseBeh2)
50
+ expect(baseCs.getBehaviorByUrl('base/beh2', '')).toBe(null)
51
+ expect(cs.getBehaviorByUrl('base/beh2', '')).toBe(null)
52
+ expect(cs.getComponentByUrl('base/comp', '')).toBe(baseComp)
53
+ expect(baseCs.getComponentByUrlWithoutDefault('base/comp/inner2', '')).toBe(baseComp2)
54
+ expect(baseCs.getComponentByUrlWithoutDefault('base/comp2', '')).toBe(null)
55
+ expect(cs.getComponentByUrlWithoutDefault('base/comp2', '')).toBe(null)
56
+ const newBeh = cs.defineBehavior({ is: 'base/beh' })
57
+ const newComp = cs.defineComponent({ is: 'base/comp' })
58
+ expect(cs.getBehaviorByUrl('base/beh', '')).toBe(newBeh)
59
+ expect(cs.getComponentByUrl('base/comp', '')).toBe(newComp)
60
+ cs.updateBaseSpace(baseCs)
61
+ expect(cs.getBehaviorByUrl('base/beh', '')).toBe(newBeh)
62
+ expect(cs.getComponentByUrl('base/comp', '')).toBe(newComp)
63
+ expect(cs.getBehaviorByUrl('base/beh2', '')).toBe(baseBeh2)
64
+ expect(cs.getComponentByUrl('base/comp2', '')).toBe(baseComp2)
65
+ })
66
+
67
+ test('share style scope manager', () => {
68
+ const cs1 = new glassEasel.ComponentSpace()
69
+ const cs2 = new glassEasel.ComponentSpace(undefined, undefined, cs1.styleScopeManager)
70
+ const scope1 = cs1.styleScopeManager.register('a')
71
+ const scope2 = cs2.styleScopeManager.register('b')
72
+ expect(cs1.styleScopeManager).toBe(cs2.styleScopeManager)
73
+ expect(scope1 === scope2).toBe(false)
74
+ expect(cs2.styleScopeManager.queryName(scope1)).toBe('a')
75
+ expect(cs1.styleScopeManager.queryName(scope2)).toBe('b')
76
+ })
77
+
78
+ test('import space (public use)', () => {
79
+ const mainCs = new glassEasel.ComponentSpace()
80
+ const mainComp = mainCs.defineComponent({ is: 'main/comp' })
81
+ const mainBeh = mainCs.defineBehavior({ is: 'main/beh' })
82
+ const extraCs = new glassEasel.ComponentSpace()
83
+ const extraComp1 = extraCs.defineComponent({ is: 'inner/comp1' })
84
+ const extraBeh1 = extraCs.defineBehavior({ is: 'inner/beh1' })
85
+ extraCs.exportComponent('outer/comp1', 'inner/comp1')
86
+ extraCs.exportBehavior('outer/beh1', 'inner/beh1')
87
+ mainCs.importSpace('space://extra', extraCs, false)
88
+ expect(mainCs.getComponentByUrlWithoutDefault('main/comp', '')).toBe(mainComp)
89
+ expect(mainCs.getComponentByUrlWithoutDefault('outer/comp1', '')).toBe(null)
90
+ expect(mainCs.getComponentByUrlWithoutDefault('space://extra/inner/comp1', '')).toBe(null)
91
+ expect(mainCs.getComponentByUrlWithoutDefault('space://extra/outer/comp1', '')).toBe(extraComp1)
92
+ expect(mainCs.getBehaviorByUrl('main/beh', '')).toBe(mainBeh)
93
+ expect(mainCs.getBehaviorByUrl('outer/beh1', '')).toBe(null)
94
+ expect(mainCs.getBehaviorByUrl('space://extra/inner/beh1', '')).toBe(null)
95
+ expect(mainCs.getBehaviorByUrl('space://extra/outer/beh1', '')).toBe(extraBeh1)
96
+ const extraComp2 = extraCs.defineComponent({ is: 'inner/comp2' })
97
+ const extraBeh2 = extraCs.defineBehavior({ is: 'inner/beh2' })
98
+ extraCs.exportComponent('outer/comp2', 'inner/comp2')
99
+ extraCs.exportBehavior('outer/beh2', 'inner/beh2')
100
+ expect(mainCs.getComponentByUrlWithoutDefault('outer/comp2', '')).toBe(null)
101
+ expect(mainCs.getComponentByUrlWithoutDefault('space://extra/inner/comp2', '')).toBe(null)
102
+ expect(mainCs.getComponentByUrlWithoutDefault('space://extra/outer/comp2', '')).toBe(extraComp2)
103
+ expect(mainCs.getBehaviorByUrl('outer/beh2', '')).toBe(null)
104
+ expect(mainCs.getBehaviorByUrl('space://extra/inner/beh2', '')).toBe(null)
105
+ expect(mainCs.getBehaviorByUrl('space://extra/outer/beh2', '')).toBe(extraBeh2)
106
+ })
107
+
108
+ test('import space (private use)', () => {
109
+ const mainCs = new glassEasel.ComponentSpace()
110
+ const mainComp = mainCs.defineComponent({ is: 'main/comp' })
111
+ const mainBeh = mainCs.defineBehavior({ is: 'main/beh' })
112
+ const extraCs = new glassEasel.ComponentSpace()
113
+ const extraComp1 = extraCs.defineComponent({ is: 'inner/comp1' })
114
+ const extraBeh1 = extraCs.defineBehavior({ is: 'inner/beh1' })
115
+ extraCs.exportComponent('outer/comp1', 'inner/comp1')
116
+ extraCs.exportBehavior('outer/beh1', 'inner/beh1')
117
+ mainCs.importSpace('space://', extraCs, true)
118
+ expect(mainCs.getComponentByUrlWithoutDefault('main/comp', '')).toBe(mainComp)
119
+ expect(mainCs.getComponentByUrlWithoutDefault('inner/comp1', '')).toBe(null)
120
+ expect(mainCs.getComponentByUrlWithoutDefault('space:///inner/comp1', '')).toBe(extraComp1)
121
+ expect(mainCs.getComponentByUrlWithoutDefault('space:///outer/comp1', '')).toBe(null)
122
+ expect(mainCs.getBehaviorByUrl('main/beh', '')).toBe(mainBeh)
123
+ expect(mainCs.getBehaviorByUrl('inner/beh1', '')).toBe(null)
124
+ expect(mainCs.getBehaviorByUrl('space:///inner/beh1', '')).toBe(extraBeh1)
125
+ expect(mainCs.getBehaviorByUrl('space:///outer/beh1', '')).toBe(null)
126
+ const extraComp2 = extraCs.defineComponent({ is: 'inner/comp2' })
127
+ const extraBeh2 = extraCs.defineBehavior({ is: 'inner/beh2' })
128
+ extraCs.exportComponent('outer/comp2', 'inner/comp2')
129
+ extraCs.exportBehavior('outer/beh2', 'inner/beh2')
130
+ expect(mainCs.getComponentByUrlWithoutDefault('inner/comp2', '')).toBe(null)
131
+ expect(mainCs.getComponentByUrlWithoutDefault('space:///inner/comp2', '')).toBe(extraComp2)
132
+ expect(mainCs.getComponentByUrlWithoutDefault('space:///outer/comp2', '')).toBe(null)
133
+ expect(mainCs.getBehaviorByUrl('inner/beh2', '')).toBe(null)
134
+ expect(mainCs.getBehaviorByUrl('space:///inner/beh2', '')).toBe(extraBeh2)
135
+ expect(mainCs.getBehaviorByUrl('space:///outer/beh2', '')).toBe(null)
136
+ })
137
+
138
+ test('import space (tricky URLs)', () => {
139
+ const mainCs = new glassEasel.ComponentSpace()
140
+ const extraCs = new glassEasel.ComponentSpace()
141
+ const extraComp = extraCs.defineComponent({ is: 'comp' })
142
+ mainCs.importSpace('space://', extraCs, true)
143
+ expect(mainCs.getComponentByUrlWithoutDefault('space://comp', '')).toBe(extraComp)
144
+ })
145
+
146
+ test('create component with URL params (without generics)', () => {
147
+ const cs = new glassEasel.ComponentSpace()
148
+ const compDef = cs.defineComponent({
149
+ is: 'comp/path',
150
+ properties: {
151
+ propA: {
152
+ type: String,
153
+ value: 'init',
154
+ },
155
+ propB: Number,
156
+ propC: Boolean,
157
+ },
158
+ data: {
159
+ dataD: 456,
160
+ },
161
+ })
162
+ const comp = cs.createComponentByUrl(
163
+ 'root',
164
+ '/comp/path?propC=1&propA&propB=3.4&dataD=789',
165
+ null,
166
+ composedBackend,
167
+ ).asInstanceOf(compDef)!
168
+ expect(comp.data.propA).toBe('init')
169
+ expect(comp.data.propB).toBe(3.4)
170
+ expect(comp.data.propC).toBe(true)
171
+ expect(comp.data.dataD).toBe(456)
172
+ })
173
+
174
+ test('create component with URL params (with generics)', () => {
175
+ const cs = new glassEasel.ComponentSpace()
176
+ const childCompDef = cs.defineComponent({
177
+ is: 'comp/child',
178
+ properties: {
179
+ pc: null,
180
+ },
181
+ })
182
+ const compDef = cs.defineComponent({
183
+ is: 'comp/parent',
184
+ properties: {
185
+ pp: Number,
186
+ },
187
+ generics: {
188
+ ga: true,
189
+ gb: {
190
+ default: 'child',
191
+ },
192
+ },
193
+ template: tmpl(`
194
+ <ga id="a" pc="{{pp}}" />
195
+ <gb id="b" pc="{{pp}}" />
196
+ `),
197
+ })
198
+ const comp = cs.createComponentByUrl(
199
+ 'root',
200
+ '/comp/parent?pp=123',
201
+ {
202
+ ga: 'comp/child',
203
+ },
204
+ composedBackend,
205
+ ).asInstanceOf(compDef)!
206
+ expect(comp.data.pp).toBe(123)
207
+ const a = (comp.$.a as glassEasel.GeneralComponent).asInstanceOf(childCompDef)!
208
+ const b = (comp.$.b as glassEasel.GeneralComponent).asInstanceOf(childCompDef)!
209
+ expect(a.data.pc).toBe(123)
210
+ expect(b.data.pc).toBe(123)
211
+ })
212
+ })
@@ -0,0 +1,461 @@
1
+ import {
2
+ domBackend,
3
+ execWithWarn,
4
+ tmpl,
5
+ } from '../base/env'
6
+ import * as glassEasel from '../../src'
7
+
8
+ const componentSpace = new glassEasel.ComponentSpace()
9
+ componentSpace.updateComponentOptions({
10
+ writeFieldsToNode: true,
11
+ writeIdToDOM: true,
12
+ })
13
+ componentSpace.defineComponent({
14
+ is: '',
15
+ })
16
+
17
+ describe('partial update', () => {
18
+ test('should be able to merge updates', () => {
19
+ const compDef = componentSpace.define()
20
+ .data(() => ({
21
+ a: 123,
22
+ b: 'abc',
23
+ }))
24
+ .registerComponent()
25
+ const comp = glassEasel.Component.createWithContext('root', compDef, domBackend)
26
+ comp.updateData({ a: 456 })
27
+ expect(comp.data.a).toBe(123)
28
+ comp.applyDataUpdates()
29
+ expect(comp.data.a).toBe(456)
30
+ expect(comp.data.b).toBe('abc')
31
+ comp.groupUpdates(() => {
32
+ comp.updateData({ b: 'def' })
33
+ comp.updateData({ a: 789 })
34
+ })
35
+ expect(comp.data).toStrictEqual({ a: 789, b: 'def' })
36
+ })
37
+
38
+ test('should be able to replace subfields', () => {
39
+ const execArr = [] as string[]
40
+ const childCompDef = componentSpace.define()
41
+ .property('p', String)
42
+ .lifetime('attached', function () {
43
+ execArr.push(this.data.p)
44
+ })
45
+ .registerComponent()
46
+ const compDef = componentSpace.define()
47
+ .usingComponents({
48
+ child: childCompDef.general(),
49
+ })
50
+ .template(tmpl(`
51
+ <child id="c" p="{{obj.a}}" />
52
+ `))
53
+ .data(() => ({
54
+ obj: { a: 123 },
55
+ }))
56
+ .methods({
57
+ setA() {
58
+ this.groupUpdates(() => {
59
+ this.replaceDataOnPath(['obj', 'a'], 456)
60
+ })
61
+ },
62
+ })
63
+ .registerComponent()
64
+ const comp = glassEasel.Component.createWithContext('root', compDef, domBackend)
65
+ glassEasel.Element.pretendAttached(comp)
66
+ const child = comp.getShadowRoot()!.getElementById('c')!.asInstanceOf(childCompDef)!
67
+ expect(comp.data.obj.a).toBe(123)
68
+ expect(child.data.p).toBe('123')
69
+ comp.setA()
70
+ expect(comp.data.obj.a).toBe(456)
71
+ expect(child.data.p).toBe('456')
72
+ comp.replaceDataOnPath(['obj'], { a: 789 })
73
+ expect(comp.data.obj.a).toBe(456)
74
+ expect(child.data.p).toBe('456')
75
+ comp.applyDataUpdates()
76
+ expect(comp.data.obj.a).toBe(789)
77
+ expect(child.data.p).toBe('789')
78
+ expect(execArr).toStrictEqual(['123'])
79
+ })
80
+
81
+ test('should be able to update list fields (without key)', () => {
82
+ let execArr = [] as string[]
83
+ const childCompDef = componentSpace.define()
84
+ .property('p', String)
85
+ .observer('p', function () {
86
+ execArr.push(this.data.p)
87
+ })
88
+ .registerComponent()
89
+ const compDef = componentSpace.define()
90
+ .usingComponents({
91
+ child: childCompDef.general(),
92
+ })
93
+ .template(tmpl(`
94
+ <child wx:for="{{list}}" p="{{item}}" />
95
+ `))
96
+ .data(() => ({
97
+ list: ['A', 'B', 'C'],
98
+ }))
99
+ .registerComponent()
100
+ const comp = glassEasel.Component.createWithContext('root', compDef, domBackend)
101
+ glassEasel.Element.pretendAttached(comp)
102
+ const getP = () => {
103
+ const ret = [] as string[]
104
+ comp.getShadowRoot()!.childNodes[0]!.asElement()!.childNodes.forEach((child) => {
105
+ ret.push(child.asElement()!.childNodes[0]!.asInstanceOf(childCompDef)!.data.p)
106
+ })
107
+ return ret
108
+ }
109
+ expect(getP()).toStrictEqual(['A', 'B', 'C'])
110
+ expect(execArr).toStrictEqual(['A', 'B', 'C'])
111
+ execArr = []
112
+ comp.groupUpdates(() => {
113
+ comp.replaceDataOnPath(['list', 1], 'D')
114
+ })
115
+ expect(getP()).toStrictEqual(['A', 'D', 'C'])
116
+ expect(execArr).toStrictEqual(['D'])
117
+ })
118
+
119
+ test('should be able to update list fields (with key)', () => {
120
+ let execArr = [] as string[]
121
+ const childCompDef = componentSpace.define()
122
+ .property('p', String)
123
+ .observer('p', function () {
124
+ execArr.push(this.data.p)
125
+ })
126
+ .registerComponent()
127
+ const compDef = componentSpace.define()
128
+ .usingComponents({
129
+ child: childCompDef.general(),
130
+ })
131
+ .template(tmpl(`
132
+ <child wx:for="{{list}}" wx:key="k" p="{{item.v}}" />
133
+ `))
134
+ .data(() => ({
135
+ list: [
136
+ { k: 1, v: 'A' },
137
+ { k: 2, v: 'B' },
138
+ { k: 2, v: 'C' },
139
+ ],
140
+ }))
141
+ .registerComponent()
142
+ const comp = execWithWarn(1, () => glassEasel.Component.createWithContext('root', compDef, domBackend))
143
+ glassEasel.Element.pretendAttached(comp)
144
+ const getP = () => {
145
+ const ret = [] as string[]
146
+ comp.getShadowRoot()!.childNodes[0]!.asElement()!.childNodes.forEach((child) => {
147
+ ret.push(child.asElement()!.childNodes[0]!.asInstanceOf(childCompDef)!.data.p)
148
+ })
149
+ return ret
150
+ }
151
+ expect(getP()).toStrictEqual(['A', 'B', 'C'])
152
+ expect(execArr).toStrictEqual(['A', 'B', 'C'])
153
+ execArr = []
154
+ execWithWarn(1, () => {
155
+ comp.groupUpdates(() => {
156
+ comp.replaceDataOnPath(['list', 0, 'v'], 'D')
157
+ })
158
+ })
159
+ expect(getP()).toStrictEqual(['D', 'B', 'C'])
160
+ expect(execArr).toStrictEqual(['D'])
161
+ execArr = []
162
+ execWithWarn(1, () => {
163
+ comp.groupUpdates(() => {
164
+ comp.replaceDataOnPath(['list', 1, 'v'], 'E')
165
+ })
166
+ })
167
+ expect(getP()).toStrictEqual(['D', 'E', 'C'])
168
+ expect(execArr).toStrictEqual(['E'])
169
+ })
170
+
171
+ test('should be able to update list keys', () => {
172
+ let execArr = [] as string[]
173
+ const childCompDef = componentSpace.define()
174
+ .property('p', String)
175
+ .observer('p', function () {
176
+ execArr.push(this.data.p)
177
+ })
178
+ .registerComponent()
179
+ const compDef = componentSpace.define()
180
+ .usingComponents({
181
+ child: childCompDef.general(),
182
+ })
183
+ .template(tmpl(`
184
+ <child wx:for="{{list}}" wx:key="k" p="{{item.v}}" />
185
+ `))
186
+ .data(() => ({
187
+ list: [
188
+ { k: 1, v: 'A' },
189
+ { k: 2, v: 'B' },
190
+ { k: 2, v: 'C' },
191
+ ],
192
+ }))
193
+ .registerComponent()
194
+ const comp = execWithWarn(1, () => glassEasel.Component.createWithContext('root', compDef, domBackend))
195
+ glassEasel.Element.pretendAttached(comp)
196
+ const getP = () => {
197
+ const ret = [] as string[]
198
+ comp.getShadowRoot()!.childNodes[0]!.asElement()!.childNodes.forEach((child) => {
199
+ ret.push(child.asElement()!.childNodes[0]!.asInstanceOf(childCompDef)!.data.p)
200
+ })
201
+ return ret
202
+ }
203
+ expect(getP()).toStrictEqual(['A', 'B', 'C'])
204
+ expect(execArr).toStrictEqual(['A', 'B', 'C'])
205
+ execArr = []
206
+ execWithWarn(1, () => {
207
+ comp.groupUpdates(() => {
208
+ comp.replaceDataOnPath(['list', 1, 'k'], 1)
209
+ })
210
+ })
211
+ expect(getP()).toStrictEqual(['A', 'B', 'C'])
212
+ expect(execArr).toStrictEqual(['A', 'B', 'C'])
213
+ execArr = []
214
+ comp.groupUpdates(() => {
215
+ comp.replaceDataOnPath(['list', 1, 'k'], 3)
216
+ })
217
+ expect(getP()).toStrictEqual(['A', 'B', 'C'])
218
+ expect(execArr).toStrictEqual(['A', 'B'])
219
+ execArr = []
220
+ comp.groupUpdates(() => {
221
+ comp.replaceDataOnPath(['list', 2, 'k'], 4)
222
+ })
223
+ expect(getP()).toStrictEqual(['A', 'B', 'C'])
224
+ expect(execArr).toStrictEqual(['C'])
225
+ execArr = []
226
+ execWithWarn(1, () => {
227
+ comp.groupUpdates(() => {
228
+ comp.replaceDataOnPath(['list', 1, 'k'], 4)
229
+ })
230
+ })
231
+ expect(getP()).toStrictEqual(['A', 'B', 'C'])
232
+ expect(execArr).toStrictEqual(['B', 'C'])
233
+ })
234
+
235
+ test('should be able to do list-splice update (without key)', () => {
236
+ let execArr = [] as string[]
237
+ const childCompDef = componentSpace.define()
238
+ .property('p', String)
239
+ .observer('p', function () {
240
+ execArr.push(this.data.p)
241
+ })
242
+ .registerComponent()
243
+ const compDef = componentSpace.define()
244
+ .usingComponents({
245
+ child: childCompDef.general(),
246
+ })
247
+ .template(tmpl(`
248
+ <child wx:for="{{list}}" p="{{item}}" />
249
+ `))
250
+ .data(() => ({
251
+ list: ['A', 'B', 'C'],
252
+ }))
253
+ .registerComponent()
254
+ const comp = glassEasel.Component.createWithContext('root', compDef, domBackend)
255
+ glassEasel.Element.pretendAttached(comp)
256
+ const getP = () => {
257
+ const ret = [] as string[]
258
+ comp.getShadowRoot()!.childNodes[0]!.asElement()!.childNodes.forEach((child) => {
259
+ ret.push(child.asElement()!.childNodes[0]!.asInstanceOf(childCompDef)!.data.p)
260
+ })
261
+ return ret
262
+ }
263
+ expect(getP()).toStrictEqual(['A', 'B', 'C'])
264
+ expect(execArr).toStrictEqual(['A', 'B', 'C'])
265
+ execArr = []
266
+ comp.groupUpdates(() => {
267
+ comp.spliceArrayDataOnPath(['list'], 1, 1, ['D', 'Z'])
268
+ comp.spliceArrayDataOnPath(['list'], 2, 1, ['E'])
269
+ })
270
+ expect(getP()).toStrictEqual(['A', 'D', 'E', 'C'])
271
+ expect(execArr).toStrictEqual(['A', 'D', 'E', 'C'])
272
+ execArr = []
273
+ comp.groupUpdates(() => {
274
+ comp.spliceArrayDataOnPath(['list'], 100, 0, ['F'])
275
+ })
276
+ expect(getP()).toStrictEqual(['A', 'D', 'E', 'C', 'F'])
277
+ expect(execArr).toStrictEqual(['A', 'D', 'E', 'C', 'F'])
278
+ execArr = []
279
+ comp.groupUpdates(() => {
280
+ comp.spliceArrayDataOnPath(['list'], 3, 3, [])
281
+ })
282
+ expect(getP()).toStrictEqual(['A', 'D', 'E'])
283
+ expect(execArr).toStrictEqual(['A', 'D', 'E'])
284
+ execArr = []
285
+ comp.groupUpdates(() => {
286
+ comp.spliceArrayDataOnPath(['list'], 0, 2, ['G'])
287
+ })
288
+ expect(getP()).toStrictEqual(['G', 'E'])
289
+ expect(execArr).toStrictEqual(['G', 'E'])
290
+ })
291
+
292
+ test('should be able to do list-splice update (with key)', () => {
293
+ let execArr = [] as string[]
294
+ const childCompDef = componentSpace.define()
295
+ .property('p', String)
296
+ .observer('p', function () {
297
+ execArr.push(this.data.p)
298
+ })
299
+ .registerComponent()
300
+ const compDef = componentSpace.define()
301
+ .usingComponents({
302
+ child: childCompDef.general(),
303
+ })
304
+ .template(tmpl(`
305
+ <child wx:for="{{list}}" wx:key="k" p="{{item.v}}" />
306
+ `))
307
+ .data(() => ({
308
+ list: [
309
+ { k: 1, v: 'A' },
310
+ { k: 2, v: 'B' },
311
+ { k: 3, v: 'C' },
312
+ ],
313
+ }))
314
+ .registerComponent()
315
+ const comp = glassEasel.Component.createWithContext('root', compDef, domBackend)
316
+ glassEasel.Element.pretendAttached(comp)
317
+ const getP = () => {
318
+ const ret = [] as string[]
319
+ comp.getShadowRoot()!.childNodes[0]!.asElement()!.childNodes.forEach((child) => {
320
+ ret.push(child.asElement()!.childNodes[0]!.asInstanceOf(childCompDef)!.data.p)
321
+ })
322
+ return ret
323
+ }
324
+ expect(getP()).toStrictEqual(['A', 'B', 'C'])
325
+ expect(execArr).toStrictEqual(['A', 'B', 'C'])
326
+ execArr = []
327
+ comp.groupUpdates(() => {
328
+ comp.spliceArrayDataOnPath(['list'], 1, 1, [{ k: 4, v: 'D' }, { k: 5, v: 'Z' }])
329
+ comp.spliceArrayDataOnPath(['list'], 2, 1, [{ k: 5, v: 'E' }])
330
+ })
331
+ expect(getP()).toStrictEqual(['A', 'D', 'E', 'C'])
332
+ expect(execArr).toStrictEqual(['D', 'E'])
333
+ execArr = []
334
+ comp.groupUpdates(() => {
335
+ comp.spliceArrayDataOnPath(['list'], 100, 0, [{ k: 6, v: 'F' }])
336
+ })
337
+ expect(getP()).toStrictEqual(['A', 'D', 'E', 'C', 'F'])
338
+ expect(execArr).toStrictEqual(['F'])
339
+ execArr = []
340
+ comp.groupUpdates(() => {
341
+ comp.replaceDataOnPath(['list', 1, 'v'], 'DD')
342
+ comp.spliceArrayDataOnPath(['list'], 3, 3, [])
343
+ })
344
+ expect(getP()).toStrictEqual(['A', 'DD', 'E'])
345
+ expect(execArr).toStrictEqual(['DD'])
346
+ execArr = []
347
+ comp.groupUpdates(() => {
348
+ comp.replaceDataOnPath(['list', 1, 'v'], 'D')
349
+ comp.spliceArrayDataOnPath(['list'], 0, 0, [{ k: 3, v: 'C' }])
350
+ })
351
+ expect(getP()).toStrictEqual(['C', 'A', 'D', 'E'])
352
+ expect(execArr).toStrictEqual(['C', 'D'])
353
+ execArr = []
354
+ comp.groupUpdates(() => {
355
+ comp.replaceDataOnPath(['list', 1, 'v'], 'DD')
356
+ comp.spliceArrayDataOnPath(['list'], 0, 2, [{ k: 7, v: 'G' }])
357
+ })
358
+ expect(getP()).toStrictEqual(['G', 'D', 'E'])
359
+ expect(execArr).toStrictEqual(['G'])
360
+ execArr = []
361
+ execWithWarn(1, () => {
362
+ comp.groupUpdates(() => {
363
+ comp.spliceArrayDataOnPath(['list'], -1, 100, [{ k: 7, v: 'GG' }])
364
+ })
365
+ })
366
+ expect(getP()).toStrictEqual(['G', 'D', 'E', 'GG'])
367
+ expect(execArr).toStrictEqual(['G', 'GG'])
368
+ execArr = []
369
+ execWithWarn(1, () => {
370
+ comp.groupUpdates(() => {
371
+ comp.spliceArrayDataOnPath(['list'], 1, 1, [])
372
+ })
373
+ })
374
+ expect(getP()).toStrictEqual(['G', 'E', 'GG'])
375
+ expect(execArr).toStrictEqual([])
376
+ })
377
+
378
+ test('should be able to do list-splice update (with key and using index)', () => {
379
+ let execArr = [] as string[]
380
+ const childCompDef = componentSpace.define()
381
+ .property('p', String)
382
+ .observer('p', function () {
383
+ execArr.push(this.data.p)
384
+ })
385
+ .registerComponent()
386
+ const compDef = componentSpace.define()
387
+ .usingComponents({
388
+ child: childCompDef.general(),
389
+ })
390
+ .template(tmpl(`
391
+ <child wx:for="{{list}}" wx:key="k" p="{{index}}:{{item.v}}" />
392
+ `))
393
+ .data(() => ({
394
+ list: [
395
+ { k: 1, v: 'A' },
396
+ { k: 2, v: 'B' },
397
+ { k: 3, v: 'C' },
398
+ ],
399
+ }))
400
+ .registerComponent()
401
+ const comp = glassEasel.Component.createWithContext('root', compDef, domBackend)
402
+ glassEasel.Element.pretendAttached(comp)
403
+ const getP = () => {
404
+ const ret = [] as string[]
405
+ comp.getShadowRoot()!.childNodes[0]!.asElement()!.childNodes.forEach((child) => {
406
+ ret.push(child.asElement()!.childNodes[0]!.asInstanceOf(childCompDef)!.data.p)
407
+ })
408
+ return ret
409
+ }
410
+ expect(getP()).toStrictEqual(['0:A', '1:B', '2:C'])
411
+ expect(execArr).toStrictEqual(['0:A', '1:B', '2:C'])
412
+ execArr = []
413
+ comp.groupUpdates(() => {
414
+ comp.spliceArrayDataOnPath(['list'], 1, 1, [{ k: 4, v: 'D' }])
415
+ })
416
+ expect(getP()).toStrictEqual(['0:A', '1:D', '2:C'])
417
+ expect(execArr).toStrictEqual(['1:D'])
418
+ execArr = []
419
+ comp.groupUpdates(() => {
420
+ comp.spliceArrayDataOnPath(['list'], 1, 0, [{ k: 5, v: 'E' }])
421
+ })
422
+ expect(getP()).toStrictEqual(['0:A', '1:E', '2:D', '3:C'])
423
+ expect(execArr).toStrictEqual(['1:E', '2:D', '3:C'])
424
+ execArr = []
425
+ comp.groupUpdates(() => {
426
+ comp.spliceArrayDataOnPath(['list'], 1, 2, [])
427
+ })
428
+ expect(getP()).toStrictEqual(['0:A', '1:C'])
429
+ expect(execArr).toStrictEqual(['1:C'])
430
+ })
431
+
432
+ test('should not allow updates before init done', () => {
433
+ const compDef = componentSpace.define()
434
+ .data(() => ({
435
+ a: 123,
436
+ b: ['a'],
437
+ }))
438
+ .init(({ self }) => {
439
+ let throwCount = 0
440
+ try {
441
+ self.setData({ a: 456 })
442
+ } catch { throwCount += 1 }
443
+ try {
444
+ self.updateData({ b: ['c'] })
445
+ } catch { throwCount += 1 }
446
+ try {
447
+ self.replaceDataOnPath(['a'], 789)
448
+ } catch { throwCount += 1 }
449
+ try {
450
+ self.spliceArrayDataOnPath(['b'], 0, 0, ['b'])
451
+ } catch { throwCount += 1 }
452
+ try {
453
+ self.groupUpdates(() => undefined)
454
+ } catch { throwCount += 1 }
455
+ expect(throwCount).toBe(5)
456
+ })
457
+ .registerComponent()
458
+ const comp = glassEasel.Component.createWithContext('root', compDef, domBackend)
459
+ expect(comp.data).toStrictEqual({ a: 123, b: ['a'] })
460
+ })
461
+ })