@hubspot/ui-extensions 0.11.5 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/__tests__/crm/hooks/useAssociations.spec.js +96 -0
  2. package/dist/__tests__/crm/hooks/useCrmProperties.spec.js +170 -1
  3. package/dist/crm/hooks/useAssociations.d.ts +2 -0
  4. package/dist/crm/hooks/useAssociations.js +87 -0
  5. package/dist/crm/hooks/useCrmProperties.d.ts +5 -1
  6. package/dist/crm/hooks/useCrmProperties.js +81 -2
  7. package/dist/hs-internal/__tests__/createRemoteComponentInternal.spec.d.ts +1 -0
  8. package/dist/hs-internal/__tests__/createRemoteComponentInternal.spec.js +139 -0
  9. package/dist/hs-internal/index.d.ts +35 -0
  10. package/dist/hs-internal/index.js +20 -0
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/shared/remoteComponents.d.ts +9 -0
  14. package/dist/shared/remoteComponents.js +9 -0
  15. package/dist/shared/types/components/accordion.d.ts +5 -5
  16. package/dist/shared/types/components/alert.d.ts +2 -2
  17. package/dist/shared/types/components/button-row.d.ts +5 -2
  18. package/dist/shared/types/components/button.d.ts +16 -10
  19. package/dist/shared/types/components/chart.d.ts +3 -3
  20. package/dist/shared/types/components/description-list.d.ts +2 -2
  21. package/dist/shared/types/components/dropdown.d.ts +8 -8
  22. package/dist/shared/types/components/empty-state.d.ts +5 -7
  23. package/dist/shared/types/components/error-state.d.ts +2 -2
  24. package/dist/shared/types/components/form.d.ts +2 -2
  25. package/dist/shared/types/components/heading.d.ts +1 -1
  26. package/dist/shared/types/components/icon.d.ts +4 -5
  27. package/dist/shared/types/components/illustration.d.ts +12 -0
  28. package/dist/shared/types/components/image.d.ts +9 -4
  29. package/dist/shared/types/components/index.d.ts +1 -0
  30. package/dist/shared/types/components/inputs.d.ts +61 -63
  31. package/dist/shared/types/components/layouts.d.ts +17 -24
  32. package/dist/shared/types/components/link.d.ts +8 -5
  33. package/dist/shared/types/components/loading-spinner.d.ts +3 -3
  34. package/dist/shared/types/components/modal.d.ts +5 -5
  35. package/dist/shared/types/components/panel.d.ts +7 -7
  36. package/dist/shared/types/components/progress-bar.d.ts +4 -4
  37. package/dist/shared/types/components/score.d.ts +13 -0
  38. package/dist/shared/types/components/score.js +1 -0
  39. package/dist/shared/types/components/selects.d.ts +11 -20
  40. package/dist/shared/types/components/statistics.d.ts +2 -2
  41. package/dist/shared/types/components/status-tag.d.ts +5 -5
  42. package/dist/shared/types/components/step-indicator.d.ts +5 -7
  43. package/dist/shared/types/components/table.d.ts +22 -12
  44. package/dist/shared/types/components/tabs.d.ts +10 -10
  45. package/dist/shared/types/components/tag.d.ts +2 -2
  46. package/dist/shared/types/components/text.d.ts +15 -21
  47. package/dist/shared/types/components/tile.d.ts +2 -2
  48. package/dist/shared/types/components/toggle.d.ts +12 -14
  49. package/dist/shared/types/components/toggleInputs.d.ts +26 -19
  50. package/dist/shared/types/components/tooltip.d.ts +1 -1
  51. package/dist/shared/types/crm.d.ts +52 -0
  52. package/dist/shared/types/http-requests.d.ts +2 -2
  53. package/dist/shared/types/index.d.ts +1 -1
  54. package/dist/shared/types/index.js +1 -0
  55. package/dist/shared/types/shared.d.ts +128 -78
  56. package/dist/shared/types/shared.js +123 -78
  57. package/dist/shared/types/worker-globals.d.ts +11 -10
  58. package/dist/testing/__tests__/mocks.useAssociations.spec.js +92 -4
  59. package/dist/testing/__tests__/mocks.useCrmProperties.spec.js +55 -7
  60. package/dist/testing/internal/mocks/mock-hooks.js +4 -0
  61. package/package.json +4 -3
