@forge/react 9.1.4 → 9.2.0-next.1

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 (60) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/out/__test__/testUtils.d.ts.map +1 -1
  3. package/out/hooks/__test__/confluenceEntity.test.d.ts +2 -0
  4. package/out/hooks/__test__/confluenceEntity.test.d.ts.map +1 -0
  5. package/out/hooks/__test__/confluenceEntity.test.js +148 -0
  6. package/out/hooks/__test__/mockPropertyHook.d.ts +56 -0
  7. package/out/hooks/__test__/mockPropertyHook.d.ts.map +1 -0
  8. package/out/hooks/__test__/mockPropertyHook.js +52 -0
  9. package/out/hooks/__test__/useConfig.test.d.ts +2 -0
  10. package/out/hooks/__test__/useConfig.test.d.ts.map +1 -0
  11. package/out/hooks/__test__/useConfig.test.js +49 -0
  12. package/out/hooks/__test__/useEntityProperty.test.d.ts +2 -0
  13. package/out/hooks/__test__/useEntityProperty.test.d.ts.map +1 -0
  14. package/out/hooks/__test__/useEntityProperty.test.js +118 -0
  15. package/out/hooks/__test__/useProductContext.test.d.ts +2 -0
  16. package/out/hooks/__test__/useProductContext.test.d.ts.map +1 -0
  17. package/out/hooks/__test__/useProductContext.test.js +58 -0
  18. package/out/hooks/confluenceEntity.d.ts +11 -0
  19. package/out/hooks/confluenceEntity.d.ts.map +1 -0
  20. package/out/hooks/confluenceEntity.js +105 -0
  21. package/out/hooks/types/confEntityProps.d.ts +19 -0
  22. package/out/hooks/types/confEntityProps.d.ts.map +1 -0
  23. package/out/hooks/types/confEntityProps.js +2 -0
  24. package/out/hooks/types/entityProps.d.ts +53 -0
  25. package/out/hooks/types/entityProps.d.ts.map +1 -0
  26. package/out/hooks/types/entityProps.js +9 -0
  27. package/out/hooks/types/index.d.ts +4 -0
  28. package/out/hooks/types/index.d.ts.map +1 -0
  29. package/out/hooks/types/index.js +6 -0
  30. package/out/hooks/types/jiraEntityProps.d.ts +2 -0
  31. package/out/hooks/types/jiraEntityProps.d.ts.map +1 -0
  32. package/out/hooks/types/jiraEntityProps.js +2 -0
  33. package/out/hooks/useConfig.d.ts +2 -0
  34. package/out/hooks/useConfig.d.ts.map +1 -0
  35. package/out/hooks/useConfig.js +9 -0
  36. package/out/hooks/useContentProperty.d.ts +2 -0
  37. package/out/hooks/useContentProperty.d.ts.map +1 -0
  38. package/out/hooks/useContentProperty.js +15 -0
  39. package/out/hooks/useEntityProperty.d.ts +3 -0
  40. package/out/hooks/useEntityProperty.d.ts.map +1 -0
  41. package/out/hooks/useEntityProperty.js +38 -0
  42. package/out/hooks/useProductContext.d.ts +3 -0
  43. package/out/hooks/useProductContext.d.ts.map +1 -0
  44. package/out/hooks/useProductContext.js +18 -0
  45. package/out/hooks/useSpaceProperty.d.ts +2 -0
  46. package/out/hooks/useSpaceProperty.d.ts.map +1 -0
  47. package/out/hooks/useSpaceProperty.js +15 -0
  48. package/out/hooks/utils/apiRequestUtils.d.ts +9 -0
  49. package/out/hooks/utils/apiRequestUtils.d.ts.map +1 -0
  50. package/out/hooks/utils/apiRequestUtils.js +34 -0
  51. package/out/hooks/utils/valueUtils.d.ts +2 -0
  52. package/out/hooks/utils/valueUtils.d.ts.map +1 -0
  53. package/out/hooks/utils/valueUtils.js +8 -0
  54. package/out/index.d.ts +4 -0
  55. package/out/index.d.ts.map +1 -1
  56. package/out/index.js +9 -1
  57. package/out/reconciler.d.ts +0 -1
  58. package/out/reconciler.d.ts.map +1 -1
  59. package/package.json +2 -1
  60. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @forge/react
2
2
 
