@hubspot/ui-extensions 0.11.4 → 0.11.6

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 (155) 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/hooks/useExtensionActions.d.ts +4 -0
  8. package/dist/hooks/useExtensionActions.js +6 -0
  9. package/dist/hooks/useExtensionContext.d.ts +4 -0
  10. package/dist/hooks/useExtensionContext.js +6 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +2 -0
  13. package/dist/internal/global-utils.js +4 -0
  14. package/dist/internal/hook-utils.d.ts +10 -3
  15. package/dist/internal/hook-utils.js +10 -1
  16. package/dist/shared/types/components/accordion.d.ts +5 -5
  17. package/dist/shared/types/components/alert.d.ts +2 -2
  18. package/dist/shared/types/components/button-row.d.ts +5 -2
  19. package/dist/shared/types/components/button.d.ts +16 -10
  20. package/dist/shared/types/components/chart.d.ts +3 -3
  21. package/dist/shared/types/components/description-list.d.ts +2 -2
  22. package/dist/shared/types/components/dropdown.d.ts +8 -8
  23. package/dist/shared/types/components/empty-state.d.ts +5 -7
  24. package/dist/shared/types/components/error-state.d.ts +2 -2
  25. package/dist/shared/types/components/form.d.ts +2 -2
  26. package/dist/shared/types/components/heading.d.ts +1 -1
  27. package/dist/shared/types/components/icon.d.ts +4 -5
  28. package/dist/shared/types/components/illustration.d.ts +12 -0
  29. package/dist/shared/types/components/image.d.ts +9 -4
  30. package/dist/shared/types/components/inputs.d.ts +51 -64
  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/selects.d.ts +11 -20
  38. package/dist/shared/types/components/statistics.d.ts +2 -2
  39. package/dist/shared/types/components/status-tag.d.ts +5 -5
  40. package/dist/shared/types/components/step-indicator.d.ts +5 -7
  41. package/dist/shared/types/components/table.d.ts +22 -12
  42. package/dist/shared/types/components/tabs.d.ts +10 -10
  43. package/dist/shared/types/components/tag.d.ts +2 -2
  44. package/dist/shared/types/components/text.d.ts +15 -21
  45. package/dist/shared/types/components/tile.d.ts +2 -2
  46. package/dist/shared/types/components/toggle.d.ts +12 -14
  47. package/dist/shared/types/components/toggleInputs.d.ts +26 -19
  48. package/dist/shared/types/components/tooltip.d.ts +1 -1
  49. package/dist/shared/types/crm.d.ts +52 -0
  50. package/dist/shared/types/http-requests.d.ts +2 -2
  51. package/dist/shared/types/shared.d.ts +123 -78
  52. package/dist/shared/types/shared.js +123 -78
  53. package/dist/shared/types/worker-globals.d.ts +15 -0
  54. package/dist/{experimental/testing → testing}/__tests__/debug.spec.js +1 -1
  55. package/dist/{experimental/testing → testing}/__tests__/find.spec.js +1 -1
  56. package/dist/{experimental/testing → testing}/__tests__/findAll.spec.js +1 -1
  57. package/dist/{experimental/testing → testing}/__tests__/findAllChildren.spec.js +1 -1
  58. package/dist/{experimental/testing → testing}/__tests__/findByTestId.spec.js +1 -1
  59. package/dist/{experimental/testing → testing}/__tests__/findChild.spec.js +1 -1
  60. package/dist/{experimental/testing → testing}/__tests__/fragments.spec.js +1 -1
  61. package/dist/{experimental/testing → testing}/__tests__/invalid-components.spec.js +1 -1
  62. package/dist/{experimental/testing → testing}/__tests__/isMatch.spec.js +1 -1
  63. package/dist/{experimental/testing → testing}/__tests__/logger.spec.js +1 -1
  64. package/dist/{experimental/testing → testing}/__tests__/maybeFind.spec.js +1 -1
  65. package/dist/{experimental/testing → testing}/__tests__/maybeFindByTestId.spec.js +1 -1
  66. package/dist/{experimental/testing → testing}/__tests__/maybeFindChild.spec.js +1 -1
  67. package/dist/{experimental/testing → testing}/__tests__/mocks.runServerlessFunction.spec.js +1 -1
  68. package/dist/testing/__tests__/mocks.useAssociations.spec.js +135 -0
  69. package/dist/testing/__tests__/mocks.useCrmProperties.spec.js +106 -0
  70. package/dist/testing/__tests__/mocks.useExtensionActions.spec.js +32 -0
  71. package/dist/testing/__tests__/mocks.useExtensionContext.spec.js +46 -0
  72. package/dist/{experimental/testing → testing}/__tests__/props.spec.js +1 -1
  73. package/dist/{experimental/testing → testing}/__tests__/testId.spec.js +1 -1
  74. package/dist/{experimental/testing → testing}/__tests__/trigger.spec.js +1 -1
  75. package/dist/{experimental/testing → testing}/__tests__/type-utils.spec.js +1 -1
  76. package/dist/testing/__tests__/waitFor.spec.d.ts +1 -0
  77. package/dist/{experimental/testing → testing}/__tests__/waitFor.spec.js +1 -1
  78. package/dist/{experimental/testing → testing}/internal/convert.js +1 -1
  79. package/dist/{experimental/testing → testing}/internal/element.d.ts +1 -1
  80. package/dist/{experimental/testing → testing}/internal/errors.js +1 -1
  81. package/dist/{experimental/testing → testing}/internal/match.d.ts +1 -1
  82. package/dist/{experimental/testing → testing}/internal/mocks/index.d.ts +1 -1
  83. package/dist/{experimental/testing → testing}/internal/mocks/mock-extension-point-api.d.ts +1 -1
  84. package/dist/{experimental/testing → testing}/internal/mocks/mock-extension-point-api.js +1 -1
  85. package/dist/testing/internal/mocks/mock-hooks.d.ts +3 -0
  86. package/dist/{experimental/testing → testing}/internal/mocks/mock-hooks.js +14 -0
  87. package/dist/{experimental/testing → testing}/internal/print.js +1 -1
  88. package/dist/{experimental/testing → testing}/internal/query.d.ts +1 -1
  89. package/dist/{experimental/testing → testing}/internal/query.js +1 -1
  90. package/dist/{experimental/testing → testing}/internal/types-internal.d.ts +7 -3
  91. package/dist/testing/internal/types-internal.js +1 -0
  92. package/dist/{experimental/testing → testing}/render.d.ts +1 -1
  93. package/dist/{experimental/testing → testing}/render.js +7 -7
  94. package/dist/{experimental/testing → testing}/types.d.ts +25 -5
  95. package/dist/{experimental/testing → testing}/utils.d.ts +1 -1
  96. package/dist/{experimental/testing → testing}/utils.js +1 -1
  97. package/package.json +3 -3
  98. package/dist/experimental/testing/__tests__/mocks.useAssociations.spec.js +0 -47
  99. package/dist/experimental/testing/__tests__/mocks.useCrmProperties.spec.js +0 -58
  100. package/dist/experimental/testing/internal/mocks/mock-hooks.d.ts +0 -2
  101. /package/dist/{experimental/testing → testing}/__tests__/createRenderer.spec.d.ts +0 -0
  102. /package/dist/{experimental/testing → testing}/__tests__/createRenderer.spec.js +0 -0
  103. /package/dist/{experimental/testing → testing}/__tests__/debug.spec.d.ts +0 -0
  104. /package/dist/{experimental/testing → testing}/__tests__/find.spec.d.ts +0 -0
  105. /package/dist/{experimental/testing → testing}/__tests__/findAll.spec.d.ts +0 -0
  106. /package/dist/{experimental/testing → testing}/__tests__/findAllChildren.spec.d.ts +0 -0
  107. /package/dist/{experimental/testing → testing}/__tests__/findByTestId.spec.d.ts +0 -0
  108. /package/dist/{experimental/testing → testing}/__tests__/findChild.spec.d.ts +0 -0
  109. /package/dist/{experimental/testing → testing}/__tests__/fragments.spec.d.ts +0 -0
  110. /package/dist/{experimental/testing → testing}/__tests__/invalid-components.spec.d.ts +0 -0
  111. /package/dist/{experimental/testing → testing}/__tests__/isMatch.spec.d.ts +0 -0
  112. /package/dist/{experimental/testing → testing}/__tests__/logger.spec.d.ts +0 -0
  113. /package/dist/{experimental/testing → testing}/__tests__/maybeFind.spec.d.ts +0 -0
  114. /package/dist/{experimental/testing → testing}/__tests__/maybeFindByTestId.spec.d.ts +0 -0
  115. /package/dist/{experimental/testing → testing}/__tests__/maybeFindChild.spec.d.ts +0 -0
  116. /package/dist/{experimental/testing → testing}/__tests__/mocks.actions.spec.d.ts +0 -0
  117. /package/dist/{experimental/testing → testing}/__tests__/mocks.actions.spec.js +0 -0
  118. /package/dist/{experimental/testing → testing}/__tests__/mocks.context.spec.d.ts +0 -0
  119. /package/dist/{experimental/testing → testing}/__tests__/mocks.context.spec.js +0 -0
  120. /package/dist/{experimental/testing → testing}/__tests__/mocks.runServerlessFunction.spec.d.ts +0 -0
  121. /package/dist/{experimental/testing → testing}/__tests__/mocks.useAssociations.spec.d.ts +0 -0
  122. /package/dist/{experimental/testing → testing}/__tests__/mocks.useCrmProperties.spec.d.ts +0 -0
  123. /package/dist/{experimental/testing/__tests__/props.spec.d.ts → testing/__tests__/mocks.useExtensionActions.spec.d.ts} +0 -0
  124. /package/dist/{experimental/testing/__tests__/testId.spec.d.ts → testing/__tests__/mocks.useExtensionContext.spec.d.ts} +0 -0
  125. /package/dist/{experimental/testing/__tests__/trigger.spec.d.ts → testing/__tests__/props.spec.d.ts} +0 -0
  126. /package/dist/{experimental/testing/__tests__/type-utils.spec.d.ts → testing/__tests__/testId.spec.d.ts} +0 -0
  127. /package/dist/{experimental/testing/__tests__/waitFor.spec.d.ts → testing/__tests__/trigger.spec.d.ts} +0 -0
  128. /package/dist/{experimental/testing/internal/types-internal.js → testing/__tests__/type-utils.spec.d.ts} +0 -0
  129. /package/dist/{experimental/testing → testing}/index.d.ts +0 -0
  130. /package/dist/{experimental/testing → testing}/index.js +0 -0
  131. /package/dist/{experimental/testing → testing}/internal/constants.d.ts +0 -0
  132. /package/dist/{experimental/testing → testing}/internal/constants.js +0 -0
  133. /package/dist/{experimental/testing → testing}/internal/convert.d.ts +0 -0
  134. /package/dist/{experimental/testing → testing}/internal/debug.d.ts +0 -0
  135. /package/dist/{experimental/testing → testing}/internal/debug.js +0 -0
  136. /package/dist/{experimental/testing → testing}/internal/document.d.ts +0 -0
  137. /package/dist/{experimental/testing → testing}/internal/document.js +0 -0
  138. /package/dist/{experimental/testing → testing}/internal/element.js +0 -0
  139. /package/dist/{experimental/testing → testing}/internal/errors.d.ts +0 -0
  140. /package/dist/{experimental/testing → testing}/internal/fragment.d.ts +0 -0
  141. /package/dist/{experimental/testing → testing}/internal/fragment.js +0 -0
  142. /package/dist/{experimental/testing → testing}/internal/match.js +0 -0
  143. /package/dist/{experimental/testing → testing}/internal/mocks/index.js +0 -0
  144. /package/dist/{experimental/testing → testing}/internal/print.d.ts +0 -0
  145. /package/dist/{experimental/testing → testing}/internal/root.d.ts +0 -0
  146. /package/dist/{experimental/testing → testing}/internal/root.js +0 -0
  147. /package/dist/{experimental/testing → testing}/internal/text.d.ts +0 -0
  148. /package/dist/{experimental/testing → testing}/internal/text.js +0 -0
  149. /package/dist/{experimental/testing → testing}/internal/type-utils-internal.d.ts +0 -0
  150. /package/dist/{experimental/testing → testing}/internal/type-utils-internal.js +0 -0
  151. /package/dist/{experimental/testing → testing}/internal/utils/promise-utils.d.ts +0 -0
  152. /package/dist/{experimental/testing → testing}/internal/utils/promise-utils.js +0 -0
  153. /package/dist/{experimental/testing → testing}/type-utils.d.ts +0 -0
  154. /package/dist/{experimental/testing → testing}/type-utils.js +0 -0
  155. /package/dist/{experimental/testing → testing}/types.js +0 -0
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button, ButtonRow, List, Text } from "../../../index.js";
3
+ import { Alert, Button, ButtonRow, List, Text } from "../../index.js";
4
4
  import { createRenderer, isRenderedTextNode } from "../index.js";
