@gogocat/data-bind 1.12.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/.editorconfig +14 -14
  2. package/.vscode/launch.json +12 -12
  3. package/CONFIGURATION.md +294 -0
  4. package/REACTIVE_MODE.md +553 -0
  5. package/README.md +266 -829
  6. package/babel.config.json +30 -0
  7. package/dist/js/_escape.d.ts +14 -0
  8. package/dist/js/_escape.d.ts.map +1 -0
  9. package/dist/js/applyBinding.d.ts +11 -0
  10. package/dist/js/applyBinding.d.ts.map +1 -0
  11. package/dist/js/attrBinding.d.ts +12 -0
  12. package/dist/js/attrBinding.d.ts.map +1 -0
  13. package/dist/js/binder.d.ts +67 -0
  14. package/dist/js/binder.d.ts.map +1 -0
  15. package/dist/js/changeBinding.d.ts +19 -0
  16. package/dist/js/changeBinding.d.ts.map +1 -0
  17. package/dist/js/commentWrapper.d.ts +39 -0
  18. package/dist/js/commentWrapper.d.ts.map +1 -0
  19. package/dist/js/config.d.ts +55 -0
  20. package/dist/js/config.d.ts.map +1 -0
  21. package/dist/js/createBindingOption.d.ts +32 -0
  22. package/dist/js/createBindingOption.d.ts.map +1 -0
  23. package/dist/js/createEventBinding.d.ts +10 -0
  24. package/dist/js/createEventBinding.d.ts.map +1 -0
  25. package/dist/js/cssBinding.d.ts +15 -0
  26. package/dist/js/cssBinding.d.ts.map +1 -0
  27. package/dist/js/dataBind.js +2756 -2530
  28. package/dist/js/dataBind.min.js +8 -1
  29. package/dist/js/dataBind.min.js.map +1 -1
  30. package/dist/js/domWalker.d.ts +9 -0
  31. package/dist/js/domWalker.d.ts.map +1 -0
  32. package/dist/js/forOfBinding.d.ts +12 -0
  33. package/dist/js/forOfBinding.d.ts.map +1 -0
  34. package/dist/js/hoverBinding.d.ts +13 -0
  35. package/dist/js/hoverBinding.d.ts.map +1 -0
  36. package/dist/js/ifBinding.d.ts +12 -0
  37. package/dist/js/ifBinding.d.ts.map +1 -0
  38. package/dist/js/index.d.ts +10 -0
  39. package/dist/js/index.d.ts.map +1 -0
  40. package/dist/js/modelBinding.d.ts +12 -0
  41. package/dist/js/modelBinding.d.ts.map +1 -0
  42. package/dist/js/postProcess.d.ts +3 -0
  43. package/dist/js/postProcess.d.ts.map +1 -0
  44. package/dist/js/pubSub.d.ts +11 -0
  45. package/dist/js/pubSub.d.ts.map +1 -0
  46. package/dist/js/reactiveProxy.d.ts +28 -0
  47. package/dist/js/reactiveProxy.d.ts.map +1 -0
  48. package/dist/js/renderForOfBinding.d.ts +8 -0
  49. package/dist/js/renderForOfBinding.d.ts.map +1 -0
  50. package/dist/js/renderIfBinding.d.ts +22 -0
  51. package/dist/js/renderIfBinding.d.ts.map +1 -0
  52. package/dist/js/renderIteration.d.ts +16 -0
  53. package/dist/js/renderIteration.d.ts.map +1 -0
  54. package/dist/js/renderTemplate.d.ts +14 -0
  55. package/dist/js/renderTemplate.d.ts.map +1 -0
  56. package/dist/js/renderTemplatesBinding.d.ts +19 -0
  57. package/dist/js/renderTemplatesBinding.d.ts.map +1 -0
  58. package/dist/js/showBinding.d.ts +13 -0
  59. package/dist/js/showBinding.d.ts.map +1 -0
  60. package/dist/js/switchBinding.d.ts +13 -0
  61. package/dist/js/switchBinding.d.ts.map +1 -0
  62. package/dist/js/textBinding.d.ts +13 -0
  63. package/dist/js/textBinding.d.ts.map +1 -0
  64. package/dist/js/types/_escape.d.ts +14 -0
  65. package/dist/js/types/_escape.d.ts.map +1 -0
  66. package/dist/js/types/applyBinding.d.ts +11 -0
  67. package/dist/js/types/applyBinding.d.ts.map +1 -0
  68. package/dist/js/types/attrBinding.d.ts +12 -0
  69. package/dist/js/types/attrBinding.d.ts.map +1 -0
  70. package/dist/js/types/binder.d.ts +67 -0
  71. package/dist/js/types/binder.d.ts.map +1 -0
  72. package/dist/js/types/changeBinding.d.ts +19 -0
  73. package/dist/js/types/changeBinding.d.ts.map +1 -0
  74. package/dist/js/types/commentWrapper.d.ts +39 -0
  75. package/dist/js/types/commentWrapper.d.ts.map +1 -0
  76. package/dist/js/types/config.d.ts +55 -0
  77. package/dist/js/types/config.d.ts.map +1 -0
  78. package/dist/js/types/createBindingOption.d.ts +32 -0
  79. package/dist/js/types/createBindingOption.d.ts.map +1 -0
  80. package/dist/js/types/createEventBinding.d.ts +10 -0
  81. package/dist/js/types/createEventBinding.d.ts.map +1 -0
  82. package/dist/js/types/cssBinding.d.ts +15 -0
  83. package/dist/js/types/cssBinding.d.ts.map +1 -0
  84. package/dist/js/types/domWalker.d.ts +9 -0
  85. package/dist/js/types/domWalker.d.ts.map +1 -0
  86. package/dist/js/types/forOfBinding.d.ts +12 -0
  87. package/dist/js/types/forOfBinding.d.ts.map +1 -0
  88. package/dist/js/types/hoverBinding.d.ts +13 -0
  89. package/dist/js/types/hoverBinding.d.ts.map +1 -0
  90. package/dist/js/types/ifBinding.d.ts +12 -0
  91. package/dist/js/types/ifBinding.d.ts.map +1 -0
  92. package/dist/js/types/index.d.ts +10 -0
  93. package/dist/js/types/index.d.ts.map +1 -0
  94. package/dist/js/types/modelBinding.d.ts +12 -0
  95. package/dist/js/types/modelBinding.d.ts.map +1 -0
  96. package/dist/js/types/postProcess.d.ts +3 -0
  97. package/dist/js/types/postProcess.d.ts.map +1 -0
  98. package/dist/js/types/pubSub.d.ts +11 -0
  99. package/dist/js/types/pubSub.d.ts.map +1 -0
  100. package/dist/js/types/reactiveProxy.d.ts +28 -0
  101. package/dist/js/types/reactiveProxy.d.ts.map +1 -0
  102. package/dist/js/types/renderForOfBinding.d.ts +8 -0
  103. package/dist/js/types/renderForOfBinding.d.ts.map +1 -0
  104. package/dist/js/types/renderIfBinding.d.ts +22 -0
  105. package/dist/js/types/renderIfBinding.d.ts.map +1 -0
  106. package/dist/js/types/renderIteration.d.ts +16 -0
  107. package/dist/js/types/renderIteration.d.ts.map +1 -0
  108. package/dist/js/types/renderTemplate.d.ts +14 -0
  109. package/dist/js/types/renderTemplate.d.ts.map +1 -0
  110. package/dist/js/types/renderTemplatesBinding.d.ts +19 -0
  111. package/dist/js/types/renderTemplatesBinding.d.ts.map +1 -0
  112. package/dist/js/types/showBinding.d.ts +13 -0
  113. package/dist/js/types/showBinding.d.ts.map +1 -0
  114. package/dist/js/types/switchBinding.d.ts +13 -0
  115. package/dist/js/types/switchBinding.d.ts.map +1 -0
  116. package/dist/js/types/textBinding.d.ts +13 -0
  117. package/dist/js/types/textBinding.d.ts.map +1 -0
  118. package/dist/js/types/types.d.ts +111 -0
  119. package/dist/js/types/types.d.ts.map +1 -0
  120. package/dist/js/types/util.d.ts +119 -0
  121. package/dist/js/types/util.d.ts.map +1 -0
  122. package/dist/js/types.d.ts +111 -0
  123. package/dist/js/types.d.ts.map +1 -0
  124. package/dist/js/util.d.ts +119 -0
  125. package/dist/js/util.d.ts.map +1 -0
  126. package/eslint.config.js +124 -0
  127. package/examples/DBMONSTER_COMPARISON.md +123 -0
  128. package/examples/afterRenderDemo.html +119 -0
  129. package/examples/bootstrap/css/animate.css +1579 -1579
  130. package/examples/bootstrap/css/bootstrap.min.css +6 -6
  131. package/examples/bootstrap/css/homeservices.css +378 -390
  132. package/examples/bootstrap/css/open-iconic.css +511 -511
  133. package/examples/bootstrap/fonts/open-iconic.svg +543 -543
  134. package/examples/bootstrap/js/compMessageDialog.js +20 -19
  135. package/examples/bootstrap/js/compSearchBar.js +12 -19
  136. package/examples/bootstrap/js/compSearchResults.js +50 -46
  137. package/examples/bootstrap/js/featureAdsResult.json +65 -65
  138. package/examples/bootstrap/js/searchResult.json +57 -57
  139. package/examples/bootstrap.html +343 -332
  140. package/examples/css/baseTodo.css +141 -141
  141. package/examples/css/dbMonsterStyles.css +27 -27
  142. package/examples/css/indexTodo.css +374 -374
  143. package/examples/dbmonsterForOfReactive.html +40 -0
  144. package/examples/dbmonsterReact.html +19 -0
  145. package/examples/forOfBindingSimpleDebug.html +45 -0
  146. package/examples/globalConfig.html +131 -0
  147. package/examples/js/afterRenderDemo.js +190 -0
  148. package/examples/js/appTodo.js +46 -46
  149. package/examples/js/attrBindingDemo.js +2 -2
  150. package/examples/js/dbMonApp.js +24 -26
  151. package/examples/js/dbMonAppReact.jsx +79 -0
  152. package/examples/js/dbMonAppReactive.js +28 -0
  153. package/examples/js/fiberDemo.js +4 -4
  154. package/examples/js/filtersDemo.js +8 -8
  155. package/examples/js/forOfDemo.js +7 -9
  156. package/examples/js/forOfDemoComplex.js +44 -17
  157. package/examples/js/form.js +14 -14
  158. package/examples/js/globalConfig.js +117 -0
  159. package/examples/js/ifBindingDemo.js +16 -16
  160. package/examples/js/reactiveDemo.js +119 -0
  161. package/examples/js/switchBindingDemo.js +8 -8
  162. package/examples/react-dbmonster/dist/bundle.js +43 -0
  163. package/examples/react-dbmonster/package-lock.json +537 -0
  164. package/examples/react-dbmonster/package.json +16 -0
  165. package/examples/react-dbmonster/src/index.jsx +80 -0
  166. package/examples/reactiveDemo.html +127 -0
  167. package/examples/refreshRateTest.html +75 -75
  168. package/index.html +841 -0
  169. package/package.json +31 -34
  170. package/rollup.config.js +79 -36
  171. package/src/{_escape.js → _escape.ts} +19 -17
  172. package/src/{applyBinding.js → applyBinding.ts} +27 -18
  173. package/src/{attrBinding.js → attrBinding.ts} +14 -13
  174. package/src/{binder.js → binder.ts} +289 -181
  175. package/src/changeBinding.ts +93 -0
  176. package/src/{commentWrapper.js → commentWrapper.ts} +33 -30
  177. package/src/config.ts +107 -0
  178. package/src/{createBindingOption.js → createBindingOption.ts} +39 -15
  179. package/src/createEventBinding.ts +88 -0
  180. package/src/{cssBinding.js → cssBinding.ts} +13 -11
  181. package/src/{domWalker.js → domWalker.ts} +44 -30
  182. package/src/{forOfBinding.js → forOfBinding.ts} +4 -3
  183. package/src/hoverBinding.ts +84 -0
  184. package/src/{ifBinding.js → ifBinding.ts} +14 -12
  185. package/src/index.ts +53 -0
  186. package/src/{modelBinding.js → modelBinding.ts} +11 -9
  187. package/src/{postProcess.js → postProcess.ts} +6 -4
  188. package/src/{pubSub.js → pubSub.ts} +24 -21
  189. package/src/reactiveProxy.ts +285 -0
  190. package/src/{renderForOfBinding.js → renderForOfBinding.ts} +54 -32
  191. package/src/{renderIfBinding.js → renderIfBinding.ts} +41 -19
  192. package/src/{renderIteration.js → renderIteration.ts} +24 -8
  193. package/src/renderTemplate.ts +165 -0
  194. package/src/renderTemplatesBinding.ts +73 -0
  195. package/src/{showBinding.js → showBinding.ts} +4 -3
  196. package/src/{switchBinding.js → switchBinding.ts} +18 -15
  197. package/src/{textBinding.js → textBinding.ts} +5 -4
  198. package/src/types.ts +124 -0
  199. package/src/util.ts +810 -0
  200. package/test/css/reporter.css +9 -9
  201. package/test/globals.d.ts +19 -0
  202. package/test/helpers/testHelper.js +46 -11
  203. package/test/mocks/featureAdsResult.json +65 -65
  204. package/test/mocks/searchResult.json +57 -57
  205. package/test/specs/{attrBinding.spec.js → attrBinding.spec.ts} +103 -106
  206. package/test/specs/{binder.spec.js → binder.spec.ts} +29 -27
  207. package/test/specs/blurBinding.spec.ts +60 -0
  208. package/test/specs/chainableUse.spec.ts +125 -0
  209. package/test/specs/clickBinding.spec.ts +194 -0
  210. package/test/specs/{cssBinding.spec.js → cssBinding.spec.ts} +72 -79
  211. package/test/specs/{dataBindBootstrap.spec.js → dataBindBootstrap.spec.ts} +332 -313
  212. package/test/specs/{filter.spec.js → filter.spec.ts} +75 -76
  213. package/test/specs/{forOfBinding.spec.js → forOfBinding.spec.ts} +208 -219
  214. package/test/specs/formBinding.spec.ts +272 -0
  215. package/test/specs/ifBinding.spec.ts +165 -0
  216. package/test/specs/{nestedComponent.spec.js → nestedComponent.spec.ts} +88 -88
  217. package/test/specs/reactiveProxy.spec.ts +465 -0
  218. package/test/specs/{showBinding.spec.js → showBinding.spec.ts} +148 -149
  219. package/test/specs/{switchBinding.spec.js → switchBinding.spec.ts} +172 -173
  220. package/test/specs/templateBinding.spec.ts +273 -0
  221. package/test/specs/{textBinding.spec.js → textBinding.spec.ts} +47 -48
  222. package/test/tsconfig.json +31 -0
  223. package/test-output.txt +200 -0
  224. package/test-reactive.html +224 -0
  225. package/tsconfig.json +28 -0
  226. package/vendors/lodash.custom.js +4577 -4577
  227. package/vendors/lodash.custom.min.js +45 -45
  228. package/vitest.config.js +27 -0
  229. package/.eslintrc.js +0 -1
  230. package/.grunt/grunt-contrib-jasmine/boot.js +0 -161
  231. package/.grunt/grunt-contrib-jasmine/dist/js/dataBind.js +0 -9
  232. package/.grunt/grunt-contrib-jasmine/grunt-template-jasmine-istanbul/reporter.js +0 -23
  233. package/.grunt/grunt-contrib-jasmine/jasmine-html.js +0 -853
  234. package/.grunt/grunt-contrib-jasmine/jasmine.css +0 -271
  235. package/.grunt/grunt-contrib-jasmine/jasmine.js +0 -9761
  236. package/.grunt/grunt-contrib-jasmine/jasmine_favicon.png +0 -0
  237. package/.grunt/grunt-contrib-jasmine/json2.js +0 -489
  238. package/.grunt/grunt-contrib-jasmine/reporter.js +0 -107
  239. package/coverage/coverage.json +0 -1
  240. package/coverage/lcov/lcov-report/base.css +0 -213
  241. package/coverage/lcov/lcov-report/index.html +0 -93
  242. package/coverage/lcov/lcov-report/js/dataBind.js.html +0 -6596
  243. package/coverage/lcov/lcov-report/js/index.html +0 -93
  244. package/coverage/lcov/lcov-report/prettify.css +0 -1
  245. package/coverage/lcov/lcov-report/prettify.js +0 -1
  246. package/coverage/lcov/lcov-report/sort-arrow-sprite.png +0 -0
  247. package/coverage/lcov/lcov-report/sorter.js +0 -158
  248. package/coverage/lcov/lcov.info +0 -1991
  249. package/eslintrc.json +0 -40
  250. package/examples/bootstrap/js/bootstrap.min.js +0 -6
  251. package/examples/bootstrap/js/popper.min.js +0 -5
  252. package/examples/bootstrap/js/searchSuggestion.js +0 -58
  253. package/examples/bootstrap/js/typeahead.jquery.js +0 -1538
  254. package/gruntfile.js +0 -92
  255. package/gulpfile.js +0 -32
  256. package/src/applyBindingExport.js +0 -5
  257. package/src/changeBinding.js +0 -63
  258. package/src/config.js +0 -66
  259. package/src/createEventBinding.js +0 -46
  260. package/src/eventSystem.js +0 -46
  261. package/src/hoverBinding.js +0 -57
  262. package/src/index.js +0 -26
  263. package/src/renderTemplate.js +0 -128
  264. package/src/renderTemplatesBinding.js +0 -44
  265. package/src/util.js +0 -648
  266. package/test/specs/blurBinding.spec.js +0 -57
  267. package/test/specs/formBinding.spec.js +0 -316
  268. package/test/specs/ifBinding.spec.js +0 -169
  269. package/test/specs/templateBinding.spec.js +0 -117
  270. package/vendors/jasmine-jquery.js +0 -841
  271. package/vendors/jquery-3.2.1.min.js +0 -4
