@nyaruka/temba-components 0.131.2 → 0.132.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 (232) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/demo/components/floating-tabs/example.html +400 -0
  3. package/demo/components/flow/index.html +1 -1
  4. package/demo/data/flows/sample-flow.json +41 -2
  5. package/demo/data/flows/voicemail.json +613 -0
  6. package/demo/index.html +6 -0
  7. package/dist/locales/es.js +5 -5
  8. package/dist/locales/es.js.map +1 -1
  9. package/dist/locales/fr.js +5 -5
  10. package/dist/locales/fr.js.map +1 -1
  11. package/dist/locales/locale-codes.js +11 -2
  12. package/dist/locales/locale-codes.js.map +1 -1
  13. package/dist/locales/pt.js +5 -5
  14. package/dist/locales/pt.js.map +1 -1
  15. package/dist/temba-components.js +1122 -548
  16. package/dist/temba-components.js.map +1 -1
  17. package/out-tsc/src/display/FloatingTab.js +167 -0
  18. package/out-tsc/src/display/FloatingTab.js.map +1 -0
  19. package/out-tsc/src/display/ProgressBar.js +22 -2
  20. package/out-tsc/src/display/ProgressBar.js.map +1 -1
  21. package/out-tsc/src/events.js.map +1 -1
  22. package/out-tsc/src/flow/CanvasNode.js +165 -31
  23. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  24. package/out-tsc/src/flow/Editor.js +870 -3
  25. package/out-tsc/src/flow/Editor.js.map +1 -1
  26. package/out-tsc/src/flow/NodeEditor.js +239 -19
  27. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  28. package/out-tsc/src/flow/NodeTypeSelector.js +51 -4
  29. package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -1
  30. package/out-tsc/src/flow/StickyNote.js +12 -3
  31. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  32. package/out-tsc/src/flow/actions/add_contact_groups.js +2 -1
  33. package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
  34. package/out-tsc/src/flow/actions/add_contact_urn.js +2 -1
  35. package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
  36. package/out-tsc/src/flow/actions/add_input_labels.js +2 -1
  37. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
  38. package/out-tsc/src/flow/actions/play_audio.js +2 -1
  39. package/out-tsc/src/flow/actions/play_audio.js.map +1 -1
  40. package/out-tsc/src/flow/actions/remove_contact_groups.js +2 -1
  41. package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
  42. package/out-tsc/src/flow/actions/request_optin.js +1 -0
  43. package/out-tsc/src/flow/actions/request_optin.js.map +1 -1
  44. package/out-tsc/src/flow/actions/say_msg.js +2 -1
  45. package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
  46. package/out-tsc/src/flow/actions/send_broadcast.js +2 -1
  47. package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
  48. package/out-tsc/src/flow/actions/send_email.js +2 -1
  49. package/out-tsc/src/flow/actions/send_email.js.map +1 -1
  50. package/out-tsc/src/flow/actions/send_msg.js +93 -3
  51. package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
  52. package/out-tsc/src/flow/actions/set_contact_channel.js +2 -1
  53. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
  54. package/out-tsc/src/flow/actions/set_contact_field.js +2 -1
  55. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
  56. package/out-tsc/src/flow/actions/set_contact_language.js +2 -1
  57. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
  58. package/out-tsc/src/flow/actions/set_contact_name.js +2 -1
  59. package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
  60. package/out-tsc/src/flow/actions/set_contact_status.js +2 -1
  61. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
  62. package/out-tsc/src/flow/actions/set_run_result.js +2 -1
  63. package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
  64. package/out-tsc/src/flow/actions/start_session.js +2 -1
  65. package/out-tsc/src/flow/actions/start_session.js.map +1 -1
  66. package/out-tsc/src/flow/config.js +19 -14
  67. package/out-tsc/src/flow/config.js.map +1 -1
  68. package/out-tsc/src/flow/nodes/shared.js +54 -0
  69. package/out-tsc/src/flow/nodes/shared.js.map +1 -1
  70. package/out-tsc/src/flow/nodes/split_by_airtime.js +9 -3
  71. package/out-tsc/src/flow/nodes/split_by_airtime.js.map +1 -1
  72. package/out-tsc/src/flow/nodes/split_by_contact_field.js +8 -3
  73. package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -1
  74. package/out-tsc/src/flow/nodes/split_by_expression.js +8 -3
  75. package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -1
  76. package/out-tsc/src/flow/nodes/split_by_groups.js +8 -3
  77. package/out-tsc/src/flow/nodes/split_by_groups.js.map +1 -1
  78. package/out-tsc/src/flow/nodes/split_by_intent.js +3 -2
  79. package/out-tsc/src/flow/nodes/split_by_intent.js.map +1 -1
  80. package/out-tsc/src/flow/nodes/split_by_llm.js +9 -2
  81. package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
  82. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +9 -2
  83. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
  84. package/out-tsc/src/flow/nodes/split_by_random.js +8 -2
  85. package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
  86. package/out-tsc/src/flow/nodes/split_by_resthook.js +8 -3
  87. package/out-tsc/src/flow/nodes/split_by_resthook.js.map +1 -1
  88. package/out-tsc/src/flow/nodes/split_by_run_result.js +14 -3
  89. package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -1
  90. package/out-tsc/src/flow/nodes/split_by_scheme.js +8 -3
  91. package/out-tsc/src/flow/nodes/split_by_scheme.js.map +1 -1
  92. package/out-tsc/src/flow/nodes/split_by_subflow.js +8 -2
  93. package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
  94. package/out-tsc/src/flow/nodes/split_by_ticket.js +8 -2
  95. package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
  96. package/out-tsc/src/flow/nodes/split_by_webhook.js +8 -2
  97. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
  98. package/out-tsc/src/flow/nodes/wait_for_digits.js +3 -2
  99. package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
  100. package/out-tsc/src/flow/nodes/wait_for_menu.js +3 -2
  101. package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -1
  102. package/out-tsc/src/flow/nodes/wait_for_response.js +8 -3
  103. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  104. package/out-tsc/src/flow/types.js +15 -0
  105. package/out-tsc/src/flow/types.js.map +1 -1
  106. package/out-tsc/src/layout/FloatingWindow.js +346 -0
  107. package/out-tsc/src/layout/FloatingWindow.js.map +1 -0
  108. package/out-tsc/src/live/ContactChat.js +41 -49
  109. package/out-tsc/src/live/ContactChat.js.map +1 -1
  110. package/out-tsc/src/locales/es.js +5 -5
  111. package/out-tsc/src/locales/es.js.map +1 -1
  112. package/out-tsc/src/locales/fr.js +5 -5
  113. package/out-tsc/src/locales/fr.js.map +1 -1
  114. package/out-tsc/src/locales/locale-codes.js +11 -2
  115. package/out-tsc/src/locales/locale-codes.js.map +1 -1
  116. package/out-tsc/src/locales/pt.js +5 -5
  117. package/out-tsc/src/locales/pt.js.map +1 -1
  118. package/out-tsc/src/store/AppState.js +75 -1
  119. package/out-tsc/src/store/AppState.js.map +1 -1
  120. package/out-tsc/temba-modules.js +4 -0
  121. package/out-tsc/temba-modules.js.map +1 -1
  122. package/out-tsc/test/nodes/split_by_run_result.test.js +83 -0
  123. package/out-tsc/test/nodes/split_by_run_result.test.js.map +1 -1
  124. package/out-tsc/test/temba-backwards-compatibility.test.js +30 -0
  125. package/out-tsc/test/temba-backwards-compatibility.test.js.map +1 -0
  126. package/out-tsc/test/temba-contact-chat.test.js +27 -12
  127. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  128. package/out-tsc/test/temba-floating-tab.test.js +91 -0
  129. package/out-tsc/test/temba-floating-tab.test.js.map +1 -0
  130. package/out-tsc/test/temba-floating-window.test.js +301 -0
  131. package/out-tsc/test/temba-floating-window.test.js.map +1 -0
  132. package/out-tsc/test/temba-flow-editor-node.test.js +117 -0
  133. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  134. package/out-tsc/test/temba-localization.test.js +490 -0
  135. package/out-tsc/test/temba-localization.test.js.map +1 -0
  136. package/out-tsc/test/temba-node-type-selector.test.js +217 -0
  137. package/out-tsc/test/temba-node-type-selector.test.js.map +1 -1
  138. package/out-tsc/test/utils.test.js +18 -0
  139. package/out-tsc/test/utils.test.js.map +1 -1
  140. package/package.json +1 -1
  141. package/screenshots/truth/floating-tab/default.png +0 -0
  142. package/screenshots/truth/floating-tab/gray.png +0 -0
  143. package/screenshots/truth/floating-tab/green.png +0 -0
  144. package/screenshots/truth/floating-tab/hidden.png +0 -0
  145. package/screenshots/truth/floating-tab/hover.png +0 -0
  146. package/screenshots/truth/floating-tab/purple.png +0 -0
  147. package/screenshots/truth/floating-window/chromeless.png +0 -0
  148. package/screenshots/truth/floating-window/custom-size.png +0 -0
  149. package/screenshots/truth/floating-window/default.png +0 -0
  150. package/screenshots/truth/floating-window/with-header.png +0 -0
  151. package/screenshots/truth/node-type-selector/action-mode.png +0 -0
  152. package/screenshots/truth/node-type-selector/split-mode.png +0 -0
  153. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  154. package/src/display/FloatingTab.ts +174 -0
  155. package/src/display/ProgressBar.ts +22 -2
  156. package/src/events.ts +2 -4
  157. package/src/flow/CanvasNode.ts +190 -32
  158. package/src/flow/Editor.ts +1054 -4
  159. package/src/flow/NodeEditor.ts +317 -19
  160. package/src/flow/NodeTypeSelector.ts +54 -4
  161. package/src/flow/StickyNote.ts +12 -3
  162. package/src/flow/actions/add_contact_groups.ts +2 -1
  163. package/src/flow/actions/add_contact_urn.ts +3 -1
  164. package/src/flow/actions/add_input_labels.ts +2 -1
  165. package/src/flow/actions/play_audio.ts +2 -1
  166. package/src/flow/actions/remove_contact_groups.ts +3 -1
  167. package/src/flow/actions/request_optin.ts +1 -0
  168. package/src/flow/actions/say_msg.ts +2 -1
  169. package/src/flow/actions/send_broadcast.ts +2 -1
  170. package/src/flow/actions/send_email.ts +3 -1
  171. package/src/flow/actions/send_msg.ts +134 -3
  172. package/src/flow/actions/set_contact_channel.ts +2 -1
  173. package/src/flow/actions/set_contact_field.ts +2 -1
  174. package/src/flow/actions/set_contact_language.ts +3 -1
  175. package/src/flow/actions/set_contact_name.ts +2 -1
  176. package/src/flow/actions/set_contact_status.ts +2 -1
  177. package/src/flow/actions/set_run_result.ts +2 -1
  178. package/src/flow/actions/start_session.ts +3 -1
  179. package/src/flow/config.ts +24 -16
  180. package/src/flow/nodes/shared.ts +70 -1
  181. package/src/flow/nodes/split_by_airtime.ts +20 -3
  182. package/src/flow/nodes/split_by_contact_field.ts +13 -3
  183. package/src/flow/nodes/split_by_expression.ts +13 -3
  184. package/src/flow/nodes/split_by_groups.ts +13 -3
  185. package/src/flow/nodes/split_by_intent.ts +3 -2
  186. package/src/flow/nodes/split_by_llm.ts +19 -2
  187. package/src/flow/nodes/split_by_llm_categorize.ts +13 -2
  188. package/src/flow/nodes/split_by_random.ts +12 -2
  189. package/src/flow/nodes/split_by_resthook.ts +13 -3
  190. package/src/flow/nodes/split_by_run_result.ts +20 -3
  191. package/src/flow/nodes/split_by_scheme.ts +13 -3
  192. package/src/flow/nodes/split_by_subflow.ts +12 -2
  193. package/src/flow/nodes/split_by_ticket.ts +12 -2
  194. package/src/flow/nodes/split_by_webhook.ts +12 -2
  195. package/src/flow/nodes/wait_for_digits.ts +3 -2
  196. package/src/flow/nodes/wait_for_menu.ts +3 -2
  197. package/src/flow/nodes/wait_for_response.ts +13 -3
  198. package/src/flow/types.ts +49 -0
  199. package/src/layout/FloatingWindow.ts +386 -0
  200. package/src/live/ContactChat.ts +42 -49
  201. package/src/locales/es.ts +18 -13
  202. package/src/locales/fr.ts +18 -13
  203. package/src/locales/locale-codes.ts +11 -2
  204. package/src/locales/pt.ts +18 -13
  205. package/src/store/AppState.ts +116 -1
  206. package/static/api/llms.json +18 -0
  207. package/temba-modules.ts +4 -0
  208. package/test/nodes/split_by_run_result.test.ts +99 -0
  209. package/test/temba-backwards-compatibility.test.ts +37 -0
  210. package/test/temba-contact-chat.test.ts +27 -12
  211. package/test/temba-floating-tab.test.ts +110 -0
  212. package/test/temba-floating-window.test.ts +477 -0
  213. package/test/temba-flow-editor-node.test.ts +144 -0
  214. package/test/temba-localization.test.ts +635 -0
  215. package/test/temba-node-type-selector.test.ts +289 -0
  216. package/test/utils.test.ts +20 -0
  217. package/test-assets/contacts/history.json +5 -6
  218. package/test-assets/select/llms.json +2 -2
  219. package/web-dev-server.config.mjs +47 -1
  220. package/web-test-runner.config.mjs +0 -1
  221. package/out-tsc/src/flow/nodes/wait_for_audio.js +0 -7
  222. package/out-tsc/src/flow/nodes/wait_for_audio.js.map +0 -1
  223. package/out-tsc/src/flow/nodes/wait_for_image.js +0 -7
  224. package/out-tsc/src/flow/nodes/wait_for_image.js.map +0 -1
  225. package/out-tsc/src/flow/nodes/wait_for_location.js +0 -7
  226. package/out-tsc/src/flow/nodes/wait_for_location.js.map +0 -1
  227. package/out-tsc/src/flow/nodes/wait_for_video.js +0 -7
  228. package/out-tsc/src/flow/nodes/wait_for_video.js.map +0 -1
  229. package/src/flow/nodes/wait_for_audio.ts +0 -7
  230. package/src/flow/nodes/wait_for_image.ts +0 -7
  231. package/src/flow/nodes/wait_for_location.ts +0 -7
  232. package/src/flow/nodes/wait_for_video.ts +0 -7
