@atlassian/clientside-extensions-components 2.4.1 → 2.5.0-84fa90d-kwd5ix2w

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 (147) hide show
  1. package/dist/cjs/ExtensionPoint.js +4 -4
  2. package/dist/cjs/ExtensionPoint.js.map +1 -1
  3. package/dist/cjs/ExtensionPointInfo.js +8 -8
  4. package/dist/cjs/ExtensionPointInfo.js.map +1 -1
  5. package/dist/cjs/ExtensionsObservable.js +14 -12
  6. package/dist/cjs/ExtensionsObservable.js.map +1 -1
  7. package/dist/cjs/debug/useDebug.js +3 -3
  8. package/dist/cjs/debug/useDebug.js.map +1 -1
  9. package/dist/cjs/debug/useDiscovery.js +3 -3
  10. package/dist/cjs/debug/useDiscovery.js.map +1 -1
  11. package/dist/cjs/debug/useLogging.js +3 -3
  12. package/dist/cjs/debug/useLogging.js.map +1 -1
  13. package/dist/cjs/debug/useValidation.js +3 -3
  14. package/dist/cjs/debug/useValidation.js.map +1 -1
  15. package/dist/cjs/handlers/AsyncPanelHandler.js +10 -9
  16. package/dist/cjs/handlers/AsyncPanelHandler.js.map +1 -1
  17. package/dist/cjs/handlers/ButtonHandler.js +4 -3
  18. package/dist/cjs/handlers/ButtonHandler.js.map +1 -1
  19. package/dist/cjs/handlers/LinkHandler.js +4 -3
  20. package/dist/cjs/handlers/LinkHandler.js.map +1 -1
  21. package/dist/cjs/handlers/ModalHandler.js +16 -14
  22. package/dist/cjs/handlers/ModalHandler.js.map +1 -1
  23. package/dist/cjs/handlers/PanelHandler.js +6 -5
  24. package/dist/cjs/handlers/PanelHandler.js.map +1 -1
  25. package/dist/cjs/handlers/SectionHandler.js +3 -2
  26. package/dist/cjs/handlers/SectionHandler.js.map +1 -1
  27. package/dist/cjs/handlers/index.js +1 -0
  28. package/dist/cjs/handlers/index.js.map +1 -1
  29. package/dist/cjs/index.js +11 -10
  30. package/dist/cjs/index.js.map +1 -1
  31. package/dist/cjs/renderElementAsReact.js +3 -3
  32. package/dist/cjs/renderElementAsReact.js.map +1 -1
  33. package/dist/cjs/styled.js +13 -13
  34. package/dist/cjs/styled.js.map +1 -1
  35. package/dist/cjs/useExtensions.js +18 -14
  36. package/dist/cjs/useExtensions.js.map +1 -1
  37. package/dist/cjs/useWebPanelRenderer.js +4 -4
  38. package/dist/cjs/useWebPanelRenderer.js.map +1 -1
  39. package/dist/esm/ExtensionPointInfo.js.map +1 -1
  40. package/dist/esm/ExtensionsObservable.js.map +1 -1
  41. package/dist/esm/debug/types.js +1 -0
  42. package/dist/esm/handlers/types.js +1 -0
  43. package/dist/esm/renderElementAsReact.js +1 -1
  44. package/dist/esm/renderElementAsReact.js.map +1 -1
  45. package/dist/esm/useWebPanelRenderer.js.map +1 -1
  46. package/dist/types/ExtensionPointInfo.d.ts.map +1 -1
  47. package/dist/types/styled.d.ts +7 -7
  48. package/dist/types/styled.d.ts.map +1 -1
  49. package/lib/ExtensionPointInfo.tsx +1 -0
  50. package/lib/ExtensionsObservable.test.ts +2 -2
  51. package/package.json +12 -11
  52. package/dist/cjs/ExtensionPoint.test.js +0 -96
  53. package/dist/cjs/ExtensionPoint.test.js.map +0 -1
  54. package/dist/cjs/ExtensionPointInfo.test.js +0 -189
  55. package/dist/cjs/ExtensionPointInfo.test.js.map +0 -1
  56. package/dist/cjs/ExtensionsObservable.test.js +0 -349
  57. package/dist/cjs/ExtensionsObservable.test.js.map +0 -1
  58. package/dist/cjs/debug/useDebug.test.js +0 -49
  59. package/dist/cjs/debug/useDebug.test.js.map +0 -1
  60. package/dist/cjs/debug/useDiscovery.test.js +0 -49
  61. package/dist/cjs/debug/useDiscovery.test.js.map +0 -1
  62. package/dist/cjs/debug/useLogging.test.js +0 -49
  63. package/dist/cjs/debug/useLogging.test.js.map +0 -1
  64. package/dist/cjs/debug/useValidation.test.js +0 -49
  65. package/dist/cjs/debug/useValidation.test.js.map +0 -1
  66. package/dist/cjs/handlers/AsyncPanelHandler.test.js +0 -189
  67. package/dist/cjs/handlers/AsyncPanelHandler.test.js.map +0 -1
  68. package/dist/cjs/handlers/ButtonHandler.test.js +0 -40
  69. package/dist/cjs/handlers/ButtonHandler.test.js.map +0 -1
  70. package/dist/cjs/handlers/LinkHandler.test.js +0 -43
  71. package/dist/cjs/handlers/LinkHandler.test.js.map +0 -1
  72. package/dist/cjs/handlers/ModalHandler.test.js +0 -189
  73. package/dist/cjs/handlers/ModalHandler.test.js.map +0 -1
  74. package/dist/cjs/handlers/PanelHandler.test.js +0 -88
  75. package/dist/cjs/handlers/PanelHandler.test.js.map +0 -1
  76. package/dist/cjs/handlers/SectionHandler.test.js +0 -17
  77. package/dist/cjs/handlers/SectionHandler.test.js.map +0 -1
  78. package/dist/cjs/index.test.js +0 -7
  79. package/dist/cjs/index.test.js.map +0 -1
  80. package/dist/cjs/renderElementAsReact.test.js +0 -54
  81. package/dist/cjs/renderElementAsReact.test.js.map +0 -1
  82. package/dist/cjs/useExtensions.test.js +0 -647
  83. package/dist/cjs/useExtensions.test.js.map +0 -1
  84. package/dist/esm/ExtensionPoint.test.js +0 -93
  85. package/dist/esm/ExtensionPoint.test.js.map +0 -1
  86. package/dist/esm/ExtensionPointInfo.test.js +0 -186
  87. package/dist/esm/ExtensionPointInfo.test.js.map +0 -1
  88. package/dist/esm/ExtensionsObservable.test.js +0 -346
  89. package/dist/esm/ExtensionsObservable.test.js.map +0 -1
  90. package/dist/esm/debug/useDebug.test.js +0 -46
  91. package/dist/esm/debug/useDebug.test.js.map +0 -1
  92. package/dist/esm/debug/useDiscovery.test.js +0 -46
  93. package/dist/esm/debug/useDiscovery.test.js.map +0 -1
  94. package/dist/esm/debug/useLogging.test.js +0 -46
  95. package/dist/esm/debug/useLogging.test.js.map +0 -1
  96. package/dist/esm/debug/useValidation.test.js +0 -46
  97. package/dist/esm/debug/useValidation.test.js.map +0 -1
  98. package/dist/esm/handlers/AsyncPanelHandler.test.js +0 -186
  99. package/dist/esm/handlers/AsyncPanelHandler.test.js.map +0 -1
  100. package/dist/esm/handlers/ButtonHandler.test.js +0 -37
  101. package/dist/esm/handlers/ButtonHandler.test.js.map +0 -1
  102. package/dist/esm/handlers/LinkHandler.test.js +0 -40
  103. package/dist/esm/handlers/LinkHandler.test.js.map +0 -1
  104. package/dist/esm/handlers/ModalHandler.test.js +0 -186
  105. package/dist/esm/handlers/ModalHandler.test.js.map +0 -1
  106. package/dist/esm/handlers/PanelHandler.test.js +0 -85
  107. package/dist/esm/handlers/PanelHandler.test.js.map +0 -1
  108. package/dist/esm/handlers/SectionHandler.test.js +0 -14
  109. package/dist/esm/handlers/SectionHandler.test.js.map +0 -1
  110. package/dist/esm/index.test.js +0 -7
  111. package/dist/esm/index.test.js.map +0 -1
  112. package/dist/esm/renderElementAsReact.test.js +0 -51
  113. package/dist/esm/renderElementAsReact.test.js.map +0 -1
  114. package/dist/esm/useExtensions.test.js +0 -644
  115. package/dist/esm/useExtensions.test.js.map +0 -1
  116. package/dist/types/ExtensionPoint.test.d.ts +0 -2
  117. package/dist/types/ExtensionPoint.test.d.ts.map +0 -1
  118. package/dist/types/ExtensionPointInfo.test.d.ts +0 -2
  119. package/dist/types/ExtensionPointInfo.test.d.ts.map +0 -1
  120. package/dist/types/ExtensionsObservable.test.d.ts +0 -2
  121. package/dist/types/ExtensionsObservable.test.d.ts.map +0 -1
  122. package/dist/types/debug/useDebug.test.d.ts +0 -2
  123. package/dist/types/debug/useDebug.test.d.ts.map +0 -1
  124. package/dist/types/debug/useDiscovery.test.d.ts +0 -2
  125. package/dist/types/debug/useDiscovery.test.d.ts.map +0 -1
  126. package/dist/types/debug/useLogging.test.d.ts +0 -2
  127. package/dist/types/debug/useLogging.test.d.ts.map +0 -1
  128. package/dist/types/debug/useValidation.test.d.ts +0 -2
  129. package/dist/types/debug/useValidation.test.d.ts.map +0 -1
  130. package/dist/types/handlers/AsyncPanelHandler.test.d.ts +0 -2
  131. package/dist/types/handlers/AsyncPanelHandler.test.d.ts.map +0 -1
  132. package/dist/types/handlers/ButtonHandler.test.d.ts +0 -2
  133. package/dist/types/handlers/ButtonHandler.test.d.ts.map +0 -1
  134. package/dist/types/handlers/LinkHandler.test.d.ts +0 -2
  135. package/dist/types/handlers/LinkHandler.test.d.ts.map +0 -1
  136. package/dist/types/handlers/ModalHandler.test.d.ts +0 -2
  137. package/dist/types/handlers/ModalHandler.test.d.ts.map +0 -1
  138. package/dist/types/handlers/PanelHandler.test.d.ts +0 -2
  139. package/dist/types/handlers/PanelHandler.test.d.ts.map +0 -1
  140. package/dist/types/handlers/SectionHandler.test.d.ts +0 -2
  141. package/dist/types/handlers/SectionHandler.test.d.ts.map +0 -1
  142. package/dist/types/index.test.d.ts +0 -1
  143. package/dist/types/index.test.d.ts.map +0 -1
  144. package/dist/types/renderElementAsReact.test.d.ts +0 -2
  145. package/dist/types/renderElementAsReact.test.d.ts.map +0 -1
  146. package/dist/types/useExtensions.test.d.ts +0 -2
  147. package/dist/types/useExtensions.test.d.ts.map +0 -1
