@hubspot/ui-extensions 0.11.0 → 0.11.2

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 (93) hide show
  1. package/dist/__synced__/experimental/types.synced.d.ts +3 -4
  2. package/dist/__synced__/remoteComponents.synced.d.ts +168 -355
  3. package/dist/__synced__/remoteComponents.synced.js +186 -83
  4. package/dist/__synced__/types/components/button.synced.d.ts +6 -0
  5. package/dist/__synced__/types/components/index.synced.d.ts +38 -38
  6. package/dist/__synced__/types/index.synced.d.ts +7 -7
  7. package/dist/__synced__/types/index.synced.js +1 -9
  8. package/dist/__synced__/types/shared.synced.d.ts +2 -3
  9. package/dist/__synced__/utils/remote-component-registry.synced.d.ts +80 -0
  10. package/dist/__synced__/utils/remote-component-registry.synced.js +64 -0
  11. package/dist/__tests__/crm/hooks/useAssociations.spec.js +33 -29
  12. package/dist/__tests__/crm/hooks/useCrmProperties.spec.js +19 -18
  13. package/dist/__tests__/crm/utils/fetchAssociations.spec.js +8 -7
  14. package/dist/__tests__/crm/utils/fetchCrmProperties.spec.js +34 -33
  15. package/dist/crm/index.d.ts +1 -1
  16. package/dist/crm/index.js +1 -1
  17. package/dist/experimental/index.d.ts +1 -1
  18. package/dist/experimental/index.js +1 -1
  19. package/dist/experimental/testing/__tests__/debug.spec.d.ts +1 -0
  20. package/dist/experimental/testing/__tests__/debug.spec.js +43 -0
  21. package/dist/experimental/testing/__tests__/find.spec.d.ts +1 -0
  22. package/dist/experimental/testing/__tests__/find.spec.js +33 -0
  23. package/dist/experimental/testing/__tests__/findAll.spec.d.ts +1 -0
  24. package/dist/experimental/testing/__tests__/findAll.spec.js +12 -0
  25. package/dist/experimental/testing/__tests__/findAllChildren.spec.d.ts +1 -0
  26. package/dist/experimental/testing/__tests__/findAllChildren.spec.js +48 -0
  27. package/dist/experimental/testing/__tests__/findChild.spec.d.ts +1 -0
  28. package/dist/experimental/testing/__tests__/findChild.spec.js +29 -0
  29. package/dist/experimental/testing/__tests__/fragments.spec.d.ts +1 -0
  30. package/dist/experimental/testing/__tests__/fragments.spec.js +59 -0
  31. package/dist/experimental/testing/__tests__/invalid-components.spec.d.ts +1 -0
  32. package/dist/experimental/testing/__tests__/invalid-components.spec.js +88 -0
  33. package/dist/experimental/testing/__tests__/isMatch.spec.d.ts +1 -0
  34. package/dist/experimental/testing/__tests__/isMatch.spec.js +60 -0
  35. package/dist/experimental/testing/__tests__/maybeFind.spec.d.ts +1 -0
  36. package/dist/experimental/testing/__tests__/maybeFind.spec.js +58 -0
  37. package/dist/experimental/testing/__tests__/maybeFindChild.spec.d.ts +1 -0
  38. package/dist/experimental/testing/__tests__/maybeFindChild.spec.js +65 -0
  39. package/dist/experimental/testing/__tests__/trigger.spec.d.ts +1 -0
  40. package/dist/experimental/testing/__tests__/trigger.spec.js +40 -0
  41. package/dist/experimental/testing/__tests__/type-utils.spec.d.ts +1 -0
  42. package/dist/experimental/testing/__tests__/type-utils.spec.js +163 -0
  43. package/dist/experimental/testing/__tests__/waitFor.spec.d.ts +1 -0
  44. package/dist/experimental/testing/__tests__/waitFor.spec.js +55 -0
  45. package/dist/experimental/testing/index.d.ts +3 -0
  46. package/dist/experimental/testing/index.js +3 -0
  47. package/dist/experimental/testing/internal/constants.d.ts +2 -0
  48. package/dist/experimental/testing/internal/constants.js +1 -0
  49. package/dist/experimental/testing/internal/convert.d.ts +10 -0
  50. package/dist/experimental/testing/internal/convert.js +131 -0
  51. package/dist/experimental/testing/internal/debug.d.ts +8 -0
  52. package/dist/experimental/testing/internal/debug.js +19 -0
  53. package/dist/experimental/testing/internal/document.d.ts +14 -0
  54. package/dist/experimental/testing/internal/document.js +37 -0
  55. package/dist/experimental/testing/internal/element.d.ts +11 -0
  56. package/dist/experimental/testing/internal/element.js +67 -0
  57. package/dist/experimental/testing/internal/errors.d.ts +56 -0
  58. package/dist/experimental/testing/internal/errors.js +70 -0
  59. package/dist/experimental/testing/internal/fragment.d.ts +8 -0
  60. package/dist/experimental/testing/internal/fragment.js +44 -0
  61. package/dist/experimental/testing/internal/match.d.ts +19 -0
  62. package/dist/experimental/testing/internal/match.js +42 -0
  63. package/dist/experimental/testing/internal/print.d.ts +6 -0
  64. package/dist/experimental/testing/internal/print.js +114 -0
  65. package/dist/experimental/testing/internal/query.d.ts +57 -0
  66. package/dist/experimental/testing/internal/query.js +213 -0
  67. package/dist/experimental/testing/internal/root.d.ts +8 -0
  68. package/dist/experimental/testing/internal/root.js +44 -0
  69. package/dist/experimental/testing/internal/text.d.ts +9 -0
  70. package/dist/experimental/testing/internal/text.js +16 -0
  71. package/dist/experimental/testing/internal/utils/promise-utils.d.ts +14 -0
  72. package/dist/experimental/testing/internal/utils/promise-utils.js +14 -0
  73. package/dist/experimental/testing/render.d.ts +9 -0
  74. package/dist/experimental/testing/render.js +155 -0
  75. package/dist/experimental/testing/types.d.ts +2 -1
  76. package/dist/hubspot.d.ts +1 -1
  77. package/dist/index.d.ts +2 -2
  78. package/dist/index.js +2 -2
  79. package/dist/pages/home/index.d.ts +1 -1
  80. package/dist/pages/home/index.js +1 -1
  81. package/package.json +19 -16
  82. package/dist/__synced__/appHomeRemoteComponents.synced.d.ts +0 -28
  83. package/dist/__synced__/appHomeRemoteComponents.synced.js +0 -21
  84. package/dist/__synced__/crmRemoteComponents.synced.d.ts +0 -66
  85. package/dist/__synced__/crmRemoteComponents.synced.js +0 -15
  86. package/dist/__synced__/experimentalRemoteComponents.synced.d.ts +0 -94
  87. package/dist/__synced__/experimentalRemoteComponents.synced.js +0 -56
  88. package/dist/coreComponents.d.ts +0 -848
  89. package/dist/coreComponents.js +0 -582
  90. package/dist/experimental/types.d.ts +0 -240
  91. package/dist/experimental/types.js +0 -5
  92. package/dist/types.d.ts +0 -3214
  93. package/dist/types.js +0 -244