5
5
  function MyComponent() {
6
6
  return (_jsxs(_Fragment, { children: [_jsx(ButtonRow, { children: _jsx(Button, { variant: "primary", overlay: _jsx(List, { children: _jsx(Text, { children: "Item 1" }) }), children: "Click me!" }) }), _jsx(Alert, { title: "My Alert" })] }));
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button, ButtonRow, Text } from "../../../index.js";
3
+ import { Alert, Button, ButtonRow, Text } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  import { ComponentNotFoundError, FindInvalidComponentError, } from "../internal/errors.js";
6
6
  describe('find()', () => {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button, ButtonRow } from "../../../index.js";
3
+ import { Alert, Button, ButtonRow } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  describe('findAll()', () => {
6
6
  it('should allow finding all matching components', () => {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button, ButtonRow, Text } from "../../../index.js";
3
+ import { Alert, Button, ButtonRow, Text } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  describe('findAllChildren()', () => {
6
6
  it('should allow finding all direct children from the root node', () => {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button, ButtonRow, Text } from "../../../index.js";
3
+ import { Alert, Button, ButtonRow, Text } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  import { ComponentMismatchedByTestIdError, ComponentNotFoundByTestIdError, FindInvalidComponentError, } from "../internal/errors.js";
6
6
  describe('findByTestId()', () => {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button, ButtonRow } from "../../../index.js";
3
+ import { Alert, Button, ButtonRow } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  import { ComponentNotFoundError, FindInvalidComponentError, } from "../internal/errors.js";
6
6
  describe('findChild()', () => {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button, ButtonRow, List, Text } from "../../../index.js";
3
+ import { Alert, Button, ButtonRow, List, Text } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  import { InvalidFragmentPropArrayError } from "../internal/errors.js";
6
6
  describe('fragments', () => {
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
3
  import { describe, expect, it } from 'vitest';
4
- import { Alert, Button, ButtonRow, Text } from "../../../index.js";
4
+ import { Alert, Button, ButtonRow, Text } from "../../index.js";
5
5
  import { createRenderer } from "../index.js";
6
6
  import { InvalidComponentsError } from "../internal/errors.js";
7
7
  import { createDeferred } from "../internal/utils/promise-utils.js";
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button } from "../../../index.js";
3
+ import { Alert, Button } from "../../index.js";
4
4
  import { createRenderer, isMatch, isRenderedFragmentNode, } from "../index.js";
5
5
  describe('isMatch()', () => {
6
6
  describe('isMatch() utility function', () => {
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { logger } from "../../../logger.js";
2
+ import { logger } from "../../logger.js";
3
3
  describe('logger in test environment', () => {
4
4
  it('should be available', () => {
5
5
  expect(logger.debug).toBeInstanceOf(Function);
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button, ButtonRow, Text } from "../../../index.js";
3
+ import { Alert, Button, ButtonRow, Text } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  describe('maybeFind()', () => {
6
6
  it('should return the element when found', () => {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button, ButtonRow } from "../../../index.js";
3
+ import { Alert, Button, ButtonRow } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  import { ComponentMismatchedByTestIdError, FindInvalidComponentError, } from "../internal/errors.js";
6
6
  describe('maybeFindByTestId()', () => {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Alert, Button, ButtonRow, Text } from "../../../index.js";
3
+ import { Alert, Button, ButtonRow, Text } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  describe('maybeFindChild()', () => {
6
6
  it('should return direct child from the root node', () => {
@@ -1,6 +1,6 @@
1
1
  import { describe, it } from 'vitest';
2
2
  import { createRenderer } from "../index.js";
3
- import { ServerlessExecutionStatus, } from "../../../shared/types/http-requests.js";
3
+ import { ServerlessExecutionStatus, } from "../../shared/types/http-requests.js";
4
4
  describe('mock runServerlessFunction', () => {
5
5
  it('should provide the ability to spy on the runServerlessFunction function', async () => {
6
6
  const { mocks } = createRenderer('crm.record.tab');
@@ -0,0 +1,135 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { Text, Button } from "../../index.js";
4
+ import { createRenderer } from "../index.js";
5
+ import { useAssociations } from "../../crm/index.js";
6
+ function MyComponent() {
7
+ const { results, isLoading, isRefetching, error, refetch } = useAssociations({
8
+ toObjectType: '0-1',
9
+ properties: ['firstname', 'lastname'],
10
+ pageLength: 10,
11
+ });
12
+ if (isLoading) {
13
+ return _jsx(Text, { children: "Loading..." });
14
+ }
15
+ if (isRefetching) {
16
+ return _jsx(Text, { children: "Refetching..." });
17
+ }
18
+ if (error) {
19
+ return _jsx(Text, { children: "Something went wrong!" });
20
+ }
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" })] }));
22
+ }
23
+ describe('mock useAssociations', () => {
24
+ it('should provide a default mock implementation', () => {
25
+ const { render } = createRenderer('crm.record.tab');
26
+ const { findAll } = render(_jsx(MyComponent, {}));
27
+ const textNodes = findAll(Text);
28
+ expect(textNodes.length).toEqual(1);
29
+ expect(textNodes[0].text).toEqual('fake_firstname fake_lastname');
30
+ });
31
+ it('should allow mocking the next function result', () => {
32
+ const { render, mocks } = createRenderer('crm.record.tab');
33
+ mocks.useAssociations.nextResult({
34
+ results: [],
35
+ error: new Error('Something went wrong!'),
36
+ isLoading: false,
37
+ isRefetching: false,
38
+ refetch: async () => { },
39
+ pagination: {
40
+ hasNextPage: false,
41
+ hasPreviousPage: false,
42
+ currentPage: 1,
43
+ pageSize: 10,
44
+ nextPage: () => { },
45
+ previousPage: () => { },
46
+ reset: () => { },
47
+ },
48
+ });
49
+ const { find } = render(_jsx(MyComponent, {}));
50
+ expect(find(Text).text).toEqual('Something went wrong!');
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
+ });
135
+ });
@@ -0,0 +1,106 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { Text, Button } from "../../index.js";
4
+ import { createRenderer } from "../index.js";
5
+ import { useCrmProperties } from "../../crm/index.js";
6
+ function MyComponent() {
7
+ const { properties, isLoading, isRefetching, error, refetch } = useCrmProperties(['firstname', 'lastname']);
8
+ if (isLoading) {
9
+ return _jsx(Text, { children: "Loading..." });
10
+ }
11
+ if (isRefetching) {
12
+ return _jsx(Text, { children: "Refetching..." });
13
+ }
14
+ if (error) {
15
+ return _jsx(Text, { children: "Something went wrong!" });
16
+ }
17
+ return (_jsxs(_Fragment, { children: [_jsxs(Text, { children: ["First name: ", properties.firstname] }), _jsxs(Text, { children: ["Last name: ", properties.lastname] }), _jsx(Button, { testId: "refetchButton", onClick: () => refetch(), children: "Refetch" })] }));
18
+ }
19
+ describe('mock useCrmProperties', () => {
20
+ it('should provide a default mock implementation', () => {
21
+ const { render } = createRenderer('crm.record.tab');
22
+ const { findAll } = render(_jsx(MyComponent, {}));
23
+ const textNodes = findAll(Text);
24
+ expect(textNodes.length).toEqual(2);
25
+ expect(textNodes[0].text).toEqual('First name: fake_firstname');
26
+ expect(textNodes[1].text).toEqual('Last name: fake_lastname');
27
+ });
28
+ it('should allow mocking the next function result', () => {
29
+ const { render, mocks } = createRenderer('crm.record.tab');
30
+ mocks.useCrmProperties.nextResult({
31
+ properties: {},
32
+ error: new Error('Something went wrong!'),
33
+ isLoading: false,
34
+ isRefetching: false,
35
+ refetch: () => Promise.resolve(),
36
+ });
37
+ const { find } = render(_jsx(MyComponent, {}));
38
+ expect(find(Text).text).toEqual('Something went wrong!');
39
+ });
40
+ it('should allow providing a custom mock function', () => {
41
+ const { render, mocks, findAll } = createRenderer('crm.record.tab');
42
+ mocks.useCrmProperties.willCall((propertyNames) => {
43
+ const properties = propertyNames.reduce((acc, propertyName) => {
44
+ acc[propertyName] = propertyName.toUpperCase();
45
+ return acc;
46
+ }, {});
47
+ return {
48
+ properties,
49
+ error: null,
50
+ isLoading: false,
51
+ isRefetching: false,
52
+ refetch: async () => { },
53
+ };
54
+ });
55
+ render(_jsx(MyComponent, {}));
56
+ const textNodes = findAll(Text);
57
+ const firstNameText = textNodes[0];
58
+ const lastNameText = textNodes[1];
59
+ expect(firstNameText.isMatch(Text) && firstNameText.text).toEqual('First name: FIRSTNAME');
60
+ expect(lastNameText.isMatch(Text) && lastNameText.text).toEqual('Last name: LASTNAME');
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
+ });
106
+ });
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createRenderer } from "../index.js";
3
+ import { useExtensionActions } from "../../hooks/useExtensionActions.js";
4
+ import { Button } from "../../index.js";
5
+ function MyActionsCrmComponent() {
6
+ const actions = useExtensionActions();
7
+ return (_jsxs(_Fragment, { children: [_jsx(Button, { testId: "reloadButton", onClick: () => actions.reloadPage(), children: "Reload Page" }), _jsx(Button, { testId: "fetchButton", onClick: () => {
8
+ actions.fetchCrmObjectProperties(['firstname', 'lastname']);
9
+ }, children: "Fetch Properties" })] }));
10
+ }
11
+ function MyActionsHomeComponent() {
12
+ const actions = useExtensionActions();
13
+ return (_jsx(_Fragment, { children: _jsx(Button, { testId: "copyButton", onClick: () => actions.copyTextToClipboard('Hello world'), children: "Copy Text" }) }));
14
+ }
15
+ describe('mock actions', () => {
16
+ it('should provide the ability to spy on the actions for the "crm.record.tab" extension point', () => {
17
+ const { mocks, render, findByTestId } = createRenderer('crm.record.tab');
18
+ const { actions } = mocks;
19
+ render(_jsx(MyActionsCrmComponent, {}));
20
+ findByTestId(Button, 'reloadButton').trigger('onClick');
21
+ expect(actions.reloadPage.callCount).toBe(1);
22
+ findByTestId(Button, 'fetchButton').trigger('onClick');
23
+ expect(actions.fetchCrmObjectProperties.callCount).toBe(1);
24
+ });
25
+ it('should provide the ability to spy on the actions for the "home" extension point', () => {
26
+ const { mocks, render, findByTestId } = createRenderer('home');
27
+ const { actions } = mocks;
28
+ render(_jsx(MyActionsHomeComponent, {}));
29
+ findByTestId(Button, 'copyButton').trigger('onClick');
30
+ expect(actions.copyTextToClipboard.callCount).toBe(1);
31
+ });
32
+ });
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Text } from "../../index.js";
4
+ import { createRenderer } from "../index.js";
5
+ import { useExtensionContext } from "../../hooks/useExtensionContext.js";
6
+ function MyComponent() {
7
+ const context = useExtensionContext();
8
+ return (_jsxs(_Fragment, { children: [_jsx(Text, { testId: "location-text", children: context.location }), _jsx(Text, { testId: "user-email", children: context.user.email }), _jsx(Text, { testId: "user-firstName", children: context.user.firstName }), _jsx(Text, { testId: "user-lastName", children: context.user.lastName }), _jsx(Text, { testId: "portal-id", children: context.portal.id }), _jsx(Text, { testId: "portal-timezone", children: context.portal.timezone }), 'crm' in context && (_jsxs(_Fragment, { children: [_jsx(Text, { testId: "crm-objectId", children: context.crm.objectId }), _jsx(Text, { testId: "crm-objectTypeId", children: context.crm.objectTypeId })] }))] }));
9
+ }
10
+ describe('mock useExtensionContext', () => {
11
+ it('should provide a CRM mock implementation', () => {
12
+ const { render, findByTestId } = createRenderer('crm.record.tab');
13
+ render(_jsx(MyComponent, {}));
14
+ expect(findByTestId(Text, 'location-text').text).toEqual('crm.record.tab');
15
+ expect(findByTestId(Text, 'user-email').text).toEqual('fake_email@example.com');
16
+ expect(findByTestId(Text, 'user-firstName').text).toEqual('fake_firstName');
17
+ expect(findByTestId(Text, 'user-lastName').text).toEqual('fake_lastName');
18
+ expect(findByTestId(Text, 'portal-id').text).toEqual('123');
19
+ expect(findByTestId(Text, 'portal-timezone').text).toEqual('America/New_York');
20
+ expect(findByTestId(Text, 'crm-objectId').text).toEqual('123');
21
+ expect(findByTestId(Text, 'crm-objectTypeId').text).toEqual('0-1');
22
+ });
23
+ it('should provide a generic mock implementation without CRM properties', () => {
24
+ const { render, findByTestId, maybeFindByTestId } = createRenderer('settings');
25
+ render(_jsx(MyComponent, {}));
26
+ expect(findByTestId(Text, 'location-text').text).toEqual('settings');
27
+ expect(findByTestId(Text, 'user-email').text).toEqual('fake_email@example.com');
28
+ expect(findByTestId(Text, 'user-firstName').text).toEqual('fake_firstName');
29
+ expect(findByTestId(Text, 'user-lastName').text).toEqual('fake_lastName');
30
+ expect(findByTestId(Text, 'portal-id').text).toEqual('123');
31
+ expect(findByTestId(Text, 'portal-timezone').text).toEqual('America/New_York');
32
+ // doesn't have the CRM properties
33
+ expect(maybeFindByTestId(Text, 'crm-objectId')).toBeNull();
34
+ expect(maybeFindByTestId(Text, 'crm-objectTypeId')).toBeNull();
35
+ });
36
+ it('should use the mutated context', () => {
37
+ const newName = 'Gracie';
38
+ const { render, findByTestId, mocks } = createRenderer('settings');
39
+ mocks.context.user.firstName = newName;
40
+ render(_jsx(MyComponent, {}));
41
+ // no longer has the default context value, it has the mutate context
42
+ expect(findByTestId(Text, 'user-firstName').text).toEqual(newName);
43
+ // other properties stay the same
44
+ expect(findByTestId(Text, 'location-text').text).toEqual('settings');
45
+ });
46
+ });
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Button, ButtonRow } from "../../../index.js";
3
+ import { Button, ButtonRow } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  describe('props', () => {
6
6
  it('should remove the children prop from the props object', () => {
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button } from "../../../index.js";
2
+ import { Button } from "../../index.js";
3
3
  import { createRenderer } from "../index.js";
4
4
  import { DuplicateTestIdError } from "../internal/errors.js";
5
5
  describe('testId', () => {
@@ -1,7 +1,7 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
3
  import { describe, expect, it } from 'vitest';
4
- import { Button } from "../../../index.js";
4
+ import { Button } from "../../index.js";
5
5
  import { createRenderer } from "../index.js";
6
6
  import { InvalidEventFunctionError, MissingEventFunctionError, } from "../internal/errors.js";
7
7
  describe('trigger()', () => {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { describe, expect, it } from 'vitest';
3
- import { Button, ButtonRow, Text } from "../../../index.js";
3
+ import { Button, ButtonRow, Text } from "../../index.js";
4
4
  import { createRenderer } from "../index.js";
5
5
  import { isRenderedElementNode, isRenderedFragmentNode, isRenderedRootNode, isRenderedTextNode, } from "../type-utils.js";
6
6
  import { RenderedNodeType } from "../types.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,7 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
3
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { Button } from "../../../index.js";
4
+ import { Button } from "../../index.js";
5
5
  import { createRenderer } from "../index.js";
6
6
  import { WaitForTimeoutError } from "../internal/errors.js";
7
7
  describe('waitFor()', () => {
@@ -3,7 +3,7 @@ import { createElementNode } from "./element.js";
3
3
  import { DuplicateTestIdError, InvalidFragmentPropArrayError, } from "./errors.js";
4
4
  import { createFragmentNode } from "./fragment.js";
5
5
  import { createTextNode } from "./text.js";
6
- import { __hubSpotComponentRegistry } from "../../../shared/remoteComponents.js";
6
+ import { __hubSpotComponentRegistry } from "../../shared/remoteComponents.js";
7
7
  import { isRenderedTextNode } from "../type-utils.js";
8
8
  import { EMPTY_RENDERED_CHILD_NODES } from "./constants.js";
9
9
  import { asRenderedParentNode } from "./type-utils-internal.js";
@@ -1,4 +1,4 @@
1
- import type { UnknownComponentProps } from '../../../shared/types/shared.ts';
1
+ import type { UnknownComponentProps } from '../../shared/types/shared.ts';
2
2
  import { RenderedElementNode } from '../types.ts';
3
3
  import type { RenderedDocumentInternal } from './types-internal.ts';
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { EXTENSION_POINT_LOCATIONS } from "../../../shared/types/extension-points.js";
1
+ import { EXTENSION_POINT_LOCATIONS } from "../../shared/types/extension-points.js";
2
2
  import { printNode } from "./print.js";
3
3
  import { asRenderedNode } from "./type-utils-internal.js";
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { UnknownComponentProps } from '../../../shared/types/shared.ts';
1
+ import { UnknownComponentProps } from '../../shared/types/shared.ts';
2
2
  import { ElementMatcher, RenderedElementNode } from '../types.ts';
3
3
  /**
4
4
  * Checks if the element matches the matcher.
@@ -1,6 +1,6 @@
1
1
  import { RendererSpies } from '../../types.ts';
2
2
  import { RendererMocksInternal } from '../types-internal.ts';
3
- import { ExtensionPointLocation } from '../../../../shared/types/extension-points.ts';
3
+ import { ExtensionPointLocation } from '../../../shared/types/extension-points.ts';
4
4
  /**
5
5
  * An object containing the mocks and spies.
6
6
  */
@@ -1,2 +1,2 @@
1
- import { ExtensionPointApi, type ExtensionPointLocation } from '../../../../shared/types/extension-points.ts';
1
+ import { ExtensionPointApi, type ExtensionPointLocation } from '../../../shared/types/extension-points.ts';
2
2
  export declare const createMockExtensionPointApi: (extensionPointLocation: ExtensionPointLocation) => ExtensionPointApi<ExtensionPointLocation>;
@@ -1,4 +1,4 @@
1
- import { ServerlessExecutionStatus, } from "../../../../shared/types/http-requests.js";
1
+ import { ServerlessExecutionStatus, } from "../../../shared/types/http-requests.js";
2
2
  const fakePrefix = 'fake_';
3
3
  const createMockServerlessFuncRunner = () => {
4
4
  return () => Promise.resolve({
@@ -0,0 +1,3 @@
1
+ import { RendererMockHooksInternal } from '../types-internal.ts';
2
+ import type { ExtensionPointLocation } from '../../../shared/types/extension-points.ts';
3
+ export declare const createMockHooks: <TExtensionPointLocation extends ExtensionPointLocation>() => RendererMockHooksInternal;
@@ -1,3 +1,4 @@
1
+ import { useMocksContext } from "../../../internal/hook-utils.js";
1
2
  /**
2
3
  * Creates a record of property names and their fake values.
3
4
  *
@@ -23,6 +24,8 @@ export const createMockHooks = () => {
23
24
  properties,
24
25
  error: null,
25
26
  isLoading: false,
27
+ isRefetching: false,
28
+ refetch: async () => { },
26
29
  };
27
30
  },
28
31
  useAssociations: (config) => {
@@ -44,6 +47,8 @@ export const createMockHooks = () => {
44
47
  ],
45
48
  error: null,
46
49
  isLoading: false,
50
+ isRefetching: false,
51
+ refetch: async () => { },
47
52
  pagination: {
48
53
  hasNextPage: false,
49
54
  hasPreviousPage: false,
@@ -55,5 +60,14 @@ export const createMockHooks = () => {
55
60
  },
56
61
  };
57
62
  },
63
+ useExtensionContext: () => {
64
+ const mocks = useMocksContext();
65
+ return mocks.context;
66
+ },
67
+ useExtensionActions: () => {
68
+ const mocks = useMocksContext();
69
+ return mocks
70
+ .actions;
71
+ },
58
72
  };
59
73
  };
@@ -1,4 +1,4 @@
1
- import { __hubSpotComponentRegistry } from "../../../shared/remoteComponents.js";
1
+ import { __hubSpotComponentRegistry } from "../../shared/remoteComponents.js";
2
2
  import { isRenderedElementNode, isRenderedFragmentNode, isRenderedRootNode, isRenderedTextNode, } from "../type-utils.js";
3
3
  const INDENT_STRING = ' ';
4
4
  const printTextNode = (node, indent, printContext) => {
@@ -1,4 +1,4 @@
1
- import type { HubSpotReactComponent, UnknownComponentProps } from '../../../shared/types/shared.ts';
1
+ import type { HubSpotReactComponent, UnknownComponentProps } from '../../shared/types/shared.ts';
2
2
  import type { ElementMatcher, RenderedElementNode } from '../types.ts';
3
3
  import type { RenderedDocumentInternal, RenderedParentNodeInternal } from './types-internal.ts';
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { __hubSpotComponentRegistry } from "../../../shared/remoteComponents.js";
1
+ import { __hubSpotComponentRegistry } from "../../shared/remoteComponents.js";
2
2
  import { isRenderedElementNode } from "../type-utils.js";
3
3
  import { ComponentMismatchedByTestIdError, ComponentNotFoundByTestIdError, ComponentNotFoundError, FindInvalidComponentError, InvalidComponentsError, } from "./errors.js";
4
4
  import { checkElementMatches } from "./match.js";