@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.
- package/dist/__synced__/experimental/types.synced.d.ts +3 -4
- package/dist/__synced__/remoteComponents.synced.d.ts +168 -355
- package/dist/__synced__/remoteComponents.synced.js +186 -83
- package/dist/__synced__/types/components/button.synced.d.ts +6 -0
- package/dist/__synced__/types/components/index.synced.d.ts +38 -38
- package/dist/__synced__/types/index.synced.d.ts +7 -7
- package/dist/__synced__/types/index.synced.js +1 -9
- package/dist/__synced__/types/shared.synced.d.ts +2 -3
- package/dist/__synced__/utils/remote-component-registry.synced.d.ts +80 -0
- package/dist/__synced__/utils/remote-component-registry.synced.js +64 -0
- package/dist/__tests__/crm/hooks/useAssociations.spec.js +33 -29
- package/dist/__tests__/crm/hooks/useCrmProperties.spec.js +19 -18
- package/dist/__tests__/crm/utils/fetchAssociations.spec.js +8 -7
- package/dist/__tests__/crm/utils/fetchCrmProperties.spec.js +34 -33
- package/dist/crm/index.d.ts +1 -1
- package/dist/crm/index.js +1 -1
- package/dist/experimental/index.d.ts +1 -1
- package/dist/experimental/index.js +1 -1
- package/dist/experimental/testing/__tests__/debug.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/debug.spec.js +43 -0
- package/dist/experimental/testing/__tests__/find.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/find.spec.js +33 -0
- package/dist/experimental/testing/__tests__/findAll.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/findAll.spec.js +12 -0
- package/dist/experimental/testing/__tests__/findAllChildren.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/findAllChildren.spec.js +48 -0
- package/dist/experimental/testing/__tests__/findChild.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/findChild.spec.js +29 -0
- package/dist/experimental/testing/__tests__/fragments.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/fragments.spec.js +59 -0
- package/dist/experimental/testing/__tests__/invalid-components.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/invalid-components.spec.js +88 -0
- package/dist/experimental/testing/__tests__/isMatch.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/isMatch.spec.js +60 -0
- package/dist/experimental/testing/__tests__/maybeFind.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/maybeFind.spec.js +58 -0
- package/dist/experimental/testing/__tests__/maybeFindChild.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/maybeFindChild.spec.js +65 -0
- package/dist/experimental/testing/__tests__/trigger.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/trigger.spec.js +40 -0
- package/dist/experimental/testing/__tests__/type-utils.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/type-utils.spec.js +163 -0
- package/dist/experimental/testing/__tests__/waitFor.spec.d.ts +1 -0
- package/dist/experimental/testing/__tests__/waitFor.spec.js +55 -0
- package/dist/experimental/testing/index.d.ts +3 -0
- package/dist/experimental/testing/index.js +3 -0
- package/dist/experimental/testing/internal/constants.d.ts +2 -0
- package/dist/experimental/testing/internal/constants.js +1 -0
- package/dist/experimental/testing/internal/convert.d.ts +10 -0
- package/dist/experimental/testing/internal/convert.js +131 -0
- package/dist/experimental/testing/internal/debug.d.ts +8 -0
- package/dist/experimental/testing/internal/debug.js +19 -0
- package/dist/experimental/testing/internal/document.d.ts +14 -0
- package/dist/experimental/testing/internal/document.js +37 -0
- package/dist/experimental/testing/internal/element.d.ts +11 -0
- package/dist/experimental/testing/internal/element.js +67 -0
- package/dist/experimental/testing/internal/errors.d.ts +56 -0
- package/dist/experimental/testing/internal/errors.js +70 -0
- package/dist/experimental/testing/internal/fragment.d.ts +8 -0
- package/dist/experimental/testing/internal/fragment.js +44 -0
- package/dist/experimental/testing/internal/match.d.ts +19 -0
- package/dist/experimental/testing/internal/match.js +42 -0
- package/dist/experimental/testing/internal/print.d.ts +6 -0
- package/dist/experimental/testing/internal/print.js +114 -0
- package/dist/experimental/testing/internal/query.d.ts +57 -0
- package/dist/experimental/testing/internal/query.js +213 -0
- package/dist/experimental/testing/internal/root.d.ts +8 -0
- package/dist/experimental/testing/internal/root.js +44 -0
- package/dist/experimental/testing/internal/text.d.ts +9 -0
- package/dist/experimental/testing/internal/text.js +16 -0
- package/dist/experimental/testing/internal/utils/promise-utils.d.ts +14 -0
- package/dist/experimental/testing/internal/utils/promise-utils.js +14 -0
- package/dist/experimental/testing/render.d.ts +9 -0
- package/dist/experimental/testing/render.js +155 -0
- package/dist/experimental/testing/types.d.ts +2 -1
- package/dist/hubspot.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/pages/home/index.d.ts +1 -1
- package/dist/pages/home/index.js +1 -1
- package/package.json +19 -16
- package/dist/__synced__/appHomeRemoteComponents.synced.d.ts +0 -28
- package/dist/__synced__/appHomeRemoteComponents.synced.js +0 -21
- package/dist/__synced__/crmRemoteComponents.synced.d.ts +0 -66
- package/dist/__synced__/crmRemoteComponents.synced.js +0 -15
- package/dist/__synced__/experimentalRemoteComponents.synced.d.ts +0 -94
- package/dist/__synced__/experimentalRemoteComponents.synced.js +0 -56
- package/dist/coreComponents.d.ts +0 -848
- package/dist/coreComponents.js +0 -582
- package/dist/experimental/types.d.ts +0 -240
- package/dist/experimental/types.js +0 -5
- package/dist/types.d.ts +0 -3214
- 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
|
|
2
|
-
export type
|
|
3
|
-
export type
|
|
4
|
-
export type
|
|
5
|
-
export type
|
|
6
|
-
export type
|
|
7
|
-
export type
|
|
8
|
-
export type
|
|
9
|
-
export type
|
|
10
|
-
export type
|
|
11
|
-
export type
|
|
12
|
-
export type
|
|
13
|
-
export type
|
|
14
|
-
export type
|
|
15
|
-
export type
|
|
16
|
-
export type
|
|
17
|
-
export type
|
|
18
|
-
export type
|
|
19
|
-
export type
|
|
20
|
-
export type
|
|
21
|
-
export type
|
|
22
|
-
export type
|
|
23
|
-
export type
|
|
24
|
-
export type
|
|
25
|
-
export type
|
|
26
|
-
export type
|
|
27
|
-
export type
|
|
28
|
-
export type
|
|
29
|
-
export type
|
|
30
|
-
export type
|
|
31
|
-
export type
|
|
32
|
-
export type
|
|
33
|
-
export type
|
|
34
|
-
export type
|
|
35
|
-
export type
|
|
36
|
-
export type
|
|
37
|
-
export type
|
|
38
|
-
export type
|
|
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
|
-
|
|
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 {
|
|
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?:
|
|
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
|
-
|
|
6
|
+
vi.mock('../../../logger', () => ({
|
|
6
7
|
logger: {
|
|
7
|
-
debug:
|
|
8
|
-
info:
|
|
9
|
-
warn:
|
|
10
|
-
error:
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
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:
|
|
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
|
-
|
|
6
|
+
vi.mock('../../../logger', () => ({
|
|
5
7
|
logger: {
|
|
6
|
-
debug:
|
|
7
|
-
info:
|
|
8
|
-
warn:
|
|
9
|
-
error:
|
|
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
|
-
|
|
14
|
-
const mockFetchCrmProperties =
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
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 =
|
|
221
|
-
const mockCleanup2 =
|
|
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 =
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
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:
|
|
317
|
+
json: vi.fn().mockResolvedValue(mockApiResponse),
|
|
317
318
|
});
|
|
318
319
|
const result = await fetchAssociations(createBasicRequest());
|
|
319
320
|
expect(typeof result.cleanup).toBe('function');
|