@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.
- package/dist/cjs/ExtensionPoint.js +4 -4
- package/dist/cjs/ExtensionPoint.js.map +1 -1
- package/dist/cjs/ExtensionPointInfo.js +8 -8
- package/dist/cjs/ExtensionPointInfo.js.map +1 -1
- package/dist/cjs/ExtensionsObservable.js +14 -12
- package/dist/cjs/ExtensionsObservable.js.map +1 -1
- package/dist/cjs/debug/useDebug.js +3 -3
- package/dist/cjs/debug/useDebug.js.map +1 -1
- package/dist/cjs/debug/useDiscovery.js +3 -3
- package/dist/cjs/debug/useDiscovery.js.map +1 -1
- package/dist/cjs/debug/useLogging.js +3 -3
- package/dist/cjs/debug/useLogging.js.map +1 -1
- package/dist/cjs/debug/useValidation.js +3 -3
- package/dist/cjs/debug/useValidation.js.map +1 -1
- package/dist/cjs/handlers/AsyncPanelHandler.js +10 -9
- package/dist/cjs/handlers/AsyncPanelHandler.js.map +1 -1
- package/dist/cjs/handlers/ButtonHandler.js +4 -3
- package/dist/cjs/handlers/ButtonHandler.js.map +1 -1
- package/dist/cjs/handlers/LinkHandler.js +4 -3
- package/dist/cjs/handlers/LinkHandler.js.map +1 -1
- package/dist/cjs/handlers/ModalHandler.js +16 -14
- package/dist/cjs/handlers/ModalHandler.js.map +1 -1
- package/dist/cjs/handlers/PanelHandler.js +6 -5
- package/dist/cjs/handlers/PanelHandler.js.map +1 -1
- package/dist/cjs/handlers/SectionHandler.js +3 -2
- package/dist/cjs/handlers/SectionHandler.js.map +1 -1
- package/dist/cjs/handlers/index.js +1 -0
- package/dist/cjs/handlers/index.js.map +1 -1
- package/dist/cjs/index.js +11 -10
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/renderElementAsReact.js +3 -3
- package/dist/cjs/renderElementAsReact.js.map +1 -1
- package/dist/cjs/styled.js +13 -13
- package/dist/cjs/styled.js.map +1 -1
- package/dist/cjs/useExtensions.js +18 -14
- package/dist/cjs/useExtensions.js.map +1 -1
- package/dist/cjs/useWebPanelRenderer.js +4 -4
- package/dist/cjs/useWebPanelRenderer.js.map +1 -1
- package/dist/esm/ExtensionPointInfo.js.map +1 -1
- package/dist/esm/ExtensionsObservable.js.map +1 -1
- package/dist/esm/debug/types.js +1 -0
- package/dist/esm/handlers/types.js +1 -0
- package/dist/esm/renderElementAsReact.js +1 -1
- package/dist/esm/renderElementAsReact.js.map +1 -1
- package/dist/esm/useWebPanelRenderer.js.map +1 -1
- package/dist/types/ExtensionPointInfo.d.ts.map +1 -1
- package/dist/types/styled.d.ts +7 -7
- package/dist/types/styled.d.ts.map +1 -1
- package/lib/ExtensionPointInfo.tsx +1 -0
- package/lib/ExtensionsObservable.test.ts +2 -2
- package/package.json +12 -11
- package/dist/cjs/ExtensionPoint.test.js +0 -96
- package/dist/cjs/ExtensionPoint.test.js.map +0 -1
- package/dist/cjs/ExtensionPointInfo.test.js +0 -189
- package/dist/cjs/ExtensionPointInfo.test.js.map +0 -1
- package/dist/cjs/ExtensionsObservable.test.js +0 -349
- package/dist/cjs/ExtensionsObservable.test.js.map +0 -1
- package/dist/cjs/debug/useDebug.test.js +0 -49
- package/dist/cjs/debug/useDebug.test.js.map +0 -1
- package/dist/cjs/debug/useDiscovery.test.js +0 -49
- package/dist/cjs/debug/useDiscovery.test.js.map +0 -1
- package/dist/cjs/debug/useLogging.test.js +0 -49
- package/dist/cjs/debug/useLogging.test.js.map +0 -1
- package/dist/cjs/debug/useValidation.test.js +0 -49
- package/dist/cjs/debug/useValidation.test.js.map +0 -1
- package/dist/cjs/handlers/AsyncPanelHandler.test.js +0 -189
- package/dist/cjs/handlers/AsyncPanelHandler.test.js.map +0 -1
- package/dist/cjs/handlers/ButtonHandler.test.js +0 -40
- package/dist/cjs/handlers/ButtonHandler.test.js.map +0 -1
- package/dist/cjs/handlers/LinkHandler.test.js +0 -43
- package/dist/cjs/handlers/LinkHandler.test.js.map +0 -1
- package/dist/cjs/handlers/ModalHandler.test.js +0 -189
- package/dist/cjs/handlers/ModalHandler.test.js.map +0 -1
- package/dist/cjs/handlers/PanelHandler.test.js +0 -88
- package/dist/cjs/handlers/PanelHandler.test.js.map +0 -1
- package/dist/cjs/handlers/SectionHandler.test.js +0 -17
- package/dist/cjs/handlers/SectionHandler.test.js.map +0 -1
- package/dist/cjs/index.test.js +0 -7
- package/dist/cjs/index.test.js.map +0 -1
- package/dist/cjs/renderElementAsReact.test.js +0 -54
- package/dist/cjs/renderElementAsReact.test.js.map +0 -1
- package/dist/cjs/useExtensions.test.js +0 -647
- package/dist/cjs/useExtensions.test.js.map +0 -1
- package/dist/esm/ExtensionPoint.test.js +0 -93
- package/dist/esm/ExtensionPoint.test.js.map +0 -1
- package/dist/esm/ExtensionPointInfo.test.js +0 -186
- package/dist/esm/ExtensionPointInfo.test.js.map +0 -1
- package/dist/esm/ExtensionsObservable.test.js +0 -346
- package/dist/esm/ExtensionsObservable.test.js.map +0 -1
- package/dist/esm/debug/useDebug.test.js +0 -46
- package/dist/esm/debug/useDebug.test.js.map +0 -1
- package/dist/esm/debug/useDiscovery.test.js +0 -46
- package/dist/esm/debug/useDiscovery.test.js.map +0 -1
- package/dist/esm/debug/useLogging.test.js +0 -46
- package/dist/esm/debug/useLogging.test.js.map +0 -1
- package/dist/esm/debug/useValidation.test.js +0 -46
- package/dist/esm/debug/useValidation.test.js.map +0 -1
- package/dist/esm/handlers/AsyncPanelHandler.test.js +0 -186
- package/dist/esm/handlers/AsyncPanelHandler.test.js.map +0 -1
- package/dist/esm/handlers/ButtonHandler.test.js +0 -37
- package/dist/esm/handlers/ButtonHandler.test.js.map +0 -1
- package/dist/esm/handlers/LinkHandler.test.js +0 -40
- package/dist/esm/handlers/LinkHandler.test.js.map +0 -1
- package/dist/esm/handlers/ModalHandler.test.js +0 -186
- package/dist/esm/handlers/ModalHandler.test.js.map +0 -1
- package/dist/esm/handlers/PanelHandler.test.js +0 -85
- package/dist/esm/handlers/PanelHandler.test.js.map +0 -1
- package/dist/esm/handlers/SectionHandler.test.js +0 -14
- package/dist/esm/handlers/SectionHandler.test.js.map +0 -1
- package/dist/esm/index.test.js +0 -7
- package/dist/esm/index.test.js.map +0 -1
- package/dist/esm/renderElementAsReact.test.js +0 -51
- package/dist/esm/renderElementAsReact.test.js.map +0 -1
- package/dist/esm/useExtensions.test.js +0 -644
- package/dist/esm/useExtensions.test.js.map +0 -1
- package/dist/types/ExtensionPoint.test.d.ts +0 -2
- package/dist/types/ExtensionPoint.test.d.ts.map +0 -1
- package/dist/types/ExtensionPointInfo.test.d.ts +0 -2
- package/dist/types/ExtensionPointInfo.test.d.ts.map +0 -1
- package/dist/types/ExtensionsObservable.test.d.ts +0 -2
- package/dist/types/ExtensionsObservable.test.d.ts.map +0 -1
- package/dist/types/debug/useDebug.test.d.ts +0 -2
- package/dist/types/debug/useDebug.test.d.ts.map +0 -1
- package/dist/types/debug/useDiscovery.test.d.ts +0 -2
- package/dist/types/debug/useDiscovery.test.d.ts.map +0 -1
- package/dist/types/debug/useLogging.test.d.ts +0 -2
- package/dist/types/debug/useLogging.test.d.ts.map +0 -1
- package/dist/types/debug/useValidation.test.d.ts +0 -2
- package/dist/types/debug/useValidation.test.d.ts.map +0 -1
- package/dist/types/handlers/AsyncPanelHandler.test.d.ts +0 -2
- package/dist/types/handlers/AsyncPanelHandler.test.d.ts.map +0 -1
- package/dist/types/handlers/ButtonHandler.test.d.ts +0 -2
- package/dist/types/handlers/ButtonHandler.test.d.ts.map +0 -1
- package/dist/types/handlers/LinkHandler.test.d.ts +0 -2
- package/dist/types/handlers/LinkHandler.test.d.ts.map +0 -1
- package/dist/types/handlers/ModalHandler.test.d.ts +0 -2
- package/dist/types/handlers/ModalHandler.test.d.ts.map +0 -1
- package/dist/types/handlers/PanelHandler.test.d.ts +0 -2
- package/dist/types/handlers/PanelHandler.test.d.ts.map +0 -1
- package/dist/types/handlers/SectionHandler.test.d.ts +0 -2
- package/dist/types/handlers/SectionHandler.test.d.ts.map +0 -1
- package/dist/types/index.test.d.ts +0 -1
- package/dist/types/index.test.d.ts.map +0 -1
- package/dist/types/renderElementAsReact.test.d.ts +0 -2
- package/dist/types/renderElementAsReact.test.d.ts.map +0 -1
- package/dist/types/useExtensions.test.d.ts +0 -2
- 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
|