@@ -18,151 +18,196 @@ export class FormSubmitExtensionEvent extends ExtensionEvent {
18
18
  }
19
19
  }
20
20
  export const iconNames = {
21
- success: 'success',
22
- remove: 'remove',
23
21
  add: 'add',
22
+ appointment: 'appointment',
23
+ approvals: 'approvals',
24
+ artificialIntelligence: 'artificialIntelligence',
25
+ artificialIntelligenceEnhanced: 'artificialIntelligenceEnhanced',
24
26
  attach: 'attach',
25
- date: 'date',
27
+ bank: 'bank',
28
+ block: 'block',
29
+ book: 'knowledgeBase',
30
+ bulb: 'bulb',
31
+ callTranscript: 'callTranscript',
32
+ calling: 'calling',
33
+ callingHangup: 'callingHangup',
34
+ callingMade: 'callingMade',
35
+ callingMissed: 'callingMissed',
36
+ callingVoicemail: 'callingVoicemail',
37
+ campaigns: 'campaigns',
38
+ cap: 'cap',
39
+ checkCircle: 'checkCircle',
40
+ circleFilled: 'circleFilled',
41
+ circleHollow: 'circleHollow',
42
+ clock: 'time',
43
+ comment: 'comments',
44
+ contact: 'contacts',
26
45
  copy: 'duplicate',
46
+ crm: 'crm',
47
+ dataSync: 'dataSync',
48
+ date: 'date',
49
+ delay: 'delay',
27
50
  delete: 'delete',
51
+ description: 'description',
52
+ developerProjects: 'developerProjects',
53
+ documents: 'documents',
54
+ downCarat: 'downCarat',
55
+ download: 'download',
28
56
  edit: 'edit',
57
+ ellipses: 'ellipses',
29
58
  email: 'email',
59
+ emailOpen: 'emailOpen',
60
+ emailThreadedReplies: 'emailThreadedReplies',
61
+ enrichment: 'enrichment',
62
+ enroll: 'enroll',
30
63
  exclamation: 'exclamation',
31
- question: 'question',
32
- home: 'home',
33
- location: 'location',
34
- upCarat: 'upCarat',
35
- downCarat: 'downCarat',
36
- warning: 'warning',
37
- shoppingCart: 'cart',
38
- clock: 'time',
39
- comment: 'comments',
40
- contact: 'contacts',
41
- star: 'favorite',
42
- file: 'file',
43
- reports: 'reports',
44
- video: 'video',
45
- robot: 'simpleBot',
46
- refresh: 'refresh',
64
+ exclamationCircle: 'exclamationCircle',
47
65
  faceHappy: 'emoji',
66
+ faceHappyFilled: 'emojiFillHappy',
48
67
  faceNeutral: 'emojiLineNeutral',
68
+ faceNeutralFilled: 'emojiFillNeutral',
49
69
  faceSad: 'emojiLineSad',
50
- upload: 'upload',
51
- download: 'download',
52
- left: 'left',
53
- right: 'right',
54
- dataSync: 'dataSync',
55
- imageGallery: 'imageGallery',
56
- search: 'search',
57
- save: 'saveEditableView',
58
- notification: 'notification',
59
- bulb: 'bulb',
60
- settings: 'settings',
70
+ faceSadFilled: 'emojiFillSad',
71
+ facebook: 'socialBlockFacebook',
72
+ favoriteHollow: 'favoriteHollow',
73
+ file: 'file',
74
+ filledXCircleIcon: 'filledXCircleIcon',
61
75
  filter: 'filter',
76
+ flame: 'highlyEngagedLead',
77
+ folder: 'folder',
78
+ folderOpen: 'folderOpen',
79
+ forward: 'forward',
62
80
  gauge: 'gauge',
63
- enroll: 'enroll',
64
81
  generateChart: 'generateChart',
65
82
  gift: 'gift',
66
- flame: 'highlyEngagedLead',
67
- inbox: 'inbox',
83
+ globe: 'language',
84
+ globeLine: 'globe',
85
+ goal: 'goal',
86
+ googlePlus: 'socialBlockGoogleplus',
87
+ guidedActions: 'guidedActions',
88
+ hash: 'numericDataType',
89
+ hide: 'hide',
90
+ home: 'home',
91
+ hubDB: 'hubDB',
68
92
  image: 'insertImage',
69
- quote: 'insertQuote',
93
+ imageGallery: 'imageGallery',
94
+ inbox: 'inbox',
95
+ info: 'info',
96
+ infoNoCircle: 'infoNoCircle',
70
97
  insertVideo: 'insertVideo',
98
+ instagram: 'socialBlockInstagram',
99
+ integrations: 'integrations',
71
100
  invoice: 'invoice',
72
101
  key: 'key',
73
- book: 'knowledgeBase',
74
- globe: 'language',
102
+ language: 'language',
103
+ left: 'left',
104
+ lessCircle: 'lessCircle',
75
105
  lesson: 'lesson',
106
+ light: 'light',
76
107
  link: 'link',
108
+ linkedin: 'socialBlockLinkedin',
77
109
  listView: 'listView',
110
+ location: 'location',
78
111
  locked: 'locked',
79
112
  mention: 'mention',
80
113
  messages: 'messages',
81
114
  mobile: 'mobile',
115
+ moreCircle: 'moreCircle',
116
+ notEditable: 'notEditable',
117
+ notification: 'notification',
82
118
  notificationOff: 'notificationOff',
83
- hash: 'numericDataType',
84
119
  objectAssociations: 'objectAssociations',
85
120
  objectAssociationsManyToMany: 'objectAssociationsManyToMany',
86
121
  objectAssociationsManyToOne: 'objectAssociationsManyToOne',
87
122
  office365: 'office365',
88
123
  order: 'order',
89
124
  paymentSubscriptions: 'paymentSubscriptions',
90
- product: 'product',
125
+ pin: 'pin',
126
+ pinterest: 'socialBlockPinterest',
91
127
  powerPointFile: 'powerPointFile',
92
128
  presentation: 'presentation',
129
+ product: 'product',
93
130
  publish: 'publish',
131
+ question: 'question',
94
132
  questionAnswer: 'questionAnswer',
133
+ questionCircle: 'questionCircle',
95
134
  quickbooks: 'quickbooks',
135
+ quote: 'insertQuote',
96
136
  readMore: 'readMore',
97
- realEstateListing: 'realEstateListing',
98
137
  readOnlyView: 'readOnlyView',
138
+ realEstateListing: 'realEstateListing',
99
139
  recentlySelected: 'recentlySelected',
100
140
  record: 'record',
101
141
  redo: 'redo',
102
- undo: 'undo',
142
+ refresh: 'refresh',
103
143
  registration: 'registration',
144
+ remove: 'remove',
104
145
  replace: 'replace',
146
+ reports: 'reports',
147
+ right: 'right',
148
+ robot: 'simpleBot',
105
149
  rotate: 'rotate',
150
+ rss: 'socialBlockRss',
106
151
  salesQuote: 'salesQuote',
107
152
  salesTemplates: 'salesTemplates',
153
+ save: 'saveEditableView',
154
+ search: 'search',
155
+ send: 'send',
108
156
  sequences: 'sequences',
157
+ settings: 'settings',
158
+ shoppingCart: 'cart',
159
+ signal: 'signal',
160
+ signalPoor: 'signalPoor',
161
+ signature: 'signature',
162
+ snooze: 'snooze',
163
+ sortAlpAsc: 'sortAlpAsc',
164
+ sortAlpDesc: 'sortAlpDesc',
165
+ sortAmtAsc: 'sortAmtAsc',
166
+ sortAmtDesc: 'sortAmtDesc',
167
+ sortNumAsc: 'sortNumAsc',
168
+ sortNumDesc: 'sortNumDesc',
169
+ sortTableAsc: 'sortTableAsc',
170
+ sortTableDesc: 'sortTableDesc',
109
171
  spellCheck: 'spellCheck',
172
+ sprocket: 'sprocket',
173
+ star: 'favorite',
174
+ stopRecord: 'stopRecord',
110
175
  strike: 'strike',
176
+ styles: 'styles',
177
+ success: 'success',
111
178
  tablet: 'tablet',
112
179
  tag: 'tag',
113
180
  tasks: 'tasks',
114
181
  test: 'test',
115
- ticket: 'ticket',
116
- thumbsUp: 'thumbsUp',
182
+ text: 'text',
183
+ textBodyExpanded: 'textBodyExpanded',
184
+ textColor: 'textColor',
185
+ textDataType: 'textDataType',
186
+ textSnippet: 'textSnippet',
117
187
  thumbsDown: 'thumbsDown',
188
+ thumbsUp: 'thumbsUp',
189
+ ticket: 'ticket',
118
190
  translate: 'translate',
119
191
  trophy: 'trophy',
192
+ twitter: 'socialBlockTwitter',
193
+ undo: 'undo',
194
+ upCarat: 'upCarat',
195
+ upload: 'upload',
196
+ video: 'video',
120
197
  videoFile: 'videoFile',
121
198
  videoPlayerSubtitles: 'videoPlayerSubtitles',
122
199
  view: 'view',
123
200
  viewDetails: 'viewDetails',
201
+ warning: 'warning',
124
202
  website: 'website',
125
203
  workflows: 'workflows',
126
- zoomIn: 'zoomIn',
127
- zoomOut: 'zoomOut',
128
- goal: 'goal',
129
- campaigns: 'campaigns',
130
- cap: 'cap',
131
- block: 'block',
132
- bank: 'bank',
133
- approvals: 'approvals',
134
- appointment: 'appointment',
135
- facebook: 'socialBlockFacebook',
136
- googlePlus: 'socialBlockGoogleplus',
137
- instagram: 'socialBlockInstagram',
138
- linkedin: 'socialBlockLinkedin',
139
- pinterest: 'socialBlockPinterest',
140
- rss: 'socialBlockRss',
141
- twitter: 'socialBlockTwitter',
142
204
  x: 'socialBlockX',
205
+ xCircle: 'xCircle',
143
206
  xing: 'socialBlockXing',
144
207
  youtube: 'socialBlockYoutube',
145
208
  youtubePlay: 'socialBlockYoutubeplay',
146
- sortAlpAsc: 'sortAlpAsc',
147
- sortAlpDesc: 'sortAlpDesc',
148
- sortAmtAsc: 'sortAmtAsc',
149
- sortAmtDesc: 'sortAmtDesc',
150
- sortNumAsc: 'sortNumAsc',
151
- sortNumDesc: 'sortNumDesc',
152
- sortTableAsc: 'sortTableAsc',
153
- sortTableDesc: 'sortTableDesc',
154
- text: 'text',
155
- textColor: 'textColor',
156
- textDataType: 'textDataType',
157
- textSnippet: 'textSnippet',
158
- calling: 'calling',
159
- callingHangup: 'callingHangup',
160
- callingMade: 'callingMade',
161
- callingMissed: 'callingMissed',
162
- callingVoicemail: 'callingVoicemail',
163
- faceHappyFilled: 'emojiFillHappy',
164
- faceNeutralFilled: 'emojiFillNeutral',
165
- faceSadFilled: 'emojiFillSad',
209
+ zoomIn: 'zoomIn',
210
+ zoomOut: 'zoomOut',
166
211
  };