@@ -38,6 +38,12 @@ export interface BaseButtonProps {
38
38
  * @defaultValue `"md"`
39
39
  */
40
40
  size?: TShirtSizes['xs'] | TShirtSizes['sm'] | TShirtSizes['md'];
41
+ /**
42
+ * When set to `true`, long button text will be truncated with an ellipsis (`...`) and the full text will appear in a tooltip on hover.
43
+ *
44
+ * @defaultValue `false`
45
+ */
46
+ truncate?: boolean;
41
47
  }
42
48
  /**
43
49
  * The props type for {@link !components.Button}.
@@ -1,38 +1,38 @@
1
- export type { AlertProps } from './alert.synced';
2
- export type { ButtonProps, LoadingButtonProps } from './button.synced';
3
- export type { ButtonRowProps } from './button-row.synced';
4
- export type { CardProps } from './card.synced';
5
- export type { ChartProps, LineChartProps, BarChartProps } from './chart.synced';
6
- export type { DescriptionListProps, DescriptionListItemProps, } from './description-list.synced';
7
- export type { DividerProps } from './divider.synced';
8
- export type { EmptyStateProps } from './empty-state.synced';
9
- export type { ErrorStateProps } from './error-state.synced';
10
- export type { HeadingProps } from './heading.synced';
11
- export type { FormProps } from './form.synced';
12
- export type { IconProps } from './icon.synced';
13
- export type { IllustrationProps } from './illustration.synced';
14
- export type { IframeProps } from './iframe.synced';
15
- export type { ImageProps } from './image.synced';
16
- export type { InputProps, TextAreaProps, TextareaProps, NumberInputProps, DateInputProps, StepperInputProps, SearchInputProps, TimeInputProps, CurrencyInputProps, } from './inputs.synced';
17
- export type { StackProps, FlexProps, BoxProps, InlineProps, AutoGridProps, } from './layouts.synced';
18
- export type { LinkProps } from './link.synced';
19
- export type { ListProps } from './list.synced';
20
- export type { LoadingSpinnerProps } from './loading-spinner.synced';
21
- export type { ModalProps, ModalBodyProps, ModalFooterProps } from './modal.synced';
22
- export type { ProgressBarProps } from './progress-bar.synced';
23
- export type { PanelProps, PanelFooterProps, PanelBodyProps, PanelSectionProps, } from './panel.synced';
24
- export type { SelectProps, MultiSelectProps } from './selects.synced';
25
- export type { StatisticsProps, StatisticsItemProps, StatisticsTrendProps, } from './statistics.synced';
26
- export type { StatusTagProps } from './status-tag.synced';
27
- export type { StepIndicatorProps } from './step-indicator.synced';
28
- export type { TableProps, TableElementProps, TableCellProps, TableHeaderProps, } from './table.synced';
29
- export type { TabsProps, TabProps } from './tabs.synced';
30
- export type { TagProps } from './tag.synced';
31
- export type { TextProps } from './text.synced';
32
- export type { TileProps } from './tile.synced';
33
- export type { ToggleProps } from './toggle.synced';
34
- export type { CheckboxProps, RadioButtonProps, ToggleGroupProps, CheckboxListProps, RadioButtonListProps, } from './toggleInputs.synced';
35
- export type { AccordionProps } from './accordion.synced';
36
- export type { DropdownProps, DropdownButtonItemProps } from './dropdown.synced';
37
- export type { TooltipProps } from './tooltip.synced';
38
- export type { HeaderActionsProps, HeaderActionButtonProps, } from './app-home-header-actions.synced';
1
+ export type * from './accordion.synced';
2
+ export type * from './alert.synced';
3
+ export type * from './app-home-header-actions.synced';
4
+ export type * from './button-row.synced';
5
+ export type * from './button.synced';
6
+ export type * from './card.synced';
7
+ export type * from './chart.synced';
8
+ export type * from './description-list.synced';
9
+ export type * from './divider.synced';
10
+ export type * from './dropdown.synced';
11
+ export type * from './empty-state.synced';
12
+ export type * from './error-state.synced';
13
+ export type * from './form.synced';
14
+ export type * from './heading.synced';
15
+ export type * from './icon.synced';
16
+ export type * from './iframe.synced';
17
+ export type * from './illustration.synced';
18
+ export type * from './image.synced';
19
+ export type * from './inputs.synced';
20
+ export type * from './layouts.synced';
21
+ export type * from './link.synced';
22
+ export type * from './list.synced';
23
+ export type * from './loading-spinner.synced';
24
+ export type * from './modal.synced';
25
+ export type * from './panel.synced';
26
+ export type * from './progress-bar.synced';
27
+ export type * from './selects.synced';
28
+ export type * from './statistics.synced';
29
+ export type * from './status-tag.synced';
30
+ export type * from './step-indicator.synced';
31
+ export type * from './table.synced';
32
+ export type * from './tabs.synced';
33
+ export type * from './tag.synced';
34
+ export type * from './text.synced';
35
+ export type * from './tile.synced';
36
+ export type * from './toggle.synced';
37
+ export type * from './toggleInputs.synced';
38
+ export type * from './tooltip.synced';
@@ -1,8 +1,8 @@
1
- export * from './components/index.synced';
2
- export * from './actions.synced';
3
- export * from './context.synced';
4
- export * from './crm.synced';
5
- export * from './extension-points.synced';
6
- export * from './http-requests.synced';
7
- export * from './reactions.synced';
1
+ export type * from './components/index.synced';
2
+ export type * from './actions.synced';
3
+ export type * from './context.synced';
4
+ export type * from './crm.synced';
5
+ export type * from './extension-points.synced';
6
+ export type * from './http-requests.synced';
7
+ export type * from './reactions.synced';
8
8
  export * from './shared.synced';
@@ -1,9 +1 @@
1
- // Do not manually update this file, changes will be autogenerated by our scripts based on: ui-extensions-remote-renderer/static/js/types/index.ts
2
- export * from './components/index.synced';
3
- export * from './actions.synced';
4
- export * from './context.synced';
5
- export * from './crm.synced';
6
- export * from './extension-points.synced';
7
- export * from './http-requests.synced';
8
- export * from './reactions.synced';
9
- export * from './shared.synced';
1
+ export * from './shared.synced'; // NOTE: `shared.ts` has some exported classes so we can't use `export type` for now
@@ -1,5 +1,4 @@
1
- import { RemoteFragment } from '@remote-ui/core';
2
- import type { ReactElement, ComponentType } from 'react';
1
+ import type { ReactElement, ComponentType, ReactNode } from 'react';
3
2
  export type UnknownComponentProps = Record<string, any>;
4
3
  /**
5
4
  * Represents a HubSpot-provided React component.
@@ -22,7 +21,7 @@ export declare class FormSubmitExtensionEvent<V> extends ExtensionEvent {
22
21
  constructor(value: V, event: Event);
23
22
  }
24
23
  export type OverlayComponentProps = {
25
- overlay?: RemoteFragment;
24
+ overlay?: ReactNode;
26
25
  };
27
26
  export type HrefOptions = {
28
27
  url: string;
@@ -0,0 +1,80 @@
1
+ import { HubSpotReactComponent, HubSpotReactFragmentProp, UnknownComponentProps } from '../types/shared.synced';
2
+ /**
3
+ * Options for creating a remote React component.
4
+ */
5
+ interface CreateRemoteComponentOptions<TProps extends UnknownComponentProps = UnknownComponentProps> {
6
+ /**
7
+ * An array of prop names that are allowed to be used as fragment props.
8
+ */
9
+ fragmentProps?: ComponentFragmentPropName<TProps>[];
10
+ }
11
+ /**
12
+ * Options for creating a remote React component.
13
+ */
14
+ interface CreateRemoteCompoundComponentOptions<TProps extends UnknownComponentProps, TCompoundComponentProps> {
15
+ /**
16
+ * An array of prop names that are allowed to be used as fragment props.
17
+ */
18
+ fragmentProps?: ComponentFragmentPropName<TProps>[];
19
+ compoundComponentProperties: TCompoundComponentProps;
20
+ }
21
+ /**
22
+ * Utility type for filtering out all of the prop names where the value is a ReactNode (excluding primitives).
23
+ * We use this to know which props are allowed to be used as fragment props.
24
+ */
25
+ type ComponentFragmentPropName<TProps extends UnknownComponentProps> = {
26
+ [K in keyof TProps]: HubSpotReactFragmentProp extends Required<TProps>[K] ? K : never;
27
+ }[keyof TProps & string];
28
+ /**
29
+ * Represents a registry of HubSpot-provided React components that is used internally by the UI extensions SDK.
30
+ */
31
+ export interface RemoteComponentRegistry {
32
+ /**
33
+ * Creates a new remote React component and registers it with the registry.
34
+ *
35
+ * @param componentName The name of the component to create and register.
36
+ * @param options The options for the remote React component.
37
+ * @returns The remote React component that can be used as a React component.
38
+ */
39
+ createAndRegisterRemoteReactComponent: <TProps extends UnknownComponentProps>(componentName: string, options?: CreateRemoteComponentOptions<TProps>) => HubSpotReactComponent<TProps>;
40
+ /**
41
+ * Creates a new remote compound React component and registers it with the registry. A compound component is a component that is
42
+ * composed of multiple components attached to a single component function.
43
+ *
44
+ * @param componentName The name of the component to create and register.
45
+ * @param options The options for the remote compound React component.
46
+ * @returns The remote compound React component that can be used as a React component.
47
+ */
48
+ createAndRegisterRemoteCompoundReactComponent: <TProps extends UnknownComponentProps, TCompoundComponentProps>(componentName: string, options: CreateRemoteCompoundComponentOptions<TProps, TCompoundComponentProps>) => HubSpotReactComponent<TProps> & TCompoundComponentProps;
49
+ /**
50
+ * Returns the name of a HubSpot-provided React component.
51
+ *
52
+ * @param component The React component to get the name of.
53
+ * @returns The name of the HubSpot-provided React component.
54
+ */
55
+ getComponentName: (component: HubSpotReactComponent<any>) => string | null;
56
+ /**
57
+ * Returns true if the given component name is allowed to be used in HubSpot.
58
+ *
59
+ * @param name The name of the component to check if it is allowed to be used in HubSpot.
60
+ * @returns `true` if the given component name is allowed to be used in HubSpot.
61
+ */
62
+ isAllowedComponentName: (name: string) => boolean;
63
+ /**
64
+ * Returns true if the given prop name is a fragment prop for the given component name.
65
+ *
66
+ * @param componentName The name of the component to check if the prop is a fragment prop for.
67
+ * @param propName The name of the prop to check if it is a fragment prop.
68
+ * @returns `true` if the prop name is a fragment prop for the given component name.
69
+ */
70
+ isComponentFragmentProp: (componentName: string, propName: string) => boolean;
71
+ /**
72
+ * Returns the names of the fragment props for a given component name.
73
+ *
74
+ * @param componentName The name of the component to get the fragment props for.
75
+ * @returns The names of the fragment props for the given component name.
76
+ */
77
+ getComponentFragmentPropNames: (componentName: string) => string[];
78
+ }
79
+ export declare const createRemoteComponentRegistry: () => RemoteComponentRegistry;
80
+ export {};
@@ -0,0 +1,64 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // Do not manually update this file, changes will be autogenerated by our scripts based on: ui-extensions-remote-renderer/static/js/utils/remote-component-registry.tsx
3
+ import { createRemoteReactComponent } from '@remote-ui/react';
4
+ export const createRemoteComponentRegistry = () => {
5
+ const componentMetadataLookup = new Map();
6
+ const componentNameByComponentMap = new Map();
7
+ const registerComponent = (component, componentName, fragmentProps) => {
8
+ componentNameByComponentMap.set(component, componentName);
9
+ componentMetadataLookup.set(componentName, {
10
+ fragmentPropsSet: new Set(fragmentProps),
11
+ fragmentPropsArray: fragmentProps,
12
+ });
13
+ return component;
14
+ };
15
+ return {
16
+ getComponentName: (component) => {
17
+ const componentName = componentNameByComponentMap.get(component);
18
+ if (!componentName) {
19
+ return null;
20
+ }
21
+ return componentName;
22
+ },
23
+ isAllowedComponentName: (componentName) => {
24
+ return componentMetadataLookup.has(componentName);
25
+ },
26
+ isComponentFragmentProp: (componentName, propName) => {
27
+ const componentMetadata = componentMetadataLookup.get(componentName);
28
+ if (!componentMetadata) {
29
+ return false;
30
+ }
31
+ return componentMetadata.fragmentPropsSet.has(propName);
32
+ },
33
+ getComponentFragmentPropNames: (componentName) => {
34
+ const componentMetadata = componentMetadataLookup.get(componentName);
35
+ if (!componentMetadata) {
36
+ return [];
37
+ }
38
+ const { fragmentPropsArray } = componentMetadata;
39
+ return fragmentPropsArray;
40
+ },
41
+ createAndRegisterRemoteReactComponent: (componentName, options = {}) => {
42
+ const { fragmentProps = [] } = options;
43
+ const remoteReactComponent = createRemoteReactComponent(componentName, {
44
+ fragmentProps: fragmentProps,
45
+ });
46
+ return registerComponent(remoteReactComponent, componentName, fragmentProps);
47
+ },
48
+ createAndRegisterRemoteCompoundReactComponent: (componentName, options) => {
49
+ const { fragmentProps = [] } = options;
50
+ const RemoteComponentType = createRemoteReactComponent(componentName, {
51
+ fragmentProps,
52
+ });
53
+ // We can only attach properties to a function component type, so we need to check if the remote component type is a function.
54
+ // If the remote component type is not a function, we need to wrap it in a function component.
55
+ const CompoundFunctionComponentType = typeof RemoteComponentType === 'function'
56
+ ? RemoteComponentType
57
+ : (props) => (_jsx(RemoteComponentType, { ...props }));
58
+ // Attach the compound component properties to the function component that we will be returning.
59
+ Object.assign(CompoundFunctionComponentType, options.compoundComponentProperties);
60
+ // Register the compound function component with the registry and return it.
61
+ return registerComponent(CompoundFunctionComponentType, componentName, fragmentProps);
62
+ },
63
+ };
64
+ };
@@ -1,20 +1,24 @@
1
1
  import { renderHook, waitFor } from '@testing-library/react';
