@hubspot/ui-extensions 0.11.1 → 0.11.3

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 (236) hide show
  1. package/dist/__tests__/crm/hooks/useAssociations.spec.js +36 -32
  2. package/dist/__tests__/crm/hooks/useCrmProperties.spec.js +20 -19
  3. package/dist/__tests__/crm/utils/fetchAssociations.spec.js +13 -12
  4. package/dist/__tests__/crm/utils/fetchCrmProperties.spec.js +38 -37
  5. package/dist/clientTypes.d.ts +1 -0
  6. package/dist/clientTypes.js +1 -1
  7. package/dist/crm/hooks/useAssociations.d.ts +5 -3
  8. package/dist/crm/hooks/useAssociations.js +4 -2
  9. package/dist/crm/hooks/useCrmProperties.d.ts +4 -2
  10. package/dist/crm/hooks/useCrmProperties.js +4 -2
  11. package/dist/crm/index.d.ts +4 -4
  12. package/dist/crm/index.js +3 -3
  13. package/dist/crm/utils/fetchAssociations.d.ts +1 -1
  14. package/dist/experimental/index.d.ts +4 -4
  15. package/dist/experimental/index.js +3 -3
  16. package/dist/experimental/testing/__tests__/createRenderer.spec.js +23 -0
  17. package/dist/experimental/testing/__tests__/debug.spec.js +57 -0
  18. package/dist/experimental/testing/__tests__/find.spec.js +48 -0
  19. package/dist/experimental/testing/__tests__/findAll.spec.js +13 -0
  20. package/dist/experimental/testing/__tests__/findAllChildren.spec.js +54 -0
  21. package/dist/experimental/testing/__tests__/findByTestId.spec.js +126 -0
  22. package/dist/experimental/testing/__tests__/findChild.spec.js +33 -0
  23. package/dist/experimental/testing/__tests__/fragments.spec.js +66 -0
  24. package/dist/experimental/testing/__tests__/invalid-components.spec.js +96 -0
  25. package/dist/experimental/testing/__tests__/isMatch.spec.js +113 -0
  26. package/dist/experimental/testing/__tests__/logger.spec.js +10 -0
  27. package/dist/experimental/testing/__tests__/maybeFind.spec.js +67 -0
  28. package/dist/experimental/testing/__tests__/maybeFindByTestId.spec.js +65 -0
  29. package/dist/experimental/testing/__tests__/maybeFindChild.spec.js +75 -0
  30. package/dist/experimental/testing/__tests__/mocks.actions.spec.js +19 -0
  31. package/dist/experimental/testing/__tests__/mocks.context.spec.js +24 -0
  32. package/dist/experimental/testing/__tests__/mocks.runServerlessFunction.spec.js +35 -0
  33. package/dist/experimental/testing/__tests__/mocks.useAssociations.spec.js +47 -0
  34. package/dist/experimental/testing/__tests__/mocks.useCrmProperties.spec.js +58 -0
  35. package/dist/experimental/testing/__tests__/props.spec.js +13 -0
  36. package/dist/experimental/testing/__tests__/testId.spec.js +18 -0
  37. package/dist/experimental/testing/__tests__/trigger.spec.js +43 -0
  38. package/dist/experimental/testing/__tests__/type-utils.spec.js +165 -0
  39. package/dist/experimental/testing/__tests__/waitFor.spec.js +57 -0
  40. package/dist/experimental/testing/index.d.ts +4 -0
  41. package/dist/experimental/testing/index.js +4 -0
  42. package/dist/experimental/testing/internal/constants.d.ts +2 -2
  43. package/dist/experimental/testing/internal/constants.js +1 -1
  44. package/dist/experimental/testing/internal/convert.d.ts +10 -0
  45. package/dist/experimental/testing/internal/convert.js +149 -0
  46. package/dist/experimental/testing/internal/debug.d.ts +3 -3
  47. package/dist/experimental/testing/internal/debug.js +12 -4
  48. package/dist/experimental/testing/internal/document.d.ts +14 -0
  49. package/dist/experimental/testing/internal/document.js +40 -0
  50. package/dist/experimental/testing/internal/element.d.ts +4 -3
  51. package/dist/experimental/testing/internal/element.js +15 -10
  52. package/dist/experimental/testing/internal/errors.d.ts +57 -2
  53. package/dist/experimental/testing/internal/errors.js +62 -2
  54. package/dist/experimental/testing/internal/fragment.d.ts +3 -2
  55. package/dist/experimental/testing/internal/fragment.js +13 -9
  56. package/dist/experimental/testing/internal/match.d.ts +10 -0
  57. package/dist/experimental/testing/internal/match.js +19 -0
  58. package/dist/experimental/testing/internal/mocks/index.d.ts +17 -0
  59. package/dist/experimental/testing/internal/mocks/index.js +46 -0
  60. package/dist/experimental/testing/internal/mocks/mock-extension-point-api.d.ts +2 -0
  61. package/dist/experimental/testing/internal/mocks/mock-extension-point-api.js +166 -0
  62. package/dist/experimental/testing/internal/mocks/mock-hooks.d.ts +2 -0
  63. package/dist/experimental/testing/internal/mocks/mock-hooks.js +59 -0
  64. package/dist/experimental/testing/internal/print.d.ts +2 -2
  65. package/dist/experimental/testing/internal/print.js +17 -11
  66. package/dist/experimental/testing/internal/query.d.ts +19 -9
  67. package/dist/experimental/testing/internal/query.js +91 -46
  68. package/dist/experimental/testing/internal/root.d.ts +1 -1
  69. package/dist/experimental/testing/internal/root.js +12 -8
  70. package/dist/experimental/testing/internal/text.d.ts +3 -2
  71. package/dist/experimental/testing/internal/text.js +12 -3
  72. package/dist/experimental/testing/internal/type-utils-internal.d.ts +44 -0
  73. package/dist/experimental/testing/internal/type-utils-internal.js +54 -0
  74. package/dist/experimental/testing/internal/types-internal.d.ts +20 -2
  75. package/dist/experimental/testing/internal/utils/promise-utils.d.ts +14 -0
  76. package/dist/experimental/testing/internal/utils/promise-utils.js +14 -0
  77. package/dist/experimental/testing/render.d.ts +35 -0
  78. package/dist/experimental/testing/render.js +219 -0
  79. package/dist/experimental/testing/type-utils.d.ts +2 -2
  80. package/dist/experimental/testing/type-utils.js +1 -1
  81. package/dist/experimental/testing/types.d.ts +127 -9
  82. package/dist/experimental/testing/utils.d.ts +11 -0
  83. package/dist/experimental/testing/utils.js +24 -0
  84. package/dist/hubspot.d.ts +2 -4
  85. package/dist/hubspot.js +3 -3
  86. package/dist/index.d.ts +5 -5
  87. package/dist/index.js +5 -5
  88. package/dist/internal/global-utils.d.ts +6 -0
  89. package/dist/internal/global-utils.js +37 -0
  90. package/dist/internal/hook-utils.d.ts +19 -0
  91. package/dist/internal/hook-utils.js +34 -0
  92. package/dist/logger.d.ts +1 -8
  93. package/dist/logger.js +3 -2
  94. package/dist/pages/home/index.d.ts +1 -1
  95. package/dist/pages/home/index.js +1 -1
  96. package/dist/{__synced__/remoteComponents.synced.d.ts → shared/remoteComponents.d.ts} +159 -77
  97. package/dist/{__synced__/remoteComponents.synced.js → shared/remoteComponents.js} +99 -1
  98. package/dist/{__synced__/types/components/accordion.synced.d.ts → shared/types/components/accordion.d.ts} +2 -2
  99. package/dist/{__synced__/types/components/alert.synced.d.ts → shared/types/components/alert.d.ts} +2 -1
  100. package/dist/{__synced__/types/components/app-home-header-actions.synced.d.ts → shared/types/components/app-home-header-actions.d.ts} +4 -4
  101. package/dist/{__synced__/types/components/button-row.synced.d.ts → shared/types/components/button-row.d.ts} +2 -2
  102. package/dist/{__synced__/types/components/button.synced.d.ts → shared/types/components/button.d.ts} +9 -3
  103. package/dist/{__synced__/types/components/card.synced.d.ts → shared/types/components/card.d.ts} +2 -1
  104. package/dist/{__synced__/types/components/chart.synced.d.ts → shared/types/components/chart.d.ts} +2 -1
  105. package/dist/{__synced__/types/components/description-list.synced.d.ts → shared/types/components/description-list.d.ts} +3 -2
  106. package/dist/{__synced__/types/components/divider.synced.d.ts → shared/types/components/divider.d.ts} +2 -2
  107. package/dist/{__synced__/types/components/dropdown.synced.d.ts → shared/types/components/dropdown.d.ts} +5 -5
  108. package/dist/{__synced__/types/components/empty-state.synced.d.ts → shared/types/components/empty-state.d.ts} +2 -1
  109. package/dist/{__synced__/types/components/error-state.synced.d.ts → shared/types/components/error-state.d.ts} +2 -1
  110. package/dist/{__synced__/types/components/form.synced.d.ts → shared/types/components/form.d.ts} +3 -3
  111. package/dist/{__synced__/types/components/heading.synced.d.ts → shared/types/components/heading.d.ts} +2 -1
  112. package/dist/{__synced__/types/components/icon.synced.d.ts → shared/types/components/icon.d.ts} +2 -2
  113. package/dist/{__synced__/types/components/iframe.synced.d.ts → shared/types/components/iframe.d.ts} +2 -2
  114. package/dist/{__synced__/types/components/illustration.synced.d.ts → shared/types/components/illustration.d.ts} +2 -1
  115. package/dist/{__synced__/types/components/image.synced.d.ts → shared/types/components/image.d.ts} +3 -3
  116. package/dist/shared/types/components/index.d.ts +38 -0
  117. package/dist/shared/types/components/index.js +1 -0
  118. package/dist/{__synced__/types/components/inputs.synced.d.ts → shared/types/components/inputs.d.ts} +2 -1
  119. package/dist/shared/types/components/inputs.js +1 -0
  120. package/dist/{__synced__/types/components/layouts.synced.d.ts → shared/types/components/layouts.d.ts} +6 -6
  121. package/dist/shared/types/components/layouts.js +1 -0
  122. package/dist/{__synced__/types/components/link.synced.d.ts → shared/types/components/link.d.ts} +3 -3
  123. package/dist/shared/types/components/link.js +1 -0
  124. package/dist/{__synced__/types/components/list.synced.d.ts → shared/types/components/list.d.ts} +2 -1
  125. package/dist/shared/types/components/list.js +1 -0
  126. package/dist/{__synced__/types/components/loading-spinner.synced.d.ts → shared/types/components/loading-spinner.d.ts} +2 -2
  127. package/dist/shared/types/components/loading-spinner.js +1 -0
  128. package/dist/{__synced__/types/components/modal.synced.d.ts → shared/types/components/modal.d.ts} +4 -4
  129. package/dist/shared/types/components/modal.js +1 -0
  130. package/dist/{__synced__/types/components/panel.synced.d.ts → shared/types/components/panel.d.ts} +5 -5
  131. package/dist/shared/types/components/panel.js +1 -0
  132. package/dist/{__synced__/types/components/progress-bar.synced.d.ts → shared/types/components/progress-bar.d.ts} +2 -1
  133. package/dist/shared/types/components/progress-bar.js +1 -0
  134. package/dist/{__synced__/types/components/selects.synced.d.ts → shared/types/components/selects.d.ts} +2 -1
  135. package/dist/shared/types/components/selects.js +1 -0
  136. package/dist/{__synced__/types/components/statistics.synced.d.ts → shared/types/components/statistics.d.ts} +4 -3
  137. package/dist/shared/types/components/statistics.js +1 -0
  138. package/dist/{__synced__/types/components/status-tag.synced.d.ts → shared/types/components/status-tag.d.ts} +2 -1
  139. package/dist/shared/types/components/status-tag.js +1 -0
  140. package/dist/{__synced__/types/components/step-indicator.synced.d.ts → shared/types/components/step-indicator.d.ts} +2 -2
  141. package/dist/shared/types/components/step-indicator.js +1 -0
  142. package/dist/{__synced__/types/components/table.synced.d.ts → shared/types/components/table.d.ts} +5 -4
  143. package/dist/shared/types/components/table.js +1 -0
  144. package/dist/{__synced__/types/components/tabs.synced.d.ts → shared/types/components/tabs.d.ts} +3 -2
  145. package/dist/shared/types/components/tabs.js +1 -0
  146. package/dist/{__synced__/types/components/tag.synced.d.ts → shared/types/components/tag.d.ts} +3 -3
  147. package/dist/shared/types/components/tag.js +1 -0
  148. package/dist/{__synced__/types/components/text.synced.d.ts → shared/types/components/text.d.ts} +2 -1
  149. package/dist/shared/types/components/text.js +1 -0
  150. package/dist/{__synced__/types/components/tile.synced.d.ts → shared/types/components/tile.d.ts} +2 -1
  151. package/dist/shared/types/components/tile.js +1 -0
  152. package/dist/{__synced__/types/components/toggle.synced.d.ts → shared/types/components/toggle.d.ts} +2 -2
  153. package/dist/shared/types/components/toggle.js +1 -0
  154. package/dist/{__synced__/types/components/toggleInputs.synced.d.ts → shared/types/components/toggleInputs.d.ts} +4 -4
  155. package/dist/shared/types/components/toggleInputs.js +1 -0
  156. package/dist/{__synced__/types/components/tooltip.synced.d.ts → shared/types/components/tooltip.d.ts} +2 -1
  157. package/dist/shared/types/components/tooltip.js +1 -0
  158. package/dist/{__synced__/types/context.synced.d.ts → shared/types/context.d.ts} +1 -1
  159. package/dist/shared/types/context.js +1 -0
  160. package/dist/{__synced__/types/crm.synced.d.ts → shared/types/crm.d.ts} +13 -13
  161. package/dist/shared/types/crm.js +1 -0
  162. package/dist/{__synced__/experimental/types.synced.d.ts → shared/types/experimental.d.ts} +12 -17
  163. package/dist/shared/types/experimental.js +1 -0
  164. package/dist/shared/types/extend.d.ts +4 -0
  165. package/dist/shared/types/extend.js +1 -0
  166. package/dist/{__synced__/types/extension-points.synced.d.ts → shared/types/extension-points.d.ts} +18 -10
  167. package/dist/{__synced__/types/http-requests.synced.d.ts → shared/types/http-requests.d.ts} +1 -1
  168. package/dist/shared/types/index.d.ts +8 -0
  169. package/dist/shared/types/index.js +1 -0
  170. package/dist/shared/types/logger.d.ts +7 -0
  171. package/dist/shared/types/logger.js +1 -0
  172. package/dist/shared/types/reactions.js +1 -0
  173. package/dist/{__synced__/types/shared.synced.d.ts → shared/types/shared.d.ts} +3 -0
  174. package/dist/shared/types/worker-globals.d.ts +17 -0
  175. package/dist/shared/types/worker-globals.js +1 -0
  176. package/dist/{__synced__/utils/remote-component-registry.synced.d.ts → shared/utils/remote-component-registry.d.ts} +1 -1
  177. package/dist/{__synced__/utils/remote-component-registry.synced.js → shared/utils/remote-component-registry.js} +0 -1
  178. package/package.json +13 -14
  179. package/dist/__synced__/appHomeRemoteComponents.synced.d.ts +0 -28
  180. package/dist/__synced__/appHomeRemoteComponents.synced.js +0 -21
  181. package/dist/__synced__/crmRemoteComponents.synced.d.ts +0 -66
  182. package/dist/__synced__/crmRemoteComponents.synced.js +0 -15
  183. package/dist/__synced__/experimental/types.synced.js +0 -5
  184. package/dist/__synced__/experimentalRemoteComponents.synced.d.ts +0 -94
  185. package/dist/__synced__/experimentalRemoteComponents.synced.js +0 -56
  186. package/dist/__synced__/types/components/index.synced.d.ts +0 -38
  187. package/dist/__synced__/types/index.synced.d.ts +0 -8
  188. package/dist/__synced__/types/index.synced.js +0 -1
  189. /package/dist/{__synced__/types/actions.synced.js → experimental/testing/__tests__/createRenderer.spec.d.ts} +0 -0
  190. /package/dist/{__synced__/types/components/accordion.synced.js → experimental/testing/__tests__/debug.spec.d.ts} +0 -0
  191. /package/dist/{__synced__/types/components/alert.synced.js → experimental/testing/__tests__/find.spec.d.ts} +0 -0
  192. /package/dist/{__synced__/types/components/app-home-header-actions.synced.js → experimental/testing/__tests__/findAll.spec.d.ts} +0 -0
  193. /package/dist/{__synced__/types/components/button-row.synced.js → experimental/testing/__tests__/findAllChildren.spec.d.ts} +0 -0
  194. /package/dist/{__synced__/types/components/button.synced.js → experimental/testing/__tests__/findByTestId.spec.d.ts} +0 -0
  195. /package/dist/{__synced__/types/components/card.synced.js → experimental/testing/__tests__/findChild.spec.d.ts} +0 -0
  196. /package/dist/{__synced__/types/components/description-list.synced.js → experimental/testing/__tests__/fragments.spec.d.ts} +0 -0
  197. /package/dist/{__synced__/types/components/divider.synced.js → experimental/testing/__tests__/invalid-components.spec.d.ts} +0 -0
  198. /package/dist/{__synced__/types/components/dropdown.synced.js → experimental/testing/__tests__/isMatch.spec.d.ts} +0 -0
  199. /package/dist/{__synced__/types/components/empty-state.synced.js → experimental/testing/__tests__/logger.spec.d.ts} +0 -0
  200. /package/dist/{__synced__/types/components/error-state.synced.js → experimental/testing/__tests__/maybeFind.spec.d.ts} +0 -0
  201. /package/dist/{__synced__/types/components/form.synced.js → experimental/testing/__tests__/maybeFindByTestId.spec.d.ts} +0 -0
  202. /package/dist/{__synced__/types/components/heading.synced.js → experimental/testing/__tests__/maybeFindChild.spec.d.ts} +0 -0
  203. /package/dist/{__synced__/types/components/icon.synced.js → experimental/testing/__tests__/mocks.actions.spec.d.ts} +0 -0
  204. /package/dist/{__synced__/types/components/iframe.synced.js → experimental/testing/__tests__/mocks.context.spec.d.ts} +0 -0
  205. /package/dist/{__synced__/types/components/image.synced.js → experimental/testing/__tests__/mocks.runServerlessFunction.spec.d.ts} +0 -0
  206. /package/dist/{__synced__/types/components/index.synced.js → experimental/testing/__tests__/mocks.useAssociations.spec.d.ts} +0 -0
  207. /package/dist/{__synced__/types/components/inputs.synced.js → experimental/testing/__tests__/mocks.useCrmProperties.spec.d.ts} +0 -0
  208. /package/dist/{__synced__/types/components/layouts.synced.js → experimental/testing/__tests__/props.spec.d.ts} +0 -0
  209. /package/dist/{__synced__/types/components/link.synced.js → experimental/testing/__tests__/testId.spec.d.ts} +0 -0
  210. /package/dist/{__synced__/types/components/list.synced.js → experimental/testing/__tests__/trigger.spec.d.ts} +0 -0
  211. /package/dist/{__synced__/types/components/loading-spinner.synced.js → experimental/testing/__tests__/type-utils.spec.d.ts} +0 -0
  212. /package/dist/{__synced__/types/components/modal.synced.js → experimental/testing/__tests__/waitFor.spec.d.ts} +0 -0
  213. /package/dist/{__synced__/types/actions.synced.d.ts → shared/types/actions.d.ts} +0 -0
  214. /package/dist/{__synced__/types/components/panel.synced.js → shared/types/actions.js} +0 -0
  215. /package/dist/{__synced__/types/components/progress-bar.synced.js → shared/types/components/accordion.js} +0 -0
  216. /package/dist/{__synced__/types/components/selects.synced.js → shared/types/components/alert.js} +0 -0
  217. /package/dist/{__synced__/types/components/statistics.synced.js → shared/types/components/app-home-header-actions.js} +0 -0
  218. /package/dist/{__synced__/types/components/status-tag.synced.js → shared/types/components/button-row.js} +0 -0
  219. /package/dist/{__synced__/types/components/step-indicator.synced.js → shared/types/components/button.js} +0 -0
  220. /package/dist/{__synced__/types/components/table.synced.js → shared/types/components/card.js} +0 -0
  221. /package/dist/{__synced__/types/components/chart.synced.js → shared/types/components/chart.js} +0 -0
  222. /package/dist/{__synced__/types/components/tabs.synced.js → shared/types/components/description-list.js} +0 -0
  223. /package/dist/{__synced__/types/components/tag.synced.js → shared/types/components/divider.js} +0 -0
  224. /package/dist/{__synced__/types/components/text.synced.js → shared/types/components/dropdown.js} +0 -0
  225. /package/dist/{__synced__/types/components/tile.synced.js → shared/types/components/empty-state.js} +0 -0
  226. /package/dist/{__synced__/types/components/toggle.synced.js → shared/types/components/error-state.js} +0 -0
  227. /package/dist/{__synced__/types/components/toggleInputs.synced.js → shared/types/components/form.js} +0 -0
  228. /package/dist/{__synced__/types/components/tooltip.synced.js → shared/types/components/heading.js} +0 -0
  229. /package/dist/{__synced__/types/context.synced.js → shared/types/components/icon.js} +0 -0
  230. /package/dist/{__synced__/types/crm.synced.js → shared/types/components/iframe.js} +0 -0
  231. /package/dist/{__synced__/types/components/illustration.synced.js → shared/types/components/illustration.js} +0 -0
  232. /package/dist/{__synced__/types/reactions.synced.js → shared/types/components/image.js} +0 -0
  233. /package/dist/{__synced__/types/extension-points.synced.js → shared/types/extension-points.js} +0 -0
  234. /package/dist/{__synced__/types/http-requests.synced.js → shared/types/http-requests.js} +0 -0
  235. /package/dist/{__synced__/types/reactions.synced.d.ts → shared/types/reactions.d.ts} +0 -0
  236. /package/dist/{__synced__/types/shared.synced.js → shared/types/shared.js} +0 -0
