@appsemble/cli 0.29.11 → 0.30.2

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 (156) hide show
  1. package/README.md +10 -10
  2. package/commands/app/create.d.ts +1 -1
  3. package/commands/app/create.js +5 -5
  4. package/commands/{team → group}/create.d.ts +3 -3
  5. package/commands/{team → group}/create.js +5 -5
  6. package/commands/{team → group}/delete.d.ts +3 -3
  7. package/commands/{team → group}/delete.js +5 -5
  8. package/commands/{team → group}/index.d.ts +2 -2
  9. package/commands/{team → group}/index.js +4 -4
  10. package/commands/{team → group}/member/delete.d.ts +3 -3
  11. package/commands/{team → group}/member/delete.js +5 -5
  12. package/commands/{team → group}/member/index.d.ts +1 -1
  13. package/commands/{team → group}/member/index.js +1 -3
  14. package/commands/{team → group}/member/invite.d.ts +3 -3
  15. package/commands/{team → group}/member/invite.js +5 -5
  16. package/commands/{team → group}/update.d.ts +3 -3
  17. package/commands/{team → group}/update.js +7 -7
  18. package/commands/migrateAppDefinitions.d.ts +13 -0
  19. package/commands/migrateAppDefinitions.js +73 -0
  20. package/commands/serve.d.ts +1 -1
  21. package/commands/serve.js +16 -16
  22. package/index.js +4 -2
  23. package/lib/app.js +13 -3
  24. package/lib/app.test.js +1266 -1262
  25. package/lib/asset.js +4 -2
  26. package/lib/asset.test.js +70 -67
  27. package/lib/block.test.js +144 -142
  28. package/lib/config.test.js +205 -203
  29. package/lib/createServers.js +3 -1
  30. package/lib/group.d.ts +61 -0
  31. package/lib/group.js +55 -0
  32. package/lib/group.test.js +610 -0
  33. package/lib/organization.test.js +189 -187
  34. package/lib/resource.js +3 -1
  35. package/lib/resource.test.js +322 -320
  36. package/lib/serverImport.d.ts +1 -1
  37. package/package.json +8 -7
  38. package/server/argv.d.ts +4 -4
  39. package/server/argv.js +1 -1
  40. package/server/controllers/apps/actions/index.d.ts +5 -0
  41. package/server/controllers/apps/actions/index.js +6 -0
  42. package/server/controllers/apps/actions/proxyDelete.d.ts +2 -0
  43. package/server/controllers/apps/actions/proxyDelete.js +4 -0
  44. package/server/controllers/apps/actions/proxyGet.d.ts +2 -0
  45. package/server/controllers/apps/actions/proxyGet.js +4 -0
  46. package/server/controllers/apps/actions/proxyPatch.d.ts +2 -0
  47. package/server/controllers/apps/actions/proxyPatch.js +4 -0
  48. package/server/controllers/apps/actions/proxyPost.d.ts +2 -0
  49. package/server/controllers/apps/actions/proxyPost.js +4 -0
  50. package/server/controllers/apps/actions/proxyPut.d.ts +2 -0
  51. package/server/controllers/apps/actions/proxyPut.js +4 -0
  52. package/server/controllers/apps/index.d.ts +2 -0
  53. package/server/controllers/apps/index.js +3 -0
  54. package/server/controllers/apps/members/current/getCurrentAppMember.d.ts +2 -0
  55. package/server/controllers/apps/members/current/getCurrentAppMember.js +4 -0
  56. package/server/controllers/apps/members/current/index.d.ts +1 -0
  57. package/server/controllers/apps/members/current/index.js +2 -0
  58. package/server/controllers/apps/members/index.d.ts +1 -0
  59. package/server/controllers/apps/members/index.js +2 -0
  60. package/server/controllers/common/apps/assets/getAppAssetById.d.ts +2 -0
  61. package/server/controllers/common/apps/assets/getAppAssetById.js +4 -0
  62. package/server/controllers/common/apps/assets/index.d.ts +1 -0
  63. package/server/controllers/common/apps/assets/index.js +2 -0
  64. package/server/controllers/common/apps/groups/getAppGroups.d.ts +2 -0
  65. package/server/controllers/common/apps/groups/getAppGroups.js +4 -0
  66. package/server/controllers/common/apps/groups/index.d.ts +1 -0
  67. package/server/controllers/common/apps/groups/index.js +2 -0
  68. package/server/controllers/common/apps/index.d.ts +5 -0
  69. package/server/controllers/common/apps/index.js +6 -0
  70. package/server/controllers/common/apps/messages/getAppMessages.d.ts +2 -0
  71. package/server/controllers/common/apps/messages/getAppMessages.js +4 -0
  72. package/server/controllers/common/apps/messages/index.d.ts +1 -0
  73. package/server/controllers/common/apps/messages/index.js +2 -0
  74. package/server/controllers/common/apps/resources/countAppResources.d.ts +2 -0
  75. package/server/controllers/common/apps/resources/countAppResources.js +4 -0
  76. package/server/controllers/common/apps/resources/createAppResource.d.ts +2 -0
  77. package/server/controllers/common/apps/resources/createAppResource.js +4 -0
  78. package/server/controllers/common/apps/resources/deleteAppResource.d.ts +2 -0
  79. package/server/controllers/common/apps/resources/deleteAppResource.js +4 -0
  80. package/server/controllers/common/apps/resources/getAppResourceById.d.ts +2 -0
  81. package/server/controllers/common/apps/resources/getAppResourceById.js +4 -0
  82. package/server/controllers/common/apps/resources/index.d.ts +6 -0
  83. package/server/controllers/common/apps/resources/index.js +7 -0
  84. package/server/controllers/common/apps/resources/queryAppResources.d.ts +2 -0
  85. package/server/controllers/common/apps/resources/queryAppResources.js +4 -0
  86. package/server/controllers/common/apps/resources/updateAppResource.d.ts +2 -0
  87. package/server/controllers/common/apps/resources/updateAppResource.js +4 -0
  88. package/server/controllers/common/apps/variables/getAppVariables.js +4 -0
  89. package/server/controllers/common/apps/variables/index.d.ts +1 -0
  90. package/server/controllers/common/apps/variables/index.js +2 -0
  91. package/server/controllers/common/index.d.ts +1 -0
  92. package/server/controllers/common/index.js +2 -0
  93. package/server/controllers/index.d.ts +3 -8
  94. package/server/controllers/index.js +3 -8
  95. package/server/controllers/main/apps/assets/createAppAsset.d.ts +2 -0
  96. package/server/controllers/main/apps/assets/createAppAsset.js +4 -0
  97. package/server/controllers/main/apps/assets/index.d.ts +1 -0
  98. package/server/controllers/main/apps/assets/index.js +2 -0
  99. package/server/controllers/main/apps/index.d.ts +1 -0
  100. package/server/controllers/main/apps/index.js +2 -0
  101. package/server/controllers/main/index.d.ts +1 -0
  102. package/server/controllers/main/index.js +2 -0
  103. package/server/options/checkAppMemberAppPermissions.d.ts +1 -0
  104. package/server/options/checkAppMemberAppPermissions.js +4 -0
  105. package/server/options/checkAppPermissions.d.ts +1 -0
  106. package/server/options/checkAppPermissions.js +4 -0
  107. package/server/options/checkAuthSubjectAppPermissions.d.ts +1 -0
  108. package/server/options/checkAuthSubjectAppPermissions.js +4 -0
  109. package/server/options/checkUserOrganizationPermissions.d.ts +1 -0
  110. package/server/options/checkUserOrganizationPermissions.js +4 -0
  111. package/server/options/getAppGroups.d.ts +2 -0
  112. package/server/options/getAppGroups.js +4 -0
  113. package/server/options/getCurrentAppMember.d.ts +3 -0
  114. package/server/options/getCurrentAppMember.js +4 -0
  115. package/server/options/index.d.ts +6 -5
  116. package/server/options/index.js +6 -5
  117. package/server/options/options.js +7 -6
  118. package/templates/apps/empty/app-definition.yaml +2 -2
  119. package/templates/blocks/mini-jsx/package.json +1 -1
  120. package/templates/blocks/preact/package.json +2 -2
  121. package/templates/blocks/vanilla/package.json +1 -1
  122. package/vitest.setup.js +11 -0
  123. package/commands/team/member/update.d.ts +0 -16
  124. package/commands/team/member/update.js +0 -46
  125. package/lib/team.d.ts +0 -61
  126. package/lib/team.js +0 -83
  127. package/lib/team.test.js +0 -625
  128. package/server/controllers/action.d.ts +0 -6
  129. package/server/controllers/action.js +0 -8
  130. package/server/controllers/appMembers.d.ts +0 -2
  131. package/server/controllers/appMembers.js +0 -4
  132. package/server/controllers/appMessages.d.ts +0 -2
  133. package/server/controllers/appMessages.js +0 -4
  134. package/server/controllers/appVariables.js +0 -4
  135. package/server/controllers/assets.d.ts +0 -4
  136. package/server/controllers/assets.js +0 -6
  137. package/server/controllers/oauth2Provider.d.ts +0 -2
  138. package/server/controllers/oauth2Provider.js +0 -4
  139. package/server/controllers/resources.d.ts +0 -7
  140. package/server/controllers/resources.js +0 -9
  141. package/server/controllers/teams.d.ts +0 -2
  142. package/server/controllers/teams.js +0 -4
  143. package/server/options/checkRole.d.ts +0 -1
  144. package/server/options/checkRole.js +0 -2
  145. package/server/options/checkRole.test.d.ts +0 -1
  146. package/server/options/checkRole.test.js +0 -13
  147. package/server/options/getAppMembers.d.ts +0 -3
  148. package/server/options/getAppMembers.js +0 -4
  149. package/server/options/getAppTeams.d.ts +0 -2
  150. package/server/options/getAppTeams.js +0 -4
  151. package/server/options/getAppUserInfo.d.ts +0 -3
  152. package/server/options/getAppUserInfo.js +0 -4
  153. package/server/options/verifyResourceActionPermission.d.ts +0 -1
  154. package/server/options/verifyResourceActionPermission.js +0 -2
  155. /package/lib/{team.test.d.ts → group.test.d.ts} +0 -0
  156. /package/server/controllers/{appVariables.d.ts → common/apps/variables/getAppVariables.d.ts} +0 -0
package/lib/app.test.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { writeFile } from 'node:fs/promises';
2
2
  import { readFixture, resolveFixture } from '@appsemble/node-utils';
3
- import { createServer, createTestUser, models, setArgv, useTestDatabase } from '@appsemble/server';
3
+ import { createServer, createTestUser, models, setArgv } from '@appsemble/server';
4
+ import { PredefinedOrganizationRole } from '@appsemble/types';
4
5
  import { ISODateTimePattern } from '@appsemble/utils';
5
6
  import { setTestApp } from 'axios-test-instance';
6
7
  import FormData from 'form-data';