167
212
  /** @deprecated use ExtensionEvent/FormSubmitExtensionEvent instead */
168
213
  export class RemoteEvent {
@@ -1,6 +1,16 @@
1
1
  import { Logger } from './logger.ts';
2
2
  import { HubspotExtendFunction } from './extend.ts';
3
3
  import type { ExtensionPoints, ExtensionPointApiContext, ExtensionPointApiActions } from './extension-points.ts';
4
+ export interface WorkersApi {
5
+ /**
6
+ * Hook added to worker globals so customer code can access extension context at runtime.
7
+ */
8
+ useExtensionContext: <ExtensionPoint extends keyof ExtensionPoints>() => ExtensionPointApiContext<ExtensionPoint>;
9
+ /**
10
+ * Hook added to worker globals so customer code can access extension actions at runtime.
11
+ */
12
+ useExtensionActions: <ExtensionPoint extends keyof ExtensionPoints>() => ExtensionPointApiActions<ExtensionPoint>;
13
+ }
4
14
  export interface WorkerGlobalsInternal {
5
15
  /**
6
16
  * A marker that the current global is a HubSpot extension worker.
@@ -19,14 +29,5 @@ export interface WorkerGlobalsInternal {
19
29
  * Namespace where all HubSpot APIs that go on the worker should live.
20
30
  * This avoids polluting the global and reduces the possibility of customer code having collisions with our code.
21
31
  */
22
- hsWorkerAPI: {
23
- /**
24
- * Hook added to worker globals so customer code can access extension context at runtime.
25
- */
26
- useExtensionContext: <ExtensionPoint extends keyof ExtensionPoints>() => ExtensionPointApiContext<ExtensionPoint>;
27
- /**
28
- * Hook added to worker globals so customer code can access extension actions at runtime.
29
- */
30
- useExtensionActions: <ExtensionPoint extends keyof ExtensionPoints>() => ExtensionPointApiActions<ExtensionPoint>;
31
- };
32
+ hsWorkerAPI: WorkersApi;
32
33
  }
@@ -1,10 +1,10 @@
1
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";
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { Text, Button } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  import { useAssociations } from "../../crm/index.js";
6
6
  function MyComponent() {
7
- const { results, isLoading, error } = useAssociations({
7
+ const { results, isLoading, isRefetching, error, refetch } = useAssociations({
8
8
  toObjectType: '0-1',
9
9
  properties: ['firstname', 'lastname'],
10
10
  pageLength: 10,
@@ -12,10 +12,13 @@ function MyComponent() {
12
12
  if (isLoading) {
13
13
  return _jsx(Text, { children: "Loading..." });
14
14
  }
15
+ if (isRefetching) {
16
+ return _jsx(Text, { children: "Refetching..." });
17
+ }
15
18
  if (error) {
16
19
  return _jsx(Text, { children: "Something went wrong!" });
17
20
  }
18
- return (_jsx(_Fragment, { children: results.map((result) => (_jsxs(Text, { children: [result.properties.firstname, " ", result.properties.lastname] }, result.toObjectId))) }));
21
+ return (_jsxs(_Fragment, { children: [results.map((result) => (_jsxs(Text, { children: [result.properties.firstname, " ", result.properties.lastname] }, result.toObjectId))), _jsx(Button, { testId: "refetchButton", onClick: () => refetch(), children: "Refetch" })] }));
19
22
  }
20
23
  describe('mock useAssociations', () => {
21
24
  it('should provide a default mock implementation', () => {
@@ -31,6 +34,8 @@ describe('mock useAssociations', () => {
31
34
  results: [],
32
35
  error: new Error('Something went wrong!'),
33
36
  isLoading: false,
37
+ isRefetching: false,
38
+ refetch: async () => { },
34
39
  pagination: {
35
40
  hasNextPage: false,
36
41
  hasPreviousPage: false,
@@ -44,4 +49,87 @@ describe('mock useAssociations', () => {
44
49
  const { find } = render(_jsx(MyComponent, {}));
45
50
  expect(find(Text).text).toEqual('Something went wrong!');
46
51
  });
52
+ it('should allow tracking refetch calls with a custom spy', () => {
53
+ const { render, mocks, findByTestId } = createRenderer('crm.record.tab');
54
+ const refetchSpy = vi.fn().mockResolvedValue(undefined);
55
+ mocks.useAssociations.nextResult({
56
+ results: [
57
+ {
58
+ toObjectId: 1,
59
+ associationTypes: [],
60
+ properties: { firstname: 'John', lastname: 'Doe' },
61
+ },
62
+ ],
63
+ error: null,
64
+ isLoading: false,
65
+ isRefetching: false,
66
+ refetch: refetchSpy,
67
+ pagination: {
68
+ hasNextPage: false,
69
+ hasPreviousPage: false,
70
+ currentPage: 1,
71
+ pageSize: 10,
72
+ nextPage: () => { },
73
+ previousPage: () => { },
74
+ reset: () => { },
75
+ },
76
+ });
77
+ render(_jsx(MyComponent, {}));
78
+ findByTestId(Button, 'refetchButton').trigger('onClick');
79
+ expect(refetchSpy).toHaveBeenCalledTimes(1);
80
+ });
81
+ it('should allow mocking isRefetching state during refetch', () => {
82
+ const { render, mocks } = createRenderer('crm.record.tab');
83
+ mocks.useAssociations.nextResult({
84
+ results: [],
85
+ error: null,
86
+ isLoading: false,
87
+ isRefetching: true,
88
+ refetch: async () => { },
89
+ pagination: {
90
+ hasNextPage: false,
91
+ hasPreviousPage: false,
92
+ currentPage: 1,
93
+ pageSize: 10,
94
+ nextPage: () => { },
95
+ previousPage: () => { },
96
+ reset: () => { },
97
+ },
98
+ });
99
+ const { find } = render(_jsx(MyComponent, {}));
100
+ expect(find(Text).text).toEqual('Refetching...');
101
+ });
102
+ it('should allow providing a custom refetch implementation', () => {
103
+ const { render, mocks, findByTestId } = createRenderer('crm.record.tab');
104
+ const refetchSpy = vi.fn().mockResolvedValue(undefined);
105
+ const customData = { customKey: 'customValue' };
106
+ mocks.useAssociations.nextResult({
107
+ results: [
108
+ {
109
+ toObjectId: 1,
110
+ associationTypes: [],
111
+ properties: { firstname: 'Test', lastname: 'User' },
112
+ },
113
+ ],
114
+ error: null,
115
+ isLoading: false,
116
+ isRefetching: false,
117
+ refetch: async () => {
118
+ await refetchSpy(customData);
119
+ },
120
+ pagination: {
121
+ hasNextPage: false,
122
+ hasPreviousPage: false,
123
+ currentPage: 1,
124
+ pageSize: 10,
125
+ nextPage: () => { },
126
+ previousPage: () => { },
127
+ reset: () => { },
128
+ },
129
+ });
130
+ render(_jsx(MyComponent, {}));
131
+ findByTestId(Button, 'refetchButton').trigger('onClick');
132
+ expect(refetchSpy).toHaveBeenCalledTimes(1);
133
+ expect(refetchSpy).toHaveBeenCalledWith(customData);
134
+ });
47
135
  });
@@ -1,20 +1,20 @@
1
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";
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { Text, Button } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  import { useCrmProperties } from "../../crm/index.js";
6
6
  function MyComponent() {
7
- const { properties, isLoading, error } = useCrmProperties([
8
- 'firstname',
9
- 'lastname',
10
- ]);
7
+ const { properties, isLoading, isRefetching, error, refetch } = useCrmProperties(['firstname', 'lastname']);
11
8
  if (isLoading) {
12
9
  return _jsx(Text, { children: "Loading..." });
13
10
  }
11
+ if (isRefetching) {
12
+ return _jsx(Text, { children: "Refetching..." });
13
+ }
14
14
  if (error) {
15
15
  return _jsx(Text, { children: "Something went wrong!" });
16
16
  }
17
- return (_jsxs(_Fragment, { children: [_jsxs(Text, { children: ["First name: ", properties.firstname] }), _jsxs(Text, { children: ["Last name: ", properties.lastname] })] }));
17
+ return (_jsxs(_Fragment, { children: [_jsxs(Text, { children: ["First name: ", properties.firstname] }), _jsxs(Text, { children: ["Last name: ", properties.lastname] }), _jsx(Button, { testId: "refetchButton", onClick: () => refetch(), children: "Refetch" })] }));
18
18
  }
19
19
  describe('mock useCrmProperties', () => {
20
20
  it('should provide a default mock implementation', () => {
@@ -31,6 +31,8 @@ describe('mock useCrmProperties', () => {
31
31
  properties: {},
32
32
  error: new Error('Something went wrong!'),
33
33
  isLoading: false,
34
+ isRefetching: false,
35
+ refetch: () => Promise.resolve(),
34
36
  });
35
37
  const { find } = render(_jsx(MyComponent, {}));
36
38
  expect(find(Text).text).toEqual('Something went wrong!');
@@ -46,6 +48,8 @@ describe('mock useCrmProperties', () => {
46
48
  properties,
47
49
  error: null,
48
50
  isLoading: false,
51
+ isRefetching: false,
52
+ refetch: async () => { },
49
53
  };
50
54
  });
51
55
  render(_jsx(MyComponent, {}));
@@ -55,4 +59,48 @@ describe('mock useCrmProperties', () => {
55
59
  expect(firstNameText.isMatch(Text) && firstNameText.text).toEqual('First name: FIRSTNAME');
56
60
  expect(lastNameText.isMatch(Text) && lastNameText.text).toEqual('Last name: LASTNAME');
57
61
  });
62
+ it('should allow tracking refetch calls with a custom spy', () => {
63
+ const { render, mocks, findByTestId } = createRenderer('crm.record.tab');
64
+ const refetchSpy = vi.fn().mockResolvedValue(undefined);
65
+ mocks.useCrmProperties.nextResult({
66
+ properties: { firstname: 'John', lastname: 'Doe' },
67
+ error: null,
68
+ isLoading: false,
69
+ isRefetching: false,
70
+ refetch: refetchSpy,
71
+ });
72
+ render(_jsx(MyComponent, {}));
73
+ findByTestId(Button, 'refetchButton').trigger('onClick');
74
+ expect(refetchSpy).toHaveBeenCalledTimes(1);
75
+ });
76
+ it('should allow mocking isRefetching state during refetch', () => {
77
+ const { render, mocks } = createRenderer('crm.record.tab');
78
+ mocks.useCrmProperties.nextResult({
79
+ properties: {},
80
+ error: null,
81
+ isLoading: false,
82
+ isRefetching: true,
83
+ refetch: async () => { },
84
+ });
85
+ const { find } = render(_jsx(MyComponent, {}));
86
+ expect(find(Text).text).toEqual('Refetching...');
87
+ });
88
+ it('should allow providing a custom refetch implementation', () => {
89
+ const { render, mocks, findByTestId } = createRenderer('crm.record.tab');
90
+ const refetchSpy = vi.fn().mockResolvedValue(undefined);
91
+ const customData = { customKey: 'customValue' };
92
+ mocks.useCrmProperties.nextResult({
93
+ properties: { firstname: 'Test Value', lastname: 'Test' },
94
+ error: null,
95
+ isLoading: false,
96
+ isRefetching: false,
97
+ refetch: async () => {
98
+ await refetchSpy(customData);
99
+ },
100
+ });
101
+ render(_jsx(MyComponent, {}));
102
+ findByTestId(Button, 'refetchButton').trigger('onClick');
103
+ expect(refetchSpy).toHaveBeenCalledTimes(1);
104
+ expect(refetchSpy).toHaveBeenCalledWith(customData);
105
+ });
58
106
  });
@@ -24,6 +24,8 @@ export const createMockHooks = () => {
24
24
  properties,
25
25
  error: null,
26
26
  isLoading: false,
27
+ isRefetching: false,
28
+ refetch: async () => { },
27
29
  };
28
30
  },
29
31
  useAssociations: (config) => {
@@ -45,6 +47,8 @@ export const createMockHooks = () => {
45
47
  ],
46
48
  error: null,
47
49
  isLoading: false,
50
+ isRefetching: false,
51
+ refetch: async () => { },
48
52
  pagination: {
49
53
  hasNextPage: false,
50
54
  hasPreviousPage: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/ui-extensions",
3
- "version": "0.11.5",
3
+ "version": "0.12.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -28,7 +28,8 @@
28
28
  "./crm": "./dist/crm/index.js",
29
29
  "./pages/home": "./dist/pages/home/index.js",
30
30
  "./experimental": "./dist/experimental/index.js",
31
- "./testing": "./dist/testing/index.js"
31
+ "./testing": "./dist/testing/index.js",
32
+ "./hs-internal": "./dist/hs-internal/index.js"
32
33
  },
33
34
  "license": "MIT",
34
35
  "dependencies": {
@@ -74,5 +75,5 @@
74
75
  "tsd": {
75
76
  "directory": "src/__tests__/test-d"
76
77
  },
77
- "gitHead": "e262c2b6780bb1f65bd09b1df4a2e724cd627c19"
78
+ "gitHead": "c5b66da065a341df3afd98ce6641bb3e6317aeb4"
78
79
  }