@@ -111,5 +111,222 @@ describe('temba-node-type-selector', () => {
111
111
  expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });
112
112
  expect(selector.open).to.be.false;
113
113
  });
114
+ it('filters actions by flow type - voice flow should show voice-only actions', async () => {
115
+ var _a;
116
+ const selector = await createSelector();
117
+ selector.flowType = 'voice';
118
+ await selector.updateComplete;
119
+ selector.show('action', { x: 100, y: 100 });
120
+ await selector.updateComplete;
121
+ // get all node item titles
122
+ const nodeItems = (_a = selector.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.node-item-title');
123
+ const titles = Array.from(nodeItems || []).map((item) => { var _a; return (_a = item.textContent) === null || _a === void 0 ? void 0 : _a.trim(); });
124
+ // voice flow should have Say Message and Play Audio
125
+ expect(titles).to.include('Say Message');
126
+ expect(titles).to.include('Play Audio');
127
+ });
128
+ it('filters actions by flow type - message flow should not show voice-only actions', async () => {
129
+ var _a;
130
+ const selector = await createSelector();
131
+ selector.flowType = 'message';
132
+ await selector.updateComplete;
133
+ selector.show('action', { x: 100, y: 100 });
134
+ await selector.updateComplete;
135
+ // get all node item titles
136
+ const nodeItems = (_a = selector.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.node-item-title');
137
+ const titles = Array.from(nodeItems || []).map((item) => { var _a; return (_a = item.textContent) === null || _a === void 0 ? void 0 : _a.trim(); });
138
+ // message flow should not have Say Message or Play Audio
139
+ expect(titles).to.not.include('Say Message');
140
+ expect(titles).to.not.include('Play Audio');
141
+ });
142
+ it('filters splits by flow type - message flow should show wait for response', async () => {
143
+ var _a;
144
+ const selector = await createSelector();
145
+ selector.flowType = 'message';
146
+ await selector.updateComplete;
147
+ selector.show('split', { x: 100, y: 100 });
148
+ await selector.updateComplete;
149
+ // get all node item titles
150
+ const nodeItems = (_a = selector.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.node-item-title');
151
+ const titles = Array.from(nodeItems || []).map((item) => { var _a; return (_a = item.textContent) === null || _a === void 0 ? void 0 : _a.trim(); });
152
+ // message flow should have Wait for Response
153
+ expect(titles).to.include('Wait for Response');
154
+ });
155
+ it('filters splits by flow type - voice flow should not show wait for response', async () => {
156
+ var _a;
157
+ const selector = await createSelector();
158
+ selector.flowType = 'voice';
159
+ await selector.updateComplete;
160
+ selector.show('split', { x: 100, y: 100 });
161
+ await selector.updateComplete;
162
+ // get all node item titles
163
+ const nodeItems = (_a = selector.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.node-item-title');
164
+ const titles = Array.from(nodeItems || []).map((item) => { var _a; return (_a = item.textContent) === null || _a === void 0 ? void 0 : _a.trim(); });
165
+ // voice flow should not have Wait for Response
166
+ expect(titles).to.not.include('Wait for Response');
167
+ // but should have Wait for Digits and Wait for Menu Selection
168
+ expect(titles).to.include('Wait for Digits');
169
+ expect(titles).to.include('Wait for Menu Selection');
170
+ });
171
+ it('filters by features - AI feature enables AI splits', async () => {
172
+ var _a;
173
+ const selector = await createSelector();
174
+ selector.flowType = 'message';
175
+ selector.features = ['ai'];
176
+ await selector.updateComplete;
177
+ selector.show('split', { x: 100, y: 100 });
178
+ await selector.updateComplete;
179
+ // get all node item titles
180
+ const nodeItems = (_a = selector.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.node-item-title');
181
+ const titles = Array.from(nodeItems || []).map((item) => { var _a; return (_a = item.textContent) === null || _a === void 0 ? void 0 : _a.trim(); });
182
+ // split_by_llm_categorize (Split by AI) is filtered out for old editor compatibility
183
+ // so it should NOT appear even when AI feature is enabled
184
+ expect(titles).to.not.include('Split by AI');
185
+ });
186
+ it('filters by features - without AI feature, AI splits are hidden', async () => {
187
+ var _a;
188
+ const selector = await createSelector();
189
+ selector.flowType = 'message';
190
+ selector.features = [];
191
+ await selector.updateComplete;
192
+ selector.show('split', { x: 100, y: 100 });
193
+ await selector.updateComplete;
194
+ // get all node item titles
195
+ const nodeItems = (_a = selector.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.node-item-title');
196
+ const titles = Array.from(nodeItems || []).map((item) => { var _a; return (_a = item.textContent) === null || _a === void 0 ? void 0 : _a.trim(); });
197
+ // without ai feature, should not have Call AI or Split by AI
198
+ expect(titles).to.not.include('Call AI');
199
+ expect(titles).to.not.include('Split by AI');
200
+ });
201
+ it('filters by features - airtime feature enables airtime actions', async () => {
202
+ var _a;
203
+ const selector = await createSelector();
204
+ selector.flowType = 'message';
205
+ selector.features = ['airtime'];
206
+ await selector.updateComplete;
207
+ selector.show('action', { x: 100, y: 100 });
208
+ await selector.updateComplete;
209
+ // get all node item titles
210
+ const nodeItems = (_a = selector.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.node-item-title');
211
+ const titles = Array.from(nodeItems || []).map((item) => { var _a; return (_a = item.textContent) === null || _a === void 0 ? void 0 : _a.trim(); });
212
+ // with airtime feature, should have Send Airtime
213
+ expect(titles).to.include('Send Airtime');
214
+ });
215
+ it('filters by features - without airtime feature, airtime actions are hidden', async () => {
216
+ var _a;
217
+ const selector = await createSelector();
218
+ selector.flowType = 'message';
219
+ selector.features = [];
220
+ await selector.updateComplete;
221
+ selector.show('action', { x: 100, y: 100 });
222
+ await selector.updateComplete;
223
+ // get all node item titles
224
+ const nodeItems = (_a = selector.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.node-item-title');
225
+ const titles = Array.from(nodeItems || []).map((item) => { var _a; return (_a = item.textContent) === null || _a === void 0 ? void 0 : _a.trim(); });
226
+ // without airtime feature, should not have Send Airtime
227
+ expect(titles).to.not.include('Send Airtime');
228
+ });
229
+ it('hides actions/nodes with empty flowTypes array from selector', async () => {
230
+ const selector = await createSelector();
231
+ // test that isConfigAvailable returns false for empty flowTypes array
232
+ const configWithEmptyFlowTypes = {
233
+ name: 'Test Action',
234
+ type: 'test_action',
235
+ flowTypes: [] // empty array should hide from all flow types
236
+ };
237
+ selector.flowType = 'message';
238
+ await selector.updateComplete;
239
+ // call private method via any to test behavior
240
+ const isAvailable = selector.isConfigAvailable(configWithEmptyFlowTypes);
241
+ expect(isAvailable).to.be.false;
242
+ // test with different flow types - should still be false
243
+ selector.flowType = 'voice';
244
+ await selector.updateComplete;
245
+ const isAvailableVoice = selector.isConfigAvailable(configWithEmptyFlowTypes);
246
+ expect(isAvailableVoice).to.be.false;
247
+ });
248
+ it('shows actions/nodes with undefined flowTypes for all flow types', async () => {
249
+ const selector = await createSelector();
250
+ // test that isConfigAvailable returns true for undefined flowTypes
251
+ const configWithUndefinedFlowTypes = {
252
+ name: 'Test Action',
253
+ type: 'test_action'
254
+ // flowTypes is undefined - should be available for all
255
+ };
256
+ selector.flowType = 'message';
257
+ await selector.updateComplete;
258
+ const isAvailable = selector.isConfigAvailable(configWithUndefinedFlowTypes);
259
+ expect(isAvailable).to.be.true;
260
+ // test with different flow types - should still be true
261
+ selector.flowType = 'voice';
262
+ await selector.updateComplete;
263
+ const isAvailableVoice = selector.isConfigAvailable(configWithUndefinedFlowTypes);
264
+ expect(isAvailableVoice).to.be.true;
265
+ });
266
+ describe('alias filtering', () => {
267
+ it('should not show split_by_run_result twice when aliases exist', async () => {
268
+ const selector = await createSelector();
269
+ selector.show('split', { x: 100, y: 100 });
270
+ await selector.updateComplete;
271
+ // Get all the node items rendered in the selector
272
+ const nodeItems = selector.shadowRoot.querySelectorAll('.node-item');
273
+ // Count how many times "Split by Result" appears
274
+ let splitByResultCount = 0;
275
+ nodeItems.forEach((item) => {
276
+ var _a;
277
+ const title = item.querySelector('.node-item-title');
278
+ if ((_a = title === null || title === void 0 ? void 0 : title.textContent) === null || _a === void 0 ? void 0 : _a.includes('Split by Result')) {
279
+ splitByResultCount++;
280
+ }
281
+ });
282
+ // Should only appear once, not twice
283
+ expect(splitByResultCount).to.equal(1);
284
+ });
285
+ it('should not show split_by_run_result_delimited type in the selector', async () => {
286
+ const selector = await createSelector();
287
+ selector.show('split', { x: 100, y: 100 });
288
+ await selector.updateComplete;
289
+ // Get all the node items and check their data-type attributes
290
+ const nodeItems = selector.shadowRoot.querySelectorAll('.node-item');
291
+ let foundDelimitedType = false;
292
+ nodeItems.forEach((item) => {
293
+ const typeAttr = item.getAttribute('data-type');
294
+ if (typeAttr === 'split_by_run_result_delimited') {
295
+ foundDelimitedType = true;
296
+ }
297
+ });
298
+ expect(foundDelimitedType).to.be.false;
299
+ });
300
+ it('should not show split_by_llm_categorize in split mode', async () => {
301
+ const selector = await createSelector();
302
+ selector.show('split', { x: 100, y: 100 });
303
+ await selector.updateComplete;
304
+ // Get all the node items and check their data-type attributes
305
+ const nodeItems = selector.shadowRoot.querySelectorAll('.node-item');
306
+ let foundLLMCategorize = false;
307
+ nodeItems.forEach((item) => {
308
+ const typeAttr = item.getAttribute('data-type');
309
+ if (typeAttr === 'split_by_llm_categorize') {
310
+ foundLLMCategorize = true;
311
+ }
312
+ });
313
+ expect(foundLLMCategorize).to.be.false;
314
+ });
315
+ it('should not show split_by_llm_categorize in action mode', async () => {
316
+ const selector = await createSelector();
317
+ selector.show('action', { x: 100, y: 100 });
318
+ await selector.updateComplete;
319
+ // Get all the node items and check their data-type attributes
320
+ const nodeItems = selector.shadowRoot.querySelectorAll('.node-item');
321
+ let foundLLMCategorize = false;
322
+ nodeItems.forEach((item) => {
323
+ const typeAttr = item.getAttribute('data-type');
324
+ if (typeAttr === 'split_by_llm_categorize') {
325
+ foundLLMCategorize = true;
326
+ }
327
+ });
328
+ expect(foundLLMCategorize).to.be.false;
329
+ });
330
+ });
114
331
  });
115
332
  //# sourceMappingURL=temba-node-type-selector.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"temba-node-type-selector.test.js","sourceRoot":"","sources":["../../test/temba-node-type-selector.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, assert } from '@open-wc/testing';\nimport { NodeTypeSelector } from '../src/flow/NodeTypeSelector';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\ndescribe('temba-node-type-selector', () => {\n const createSelector = async () => {\n const component = (await getComponent(\n 'temba-node-type-selector',\n {},\n '',\n 700,\n 600\n )) as NodeTypeSelector;\n await component.updateComplete;\n return component;\n };\n\n it('can be created', async () => {\n const selector = await createSelector();\n assert.instanceOf(selector, NodeTypeSelector);\n expect(selector.open).to.be.false;\n });\n\n it('is not visible when closed', async () => {\n const selector = await createSelector();\n expect(selector.open).to.be.false;\n\n // component should not be in DOM when closed\n expect(selector.hasAttribute('open')).to.be.false;\n });\n\n it('shows dialog when opened in action mode', async () => {\n const selector = await createSelector();\n\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n expect(selector.mode).to.equal('action');\n expect(selector.hasAttribute('open')).to.be.true;\n\n const dialog = selector.shadowRoot?.querySelector('.dialog') as HTMLElement;\n await assertScreenshot('node-type-selector/action-mode', getClip(dialog));\n });\n\n it('shows dialog when opened in split mode', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n expect(selector.mode).to.equal('split');\n\n const dialog = selector.shadowRoot?.querySelector('.dialog') as HTMLElement;\n await assertScreenshot('node-type-selector/split-mode', getClip(dialog));\n });\n\n it('displays action types in action mode', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const title = selector.shadowRoot?.querySelector('.header h2');\n expect(title?.textContent).to.equal('Select an Action');\n\n // verify we have node items\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item');\n expect(nodeItems?.length).to.be.greaterThan(0);\n });\n\n it('displays split types in split mode', async () => {\n const selector = await createSelector();\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const title = selector.shadowRoot?.querySelector('.header h2');\n expect(title?.textContent).to.equal('Select a Split');\n\n // verify we have node items\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item');\n expect(nodeItems?.length).to.be.greaterThan(0);\n });\n\n it('closes when close() is called', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n\n selector.close();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('closes when overlay is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const overlay = selector.shadowRoot?.querySelector(\n '.overlay'\n ) as HTMLElement;\n overlay.click();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('closes when cancel button is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const cancelButton = selector.shadowRoot?.querySelector(\n 'temba-button'\n ) as HTMLElement;\n cancelButton.click();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('fires selection event when node type is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n let selectionFired = false;\n let selectionDetail = null;\n\n selector.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n // click on first node item\n const firstNodeItem = selector.shadowRoot?.querySelector(\n '.node-item'\n ) as HTMLElement;\n firstNodeItem.click();\n await selector.updateComplete;\n\n expect(selectionFired).to.be.true;\n expect(selectionDetail).to.have.property('nodeType');\n expect(selectionDetail).to.have.property('position');\n expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });\n expect(selector.open).to.be.false;\n });\n});\n"]}
1
+ {"version":3,"file":"temba-node-type-selector.test.js","sourceRoot":"","sources":["../../test/temba-node-type-selector.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, assert } from '@open-wc/testing';\nimport { NodeTypeSelector } from '../src/flow/NodeTypeSelector';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\ndescribe('temba-node-type-selector', () => {\n const createSelector = async () => {\n const component = (await getComponent(\n 'temba-node-type-selector',\n {},\n '',\n 700,\n 600\n )) as NodeTypeSelector;\n await component.updateComplete;\n return component;\n };\n\n it('can be created', async () => {\n const selector = await createSelector();\n assert.instanceOf(selector, NodeTypeSelector);\n expect(selector.open).to.be.false;\n });\n\n it('is not visible when closed', async () => {\n const selector = await createSelector();\n expect(selector.open).to.be.false;\n\n // component should not be in DOM when closed\n expect(selector.hasAttribute('open')).to.be.false;\n });\n\n it('shows dialog when opened in action mode', async () => {\n const selector = await createSelector();\n\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n expect(selector.mode).to.equal('action');\n expect(selector.hasAttribute('open')).to.be.true;\n\n const dialog = selector.shadowRoot?.querySelector('.dialog') as HTMLElement;\n await assertScreenshot('node-type-selector/action-mode', getClip(dialog));\n });\n\n it('shows dialog when opened in split mode', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n expect(selector.mode).to.equal('split');\n\n const dialog = selector.shadowRoot?.querySelector('.dialog') as HTMLElement;\n await assertScreenshot('node-type-selector/split-mode', getClip(dialog));\n });\n\n it('displays action types in action mode', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const title = selector.shadowRoot?.querySelector('.header h2');\n expect(title?.textContent).to.equal('Select an Action');\n\n // verify we have node items\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item');\n expect(nodeItems?.length).to.be.greaterThan(0);\n });\n\n it('displays split types in split mode', async () => {\n const selector = await createSelector();\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const title = selector.shadowRoot?.querySelector('.header h2');\n expect(title?.textContent).to.equal('Select a Split');\n\n // verify we have node items\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item');\n expect(nodeItems?.length).to.be.greaterThan(0);\n });\n\n it('closes when close() is called', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n\n selector.close();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('closes when overlay is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const overlay = selector.shadowRoot?.querySelector(\n '.overlay'\n ) as HTMLElement;\n overlay.click();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('closes when cancel button is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const cancelButton = selector.shadowRoot?.querySelector(\n 'temba-button'\n ) as HTMLElement;\n cancelButton.click();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('fires selection event when node type is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n let selectionFired = false;\n let selectionDetail = null;\n\n selector.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n // click on first node item\n const firstNodeItem = selector.shadowRoot?.querySelector(\n '.node-item'\n ) as HTMLElement;\n firstNodeItem.click();\n await selector.updateComplete;\n\n expect(selectionFired).to.be.true;\n expect(selectionDetail).to.have.property('nodeType');\n expect(selectionDetail).to.have.property('position');\n expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });\n expect(selector.open).to.be.false;\n });\n\n it('filters actions by flow type - voice flow should show voice-only actions', async () => {\n const selector = await createSelector();\n selector.flowType = 'voice';\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // voice flow should have Say Message and Play Audio\n expect(titles).to.include('Say Message');\n expect(titles).to.include('Play Audio');\n });\n\n it('filters actions by flow type - message flow should not show voice-only actions', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // message flow should not have Say Message or Play Audio\n expect(titles).to.not.include('Say Message');\n expect(titles).to.not.include('Play Audio');\n });\n\n it('filters splits by flow type - message flow should show wait for response', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // message flow should have Wait for Response\n expect(titles).to.include('Wait for Response');\n });\n\n it('filters splits by flow type - voice flow should not show wait for response', async () => {\n const selector = await createSelector();\n selector.flowType = 'voice';\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // voice flow should not have Wait for Response\n expect(titles).to.not.include('Wait for Response');\n\n // but should have Wait for Digits and Wait for Menu Selection\n expect(titles).to.include('Wait for Digits');\n expect(titles).to.include('Wait for Menu Selection');\n });\n\n it('filters by features - AI feature enables AI splits', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = ['ai'];\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // split_by_llm_categorize (Split by AI) is filtered out for old editor compatibility\n // so it should NOT appear even when AI feature is enabled\n expect(titles).to.not.include('Split by AI');\n });\n\n it('filters by features - without AI feature, AI splits are hidden', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = [];\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // without ai feature, should not have Call AI or Split by AI\n expect(titles).to.not.include('Call AI');\n expect(titles).to.not.include('Split by AI');\n });\n\n it('filters by features - airtime feature enables airtime actions', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = ['airtime'];\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // with airtime feature, should have Send Airtime\n expect(titles).to.include('Send Airtime');\n });\n\n it('filters by features - without airtime feature, airtime actions are hidden', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = [];\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // without airtime feature, should not have Send Airtime\n expect(titles).to.not.include('Send Airtime');\n });\n\n it('hides actions/nodes with empty flowTypes array from selector', async () => {\n const selector = await createSelector();\n\n // test that isConfigAvailable returns false for empty flowTypes array\n const configWithEmptyFlowTypes = {\n name: 'Test Action',\n type: 'test_action',\n flowTypes: [] // empty array should hide from all flow types\n };\n\n selector.flowType = 'message';\n await selector.updateComplete;\n\n // call private method via any to test behavior\n const isAvailable = (selector as any).isConfigAvailable(\n configWithEmptyFlowTypes\n );\n expect(isAvailable).to.be.false;\n\n // test with different flow types - should still be false\n selector.flowType = 'voice';\n await selector.updateComplete;\n\n const isAvailableVoice = (selector as any).isConfigAvailable(\n configWithEmptyFlowTypes\n );\n expect(isAvailableVoice).to.be.false;\n });\n\n it('shows actions/nodes with undefined flowTypes for all flow types', async () => {\n const selector = await createSelector();\n\n // test that isConfigAvailable returns true for undefined flowTypes\n const configWithUndefinedFlowTypes = {\n name: 'Test Action',\n type: 'test_action'\n // flowTypes is undefined - should be available for all\n };\n\n selector.flowType = 'message';\n await selector.updateComplete;\n\n const isAvailable = (selector as any).isConfigAvailable(\n configWithUndefinedFlowTypes\n );\n expect(isAvailable).to.be.true;\n\n // test with different flow types - should still be true\n selector.flowType = 'voice';\n await selector.updateComplete;\n\n const isAvailableVoice = (selector as any).isConfigAvailable(\n configWithUndefinedFlowTypes\n );\n expect(isAvailableVoice).to.be.true;\n });\n\n describe('alias filtering', () => {\n it('should not show split_by_run_result twice when aliases exist', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items rendered in the selector\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n // Count how many times \"Split by Result\" appears\n let splitByResultCount = 0;\n nodeItems.forEach((item) => {\n const title = item.querySelector('.node-item-title');\n if (title?.textContent?.includes('Split by Result')) {\n splitByResultCount++;\n }\n });\n\n // Should only appear once, not twice\n expect(splitByResultCount).to.equal(1);\n });\n\n it('should not show split_by_run_result_delimited type in the selector', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items and check their data-type attributes\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n let foundDelimitedType = false;\n nodeItems.forEach((item) => {\n const typeAttr = item.getAttribute('data-type');\n if (typeAttr === 'split_by_run_result_delimited') {\n foundDelimitedType = true;\n }\n });\n\n expect(foundDelimitedType).to.be.false;\n });\n\n it('should not show split_by_llm_categorize in split mode', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items and check their data-type attributes\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n let foundLLMCategorize = false;\n nodeItems.forEach((item) => {\n const typeAttr = item.getAttribute('data-type');\n if (typeAttr === 'split_by_llm_categorize') {\n foundLLMCategorize = true;\n }\n });\n\n expect(foundLLMCategorize).to.be.false;\n });\n\n it('should not show split_by_llm_categorize in action mode', async () => {\n const selector = await createSelector();\n\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items and check their data-type attributes\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n let foundLLMCategorize = false;\n nodeItems.forEach((item) => {\n const typeAttr = item.getAttribute('data-type');\n if (typeAttr === 'split_by_llm_categorize') {\n foundLLMCategorize = true;\n }\n });\n\n expect(foundLLMCategorize).to.be.false;\n });\n });\n});\n"]}
@@ -1,6 +1,24 @@
1
1
  import '../temba-modules';
2
2
  import { DateTime } from 'luxon';
3
3
  import { expect, fixture, html, assert } from '@open-wc/testing';
4
+ // disable transitions for all tests to prevent flaky screenshot tests
5
+ const style = document.createElement('style');
6
+ style.textContent = `
7
+ * {
8
+ --transition-speed: 0ms !important;
9
+ }
10
+ `;
11
+ document.head.appendChild(style);
12
+ // prevent resize event listeners from being added during tests
13
+ // this prevents flaky positioning in components that adjust on resize
14
+ const originalAddEventListener = window.addEventListener;
15
+ window.addEventListener = function (type, listener, options) {
16
+ if (type === 'resize') {
17
+ // skip adding resize listeners during tests
18
+ return;
19
+ }
20
+ return originalAddEventListener.call(this, type, listener, options);
21
+ };
4
22
  import MouseHelper from './MouseHelper';
5
23
  import { stub } from 'sinon';
6
24
  const gets = [];
@@ -1 +1 @@
1
- {"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../test/utils.test.ts"],"names":[],"mappings":"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","sourcesContent":["import '../temba-modules';\nimport { DateTime } from 'luxon';\ninterface Clip {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nimport { expect, fixture, html, assert } from '@open-wc/testing';\nimport MouseHelper from './MouseHelper';\nimport { Store } from '../src/store/Store';\nimport { stub } from 'sinon';\nimport { Select, SelectOption } from '../src/form/select/Select';\nimport { Options } from '../src/display/Options';\nimport { Attachment } from '../src/interfaces';\nimport { Compose } from '../src/form/Compose';\n\nexport interface CodeMock {\n endpoint: RegExp;\n body: string;\n headers: any;\n status: string;\n}\n\nconst gets: CodeMock[] = [];\nlet posts: CodeMock[] = [];\nlet normalFetch;\n\nexport const showMouse = async () => {\n const mouse = await fixture(html`<mouse-helper />`);\n assert.instanceOf(mouse, MouseHelper);\n};\n\nexport const getAttributes = (attrs: any = {}) => {\n return `${Object.keys(attrs)\n .map((name: string) => {\n if (typeof attrs[name] === 'boolean' && attrs[name]) {\n return name;\n }\n return `${name}='${attrs[name]}'`;\n })\n .join(' ')}`;\n};\n\nexport const getComponent = async (\n tag,\n attrs: any = {},\n slot = '',\n width = 250,\n height = 0,\n style = ''\n) => {\n const spec = `<${tag} ${getAttributes(attrs)}>${slot}</${tag}>`;\n const parentNode = document.createElement('div');\n const styleAttribute = `\n ${width > 0 ? `width:${width}px;` : ``} \n ${height > 0 ? `height:${height}px;` : ``}\n ${style ? style : ``}\n `;\n parentNode.setAttribute('style', styleAttribute);\n return await fixture(spec, { parentNode });\n};\n\nconst createResponse = (mocked) => {\n const mockResponse = new window.Response(mocked.body, {\n status: mocked.status,\n headers: {\n 'Content-type': 'text/html',\n ...mocked.headers\n }\n });\n\n return Promise.resolve(mockResponse);\n};\n\nconst createJSONResponse = (mocked) => {\n const mockResponse = new window.Response(JSON.stringify(mocked.body), {\n status: mocked.status,\n headers: {\n 'Content-type': 'application/json',\n ...mocked.headers\n }\n });\n\n return Promise.resolve(mockResponse);\n};\n\nconst getResponse = (endpoint: string, options = { method: 'GET' }) => {\n // check if our path has been mocked in code\n const mocks = options.method === 'GET' ? gets : posts;\n const codeMock = mocks.find((mock) => mock.endpoint.test(endpoint));\n\n if (codeMock) {\n if (typeof codeMock.body === 'string') {\n // see if we are being mocked to a file\n if (codeMock.body.startsWith('/')) {\n endpoint = codeMock.body;\n } else {\n return createResponse(codeMock);\n }\n } else {\n return createJSONResponse(codeMock);\n }\n }\n // otherwise fetch over http\n return normalFetch(endpoint, options);\n};\n\nbefore(async () => {\n normalFetch = window.fetch;\n stub(window, 'fetch').callsFake(getResponse);\n await setViewport({ width: 1920, height: 1080, deviceScaleFactor: 2 });\n});\n\nafter(() => {\n (window.fetch as any).restore();\n});\n\nconst mockMapping = {\n '/test-assets/api/users/admin1.json': [\n /\\/api\\/v2\\/users.json\\?email=admin1@nyaruka.com/\n ],\n '/test-assets/api/users/editor1.json': [\n /\\/api\\/v2\\/users.json\\?email=editor1@nyaruka.com/\n ],\n '/test-assets/api/users/agent1.json': [\n /\\/api\\/v2\\/users.json\\?email=agent1@nyaruka.com/\n ],\n '/test-assets/api/users/viewer1.json': [\n /\\/api\\/v2\\/users.json\\?email=viewer1@nyaruka.com/\n ],\n '/test-assets/contacts/contact-tickets.json': [\n /\\/api\\/v2\\/tickets.json\\?contact=24d64810-3315-4ff5-be85-48e3fe055bf9/\n ]\n};\n\nexport const mockAPI = () => {\n for (const key in mockMapping) {\n const urls = mockMapping[key];\n for (const url of urls) {\n mockGET(url, key);\n }\n }\n\n // Add mock data for contact form endpoints\n mockGET(/\\/api\\/v2\\/channels\\.json/, {\n results: [\n { uuid: 'chan-1', name: 'WhatsApp Channel' },\n { uuid: 'chan-2', name: 'Telegram Channel' },\n { uuid: 'chan-3', name: 'SMS Channel' },\n { uuid: 'chan-4', name: 'Facebook Messenger' }\n ]\n });\n\n mockGET(/\\/api\\/v2\\/languages\\.json/, {\n results: [\n { iso: 'eng', name: 'English' },\n { iso: 'spa', name: 'Spanish' },\n { iso: 'fra', name: 'French' },\n { iso: 'por', name: 'Portuguese' },\n { iso: 'deu', name: 'German' }\n ]\n });\n};\n\nexport const mockGET = (\n endpoint: RegExp,\n body: any,\n headers: any = {},\n status = '200'\n) => {\n gets.push({ endpoint, body, headers, status });\n};\n\nexport const mockPOST = (\n endpoint: RegExp,\n body: any,\n headers: any = {},\n status = '200'\n) => {\n posts.push({ endpoint, body, headers, status });\n};\n\nexport const clearMockPosts = () => {\n posts = [];\n};\n\nexport const checkTimers = (clock: any) => {\n expect(!!clock.timers).to.equal(true, 'Expected timers not found');\n expect(\n Object.keys(clock.timers).length,\n `Timers still to be run ${JSON.stringify(clock.timers)}`\n ).to.equal(0);\n};\n\nexport const delay = (millis: number) => {\n return new Promise(function (resolve) {\n window.setTimeout(resolve, millis);\n });\n};\n\n// Enhanced wait utility for more robust testing\nexport const waitForCondition = async (\n predicate: () => boolean,\n maxAttempts: number = 20,\n delayMs: number = 50\n): Promise<void> => {\n let attempts = 0;\n while (!predicate() && attempts < maxAttempts) {\n await delay(delayMs);\n attempts++;\n }\n if (!predicate()) {\n throw new Error(\n `Condition not met after ${maxAttempts} attempts (${\n maxAttempts * delayMs\n }ms)`\n );\n }\n};\n\nexport const assertScreenshot = async (filename: string, clip: Clip) => {\n // detect if we're running in copilot's environment and use adaptive threshold\n const isCopilotEnvironment = (window as any).isCopilotEnvironment;\n const threshold = isCopilotEnvironment ? 1.0 : 0.1;\n const exclude: Clip[] = [];\n\n try {\n await (window as any).matchPageSnapshot(\n `${filename}.png`,\n clip,\n exclude,\n threshold\n );\n } catch (error) {\n if (error.message) {\n throw new Error(\n `${error.message} ${\n error.expected\n ? `Expected ${error.expected} but got ${error.actual}`\n : ''\n } ${error.files ? `\\n${error.files.join('\\n')}` : ''}`\n );\n }\n throw new Error(error);\n }\n};\n\nexport const getClip = (ele: HTMLElement) => {\n let clip: any = ele.getBoundingClientRect();\n if (!clip.width || !clip.height) {\n clip = ele.shadowRoot.firstElementChild.getBoundingClientRect();\n }\n\n // add some padding\n const padding = 10;\n const width = clip.width + padding * 2;\n const height = clip.height + padding * 2;\n const y = clip.y - padding;\n const x = clip.x - padding;\n\n const newClip = {\n x,\n y,\n width,\n height,\n bottom: y + height,\n right: x + width,\n top: y,\n left: x\n };\n\n return newClip;\n};\n\nexport const mouseClickElement = async (ele: HTMLElement | Element) => {\n const bounds = ele.getBoundingClientRect();\n await mouseClick(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);\n};\n\nexport const getHTMLAttrs = (attrs: any = {}) => {\n return Object.keys(attrs)\n .map((name: string) => `${name}='${attrs[name]}'`)\n .join(' ');\n};\n\nexport const getHTML = (tag: string, attrs: any = {}) => {\n return `<${tag} ${getHTMLAttrs(attrs)}></${tag}>`;\n};\n\nexport const loadStore = async () => {\n const store: Store = await fixture(\n `<temba-store \n completion='/test-assets/store/editor.json'\n groups='/test-assets/store/groups.json'\n languages='/test-assets/store/languages.json'\n fields='/test-assets/store/fields.json'\n users='/test-assets/store/users.json'\n workspace='/test-assets/store/workspace.json'\n />`\n );\n await store.initialHttpComplete;\n await store.initialHttpComplete;\n\n return store;\n};\n\nexport const mockNow = (isodate: string) => {\n return stub(DateTime, 'now').returns(DateTime.fromISO(isodate));\n};\n\nexport const getOptions = (select: Select<SelectOption>): Options => {\n return select.shadowRoot.querySelector('temba-options[visible]');\n};\n\nexport const clickOption = async (\n clock: any,\n select: Select<SelectOption>,\n index: number\n) => {\n const options = getOptions(select);\n if (!options) {\n throw new Error('No options element found');\n }\n\n // Wait for the specific option to be available, but only if it's not already there\n const existingOption = options.shadowRoot?.querySelector(\n `[data-option-index=\"${index}\"]`\n );\n if (!existingOption) {\n try {\n // Increased wait time to handle slower CI environments\n await waitForCondition(\n () => {\n const option = options.shadowRoot?.querySelector(\n `[data-option-index=\"${index}\"]`\n );\n return !!option;\n },\n 10,\n 25\n );\n } catch (e) {\n throw new Error(`Option at index ${index} not found after waiting`);\n }\n }\n\n const option = options.shadowRoot.querySelector(\n `[data-option-index=\"${index}\"]`\n ) as HTMLDivElement;\n\n await mouseClickElement(option);\n await options.updateComplete;\n await select.updateComplete;\n await clock.runAll();\n\n checkTimers(clock);\n};\nexport const openSelect = async (clock: any, select: Select<SelectOption>) => {\n const container = select.shadowRoot.querySelector('.select-container');\n container.dispatchEvent(new MouseEvent('click', { bubbles: true }));\n\n clock.runAll();\n\n // add more explicit waiting and clock ticks\n await select.updateComplete;\n clock.runAll();\n\n // reduce wait time for options to become visible\n await waitFor(25);\n clock.runAll();\n\n // For non-endpoint selects, options might be immediately available\n // For endpoint selects, we need to wait for them to load\n const hasEndpoint = select.getAttribute('endpoint');\n if (hasEndpoint) {\n try {\n // Wait for options to be properly rendered and visible (but only for endpoint selects)\n // Increased max attempts to handle slower CI environments\n await waitForCondition(\n () => {\n const options = select.shadowRoot.querySelector(\n 'temba-options[visible]'\n );\n return options && options.isConnected;\n },\n 10,\n 25\n );\n } catch (e) {\n // If condition fails, continue - some tests might not need options to be visible immediately\n }\n }\n};\n\nexport const openAndClick = async (\n clock: any,\n select: Select<SelectOption>,\n idx: number\n) => {\n await openSelect(clock, select);\n\n // Add this line to ensure proper timing when running as part of a test suite\n await select.updateComplete;\n clock.tick(25); // Reduced from 50 to give minimum time for options to render\n\n await clickOption(clock, select, idx);\n};\n\n// valid = attachments that are uploaded sent to the server when the user clicks send\nexport const getValidAttachments = (numFiles = 2): Attachment[] => {\n const attachments = [];\n let index = 1;\n while (index <= numFiles) {\n const s = 's' + index;\n const attachment = {\n uuid: s,\n content_type: 'image/png',\n type: 'image/png',\n filename: 'name_' + s,\n url: 'url_' + s,\n size: 1024,\n error: null\n } as Attachment;\n attachments.push(attachment);\n index++;\n }\n return attachments;\n};\n\nexport const updateComponent = async (\n compose: Compose,\n text?: string,\n attachments?: Attachment[]\n): Promise<void> => {\n compose.initialText = text ? text : '';\n compose.currentAttachments = attachments ? attachments : [];\n await compose.updateComplete;\n};\nexport const getValidText = () => {\n return 'sà-wàd-dee!';\n};\n\n// Helper for waiting for select pagination to complete\nexport const waitForSelectPagination = async (\n select: Select<SelectOption>,\n clock: any,\n expectedCount: number,\n maxAttempts: number = 30\n): Promise<void> => {\n let attempts = 0;\n while (attempts < maxAttempts) {\n // Ensure we're not still fetching\n if (!select.fetching && select.visibleOptions.length >= expectedCount) {\n return;\n }\n\n await select.updateComplete;\n clock.runAll();\n\n // Give more time between attempts for slow CI environments\n await delay(75);\n\n attempts++;\n }\n\n throw new Error(\n `Pagination did not complete after ${maxAttempts} attempts (${\n maxAttempts * 75\n }ms). ` +\n `Expected ${expectedCount} options, got ${select.visibleOptions.length}. ` +\n `Fetching: ${select.fetching}`\n );\n};\n"]}
1
+ {"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../test/utils.test.ts"],"names":[],"mappings":"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","sourcesContent":["import '../temba-modules';\nimport { DateTime } from 'luxon';\ninterface Clip {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nimport { expect, fixture, html, assert } from '@open-wc/testing';\n\n// disable transitions for all tests to prevent flaky screenshot tests\nconst style = document.createElement('style');\nstyle.textContent = `\n * {\n --transition-speed: 0ms !important;\n }\n`;\ndocument.head.appendChild(style);\n\n// prevent resize event listeners from being added during tests\n// this prevents flaky positioning in components that adjust on resize\nconst originalAddEventListener = window.addEventListener;\nwindow.addEventListener = function (type, listener, options) {\n if (type === 'resize') {\n // skip adding resize listeners during tests\n return;\n }\n return originalAddEventListener.call(this, type, listener, options);\n} as typeof window.addEventListener;\nimport MouseHelper from './MouseHelper';\nimport { Store } from '../src/store/Store';\nimport { stub } from 'sinon';\nimport { Select, SelectOption } from '../src/form/select/Select';\nimport { Options } from '../src/display/Options';\nimport { Attachment } from '../src/interfaces';\nimport { Compose } from '../src/form/Compose';\n\nexport interface CodeMock {\n endpoint: RegExp;\n body: string;\n headers: any;\n status: string;\n}\n\nconst gets: CodeMock[] = [];\nlet posts: CodeMock[] = [];\nlet normalFetch;\n\nexport const showMouse = async () => {\n const mouse = await fixture(html`<mouse-helper />`);\n assert.instanceOf(mouse, MouseHelper);\n};\n\nexport const getAttributes = (attrs: any = {}) => {\n return `${Object.keys(attrs)\n .map((name: string) => {\n if (typeof attrs[name] === 'boolean' && attrs[name]) {\n return name;\n }\n return `${name}='${attrs[name]}'`;\n })\n .join(' ')}`;\n};\n\nexport const getComponent = async (\n tag,\n attrs: any = {},\n slot = '',\n width = 250,\n height = 0,\n style = ''\n) => {\n const spec = `<${tag} ${getAttributes(attrs)}>${slot}</${tag}>`;\n const parentNode = document.createElement('div');\n const styleAttribute = `\n ${width > 0 ? `width:${width}px;` : ``} \n ${height > 0 ? `height:${height}px;` : ``}\n ${style ? style : ``}\n `;\n parentNode.setAttribute('style', styleAttribute);\n return await fixture(spec, { parentNode });\n};\n\nconst createResponse = (mocked) => {\n const mockResponse = new window.Response(mocked.body, {\n status: mocked.status,\n headers: {\n 'Content-type': 'text/html',\n ...mocked.headers\n }\n });\n\n return Promise.resolve(mockResponse);\n};\n\nconst createJSONResponse = (mocked) => {\n const mockResponse = new window.Response(JSON.stringify(mocked.body), {\n status: mocked.status,\n headers: {\n 'Content-type': 'application/json',\n ...mocked.headers\n }\n });\n\n return Promise.resolve(mockResponse);\n};\n\nconst getResponse = (endpoint: string, options = { method: 'GET' }) => {\n // check if our path has been mocked in code\n const mocks = options.method === 'GET' ? gets : posts;\n const codeMock = mocks.find((mock) => mock.endpoint.test(endpoint));\n\n if (codeMock) {\n if (typeof codeMock.body === 'string') {\n // see if we are being mocked to a file\n if (codeMock.body.startsWith('/')) {\n endpoint = codeMock.body;\n } else {\n return createResponse(codeMock);\n }\n } else {\n return createJSONResponse(codeMock);\n }\n }\n // otherwise fetch over http\n return normalFetch(endpoint, options);\n};\n\nbefore(async () => {\n normalFetch = window.fetch;\n stub(window, 'fetch').callsFake(getResponse);\n await setViewport({ width: 1920, height: 1080, deviceScaleFactor: 2 });\n});\n\nafter(() => {\n (window.fetch as any).restore();\n});\n\nconst mockMapping = {\n '/test-assets/api/users/admin1.json': [\n /\\/api\\/v2\\/users.json\\?email=admin1@nyaruka.com/\n ],\n '/test-assets/api/users/editor1.json': [\n /\\/api\\/v2\\/users.json\\?email=editor1@nyaruka.com/\n ],\n '/test-assets/api/users/agent1.json': [\n /\\/api\\/v2\\/users.json\\?email=agent1@nyaruka.com/\n ],\n '/test-assets/api/users/viewer1.json': [\n /\\/api\\/v2\\/users.json\\?email=viewer1@nyaruka.com/\n ],\n '/test-assets/contacts/contact-tickets.json': [\n /\\/api\\/v2\\/tickets.json\\?contact=24d64810-3315-4ff5-be85-48e3fe055bf9/\n ]\n};\n\nexport const mockAPI = () => {\n for (const key in mockMapping) {\n const urls = mockMapping[key];\n for (const url of urls) {\n mockGET(url, key);\n }\n }\n\n // Add mock data for contact form endpoints\n mockGET(/\\/api\\/v2\\/channels\\.json/, {\n results: [\n { uuid: 'chan-1', name: 'WhatsApp Channel' },\n { uuid: 'chan-2', name: 'Telegram Channel' },\n { uuid: 'chan-3', name: 'SMS Channel' },\n { uuid: 'chan-4', name: 'Facebook Messenger' }\n ]\n });\n\n mockGET(/\\/api\\/v2\\/languages\\.json/, {\n results: [\n { iso: 'eng', name: 'English' },\n { iso: 'spa', name: 'Spanish' },\n { iso: 'fra', name: 'French' },\n { iso: 'por', name: 'Portuguese' },\n { iso: 'deu', name: 'German' }\n ]\n });\n};\n\nexport const mockGET = (\n endpoint: RegExp,\n body: any,\n headers: any = {},\n status = '200'\n) => {\n gets.push({ endpoint, body, headers, status });\n};\n\nexport const mockPOST = (\n endpoint: RegExp,\n body: any,\n headers: any = {},\n status = '200'\n) => {\n posts.push({ endpoint, body, headers, status });\n};\n\nexport const clearMockPosts = () => {\n posts = [];\n};\n\nexport const checkTimers = (clock: any) => {\n expect(!!clock.timers).to.equal(true, 'Expected timers not found');\n expect(\n Object.keys(clock.timers).length,\n `Timers still to be run ${JSON.stringify(clock.timers)}`\n ).to.equal(0);\n};\n\nexport const delay = (millis: number) => {\n return new Promise(function (resolve) {\n window.setTimeout(resolve, millis);\n });\n};\n\n// Enhanced wait utility for more robust testing\nexport const waitForCondition = async (\n predicate: () => boolean,\n maxAttempts: number = 20,\n delayMs: number = 50\n): Promise<void> => {\n let attempts = 0;\n while (!predicate() && attempts < maxAttempts) {\n await delay(delayMs);\n attempts++;\n }\n if (!predicate()) {\n throw new Error(\n `Condition not met after ${maxAttempts} attempts (${\n maxAttempts * delayMs\n }ms)`\n );\n }\n};\n\nexport const assertScreenshot = async (filename: string, clip: Clip) => {\n // detect if we're running in copilot's environment and use adaptive threshold\n const isCopilotEnvironment = (window as any).isCopilotEnvironment;\n const threshold = isCopilotEnvironment ? 1.0 : 0.1;\n const exclude: Clip[] = [];\n\n try {\n await (window as any).matchPageSnapshot(\n `${filename}.png`,\n clip,\n exclude,\n threshold\n );\n } catch (error) {\n if (error.message) {\n throw new Error(\n `${error.message} ${\n error.expected\n ? `Expected ${error.expected} but got ${error.actual}`\n : ''\n } ${error.files ? `\\n${error.files.join('\\n')}` : ''}`\n );\n }\n throw new Error(error);\n }\n};\n\nexport const getClip = (ele: HTMLElement) => {\n let clip: any = ele.getBoundingClientRect();\n if (!clip.width || !clip.height) {\n clip = ele.shadowRoot.firstElementChild.getBoundingClientRect();\n }\n\n // add some padding\n const padding = 10;\n const width = clip.width + padding * 2;\n const height = clip.height + padding * 2;\n const y = clip.y - padding;\n const x = clip.x - padding;\n\n const newClip = {\n x,\n y,\n width,\n height,\n bottom: y + height,\n right: x + width,\n top: y,\n left: x\n };\n\n return newClip;\n};\n\nexport const mouseClickElement = async (ele: HTMLElement | Element) => {\n const bounds = ele.getBoundingClientRect();\n await mouseClick(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);\n};\n\nexport const getHTMLAttrs = (attrs: any = {}) => {\n return Object.keys(attrs)\n .map((name: string) => `${name}='${attrs[name]}'`)\n .join(' ');\n};\n\nexport const getHTML = (tag: string, attrs: any = {}) => {\n return `<${tag} ${getHTMLAttrs(attrs)}></${tag}>`;\n};\n\nexport const loadStore = async () => {\n const store: Store = await fixture(\n `<temba-store \n completion='/test-assets/store/editor.json'\n groups='/test-assets/store/groups.json'\n languages='/test-assets/store/languages.json'\n fields='/test-assets/store/fields.json'\n users='/test-assets/store/users.json'\n workspace='/test-assets/store/workspace.json'\n />`\n );\n await store.initialHttpComplete;\n await store.initialHttpComplete;\n\n return store;\n};\n\nexport const mockNow = (isodate: string) => {\n return stub(DateTime, 'now').returns(DateTime.fromISO(isodate));\n};\n\nexport const getOptions = (select: Select<SelectOption>): Options => {\n return select.shadowRoot.querySelector('temba-options[visible]');\n};\n\nexport const clickOption = async (\n clock: any,\n select: Select<SelectOption>,\n index: number\n) => {\n const options = getOptions(select);\n if (!options) {\n throw new Error('No options element found');\n }\n\n // Wait for the specific option to be available, but only if it's not already there\n const existingOption = options.shadowRoot?.querySelector(\n `[data-option-index=\"${index}\"]`\n );\n if (!existingOption) {\n try {\n // Increased wait time to handle slower CI environments\n await waitForCondition(\n () => {\n const option = options.shadowRoot?.querySelector(\n `[data-option-index=\"${index}\"]`\n );\n return !!option;\n },\n 10,\n 25\n );\n } catch (e) {\n throw new Error(`Option at index ${index} not found after waiting`);\n }\n }\n\n const option = options.shadowRoot.querySelector(\n `[data-option-index=\"${index}\"]`\n ) as HTMLDivElement;\n\n await mouseClickElement(option);\n await options.updateComplete;\n await select.updateComplete;\n await clock.runAll();\n\n checkTimers(clock);\n};\nexport const openSelect = async (clock: any, select: Select<SelectOption>) => {\n const container = select.shadowRoot.querySelector('.select-container');\n container.dispatchEvent(new MouseEvent('click', { bubbles: true }));\n\n clock.runAll();\n\n // add more explicit waiting and clock ticks\n await select.updateComplete;\n clock.runAll();\n\n // reduce wait time for options to become visible\n await waitFor(25);\n clock.runAll();\n\n // For non-endpoint selects, options might be immediately available\n // For endpoint selects, we need to wait for them to load\n const hasEndpoint = select.getAttribute('endpoint');\n if (hasEndpoint) {\n try {\n // Wait for options to be properly rendered and visible (but only for endpoint selects)\n // Increased max attempts to handle slower CI environments\n await waitForCondition(\n () => {\n const options = select.shadowRoot.querySelector(\n 'temba-options[visible]'\n );\n return options && options.isConnected;\n },\n 10,\n 25\n );\n } catch (e) {\n // If condition fails, continue - some tests might not need options to be visible immediately\n }\n }\n};\n\nexport const openAndClick = async (\n clock: any,\n select: Select<SelectOption>,\n idx: number\n) => {\n await openSelect(clock, select);\n\n // Add this line to ensure proper timing when running as part of a test suite\n await select.updateComplete;\n clock.tick(25); // Reduced from 50 to give minimum time for options to render\n\n await clickOption(clock, select, idx);\n};\n\n// valid = attachments that are uploaded sent to the server when the user clicks send\nexport const getValidAttachments = (numFiles = 2): Attachment[] => {\n const attachments = [];\n let index = 1;\n while (index <= numFiles) {\n const s = 's' + index;\n const attachment = {\n uuid: s,\n content_type: 'image/png',\n type: 'image/png',\n filename: 'name_' + s,\n url: 'url_' + s,\n size: 1024,\n error: null\n } as Attachment;\n attachments.push(attachment);\n index++;\n }\n return attachments;\n};\n\nexport const updateComponent = async (\n compose: Compose,\n text?: string,\n attachments?: Attachment[]\n): Promise<void> => {\n compose.initialText = text ? text : '';\n compose.currentAttachments = attachments ? attachments : [];\n await compose.updateComplete;\n};\nexport const getValidText = () => {\n return 'sà-wàd-dee!';\n};\n\n// Helper for waiting for select pagination to complete\nexport const waitForSelectPagination = async (\n select: Select<SelectOption>,\n clock: any,\n expectedCount: number,\n maxAttempts: number = 30\n): Promise<void> => {\n let attempts = 0;\n while (attempts < maxAttempts) {\n // Ensure we're not still fetching\n if (!select.fetching && select.visibleOptions.length >= expectedCount) {\n return;\n }\n\n await select.updateComplete;\n clock.runAll();\n\n // Give more time between attempts for slow CI environments\n await delay(75);\n\n attempts++;\n }\n\n throw new Error(\n `Pagination did not complete after ${maxAttempts} attempts (${\n maxAttempts * 75\n }ms). ` +\n `Expected ${expectedCount} options, got ${select.visibleOptions.length}. ` +\n `Fetching: ${select.fetching}`\n );\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nyaruka/temba-components",
3
- "version": "0.131.2",
3
+ "version": "0.132.0",
4
4
  "description": "Web components to support rapidpro and related projects",
5
5
  "author": "Nyaruka <code@nyaruka.coim>",
6
6
  "main": "dist/index.js",