@@ -1,647 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const utils_1 = require("ts-jest/utils");
5
- const react_hooks_1 = require("@testing-library/react-hooks");
6
- const clientside_extensions_registry_1 = tslib_1.__importDefault(require("@atlassian/clientside-extensions-registry"));
7
- const debug = tslib_1.__importStar(require("@atlassian/clientside-extensions-debug"));
8
- const clientside_extensions_debug_1 = require("@atlassian/clientside-extensions-debug");
9
- const clientside_extensions_schema_1 = require("@atlassian/clientside-extensions-schema");
10
- const useExtensions_1 = require("./useExtensions");
11
- jest.mock('@atlassian/clientside-extensions-registry');
12
- debug.setLoggingEnabled(true);
13
- debug.setDebugEnabled(true);
14
- // avoid spamming the console with error/warn messages
15
- // eslint-disable-next-line no-underscore-dangle
16
- debug._deregisterDefaultLogger();
17
- function applyAttributesProvider(descriptor) {
18
- const { attributesProvider, ...restDescriptor } = descriptor;
19
- return {
20
- ...restDescriptor,
21
- attributes: {
22
- ...restDescriptor.attributes,
23
- ...(attributesProvider ? attributesProvider({ updateAttributes: () => { }, onCleanup: () => { } }, null) : {}),
24
- },
25
- };
26
- }
27
- function createMockLocationObserver() {
28
- let locationObserver;
29
- utils_1.mocked(clientside_extensions_registry_1.default.getLocation).mockClear();
30
- utils_1.mocked(clientside_extensions_registry_1.default.getLocation).mockImplementation(() => ({
31
- subscribe: (observer) => {
32
- locationObserver = observer;
33
- return {
34
- unsubscribe: () => { },
35
- };
36
- },
37
- }));
38
- return (payload) => locationObserver(payload);
39
- }
40
- const attributeValidator = () => ({ warnings: [], errors: [] });
41
- const contextValidator = () => ({ warnings: [], errors: [] });
42
- const options = {
43
- attributeValidator,
44
- contextValidator,
45
- };
46
- const supportedExtension = {
47
- key: 'fake-1',
48
- location: 'fake-location',
49
- weight: 10,
50
- attributes: { label: 'a fake label' },
51
- attributesProvider: () => ({ type: 'button' }),
52
- };
53
- const unsupportedExtension = {
54
- key: 'fake-2',
55
- location: 'fake-location',
56
- weight: 10,
57
- attributes: { label: 'a fake label' },
58
- };
59
- const wrongTypeExtension = {
60
- key: 'fake-3',
61
- location: 'fake-location',
62
- weight: 10,
63
- attributes: { label: 'a fake label' },
64
- attributesProvider: () => ({ type: 'oopps' }),
65
- };
66
- const brokenExtension = {
67
- key: 'fake-4',
68
- location: 'fake-location',
69
- weight: 10,
70
- attributes: { label: 'a fake label' },
71
- attributesProvider: () => {
72
- throw new Error('fake error');
73
- },
74
- };
75
- const brokenOnActionExtension = {
76
- key: 'fake-button',
77
- location: 'fake-location',
78
- weight: 10,
79
- attributes: { label: 'a fake label' },
80
- attributesProvider: () => ({
81
- type: 'button',
82
- onAction: () => {
83
- throw new Error('error from onAction');
84
- },
85
- }),
86
- };
87
- const toEvaluatedDecorator = (descriptor) => {
88
- const { attributesProvider, attributes, ...rest } = descriptor;
89
- const ensureAP = attributesProvider !== null && attributesProvider !== void 0 ? attributesProvider : (() => ({}));
90
- const evaluatedAttributes = { ...attributes, ...ensureAP({}, null) };
91
- return {
92
- ...rest,
93
- attributes: evaluatedAttributes,
94
- };
95
- };
96
- describe('useExtensionsLoadingState hook', () => {
97
- let locationObserver;
98
- beforeEach(() => {
99
- locationObserver = createMockLocationObserver();
100
- });
101
- it('should notify when the loading state changes', () => {
102
- let loading;
103
- const { result } = react_hooks_1.renderHook(() => useExtensions_1.useExtensionsLoadingState('fake-location', null, options));
104
- loading = result.current;
105
- expect(loading).toBe(true);
106
- react_hooks_1.act(() => {
107
- locationObserver({ descriptors: [], loadingState: false });
108
- });
109
- loading = result.current;
110
- expect(loading).toBe(false);
111
- });
112
- });
113
- describe('useExtensions hook', () => {
114
- let locationObserver;
115
- beforeEach(() => {
116
- locationObserver = createMockLocationObserver();
117
- });
118
- it('should return a list with only the supported extensions', () => {
119
- const localValidate = (descriptor) => {
120
- return JSON.stringify(descriptor) === '{"label":"a fake label","type":"button"}'
121
- ? { errors: [], warnings: [] }
122
- : {
123
- errors: [
124
- {
125
- severity: clientside_extensions_schema_1.ErrorLevels.ERROR,
126
- error: 'asd',
127
- },
128
- ],
129
- warnings: [],
130
- };
131
- };
132
- const { result } = react_hooks_1.renderHook(() => useExtensions_1.useExtensions('fake-location', null, { ...options, attributeValidator: localValidate }));
133
- react_hooks_1.act(() => {
134
- locationObserver({ descriptors: [supportedExtension, unsupportedExtension, wrongTypeExtension], loadingState: false });
135
- });
136
- const extensions = result.current;
137
- expect(extensions).toEqual([
138
- {
139
- ...applyAttributesProvider(supportedExtension),
140
- },
141
- ]);
142
- });
143
- });
144
- describe('useExtensionsUnsupported hook', () => {
145
- let locationObserver;
146
- beforeEach(() => {
147
- locationObserver = createMockLocationObserver();
148
- });
149
- it('should return a list with only the unsupported extensions', () => {
150
- const localValidate = (descriptor) => {
151
- const { type } = descriptor;
152
- return type === 'button'
153
- ? { errors: [], warnings: [] }
154
- : {
155
- errors: [
156
- {
157
- severity: clientside_extensions_schema_1.ErrorLevels.ERROR,
158
- error: 'asd',
159
- },
160
- ],
161
- warnings: [],
162
- };
163
- };
164
- const { result } = react_hooks_1.renderHook(() => useExtensions_1.useExtensionsUnsupported('fake-location', null, { ...options, attributeValidator: localValidate }));
165
- react_hooks_1.act(() => {
166
- locationObserver({ descriptors: [supportedExtension, unsupportedExtension, wrongTypeExtension], loadingState: false });
167
- });
168
- const extensions = result.current;
169
- expect(extensions).toEqual([toEvaluatedDecorator(unsupportedExtension), toEvaluatedDecorator(wrongTypeExtension)]);
170
- });
171
- });
172
- describe('useExtensionsAll hook', () => {
173
- const loggerLogs = [];
174
- const onDebugSpy = jest.fn().mockImplementation((payload) => {
175
- loggerLogs.push(payload);
176
- });
177
- debug.observeLogger(onDebugSpy);
178
- let locationObserver;
179
- beforeEach(() => {
180
- locationObserver = createMockLocationObserver();
181
- });
182
- afterEach(() => {
183
- loggerLogs.length = 0;
184
- onDebugSpy.mockClear();
185
- });
186
- it('should return an empty array if no extensions are registered for an extension point', () => {
187
- const { result } = react_hooks_1.renderHook(() => useExtensions_1.useExtensionsAll('fake-location', null, options));
188
- react_hooks_1.act(() => {
189
- locationObserver({ descriptors: [], loadingState: false });
190
- });
191
- const [extensions, unsupportedExtensions, loading] = result.current;
192
- expect(extensions).toEqual([]);
193
- expect(unsupportedExtensions).toEqual([]);
194
- expect(loading).toBe(false);
195
- });
196
- it('should only return extensions of a supported type and log validation type error', () => {
197
- const localValidate = (descriptor) => {
198
- const { type } = descriptor;
199
- return type !== 'oopps'
200
- ? { warnings: [], errors: [] }
201
- : {
202
- errors: [
203
- {
204
- severity: clientside_extensions_schema_1.ErrorLevels.ERROR,
205
- error: 'asd',
206
- },
207
- ],
208
- warnings: [],
209
- };
210
- };
211
- const { result } = react_hooks_1.renderHook(() => useExtensions_1.useExtensionsAll('fake-location', null, { ...options, attributeValidator: localValidate }));
212
- react_hooks_1.act(() => {
213
- locationObserver({ descriptors: [supportedExtension, wrongTypeExtension], loadingState: false });
214
- });
215
- const [extensions] = result.current;
216
- expect(extensions).toEqual([{ ...applyAttributesProvider(supportedExtension) }]);
217
- expect(loggerLogs).toContainEqual(expect.objectContaining({
218
- level: clientside_extensions_debug_1.LogLevel.error,
219
- message: expect.stringContaining('Schema validation for extension "fake-3" returned errors'),
220
- }));
221
- });
222
- it('should update the attributes when using the ”updateAttributes” function', async () => {
223
- const changeAttributesExtension = {
224
- key: 'fake-1',
225
- location: 'fake-location',
226
- weight: 10,
227
- attributes: { label: 'a fake label' },
228
- attributesProvider: ({ updateAttributes }) => ({
229
- type: 'button',
230
- onAction: () => updateAttributes({ label: 'a new fake label' }),
231
- }),
232
- };
233
- const { result, waitForNextUpdate } = react_hooks_1.renderHook(() => useExtensions_1.useExtensionsAll('fake-location', null, options));
234
- react_hooks_1.act(() => {
235
- locationObserver({ descriptors: [changeAttributesExtension], loadingState: false });
236
- });
237
- react_hooks_1.act(() => {
238
- const [extensions] = result.current;
239
- const [testExtension] = extensions;
240
- testExtension.attributes.onAction();
241
- });
242
- await waitForNextUpdate();
243
- const [extensionsUpdated] = result.current;
244
- const [testExtensionChanged] = extensionsUpdated;
245
- expect(testExtensionChanged.attributes.label).toBe('a new fake label');
246
- });
247
- it('should catch errors when calling update attributes API', () => {
248
- const brokenUpdateAttributesExtension = {
249
- key: 'fake-1',
250
- location: 'fake-location',
251
- weight: 10,
252
- attributes: { label: 'a fake label' },
253
- attributesProvider: ({ updateAttributes }) => ({
254
- type: 'button',
255
- onAction: () => updateAttributes(() => {
256
- throw new Error('update attributes error');
257
- }),
258
- }),
259
- };
260
- const { result } = react_hooks_1.renderHook(() => useExtensions_1.useExtensionsAll('fake-location', null, options));
261
- react_hooks_1.act(() => {
262
- locationObserver({ descriptors: [brokenUpdateAttributesExtension], loadingState: false });
263
- });
264
- expect(loggerLogs).not.toContainEqual(expect.objectContaining({
265
- level: clientside_extensions_debug_1.LogLevel.error,
266
- }));
267
- react_hooks_1.act(() => {
268
- const [extensions] = result.current;
269
- const [testExtension] = extensions;
270
- testExtension.attributes.onAction();
271
- });
272
- expect(loggerLogs).toContainEqual(expect.objectContaining({
273
- level: clientside_extensions_debug_1.LogLevel.error,
274
- message: expect.stringContaining('Updating attributes for extension fake-1 failed'),
275
- }));
276
- expect(result.error).toBeFalsy();
277
- });
278
- it('should add new attributes when using `updateAttributes` function', async () => {
279
- let localExtensionApi;
280
- const extension = {
281
- key: 'fake-1',
282
- location: 'fake-location',
283
- weight: 10,
284
- attributes: {},
285
- attributesProvider: (extensionApi) => {
286
- localExtensionApi = extensionApi;
287
- return {
288
- type: 'button',
289
- };
290
- },
291
- };
292
- const { result, waitForNextUpdate } = react_hooks_1.renderHook(() => useExtensions_1.useExtensions('fake-location', null, options));
293
- // First render
294
- react_hooks_1.act(() => {
295
- locationObserver({ descriptors: [extension], loadingState: false });
296
- });
297
- const [extensionFirstRender] = result.current;
298
- expect(extensionFirstRender.attributes).not.toHaveProperty('beforeIcon');
299
- // Add new attributes
300
- react_hooks_1.act(() => localExtensionApi.updateAttributes({
301
- beforeIcon: 'my-icon',
302
- }));
303
- await waitForNextUpdate();
304
- const [extensionSecondRender] = result.current;
305
- expect(extensionSecondRender.attributes).toHaveProperty('beforeIcon', 'my-icon');
306
- });
307
- it('should extend the existing attributes when using `updateAttributes` function with a functional update', async () => {
308
- let localExtensionApi;
309
- const extension = {
310
- key: 'fake-1',
311
- location: 'fake-location',
312
- weight: 10,
313
- attributes: {},
314
- attributesProvider(extensionApi) {
315
- localExtensionApi = extensionApi;
316
- return {
317
- type: 'button',
318
- label: 'foo',
319
- counter: 0,
320
- };
321
- },
322
- };
323
- const { result, waitForNextUpdate } = react_hooks_1.renderHook(() => useExtensions_1.useExtensions('fake-location', null, options));
324
- // First render
325
- react_hooks_1.act(() => {
326
- locationObserver({ descriptors: [extension], loadingState: false });
327
- });
328
- expect(result.current[0].attributes).toEqual({
329
- type: 'button',
330
- label: 'foo',
331
- counter: 0,
332
- });
333
- // First update
334
- react_hooks_1.act(() => localExtensionApi.updateAttributes({
335
- label: 'bar',
336
- counter: 1,
337
- }));
338
- await waitForNextUpdate();
339
- expect(result.current[0].attributes).toEqual({
340
- type: 'button',
341
- label: 'bar',
342
- counter: 1,
343
- });
344
- // Second update with manual attributes merge
345
- react_hooks_1.act(() => localExtensionApi.updateAttributes((prevAttributes) => {
346
- return {
347
- ...prevAttributes,
348
- label: 'baz',
349
- counter: prevAttributes.counter ? prevAttributes.counter + 1 : 1,
350
- };
351
- }));
352
- await waitForNextUpdate();
353
- expect(result.current[0].attributes).toEqual({
354
- type: 'button',
355
- label: 'baz',
356
- counter: 2,
357
- });
358
- // Third update with auto-merge
359
- react_hooks_1.act(() => localExtensionApi.updateAttributes((prevAttributes) => ({
360
- counter: prevAttributes.counter ? prevAttributes.counter * 2 : 2,
361
- })));
362
- await waitForNextUpdate();
363
- expect(result.current[0].attributes).toEqual({
364
- type: 'button',
365
- label: 'baz',
366
- counter: 4,
367
- });
368
- });
369
- it('should provide a clean up API that gets called when the extension point updates', async () => {
370
- const cleanupSpy = jest.fn();
371
- const cleanupExtension = {
372
- key: 'fake-1',
373
- location: 'fake-location',
374
- weight: 10,
375
- attributes: { label: 'a fake label' },
376
- attributesProvider: ({ onCleanup }) => {
377
- onCleanup(cleanupSpy);
378
- return {
379
- type: 'button',
380
- };
381
- },
382
- };
383
- // eslint-disable-next-line @typescript-eslint/no-shadow
384
- const { rerender } = react_hooks_1.renderHook(({ name, context, options }) => useExtensions_1.useExtensionsAll(name, context, options), {
385
- initialProps: {
386
- name: 'fake-location',
387
- context: {
388
- value: 1,
389
- },
390
- options,
391
- },
392
- });
393
- react_hooks_1.act(() => {
394
- locationObserver({ descriptors: [cleanupExtension], loadingState: false });
395
- });
396
- rerender({
397
- name: 'fake-location',
398
- context: {
399
- value: 3,
400
- },
401
- options,
402
- });
403
- expect(cleanupSpy).toBeCalledTimes(1);
404
- // TODO: unmounting the hook should call the cleanup callbacks, but it isn't.
405
- // unmount();
406
- // expect(cleanupSpy).toBeCalledTimes(2);
407
- });
408
- it('should catch errors when calling onCleanup API', () => {
409
- const cleanupSpy = jest.fn(() => {
410
- throw new Error('clean up error');
411
- });
412
- const cleanupExtension = {
413
- key: 'fake-1',
414
- location: 'fake-location',
415
- weight: 10,
416
- attributes: { label: 'a fake label' },
417
- attributesProvider: ({ onCleanup }) => {
418
- onCleanup(cleanupSpy);
419
- return {
420
- type: 'button',
421
- };
422
- },
423
- };
424
- // eslint-disable-next-line @typescript-eslint/no-shadow
425
- const { rerender } = react_hooks_1.renderHook(({ name, context, options }) => useExtensions_1.useExtensionsAll(name, context, options), {
426
- initialProps: {
427
- name: 'fake-location',
428
- context: {
429
- value: 1,
430
- },
431
- options,
432
- },
433
- });
434
- react_hooks_1.act(() => {
435
- locationObserver({ descriptors: [cleanupExtension], loadingState: false });
436
- });
437
- rerender({
438
- name: 'fake-location',
439
- context: {
440
- value: 3,
441
- },
442
- options,
443
- });
444
- expect(cleanupSpy).toBeCalledTimes(1);
445
- expect(loggerLogs).toContainEqual(expect.objectContaining({
446
- level: clientside_extensions_debug_1.LogLevel.error,
447
- message: expect.stringContaining('Failed to execute cleanup callback'),
448
- }));
449
- });
450
- it('should catch error when calling the attributes provider', () => {
451
- const { result } = react_hooks_1.renderHook(() => useExtensions_1.useExtensionsAll('fake-location', null, options));
452
- react_hooks_1.act(() => {
453
- locationObserver({ descriptors: [supportedExtension, brokenExtension], loadingState: false });
454
- });
455
- const [extensions] = result.current;
456
- expect(extensions).toEqual([{ ...applyAttributesProvider(supportedExtension) }]);
457
- expect(loggerLogs).toContainEqual(expect.objectContaining({
458
- level: clientside_extensions_debug_1.LogLevel.error,
459
- message: expect.stringContaining('Calling the attributes provider for extension fake-4 failed'),
460
- }));
461
- });
462
- it('should safe guard onAction attributes to prevent them from breaking the app when executed', () => {
463
- const { result } = react_hooks_1.renderHook(() => useExtensions_1.useExtensionsAll('fake-location', null, options));
464
- react_hooks_1.act(() => {
465
- locationObserver({ descriptors: [brokenOnActionExtension], loadingState: false });
466
- });
467
- const [extensions] = result.current;
468
- const [buttonExtension] = extensions;
469
- expect(buttonExtension.attributes.onAction).not.toThrow();
470
- });
471
- it('should throw an error if no context schema is provided when providing context', () => {
472
- const { result } = react_hooks_1.renderHook(() => useExtensions_1.useExtensionsAll('fake-location', { info: 'test-info' }, { attributeValidator }));
473
- expect(result.error).toEqual(Error('No context validator specified for extension point "fake-location"'));
474
- });
475
- it('should call the attributes provider only once when passed context did not changed', () => {
476
- const stableContext = {
477
- foo: 'bar',
478
- };
479
- const attributesExtension = {
480
- key: 'fake-1',
481
- location: 'fake-location',
482
- weight: 10,
483
- attributes: {
484
- type: 'button',
485
- },
486
- attributesProvider: (_, context) => ({
487
- context,
488
- }),
489
- };
490
- const { result, rerender } = react_hooks_1.renderHook(({ context }) => useExtensions_1.useExtensionsAll('fake-location', context, options));
491
- // First call
492
- rerender({
493
- context: stableContext,
494
- });
495
- react_hooks_1.act(() => {
496
- locationObserver({ descriptors: [attributesExtension], loadingState: false });
497
- });
498
- const [supportedDescriptorsFirstUpdate] = result.current;
499
- const [{ attributes: attributesFirstUpdate }] = supportedDescriptorsFirstUpdate;
500
- expect(attributesFirstUpdate.context).toBe(stableContext);
501
- // Second call
502
- rerender({
503
- context: stableContext,
504
- });
505
- react_hooks_1.act(() => {
506
- locationObserver({ descriptors: [attributesExtension], loadingState: false });
507
- });
508
- const [supportedDescriptorsSecondUpdate] = result.current;
509
- const [{ attributes: attributesSecondUpdate }] = supportedDescriptorsSecondUpdate;
510
- expect(attributesSecondUpdate.context).toBe(stableContext);
511
- expect(utils_1.mocked(clientside_extensions_registry_1.default.getLocation)).toHaveBeenCalledTimes(1);
512
- });
513
- it('should call the attributes provider twice when passed context did changed', () => {
514
- const firstContext = {
515
- foo: 'bar',
516
- };
517
- const secondContext = {
518
- biz: 'baz',
519
- };
520
- const attributesExtension = {
521
- key: 'fake-1',
522
- location: 'fake-location',
523
- weight: 10,
524
- attributes: {
525
- type: 'button',
526
- },
527
- attributesProvider: (_, context) => ({
528
- context,
529
- }),
530
- };
531
- const { result, rerender } = react_hooks_1.renderHook(({ context }) => useExtensions_1.useExtensionsAll('fake-location', context, options));
532
- // First update
533
- rerender({
534
- context: firstContext,
535
- });
536
- react_hooks_1.act(() => {
537
- locationObserver({ descriptors: [attributesExtension], loadingState: false });
538
- });
539
- const [supportedDescriptorsFirstUpdate] = result.current;
540
- const [{ attributes: attributesFirstUpdate }] = supportedDescriptorsFirstUpdate;
541
- expect(attributesFirstUpdate.context).toBe(firstContext);
542
- // Second update
543
- rerender({
544
- context: secondContext,
545
- });
546
- react_hooks_1.act(() => {
547
- locationObserver({ descriptors: [attributesExtension], loadingState: false });
548
- });
549
- const [supportedDescriptorsSecondUpdate] = result.current;
550
- const [{ attributes: attributesSecondUpdate }] = supportedDescriptorsSecondUpdate;
551
- expect(attributesSecondUpdate.context).toBe(secondContext);
552
- expect(utils_1.mocked(clientside_extensions_registry_1.default.getLocation)).toHaveBeenCalledTimes(2);
553
- });
554
- it('should log an error when attributes provider did return a non-supported value', () => {
555
- const { result } = react_hooks_1.renderHook(() => useExtensions_1.useExtensionsAll('fake-location', null, options));
556
- const firstExtension = {
557
- key: 'first',
558
- location: 'fake-location',
559
- weight: 0,
560
- attributes: {},
561
- // @ts-expect-error - Ignore the type since we don't know what extension developer might return in the runtime
562
- attributesProvider() {
563
- return null;
564
- },
565
- };
566
- const secondExtension = {
567
- key: 'second',
568
- location: 'fake-location',
569
- weight: 0,
570
- attributes: {},
571
- // @ts-expect-error - Ignore the type since we don't know what extension developer might return in the runtime
572
- attributesProvider() {
573
- return false;
574
- },
575
- };
576
- const thirdExtension = {
577
- key: 'third',
578
- location: 'fake-location',
579
- weight: 0,
580
- attributes: {},
581
- // @ts-expect-error - Ignore the type since we don't know what extension developer might return in the runtime
582
- attributesProvider() {
583
- return -Infinity;
584
- },
585
- };
586
- const fourthExtension = {
587
- key: 'fourth',
588
- location: 'fake-location',
589
- weight: 0,
590
- attributes: {},
591
- // @ts-expect-error - Ignore the type since we don't know what extension developer might return in the runtime
592
- attributesProvider() {
593
- return () => { };
594
- },
595
- };
596
- const fifthExtension = {
597
- key: 'fifth',
598
- location: 'fake-location',
599
- weight: 0,
600
- attributes: {},
601
- // @ts-expect-error - Ignore the type since we don't know what extension developer might return in the runtime
602
- attributesProvider() {
603
- return [];
604
- },
605
- };
606
- const sixthExtension = {
607
- key: 'sixth',
608
- location: 'fake-location',
609
- weight: 0,
610
- attributes: {},
611
- // @ts-expect-error - Ignore the type since we don't know what extension developer might return in the runtime
612
- attributesProvider() {
613
- return '';
614
- },
615
- };
616
- const seventhExtension = {
617
- key: 'seventh',
618
- location: 'fake-location',
619
- weight: 0,
620
- attributes: {},
621
- // @ts-expect-error - Ignore the type since we don't know what extension developer might return in the runtime
622
- attributesProvider() {
623
- return undefined;
624
- },
625
- };
626
- const descriptors = [
627
- firstExtension,
628
- secondExtension,
629
- thirdExtension,
630
- fourthExtension,
631
- fifthExtension,
632
- sixthExtension,
633
- seventhExtension,
634
- ];
635
- react_hooks_1.act(() => {
636
- locationObserver({
637
- descriptors,
638
- loadingState: false,
639
- });
640
- });
641
- const [extensions] = result.current;
642
- expect(extensions).toHaveLength(0);
643
- const errors = loggerLogs.filter((log) => log.level === clientside_extensions_debug_1.LogLevel.error);
644
- expect(errors).toHaveLength(7);
645
- });
646
- });
647
- //# sourceMappingURL=useExtensions.test.js.map