3
+ ## 9.2.0-next.1
4
+
5
+ ### Minor Changes
6
+
7
+ - be57ee6: Created hooks for the package:
8
+ - useProductContext: outputs the app's environment context via @forge/bridge's view.getContext()
9
+ - useConfig: requests for product environment context and extracts the app's config (if available)
10
+
11
+ ## 9.2.0-next.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 0cbc4ee: creates useSpaceProperty and useContentProperty hooks for UI kit 2
16
+
17
+ - useSpaceProperty:
18
+ - manages a Confluence space's property (via Confluence v2 API)
19
+ - requires the following scopes:
20
+ - read:space:confluence
21
+ - write:space:confluence
22
+ - useContentProperty
23
+ - manages a Confluence page's property (via Confluence v2 API)
24
+ - requires the following scopes
25
+ - read:page:confluence
26
+ - write:page:confluence
27
+
3
28
  ## 9.1.4
4
29
 
5
30
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../../src/__test__/testUtils.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,oBAAY,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC;AAC/D,aAAK,WAAW,GAAG,MAAM,UAAU,EAAE,CAAC;AAEtC,aAAK,iBAAiB,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,KAAK,UAAU,GAAG,IAAI,CAAC;AAC1E,aAAK,yBAAyB,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,KAAK,QAAQ,GAAG,IAAI,CAAC;AAChF,aAAK,qBAAqB,GAAG,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAC;AAE9F,aAAK,cAAc,GAAG;IACpB,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAMF,eAAO,MAAM,WAAW,EAAE,WAWzB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,iBAK/B,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,yBAMvC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,qBAkBnC,CAAC"}
1
+ {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../../src/__test__/testUtils.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,oBAAY,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC;AAC/D,aAAK,WAAW,GAAG,MAAM,UAAU,EAAE,CAAC;AAEtC,aAAK,iBAAiB,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,KAAK,UAAU,GAAG,IAAI,CAAC;AAC1E,aAAK,yBAAyB,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,KAAK,QAAQ,GAAG,IAAI,CAAC;AAChF,aAAK,qBAAqB,GAAG,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAC;AAE9F,aAAK,cAAc,GAAG;IACpB,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAMF,eAAO,MAAM,WAAW,EAAE,WAYzB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,iBAK/B,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,yBAMvC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,qBAkBnC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=confluenceEntity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confluenceEntity.test.d.ts","sourceRoot":"","sources":["../../../src/hooks/__test__/confluenceEntity.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const mockRequestConf = jest.fn();
4
+ const mockGetContext = jest.fn(async () => mockPropertyHook_1.mockConfContext);
5
+ const confluenceEntity_1 = require("../confluenceEntity");
6
+ const mockPropertyHook_1 = require("./mockPropertyHook");
7
+ jest.mock('@forge/bridge', () => ({
8
+ requestConfluence: mockRequestConf,
9
+ view: { getContext: mockGetContext }
10
+ }));
11
+ describe('confAPIEndpoints string generation, given an entityType, productContext and required property data', () => {
12
+ const spaceEndpoints = (0, confluenceEntity_1.confAPIEndpoints)({ entityType: 'Space', context: mockPropertyHook_1.mockConfContext });
13
+ const contentEndpoints = (0, confluenceEntity_1.confAPIEndpoints)({ entityType: 'Content', context: mockPropertyHook_1.mockConfContext });
14
+ it('should generate the expected property create URL', () => {
15
+ expect(spaceEndpoints.create()).toEqual('/wiki/api/v2/spaces/MOCK_SPACE_ID/properties');
16
+ expect(contentEndpoints.create()).toEqual('/wiki/api/v2/pages/MOCK_PAGE_ID/properties');
17
+ });
18
+ it('should generate the expected property get URL', () => {
19
+ expect(spaceEndpoints.fetch('MOCK_PROP_KEY')).toEqual('/wiki/api/v2/spaces/MOCK_SPACE_ID/properties?key=MOCK_PROP_KEY');
20
+ expect(contentEndpoints.fetch('MOCK_PROP_KEY')).toEqual('/wiki/api/v2/pages/MOCK_PAGE_ID/properties?key=MOCK_PROP_KEY');
21
+ });
22
+ it('should generate the expected property update URL', () => {
23
+ expect(spaceEndpoints.update('MOCK_PROP_ID')).toEqual('/wiki/api/v2/spaces/MOCK_SPACE_ID/properties/MOCK_PROP_ID');
24
+ expect(contentEndpoints.update('MOCK_PROP_ID')).toEqual('/wiki/api/v2/pages/MOCK_PAGE_ID/properties/MOCK_PROP_ID');
25
+ });
26
+ it('should generate the expected property delete URL', () => {
27
+ expect(spaceEndpoints.delete('MOCK_PROP_ID')).toEqual('/wiki/api/v2/spaces/MOCK_SPACE_ID/properties/MOCK_PROP_ID');
28
+ expect(contentEndpoints.delete('MOCK_PROP_ID')).toEqual('/wiki/api/v2/pages/MOCK_PAGE_ID/properties/MOCK_PROP_ID');
29
+ });
30
+ it('should throw an error if spaceId not available', () => {
31
+ expect(() => (0, confluenceEntity_1.confAPIEndpoints)({ entityType: 'Space', context: { extension: {} } })).toThrow('Space properties not available for this app.');
32
+ expect(() => (0, confluenceEntity_1.confAPIEndpoints)({ entityType: 'Content', context: { extension: {} } })).toThrow('Content properties not available for this app.');
33
+ });
34
+ });
35
+ describe('confluenceEntity', () => {
36
+ const contentEntity = (0, confluenceEntity_1.confluenceEntity)({
37
+ entityType: 'Content',
38
+ origPropertyKey: 'MOCK_PROP_KEY',
39
+ initValue: mockPropertyHook_1.DEFAULT_PROP_VALUE
40
+ });
41
+ const contentEndpoints = (0, confluenceEntity_1.confAPIEndpoints)({ entityType: 'Content', context: mockPropertyHook_1.mockConfContext });
42
+ afterEach(() => jest.clearAllMocks());
43
+ describe('when running its get() output function', () => {
44
+ beforeAll(() => {
45
+ mockRequestConf.mockResolvedValue(mockPropertyHook_1.mockConfGetExistingRes);
46
+ });
47
+ it('should make a GET request with the right URL', async () => {
48
+ const contentGetUrl = contentEndpoints.fetch('forge-undefined-MOCK_PROP_KEY');
49
+ const contentGetBody = expect.objectContaining({ method: 'GET' });
50
+ await contentEntity.get();
51
+ expect(mockRequestConf).toHaveBeenNthCalledWith(1, contentGetUrl, contentGetBody);
52
+ });
53
+ it('if the property exists, it should return its value', async () => {
54
+ const output = await contentEntity.get();
55
+ expect(output).toEqual(mockPropertyHook_1.EXISTING_PROP_VALUE);
56
+ expect(mockRequestConf).toHaveBeenCalledTimes(1);
57
+ });
58
+ it('should throw an error if the GET request fails', async () => {
59
+ mockRequestConf.mockResolvedValueOnce(mockPropertyHook_1.mockConfFailedRes);
60
+ await expect(contentEntity.get).rejects.toThrow(`The request to fetch the content property (forge-undefined-MOCK_PROP_KEY) failed with status (400).`);
61
+ });
62
+ describe('if the property does not exist, it should create it', () => {
63
+ beforeEach(() => {
64
+ mockRequestConf.mockResolvedValueOnce(mockPropertyHook_1.mockConfGetNonExistentRes).mockResolvedValueOnce(mockPropertyHook_1.mockConfCreateRes);
65
+ });
66
+ it('should make a POST request to the API with the right URL and body', async () => {
67
+ const contentPostUrl = contentEndpoints.create();
68
+ const contentPostBody = expect.objectContaining({
69
+ method: 'POST',
70
+ body: JSON.stringify({ key: 'forge-undefined-MOCK_PROP_KEY', value: mockPropertyHook_1.DEFAULT_PROP_VALUE })
71
+ });
72
+ await contentEntity.get();
73
+ expect(mockRequestConf).toHaveBeenCalledTimes(2);
74
+ expect(mockRequestConf).toHaveBeenNthCalledWith(2, contentPostUrl, contentPostBody);
75
+ });
76
+ it('should return the value of the created property (i.e. DEFAULT_PROP_VALUE value)', async () => {
77
+ const output = await contentEntity.get();
78
+ expect(output).toEqual(mockPropertyHook_1.DEFAULT_PROP_VALUE);
79
+ });
80
+ it('should throw an error if the POST request fails', async () => {
81
+ mockRequestConf.mockReset();
82
+ mockRequestConf.mockResolvedValueOnce(mockPropertyHook_1.mockConfGetNonExistentRes).mockResolvedValueOnce(mockPropertyHook_1.mockConfFailedRes);
83
+ await expect(contentEntity.get).rejects.toThrow(`The request to create the content property (forge-undefined-MOCK_PROP_KEY) failed with status (400).`);
84
+ });
85
+ });
86
+ });
87
+ describe('when running its update() output function', () => {
88
+ beforeEach(() => {
89
+ mockRequestConf.mockResolvedValueOnce(mockPropertyHook_1.mockConfGetExistingRes).mockResolvedValueOnce(mockPropertyHook_1.mockConfUpdateValueRes);
90
+ });
91
+ it('should fetch the original property, then make a PUT request with the right url and body', async () => {
92
+ const contentGetUrl = contentEndpoints.fetch('forge-undefined-MOCK_PROP_KEY');
93
+ const contentGetBody = expect.objectContaining({ method: 'GET' });
94
+ const contentPutUrl = contentEndpoints.update('MOCK_PROP_ID');
95
+ const valueUpdateStr = `"value":${mockPropertyHook_1.UPDATED_PROP_VALUE}`;
96
+ const versionUpdateStr = `"version":{"number":${mockPropertyHook_1.UPDATED_PROP_VALUE}`;
97
+ const contentPutBody = (updateStr) => expect.objectContaining({
98
+ body: expect.stringContaining(updateStr)
99
+ });
100
+ await contentEntity.update(mockPropertyHook_1.UPDATED_PROP_VALUE);
101
+ expect(mockRequestConf).toHaveBeenCalledTimes(2);
102
+ expect(mockRequestConf).toHaveBeenNthCalledWith(1, contentGetUrl, contentGetBody);
103
+ [valueUpdateStr, versionUpdateStr].forEach((updateStr) => {
104
+ expect(mockRequestConf).toHaveBeenNthCalledWith(2, contentPutUrl, contentPutBody(updateStr));
105
+ });
106
+ });
107
+ it('should return the value of the UPDATED_PROP_VALUE property when updating with solid value', async () => {
108
+ const valUpdate = await contentEntity.update(mockPropertyHook_1.UPDATED_PROP_VALUE);
109
+ expect(valUpdate).toEqual(mockPropertyHook_1.UPDATED_PROP_VALUE);
110
+ });
111
+ it('should return the value of the UPDATED_PROP_VALUE property when updating with setter function', async () => {
112
+ mockRequestConf.mockReset();
113
+ mockRequestConf.mockResolvedValueOnce(mockPropertyHook_1.mockConfGetExistingRes).mockResolvedValueOnce(mockPropertyHook_1.mockConfUpdateFunctionRes);
114
+ const updateCBFunc = (existingVal) => {
115
+ return existingVal * mockPropertyHook_1.UPDATED_PROP_VALUE;
116
+ };
117
+ const expectedResult = mockPropertyHook_1.EXISTING_PROP_VALUE * mockPropertyHook_1.UPDATED_PROP_VALUE;
118
+ const funcUpdate = await contentEntity.update(updateCBFunc);
119
+ expect(funcUpdate).toEqual(expectedResult);
120
+ });
121
+ it('should throw an error if the PUT request fails', async () => {
122
+ mockRequestConf.mockReset();
123
+ mockRequestConf.mockResolvedValueOnce(mockPropertyHook_1.mockConfGetExistingRes).mockResolvedValueOnce(mockPropertyHook_1.mockConfFailedRes);
124
+ await expect(() => contentEntity.update(mockPropertyHook_1.UPDATED_PROP_VALUE)).rejects.toThrow(`The request to update the content property (forge-undefined-MOCK_PROP_KEY) failed with status (400).`);
125
+ });
126
+ });
127
+ describe('when running its delete() output function', () => {
128
+ beforeEach(() => {
129
+ mockRequestConf.mockResolvedValueOnce(mockPropertyHook_1.mockConfGetExistingRes).mockResolvedValueOnce(mockPropertyHook_1.mockConfDeleteRes);
130
+ });
131
+ it('should fetch the original property, then make a DELETE request with the right url', async () => {
132
+ const contentGetUrl = contentEndpoints.fetch('forge-undefined-MOCK_PROP_KEY');
133
+ const contentGetBody = expect.objectContaining({ method: 'GET' });
134
+ const contentDeleteUrl = contentEndpoints.delete('MOCK_PROP_ID');
135
+ const contentDeleteBody = expect.objectContaining({ method: 'DELETE' });
136
+ await contentEntity.delete();
137
+ expect(mockRequestConf).toHaveBeenCalledTimes(2);
138
+ expect(mockRequestConf).toHaveBeenNthCalledWith(1, contentGetUrl, contentGetBody);
139
+ expect(mockRequestConf).toHaveBeenNthCalledWith(2, contentDeleteUrl, contentDeleteBody);
140
+ jest.clearAllMocks();
141
+ });
142
+ it('should throw an error if the DELETE request fails', async () => {
143
+ mockRequestConf.mockReset();
144
+ mockRequestConf.mockResolvedValueOnce(mockPropertyHook_1.mockConfGetExistingRes).mockResolvedValueOnce(mockPropertyHook_1.mockConfFailedRes);
145
+ await expect(contentEntity.delete).rejects.toThrow(`The request to delete the content property (forge-undefined-MOCK_PROP_KEY) failed with status (400).`);
146
+ });
147
+ });
148
+ });
@@ -0,0 +1,56 @@
1
+ import { EntityContext } from '../types';
2
+ export declare const DEFAULT_PROP_VALUE: number, EXISTING_PROP_VALUE: number, UPDATED_PROP_VALUE: number;
3
+ export declare const mockConfContext: EntityContext;
4
+ export declare const mockConfFailedRes: {
5
+ ok: boolean;
6
+ status: number;
7
+ };
8
+ export declare const mockConfGetExistingRes: {
9
+ ok: boolean;
10
+ status: number;
11
+ json: () => {
12
+ results: {
13
+ id: string;
14
+ value: number;
15
+ version: {
16
+ number: number;
17
+ };
18
+ }[];
19
+ };
20
+ };
21
+ export declare const mockConfGetNonExistentRes: {
22
+ ok: boolean;
23
+ status: number;
24
+ json: () => {
25
+ results: never[];
26
+ };
27
+ };
28
+ export declare const mockConfCreateRes: {
29
+ ok: boolean;
30
+ status: number;
31
+ json: () => {
32
+ id: string;
33
+ value: number;
34
+ };
35
+ };
36
+ export declare const mockConfUpdateValueRes: {
37
+ ok: boolean;
38
+ status: number;
39
+ json: () => {
40
+ id: string;
41
+ value: number;
42
+ };
43
+ };
44
+ export declare const mockConfUpdateFunctionRes: {
45
+ ok: boolean;
46
+ status: number;
47
+ json: () => {
48
+ id: string;
49
+ value: number;
50
+ };
51
+ };
52
+ export declare const mockConfDeleteRes: {
53
+ ok: boolean;
54
+ status: number;
55
+ };
56
+ //# sourceMappingURL=mockPropertyHook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockPropertyHook.d.ts","sourceRoot":"","sources":["../../../src/hooks/__test__/mockPropertyHook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,eAAO,MAAO,kBAAkB,UAAE,mBAAmB,UAAE,kBAAkB,QAAa,CAAC;AAEvF,eAAO,MAAM,eAAe,EAAE,aAS7B,CAAC;AAKF,eAAO,MAAM,iBAAiB;;;CAG7B,CAAC;AACF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;CAMlC,CAAC;AACF,eAAO,MAAM,yBAAyB;;;;;;CAMrC,CAAC;AACF,eAAO,MAAM,iBAAiB;;;;;;;CAI7B,CAAC;AACF,eAAO,MAAM,sBAAsB;;;;;;;CAIlC,CAAC;AACF,eAAO,MAAM,yBAAyB;;;;;;;CAIrC,CAAC;AACF,eAAO,MAAM,iBAAiB;;;CAG7B,CAAC"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.mockConfDeleteRes = exports.mockConfUpdateFunctionRes = exports.mockConfUpdateValueRes = exports.mockConfCreateRes = exports.mockConfGetNonExistentRes = exports.mockConfGetExistingRes = exports.mockConfFailedRes = exports.mockConfContext = exports.UPDATED_PROP_VALUE = exports.EXISTING_PROP_VALUE = exports.DEFAULT_PROP_VALUE = void 0;
5
+ _a = [1, 2, 3], exports.DEFAULT_PROP_VALUE = _a[0], exports.EXISTING_PROP_VALUE = _a[1], exports.UPDATED_PROP_VALUE = _a[2];
6
+ exports.mockConfContext = {
7
+ extension: {
8
+ space: {
9
+ id: 'MOCK_SPACE_ID'
10
+ },
11
+ content: {
12
+ id: 'MOCK_PAGE_ID'
13
+ }
14
+ }
15
+ };
16
+ exports.mockConfFailedRes = {
17
+ ok: false,
18
+ status: 400
19
+ };
20
+ exports.mockConfGetExistingRes = {
21
+ ok: true,
22
+ status: 200,
23
+ json: () => ({
24
+ results: [{ id: 'MOCK_PROP_ID', value: exports.EXISTING_PROP_VALUE, version: { number: exports.EXISTING_PROP_VALUE } }]
25
+ })
26
+ };
27
+ exports.mockConfGetNonExistentRes = {
28
+ ok: true,
29
+ status: 200,
30
+ json: () => ({
31
+ results: []
32
+ })
33
+ };
34
+ exports.mockConfCreateRes = {
35
+ ok: true,
36
+ status: 201,
37
+ json: () => ({ id: 'MOCK_PROP_ID', value: exports.DEFAULT_PROP_VALUE })
38
+ };
39
+ exports.mockConfUpdateValueRes = {
40
+ ok: true,
41
+ status: 200,
42
+ json: () => ({ id: 'MOCK_PROP_ID', value: exports.UPDATED_PROP_VALUE })
43
+ };
44
+ exports.mockConfUpdateFunctionRes = {
45
+ ok: true,
46
+ status: 200,
47
+ json: () => ({ id: 'MOCK_PROP_ID', value: exports.UPDATED_PROP_VALUE * exports.EXISTING_PROP_VALUE })
48
+ };
49
+ exports.mockConfDeleteRes = {
50
+ ok: true,
51
+ status: 204
52
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=useConfig.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConfig.test.d.ts","sourceRoot":"","sources":["../../../src/hooks/__test__/useConfig.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const mockGetContext = jest.fn(async () => null);
6
+ const react_1 = tslib_1.__importStar(require("react"));
7
+ const reconcilerTestRenderer_1 = tslib_1.__importDefault(require("../../__test__/reconcilerTestRenderer"));
8
+ const useConfig_1 = require("../useConfig");
9
+ const testUtils_1 = require("../../__test__/testUtils");
10
+ jest.mock('@forge/bridge', () => ({
11
+ view: {
12
+ getContext: mockGetContext
13
+ }
14
+ }));
15
+ const MOCK_CONFIG = {
16
+ value: 1
17
+ };
18
+ const MOCK_CONTEXT_WITH_CONFIG = {
19
+ extension: {
20
+ config: MOCK_CONFIG
21
+ }
22
+ };
23
+ const MOCK_CONTEXT_NO_CONFIG = {
24
+ extension: {}
25
+ };
26
+ const configListener = jest.fn();
27
+ const renderTest = async () => {
28
+ const Test = () => {
29
+ const config = (0, useConfig_1.useConfig)();
30
+ (0, react_1.useEffect)(() => configListener(config), [config]);
31
+ return (0, jsx_runtime_1.jsx)(react_1.default.Fragment, {});
32
+ };
33
+ await reconcilerTestRenderer_1.default.create((0, jsx_runtime_1.jsx)(Test, {}));
34
+ };
35
+ describe('useConfig', () => {
36
+ beforeAll(() => (0, testUtils_1.setupBridge)());
37
+ afterEach(() => jest.clearAllMocks());
38
+ it('correctly outputs a given config', async () => {
39
+ mockGetContext.mockResolvedValue(MOCK_CONTEXT_WITH_CONFIG);
40
+ await renderTest();
41
+ expect(configListener).toHaveBeenCalledWith(expect.objectContaining(MOCK_CONFIG));
42
+ });
43
+ it('when there is no config, outputs undefined', async () => {
44
+ mockGetContext.mockResolvedValue(MOCK_CONTEXT_NO_CONFIG);
45
+ await renderTest();
46
+ expect(configListener.mock.calls[0][0]).toEqual(undefined);
47
+ expect(configListener).not.toHaveBeenNthCalledWith(2, expect.anything);
48
+ });
49
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=useEntityProperty.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEntityProperty.test.d.ts","sourceRoot":"","sources":["../../../src/hooks/__test__/useEntityProperty.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = tslib_1.__importStar(require("react"));
6
+ const testUtils_1 = require("../../__test__/testUtils");
7
+ const reconcilerTestRenderer_1 = tslib_1.__importDefault(require("../../__test__/reconcilerTestRenderer"));
8
+ const mockPropertyHook_1 = require("./mockPropertyHook");
9
+ const useEntityProperty_1 = require("../useEntityProperty");
10
+ const mockRequest = jest.fn();
11
+ const mockEntity = () => ({
12
+ get: async () => {
13
+ mockRequest('get');
14
+ return mockPropertyHook_1.EXISTING_PROP_VALUE;
15
+ },
16
+ update: async () => {
17
+ const response = await mockRequest('update');
18
+ if (!response.ok) {
19
+ throw new Error();
20
+ }
21
+ return mockPropertyHook_1.UPDATED_PROP_VALUE;
22
+ },
23
+ delete: async () => {
24
+ mockRequest('delete');
25
+ }
26
+ });
27
+ const useMockEntityProperty = () => {
28
+ const entityManager = (0, react_1.useMemo)(mockEntity, []);
29
+ return (0, useEntityProperty_1.useEntityProperty)(entityManager);
30
+ };
31
+ const propListener = jest.fn();
32
+ var renderActions;
33
+ (function (renderActions) {
34
+ renderActions[renderActions["noAction"] = 0] = "noAction";
35
+ renderActions[renderActions["toUpdate"] = 1] = "toUpdate";
36
+ renderActions[renderActions["toDelete"] = 2] = "toDelete";
37
+ })(renderActions || (renderActions = {}));
38
+ ;
39
+ const renderTest = async (action = renderActions.noAction, retryCount) => {
40
+ const Test = () => {
41
+ const [prop, setProp, delProp] = useMockEntityProperty();
42
+ (0, react_1.useEffect)(() => propListener(prop), [prop]);
43
+ (0, react_1.useEffect)(() => {
44
+ if (action === renderActions.toUpdate) {
45
+ void setProp(mockPropertyHook_1.UPDATED_PROP_VALUE, retryCount);
46
+ }
47
+ if (action === renderActions.toDelete) {
48
+ void delProp();
49
+ }
50
+ }, []);
51
+ return (0, jsx_runtime_1.jsx)(react_1.default.Fragment, {});
52
+ };
53
+ await reconcilerTestRenderer_1.default.create((0, jsx_runtime_1.jsx)(Test, {}));
54
+ };
55
+ describe('useEntityProperty', () => {
56
+ beforeAll(testUtils_1.setupBridge);
57
+ beforeEach(() => {
58
+ mockRequest.mockResolvedValue(mockPropertyHook_1.mockConfGetExistingRes);
59
+ });
60
+ afterEach(() => {
61
+ jest.clearAllMocks();
62
+ });
63
+ describe('initial returned prop value', () => {
64
+ it("is acquired from the given entityManager's get() function", async () => {
65
+ await renderTest();
66
+ expect(mockRequest).toHaveBeenNthCalledWith(1, 'get');
67
+ });
68
+ it('is statefully and correctly rendered', async () => {
69
+ await renderTest();
70
+ expect(propListener).toHaveBeenNthCalledWith(1, undefined);
71
+ expect(propListener).toHaveBeenNthCalledWith(2, mockPropertyHook_1.EXISTING_PROP_VALUE);
72
+ });
73
+ });
74
+ describe('returned value-setting function', () => {
75
+ it("calls the given entityManager's update() function", async () => {
76
+ await renderTest(renderActions.toUpdate);
77
+ expect(mockRequest).toHaveBeenNthCalledWith(2, 'update');
78
+ });
79
+ it('updates the returned prop value statefully and correctly', async () => {
80
+ await renderTest(renderActions.toUpdate);
81
+ expect(propListener).toHaveBeenNthCalledWith(3, mockPropertyHook_1.UPDATED_PROP_VALUE);
82
+ });
83
+ it('makes 2 retries (by default) when initial attempt fails', async () => {
84
+ mockRequest.mockResolvedValue(() => mockPropertyHook_1.mockConfFailedRes);
85
+ await renderTest(renderActions.toUpdate);
86
+ expect(mockRequest).toHaveBeenNthCalledWith(2, 'update');
87
+ expect(mockRequest).toHaveBeenNthCalledWith(3, 'update');
88
+ expect(mockRequest).toHaveBeenNthCalledWith(4, 'update');
89
+ expect(mockRequest).not.toHaveBeenNthCalledWith(5, 'update');
90
+ });
91
+ it('stops retrying when a previous retry succeeds', async () => {
92
+ mockRequest.mockResolvedValueOnce(() => mockPropertyHook_1.mockConfFailedRes).mockResolvedValueOnce(() => mockPropertyHook_1.mockConfUpdateValueRes);
93
+ await renderTest(renderActions.toUpdate);
94
+ expect(mockRequest).toHaveBeenNthCalledWith(2, 'update');
95
+ expect(mockRequest).toHaveBeenNthCalledWith(3, 'update');
96
+ expect(mockRequest).not.toHaveBeenNthCalledWith(4, 'update');
97
+ });
98
+ it('makes custom number of retries (if given) when initial attempts fails', async () => {
99
+ const retryCount = 5;
100
+ mockRequest.mockResolvedValue(() => mockPropertyHook_1.mockConfFailedRes);
101
+ await renderTest(renderActions.toUpdate, retryCount);
102
+ for (let i = 2; i <= retryCount + 2; i++) {
103
+ expect(mockRequest).toHaveBeenNthCalledWith(i, 'update');
104
+ }
105
+ expect(mockRequest).not.toHaveBeenNthCalledWith(retryCount + 3, 'update');
106
+ });
107
+ });
108
+ describe('returned property-deleting function', () => {
109
+ it("calls the given entityManager's delete() function", async () => {
110
+ await renderTest(renderActions.toDelete);
111
+ expect(mockRequest).toHaveBeenNthCalledWith(2, 'delete');
112
+ });
113
+ it('updates the outputted prop value statefully to undefined', async () => {
114
+ await renderTest(renderActions.toDelete);
115
+ expect(propListener).toHaveBeenNthCalledWith(3, undefined);
116
+ });
117
+ });
118
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=useProductContext.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useProductContext.test.d.ts","sourceRoot":"","sources":["../../../src/hooks/__test__/useProductContext.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const mockGetContext = jest.fn(async () => null);
6
+ const useProductContext_1 = require("../useProductContext");
7
+ const react_1 = tslib_1.__importStar(require("react"));
8
+ const testUtils_1 = require("../../__test__/testUtils");
9
+ const reconcilerTestRenderer_1 = tslib_1.__importDefault(require("../../__test__/reconcilerTestRenderer"));
10
+ jest.mock('@forge/bridge', () => ({
11
+ view: {
12
+ getContext: mockGetContext
13
+ }
14
+ }));
15
+ const MOCK_CONTEXT = {
16
+ accountId: 'client-accountId',
17
+ cloudId: 'DUMMY-cloudId',
18
+ extension: { contentId: 'DUMMY-contentId' },
19
+ license: undefined,
20
+ localId: 'DUMMY-localId',
21
+ locale: 'DUMMY-locale',
22
+ moduleKey: 'DUMMY-moduleKey',
23
+ siteUrl: 'DUMMY-siteUrl',
24
+ timezone: 'DUMMY-timezone'
25
+ };
26
+ const prodContListener = jest.fn();
27
+ const renderTest = async () => {
28
+ const Test = () => {
29
+ const prodCont = (0, useProductContext_1.useProductContext)();
30
+ (0, react_1.useEffect)(() => prodContListener(prodCont), [prodCont]);
31
+ return (0, jsx_runtime_1.jsx)(react_1.default.Fragment, {});
32
+ };
33
+ await reconcilerTestRenderer_1.default.create((0, jsx_runtime_1.jsx)(Test, {}));
34
+ };
35
+ describe('useProductContext', () => {
36
+ const LOAD_TIME = 500;
37
+ beforeAll(() => (0, testUtils_1.setupBridge)());
38
+ afterEach(() => jest.clearAllMocks());
39
+ it("automatically fetches data via bridge's view.getContext()", async () => {
40
+ await renderTest();
41
+ expect(mockGetContext).toHaveBeenCalled();
42
+ });
43
+ it('corrently renders an expected ProductContext that is available upon load', async () => {
44
+ mockGetContext.mockResolvedValue(MOCK_CONTEXT);
45
+ await renderTest();
46
+ expect(prodContListener.mock.calls[1][0]).toEqual(MOCK_CONTEXT);
47
+ });
48
+ it('corrently renders an expected ProductContext that takes time to load', async () => {
49
+ mockGetContext.mockImplementation(async () => {
50
+ await new Promise((res) => setTimeout(res, LOAD_TIME));
51
+ return MOCK_CONTEXT;
52
+ });
53
+ await renderTest();
54
+ expect(prodContListener).not.toHaveBeenNthCalledWith(2, expect.anything());
55
+ await new Promise((res) => setTimeout(res, LOAD_TIME * 2));
56
+ expect(prodContListener.mock.calls[1][0]).toEqual(MOCK_CONTEXT);
57
+ }, LOAD_TIME * 3);
58
+ });
@@ -0,0 +1,11 @@
1
+ import { ConfEndpointInitializer, ManagePropsData, ConfluenceEntityType, EntityManager } from './types';
2
+ export declare const confAPIEndpoints: ({ entityType, context }: ConfEndpointInitializer) => {
3
+ create: () => string;
4
+ fetch: (propertyKey: string) => string;
5
+ update: (propertyId: string) => string;
6
+ delete: (propertyId: string) => string;
7
+ };
8
+ export declare const confluenceEntity: <PropValue>({ entityType, origPropertyKey, initValue }: ManagePropsData<PropValue> & {
9
+ entityType: ConfluenceEntityType;
10
+ }) => EntityManager<PropValue>;
11
+ //# sourceMappingURL=confluenceEntity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confluenceEntity.d.ts","sourceRoot":"","sources":["../../src/hooks/confluenceEntity.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,uBAAuB,EAEvB,eAAe,EACf,oBAAoB,EACpB,aAAa,EAEd,MAAM,SAAS,CAAC;AAMjB,eAAO,MAAM,gBAAgB,4BAA6B,uBAAuB;;yBAqBxD,MAAM;yBACN,MAAM;yBACN,MAAM;CAE9B,CAAC;AAEF,eAAO,MAAM,gBAAgB;gBAIiB,oBAAoB;8BAqGjE,CAAC"}