@@ -13,65 +14,65 @@ const argv = { host: 'http://localhost', secret: 'test', aesSecret: 'testSecret'
13
14
  let user;
14
15
  let organization;
15
16
  let testApp;
16
- useTestDatabase(import.meta);
17
- beforeAll(() => {
18
- vi.useFakeTimers();
19
- setArgv(argv);
20
- });
21
- beforeEach(async () => {
22
- vi.clearAllTimers();
23
- vi.setSystemTime(0);
24
- const server = await createServer();
25
- testApp = await setTestApp(server);
26
- initAxios({ remote: testApp.defaults.baseURL });
27
- user = await createTestUser();
28
- organization = await Organization.create({
29
- id: 'testorganization',
30
- name: 'Test Organization',
31
- });
32
- await OrganizationMember.create({
33
- OrganizationId: organization.id,
34
- UserId: user.id,
35
- role: 'Owner',
17
+ describe('app', () => {
18
+ beforeAll(() => {
19
+ vi.useFakeTimers();
20
+ setArgv(argv);
36
21
  });
37
- await Organization.create({ id: 'appsemble', name: 'Appsemble' });
38
- await BlockVersion.create({
39
- name: 'test',
40
- OrganizationId: 'appsemble',
41
- version: '0.0.0',
42
- parameters: {
43
- type: 'object',
44
- properties: {
45
- foo: {
46
- type: 'number',
22
+ beforeEach(async () => {
23
+ vi.clearAllTimers();
24
+ vi.setSystemTime(0);
25
+ const server = await createServer();
26
+ testApp = await setTestApp(server);
27
+ initAxios({ remote: testApp.defaults.baseURL });
28
+ user = await createTestUser();
29
+ organization = await Organization.create({
30
+ id: 'testorganization',
31
+ name: 'Test Organization',
32
+ });
33
+ await OrganizationMember.create({
34
+ OrganizationId: organization.id,
35
+ UserId: user.id,
36
+ role: PredefinedOrganizationRole.Owner,
37
+ });
38
+ await Organization.create({ id: 'appsemble', name: 'Appsemble' });
39
+ await BlockVersion.create({
40
+ name: 'test',
41
+ OrganizationId: 'appsemble',
42
+ version: '0.0.0',
43
+ parameters: {
44
+ type: 'object',
45
+ properties: {
46
+ foo: {
47
+ type: 'number',
48
+ },
47
49
  },
48
50
  },
49
- },
51
+ });
50
52
  });
51
- });
52
- afterAll(() => {
53
- vi.useRealTimers();
54
- });
55
- describe('publishApp', () => {
56
- it('should publish app', async () => {
53
+ afterAll(() => {
57
54
  vi.useRealTimers();
58
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
59
- await publishApp({
60
- path: resolveFixture('apps/test'),
61
- organization: organization.id,
62
- remote: testApp.defaults.baseURL,
63
- clientCredentials,
64
- // Required defaults
65
- visibility: 'unlisted',
66
- iconBackground: '#ffffff',
67
- });
68
- vi.useFakeTimers();
69
- const app = await App.findOne();
70
- expect(app.toJSON()).toMatchInlineSnapshot({
71
- $created: expect.stringMatching(ISODateTimePattern),
72
- $updated: expect.stringMatching(ISODateTimePattern),
73
- iconUrl: expect.any(String),
74
- }, `
55
+ });
56
+ describe('publishApp', () => {
57
+ it('should publish app', async () => {
58
+ vi.useRealTimers();
59
+ const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
60
+ await publishApp({
61
+ path: resolveFixture('apps/test'),
62
+ organization: organization.id,
63
+ remote: testApp.defaults.baseURL,
64
+ clientCredentials,
65
+ // Required defaults
66
+ visibility: 'unlisted',
67
+ iconBackground: '#ffffff',
68
+ });
69
+ vi.useFakeTimers();
70
+ const app = await App.findOne();
71
+ expect(app.toJSON()).toMatchInlineSnapshot({
72
+ $created: expect.stringMatching(ISODateTimePattern),
73
+ $updated: expect.stringMatching(ISODateTimePattern),
74
+ iconUrl: expect.any(String),
75
+ }, `
75
76
  {
76
77
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
77
78
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -161,77 +162,77 @@ describe('publishApp', () => {
161
162
  ",
162
163
  }
163
164
  `);
164
- expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
165
- expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
166
- const appBlockStyle = await AppBlockStyle.findOne();
167
- expect(appBlockStyle.style).toBe(`.tux {
165
+ expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
166
+ expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
167
+ const appBlockStyle = await AppBlockStyle.findOne();
168
+ expect(appBlockStyle.style).toBe(`.tux {
168
169
  color: rgb(0 0 0);
169
170
  }`);
170
- const appScreenshot = await AppScreenshot.findOne();
171
- expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
172
- const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
173
- expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
174
- ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
175
- ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
176
- ]);
177
- const resource = await Resource.findAll();
178
- expect(resource).toStrictEqual([]);
179
- const asset = await Asset.findAll();
180
- expect(asset).toStrictEqual([]);
181
- });
182
- it('should throw an error if the user doesn’t have enough scope permissions', async () => {
183
- const clientCredentials = await authorizeCLI('', testApp);
184
- vi.useRealTimers();
185
- await expect(() => publishApp({
186
- path: resolveFixture('apps/test'),
187
- organization: organization.id,
188
- remote: testApp.defaults.baseURL,
189
- clientCredentials,
190
- // Required defaults
191
- visibility: 'unlisted',
192
- iconBackground: '#ffffff',
193
- })).rejects.toThrow('Request failed with status code 401');
194
- vi.useFakeTimers();
195
- const app = await App.findOne();
196
- expect(app).toBeNull();
197
- });
198
- it('should not publish if dryRun is specified', async () => {
199
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
200
- await publishApp({
201
- path: resolveFixture('apps/test'),
202
- organization: organization.id,
203
- remote: testApp.defaults.baseURL,
204
- clientCredentials,
205
- // Required defaults
206
- visibility: 'unlisted',
207
- iconBackground: '#ffffff',
208
- dryRun: true,
171
+ const appScreenshot = await AppScreenshot.findOne();
172
+ expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
173
+ const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
174
+ expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
175
+ ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
176
+ ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
177
+ ]);
178
+ const resource = await Resource.findAll();
179
+ expect(resource).toStrictEqual([]);
180
+ const asset = await Asset.findAll();
181
+ expect(asset).toStrictEqual([]);
209
182
  });
210
- const apps = await App.findAll();
211
- expect(apps).toStrictEqual([]);
212
- });
213
- it('should publish app with resources and assets', async () => {
214
- vi.useRealTimers();
215
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
216
- await publishApp({
217
- path: resolveFixture('apps/test'),
218
- organization: organization.id,
219
- remote: testApp.defaults.baseURL,
220
- clientCredentials,
221
- // Required defaults
222
- visibility: 'unlisted',
223
- iconBackground: '#ffffff',
224
- // Additional
225
- resources: true,
226
- assets: true,
183
+ it('should throw an error if the user doesn’t have enough scope permissions', async () => {
184
+ const clientCredentials = await authorizeCLI('', testApp);
185
+ vi.useRealTimers();
186
+ await expect(() => publishApp({
187
+ path: resolveFixture('apps/test'),
188
+ organization: organization.id,
189
+ remote: testApp.defaults.baseURL,
190
+ clientCredentials,
191
+ // Required defaults
192
+ visibility: 'unlisted',
193
+ iconBackground: '#ffffff',
194
+ })).rejects.toThrow('Request failed with status code 401');
195
+ vi.useFakeTimers();
196
+ const app = await App.findOne();
197
+ expect(app).toBeNull();
227
198
  });
228
- vi.useFakeTimers();
229
- const app = await App.findOne();
230
- expect(app.toJSON()).toMatchInlineSnapshot({
231
- $created: expect.stringMatching(ISODateTimePattern),
232
- $updated: expect.stringMatching(ISODateTimePattern),
233
- iconUrl: expect.any(String),
234
- }, `
199
+ it('should not publish if dryRun is specified', async () => {
200
+ const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
201
+ await publishApp({
202
+ path: resolveFixture('apps/test'),
203
+ organization: organization.id,
204
+ remote: testApp.defaults.baseURL,
205
+ clientCredentials,
206
+ // Required defaults
207
+ visibility: 'unlisted',
208
+ iconBackground: '#ffffff',
209
+ dryRun: true,
210
+ });
211
+ const apps = await App.findAll();
212
+ expect(apps).toStrictEqual([]);
213
+ });
214
+ it('should publish app with resources and assets', async () => {
215
+ vi.useRealTimers();
216
+ const clientCredentials = await authorizeCLI('apps:write resources:write assets:write', testApp);
217
+ await publishApp({
218
+ path: resolveFixture('apps/test'),
219
+ organization: organization.id,
220
+ remote: testApp.defaults.baseURL,
221
+ clientCredentials,
222
+ // Required defaults
223
+ visibility: 'unlisted',
224
+ iconBackground: '#ffffff',
225
+ // Additional
226
+ resources: true,
227
+ assets: true,
228
+ });
229
+ vi.useFakeTimers();
230
+ const app = await App.findOne();
231
+ expect(app.toJSON()).toMatchInlineSnapshot({
232
+ $created: expect.stringMatching(ISODateTimePattern),
233
+ $updated: expect.stringMatching(ISODateTimePattern),
234
+ iconUrl: expect.any(String),
235
+ }, `
235
236
  {
236
237
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
237
238
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -321,26 +322,26 @@ describe('publishApp', () => {
321
322
  ",
322
323
  }
323
324
  `);
324
- expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
325
- expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
326
- const appBlockStyle = await AppBlockStyle.findOne();
327
- expect(appBlockStyle.style).toBe(`.tux {
325
+ expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
326
+ expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
327
+ const appBlockStyle = await AppBlockStyle.findOne();
328
+ expect(appBlockStyle.style).toBe(`.tux {
328
329
  color: rgb(0 0 0);
329
330
  }`);
330
- const appScreenshot = await AppScreenshot.findOne();
331
- expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
332
- const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
333
- expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
334
- ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
335
- ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
336
- ]);
337
- const resources = await Resource.findAll();
338
- expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
339
- {
340
- $created: expect.stringMatching(ISODateTimePattern),
341
- $updated: expect.stringMatching(ISODateTimePattern),
342
- },
343
- ], `
331
+ const appScreenshot = await AppScreenshot.findOne();
332
+ expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
333
+ const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
334
+ expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
335
+ ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
336
+ ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
337
+ ]);
338
+ const resources = await Resource.findAll();
339
+ expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
340
+ {
341
+ $created: expect.stringMatching(ISODateTimePattern),
342
+ $updated: expect.stringMatching(ISODateTimePattern),
343
+ },
344
+ ], `
344
345
  [
345
346
  {
346
347
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -350,42 +351,42 @@ describe('publishApp', () => {
350
351
  },
351
352
  ]
352
353
  `);
353
- const assets = await Asset.findAll();
354
- expect(assets.map((a) => a.data)).toStrictEqual([
355
- await readFixture('apps/test/assets/tux.png'),
356
- ]);
357
- });
358
- it('should publish app with runtime config', async () => {
359
- await AppCollection.create({
360
- name: 'test',
361
- expertName: 'Expert',
362
- expertProfileImage: Buffer.alloc(0),
363
- expertProfileImageMimeType: 'image/png',
364
- headerImage: Buffer.alloc(0),
365
- headerImageMimeType: 'image/png',
366
- OrganizationId: organization.id,
367
- visibility: 'public',
354
+ const assets = await Asset.findAll();
355
+ expect(assets.map((a) => a.data)).toStrictEqual([
356
+ await readFixture('apps/test/assets/tux.png'),
357
+ ]);
368
358
  });
369
- vi.useRealTimers();
370
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
371
- await publishApp({
372
- path: resolveFixture('apps/test'),
373
- organization: organization.id,
374
- remote: testApp.defaults.baseURL,
375
- clientCredentials,
376
- // Required defaults
377
- visibility: 'unlisted',
378
- iconBackground: '#ffffff',
379
- // Define context
380
- context: 'test',
381
- });
382
- vi.useFakeTimers();
383
- const app = await App.findOne();
384
- expect(app.toJSON()).toMatchInlineSnapshot({
385
- $created: expect.stringMatching(ISODateTimePattern),
386
- $updated: expect.stringMatching(ISODateTimePattern),
387
- iconUrl: expect.any(String),
388
- }, `
359
+ it('should publish app with runtime config', async () => {
360
+ await AppCollection.create({
361
+ name: 'test',
362
+ expertName: 'Expert',
363
+ expertProfileImage: Buffer.alloc(0),
364
+ expertProfileImageMimeType: 'image/png',
365
+ headerImage: Buffer.alloc(0),
366
+ headerImageMimeType: 'image/png',
367
+ OrganizationId: organization.id,
368
+ visibility: 'public',
369
+ });
370
+ vi.useRealTimers();
371
+ const clientCredentials = await authorizeCLI('apps:write resources:write assets:write', testApp);
372
+ await publishApp({
373
+ path: resolveFixture('apps/test'),
374
+ organization: organization.id,
375
+ remote: testApp.defaults.baseURL,
376
+ clientCredentials,
377
+ // Required defaults
378
+ visibility: 'unlisted',
379
+ iconBackground: '#ffffff',
380
+ // Define context
381
+ context: 'test',
382
+ });
383
+ vi.useFakeTimers();
384
+ const app = await App.findOne();
385
+ expect(app.toJSON()).toMatchInlineSnapshot({
386
+ $created: expect.stringMatching(ISODateTimePattern),
387
+ $updated: expect.stringMatching(ISODateTimePattern),
388
+ iconUrl: expect.any(String),
389
+ }, `
389
390
  {
390
391
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
391
392
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -475,30 +476,30 @@ describe('publishApp', () => {
475
476
  ",
476
477
  }
477
478
  `);
478
- expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
479
- expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
480
- const appBlockStyle = await AppBlockStyle.findOne();
481
- expect(appBlockStyle.style).toBe(`.tux {
479
+ expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
480
+ expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
481
+ const appBlockStyle = await AppBlockStyle.findOne();
482
+ expect(appBlockStyle.style).toBe(`.tux {
482
483
  color: rgb(0 0 0);
483
484
  }`);
484
- const appScreenshot = await AppScreenshot.findOne();
485
- expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
486
- const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
487
- expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
488
- ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
489
- ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
490
- ]);
491
- const resources = await Resource.findAll();
492
- expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
493
- {
494
- $created: expect.stringMatching(ISODateTimePattern),
495
- $updated: expect.stringMatching(ISODateTimePattern),
496
- },
497
- {
498
- $created: expect.stringMatching(ISODateTimePattern),
499
- $updated: expect.stringMatching(ISODateTimePattern),
500
- },
501
- ], `
485
+ const appScreenshot = await AppScreenshot.findOne();
486
+ expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
487
+ const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
488
+ expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
489
+ ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
490
+ ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
491
+ ]);
492
+ const resources = await Resource.findAll();
493
+ expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
494
+ {
495
+ $created: expect.stringMatching(ISODateTimePattern),
496
+ $updated: expect.stringMatching(ISODateTimePattern),
497
+ },
498
+ {
499
+ $created: expect.stringMatching(ISODateTimePattern),
500
+ $updated: expect.stringMatching(ISODateTimePattern),
501
+ },
502
+ ], `
502
503
  [
503
504
  {
504
505
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -515,38 +516,38 @@ describe('publishApp', () => {
515
516
  },
516
517
  ]
517
518
  `);
518
- const assets = await Asset.findAll();
519
- expect(assets.map((a) => a.data)).toStrictEqual([
520
- await readFixture('apps/test/assets/tux.png'),
521
- await readFixture('apps/test/assets/tux.png'),
522
- ]);
523
- const appCollectionApp = await AppCollectionApp.findOne();
524
- expect(appCollectionApp.AppId).toBe(1);
525
- expect(appCollectionApp.AppCollectionId).toBe(1);
526
- });
527
- it('should publish app with app variant patches applied', async () => {
528
- vi.useRealTimers();
529
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
530
- await publishApp({
531
- path: resolveFixture('apps/test'),
532
- organization: organization.id,
533
- remote: testApp.defaults.baseURL,
534
- clientCredentials,
535
- // Required defaults
536
- visibility: 'unlisted',
537
- iconBackground: '#ffffff',
538
- // Define app variant
539
- variant: 'tux',
540
- resources: true,
541
- assets: true,
519
+ const assets = await Asset.findAll();
520
+ expect(assets.map((a) => a.data)).toStrictEqual([
521
+ await readFixture('apps/test/assets/tux.png'),
522
+ await readFixture('apps/test/assets/tux.png'),
523
+ ]);
524
+ const appCollectionApp = await AppCollectionApp.findOne();
525
+ expect(appCollectionApp.AppId).toBe(1);
526
+ expect(appCollectionApp.AppCollectionId).toBe(1);
542
527
  });
543
- vi.useFakeTimers();
544
- const app = await App.findOne();
545
- expect(app.toJSON()).toMatchInlineSnapshot({
546
- $created: expect.stringMatching(ISODateTimePattern),
547
- $updated: expect.stringMatching(ISODateTimePattern),
548
- iconUrl: expect.any(String),
549
- }, `
528
+ it('should publish app with app variant patches applied', async () => {
529
+ vi.useRealTimers();
530
+ const clientCredentials = await authorizeCLI('apps:write resources:write assets:write', testApp);
531
+ await publishApp({
532
+ path: resolveFixture('apps/test'),
533
+ organization: organization.id,
534
+ remote: testApp.defaults.baseURL,
535
+ clientCredentials,
536
+ // Required defaults
537
+ visibility: 'unlisted',
538
+ iconBackground: '#ffffff',
539
+ // Define app variant
540
+ variant: 'tux',
541
+ resources: true,
542
+ assets: true,
543
+ });
544
+ vi.useFakeTimers();
545
+ const app = await App.findOne();
546
+ expect(app.toJSON()).toMatchInlineSnapshot({
547
+ $created: expect.stringMatching(ISODateTimePattern),
548
+ $updated: expect.stringMatching(ISODateTimePattern),
549
+ iconUrl: expect.any(String),
550
+ }, `
550
551
  {
551
552
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
552
553
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -630,25 +631,25 @@ describe('publishApp', () => {
630
631
  ",
631
632
  }
632
633
  `);
633
- expect(app.icon).toStrictEqual(await readFixture('apps/test/variants/tux/icon.png'));
634
- expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/variants/tux/maskable-icon.png'));
635
- const appBlockStyle = await AppBlockStyle.findOne();
636
- expect(appBlockStyle.style).toBe('.tux{color:rgb(1 2 3)}');
637
- const appScreenshot = await AppScreenshot.findOne();
638
- expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/variants/tux/screenshots/tux.png'));
639
- const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
640
- const messages = JSON.parse(String(await readFixture('apps/test/variants/tux/patches/messages.json')));
641
- expect(appMessages.map(({ language, messages: msgs }) => [language, msgs])).toStrictEqual([
642
- ['nl', messages.nl],
643
- ['en', messages.en],
644
- ]);
645
- const resources = await Resource.findAll();
646
- expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
647
- {
648
- $created: expect.stringMatching(ISODateTimePattern),
649
- $updated: expect.stringMatching(ISODateTimePattern),
650
- },
651
- ], `
634
+ expect(app.icon).toStrictEqual(await readFixture('apps/test/variants/tux/icon.png'));
635
+ expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/variants/tux/maskable-icon.png'));
636
+ const appBlockStyle = await AppBlockStyle.findOne();
637
+ expect(appBlockStyle.style).toBe('.tux{color:rgb(1 2 3)}');
638
+ const appScreenshot = await AppScreenshot.findOne();
639
+ expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/variants/tux/screenshots/tux.png'));
640
+ const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
641
+ const messages = JSON.parse(String(await readFixture('apps/test/variants/tux/patches/messages.json')));
642
+ expect(appMessages.map(({ language, messages: msgs }) => [language, msgs])).toStrictEqual([
643
+ ['nl', messages.nl],
644
+ ['en', messages.en],
645
+ ]);
646
+ const resources = await Resource.findAll();
647
+ expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
648
+ {
649
+ $created: expect.stringMatching(ISODateTimePattern),
650
+ $updated: expect.stringMatching(ISODateTimePattern),
651
+ },
652
+ ], `
652
653
  [
653
654
  {
654
655
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -658,202 +659,203 @@ describe('publishApp', () => {
658
659
  },
659
660
  ]
660
661
  `);
661
- const assets = await Asset.findAll();
662
- expect(assets.map((a) => a.data)).toStrictEqual([
663
- await readFixture('apps/test/variants/tux/assets/small-tux.png'),
664
- ]);
665
- });
666
- it('should publish app variables and secrets', async () => {
667
- vi.useRealTimers();
668
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
669
- process.env.TEST_VARIABLE_1 = 'test-variable-1';
670
- process.env.TEST_VARIABLE_2 = 'test-variable-2';
671
- process.env.TEST_SECRET = 'test-secret';
672
- process.env.TEST_SERVICE_URL_PATTERNS = 'http://localhost:1234';
673
- process.env.TEST_SERVICE_IDENTIFIER = 'Authorization';
674
- process.env.TEST_SERVICE_SECRET = 'secret';
675
- process.env.TEST_SAML_IDP_CERTIFICATE = 'certificate';
676
- process.env.TEST_SAML_ENTITY_ID = 'http://localhost:1234';
677
- process.env.TEST_SAML_SSO_URL = 'http://localhost:1234';
678
- process.env.TEST_OAUTH2_AUTHORIZATION_URL = 'http://localhost:1234';
679
- process.env.TEST_OAUTH2_TOKEN_URL = 'http://localhost:1234';
680
- process.env.TEST_OAUTH2_USER_INFO_URL = 'http://localhost:1234';
681
- process.env.TEST_OAUTH2_CLIENT_ID = 'id';
682
- process.env.TEST_OAUTH2_CLIENT_SECRET = 'secret';
683
- process.env.TEST_SCIM_TOKEN = 'token';
684
- process.env.TEST_SSL_KEY = 'key';
685
- process.env.TEST_SSL_CERTIFICATE = 'certificate';
686
- await publishApp({
687
- path: resolveFixture('apps/test'),
688
- organization: organization.id,
689
- remote: testApp.defaults.baseURL,
690
- clientCredentials,
691
- visibility: 'unlisted',
692
- iconBackground: '#ffffff',
662
+ const assets = await Asset.findAll();
663
+ expect(assets.map((a) => a.data)).toStrictEqual([
664
+ await readFixture('apps/test/variants/tux/assets/small-tux.png'),
665
+ ]);
693
666
  });
694
- vi.useFakeTimers();
695
- const app = await App.findOne({
696
- attributes: ['scimEnabled', 'scimToken', 'sslKey', 'sslCertificate'],
697
- where: {
667
+ it('should publish app variables and secrets', async () => {
668
+ vi.useRealTimers();
669
+ const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
670
+ process.env.TEST_VARIABLE_1 = 'test-variable-1';
671
+ process.env.TEST_VARIABLE_2 = 'test-variable-2';
672
+ process.env.TEST_SECRET = 'test-secret';
673
+ process.env.TEST_SERVICE_URL_PATTERNS = 'http://localhost:1234';
674
+ process.env.TEST_SERVICE_IDENTIFIER = 'Authorization';
675
+ process.env.TEST_SERVICE_SECRET = 'secret';
676
+ process.env.TEST_SAML_IDP_CERTIFICATE = 'certificate';
677
+ process.env.TEST_SAML_ENTITY_ID = 'http://localhost:1234';
678
+ process.env.TEST_SAML_SSO_URL = 'http://localhost:1234';
679
+ process.env.TEST_OAUTH2_AUTHORIZATION_URL = 'http://localhost:1234';
680
+ process.env.TEST_OAUTH2_TOKEN_URL = 'http://localhost:1234';
681
+ process.env.TEST_OAUTH2_USER_INFO_URL = 'http://localhost:1234';
682
+ process.env.TEST_OAUTH2_CLIENT_ID = 'id';
683
+ process.env.TEST_OAUTH2_CLIENT_SECRET = 'secret';
684
+ process.env.TEST_SCIM_TOKEN = 'token';
685
+ process.env.TEST_SSL_KEY = 'key';
686
+ process.env.TEST_SSL_CERTIFICATE = 'certificate';
687
+ await publishApp({
688
+ path: resolveFixture('apps/test'),
689
+ organization: organization.id,
690
+ remote: testApp.defaults.baseURL,
691
+ clientCredentials,
692
+ visibility: 'unlisted',
693
+ iconBackground: '#ffffff',
694
+ });
695
+ vi.useFakeTimers();
696
+ const app = await App.findOne({
697
+ attributes: ['scimEnabled', 'scimToken', 'sslKey', 'sslCertificate'],
698
+ where: {
699
+ id: 1,
700
+ },
701
+ });
702
+ expect({
703
+ scimEnabled: app.scimEnabled,
704
+ scimToken: app.scimToken,
705
+ sslKey: app.sslKey,
706
+ sslCertificate: app.sslCertificate,
707
+ }).toStrictEqual({
708
+ scimEnabled: true,
709
+ scimToken: expect.any(Buffer),
710
+ sslKey: 'key',
711
+ sslCertificate: 'certificate',
712
+ });
713
+ const appVariables = await AppVariable.findAll({
714
+ attributes: ['name', 'value'],
715
+ where: {
716
+ AppId: 1,
717
+ },
718
+ });
719
+ expect(appVariables[0].toJSON()).toStrictEqual({
720
+ name: 'test-variable-inline',
721
+ value: 'inline',
722
+ });
723
+ expect(appVariables[1].toJSON()).toStrictEqual({
724
+ name: 'test-variable',
725
+ value: 'test-variable-1.test-variable-2',
726
+ });
727
+ const appServiceSecret = await AppServiceSecret.findOne({
728
+ attributes: ['name', 'authenticationMethod', 'urlPatterns', 'identifier', 'secret'],
729
+ where: {
730
+ AppId: 1,
731
+ },
732
+ });
733
+ expect(appServiceSecret.toJSON()).toStrictEqual({
734
+ name: 'test-service-secret',
735
+ authenticationMethod: 'custom-header',
736
+ urlPatterns: 'http://localhost:1234',
737
+ identifier: 'Authorization',
738
+ secret: expect.any(Buffer),
739
+ });
740
+ const appSamlSecret = await AppSamlSecret.findOne({
741
+ attributes: [
742
+ 'name',
743
+ 'icon',
744
+ 'nameAttribute',
745
+ 'emailAttribute',
746
+ 'idpCertificate',
747
+ 'entityId',
748
+ 'ssoUrl',
749
+ ],
750
+ where: {
751
+ AppId: 1,
752
+ },
753
+ });
754
+ expect(appSamlSecret.toJSON()).toStrictEqual({
755
+ emailAttribute: 'email',
756
+ emailVerifiedAttribute: null,
757
+ entityId: 'http://localhost:1234',
758
+ icon: 'redhat',
698
759
  id: 1,
699
- },
700
- });
701
- expect({
702
- scimEnabled: app.scimEnabled,
703
- scimToken: app.scimToken,
704
- sslKey: app.sslKey,
705
- sslCertificate: app.sslCertificate,
706
- }).toStrictEqual({
707
- scimEnabled: true,
708
- scimToken: expect.any(Buffer),
709
- sslKey: 'key',
710
- sslCertificate: 'certificate',
711
- });
712
- const appVariables = await AppVariable.findAll({
713
- attributes: ['name', 'value'],
714
- where: {
715
- AppId: 1,
716
- },
717
- });
718
- expect(appVariables[0].toJSON()).toStrictEqual({
719
- name: 'test-variable-inline',
720
- value: 'inline',
721
- });
722
- expect(appVariables[1].toJSON()).toStrictEqual({
723
- name: 'test-variable',
724
- value: 'test-variable-1.test-variable-2',
725
- });
726
- const appServiceSecret = await AppServiceSecret.findOne({
727
- attributes: ['name', 'authenticationMethod', 'urlPatterns', 'identifier', 'secret'],
728
- where: {
729
- AppId: 1,
730
- },
731
- });
732
- expect(appServiceSecret.toJSON()).toStrictEqual({
733
- name: 'test-service-secret',
734
- authenticationMethod: 'custom-header',
735
- urlPatterns: 'http://localhost:1234',
736
- identifier: 'Authorization',
737
- secret: expect.any(Buffer),
738
- });
739
- const appSamlSecret = await AppSamlSecret.findOne({
740
- attributes: [
741
- 'name',
742
- 'icon',
743
- 'nameAttribute',
744
- 'emailAttribute',
745
- 'idpCertificate',
746
- 'entityId',
747
- 'ssoUrl',
748
- ],
749
- where: {
750
- AppId: 1,
751
- },
752
- });
753
- expect(appSamlSecret.toJSON()).toStrictEqual({
754
- emailAttribute: 'email',
755
- entityId: 'http://localhost:1234',
756
- icon: 'redhat',
757
- id: 1,
758
- idpCertificate: 'certificate',
759
- name: 'test-saml-secret',
760
- nameAttribute: 'name',
761
- ssoUrl: 'http://localhost:1234',
762
- spCertificate: expect.any(String),
763
- });
764
- const appOauth2Secret = await AppOAuth2Secret.findOne({
765
- attributes: [
766
- 'name',
767
- 'icon',
768
- 'scope',
769
- 'remapper',
770
- 'authorizationUrl',
771
- 'tokenUrl',
772
- 'userInfoUrl',
773
- 'clientId',
774
- 'clientSecret',
775
- ],
776
- where: {
777
- AppId: 1,
778
- },
779
- });
780
- expect({
781
- authorizationUrl: appOauth2Secret.authorizationUrl,
782
- clientId: appOauth2Secret.clientId,
783
- clientSecret: appOauth2Secret.clientSecret,
784
- icon: appOauth2Secret.icon,
785
- name: appOauth2Secret.name,
786
- remapper: appOauth2Secret.remapper,
787
- scope: appOauth2Secret.scope,
788
- tokenUrl: appOauth2Secret.tokenUrl,
789
- userInfoUrl: appOauth2Secret.userInfoUrl,
790
- }).toStrictEqual({
791
- authorizationUrl: 'http://localhost:1234',
792
- clientId: 'id',
793
- clientSecret: 'secret',
794
- icon: 'redhat',
795
- name: 'test-oauth2-secret',
796
- remapper: [{ prop: 'email' }],
797
- scope: 'email openid profile',
798
- tokenUrl: 'http://localhost:1234',
799
- userInfoUrl: 'http://localhost:1234',
800
- });
801
- });
802
- it('should validate and throw if there’s an error before publishing an app', async () => {
803
- await BlockVersion.destroy({
804
- where: {
805
- version: '0.0.0',
806
- OrganizationId: 'appsemble',
807
- name: 'test',
808
- },
760
+ idpCertificate: 'certificate',
761
+ name: 'test-saml-secret',
762
+ nameAttribute: 'name',
763
+ ssoUrl: 'http://localhost:1234',
764
+ spCertificate: expect.any(String),
765
+ });
766
+ const appOauth2Secret = await AppOAuth2Secret.findOne({
767
+ attributes: [
768
+ 'name',
769
+ 'icon',
770
+ 'scope',
771
+ 'remapper',
772
+ 'authorizationUrl',
773
+ 'tokenUrl',
774
+ 'userInfoUrl',
775
+ 'clientId',
776
+ 'clientSecret',
777
+ ],
778
+ where: {
779
+ AppId: 1,
780
+ },
781
+ });
782
+ expect({
783
+ authorizationUrl: appOauth2Secret.authorizationUrl,
784
+ clientId: appOauth2Secret.clientId,
785
+ clientSecret: appOauth2Secret.clientSecret,
786
+ icon: appOauth2Secret.icon,
787
+ name: appOauth2Secret.name,
788
+ remapper: appOauth2Secret.remapper,
789
+ scope: appOauth2Secret.scope,
790
+ tokenUrl: appOauth2Secret.tokenUrl,
791
+ userInfoUrl: appOauth2Secret.userInfoUrl,
792
+ }).toStrictEqual({
793
+ authorizationUrl: 'http://localhost:1234',
794
+ clientId: 'id',
795
+ clientSecret: 'secret',
796
+ icon: 'redhat',
797
+ name: 'test-oauth2-secret',
798
+ remapper: [{ prop: 'email' }],
799
+ scope: 'email openid profile',
800
+ tokenUrl: 'http://localhost:1234',
801
+ userInfoUrl: 'http://localhost:1234',
802
+ });
809
803
  });
810
- vi.useRealTimers();
811
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
812
- await expect(() => publishApp({
813
- path: resolveFixture('apps/test'),
814
- organization: organization.id,
815
- remote: testApp.defaults.baseURL,
816
- clientCredentials,
817
- // Required defaults
818
- visibility: 'unlisted',
819
- iconBackground: '#ffffff',
820
- })).rejects.toThrow('is not a known block type');
821
- const app = await App.findOne();
822
- expect(app).toBeNull();
823
- });
824
- });
825
- describe('updateApp', () => {
826
- let app;
827
- beforeEach(async () => {
828
- app = await App.create({
829
- path: 'test-app',
830
- definition: { name: 'Test App', defaultPage: 'Test Page' },
831
- vapidPublicKey: 'a',
832
- vapidPrivateKey: 'b',
833
- visibility: 'public',
834
- OrganizationId: organization.id,
804
+ it('should validate and throw if there’s an error before publishing an app', async () => {
805
+ await BlockVersion.destroy({
806
+ where: {
807
+ version: '0.0.0',
808
+ OrganizationId: 'appsemble',
809
+ name: 'test',
810
+ },
811
+ });
812
+ vi.useRealTimers();
813
+ const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
814
+ await expect(() => publishApp({
815
+ path: resolveFixture('apps/test'),
816
+ organization: organization.id,
817
+ remote: testApp.defaults.baseURL,
818
+ clientCredentials,
819
+ // Required defaults
820
+ visibility: 'unlisted',
821
+ iconBackground: '#ffffff',
822
+ })).rejects.toThrow('is not a known block type');
823
+ const app = await App.findOne();
824
+ expect(app).toBeNull();
835
825
  });
836
826
  });
837
- it('should update app', async () => {
838
- vi.useRealTimers();
839
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
840
- await updateApp({
841
- id: app.id,
842
- path: resolveFixture('apps/test'),
843
- remote: testApp.defaults.baseURL,
844
- clientCredentials,
845
- // Required defaults
846
- visibility: 'unlisted',
847
- iconBackground: '#ffffff',
848
- force: false,
827
+ describe('updateApp', () => {
828
+ let app;
829
+ beforeEach(async () => {
830
+ app = await App.create({
831
+ path: 'test-app',
832
+ definition: { name: 'Test App', defaultPage: 'Test Page' },
833
+ vapidPublicKey: 'a',
834
+ vapidPrivateKey: 'b',
835
+ visibility: 'public',
836
+ OrganizationId: organization.id,
837
+ });
849
838
  });
850
- vi.useFakeTimers();
851
- await app.reload();
852
- expect(app.toJSON()).toMatchInlineSnapshot({
853
- $created: expect.stringMatching(ISODateTimePattern),
854
- $updated: expect.stringMatching(ISODateTimePattern),
855
- iconUrl: expect.any(String),
856
- }, `
839
+ it('should update app', async () => {
840
+ vi.useRealTimers();
841
+ const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
842
+ await updateApp({
843
+ id: app.id,
844
+ path: resolveFixture('apps/test'),
845
+ remote: testApp.defaults.baseURL,
846
+ clientCredentials,
847
+ // Required defaults
848
+ visibility: 'unlisted',
849
+ iconBackground: '#ffffff',
850
+ force: false,
851
+ });
852
+ vi.useFakeTimers();
853
+ await app.reload();
854
+ expect(app.toJSON()).toMatchInlineSnapshot({
855
+ $created: expect.stringMatching(ISODateTimePattern),
856
+ $updated: expect.stringMatching(ISODateTimePattern),
857
+ iconUrl: expect.any(String),
858
+ }, `
857
859
  {
858
860
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
859
861
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -943,71 +945,71 @@ describe('updateApp', () => {
943
945
  ",
944
946
  }
945
947
  `);
946
- expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
947
- expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
948
- const appBlockStyle = await AppBlockStyle.findOne();
949
- expect(appBlockStyle.style).toBe(`.tux {
948
+ expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
949
+ expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
950
+ const appBlockStyle = await AppBlockStyle.findOne();
951
+ expect(appBlockStyle.style).toBe(`.tux {
950
952
  color: rgb(0 0 0);
951
953
  }`);
952
- const appScreenshot = await AppScreenshot.findOne();
953
- expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
954
- const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
955
- expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
956
- ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
957
- ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
958
- ]);
959
- const resource = await Resource.findAll();
960
- expect(resource).toStrictEqual([]);
961
- const asset = await Asset.findAll();
962
- expect(asset).toStrictEqual([]);
963
- });
964
- it('should throw an error if the user doesn’t have enough scope permissions', async () => {
965
- const clientCredentials = await authorizeCLI('', testApp);
966
- vi.useRealTimers();
967
- await expect(() => updateApp({
968
- id: app.id,
969
- force: false,
970
- path: resolveFixture('apps/test'),
971
- remote: testApp.defaults.baseURL,
972
- clientCredentials,
973
- // Required defaults
974
- visibility: 'unlisted',
975
- iconBackground: '#ffffff',
976
- })).rejects.toThrow('Request failed with status code 401');
977
- vi.useFakeTimers();
978
- await app.reload();
979
- expect(app).toMatchObject({
980
- path: 'test-app',
981
- definition: { name: 'Test App', defaultPage: 'Test Page' },
982
- vapidPublicKey: 'a',
983
- vapidPrivateKey: 'b',
984
- visibility: 'public',
985
- OrganizationId: organization.id,
954
+ const appScreenshot = await AppScreenshot.findOne();
955
+ expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
956
+ const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
957
+ expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
958
+ ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
959
+ ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
960
+ ]);
961
+ const resource = await Resource.findAll();
962
+ expect(resource).toStrictEqual([]);
963
+ const asset = await Asset.findAll();
964
+ expect(asset).toStrictEqual([]);
986
965
  });
987
- });
988
- it('should update app with resources and assets', async () => {
989
- vi.useRealTimers();
990
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
991
- await updateApp({
992
- id: app.id,
993
- path: resolveFixture('apps/test'),
994
- remote: testApp.defaults.baseURL,
995
- clientCredentials,
996
- // Required defaults
997
- visibility: 'unlisted',
998
- iconBackground: '#ffffff',
999
- force: false,
1000
- // Additional
1001
- resources: true,
1002
- assets: true,
966
+ it('should throw an error if the user doesn’t have enough scope permissions', async () => {
967
+ const clientCredentials = await authorizeCLI('', testApp);
968
+ vi.useRealTimers();
969
+ await expect(() => updateApp({
970
+ id: app.id,
971
+ force: false,
972
+ path: resolveFixture('apps/test'),
973
+ remote: testApp.defaults.baseURL,
974
+ clientCredentials,
975
+ // Required defaults
976
+ visibility: 'unlisted',
977
+ iconBackground: '#ffffff',
978
+ })).rejects.toThrow('Request failed with status code 401');
979
+ vi.useFakeTimers();
980
+ await app.reload();
981
+ expect(app).toMatchObject({
982
+ path: 'test-app',
983
+ definition: { name: 'Test App', defaultPage: 'Test Page' },
984
+ vapidPublicKey: 'a',
985
+ vapidPrivateKey: 'b',
986
+ visibility: 'public',
987
+ OrganizationId: organization.id,
988
+ });
1003
989
  });
1004
- vi.useFakeTimers();
1005
- await app.reload();
1006
- expect(app.toJSON()).toMatchInlineSnapshot({
1007
- $created: expect.stringMatching(ISODateTimePattern),
1008
- $updated: expect.stringMatching(ISODateTimePattern),
1009
- iconUrl: expect.any(String),
1010
- }, `
990
+ it('should update app with resources and assets', async () => {
991
+ vi.useRealTimers();
992
+ const clientCredentials = await authorizeCLI('apps:write resources:write assets:write', testApp);
993
+ await updateApp({
994
+ id: app.id,
995
+ path: resolveFixture('apps/test'),
996
+ remote: testApp.defaults.baseURL,
997
+ clientCredentials,
998
+ // Required defaults
999
+ visibility: 'unlisted',
1000
+ iconBackground: '#ffffff',
1001
+ force: false,
1002
+ // Additional
1003
+ resources: true,
1004
+ assets: true,
1005
+ });
1006
+ vi.useFakeTimers();
1007
+ await app.reload();
1008
+ expect(app.toJSON()).toMatchInlineSnapshot({
1009
+ $created: expect.stringMatching(ISODateTimePattern),
1010
+ $updated: expect.stringMatching(ISODateTimePattern),
1011
+ iconUrl: expect.any(String),
1012
+ }, `
1011
1013
  {
1012
1014
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
1013
1015
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1097,26 +1099,26 @@ describe('updateApp', () => {
1097
1099
  ",
1098
1100
  }
1099
1101
  `);
1100
- expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
1101
- expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
1102
- const appBlockStyle = await AppBlockStyle.findOne();
1103
- expect(appBlockStyle.style).toBe(`.tux {
1102
+ expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
1103
+ expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
1104
+ const appBlockStyle = await AppBlockStyle.findOne();
1105
+ expect(appBlockStyle.style).toBe(`.tux {
1104
1106
  color: rgb(0 0 0);
1105
1107
  }`);
1106
- const appScreenshot = await AppScreenshot.findOne();
1107
- expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
1108
- const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
1109
- expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
1110
- ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
1111
- ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
1112
- ]);
1113
- const resources = await Resource.findAll();
1114
- expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
1115
- {
1116
- $created: expect.stringMatching(ISODateTimePattern),
1117
- $updated: expect.stringMatching(ISODateTimePattern),
1118
- },
1119
- ], `
1108
+ const appScreenshot = await AppScreenshot.findOne();
1109
+ expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
1110
+ const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
1111
+ expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
1112
+ ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
1113
+ ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
1114
+ ]);
1115
+ const resources = await Resource.findAll();
1116
+ expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
1117
+ {
1118
+ $created: expect.stringMatching(ISODateTimePattern),
1119
+ $updated: expect.stringMatching(ISODateTimePattern),
1120
+ },
1121
+ ], `
1120
1122
  [
1121
1123
  {
1122
1124
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1126,43 +1128,43 @@ describe('updateApp', () => {
1126
1128
  },
1127
1129
  ]
1128
1130
  `);
1129
- const assets = await Asset.findAll();
1130
- expect(assets.map((a) => a.data)).toStrictEqual([
1131
- await readFixture('apps/test/assets/tux.png'),
1132
- ]);
1133
- });
1134
- it('should update app with runtime config', async () => {
1135
- await AppCollection.create({
1136
- name: 'test',
1137
- expertName: 'Expert',
1138
- expertProfileImage: Buffer.alloc(0),
1139
- expertProfileImageMimeType: 'image/png',
1140
- headerImage: Buffer.alloc(0),
1141
- headerImageMimeType: 'image/png',
1142
- OrganizationId: organization.id,
1143
- visibility: 'public',
1131
+ const assets = await Asset.findAll();
1132
+ expect(assets.map((a) => a.data)).toStrictEqual([
1133
+ await readFixture('apps/test/assets/tux.png'),
1134
+ ]);
1144
1135
  });
1145
- vi.useRealTimers();
1146
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
1147
- await updateApp({
1148
- path: resolveFixture('apps/test'),
1149
- id: app.id,
1150
- remote: testApp.defaults.baseURL,
1151
- clientCredentials,
1152
- // Required defaults
1153
- visibility: 'unlisted',
1154
- iconBackground: '#ffffff',
1155
- force: false,
1156
- // Define context
1157
- context: 'test',
1158
- });
1159
- vi.useFakeTimers();
1160
- await app.reload();
1161
- expect(app.toJSON()).toMatchInlineSnapshot({
1162
- $created: expect.stringMatching(ISODateTimePattern),
1163
- $updated: expect.stringMatching(ISODateTimePattern),
1164
- iconUrl: expect.any(String),
1165
- }, `
1136
+ it('should update app with runtime config', async () => {
1137
+ await AppCollection.create({
1138
+ name: 'test',
1139
+ expertName: 'Expert',
1140
+ expertProfileImage: Buffer.alloc(0),
1141
+ expertProfileImageMimeType: 'image/png',
1142
+ headerImage: Buffer.alloc(0),
1143
+ headerImageMimeType: 'image/png',
1144
+ OrganizationId: organization.id,
1145
+ visibility: 'public',
1146
+ });
1147
+ vi.useRealTimers();
1148
+ const clientCredentials = await authorizeCLI('apps:write resources:write assets:write', testApp);
1149
+ await updateApp({
1150
+ path: resolveFixture('apps/test'),
1151
+ id: app.id,
1152
+ remote: testApp.defaults.baseURL,
1153
+ clientCredentials,
1154
+ // Required defaults
1155
+ visibility: 'unlisted',
1156
+ iconBackground: '#ffffff',
1157
+ force: false,
1158
+ // Define context
1159
+ context: 'test',
1160
+ });
1161
+ vi.useFakeTimers();
1162
+ await app.reload();
1163
+ expect(app.toJSON()).toMatchInlineSnapshot({
1164
+ $created: expect.stringMatching(ISODateTimePattern),
1165
+ $updated: expect.stringMatching(ISODateTimePattern),
1166
+ iconUrl: expect.any(String),
1167
+ }, `
1166
1168
  {
1167
1169
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
1168
1170
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1252,30 +1254,30 @@ describe('updateApp', () => {
1252
1254
  ",
1253
1255
  }
1254
1256
  `);
1255
- expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
1256
- expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
1257
- const appBlockStyle = await AppBlockStyle.findOne();
1258
- expect(appBlockStyle.style).toBe(`.tux {
1257
+ expect(app.icon).toStrictEqual(await readFixture('apps/test/icon.png'));
1258
+ expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/maskable-icon.png'));
1259
+ const appBlockStyle = await AppBlockStyle.findOne();
1260
+ expect(appBlockStyle.style).toBe(`.tux {
1259
1261
  color: rgb(0 0 0);
1260
1262
  }`);
1261
- const appScreenshot = await AppScreenshot.findOne();
1262
- expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
1263
- const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
1264
- expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
1265
- ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
1266
- ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
1267
- ]);
1268
- const resources = await Resource.findAll();
1269
- expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
1270
- {
1271
- $created: expect.stringMatching(ISODateTimePattern),
1272
- $updated: expect.stringMatching(ISODateTimePattern),
1273
- },
1274
- {
1275
- $created: expect.stringMatching(ISODateTimePattern),
1276
- $updated: expect.stringMatching(ISODateTimePattern),
1277
- },
1278
- ], `
1263
+ const appScreenshot = await AppScreenshot.findOne();
1264
+ expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/screenshots/test_en-us.png'));
1265
+ const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
1266
+ expect(appMessages.map(({ language, messages }) => [language, messages])).toStrictEqual([
1267
+ ['nl', JSON.parse(String(await readFixture('apps/test/i18n/nl.json')))],
1268
+ ['en', JSON.parse(String(await readFixture('apps/test/i18n/en.json')))],
1269
+ ]);
1270
+ const resources = await Resource.findAll();
1271
+ expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
1272
+ {
1273
+ $created: expect.stringMatching(ISODateTimePattern),
1274
+ $updated: expect.stringMatching(ISODateTimePattern),
1275
+ },
1276
+ {
1277
+ $created: expect.stringMatching(ISODateTimePattern),
1278
+ $updated: expect.stringMatching(ISODateTimePattern),
1279
+ },
1280
+ ], `
1279
1281
  [
1280
1282
  {
1281
1283
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1292,40 +1294,40 @@ describe('updateApp', () => {
1292
1294
  },
1293
1295
  ]
1294
1296
  `);
1295
- const assets = await Asset.findAll();
1296
- expect(assets.map((a) => a.data)).toStrictEqual([
1297
- await readFixture('apps/test/assets/tux.png'),
1298
- await readFixture('apps/test/assets/tux.png'),
1299
- ]);
1300
- // TODO: not yet implemented
1301
- // const appCollectionApp = await AppCollectionApp.findOne();
1302
- // expect(appCollectionApp.AppId).toBe(1);
1303
- // expect(appCollectionApp.AppCollectionId).toBe(1);
1304
- });
1305
- it('should update app with app variant patches applied', async () => {
1306
- vi.useRealTimers();
1307
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
1308
- await updateApp({
1309
- path: resolveFixture('apps/test'),
1310
- id: app.id,
1311
- remote: testApp.defaults.baseURL,
1312
- clientCredentials,
1313
- // Required defaults
1314
- visibility: 'unlisted',
1315
- iconBackground: '#ffffff',
1316
- force: false,
1317
- // Define app variant
1318
- variant: 'tux',
1319
- resources: true,
1320
- assets: true,
1297
+ const assets = await Asset.findAll();
1298
+ expect(assets.map((a) => a.data)).toStrictEqual([
1299
+ await readFixture('apps/test/assets/tux.png'),
1300
+ await readFixture('apps/test/assets/tux.png'),
1301
+ ]);
1302
+ // TODO: not yet implemented
1303
+ // const appCollectionApp = await AppCollectionApp.findOne();
1304
+ // expect(appCollectionApp.AppId).toBe(1);
1305
+ // expect(appCollectionApp.AppCollectionId).toBe(1);
1321
1306
  });
1322
- vi.useFakeTimers();
1323
- await app.reload();
1324
- expect(app.toJSON()).toMatchInlineSnapshot({
1325
- $created: expect.stringMatching(ISODateTimePattern),
1326
- $updated: expect.stringMatching(ISODateTimePattern),
1327
- iconUrl: expect.any(String),
1328
- }, `
1307
+ it('should update app with app variant patches applied', async () => {
1308
+ vi.useRealTimers();
1309
+ const clientCredentials = await authorizeCLI('apps:write resources:write assets:write', testApp);
1310
+ await updateApp({
1311
+ path: resolveFixture('apps/test'),
1312
+ id: app.id,
1313
+ remote: testApp.defaults.baseURL,
1314
+ clientCredentials,
1315
+ // Required defaults
1316
+ visibility: 'unlisted',
1317
+ iconBackground: '#ffffff',
1318
+ force: false,
1319
+ // Define app variant
1320
+ variant: 'tux',
1321
+ resources: true,
1322
+ assets: true,
1323
+ });
1324
+ vi.useFakeTimers();
1325
+ await app.reload();
1326
+ expect(app.toJSON()).toMatchInlineSnapshot({
1327
+ $created: expect.stringMatching(ISODateTimePattern),
1328
+ $updated: expect.stringMatching(ISODateTimePattern),
1329
+ iconUrl: expect.any(String),
1330
+ }, `
1329
1331
  {
1330
1332
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
1331
1333
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1409,25 +1411,25 @@ describe('updateApp', () => {
1409
1411
  ",
1410
1412
  }
1411
1413
  `);
1412
- expect(app.icon).toStrictEqual(await readFixture('apps/test/variants/tux/icon.png'));
1413
- expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/variants/tux/maskable-icon.png'));
1414
- const appBlockStyle = await AppBlockStyle.findOne();
1415
- expect(appBlockStyle.style).toBe('.tux{color:rgb(1 2 3)}');
1416
- const appScreenshot = await AppScreenshot.findOne();
1417
- expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/variants/tux/screenshots/tux.png'));
1418
- const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
1419
- const messages = JSON.parse(String(await readFixture('apps/test/variants/tux/patches/messages.json')));
1420
- expect(appMessages.map(({ language, messages: msgs }) => [language, msgs])).toStrictEqual([
1421
- ['nl', messages.nl],
1422
- ['en', messages.en],
1423
- ]);
1424
- const resources = await Resource.findAll();
1425
- expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
1426
- {
1427
- $created: expect.stringMatching(ISODateTimePattern),
1428
- $updated: expect.stringMatching(ISODateTimePattern),
1429
- },
1430
- ], `
1414
+ expect(app.icon).toStrictEqual(await readFixture('apps/test/variants/tux/icon.png'));
1415
+ expect(app.maskableIcon).toStrictEqual(await readFixture('apps/test/variants/tux/maskable-icon.png'));
1416
+ const appBlockStyle = await AppBlockStyle.findOne();
1417
+ expect(appBlockStyle.style).toBe('.tux{color:rgb(1 2 3)}');
1418
+ const appScreenshot = await AppScreenshot.findOne();
1419
+ expect(appScreenshot.screenshot).toStrictEqual(await readFixture('apps/test/variants/tux/screenshots/tux.png'));
1420
+ const appMessages = await AppMessages.findAll({ order: [['language', 'DESC']] });
1421
+ const messages = JSON.parse(String(await readFixture('apps/test/variants/tux/patches/messages.json')));
1422
+ expect(appMessages.map(({ language, messages: msgs }) => [language, msgs])).toStrictEqual([
1423
+ ['nl', messages.nl],
1424
+ ['en', messages.en],
1425
+ ]);
1426
+ const resources = await Resource.findAll();
1427
+ expect(resources.map((r) => r.toJSON())).toMatchInlineSnapshot([
1428
+ {
1429
+ $created: expect.stringMatching(ISODateTimePattern),
1430
+ $updated: expect.stringMatching(ISODateTimePattern),
1431
+ },
1432
+ ], `
1431
1433
  [
1432
1434
  {
1433
1435
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1437,556 +1439,557 @@ describe('updateApp', () => {
1437
1439
  },
1438
1440
  ]
1439
1441
  `);
1440
- const assets = await Asset.findAll();
1441
- expect(assets.map((a) => a.data)).toStrictEqual([
1442
- await readFixture('apps/test/variants/tux/assets/small-tux.png'),
1443
- ]);
1444
- });
1445
- it('should update app variables and secrets', async () => {
1446
- vi.useRealTimers();
1447
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
1448
- process.env.TEST_VARIABLE_1 = 'test-variable-1';
1449
- process.env.TEST_VARIABLE_2 = 'test-variable-2';
1450
- process.env.TEST_SECRET = 'test-secret';
1451
- process.env.TEST_SERVICE_URL_PATTERNS = 'http://localhost:1234';
1452
- process.env.TEST_SERVICE_IDENTIFIER = 'Authorization';
1453
- process.env.TEST_SERVICE_SECRET = 'secret';
1454
- process.env.TEST_SAML_IDP_CERTIFICATE = 'certificate';
1455
- process.env.TEST_SAML_ENTITY_ID = 'http://localhost:1234';
1456
- process.env.TEST_SAML_SSO_URL = 'http://localhost:1234';
1457
- process.env.TEST_OAUTH2_AUTHORIZATION_URL = 'http://localhost:1234';
1458
- process.env.TEST_OAUTH2_TOKEN_URL = 'http://localhost:1234';
1459
- process.env.TEST_OAUTH2_USER_INFO_URL = 'http://localhost:1234';
1460
- process.env.TEST_OAUTH2_CLIENT_ID = 'id';
1461
- process.env.TEST_OAUTH2_CLIENT_SECRET = 'secret';
1462
- process.env.TEST_SCIM_TOKEN = 'token';
1463
- process.env.TEST_SSL_KEY = 'key';
1464
- process.env.TEST_SSL_CERTIFICATE = 'certificate';
1465
- await updateApp({
1466
- id: 1,
1467
- path: resolveFixture('apps/test'),
1468
- remote: testApp.defaults.baseURL,
1469
- clientCredentials,
1470
- visibility: 'unlisted',
1471
- iconBackground: '#ffffff',
1472
- force: true,
1442
+ const assets = await Asset.findAll();
1443
+ expect(assets.map((a) => a.data)).toStrictEqual([
1444
+ await readFixture('apps/test/variants/tux/assets/small-tux.png'),
1445
+ ]);
1473
1446
  });
1474
- vi.useFakeTimers();
1475
- const updatedApp = await App.findOne({
1476
- attributes: ['scimEnabled', 'scimToken', 'sslKey', 'sslCertificate'],
1477
- where: {
1447
+ it('should update app variables and secrets', async () => {
1448
+ vi.useRealTimers();
1449
+ const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
1450
+ process.env.TEST_VARIABLE_1 = 'test-variable-1';
1451
+ process.env.TEST_VARIABLE_2 = 'test-variable-2';
1452
+ process.env.TEST_SECRET = 'test-secret';
1453
+ process.env.TEST_SERVICE_URL_PATTERNS = 'http://localhost:1234';
1454
+ process.env.TEST_SERVICE_IDENTIFIER = 'Authorization';
1455
+ process.env.TEST_SERVICE_SECRET = 'secret';
1456
+ process.env.TEST_SAML_IDP_CERTIFICATE = 'certificate';
1457
+ process.env.TEST_SAML_ENTITY_ID = 'http://localhost:1234';
1458
+ process.env.TEST_SAML_SSO_URL = 'http://localhost:1234';
1459
+ process.env.TEST_OAUTH2_AUTHORIZATION_URL = 'http://localhost:1234';
1460
+ process.env.TEST_OAUTH2_TOKEN_URL = 'http://localhost:1234';
1461
+ process.env.TEST_OAUTH2_USER_INFO_URL = 'http://localhost:1234';
1462
+ process.env.TEST_OAUTH2_CLIENT_ID = 'id';
1463
+ process.env.TEST_OAUTH2_CLIENT_SECRET = 'secret';
1464
+ process.env.TEST_SCIM_TOKEN = 'token';
1465
+ process.env.TEST_SSL_KEY = 'key';
1466
+ process.env.TEST_SSL_CERTIFICATE = 'certificate';
1467
+ await updateApp({
1478
1468
  id: 1,
1479
- },
1480
- });
1481
- expect({
1482
- scimEnabled: updatedApp.scimEnabled,
1483
- scimToken: updatedApp.scimToken,
1484
- sslKey: updatedApp.sslKey,
1485
- sslCertificate: updatedApp.sslCertificate,
1486
- }).toStrictEqual({
1487
- scimEnabled: true,
1488
- scimToken: expect.any(Buffer),
1489
- sslKey: 'key',
1490
- sslCertificate: 'certificate',
1491
- });
1492
- const appVariables = await AppVariable.findAll({
1493
- attributes: ['name', 'value'],
1494
- where: {
1495
- AppId: 1,
1496
- },
1497
- });
1498
- expect(appVariables[0].toJSON()).toStrictEqual({
1499
- name: 'test-variable-inline',
1500
- value: 'inline',
1501
- });
1502
- expect(appVariables[1].toJSON()).toStrictEqual({
1503
- name: 'test-variable',
1504
- value: 'test-variable-1.test-variable-2',
1505
- });
1506
- const appServiceSecret = await AppServiceSecret.findOne({
1507
- attributes: ['name', 'authenticationMethod', 'urlPatterns', 'identifier', 'secret'],
1508
- where: {
1509
- AppId: 1,
1510
- },
1511
- });
1512
- expect(appServiceSecret.toJSON()).toStrictEqual({
1513
- name: 'test-service-secret',
1514
- authenticationMethod: 'custom-header',
1515
- urlPatterns: 'http://localhost:1234',
1516
- identifier: 'Authorization',
1517
- secret: expect.any(Buffer),
1518
- });
1519
- const appSamlSecret = await AppSamlSecret.findOne({
1520
- attributes: [
1521
- 'name',
1522
- 'icon',
1523
- 'nameAttribute',
1524
- 'emailAttribute',
1525
- 'idpCertificate',
1526
- 'entityId',
1527
- 'ssoUrl',
1528
- ],
1529
- where: {
1530
- AppId: 1,
1531
- },
1532
- });
1533
- expect(appSamlSecret.toJSON()).toStrictEqual({
1534
- emailAttribute: 'email',
1535
- entityId: 'http://localhost:1234',
1536
- icon: 'redhat',
1537
- id: 1,
1538
- idpCertificate: 'certificate',
1539
- name: 'test-saml-secret',
1540
- nameAttribute: 'name',
1541
- ssoUrl: 'http://localhost:1234',
1542
- spCertificate: expect.any(String),
1469
+ path: resolveFixture('apps/test'),
1470
+ remote: testApp.defaults.baseURL,
1471
+ clientCredentials,
1472
+ visibility: 'unlisted',
1473
+ iconBackground: '#ffffff',
1474
+ force: true,
1475
+ });
1476
+ vi.useFakeTimers();
1477
+ const updatedApp = await App.findOne({
1478
+ attributes: ['scimEnabled', 'scimToken', 'sslKey', 'sslCertificate'],
1479
+ where: {
1480
+ id: 1,
1481
+ },
1482
+ });
1483
+ expect({
1484
+ scimEnabled: updatedApp.scimEnabled,
1485
+ scimToken: updatedApp.scimToken,
1486
+ sslKey: updatedApp.sslKey,
1487
+ sslCertificate: updatedApp.sslCertificate,
1488
+ }).toStrictEqual({
1489
+ scimEnabled: true,
1490
+ scimToken: expect.any(Buffer),
1491
+ sslKey: 'key',
1492
+ sslCertificate: 'certificate',
1493
+ });
1494
+ const appVariables = await AppVariable.findAll({
1495
+ attributes: ['name', 'value'],
1496
+ where: {
1497
+ AppId: 1,
1498
+ },
1499
+ });
1500
+ expect(appVariables[0].toJSON()).toStrictEqual({
1501
+ name: 'test-variable-inline',
1502
+ value: 'inline',
1503
+ });
1504
+ expect(appVariables[1].toJSON()).toStrictEqual({
1505
+ name: 'test-variable',
1506
+ value: 'test-variable-1.test-variable-2',
1507
+ });
1508
+ const appServiceSecret = await AppServiceSecret.findOne({
1509
+ attributes: ['name', 'authenticationMethod', 'urlPatterns', 'identifier', 'secret'],
1510
+ where: {
1511
+ AppId: 1,
1512
+ },
1513
+ });
1514
+ expect(appServiceSecret.toJSON()).toStrictEqual({
1515
+ name: 'test-service-secret',
1516
+ authenticationMethod: 'custom-header',
1517
+ urlPatterns: 'http://localhost:1234',
1518
+ identifier: 'Authorization',
1519
+ secret: expect.any(Buffer),
1520
+ });
1521
+ const appSamlSecret = await AppSamlSecret.findOne({
1522
+ attributes: [
1523
+ 'name',
1524
+ 'icon',
1525
+ 'nameAttribute',
1526
+ 'emailAttribute',
1527
+ 'idpCertificate',
1528
+ 'entityId',
1529
+ 'ssoUrl',
1530
+ ],
1531
+ where: {
1532
+ AppId: 1,
1533
+ },
1534
+ });
1535
+ expect(appSamlSecret.toJSON()).toStrictEqual({
1536
+ emailAttribute: 'email',
1537
+ emailVerifiedAttribute: null,
1538
+ entityId: 'http://localhost:1234',
1539
+ icon: 'redhat',
1540
+ id: 1,
1541
+ idpCertificate: 'certificate',
1542
+ name: 'test-saml-secret',
1543
+ nameAttribute: 'name',
1544
+ ssoUrl: 'http://localhost:1234',
1545
+ spCertificate: expect.any(String),
1546
+ });
1547
+ const appOauth2Secret = await AppOAuth2Secret.findOne({
1548
+ attributes: [
1549
+ 'name',
1550
+ 'icon',
1551
+ 'scope',
1552
+ 'remapper',
1553
+ 'authorizationUrl',
1554
+ 'tokenUrl',
1555
+ 'userInfoUrl',
1556
+ 'clientId',
1557
+ 'clientSecret',
1558
+ ],
1559
+ where: {
1560
+ AppId: 1,
1561
+ },
1562
+ });
1563
+ expect({
1564
+ authorizationUrl: appOauth2Secret.authorizationUrl,
1565
+ clientId: appOauth2Secret.clientId,
1566
+ clientSecret: appOauth2Secret.clientSecret,
1567
+ icon: appOauth2Secret.icon,
1568
+ name: appOauth2Secret.name,
1569
+ remapper: appOauth2Secret.remapper,
1570
+ scope: appOauth2Secret.scope,
1571
+ tokenUrl: appOauth2Secret.tokenUrl,
1572
+ userInfoUrl: appOauth2Secret.userInfoUrl,
1573
+ }).toStrictEqual({
1574
+ authorizationUrl: 'http://localhost:1234',
1575
+ clientId: 'id',
1576
+ clientSecret: 'secret',
1577
+ icon: 'redhat',
1578
+ name: 'test-oauth2-secret',
1579
+ remapper: [{ prop: 'email' }],
1580
+ scope: 'email openid profile',
1581
+ tokenUrl: 'http://localhost:1234',
1582
+ userInfoUrl: 'http://localhost:1234',
1583
+ });
1543
1584
  });
1544
- const appOauth2Secret = await AppOAuth2Secret.findOne({
1545
- attributes: [
1546
- 'name',
1547
- 'icon',
1548
- 'scope',
1549
- 'remapper',
1550
- 'authorizationUrl',
1551
- 'tokenUrl',
1552
- 'userInfoUrl',
1553
- 'clientId',
1554
- 'clientSecret',
1585
+ it('should update an app with `app.locked` set to `fullLock` if force is specified', async () => {
1586
+ await app.update({ locked: 'fullLock' });
1587
+ const clientCredentials = await authorizeCLI('apps:write', testApp);
1588
+ await updateApp({
1589
+ path: resolveFixture('apps/test'),
1590
+ force: true,
1591
+ remote: testApp.defaults.baseURL,
1592
+ id: app.id,
1593
+ clientCredentials,
1594
+ visibility: 'public',
1595
+ iconBackground: '#fff999',
1596
+ });
1597
+ await app.reload();
1598
+ expect(app).toMatchInlineSnapshot(`
1599
+ {
1600
+ "$created": "1970-01-01T00:00:00.000Z",
1601
+ "$updated": "1970-01-01T00:00:00.000Z",
1602
+ "OrganizationId": "testorganization",
1603
+ "OrganizationName": undefined,
1604
+ "controllerCode": null,
1605
+ "controllerImplementations": null,
1606
+ "coreStyle": ".tux {
1607
+ color: rgb(0 0 0);
1608
+ }
1609
+ ",
1610
+ "definition": {
1611
+ "defaultPage": "Test Page",
1612
+ "name": "Test App",
1613
+ "pages": [
1614
+ {
1615
+ "blocks": [
1616
+ {
1617
+ "type": "test",
1618
+ "version": "0.0.0",
1619
+ },
1620
+ ],
1621
+ "name": "Test Page",
1622
+ },
1555
1623
  ],
1556
- where: {
1557
- AppId: 1,
1558
- },
1559
- });
1560
- expect({
1561
- authorizationUrl: appOauth2Secret.authorizationUrl,
1562
- clientId: appOauth2Secret.clientId,
1563
- clientSecret: appOauth2Secret.clientSecret,
1564
- icon: appOauth2Secret.icon,
1565
- name: appOauth2Secret.name,
1566
- remapper: appOauth2Secret.remapper,
1567
- scope: appOauth2Secret.scope,
1568
- tokenUrl: appOauth2Secret.tokenUrl,
1569
- userInfoUrl: appOauth2Secret.userInfoUrl,
1570
- }).toStrictEqual({
1571
- authorizationUrl: 'http://localhost:1234',
1572
- clientId: 'id',
1573
- clientSecret: 'secret',
1574
- icon: 'redhat',
1575
- name: 'test-oauth2-secret',
1576
- remapper: [{ prop: 'email' }],
1577
- scope: 'email openid profile',
1578
- tokenUrl: 'http://localhost:1234',
1579
- userInfoUrl: 'http://localhost:1234',
1580
- });
1581
- });
1582
- it('should update an app with `app.locked` set to `fullLock` if force is specified', async () => {
1583
- await app.update({ locked: 'fullLock' });
1584
- const clientCredentials = await authorizeCLI('apps:write', testApp);
1585
- await updateApp({
1586
- path: resolveFixture('apps/test'),
1587
- force: true,
1588
- remote: testApp.defaults.baseURL,
1589
- id: app.id,
1590
- clientCredentials,
1591
- visibility: 'public',
1592
- iconBackground: '#fff999',
1593
- });
1594
- await app.reload();
1595
- expect(app).toMatchInlineSnapshot(`
1596
- {
1597
- "$created": "1970-01-01T00:00:00.000Z",
1598
- "$updated": "1970-01-01T00:00:00.000Z",
1599
- "OrganizationId": "testorganization",
1600
- "OrganizationName": undefined,
1601
- "controllerCode": null,
1602
- "controllerImplementations": null,
1603
- "coreStyle": ".tux {
1604
- color: rgb(0 0 0);
1605
- }
1606
- ",
1607
- "definition": {
1608
- "defaultPage": "Test Page",
1609
- "name": "Test App",
1610
- "pages": [
1611
- {
1612
- "blocks": [
1613
- {
1614
- "type": "test",
1615
- "version": "0.0.0",
1616
- },
1617
- ],
1618
- "name": "Test Page",
1619
- },
1620
- ],
1621
- "resources": {
1622
- "test": {
1623
- "schema": {
1624
- "additionalProperties": false,
1625
- "properties": {
1626
- "test": {
1627
- "format": "binary",
1628
- "type": "string",
1624
+ "resources": {
1625
+ "test": {
1626
+ "schema": {
1627
+ "additionalProperties": false,
1628
+ "properties": {
1629
+ "test": {
1630
+ "format": "binary",
1631
+ "type": "string",
1632
+ },
1629
1633
  },
1634
+ "type": "object",
1630
1635
  },
1631
- "type": "object",
1632
1636
  },
1633
1637
  },
1634
1638
  },
1635
- },
1636
- "demoMode": false,
1637
- "domain": null,
1638
- "emailName": null,
1639
- "enableSelfRegistration": true,
1640
- "enableUnsecuredServiceSecrets": false,
1641
- "googleAnalyticsID": null,
1642
- "hasClonableAssets": undefined,
1643
- "hasClonableResources": undefined,
1644
- "hasIcon": true,
1645
- "hasMaskableIcon": true,
1646
- "iconBackground": "#fff999",
1647
- "iconUrl": "/api/apps/1/icon?maskable=true&updated=1970-01-01T00%3A00%3A00.000Z",
1648
- "id": 1,
1649
- "locked": "fullLock",
1650
- "messages": undefined,
1651
- "path": "test-app",
1652
- "rating": undefined,
1653
- "readmeUrl": undefined,
1654
- "screenshotUrls": undefined,
1655
- "sentryDsn": null,
1656
- "sentryEnvironment": null,
1657
- "sharedStyle": ".tux {
1658
- color: rgb(0 0 0);
1659
- }
1660
- ",
1661
- "showAppDefinition": false,
1662
- "showAppsembleLogin": false,
1663
- "showAppsembleOAuth2Login": true,
1664
- "template": false,
1665
- "visibility": "public",
1666
- "yaml": "name: Test App
1667
- defaultPage: Test Page
1668
- resources:
1669
- test:
1670
- schema:
1671
- additionalProperties: false
1672
- type: object
1673
- properties:
1674
- test:
1675
- type: string
1676
- format: binary
1677
- pages:
1678
- - name: Test Page
1679
- blocks:
1680
- - type: test
1681
- version: 0.0.0
1682
- ",
1683
- }
1684
- `);
1685
- });
1686
- it('should not update an app if the `app.locked` is set to `fullLock`', async () => {
1687
- await app.update({ locked: 'fullLock' });
1688
- const clientCredentials = await authorizeCLI('apps:write', testApp);
1689
- await expect(updateApp({
1690
- path: resolveFixture('apps/test'),
1691
- force: false,
1692
- remote: testApp.defaults.baseURL,
1693
- id: app.id,
1694
- clientCredentials,
1695
- visibility: 'public',
1696
- iconBackground: '#fff999',
1697
- })).rejects.toThrow('Request failed with status code 403');
1698
- await app.reload();
1699
- expect(app).toMatchInlineSnapshot(`
1700
- {
1701
- "$created": "1970-01-01T00:00:00.000Z",
1702
- "$updated": "1970-01-01T00:00:00.000Z",
1703
- "OrganizationId": "testorganization",
1704
- "OrganizationName": undefined,
1705
- "controllerCode": null,
1706
- "controllerImplementations": null,
1707
- "coreStyle": undefined,
1708
- "definition": {
1709
- "defaultPage": "Test Page",
1710
- "name": "Test App",
1711
- },
1712
- "demoMode": false,
1713
- "domain": null,
1714
- "emailName": null,
1715
- "enableSelfRegistration": true,
1716
- "enableUnsecuredServiceSecrets": false,
1717
- "googleAnalyticsID": null,
1718
- "hasClonableAssets": undefined,
1719
- "hasClonableResources": undefined,
1720
- "hasIcon": false,
1721
- "hasMaskableIcon": false,
1722
- "iconBackground": "#ffffff",
1723
- "iconUrl": null,
1724
- "id": 1,
1725
- "locked": "fullLock",
1726
- "messages": undefined,
1727
- "path": "test-app",
1728
- "rating": undefined,
1729
- "readmeUrl": undefined,
1730
- "screenshotUrls": undefined,
1731
- "sentryDsn": null,
1732
- "sentryEnvironment": null,
1733
- "sharedStyle": undefined,
1734
- "showAppDefinition": false,
1735
- "showAppsembleLogin": false,
1736
- "showAppsembleOAuth2Login": true,
1737
- "template": false,
1738
- "visibility": "public",
1739
- "yaml": "name: Test App
1740
- defaultPage: Test Page
1741
- ",
1742
- }
1743
- `);
1744
- });
1745
- it('should validate and throw if there’s an error before updating an app', async () => {
1746
- await BlockVersion.destroy({
1747
- where: {
1748
- version: '0.0.0',
1749
- OrganizationId: 'appsemble',
1750
- name: 'test',
1751
- },
1639
+ "demoMode": false,
1640
+ "domain": null,
1641
+ "emailName": null,
1642
+ "enableSelfRegistration": true,
1643
+ "enableUnsecuredServiceSecrets": false,
1644
+ "googleAnalyticsID": null,
1645
+ "hasClonableAssets": undefined,
1646
+ "hasClonableResources": undefined,
1647
+ "hasIcon": true,
1648
+ "hasMaskableIcon": true,
1649
+ "iconBackground": "#fff999",
1650
+ "iconUrl": "/api/apps/1/icon?maskable=true&updated=1970-01-01T00%3A00%3A00.000Z",
1651
+ "id": 1,
1652
+ "locked": "fullLock",
1653
+ "messages": undefined,
1654
+ "path": "test-app",
1655
+ "rating": undefined,
1656
+ "readmeUrl": undefined,
1657
+ "screenshotUrls": undefined,
1658
+ "sentryDsn": null,
1659
+ "sentryEnvironment": null,
1660
+ "sharedStyle": ".tux {
1661
+ color: rgb(0 0 0);
1662
+ }
1663
+ ",
1664
+ "showAppDefinition": false,
1665
+ "showAppsembleLogin": false,
1666
+ "showAppsembleOAuth2Login": true,
1667
+ "template": false,
1668
+ "visibility": "public",
1669
+ "yaml": "name: Test App
1670
+ defaultPage: Test Page
1671
+ resources:
1672
+ test:
1673
+ schema:
1674
+ additionalProperties: false
1675
+ type: object
1676
+ properties:
1677
+ test:
1678
+ type: string
1679
+ format: binary
1680
+ pages:
1681
+ - name: Test Page
1682
+ blocks:
1683
+ - type: test
1684
+ version: 0.0.0
1685
+ ",
1686
+ }
1687
+ `);
1752
1688
  });
1753
- vi.useRealTimers();
1754
- const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
1755
- await expect(updateApp({
1756
- path: resolveFixture('apps/test'),
1757
- id: app.id,
1758
- force: false,
1759
- remote: testApp.defaults.baseURL,
1760
- clientCredentials,
1761
- // Required defaults
1762
- visibility: 'unlisted',
1763
- iconBackground: '#ffffff',
1764
- })).rejects.toThrow('is not a known block type');
1765
- vi.useFakeTimers();
1766
- await app.reload();
1767
- expect(app.dataValues).toMatchInlineSnapshot(`
1768
- {
1769
- "OrganizationId": "testorganization",
1770
- "containers": null,
1771
- "controllerCode": null,
1772
- "controllerImplementations": null,
1773
- "coreStyle": null,
1774
- "created": 1970-01-01T00:00:00.000Z,
1775
- "definition": {
1776
- "defaultPage": "Test Page",
1777
- "name": "Test App",
1778
- },
1779
- "deleted": null,
1780
- "demoMode": false,
1781
- "domain": null,
1782
- "emailHost": null,
1783
- "emailName": null,
1784
- "emailPassword": null,
1785
- "emailPort": 587,
1786
- "emailSecure": true,
1787
- "emailUser": null,
1788
- "enableSelfRegistration": true,
1789
- "enableUnsecuredServiceSecrets": false,
1790
- "googleAnalyticsID": null,
1791
- "icon": null,
1792
- "iconBackground": null,
1793
- "id": 1,
1794
- "locked": "unlocked",
1795
- "maskableIcon": null,
1796
- "path": "test-app",
1797
- "registry": null,
1798
- "scimEnabled": false,
1799
- "scimToken": null,
1800
- "sentryDsn": null,
1801
- "sentryEnvironment": null,
1802
- "sharedStyle": null,
1803
- "showAppDefinition": false,
1804
- "showAppsembleLogin": false,
1805
- "showAppsembleOAuth2Login": true,
1806
- "sslCertificate": null,
1807
- "sslKey": null,
1808
- "template": false,
1809
- "updated": 1970-01-01T00:00:00.000Z,
1810
- "vapidPrivateKey": "b",
1811
- "vapidPublicKey": "a",
1812
- "visibility": "public",
1813
- }
1814
- `);
1815
- });
1816
- });
1817
- describe('patchApp', () => {
1818
- it('should apply patches to app', async () => {
1819
- const patches = {
1820
- demoMode: true,
1821
- enableSelfRegistration: true,
1822
- iconBackground: '#FFFFFF',
1823
- locked: 'fullLock',
1824
- path: 'updated-path',
1825
- showAppDefinition: true,
1826
- showAppsembleLogin: true,
1827
- showAppsembleOAuth2Login: true,
1828
- template: true,
1829
- visibility: 'private',
1830
- };
1831
- const app = await App.create({
1832
- path: 'test-app',
1833
- definition: { name: 'Test App', defaultPage: 'Test Page' },
1834
- vapidPublicKey: 'a',
1835
- vapidPrivateKey: 'b',
1836
- visibility: 'public',
1837
- OrganizationId: organization.id,
1838
- }, { raw: true });
1839
- await authorizeCLI('apps:write', testApp);
1840
- await patchApp({
1841
- ...patches,
1842
- remote: testApp.defaults.baseURL,
1843
- id: app.id,
1689
+ it('should not update an app if the `app.locked` is set to `fullLock`', async () => {
1690
+ await app.update({ locked: 'fullLock' });
1691
+ const clientCredentials = await authorizeCLI('apps:write', testApp);
1692
+ await expect(updateApp({
1693
+ path: resolveFixture('apps/test'),
1694
+ force: false,
1695
+ remote: testApp.defaults.baseURL,
1696
+ id: app.id,
1697
+ clientCredentials,
1698
+ visibility: 'public',
1699
+ iconBackground: '#fff999',
1700
+ })).rejects.toThrow('Request failed with status code 403');
1701
+ await app.reload();
1702
+ expect(app).toMatchInlineSnapshot(`
1703
+ {
1704
+ "$created": "1970-01-01T00:00:00.000Z",
1705
+ "$updated": "1970-01-01T00:00:00.000Z",
1706
+ "OrganizationId": "testorganization",
1707
+ "OrganizationName": undefined,
1708
+ "controllerCode": null,
1709
+ "controllerImplementations": null,
1710
+ "coreStyle": undefined,
1711
+ "definition": {
1712
+ "defaultPage": "Test Page",
1713
+ "name": "Test App",
1714
+ },
1715
+ "demoMode": false,
1716
+ "domain": null,
1717
+ "emailName": null,
1718
+ "enableSelfRegistration": true,
1719
+ "enableUnsecuredServiceSecrets": false,
1720
+ "googleAnalyticsID": null,
1721
+ "hasClonableAssets": undefined,
1722
+ "hasClonableResources": undefined,
1723
+ "hasIcon": false,
1724
+ "hasMaskableIcon": false,
1725
+ "iconBackground": "#ffffff",
1726
+ "iconUrl": null,
1727
+ "id": 1,
1728
+ "locked": "fullLock",
1729
+ "messages": undefined,
1730
+ "path": "test-app",
1731
+ "rating": undefined,
1732
+ "readmeUrl": undefined,
1733
+ "screenshotUrls": undefined,
1734
+ "sentryDsn": null,
1735
+ "sentryEnvironment": null,
1736
+ "sharedStyle": undefined,
1737
+ "showAppDefinition": false,
1738
+ "showAppsembleLogin": false,
1739
+ "showAppsembleOAuth2Login": true,
1740
+ "template": false,
1741
+ "visibility": "public",
1742
+ "yaml": "name: Test App
1743
+ defaultPage: Test Page
1744
+ ",
1745
+ }
1746
+ `);
1844
1747
  });
1845
- await app.reload();
1846
- expect(app.dataValues).toStrictEqual(expect.objectContaining({ ...app.dataValues, ...patches }));
1847
- expect(app.dataValues).toMatchInlineSnapshot(`
1848
- {
1849
- "OrganizationId": "testorganization",
1850
- "containers": null,
1851
- "controllerCode": null,
1852
- "controllerImplementations": null,
1853
- "coreStyle": null,
1854
- "created": 1970-01-01T00:00:00.000Z,
1855
- "definition": {
1856
- "defaultPage": "Test Page",
1857
- "name": "Test App",
1858
- },
1859
- "deleted": null,
1860
- "demoMode": true,
1861
- "domain": null,
1862
- "emailHost": null,
1863
- "emailName": null,
1864
- "emailPassword": null,
1865
- "emailPort": 587,
1866
- "emailSecure": true,
1867
- "emailUser": null,
1868
- "enableSelfRegistration": true,
1869
- "enableUnsecuredServiceSecrets": false,
1870
- "googleAnalyticsID": null,
1871
- "icon": null,
1872
- "iconBackground": "#FFFFFF",
1873
- "id": 1,
1874
- "locked": "fullLock",
1875
- "maskableIcon": null,
1876
- "path": "updated-path",
1877
- "registry": null,
1878
- "scimEnabled": false,
1879
- "scimToken": null,
1880
- "sentryDsn": null,
1881
- "sentryEnvironment": null,
1882
- "sharedStyle": null,
1883
- "showAppDefinition": true,
1884
- "showAppsembleLogin": true,
1885
- "showAppsembleOAuth2Login": true,
1886
- "sslCertificate": null,
1887
- "sslKey": null,
1888
- "template": true,
1889
- "updated": 1970-01-01T00:00:00.000Z,
1890
- "vapidPrivateKey": "b",
1891
- "vapidPublicKey": "a",
1892
- "visibility": "private",
1893
- }
1894
- `);
1895
- });
1896
- it.each `
1897
- key | from | to
1898
- ${'demoMode'} | ${false} | ${true}
1899
- ${'demoMode'} | ${true} | ${false}
1900
- ${'enableSelfRegistration'} | ${false} | ${true}
1901
- ${'enableSelfRegistration'} | ${true} | ${false}
1902
- ${'iconBackground'} | ${''} | ${'#FFFFFF'}
1903
- ${'path'} | ${'before'} | ${'after'}
1904
- ${'locked'} | ${'unlocked'} | ${'studioLock'}
1905
- ${'locked'} | ${'unlocked'} | ${'fullLock'}
1906
- ${'locked'} | ${'fullLock'} | ${'unlocked'}
1907
- ${'showAppDefinition'} | ${false} | ${true}
1908
- ${'showAppDefinition'} | ${true} | ${false}
1909
- ${'showAppsembleLogin'} | ${false} | ${true}
1910
- ${'showAppsembleLogin'} | ${true} | ${false}
1911
- ${'showAppsembleOAuth2Login'} | ${false} | ${true}
1912
- ${'showAppsembleOAuth2Login'} | ${true} | ${false}
1913
- ${'template'} | ${false} | ${true}
1914
- ${'template'} | ${true} | ${false}
1915
- ${'visibility'} | ${'public'} | ${'unlisted'}
1916
- ${'visibility'} | ${'public'} | ${'private'}
1917
- ${'visibility'} | ${'private'} | ${'public'}
1918
- `('should patch $key from `$from` to `$to`', async ({ from, key, to }) => {
1919
- const app = await App.create({
1920
- path: 'test-app',
1921
- definition: { name: 'Test App', defaultPage: 'Test Page' },
1922
- vapidPublicKey: 'a',
1923
- vapidPrivateKey: 'b',
1924
- visibility: 'public',
1925
- OrganizationId: organization.id,
1926
- [key]: from,
1927
- }, { raw: true });
1928
- await authorizeCLI('apps:write', testApp);
1929
- await patchApp({
1930
- [key]: to,
1931
- remote: testApp.defaults.baseURL,
1932
- id: app.id,
1748
+ it('should validate and throw if there’s an error before updating an app', async () => {
1749
+ await BlockVersion.destroy({
1750
+ where: {
1751
+ version: '0.0.0',
1752
+ OrganizationId: 'appsemble',
1753
+ name: 'test',
1754
+ },
1755
+ });
1756
+ vi.useRealTimers();
1757
+ const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
1758
+ await expect(updateApp({
1759
+ path: resolveFixture('apps/test'),
1760
+ id: app.id,
1761
+ force: false,
1762
+ remote: testApp.defaults.baseURL,
1763
+ clientCredentials,
1764
+ // Required defaults
1765
+ visibility: 'unlisted',
1766
+ iconBackground: '#ffffff',
1767
+ })).rejects.toThrow('is not a known block type');
1768
+ vi.useFakeTimers();
1769
+ await app.reload();
1770
+ expect(app.dataValues).toMatchInlineSnapshot(`
1771
+ {
1772
+ "OrganizationId": "testorganization",
1773
+ "containers": null,
1774
+ "controllerCode": null,
1775
+ "controllerImplementations": null,
1776
+ "coreStyle": null,
1777
+ "created": 1970-01-01T00:00:00.000Z,
1778
+ "definition": {
1779
+ "defaultPage": "Test Page",
1780
+ "name": "Test App",
1781
+ },
1782
+ "deleted": null,
1783
+ "demoMode": false,
1784
+ "domain": null,
1785
+ "emailHost": null,
1786
+ "emailName": null,
1787
+ "emailPassword": null,
1788
+ "emailPort": 587,
1789
+ "emailSecure": true,
1790
+ "emailUser": null,
1791
+ "enableSelfRegistration": true,
1792
+ "enableUnsecuredServiceSecrets": false,
1793
+ "googleAnalyticsID": null,
1794
+ "icon": null,
1795
+ "iconBackground": null,
1796
+ "id": 1,
1797
+ "locked": "unlocked",
1798
+ "maskableIcon": null,
1799
+ "path": "test-app",
1800
+ "registry": null,
1801
+ "scimEnabled": false,
1802
+ "scimToken": null,
1803
+ "sentryDsn": null,
1804
+ "sentryEnvironment": null,
1805
+ "sharedStyle": null,
1806
+ "showAppDefinition": false,
1807
+ "showAppsembleLogin": false,
1808
+ "showAppsembleOAuth2Login": true,
1809
+ "sslCertificate": null,
1810
+ "sslKey": null,
1811
+ "template": false,
1812
+ "updated": 1970-01-01T00:00:00.000Z,
1813
+ "vapidPrivateKey": "b",
1814
+ "vapidPublicKey": "a",
1815
+ "visibility": "public",
1816
+ }
1817
+ `);
1933
1818
  });
1934
- expect(app.dataValues[key]).toStrictEqual(from);
1935
- await app.reload();
1936
- expect(app.dataValues[key]).toStrictEqual(to);
1937
1819
  });
1938
- it('should not apply a patch if the `app.locked` is set to `fullLock`', async () => {
1939
- const app = await App.create({
1940
- path: 'test-app',
1941
- definition: { name: 'Test App', defaultPage: 'Test Page' },
1942
- vapidPublicKey: 'a',
1943
- vapidPrivateKey: 'b',
1944
- visibility: 'public',
1945
- OrganizationId: organization.id,
1946
- locked: 'fullLock',
1947
- showAppDefinition: false,
1948
- }, { raw: true });
1949
- await authorizeCLI('apps:write', testApp);
1950
- await patchApp({
1951
- remote: testApp.defaults.baseURL,
1952
- id: app.id,
1953
- showAppDefinition: true,
1820
+ describe('patchApp', () => {
1821
+ it('should apply patches to app', async () => {
1822
+ const patches = {
1823
+ demoMode: true,
1824
+ enableSelfRegistration: true,
1825
+ iconBackground: '#FFFFFF',
1826
+ locked: 'fullLock',
1827
+ path: 'updated-path',
1828
+ showAppDefinition: true,
1829
+ showAppsembleLogin: true,
1830
+ showAppsembleOAuth2Login: true,
1831
+ template: true,
1832
+ visibility: 'private',
1833
+ };
1834
+ const app = await App.create({
1835
+ path: 'test-app',
1836
+ definition: { name: 'Test App', defaultPage: 'Test Page' },
1837
+ vapidPublicKey: 'a',
1838
+ vapidPrivateKey: 'b',
1839
+ visibility: 'public',
1840
+ OrganizationId: organization.id,
1841
+ }, { raw: true });
1842
+ await authorizeCLI('apps:write', testApp);
1843
+ await patchApp({
1844
+ ...patches,
1845
+ remote: testApp.defaults.baseURL,
1846
+ id: app.id,
1847
+ });
1848
+ await app.reload();
1849
+ expect(app.dataValues).toStrictEqual(expect.objectContaining({ ...app.dataValues, ...patches }));
1850
+ expect(app.dataValues).toMatchInlineSnapshot(`
1851
+ {
1852
+ "OrganizationId": "testorganization",
1853
+ "containers": null,
1854
+ "controllerCode": null,
1855
+ "controllerImplementations": null,
1856
+ "coreStyle": null,
1857
+ "created": 1970-01-01T00:00:00.000Z,
1858
+ "definition": {
1859
+ "defaultPage": "Test Page",
1860
+ "name": "Test App",
1861
+ },
1862
+ "deleted": null,
1863
+ "demoMode": true,
1864
+ "domain": null,
1865
+ "emailHost": null,
1866
+ "emailName": null,
1867
+ "emailPassword": null,
1868
+ "emailPort": 587,
1869
+ "emailSecure": true,
1870
+ "emailUser": null,
1871
+ "enableSelfRegistration": true,
1872
+ "enableUnsecuredServiceSecrets": false,
1873
+ "googleAnalyticsID": null,
1874
+ "icon": null,
1875
+ "iconBackground": "#FFFFFF",
1876
+ "id": 1,
1877
+ "locked": "fullLock",
1878
+ "maskableIcon": null,
1879
+ "path": "updated-path",
1880
+ "registry": null,
1881
+ "scimEnabled": false,
1882
+ "scimToken": null,
1883
+ "sentryDsn": null,
1884
+ "sentryEnvironment": null,
1885
+ "sharedStyle": null,
1886
+ "showAppDefinition": true,
1887
+ "showAppsembleLogin": true,
1888
+ "showAppsembleOAuth2Login": true,
1889
+ "sslCertificate": null,
1890
+ "sslKey": null,
1891
+ "template": true,
1892
+ "updated": 1970-01-01T00:00:00.000Z,
1893
+ "vapidPrivateKey": "b",
1894
+ "vapidPublicKey": "a",
1895
+ "visibility": "private",
1896
+ }
1897
+ `);
1954
1898
  });
1955
- expect(app.dataValues.showAppDefinition).toBe(false);
1956
- await app.reload();
1957
- expect(app.dataValues.showAppDefinition).toBe(false);
1958
- });
1959
- it('should apply a patch if the `app.locked` is set to `fullLock` and `force` is specified', async () => {
1960
- const app = await App.create({
1961
- path: 'test-app',
1962
- definition: { name: 'Test App', defaultPage: 'Test Page' },
1963
- vapidPublicKey: 'a',
1964
- vapidPrivateKey: 'b',
1965
- visibility: 'public',
1966
- OrganizationId: organization.id,
1967
- locked: 'fullLock',
1968
- showAppDefinition: false,
1969
- }, { raw: true });
1970
- await authorizeCLI('apps:write', testApp);
1971
- await patchApp({
1972
- remote: testApp.defaults.baseURL,
1973
- id: app.id,
1974
- showAppDefinition: true,
1975
- force: true,
1899
+ it.each `
1900
+ key | from | to
1901
+ ${'demoMode'} | ${false} | ${true}
1902
+ ${'demoMode'} | ${true} | ${false}
1903
+ ${'enableSelfRegistration'} | ${false} | ${true}
1904
+ ${'enableSelfRegistration'} | ${true} | ${false}
1905
+ ${'iconBackground'} | ${''} | ${'#FFFFFF'}
1906
+ ${'path'} | ${'before'} | ${'after'}
1907
+ ${'locked'} | ${'unlocked'} | ${'studioLock'}
1908
+ ${'locked'} | ${'unlocked'} | ${'fullLock'}
1909
+ ${'locked'} | ${'fullLock'} | ${'unlocked'}
1910
+ ${'showAppDefinition'} | ${false} | ${true}
1911
+ ${'showAppDefinition'} | ${true} | ${false}
1912
+ ${'showAppsembleLogin'} | ${false} | ${true}
1913
+ ${'showAppsembleLogin'} | ${true} | ${false}
1914
+ ${'showAppsembleOAuth2Login'} | ${false} | ${true}
1915
+ ${'showAppsembleOAuth2Login'} | ${true} | ${false}
1916
+ ${'template'} | ${false} | ${true}
1917
+ ${'template'} | ${true} | ${false}
1918
+ ${'visibility'} | ${'public'} | ${'unlisted'}
1919
+ ${'visibility'} | ${'public'} | ${'private'}
1920
+ ${'visibility'} | ${'private'} | ${'public'}
1921
+ `('should patch $key from `$from` to `$to`', async ({ from, key, to }) => {
1922
+ const app = await App.create({
1923
+ path: 'test-app',
1924
+ definition: { name: 'Test App', defaultPage: 'Test Page' },
1925
+ vapidPublicKey: 'a',
1926
+ vapidPrivateKey: 'b',
1927
+ visibility: 'public',
1928
+ OrganizationId: organization.id,
1929
+ [key]: from,
1930
+ }, { raw: true });
1931
+ await authorizeCLI('apps:write', testApp);
1932
+ await patchApp({
1933
+ [key]: to,
1934
+ remote: testApp.defaults.baseURL,
1935
+ id: app.id,
1936
+ });
1937
+ expect(app.dataValues[key]).toStrictEqual(from);
1938
+ await app.reload();
1939
+ expect(app.dataValues[key]).toStrictEqual(to);
1940
+ });
1941
+ it('should not apply a patch if the `app.locked` is set to `fullLock`', async () => {
1942
+ const app = await App.create({
1943
+ path: 'test-app',
1944
+ definition: { name: 'Test App', defaultPage: 'Test Page' },
1945
+ vapidPublicKey: 'a',
1946
+ vapidPrivateKey: 'b',
1947
+ visibility: 'public',
1948
+ OrganizationId: organization.id,
1949
+ locked: 'fullLock',
1950
+ showAppDefinition: false,
1951
+ }, { raw: true });
1952
+ await authorizeCLI('apps:write', testApp);
1953
+ await patchApp({
1954
+ remote: testApp.defaults.baseURL,
1955
+ id: app.id,
1956
+ showAppDefinition: true,
1957
+ });
1958
+ expect(app.dataValues.showAppDefinition).toBe(false);
1959
+ await app.reload();
1960
+ expect(app.dataValues.showAppDefinition).toBe(false);
1961
+ });
1962
+ it('should apply a patch if the `app.locked` is set to `fullLock` and `force` is specified', async () => {
1963
+ const app = await App.create({
1964
+ path: 'test-app',
1965
+ definition: { name: 'Test App', defaultPage: 'Test Page' },
1966
+ vapidPublicKey: 'a',
1967
+ vapidPrivateKey: 'b',
1968
+ visibility: 'public',
1969
+ OrganizationId: organization.id,
1970
+ locked: 'fullLock',
1971
+ showAppDefinition: false,
1972
+ }, { raw: true });
1973
+ await authorizeCLI('apps:write', testApp);
1974
+ await patchApp({
1975
+ remote: testApp.defaults.baseURL,
1976
+ id: app.id,
1977
+ showAppDefinition: true,
1978
+ force: true,
1979
+ });
1980
+ expect(app.dataValues.showAppDefinition).toBe(false);
1981
+ await app.reload();
1982
+ expect(app.dataValues.showAppDefinition).toBe(true);
1976
1983
  });
1977
- expect(app.dataValues.showAppDefinition).toBe(false);
1978
- await app.reload();
1979
- expect(app.dataValues.showAppDefinition).toBe(true);
1980
1984
  });
1981
- });
1982
- describe('traverseAppDirectory', () => {
1983
- it('should read the app definition and appsembleRC from the directory', async () => {
1984
- const formData = new FormData();
1985
- const [appsembleContext, appsembleRC, yaml, app] = await traverseAppDirectory(resolveFixture('apps/test'), 'test', formData);
1986
- expect(appsembleContext).toMatchInlineSnapshot({
1987
- icon: expect.any(String),
1988
- maskableIcon: expect.any(String),
1989
- }, `
1985
+ describe('traverseAppDirectory', () => {
1986
+ it('should read the app definition and appsembleRC from the directory', async () => {
1987
+ const formData = new FormData();
1988
+ const [appsembleContext, appsembleRC, yaml, app] = await traverseAppDirectory(resolveFixture('apps/test'), 'test', formData);
1989
+ expect(appsembleContext).toMatchInlineSnapshot({
1990
+ icon: expect.any(String),
1991
+ maskableIcon: expect.any(String),
1992
+ }, `
1990
1993
  {
1991
1994
  "appLock": "studioLock",
1992
1995
  "assets": true,
@@ -2009,14 +2012,14 @@ describe('traverseAppDirectory', () => {
2009
2012
  "visibility": "public",
2010
2013
  }
2011
2014
  `);
2012
- expect(appsembleRC).toMatchInlineSnapshot({
2013
- context: {
2014
- test: {
2015
- icon: expect.any(String),
2016
- maskableIcon: expect.any(String),
2015
+ expect(appsembleRC).toMatchInlineSnapshot({
2016
+ context: {
2017
+ test: {
2018
+ icon: expect.any(String),
2019
+ maskableIcon: expect.any(String),
2020
+ },
2017
2021
  },
2018
- },
2019
- }, `
2022
+ }, `
2020
2023
  {
2021
2024
  "context": {
2022
2025
  "notFound": {
@@ -2050,30 +2053,30 @@ describe('traverseAppDirectory', () => {
2050
2053
  },
2051
2054
  }
2052
2055
  `);
2053
- expect(yaml).toMatchInlineSnapshot(`
2054
- "name: Test App
2055
- defaultPage: Test Page
2056
+ expect(yaml).toMatchInlineSnapshot(`
2057
+ "name: Test App
2058
+ defaultPage: Test Page
2056
2059
 
2057
- resources:
2058
- test:
2059
- schema:
2060
- additionalProperties: false
2061
- type: object
2062
- properties:
2063
- test:
2064
- type: string
2065
- format: binary
2060
+ resources:
2061
+ test:
2062
+ schema:
2063
+ additionalProperties: false
2064
+ type: object
2065
+ properties:
2066
+ test:
2067
+ type: string
2068
+ format: binary
2066
2069
 
2067
- pages:
2068
- - name: Test Page
2069
- blocks:
2070
- - type: test
2071
- version: 0.0.0
2072
- "
2073
- `);
2074
- expect(app).toMatchInlineSnapshot({
2075
- iconUrl: expect.any(String),
2076
- }, `
2070
+ pages:
2071
+ - name: Test Page
2072
+ blocks:
2073
+ - type: test
2074
+ version: 0.0.0
2075
+ "
2076
+ `);
2077
+ expect(app).toMatchInlineSnapshot({
2078
+ iconUrl: expect.any(String),
2079
+ }, `
2077
2080
  {
2078
2081
  "coreStyle": ".tux {
2079
2082
  color: rgb(0 0 0);
@@ -2119,87 +2122,88 @@ describe('traverseAppDirectory', () => {
2119
2122
  ",
2120
2123
  }
2121
2124
  `);
2122
- });
2123
- it('should return an error if no app-definition is found in the given directory', async () => {
2124
- const formData = new FormData();
2125
- await expect(() => traverseAppDirectory(resolveFixture('apps/empty'), null, formData)).rejects.toThrow('No app definition found');
2126
- });
2127
- });
2128
- describe('resolveAppIdAndRemote', () => {
2129
- it('should find and return app id and remote from appsembleRC', async () => {
2130
- const [appId, remote] = await resolveAppIdAndRemote(resolveFixture('apps/test'), 'resolve', 'http://localhost:8888', 55);
2131
- expect(appId).toBe(5);
2132
- expect(remote).toBe('http://localhost:5555/');
2133
- });
2134
- it('should fallback to default appId and remote if not found in context', async () => {
2135
- const [appId, remote] = await resolveAppIdAndRemote(resolveFixture('apps/test'), 'notFound', 'http://localhost:8888', 55);
2136
- expect(appId).toBe(55);
2137
- expect(remote).toBe('http://localhost:8888/');
2138
- });
2139
- it('should throw if the appId is not found in context and defaultAppId is not specified', async () => {
2140
- await expect(() => resolveAppIdAndRemote(resolveFixture('apps/test'), 'notFound', 'http://localhost:8888', null)).rejects.toThrow('App ID was not found');
2141
- });
2142
- it('should throw if the remote is not found in context and defaultAppRemote is not specified', async () => {
2143
- const app = await App.create({
2144
- path: 'test-app',
2145
- definition: { name: 'Test App', defaultPage: 'Test Page' },
2146
- vapidPublicKey: 'a',
2147
- vapidPrivateKey: 'b',
2148
- visibility: 'public',
2149
- OrganizationId: organization.id,
2150
2125
  });
2151
- await expect(() => resolveAppIdAndRemote(resolveFixture('apps/test'), 'notFound', null, app.id)).rejects.toThrow('App remote was not found');
2152
- });
2153
- });
2154
- describe('deleteApp', () => {
2155
- it('should throw if an error occurs', async () => {
2156
- const clientCredentials = await authorizeCLI('apps:delete', testApp);
2157
- await expect(() => deleteApp({ id: 1, remote: testApp.defaults.baseURL, clientCredentials })).rejects.toThrow('Request failed with status code 404');
2158
- });
2159
- it('should delete an app', async () => {
2160
- const app = await App.create({
2161
- path: 'test-app',
2162
- definition: { name: 'Test App', defaultPage: 'Test Page' },
2163
- vapidPublicKey: 'a',
2164
- vapidPrivateKey: 'b',
2165
- visibility: 'public',
2166
- OrganizationId: organization.id,
2126
+ it('should return an error if no app-definition is found in the given directory', async () => {
2127
+ const formData = new FormData();
2128
+ await expect(() => traverseAppDirectory(resolveFixture('apps/empty'), null, formData)).rejects.toThrow('No app definition found');
2167
2129
  });
2168
- const clientCredentials = await authorizeCLI('apps:delete', testApp);
2169
- await deleteApp({ id: app.id, remote: testApp.defaults.baseURL, clientCredentials });
2170
- const foundApps = await App.findAll();
2171
- expect(foundApps).toStrictEqual([]);
2172
2130
  });
2173
- });
2174
- describe('writeAppMessages', () => {
2175
- it('should extract messages from app-definition and write to file in i18n directory', async () => {
2176
- const initialMessages = JSON.parse(String(await readFixture('apps/test-messages/i18n/nl.json')));
2177
- expect(initialMessages).toMatchObject({
2178
- app: {},
2131
+ describe('resolveAppIdAndRemote', () => {
2132
+ it('should find and return app id and remote from appsembleRC', async () => {
2133
+ const [appId, remote] = await resolveAppIdAndRemote(resolveFixture('apps/test'), 'resolve', 'http://localhost:8888', 55);
2134
+ expect(appId).toBe(5);
2135
+ expect(remote).toBe('http://localhost:5555/');
2179
2136
  });
2180
- await writeAppMessages(resolveFixture('apps/test-messages'), ['nl'], [], 'json');
2181
- const messages = JSON.parse(String(await readFixture('apps/test-messages/i18n/nl.json')));
2182
- expect(messages).toMatchObject({
2183
- app: {
2184
- description: '',
2185
- name: '',
2186
- 'pages.test-page': '',
2187
- },
2137
+ it('should fallback to default appId and remote if not found in context', async () => {
2138
+ const [appId, remote] = await resolveAppIdAndRemote(resolveFixture('apps/test'), 'notFound', 'http://localhost:8888', 55);
2139
+ expect(appId).toBe(55);
2140
+ expect(remote).toBe('http://localhost:8888/');
2141
+ });
2142
+ it('should throw if the appId is not found in context and defaultAppId is not specified', async () => {
2143
+ await expect(() => resolveAppIdAndRemote(resolveFixture('apps/test'), 'notFound', 'http://localhost:8888', null)).rejects.toThrow('App ID was not found');
2144
+ });
2145
+ it('should throw if the remote is not found in context and defaultAppRemote is not specified', async () => {
2146
+ const app = await App.create({
2147
+ path: 'test-app',
2148
+ definition: { name: 'Test App', defaultPage: 'Test Page' },
2149
+ vapidPublicKey: 'a',
2150
+ vapidPrivateKey: 'b',
2151
+ visibility: 'public',
2152
+ OrganizationId: organization.id,
2153
+ });
2154
+ await expect(() => resolveAppIdAndRemote(resolveFixture('apps/test'), 'notFound', null, app.id)).rejects.toThrow('App remote was not found');
2188
2155
  });
2189
- await writeFile(resolveFixture('apps/test-messages/i18n/nl.json'), JSON.stringify(initialMessages, null, '\t'));
2190
- });
2191
- it('should throw if the language file does not exist', async () => {
2192
- await expect(() => writeAppMessages(resolveFixture('apps/test-messages'), ['hr'], [], 'json')).rejects.toThrow('Missing translations file');
2193
2156
  });
2194
- it('should throw if there are empty messages in a verified file', async () => {
2195
- const initialMessages = JSON.parse(String(await readFixture('apps/test-messages/i18n/nl.json')));
2196
- expect(initialMessages).toMatchObject({
2197
- app: {},
2157
+ describe('deleteApp', () => {
2158
+ it('should throw if an error occurs', async () => {
2159
+ const clientCredentials = await authorizeCLI('apps:delete', testApp);
2160
+ await expect(() => deleteApp({ id: 1, remote: testApp.defaults.baseURL, clientCredentials })).rejects.toThrow('Request failed with status code 404');
2161
+ });
2162
+ it('should delete an app', async () => {
2163
+ const app = await App.create({
2164
+ path: 'test-app',
2165
+ definition: { name: 'Test App', defaultPage: 'Test Page' },
2166
+ vapidPublicKey: 'a',
2167
+ vapidPrivateKey: 'b',
2168
+ visibility: 'public',
2169
+ OrganizationId: organization.id,
2170
+ });
2171
+ const clientCredentials = await authorizeCLI('apps:delete', testApp);
2172
+ await deleteApp({ id: app.id, remote: testApp.defaults.baseURL, clientCredentials });
2173
+ const foundApps = await App.findAll();
2174
+ expect(foundApps).toStrictEqual([]);
2198
2175
  });
2199
- await expect(() => writeAppMessages(resolveFixture('apps/test-messages'), ['nl'], ['nl'], 'json')).rejects.toThrow('Missing translation');
2200
2176
  });
2201
- it('should throw if app definition does not exist in the app folder', async () => {
2202
- await expect(() => writeAppMessages(resolveFixture('apps/empty'), ['nl'], [], 'json')).rejects.toThrow('Couldn’t find app definition');
2177
+ describe('writeAppMessages', () => {
2178
+ it('should extract messages from app-definition and write to file in i18n directory', async () => {
2179
+ const initialMessages = JSON.parse(String(await readFixture('apps/test-messages/i18n/nl.json')));
2180
+ expect(initialMessages).toMatchObject({
2181
+ app: {},
2182
+ });
2183
+ await writeAppMessages(resolveFixture('apps/test-messages'), ['nl'], [], 'json');
2184
+ const messages = JSON.parse(String(await readFixture('apps/test-messages/i18n/nl.json')));
2185
+ expect(messages).toMatchObject({
2186
+ app: {
2187
+ description: '',
2188
+ name: '',
2189
+ 'pages.test-page': '',
2190
+ },
2191
+ });
2192
+ await writeFile(resolveFixture('apps/test-messages/i18n/nl.json'), JSON.stringify(initialMessages, null, '\t'));
2193
+ });
2194
+ it('should throw if the language file does not exist', async () => {
2195
+ await expect(() => writeAppMessages(resolveFixture('apps/test-messages'), ['hr'], [], 'json')).rejects.toThrow('Missing translations file');
2196
+ });
2197
+ it('should throw if there are empty messages in a verified file', async () => {
2198
+ const initialMessages = JSON.parse(String(await readFixture('apps/test-messages/i18n/nl.json')));
2199
+ expect(initialMessages).toMatchObject({
2200
+ app: {},
2201
+ });
2202
+ await expect(() => writeAppMessages(resolveFixture('apps/test-messages'), ['nl'], ['nl'], 'json')).rejects.toThrow('Missing translation');
2203
+ });
2204
+ it('should throw if app definition does not exist in the app folder', async () => {
2205
+ await expect(() => writeAppMessages(resolveFixture('apps/empty'), ['nl'], [], 'json')).rejects.toThrow('Couldn’t find app definition');
2206
+ });
2203
2207
  });
2204
2208
  });
2205
2209
  //# sourceMappingURL=app.test.js.map