2
+ import { vi } from 'vitest';
2
3
  import { useAssociations } from '../../../crm/hooks/useAssociations';
3
4
  import { fetchAssociations } from '../../../crm/utils/fetchAssociations';
4
5
  // Mock the logger module
5
- jest.mock('../../../logger', () => ({
6
+ vi.mock('../../../logger', () => ({
6
7
  logger: {
7
- debug: jest.fn(),
8
- info: jest.fn(),
9
- warn: jest.fn(),
10
- error: jest.fn(),
8
+ debug: vi.fn(),
9
+ info: vi.fn(),
10
+ warn: vi.fn(),
11
+ error: vi.fn(),
11
12
  },
12
13
  }));
13
14
  // Mock the fetchAssociations function, keep utility functions
14
- jest.mock('../../../crm/utils/fetchAssociations', () => ({
15
- ...jest.requireActual('../../../crm/utils/fetchAssociations'),
16
- fetchAssociations: jest.fn(),
17
- }));
15
+ vi.mock('../../../crm/utils/fetchAssociations', async (importOriginal) => {
16
+ const actual = (await importOriginal());
17
+ return {
18
+ ...actual,
19
+ fetchAssociations: vi.fn(),
20
+ };
21
+ });
18
22
  // Get reference to the mocked function
19
23
  const mockFetchAssociations = fetchAssociations;
20
24
  describe('useAssociations with Pagination', () => {
@@ -45,7 +49,7 @@ describe('useAssociations with Pagination', () => {
45
49
  hasMore: false,
46
50
  nextOffset: 0,
47
51
  },
48
- cleanup: jest.fn(),
52
+ cleanup: vi.fn(),
49
53
  });
50
54
  const { result } = renderHook(() => useAssociations({
51
55
  toObjectType: '0-1',
@@ -69,7 +73,7 @@ describe('useAssociations with Pagination', () => {
69
73
  hasMore: false,
70
74
  nextOffset: 0,
71
75
  },
72
- cleanup: jest.fn(),
76
+ cleanup: vi.fn(),
73
77
  });
74
78
  const { result } = renderHook(() => useAssociations({
75
79
  toObjectType: '0-1',
@@ -99,7 +103,7 @@ describe('useAssociations with Pagination', () => {
99
103
  hasMore: true,
100
104
  nextOffset: 10,
101
105
  },
102
- cleanup: jest.fn(),
106
+ cleanup: vi.fn(),
103
107
  });
104
108
  const { result } = renderHook(() => useAssociations({
105
109
  toObjectType: '0-1',
@@ -128,7 +132,7 @@ describe('useAssociations with Pagination', () => {
128
132
  hasMore: false,
129
133
  nextOffset: 0,
130
134
  },
131
- cleanup: jest.fn(),
135
+ cleanup: vi.fn(),
132
136
  });
133
137
  const { result } = renderHook(() => useAssociations({
134
138
  toObjectType: '0-1',
@@ -153,7 +157,7 @@ describe('useAssociations with Pagination', () => {
153
157
  hasMore: true,
154
158
  nextOffset: 10,
155
159
  },
156
- cleanup: jest.fn(),
160
+ cleanup: vi.fn(),
157
161
  });
158
162
  // Second page response
159
163
  mockFetchAssociations.mockResolvedValueOnce({
@@ -162,7 +166,7 @@ describe('useAssociations with Pagination', () => {
162
166
  hasMore: false,
163
167
  nextOffset: 20,
164
168
  },
165
- cleanup: jest.fn(),
169
+ cleanup: vi.fn(),
166
170
  });
167
171
  const { result } = renderHook(() => useAssociations({
168
172
  toObjectType: '0-1',
@@ -193,7 +197,7 @@ describe('useAssociations with Pagination', () => {
193
197
  hasMore: true,
194
198
  nextOffset: 10,
195
199
  },
196
- cleanup: jest.fn(),
200
+ cleanup: vi.fn(),
197
201
  });
198
202
  // Second call: page 2 with hasMore: false
199
203
  mockFetchAssociations.mockResolvedValueOnce({
@@ -202,7 +206,7 @@ describe('useAssociations with Pagination', () => {
202
206
  hasMore: false,
203
207
  nextOffset: 20,
204
208
  },
205
- cleanup: jest.fn(),
209
+ cleanup: vi.fn(),
206
210
  });
207
211
  // Third call: back to page 1
208
212
  mockFetchAssociations.mockResolvedValueOnce({
@@ -211,7 +215,7 @@ describe('useAssociations with Pagination', () => {
211
215
  hasMore: true,
212
216
  nextOffset: 10,
213
217
  },
214
- cleanup: jest.fn(),
218
+ cleanup: vi.fn(),
215
219
  });
216
220
  const { result } = renderHook(() => useAssociations({
217
221
  toObjectType: '0-1',
@@ -243,7 +247,7 @@ describe('useAssociations with Pagination', () => {
243
247
  hasMore: true,
244
248
  nextOffset: 10,
245
249
  },
246
- cleanup: jest.fn(),
250
+ cleanup: vi.fn(),
247
251
  });
248
252
  const { result } = renderHook(() => useAssociations({
249
253
  toObjectType: '0-1',
@@ -277,7 +281,7 @@ describe('useAssociations with Pagination', () => {
277
281
  hasMore: false,
278
282
  nextOffset: 10,
279
283
  },
280
- cleanup: jest.fn(),
284
+ cleanup: vi.fn(),
281
285
  });
282
286
  const { result } = renderHook(() => useAssociations({
283
287
  toObjectType: '0-1',
@@ -320,7 +324,7 @@ describe('useAssociations with Pagination', () => {
320
324
  hasMore: false,
321
325
  nextOffset: 0,
322
326
  },
323
- cleanup: jest.fn(),
327
+ cleanup: vi.fn(),
324
328
  });
325
329
  // @ts-expect-error - intentional type issue to check the failure state
326
330
  const { result } = renderHook(() => useAssociations(null));
@@ -343,7 +347,7 @@ describe('useAssociations with Pagination', () => {
343
347
  hasMore: false,
344
348
  nextOffset: 0,
345
349
  },
346
- cleanup: jest.fn(),
350
+ cleanup: vi.fn(),
347
351
  });
348
352
  // @ts-expect-error - intentional type issue to check the failure state
349
353
  const { result } = renderHook(() => useAssociations(undefined));
@@ -366,7 +370,7 @@ describe('useAssociations with Pagination', () => {
366
370
  hasMore: false,
367
371
  nextOffset: 0,
368
372
  },
369
- cleanup: jest.fn(),
373
+ cleanup: vi.fn(),
370
374
  });
371
375
  // @ts-expect-error - intentional type issue to check the failure state
372
376
  const { result } = renderHook(() => useAssociations({}));
@@ -389,7 +393,7 @@ describe('useAssociations with Pagination', () => {
389
393
  hasMore: false,
390
394
  nextOffset: 0,
391
395
  },
392
- cleanup: jest.fn(),
396
+ cleanup: vi.fn(),
393
397
  });
394
398
  const { result } = renderHook(() =>
395
399
  // @ts-expect-error - intentional type issue to check the failure state
@@ -415,7 +419,7 @@ describe('useAssociations with Pagination', () => {
415
419
  hasMore: false,
416
420
  nextOffset: 0,
417
421
  },
418
- cleanup: jest.fn(),
422
+ cleanup: vi.fn(),
419
423
  });
420
424
  const { result } = renderHook(() => useAssociations({
421
425
  toObjectType: '0-1',
@@ -441,7 +445,7 @@ describe('useAssociations with Pagination', () => {
441
445
  hasMore: false,
442
446
  nextOffset: 0,
443
447
  },
444
- cleanup: jest.fn(),
448
+ cleanup: vi.fn(),
445
449
  });
446
450
  const config = {
447
451
  toObjectType: '0-1',
@@ -469,7 +473,7 @@ describe('useAssociations with Pagination', () => {
469
473
  hasMore: false,
470
474
  nextOffset: 0,
471
475
  },
472
- cleanup: jest.fn(),
476
+ cleanup: vi.fn(),
473
477
  });
474
478
  const config = {
475
479
  toObjectType: '0-1',
@@ -484,7 +488,7 @@ describe('useAssociations with Pagination', () => {
484
488
  });
485
489
  describe('lifecycle management', () => {
486
490
  it('should call cleanup function on unmount', async () => {
487
- const mockCleanup = jest.fn();
491
+ const mockCleanup = vi.fn();
488
492
  mockFetchAssociations.mockResolvedValue({
489
493
  data: {
490
494
  results: [],
@@ -514,7 +518,7 @@ describe('useAssociations with Pagination', () => {
514
518
  hasMore: false,
515
519
  nextOffset: 0,
516
520
  },
517
- cleanup: jest.fn(),
521
+ cleanup: vi.fn(),
518
522
  });
519
523
  const config = {
520
524
  toObjectType: '0-1',
@@ -1,18 +1,19 @@
1
1
  import { renderHook, waitFor } from '@testing-library/react';
2
+ import { vi } from 'vitest';
2
3
  import { useCrmProperties } from '../../../crm/hooks/useCrmProperties';
4
+ import * as fetchCrmPropertiesModule from '../../../crm/utils/fetchCrmProperties';
3
5
  // Mock the logger module
4
- jest.mock('../../../logger', () => ({
6
+ vi.mock('../../../logger', () => ({
5
7
  logger: {
6
- debug: jest.fn(),
7
- info: jest.fn(),
8
- warn: jest.fn(),
9
- error: jest.fn(),
8
+ debug: vi.fn(),
9
+ info: vi.fn(),
10
+ warn: vi.fn(),
11
+ error: vi.fn(),
10
12
  },
11
13
  }));
12
14
  // Mock the fetchCrmProperties module
13
- jest.mock('../../../crm/utils/fetchCrmProperties');
14
- const mockFetchCrmProperties = jest.fn();
15
- import * as fetchCrmPropertiesModule from '../../../crm/utils/fetchCrmProperties';
15
+ vi.mock('../../../crm/utils/fetchCrmProperties');
16
+ const mockFetchCrmProperties = vi.fn();
16
17
  fetchCrmPropertiesModule.fetchCrmProperties = mockFetchCrmProperties;
17
18
  describe('useCrmProperties', () => {
18
19
  let originalError;
@@ -46,7 +47,7 @@ describe('useCrmProperties', () => {
46
47
  firstname: 'Test value for firstname',
47
48
  lastname: 'Test value for lastname',
48
49
  },
49
- cleanup: jest.fn(),
50
+ cleanup: vi.fn(),
50
51
  });
51
52
  const propertyNames = ['firstname', 'lastname'];
52
53
  const { result } = renderHook(() => useCrmProperties(propertyNames));
@@ -78,7 +79,7 @@ describe('useCrmProperties', () => {
78
79
  capturedCallback = propertiesUpdatedCallback;
79
80
  return {
80
81
  data: { firstname: 'Initial', lastname: 'Initial' },
81
- cleanup: jest.fn(),
82
+ cleanup: vi.fn(),
82
83
  };
83
84
  });
84
85
  const propertyNames = ['firstname', 'lastname'];
@@ -105,7 +106,7 @@ describe('useCrmProperties', () => {
105
106
  capturedCallback = propertiesUpdatedCallback;
106
107
  return {
107
108
  data: { firstname: 'Initial', lastname: null },
108
- cleanup: jest.fn(),
109
+ cleanup: vi.fn(),
109
110
  };
110
111
  });
111
112
  const propertyNames = ['firstname', 'lastname'];
@@ -132,7 +133,7 @@ describe('useCrmProperties', () => {
132
133
  firstname: 'John',
133
134
  lastname: 'Doe',
134
135
  },
135
- cleanup: jest.fn(),
136
+ cleanup: vi.fn(),
136
137
  });
137
138
  const propertyNames = ['firstname', 'lastname'];
138
139
  const options = {
@@ -148,7 +149,7 @@ describe('useCrmProperties', () => {
148
149
  data: {
149
150
  firstname: 'John',
150
151
  },
151
- cleanup: jest.fn(),
152
+ cleanup: vi.fn(),
152
153
  });
153
154
  const propertyNames = ['firstname'];
154
155
  const defaultOptions = {};
@@ -162,7 +163,7 @@ describe('useCrmProperties', () => {
162
163
  data: {
163
164
  firstname: 'John',
164
165
  },
165
- cleanup: jest.fn(),
166
+ cleanup: vi.fn(),
166
167
  });
167
168
  const propertyNames = ['firstname'];
168
169
  const initialOptions = { propertiesToFormat: ['firstname'] };
@@ -181,7 +182,7 @@ describe('useCrmProperties', () => {
181
182
  data: {
182
183
  firstname: 'John',
183
184
  },
184
- cleanup: jest.fn(),
185
+ cleanup: vi.fn(),
185
186
  });
186
187
  const propertyNames = ['firstname'];
187
188
  const initialOptions = { propertiesToFormat: ['firstname'] };
@@ -201,7 +202,7 @@ describe('useCrmProperties', () => {
201
202
  });
202
203
  });
203
204
  it('should call cleanup function when component unmounts', async () => {
204
- const mockCleanup = jest.fn();
205
+ const mockCleanup = vi.fn();
205
206
  mockFetchCrmProperties.mockResolvedValue({
206
207
  data: {
207
208
  firstname: 'John',
@@ -217,8 +218,8 @@ describe('useCrmProperties', () => {
217
218
  expect(mockCleanup).toHaveBeenCalledTimes(1);
218
219
  });
219
220
  it('should call cleanup function when dependencies change', async () => {
220
- const mockCleanup1 = jest.fn();
221
- const mockCleanup2 = jest.fn();
221
+ const mockCleanup1 = vi.fn();
222
+ const mockCleanup2 = vi.fn();
222
223
  mockFetchCrmProperties
223
224
  .mockResolvedValueOnce({
224
225
  data: { firstname: 'John' },
@@ -1,5 +1,6 @@
1
+ import { vi } from 'vitest';
1
2
  // Set up the mock before importing the module
2
- const mockFetchAssociations = jest.fn();
3
+ const mockFetchAssociations = vi.fn();
3
4
  const mockSelf = {
4
5
  fetchAssociations: mockFetchAssociations,
5
6
  };
@@ -13,13 +14,13 @@ describe('fetchAssociations', () => {
13
14
  // Helper functions
14
15
  const createMockResponse = (data, overrides = {}) => ({
15
16
  ok: true,
16
- json: jest.fn().mockResolvedValue({ data, cleanup: jest.fn() }),
17
+ json: vi.fn().mockResolvedValue({ data, cleanup: vi.fn() }),
17
18
  ...overrides,
18
19
  });
19
20
  const createErrorResponse = (statusText) => ({
20
21
  ok: false,
21
22
  statusText,
22
- json: jest.fn().mockResolvedValue({}),
23
+ json: vi.fn().mockResolvedValue({}),
23
24
  });
24
25
  const expectError = async (request, expectedMessage) => {
25
26
  await expect(fetchAssociations(request)).rejects.toThrow(expectedMessage);
@@ -30,7 +31,7 @@ describe('fetchAssociations', () => {
30
31
  ...overrides,
31
32
  });
32
33
  beforeEach(() => {
33
- jest.clearAllMocks();
34
+ vi.clearAllMocks();
34
35
  // Set up dynamic mock that responds to request parameters
35
36
  mockFetchAssociations.mockImplementation((request) => {
36
37
  const { pageLength = 100, offset = 0, properties = [] } = request;
@@ -296,12 +297,12 @@ describe('fetchAssociations', () => {
296
297
  expect(mockFetchAssociations).toHaveBeenCalledWith(request, undefined);
297
298
  });
298
299
  it('should return cleanup function from API response', async () => {
299
- const mockCleanup = jest.fn();
300
+ const mockCleanup = vi.fn();
300
301
  const emptyData = { results: [], hasMore: false, nextOffset: 0 };
301
302
  const mockApiResponse = { data: emptyData, cleanup: mockCleanup };
302
303
  mockFetchAssociations.mockResolvedValueOnce({
303
304
  ok: true,
304
- json: jest.fn().mockResolvedValue(mockApiResponse),
305
+ json: vi.fn().mockResolvedValue(mockApiResponse),
305
306
  });
306
307
  const result = await fetchAssociations(createBasicRequest());
307
308
  expect(result.cleanup).toBe(mockCleanup);
@@ -313,7 +314,7 @@ describe('fetchAssociations', () => {
313
314
  const mockApiResponse = { data: emptyData }; // no cleanup function provided
314
315
  mockFetchAssociations.mockResolvedValueOnce({
315
316
  ok: true,
316
- json: jest.fn().mockResolvedValue(mockApiResponse),
317
+ json: vi.fn().mockResolvedValue(mockApiResponse),
317
318
  });
318
319
  const result = await fetchAssociations(createBasicRequest());
319
320
  expect(typeof result.cleanup).toBe('function');