@@ -1,76 +1,75 @@
1
- /* eslint-disable max-len */
2
- describe('Given [data-bind-comp="filter-component"] inited', () => {
3
- const namespace = {};
4
-
5
- jasmine.getFixtures().fixturesPath = 'test';
6
-
7
- beforeEach(function(done) {
8
- loadFixtures('./fixtures/filters.html');
9
-
10
- namespace.viewModel = {
11
- renderIntro: false,
12
- heading: 'Test data-if-binding',
13
- description: 'This is intro text',
14
- discountRate: 0.8,
15
- gstRate: 1.1,
16
- story: {
17
- title: 'Hansel and Gretel',
18
- description:
19
- '"Hansel and Gretel" (also known as Hansel and Grettel, Hansel and Grethel, or Little Brother and Little Sister) is a well-known fairy tale of German origin.',
20
- link: 'https://www.google.com.au/search?q=Hansel+and+Gretel',
21
- price: 100,
22
- },
23
- toDiscount: function(value) {
24
- return Number(value) * this.discountRate;
25
- },
26
- addGst: function(value) {
27
- return Number(value) * this.gstRate;
28
- },
29
- updateView: function(opt) {
30
- return this.APP.render(opt);
31
- },
32
- };
33
-
34
- namespace.filterComponent = dataBind.init(document.querySelector('[data-bind-comp="filter-component"]'), namespace.viewModel);
35
- namespace.filterComponent.render().then(() => done());
36
- });
37
-
38
- afterEach(() => {
39
- // clean up all app/components
40
- for (const prop in namespace) {
41
- if (namespace.hasOwnProperty(prop)) {
42
- delete namespace[prop];
43
- }
44
- }
45
- });
46
-
47
- it('Then [data-bind-comp="filter-component"] should render story with once filter and not intro', () => {
48
- const $intro = document.getElementById('intro');
49
- const $story = document.getElementById('story');
50
-
51
- expect($intro).toBe(null);
52
- expect($story).not.toBe(null);
53
- expect($story.firstElementChild).not.toBe(null);
54
- });
55
-
56
- it('Should render intro but not story section after update viewModel', (done) => {
57
- namespace.filterComponent.viewModel.renderIntro = true;
58
- namespace.filterComponent.viewModel.updateView().then(() => {
59
- const $intro = document.getElementById('intro');
60
- const $story = document.getElementById('story');
61
- expect($intro).toBe(null);
62
- expect($story).toBe(null);
63
- done();
64
- });
65
- });
66
-
67
- it('Should render story and stroyPrice pass through filters | toDiscount | addGst', () => {
68
- const $story = document.getElementById('story');
69
- const stroyPrice = document.getElementById('stroyPrice').textContent;
70
- const discountedPrice = namespace.viewModel.toDiscount(namespace.viewModel.story.price);
71
- const finalPrice = namespace.viewModel.addGst(discountedPrice);
72
-
73
- expect($story).not.toBe(null);
74
- expect(Number(stroyPrice)).toBe(finalPrice);
75
- });
76
- });
1
+ import {describe, it, expect, beforeEach, afterEach} from 'vitest';
2
+
3
+
4
+ describe('Given [data-bind-comp="filter-component"] inited', () => {
5
+ const namespace: any = {};
6
+
7
+ beforeEach(async () => {
8
+ loadFixture('test/fixtures/filters.html');
9
+
10
+ namespace.viewModel = {
11
+ renderIntro: false,
12
+ heading: 'Test data-if-binding',
13
+ description: 'This is intro text',
14
+ discountRate: 0.8,
15
+ gstRate: 1.1,
16
+ story: {
17
+ title: 'Hansel and Gretel',
18
+ description:
19
+ '"Hansel and Gretel" (also known as Hansel and Grettel, Hansel and Grethel, or Little Brother and Little Sister) is a well-known fairy tale of German origin.',
20
+ link: 'https://www.google.com.au/search?q=Hansel+and+Gretel',
21
+ price: 100,
22
+ },
23
+ toDiscount(value: any) {
24
+ return Number(value) * this.discountRate;
25
+ },
26
+ addGst(value: any) {
27
+ return Number(value) * this.gstRate;
28
+ },
29
+ updateView(opt?: any) {
30
+ return this.APP.render(opt);
31
+ },
32
+ };
33
+
34
+ namespace.filterComponent = dataBind.init(document.querySelector('[data-bind-comp="filter-component"]'), namespace.viewModel);
35
+ await namespace.filterComponent.render();
36
+ });
37
+
38
+ afterEach(() => {
39
+ // clean up all app/components
40
+ for (const prop in namespace) {
41
+ if (Object.prototype.hasOwnProperty.call(namespace, prop)) {
42
+ delete namespace[prop];
43
+ }
44
+ }
45
+ });
46
+
47
+ it('Then [data-bind-comp="filter-component"] should render story with once filter and not intro', () => {
48
+ const $intro = document.getElementById('intro');
49
+ const $story = document.getElementById('story');
50
+
51
+ expect($intro).toBe(null);
52
+ expect($story).not.toBe(null);
53
+ expect($story!.firstElementChild).not.toBe(null);
54
+ });
55
+
56
+ it('Should render intro but not story section after update viewModel', async () => {
57
+ namespace.filterComponent.viewModel.renderIntro = true;
58
+ await namespace.filterComponent.viewModel.updateView();
59
+
60
+ const $intro = document.getElementById('intro');
61
+ const $story = document.getElementById('story');
62
+ expect($intro).toBe(null);
63
+ expect($story).toBe(null);
64
+ });
65
+
66
+ it('Should render story and stroyPrice pass through filters | toDiscount | addGst', () => {
67
+ const $story = document.getElementById('story');
68
+ const stroyPrice = document.getElementById('stroyPrice')!.textContent!;
69
+ const discountedPrice = namespace.viewModel.toDiscount(namespace.viewModel.story.price);
70
+ const finalPrice = namespace.viewModel.addGst(discountedPrice);
71
+
72
+ expect($story).not.toBe(null);
73
+ expect(Number(stroyPrice)).toBe(finalPrice);
74
+ });
75
+ });
@@ -1,219 +1,208 @@
1
- /* eslint-disable max-len */
2
- // It seems PhantomJS has issue with createComment and createRange
3
- const isEnvSupportDocRange = ((document) => {
4
- let docRange;
5
- let commentNode;
6
- const commentText = 'x';
7
- let ret = true;
8
-
9
- if (typeof document.createRange !== 'function') {
10
- return (ret = false);
11
- }
12
- try {
13
- docRange = document.createRange();
14
- docRange.deleteContents();
15
- commentNode = document.createComment(commentText);
16
- if (commentNode.nodeType !== 8 || commentNode.textContent !== commentText) {
17
- return (ret = false);
18
- }
19
- } catch (err) {
20
- return (ret = false);
21
- }
22
- return ret;
23
- })(document);
24
-
25
- describe('When search-results-component with forOf binding inited', () => {
26
- const namespace = {};
27
-
28
- jasmine.getFixtures().fixturesPath = 'test';
29
-
30
- beforeEach(() => {
31
- loadFixtures('./fixtures/forOfBinding.html');
32
-
33
- namespace.viewModel = {
34
- searchResultTitle: 'Featured service providers',
35
- messageTriggerCss: '',
36
- bookmarkCss: '',
37
- searchResults: [
38
- {
39
- id: '001',
40
- title: 'Card title that wraps to a new line',
41
- description:
42
- 'This is a longer card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.',
43
- image: 'bootstrap/images/pic-home.jpg',
44
- bookmarked: false,
45
- numLikes: 110,
46
- options: [{text: '1', value: '1'}, {text: '2', value: '2'}, {text: '3', value: '3'}],
47
- },
48
- {
49
- id: '456',
50
- title: 'Card title',
51
- description: 'This card has supporting text below as a natural lead-in to additional content.',
52
- image: '',
53
- bookmarked: false,
54
- numLikes: 8,
55
- selected: true,
56
- options: [{text: '4', value: '4'}, {text: '5', value: '5'}, {text: '6', value: '6'}],
57
- },
58
- {
59
- id: '789',
60
- title: 'Sample carpemter service',
61
- description:
62
- 'This is a wider card with supporting text below as a natural lead-in to additional content. This card has even longer content than the first to show that equal height action.',
63
- image: 'bootstrap/images/pic-carpenter.jpg',
64
- bookmarked: false,
65
- numLikes: 8,
66
- highlight: true,
67
- highlightCss: 'result-item--highlight',
68
- options: [{text: '7', value: '7'}, {text: '8', value: '8'}, {text: '9', value: '9'}],
69
- },
70
- ],
71
- getResultItemAttr: function(index, oldAttrObj, $el) {
72
- const self = this;
73
- if (self.searchResults[index].image) {
74
- return {
75
- src: self.searchResults[index].image,
76
- alt: self.searchResults[index].title || '',
77
- };
78
- }
79
- },
80
- setResultOptionAttr: function($data, oldAttrObj, $el) {
81
- if ($data && $data.value) {
82
- // todo: the index here is the outter loop index
83
- return {
84
- value: $data.value,
85
- };
86
- }
87
- },
88
- onAdMessageCheck: function(e, $el, newValue, oldValue, index) {
89
- console.log('onAdMessageCheck: ', $el, newValue, oldValue, index);
90
- },
91
- onAdBookmarkClick: function(e, $el, index) {
92
- e.preventDefault();
93
- console.log('onAdBookmarkClick: ', $el, index);
94
- },
95
- };
96
-
97
- namespace.searchResultsComponent = dataBind.init(
98
- document.querySelector('[data-bind-comp="search-results-component"]'),
99
- namespace.viewModel,
100
- );
101
-
102
- namespace.searchResultsComponent.render();
103
- });
104
-
105
- afterEach(() => {
106
- // clean up all app/components
107
- for (const prop in namespace) {
108
- if (namespace.hasOwnProperty(prop)) {
109
- delete namespace[prop];
110
- }
111
- }
112
- });
113
-
114
- it('Then [data-bind-comp="search-results-component"] should have render', (done) => {
115
- // skip if test environment doesn't support document.createRange
116
- if (!isEnvSupportDocRange) {
117
- expect(isEnvSupportDocRange).toBe(false);
118
- done();
119
- return;
120
- }
121
- setTimeout(() => {
122
- expect($('#searchResultTitle').text()).toBe(namespace.viewModel.searchResultTitle);
123
- // expect($('#search-result-columns').children().length).not.toBe(0);
124
- done();
125
- }, 200);
126
- });
127
-
128
- it('Then render forOf binding elements with comment tag wrap around', (done) => {
129
- setTimeout(() => {
130
- const $searchColumn = document.getElementById('search-result-columns');
131
- // not sure why jasmine first execution before render complete, that's why element doesn't exsits
132
- // but when run just this spec it will works
133
- if (!$searchColumn.firstElementChild) {
134
- expect($searchColumn.firstElementChild).toBe(null);
135
- done();
136
- return;
137
- }
138
- const firstCommentWrap = $searchColumn.firstElementChild.previousSibling;
139
- const lastCommentWrap = $searchColumn.lastElementChild.nextSibling;
140
-
141
- expect(firstCommentWrap.nodeType).toBe(8);
142
- expect(lastCommentWrap.nodeType).toBe(8);
143
- expect(firstCommentWrap.textContent).toContain('data-forOf');
144
- expect(lastCommentWrap.textContent).toContain('data-forOf');
145
- done();
146
- }, 200);
147
- });
148
-
149
- it('Then render same amount of items in viewModel.searchResults', (done) => {
150
- setTimeout(() => {
151
- const $searchColumn = document.getElementById('search-result-columns');
152
- // not sure why jasmine first execution before render complete, that's why element doesn't exsits
153
- // but when run just this spec it will works
154
- if (!$searchColumn.firstElementChild) {
155
- expect($searchColumn.firstElementChild).toBe(null);
156
- done();
157
- return;
158
- }
159
- expect($searchColumn.children.length).toBe(namespace.viewModel.searchResults.length);
160
- done();
161
- }, 200);
162
- });
163
-
164
- describe('When each search item rendered', () => {
165
- it('should render bindings according to searchResults data', (done) => {
166
- if (!isEnvSupportDocRange) {
167
- expect(isEnvSupportDocRange).toBe(false);
168
- done();
169
- return;
170
- }
171
- setTimeout(() => {
172
- const $results = $('#search-result-columns').children();
173
- // not sure why jasmine first execution before render complete, that's why element doesn't exsits
174
- // but when run just this spec it will works
175
- if (!$results.length) {
176
- expect($results.length).toBe(0);
177
- done();
178
- return;
179
- }
180
-
181
- expect($results.length).not.toBe(0);
182
-
183
- $results.each(function(index) {
184
- const indexString = String(index);
185
- const $result = $(this);
186
- const $img = $result.find('.result-item__img');
187
- const $body = $result.find('.card-body');
188
- const $footer = $result.find('.result-item__footer');
189
- const $checkbox = $footer.find('.result-item__icon-checkbox');
190
- const $options = $footer.find('select.form-control option');
191
- const imgSrc = $img.attr('src') || '';
192
- let bodyIndex = $body.find('.bodyIndex').text();
193
- let footerIndex = $footer.find('.footerIndex').text();
194
- let bookMarkIndex = $result.find('.bookMarkIndex').text();
195
- const searchResult = namespace.viewModel.searchResults[index];
196
-
197
- bodyIndex = bodyIndex.charAt(bodyIndex.length - 1);
198
- footerIndex = footerIndex.charAt(footerIndex.length - 1);
199
- bookMarkIndex = bookMarkIndex.charAt(bookMarkIndex.length - 1);
200
-
201
- expect($img.length).not.toBe(0);
202
- expect(imgSrc).toBe(namespace.viewModel.searchResults[index].image);
203
- expect($body.children().length).not.toBe(0);
204
- expect(bodyIndex).toEqual(indexString);
205
- expect($footer.length).not.toBe(0);
206
- expect(footerIndex).toEqual(indexString);
207
- expect(bookMarkIndex).toEqual(indexString);
208
- expect($checkbox[0].checked).toEqual(Boolean(searchResult.selected));
209
- // first option is not from data
210
- expect($options.length).toEqual(searchResult.options.length + 1);
211
- expect($options.eq(index + 1).text()).toEqual(searchResult.options[index].text);
212
- expect($options.eq(index + 1).val()).toEqual(searchResult.options[index].value);
213
- });
214
-
215
- done();
216
- }, 200);
217
- });
218
- });
219
- });
1
+ import {describe, it, expect, beforeEach, afterEach} from 'vitest';
2
+ import {waitFor} from '@testing-library/dom';
3
+
4
+
5
+ // It seems PhantomJS has issue with createComment and createRange
6
+ const isEnvSupportDocRange = ((document) => {
7
+ let docRange;
8
+ let commentNode;
9
+ const commentText = 'x';
10
+ let ret = true;
11
+
12
+ if (typeof document.createRange !== 'function') {
13
+ return (ret = false);
14
+ }
15
+ try {
16
+ docRange = document.createRange();
17
+ docRange.deleteContents();
18
+ commentNode = document.createComment(commentText);
19
+ if (commentNode.nodeType !== 8 || commentNode.textContent !== commentText) {
20
+ return (ret = false);
21
+ }
22
+ } catch {
23
+ return (ret = false);
24
+ }
25
+ return ret;
26
+ })(document);
27
+
28
+ describe('When search-results-component with forOf binding inited', () => {
29
+ const namespace: any = {};
30
+
31
+ beforeEach(() => {
32
+ loadFixture('test/fixtures/forOfBinding.html');
33
+
34
+ namespace.viewModel = {
35
+ searchResultTitle: 'Featured service providers',
36
+ messageTriggerCss: '',
37
+ bookmarkCss: '',
38
+ searchResults: [
39
+ {
40
+ id: '001',
41
+ title: 'Card title that wraps to a new line',
42
+ description:
43
+ 'This is a longer card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.',
44
+ image: 'bootstrap/images/pic-home.jpg',
45
+ bookmarked: false,
46
+ numLikes: 110,
47
+ options: [{text: '1', value: '1'}, {text: '2', value: '2'}, {text: '3', value: '3'}],
48
+ },
49
+ {
50
+ id: '456',
51
+ title: 'Card title',
52
+ description: 'This card has supporting text below as a natural lead-in to additional content.',
53
+ image: '',
54
+ bookmarked: false,
55
+ numLikes: 8,
56
+ selected: true,
57
+ options: [{text: '4', value: '4'}, {text: '5', value: '5'}, {text: '6', value: '6'}],
58
+ },
59
+ {
60
+ id: '789',
61
+ title: 'Sample carpemter service',
62
+ description:
63
+ 'This is a wider card with supporting text below as a natural lead-in to additional content. This card has even longer content than the first to show that equal height action.',
64
+ image: 'bootstrap/images/pic-carpenter.jpg',
65
+ bookmarked: false,
66
+ numLikes: 8,
67
+ highlight: true,
68
+ highlightCss: 'result-item--highlight',
69
+ options: [{text: '7', value: '7'}, {text: '8', value: '8'}, {text: '9', value: '9'}],
70
+ },
71
+ ],
72
+ getResultItemAttr(index: number, _oldAttrObj: any, _$el: any) {
73
+ const self = this;
74
+ if (self.searchResults[index].image) {
75
+ return {
76
+ src: self.searchResults[index].image,
77
+ alt: self.searchResults[index].title || '',
78
+ };
79
+ }
80
+ },
81
+ setResultOptionAttr($data: any, _oldAttrObj: any, _$el: any) {
82
+ if ($data && $data.value) {
83
+ // todo: the index here is the outter loop index
84
+ return {
85
+ value: $data.value,
86
+ };
87
+ }
88
+ },
89
+ onAdMessageCheck(e: Event, $el: any, newValue: any, oldValue: any, index: number) {
90
+ console.log('onAdMessageCheck: ', $el, newValue, oldValue, index);
91
+ },
92
+ onAdBookmarkClick(e: Event, $el: any, index: number) {
93
+ e.preventDefault();
94
+ console.log('onAdBookmarkClick: ', $el, index);
95
+ },
96
+ };
97
+
98
+ namespace.searchResultsComponent = dataBind.init(
99
+ document.querySelector('[data-bind-comp="search-results-component"]'),
100
+ namespace.viewModel,
101
+ );
102
+
103
+ namespace.searchResultsComponent.render();
104
+ });
105
+
106
+ afterEach(() => {
107
+ // clean up all app/components
108
+ for (const prop in namespace) {
109
+ if (Object.prototype.hasOwnProperty.call(namespace, prop)) {
110
+ delete namespace[prop];
111
+ }
112
+ }
113
+ });
114
+
115
+ it('Then [data-bind-comp="search-results-component"] should have render', async () => {
116
+ // skip if test environment doesn't support document.createRange
117
+ if (!isEnvSupportDocRange) {
118
+ expect(isEnvSupportDocRange).toBe(false);
119
+ return;
120
+ }
121
+ await waitFor(() => {
122
+ expect(document.querySelector('#searchResultTitle')!.textContent).toBe(namespace.viewModel.searchResultTitle);
123
+ }, {timeout: 500});
124
+ });
125
+
126
+ it('Then render forOf binding elements with comment tag wrap around', async () => {
127
+ const $searchColumn = document.getElementById('search-result-columns');
128
+ // not sure why jasmine first execution before render complete, that's why element doesn't exist
129
+ // but when run just this spec it will works
130
+ if (!$searchColumn || !$searchColumn.firstElementChild) {
131
+ expect($searchColumn?.firstElementChild).toBeFalsy();
132
+ return;
133
+ }
134
+
135
+ await waitFor(() => {
136
+ const firstComment = $searchColumn.firstChild;
137
+ const lastComment = $searchColumn.lastChild;
138
+ expect(firstComment!.nodeType).toBe(Node.COMMENT_NODE);
139
+ expect(lastComment!.nodeType).toBe(Node.COMMENT_NODE);
140
+ }, {timeout: 500});
141
+ });
142
+
143
+ it('Then render same amount of items in viewModel.searchResults', async () => {
144
+ const $searchColumn = document.getElementById('search-result-columns');
145
+ // not sure why jasmine first execution before render complete, that's why element doesn't exist
146
+ // but when run just this spec it will works
147
+ if (!$searchColumn || !$searchColumn.firstElementChild) {
148
+ expect($searchColumn?.firstElementChild).toBeFalsy();
149
+ return;
150
+ }
151
+
152
+ await waitFor(() => {
153
+ const $results = Array.from($searchColumn.children);
154
+ expect($results.length).toBe(namespace.viewModel.searchResults.length);
155
+ }, {timeout: 500});
156
+ });
157
+
158
+ describe('When each search item rendered', () => {
159
+ it('should render bindings according to searchResults data', async () => {
160
+ const $searchColumn = document.querySelector('#search-result-columns');
161
+ const $results = $searchColumn ? Array.from($searchColumn.children) : [];
162
+
163
+ // not sure why jasmine first execution before render complete, that's why element doesn't exist
164
+ // but when run just this spec it will works
165
+ if (!$results.length) {
166
+ expect($results.length).toBe(0);
167
+ return;
168
+ }
169
+
170
+ await waitFor(() => {
171
+ expect($results.length).not.toBe(0);
172
+
173
+ $results.forEach(($result, index) => {
174
+ const indexString = String(index);
175
+ const $img = $result.querySelector('.result-item__img');
176
+ const $body = $result.querySelector('.card-body')!;
177
+ const $footer = $result.querySelector('.result-item__footer')!;
178
+ const $checkbox = $footer.querySelector('.result-item__icon-checkbox') as HTMLInputElement;
179
+ const $options = $footer.querySelectorAll('select.form-control option');
180
+ const imgSrc = $img ? $img.getAttribute('src') || '' : '';
181
+ let bodyIndex = $body.querySelector('.bodyIndex')?.textContent || '';
182
+ let footerIndex = $footer.querySelector('.footerIndex')?.textContent || '';
183
+ let bookMarkIndex = $result.querySelector('.bookMarkIndex')?.textContent || '';
184
+ const searchResult = namespace.viewModel.searchResults[index];
185
+
186
+ bodyIndex = bodyIndex.charAt(bodyIndex.length - 1);
187
+ footerIndex = footerIndex.charAt(footerIndex.length - 1);
188
+ bookMarkIndex = bookMarkIndex.charAt(bookMarkIndex.length - 1);
189
+
190
+ expect($img).not.toBeNull();
191
+ expect(imgSrc).toBe(namespace.viewModel.searchResults[index].image);
192
+ expect($body.children.length).not.toBe(0);
193
+ expect(bodyIndex).toEqual(indexString);
194
+ expect($footer).not.toBeNull();
195
+ expect(footerIndex).toEqual(indexString);
196
+ expect(bookMarkIndex).toEqual(indexString);
197
+ expect($checkbox.checked).toEqual(Boolean(searchResult.selected));
198
+ // first option is not from data
199
+ expect($options.length).toEqual(searchResult.options.length + 1);
200
+ if ($options[index + 1]) {
201
+ expect($options[index + 1].textContent).toEqual(searchResult.options[index].text);
202
+ expect(($options[index + 1] as HTMLOptionElement).value).toEqual(searchResult.options[index].value);
203
+ }
204
+ });
205
+ }, {timeout: 500});
206
+ });
207
+ });
208
+ });