@@ -0,0 +1,96 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { Alert, Button, ButtonRow, Text } from "../../../index.js";
5
+ import { createRenderer } from "../index.js";
6
+ import { InvalidComponentsError } from "../internal/errors.js";
7
+ import { createDeferred } from "../internal/utils/promise-utils.js";
8
+ const setTimeoutPromise = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
9
+ describe('handling invalid components', () => {
10
+ it('should throw an error if initial render contains invalid components', () => {
11
+ const { render } = createRenderer('crm.record.tab');
12
+ function MyComponent() {
13
+ return (_jsx("div", { children: _jsx("span", { children: _jsx(Button, { variant: "primary", children: "Click me!" }) }) }));
14
+ }
15
+ expect(() => render(_jsx(MyComponent, {}))).toThrow(InvalidComponentsError);
16
+ let errorMessage;
17
+ try {
18
+ render(_jsx(MyComponent, {}));
19
+ }
20
+ catch (error) {
21
+ errorMessage = String(error);
22
+ }
23
+ expect(errorMessage).toMatchSnapshot();
24
+ });
25
+ it('should throw an error if initial render contains invalid components inside a fragment', () => {
26
+ const { render } = createRenderer('crm.record.tab');
27
+ function MyComponent() {
28
+ return (_jsxs(_Fragment, { children: [_jsx(ButtonRow, { children: _jsx(Button, { variant: "primary", overlay: _jsx("div", { children: "Overlay" }), children: "Click me!" }) }), _jsx(Alert, { title: "My Alert" })] }));
29
+ }
30
+ expect(() => render(_jsx(MyComponent, {}))).toThrow(InvalidComponentsError);
31
+ });
32
+ it('should throw an error if triggering an event results in an invalid component to be rendered', () => {
33
+ const { render } = createRenderer('crm.record.tab');
34
+ function Counter() {
35
+ const [count, setCount] = useState(0);
36
+ const handleClick = () => {
37
+ setCount(count + 1);
38
+ };
39
+ return (_jsx(Button, { variant: "primary", onClick: handleClick, children: count === 0 ? 'Click me!' : _jsxs("div", { children: ["Clicked ", count, " times"] }) }));
40
+ }
41
+ const { find } = render(_jsx(Counter, {}));
42
+ expect(find(Button).text).toEqual('Click me!');
43
+ // Should throw an error because the component is invalid
44
+ expect(() => {
45
+ find(Button).trigger('onClick');
46
+ }).toThrow(InvalidComponentsError);
47
+ });
48
+ it('should throw an error if the component is invalid after an asynchronous update', async () => {
49
+ function AsyncCounter() {
50
+ const [count, setCount] = useState(0);
51
+ useEffect(() => {
52
+ setTimeout(() => {
53
+ setCount((currentCount) => currentCount + 1);
54
+ }, 10);
55
+ }, []);
56
+ return (_jsx(Button, { children: count === 0 ? 'Click me!' : _jsxs("div", { children: ["Clicked ", count, " times"] }) }));
57
+ }
58
+ const { render, find, waitFor } = createRenderer('crm.record.tab');
59
+ render(_jsx(AsyncCounter, {}));
60
+ expect(find(Button).text).toEqual('Click me!');
61
+ await expect(waitFor(() => {
62
+ expect(find(Button).text).toEqual('Clicked 1 times');
63
+ })).rejects.toThrow(InvalidComponentsError);
64
+ });
65
+ it('should throw an error if the component is invalid after an asynchronous update when not using waitFor', async () => {
66
+ const usePromise = (promise) => {
67
+ const [isPending, setIsPending] = useState(true);
68
+ useEffect(() => {
69
+ setIsPending(true);
70
+ promise
71
+ .then(() => setIsPending(false))
72
+ .catch(() => setIsPending(false));
73
+ }, [promise]);
74
+ return { isPending };
75
+ };
76
+ function AsyncCounter({ promise }) {
77
+ const { isPending } = usePromise(promise);
78
+ if (isPending) {
79
+ return _jsx(Text, { children: "Loading..." });
80
+ }
81
+ // NOTE: `<div>` is an invalid component that should trigger an error after it is loaded.
82
+ return _jsx("div", { children: "Loaded!" });
83
+ }
84
+ const loadingDeferred = createDeferred();
85
+ const { render, find } = createRenderer('crm.record.tab');
86
+ render(_jsx(AsyncCounter, { promise: loadingDeferred.promise }));
87
+ expect(find(Text).text).toEqual('Loading...');
88
+ loadingDeferred.resolve();
89
+ await loadingDeferred.promise;
90
+ // Wait another 5ms to be extra sure that the component has rerendered
91
+ await setTimeoutPromise(5);
92
+ expect(() => {
93
+ find(Text);
94
+ }).toThrow(InvalidComponentsError);
95
+ });
96
+ });
@@ -0,0 +1,113 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Alert, Button } from "../../../index.js";
4
+ import { createRenderer, isMatch, isRenderedFragmentNode, } from "../index.js";
5
+ describe('isMatch()', () => {
6
+ describe('isMatch() utility function', () => {
7
+ it('should allow assertions against a mix of text and element nodes', () => {
8
+ const { render, getRootNode } = createRenderer('crm.record.tab');
9
+ render(_jsxs(_Fragment, { children: [_jsx(Button, { variant: "primary", children: "Click me!" }), _jsx(Alert, { title: "My Alert" }), "Hello"] }));
10
+ const rootNode = getRootNode();
11
+ const { childNodes } = rootNode;
12
+ const buttonNode = childNodes[0];
13
+ const alertNode = childNodes[1];
14
+ const textNode = childNodes[2];
15
+ if (isMatch(buttonNode, Button)) {
16
+ expect(buttonNode.props.variant).toEqual('primary');
17
+ }
18
+ else {
19
+ throw new Error('Expected button node');
20
+ }
21
+ expect(isMatch(alertNode, Button)).toBe(false);
22
+ expect(isMatch(textNode, Button)).toBe(false);
23
+ });
24
+ it('should allow a custom matcher function to be provided', () => {
25
+ const { render, getRootNode } = createRenderer('crm.record.tab');
26
+ render(_jsxs(_Fragment, { children: [_jsx(Button, { variant: "primary", children: "Primary" }), _jsx(Button, { variant: "secondary", children: "Secondary" }), _jsx(Alert, { title: "My Alert" }), "Hello"] }));
27
+ const rootNode = getRootNode();
28
+ const { childNodes } = rootNode;
29
+ const primaryButtonNode = childNodes[0];
30
+ const secondaryButtonNode = childNodes[1];
31
+ const alertNode = childNodes[2];
32
+ const textNode = childNodes[3];
33
+ const matcher = (node) => node.props.variant === 'primary';
34
+ if (isMatch(primaryButtonNode, Button, matcher)) {
35
+ expect(primaryButtonNode.props.variant).toEqual('primary');
36
+ }
37
+ else {
38
+ throw new Error('Expected button node');
39
+ }
40
+ expect(isMatch(secondaryButtonNode, Button, matcher)).toBe(false);
41
+ expect(isMatch(alertNode, Button, matcher)).toBe(false);
42
+ expect(isMatch(textNode, Button, matcher)).toBe(false);
43
+ });
44
+ it('should allow a partial props object to be provided for matching', () => {
45
+ const { render, getRootNode } = createRenderer('crm.record.tab');
46
+ render(_jsxs(_Fragment, { children: [_jsx(Button, { variant: "primary", children: "Primary" }), _jsx(Button, { variant: "secondary", children: "Secondary" }), _jsx(Alert, { title: "My Alert" }), "Hello"] }));
47
+ const rootNode = getRootNode();
48
+ const { childNodes } = rootNode;
49
+ const primaryButtonNode = childNodes[0];
50
+ const secondaryButtonNode = childNodes[1];
51
+ const alertNode = childNodes[2];
52
+ const textNode = childNodes[3];
53
+ const matcher = { variant: 'primary' };
54
+ if (isMatch(primaryButtonNode, Button, matcher)) {
55
+ expect(primaryButtonNode.props.variant).toEqual('primary');
56
+ }
57
+ else {
58
+ throw new Error('Expected button node');
59
+ }
60
+ expect(isMatch(secondaryButtonNode, Button, matcher)).toBe(false);
61
+ expect(isMatch(alertNode, Button, matcher)).toBe(false);
62
+ expect(isMatch(textNode, Button, matcher)).toBe(false);
63
+ });
64
+ });
65
+ describe('RenderedText.isMatch()', () => {
66
+ it('should work correctly for text nodes', () => {
67
+ const { render, find } = createRenderer('crm.record.tab');
68
+ render(_jsx(Button, { variant: "primary", children: "Primary" }));
69
+ const buttonNode = find(Button);
70
+ const textNode = buttonNode.childNodes[0];
71
+ expect(textNode.isMatch(Button)).toBe(false);
72
+ expect(textNode.isMatch(Button) && textNode.props.variant === 'primary').toBe(false);
73
+ });
74
+ });
75
+ describe('RenderedElement.isMatch()', () => {
76
+ it('should work correctly for element nodes', () => {
77
+ const { render, find } = createRenderer('crm.record.tab');
78
+ render(_jsx(Button, { variant: "primary", children: "Primary" }));
79
+ const buttonNode = find(Button);
80
+ expect(buttonNode.isMatch(Button)).toBe(true);
81
+ });
82
+ it('should work correctly for element nodes with a custom matcher function', () => {
83
+ const { render, find } = createRenderer('crm.record.tab');
84
+ render(_jsx(Button, { variant: "primary", children: "Primary" }));
85
+ const buttonNode = find(Button);
86
+ expect(buttonNode.isMatch(Button, (node) => node.props.variant === 'primary')).toBe(true);
87
+ });
88
+ it('should work correctly for element nodes with a partial props object', () => {
89
+ const { render, find } = createRenderer('crm.record.tab');
90
+ render(_jsx(Button, { variant: "primary", children: "Primary" }));
91
+ const buttonNode = find(Button);
92
+ expect(buttonNode.isMatch(Button, { variant: 'primary' })).toBe(true);
93
+ });
94
+ });
95
+ describe('RenderedFragment.isMatch()', () => {
96
+ it('should work correctly for fragment nodes', () => {
97
+ const { render, find } = createRenderer('crm.record.tab');
98
+ render(_jsx(Button, { variant: "primary", overlay: _jsx(_Fragment, { children: "My Overlay" }), children: "Hello" }));
99
+ const buttonNode = find(Button);
100
+ const overlayFragmentNode = buttonNode.props.overlay;
101
+ expect(isRenderedFragmentNode(overlayFragmentNode)).toBe(true);
102
+ expect(overlayFragmentNode.isMatch(Button)).toBe(false);
103
+ });
104
+ });
105
+ describe('RenderedRoot.isMatch()', () => {
106
+ it('should work correctly for root nodes', () => {
107
+ const { render, getRootNode } = createRenderer('crm.record.tab');
108
+ render(_jsx(Button, { variant: "primary", children: "Primary" }));
109
+ const rootNode = getRootNode();
110
+ expect(rootNode.isMatch(Button)).toBe(false);
111
+ });
112
+ });
113
+ });
@@ -0,0 +1,10 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { logger } from "../../../logger.js";
3
+ describe('logger in test environment', () => {
4
+ it('should be available', () => {
5
+ expect(logger.debug).toBeInstanceOf(Function);
6
+ expect(logger.info).toBeInstanceOf(Function);
7
+ expect(logger.warn).toBeInstanceOf(Function);
8
+ expect(logger.error).toBeInstanceOf(Function);
9
+ });
10
+ });
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Alert, Button, ButtonRow, Text } from "../../../index.js";
4
+ import { createRenderer } from "../index.js";
5
+ describe('maybeFind()', () => {
6
+ it('should return the element when found', () => {
7
+ const { render, maybeFind } = createRenderer('crm.record.tab');
8
+ render(_jsxs(_Fragment, { children: [_jsx(ButtonRow, { children: _jsx(Button, { variant: "primary", children: "Button 1" }) }), _jsx(Alert, { title: "My Alert" })] }));
9
+ const button = maybeFind(Button);
10
+ expect(button).toBeDefined();
11
+ expect(button?.props).toEqual({ variant: 'primary' });
12
+ });
13
+ it('should return null when element is not found', () => {
14
+ const { render, maybeFind } = createRenderer('crm.record.tab');
15
+ render(_jsxs(_Fragment, { children: [_jsx(ButtonRow, { children: _jsx(Button, { variant: "primary", children: "Button 1" }) }), _jsx(Alert, { title: "My Alert" })] }));
16
+ const text = maybeFind(Text);
17
+ expect(text).toBeNull();
18
+ });
19
+ it('should return the first matching element when multiple elements match', () => {
20
+ const { render, maybeFind } = createRenderer('crm.record.tab');
21
+ render(_jsxs(_Fragment, { children: [_jsx(Alert, { title: "First Alert" }), _jsx(Alert, { title: "Second Alert" }), _jsx(Alert, { title: "Third Alert" })] }));
22
+ const alert = maybeFind(Alert);
23
+ expect(alert).toBeDefined();
24
+ expect(alert?.props).toMatchObject({ title: 'First Alert' });
25
+ });
26
+ it('should support matcher function', () => {
27
+ const { render, maybeFind } = createRenderer('crm.record.tab');
28
+ render(_jsx(_Fragment, { children: _jsxs(ButtonRow, { children: [_jsx(Button, { variant: "secondary", children: "Button 1" }), _jsx(Button, { variant: "primary", children: "Button 2" })] }) }));
29
+ const primaryButton = maybeFind(Button, (node) => node.props.variant === 'primary');
30
+ expect(primaryButton).toBeDefined();
31
+ expect(primaryButton?.props).toMatchObject({ variant: 'primary' });
32
+ });
33
+ it('should return null when matcher function does not match any elements', () => {
34
+ const { render, maybeFind } = createRenderer('crm.record.tab');
35
+ render(_jsx(_Fragment, { children: _jsxs(ButtonRow, { children: [_jsx(Button, { variant: "secondary", children: "Button 1" }), _jsx(Button, { variant: "secondary", children: "Button 2" })] }) }));
36
+ const primaryButton = maybeFind(Button, (node) => node.props.variant === 'primary');
37
+ expect(primaryButton).toBeNull();
38
+ });
39
+ it('should support matcher object', () => {
40
+ const { render, maybeFind } = createRenderer('crm.record.tab');
41
+ render(_jsx(_Fragment, { children: _jsxs(ButtonRow, { children: [_jsx(Button, { variant: "secondary", children: "Button 1" }), _jsx(Button, { variant: "primary", children: "Button 2" })] }) }));
42
+ const primaryButton = maybeFind(Button, { variant: 'primary' });
43
+ expect(primaryButton).toBeDefined();
44
+ expect(primaryButton?.props).toMatchObject({ variant: 'primary' });
45
+ });
46
+ it('should return null when matcher object does not match any elements', () => {
47
+ const { render, maybeFind } = createRenderer('crm.record.tab');
48
+ render(_jsx(_Fragment, { children: _jsxs(ButtonRow, { children: [_jsx(Button, { variant: "secondary", children: "Button 1" }), _jsx(Button, { variant: "secondary", children: "Button 2" })] }) }));
49
+ const primaryButton = maybeFind(Button, { variant: 'primary' });
50
+ expect(primaryButton).toBeNull();
51
+ });
52
+ it('should work on nested element nodes', () => {
53
+ const { render, find } = createRenderer('crm.record.tab');
54
+ render(_jsx(_Fragment, { children: _jsx(ButtonRow, { children: _jsx(Button, { variant: "primary", children: "Button 1" }) }) }));
55
+ const buttonRow = find(ButtonRow);
56
+ const nestedButton = buttonRow.maybeFind(Button);
57
+ expect(nestedButton).toBeDefined();
58
+ expect(nestedButton?.props).toMatchObject({ variant: 'primary' });
59
+ });
60
+ it('should return null on nested element when not found', () => {
61
+ const { render, find } = createRenderer('crm.record.tab');
62
+ render(_jsx(_Fragment, { children: _jsx(ButtonRow, { children: _jsx(Button, { variant: "secondary", children: "Button 1" }) }) }));
63
+ const buttonRow = find(ButtonRow);
64
+ const text = buttonRow.maybeFind(Text);
65
+ expect(text).toBeNull();
66
+ });
67
+ });
@@ -0,0 +1,65 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Alert, Button, ButtonRow } from "../../../index.js";
4
+ import { createRenderer } from "../index.js";
5
+ import { ComponentMismatchedByTestIdError, FindInvalidComponentError, } from "../internal/errors.js";
6
+ describe('maybeFindByTestId()', () => {
7
+ it('should return the element when found by testId', () => {
8
+ const { render, maybeFindByTestId } = createRenderer('crm.record.tab');
9
+ render(_jsx(_Fragment, { children: _jsx(Button, { variant: "primary", testId: "my-button", children: "Click me" }) }));
10
+ const button = maybeFindByTestId(Button, 'my-button');
11
+ expect(button).toBeDefined();
12
+ expect(button?.props).toMatchObject({
13
+ variant: 'primary',
14
+ testId: 'my-button',
15
+ });
16
+ });
17
+ it('should return null when element with the given testId is not found', () => {
18
+ const { render, maybeFindByTestId } = createRenderer('crm.record.tab');
19
+ render(_jsx(_Fragment, { children: _jsx(Button, { variant: "primary", testId: "my-button", children: "Click me" }) }));
20
+ const button = maybeFindByTestId(Button, 'non-existent-testid');
21
+ expect(button).toBeNull();
22
+ });
23
+ it('should throw ComponentMismatchedByTestIdError when testId exists but component type does not match', () => {
24
+ const { render, maybeFindByTestId } = createRenderer('crm.record.tab');
25
+ render(_jsx(_Fragment, { children: _jsx(Button, { variant: "primary", testId: "my-button", children: "Click me" }) }));
26
+ expect(() => maybeFindByTestId(Alert, 'my-button')).toThrow(ComponentMismatchedByTestIdError);
27
+ });
28
+ it('should throw FindInvalidComponentError when target component is invalid', () => {
29
+ const { render, maybeFindByTestId } = createRenderer('crm.record.tab');
30
+ render(_jsx(_Fragment, { children: _jsx(Button, { variant: "primary", testId: "my-button", children: "Click me" }) }));
31
+ const MyFakeComponent = () => { };
32
+ expect(() => maybeFindByTestId(MyFakeComponent, 'my-button')).toThrow(FindInvalidComponentError);
33
+ });
34
+ it('should return null after re-rendering removes the component', () => {
35
+ const { render, maybeFindByTestId } = createRenderer('crm.record.tab');
36
+ render(_jsx(_Fragment, { children: _jsx(Button, { variant: "primary", testId: "my-button", children: "Click me" }) }));
37
+ let button = maybeFindByTestId(Button, 'my-button');
38
+ expect(button).toBeDefined();
39
+ render(_jsx(_Fragment, { children: _jsx(Alert, { title: "My Alert" }) }));
40
+ button = maybeFindByTestId(Button, 'my-button');
41
+ expect(button).toBeNull();
42
+ });
43
+ it('should handle multiple components with different testIds', () => {
44
+ const { render, maybeFindByTestId } = createRenderer('crm.record.tab');
45
+ render(_jsxs(_Fragment, { children: [_jsx(Button, { variant: "primary", testId: "button-1", children: "Button 1" }), _jsx(Button, { variant: "secondary", testId: "button-2", children: "Button 2" }), _jsx(Button, { variant: "destructive", testId: "button-3", children: "Button 3" })] }));
46
+ const button1 = maybeFindByTestId(Button, 'button-1');
47
+ expect(button1?.props.variant).toEqual('primary');
48
+ const button2 = maybeFindByTestId(Button, 'button-2');
49
+ expect(button2?.props.variant).toEqual('secondary');
50
+ const button3 = maybeFindByTestId(Button, 'button-3');
51
+ expect(button3?.props.variant).toEqual('destructive');
52
+ const button4 = maybeFindByTestId(Button, 'button-4');
53
+ expect(button4).toBeNull();
54
+ });
55
+ it('should work with nested components', () => {
56
+ const { render, maybeFindByTestId } = createRenderer('crm.record.tab');
57
+ render(_jsx(_Fragment, { children: _jsx(ButtonRow, { children: _jsx(Button, { variant: "primary", testId: "nested-button", children: "Nested" }) }) }));
58
+ const button = maybeFindByTestId(Button, 'nested-button');
59
+ expect(button).toBeDefined();
60
+ expect(button?.props).toMatchObject({
61
+ variant: 'primary',
62
+ testId: 'nested-button',
63
+ });
64
+ });
65
+ });
@@ -0,0 +1,75 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Alert, Button, ButtonRow, Text } from "../../../index.js";
4
+ import { createRenderer } from "../index.js";
5
+ describe('maybeFindChild()', () => {
6
+ it('should return direct child from the root node', () => {
7
+ const { render, maybeFindChild } = createRenderer('crm.record.tab');
8
+ render(_jsxs(_Fragment, { children: [_jsx(ButtonRow, { children: _jsx(Button, { variant: "primary", children: "Button 1" }) }), _jsx(Alert, { title: "My Alert" })] }));
9
+ const alert = maybeFindChild(Alert);
10
+ expect(alert).toBeDefined();
11
+ expect(alert?.props).toEqual({ title: 'My Alert' });
12
+ });
13
+ it('should return null when direct child is not found', () => {
14
+ const { render, maybeFindChild } = createRenderer('crm.record.tab');
15
+ render(_jsx(_Fragment, { children: _jsx(ButtonRow, { children: _jsx(Button, { variant: "primary", children: "Button 1" }) }) }));
16
+ const text = maybeFindChild(Text);
17
+ expect(text).toBeNull();
18
+ });
19
+ it('should only find direct children, not nested descendants', () => {
20
+ const { render, maybeFindChild } = createRenderer('crm.record.tab');
21
+ render(_jsxs(_Fragment, { children: [_jsx(ButtonRow, { children: _jsx(Button, { variant: "primary", children: "Button 1" }) }), _jsx(Alert, { title: "My Alert" })] }));
22
+ const button = maybeFindChild(Button);
23
+ expect(button).toBeNull();
24
+ });
25
+ it('should return first direct child when multiple children match', () => {
26
+ const { render, maybeFindChild } = createRenderer('crm.record.tab');
27
+ render(_jsxs(_Fragment, { children: [_jsx(Alert, { title: "First Alert" }), _jsx(Alert, { title: "Second Alert" }), _jsx(Alert, { title: "Third Alert" })] }));
28
+ const alert = maybeFindChild(Alert);
29
+ expect(alert).toBeDefined();
30
+ expect(alert?.props).toMatchObject({ title: 'First Alert' });
31
+ });
32
+ it('should support matcher function', () => {
33
+ const { render, maybeFindChild } = createRenderer('crm.record.tab');
34
+ render(_jsxs(_Fragment, { children: [_jsx(Alert, { title: "First Alert" }), _jsx(Alert, { title: "Second Alert" })] }));
35
+ const secondAlert = maybeFindChild(Alert, (node) => node.props.title === 'Second Alert');
36
+ expect(secondAlert).toBeDefined();
37
+ expect(secondAlert?.props).toMatchObject({ title: 'Second Alert' });
38
+ });
39
+ it('should return null when matcher function does not match any children', () => {
40
+ const { render, maybeFindChild } = createRenderer('crm.record.tab');
41
+ render(_jsxs(_Fragment, { children: [_jsx(Alert, { title: "First Alert" }), _jsx(Alert, { title: "Second Alert" })] }));
42
+ const thirdAlert = maybeFindChild(Alert, (node) => node.props.title === 'Third Alert');
43
+ expect(thirdAlert).toBeNull();
44
+ });
45
+ it('should support matcher object', () => {
46
+ const { render, maybeFindChild } = createRenderer('crm.record.tab');
47
+ render(_jsxs(_Fragment, { children: [_jsx(Alert, { title: "First Alert" }), _jsx(Alert, { title: "Second Alert" })] }));
48
+ const secondAlert = maybeFindChild(Alert, { title: 'Second Alert' });
49
+ expect(secondAlert).toBeDefined();
50
+ expect(secondAlert?.props).toMatchObject({ title: 'Second Alert' });
51
+ });
52
+ it('should return null when matcher object does not match any children', () => {
53
+ const { render, maybeFindChild } = createRenderer('crm.record.tab');
54
+ render(_jsxs(_Fragment, { children: [_jsx(Alert, { title: "First Alert" }), _jsx(Alert, { title: "Second Alert" })] }));
55
+ const thirdAlert = maybeFindChild(Alert, { title: 'Third Alert' });
56
+ expect(thirdAlert).toBeNull();
57
+ });
58
+ it('should work on nested element nodes', () => {
59
+ const { render, find } = createRenderer('crm.record.tab');
60
+ render(_jsx(_Fragment, { children: _jsxs(ButtonRow, { children: [_jsx(Button, { variant: "primary", children: "Button 1" }), _jsx(Button, { variant: "secondary", children: "Button 2" })] }) }));
61
+ const buttonRow = find(ButtonRow);
62
+ const primaryButton = buttonRow.maybeFindChild(Button, {
63
+ variant: 'primary',
64
+ });
65
+ expect(primaryButton).toBeDefined();
66
+ expect(primaryButton?.props).toMatchObject({ variant: 'primary' });
67
+ });
68
+ it('should return null on nested element when child not found', () => {
69
+ const { render, find } = createRenderer('crm.record.tab');
70
+ render(_jsx(_Fragment, { children: _jsx(ButtonRow, { children: _jsx(Button, { variant: "secondary", children: "Button 1" }) }) }));
71
+ const buttonRow = find(ButtonRow);
72
+ const text = buttonRow.maybeFindChild(Text);
73
+ expect(text).toBeNull();
74
+ });
75
+ });
@@ -0,0 +1,19 @@
1
+ import { describe, it } from 'vitest';
2
+ import { createRenderer } from "../index.js";
3
+ describe('mock actions', () => {
4
+ it('should provide the ability to spy on the actions for the "crm.record.tab" extension point', () => {
5
+ const { mocks } = createRenderer('crm.record.tab');
6
+ const { actions } = mocks;
7
+ actions.reloadPage();
8
+ expect(actions.reloadPage.callCount).toBe(1);
9
+ actions.onCrmPropertiesUpdate(['firstname', 'lastname'], () => { });
10
+ expect(actions.onCrmPropertiesUpdate.callCount).toBe(1);
11
+ });
12
+ it('should provide the ability to spy on the actions for the "settings" extension point', () => {
13
+ const { mocks } = createRenderer('settings');
14
+ const { actions } = mocks;
15
+ actions.addAlert({
16
+ message: 'Test Alert',
17
+ });
18
+ });
19
+ });
@@ -0,0 +1,24 @@
1
+ import { describe, it } from 'vitest';
2
+ import { createRenderer } from "../index.js";
3
+ describe('mock context', () => {
4
+ it('should provide reasonable mock data for the "crm.record.tab" extension point', () => {
5
+ const { mocks } = createRenderer('crm.record.tab');
6
+ const { context } = mocks;
7
+ expect(context.location).toBe('crm.record.tab');
8
+ expect(context.user.email).toBe('fake_email@example.com');
9
+ expect(context.user.firstName).toBe('fake_firstName');
10
+ expect(context.user.lastName).toBe('fake_lastName');
11
+ expect(context.portal.id).toBe(123);
12
+ expect(context.portal.timezone).toBe('America/New_York');
13
+ expect(context.crm.objectId).toBe(123);
14
+ expect(context.crm.objectTypeId).toBe('0-1');
15
+ expect(context.variables).toEqual({ fake_variable: 'fake_value' });
16
+ });
17
+ it('should provide reasonable mock data for the "settings" extension point', () => {
18
+ const { mocks } = createRenderer('settings');
19
+ const { context } = mocks;
20
+ expect(context.location).toBe('settings');
21
+ expect(context.portal.id).toBe(123);
22
+ expect(context.portal.timezone).toBe('America/New_York');
23
+ });
24
+ });
@@ -0,0 +1,35 @@
1
+ import { describe, it } from 'vitest';
2
+ import { createRenderer } from "../index.js";
3
+ import { ServerlessExecutionStatus, } from "../../../shared/types/http-requests.js";
4
+ describe('mock runServerlessFunction', () => {
5
+ it('should provide the ability to spy on the runServerlessFunction function', async () => {
6
+ const { mocks } = createRenderer('crm.record.tab');
7
+ const { runServerlessFunction } = mocks;
8
+ const serverlessExecutionResult = {
9
+ status: ServerlessExecutionStatus.Success,
10
+ response: {
11
+ myFakeData: 'hello',
12
+ anotherFakeData: 'bye',
13
+ },
14
+ };
15
+ runServerlessFunction.nextResult(Promise.resolve(serverlessExecutionResult));
16
+ const result = await runServerlessFunction({
17
+ name: 'fake_function',
18
+ parameters: {
19
+ param1: 'value1',
20
+ },
21
+ propertiesToSend: ['prop1', 'prop2'],
22
+ });
23
+ expect(result).toEqual(serverlessExecutionResult);
24
+ expect(runServerlessFunction.callCount).toBe(1);
25
+ expect(runServerlessFunction.calls[0]).toEqual([
26
+ {
27
+ name: 'fake_function',
28
+ parameters: {
29
+ param1: 'value1',
30
+ },
31
+ propertiesToSend: ['prop1', 'prop2'],
32
+ },
33
+ ]);
34
+ });
35
+ });
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Text } from "../../../index.js";
4
+ import { createRenderer } from "../index.js";
5
+ import { useAssociations } from "../../../crm/index.js";
6
+ function MyComponent() {
7
+ const { results, isLoading, error } = useAssociations({
8
+ toObjectType: '0-1',
9
+ properties: ['firstname', 'lastname'],
10
+ pageLength: 10,
11
+ });
12
+ if (isLoading) {
13
+ return _jsx(Text, { children: "Loading..." });
14
+ }
15
+ if (error) {
16
+ return _jsx(Text, { children: "Something went wrong!" });
17
+ }
18
+ return (_jsx(_Fragment, { children: results.map((result) => (_jsxs(Text, { children: [result.properties.firstname, " ", result.properties.lastname] }, result.toObjectId))) }));
19
+ }
20
+ describe('mock useAssociations', () => {
21
+ it('should provide a default mock implementation', () => {
22
+ const { render } = createRenderer('crm.record.tab');
23
+ const { findAll } = render(_jsx(MyComponent, {}));
24
+ const textNodes = findAll(Text);
25
+ expect(textNodes.length).toEqual(1);
26
+ expect(textNodes[0].text).toEqual('fake_firstname fake_lastname');
27
+ });
28
+ it('should allow mocking the next function result', () => {
29
+ const { render, mocks } = createRenderer('crm.record.tab');
30
+ mocks.useAssociations.nextResult({
31
+ results: [],
32
+ error: new Error('Something went wrong!'),
33
+ isLoading: false,
34
+ pagination: {
35
+ hasNextPage: false,
36
+ hasPreviousPage: false,
37
+ currentPage: 1,
38
+ pageSize: 10,
39
+ nextPage: () => { },
40
+ previousPage: () => { },
41
+ reset: () => { },
42
+ },
43
+ });
44
+ const { find } = render(_jsx(MyComponent, {}));
45
+ expect(find(Text).text).toEqual('Something went wrong!');
46
+ });
47
+ });
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Text } from "../../../index.js";
4
+ import { createRenderer } from "../index.js";
5
+ import { useCrmProperties } from "../../../crm/index.js";
6
+ function MyComponent() {
7
+ const { properties, isLoading, error } = useCrmProperties([
8
+ 'firstname',
9
+ 'lastname',
10
+ ]);
11
+ if (isLoading) {
12
+ return _jsx(Text, { children: "Loading..." });
13
+ }
14
+ if (error) {
15
+ return _jsx(Text, { children: "Something went wrong!" });
16
+ }
17
+ return (_jsxs(_Fragment, { children: [_jsxs(Text, { children: ["First name: ", properties.firstname] }), _jsxs(Text, { children: ["Last name: ", properties.lastname] })] }));
18
+ }
19
+ describe('mock useCrmProperties', () => {
20
+ it('should provide a default mock implementation', () => {
21
+ const { render } = createRenderer('crm.record.tab');
22
+ const { findAll } = render(_jsx(MyComponent, {}));
23
+ const textNodes = findAll(Text);
24
+ expect(textNodes.length).toEqual(2);
25
+ expect(textNodes[0].text).toEqual('First name: fake_firstname');
26
+ expect(textNodes[1].text).toEqual('Last name: fake_lastname');
27
+ });
28
+ it('should allow mocking the next function result', () => {
29
+ const { render, mocks } = createRenderer('crm.record.tab');
30
+ mocks.useCrmProperties.nextResult({
31
+ properties: {},
32
+ error: new Error('Something went wrong!'),
33
+ isLoading: false,
34
+ });
35
+ const { find } = render(_jsx(MyComponent, {}));
36
+ expect(find(Text).text).toEqual('Something went wrong!');
37
+ });
38
+ it('should allow providing a custom mock function', () => {
39
+ const { render, mocks, findAll } = createRenderer('crm.record.tab');
40
+ mocks.useCrmProperties.willCall((propertyNames) => {
41
+ const properties = propertyNames.reduce((acc, propertyName) => {
42
+ acc[propertyName] = propertyName.toUpperCase();
43
+ return acc;
44
+ }, {});
45
+ return {
46
+ properties,
47
+ error: null,
48
+ isLoading: false,
49
+ };
50
+ });
51
+ render(_jsx(MyComponent, {}));
52
+ const textNodes = findAll(Text);
53
+ const firstNameText = textNodes[0];
54
+ const lastNameText = textNodes[1];
55
+ expect(firstNameText.isMatch(Text) && firstNameText.text).toEqual('First name: FIRSTNAME');
56
+ expect(lastNameText.isMatch(Text) && lastNameText.text).toEqual('Last name: LASTNAME');
57
+ });
58
+ });
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Button, ButtonRow } from "../../../index.js";
4
+ import { createRenderer } from "../index.js";
5
+ describe('props', () => {
6
+ it('should remove the children prop from the props object', () => {
7
+ const { render, find } = createRenderer('crm.record.tab');
8
+ render(_jsx(_Fragment, { children: _jsx(ButtonRow, { children: _jsx(Button, { variant: "primary", children: "Click me!" }) }) }));
9
+ const buttonRow = find(ButtonRow);
10
+ // @ts-expect-error - children should not be exposed in props
11
+ expect(buttonRow.props.children).toBeUndefined();
12
+ });
13
+ });