@appsemble/cli 0.30.1 → 0.30.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/app.test.js CHANGED
@@ -1,6 +1,6 @@
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
4
  import { PredefinedOrganizationRole } from '@appsemble/types';
5
5
  import { ISODateTimePattern } from '@appsemble/utils';
6
6
  import { setTestApp } from 'axios-test-instance';
@@ -14,65 +14,65 @@ const argv = { host: 'http://localhost', secret: 'test', aesSecret: 'testSecret'
14
14
  let user;
15
15
  let organization;
16
16
  let testApp;
17
- useTestDatabase(import.meta);
18
- beforeAll(() => {
19
- vi.useFakeTimers();
20
- setArgv(argv);
21
- });
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,
17
+ describe('app', () => {
18
+ beforeAll(() => {
19
+ vi.useFakeTimers();
20
+ setArgv(argv);
37
21
  });
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',
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
+ },
48
49
  },
49
50
  },
50
- },
51
+ });
51
52
  });
52
- });
53
- afterAll(() => {
54
- vi.useRealTimers();
55
- });
56
- describe('publishApp', () => {
57
- it('should publish app', async () => {
53
+ afterAll(() => {
58
54
  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
- }, `
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
+ }, `
76
76
  {
77
77
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
78
78
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -162,77 +162,77 @@ describe('publishApp', () => {
162
162
  ",
163
163
  }
164
164
  `);
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 {
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 {
169
169
  color: rgb(0 0 0);
170
170
  }`);
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([]);
182
- });
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();
198
- });
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,
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([]);
210
182
  });
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,
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();
228
198
  });
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
- }, `
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
+ }, `
236
236
  {
237
237
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
238
238
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -322,26 +322,26 @@ describe('publishApp', () => {
322
322
  ",
323
323
  }
324
324
  `);
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 {
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 {
329
329
  color: rgb(0 0 0);
330
330
  }`);
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
- ], `
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
+ ], `
345
345
  [
346
346
  {
347
347
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -351,42 +351,42 @@ describe('publishApp', () => {
351
351
  },
352
352
  ]
353
353
  `);
354
- const assets = await Asset.findAll();
355
- expect(assets.map((a) => a.data)).toStrictEqual([
356
- await readFixture('apps/test/assets/tux.png'),
357
- ]);
358
- });
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',
354
+ const assets = await Asset.findAll();
355
+ expect(assets.map((a) => a.data)).toStrictEqual([
356
+ await readFixture('apps/test/assets/tux.png'),
357
+ ]);
369
358
  });
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
- }, `
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
+ }, `
390
390
  {
391
391
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
392
392
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -476,30 +476,30 @@ describe('publishApp', () => {
476
476
  ",
477
477
  }
478
478
  `);
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 {
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 {
483
483
  color: rgb(0 0 0);
484
484
  }`);
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
- ], `
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
+ ], `
503
503
  [
504
504
  {
505
505
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -516,38 +516,38 @@ describe('publishApp', () => {
516
516
  },
517
517
  ]
518
518
  `);
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);
527
- });
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,
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);
543
527
  });
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
- }, `
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
+ }, `
551
551
  {
552
552
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
553
553
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -631,25 +631,25 @@ describe('publishApp', () => {
631
631
  ",
632
632
  }
633
633
  `);
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
- ], `
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
+ ], `
653
653
  [
654
654
  {
655
655
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -659,203 +659,203 @@ describe('publishApp', () => {
659
659
  },
660
660
  ]
661
661
  `);
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
- ]);
666
- });
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',
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
+ ]);
694
666
  });
695
- vi.useFakeTimers();
696
- const app = await App.findOne({
697
- attributes: ['scimEnabled', 'scimToken', 'sslKey', 'sslCertificate'],
698
- 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',
699
759
  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',
759
- id: 1,
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
- });
803
- });
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
- },
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
+ });
811
803
  });
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();
825
- });
826
- });
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,
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();
837
825
  });
838
826
  });
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,
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
+ });
851
838
  });
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
- }, `
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
+ }, `
859
859
  {
860
860
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
861
861
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -945,71 +945,71 @@ describe('updateApp', () => {
945
945
  ",
946
946
  }
947
947
  `);
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 {
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 {
952
952
  color: rgb(0 0 0);
953
953
  }`);
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([]);
965
- });
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,
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([]);
988
965
  });
989
- });
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,
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
+ });
1005
989
  });
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
- }, `
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
+ }, `
1013
1013
  {
1014
1014
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
1015
1015
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1099,26 +1099,26 @@ describe('updateApp', () => {
1099
1099
  ",
1100
1100
  }
1101
1101
  `);
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 {
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 {
1106
1106
  color: rgb(0 0 0);
1107
1107
  }`);
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
- ], `
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
+ ], `
1122
1122
  [
1123
1123
  {
1124
1124
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1128,43 +1128,43 @@ describe('updateApp', () => {
1128
1128
  },
1129
1129
  ]
1130
1130
  `);
1131
- const assets = await Asset.findAll();
1132
- expect(assets.map((a) => a.data)).toStrictEqual([
1133
- await readFixture('apps/test/assets/tux.png'),
1134
- ]);
1135
- });
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',
1131
+ const assets = await Asset.findAll();
1132
+ expect(assets.map((a) => a.data)).toStrictEqual([
1133
+ await readFixture('apps/test/assets/tux.png'),
1134
+ ]);
1146
1135
  });
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
- }, `
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
+ }, `
1168
1168
  {
1169
1169
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
1170
1170
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1254,30 +1254,30 @@ describe('updateApp', () => {
1254
1254
  ",
1255
1255
  }
1256
1256
  `);
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 {
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 {
1261
1261
  color: rgb(0 0 0);
1262
1262
  }`);
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
- ], `
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
+ ], `
1281
1281
  [
1282
1282
  {
1283
1283
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1294,40 +1294,40 @@ describe('updateApp', () => {
1294
1294
  },
1295
1295
  ]
1296
1296
  `);
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);
1306
- });
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,
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);
1323
1306
  });
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
- }, `
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
+ }, `
1331
1331
  {
1332
1332
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
1333
1333
  "$updated": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1411,25 +1411,25 @@ describe('updateApp', () => {
1411
1411
  ",
1412
1412
  }
1413
1413
  `);
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
- ], `
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
+ ], `
1433
1433
  [
1434
1434
  {
1435
1435
  "$created": StringMatching /\\\\d\\{4\\}\\(\\.\\\\d\\{2\\}\\)\\{2\\}\\(\\\\s\\|T\\)\\(\\\\d\\{2\\}\\.\\)\\{2\\}\\\\d\\{2\\}/,
@@ -1439,557 +1439,557 @@ describe('updateApp', () => {
1439
1439
  },
1440
1440
  ]
1441
1441
  `);
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
- ]);
1446
- });
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({
1468
- id: 1,
1469
- path: resolveFixture('apps/test'),
1470
- remote: testApp.defaults.baseURL,
1471
- clientCredentials,
1472
- visibility: 'unlisted',
1473
- iconBackground: '#ffffff',
1474
- 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
+ ]);
1475
1446
  });
1476
- vi.useFakeTimers();
1477
- const updatedApp = await App.findOne({
1478
- attributes: ['scimEnabled', 'scimToken', 'sslKey', 'sslCertificate'],
1479
- 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({
1480
1468
  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),
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
+ });
1546
1584
  });
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',
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
+ },
1558
1623
  ],
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
- });
1584
- });
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
- },
1623
- ],
1624
- "resources": {
1625
- "test": {
1626
- "schema": {
1627
- "additionalProperties": false,
1628
- "properties": {
1629
- "test": {
1630
- "format": "binary",
1631
- "type": "string",
1624
+ "resources": {
1625
+ "test": {
1626
+ "schema": {
1627
+ "additionalProperties": false,
1628
+ "properties": {
1629
+ "test": {
1630
+ "format": "binary",
1631
+ "type": "string",
1632
+ },
1632
1633
  },
1634
+ "type": "object",
1633
1635
  },
1634
- "type": "object",
1635
1636
  },
1636
1637
  },
1637
1638
  },
1638
- },
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
- `);
1688
- });
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
- `);
1747
- });
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
- },
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
+ `);
1755
1688
  });
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
- `);
1818
- });
1819
- });
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,
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
+ `);
1847
1747
  });
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
- `);
1898
- });
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,
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
+ `);
1936
1818
  });
1937
- expect(app.dataValues[key]).toStrictEqual(from);
1938
- await app.reload();
1939
- expect(app.dataValues[key]).toStrictEqual(to);
1940
1819
  });
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,
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
+ `);
1957
1898
  });
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,
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);
1979
1983
  });
1980
- expect(app.dataValues.showAppDefinition).toBe(false);
1981
- await app.reload();
1982
- expect(app.dataValues.showAppDefinition).toBe(true);
1983
1984
  });
1984
- });
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
- }, `
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
+ }, `
1993
1993
  {
1994
1994
  "appLock": "studioLock",
1995
1995
  "assets": true,
@@ -2012,14 +2012,14 @@ describe('traverseAppDirectory', () => {
2012
2012
  "visibility": "public",
2013
2013
  }
2014
2014
  `);
2015
- expect(appsembleRC).toMatchInlineSnapshot({
2016
- context: {
2017
- test: {
2018
- icon: expect.any(String),
2019
- maskableIcon: expect.any(String),
2015
+ expect(appsembleRC).toMatchInlineSnapshot({
2016
+ context: {
2017
+ test: {
2018
+ icon: expect.any(String),
2019
+ maskableIcon: expect.any(String),
2020
+ },
2020
2021
  },
2021
- },
2022
- }, `
2022
+ }, `
2023
2023
  {
2024
2024
  "context": {
2025
2025
  "notFound": {
@@ -2053,30 +2053,30 @@ describe('traverseAppDirectory', () => {
2053
2053
  },
2054
2054
  }
2055
2055
  `);
2056
- expect(yaml).toMatchInlineSnapshot(`
2057
- "name: Test App
2058
- defaultPage: Test Page
2056
+ expect(yaml).toMatchInlineSnapshot(`
2057
+ "name: Test App
2058
+ defaultPage: Test Page
2059
2059
 
2060
- resources:
2061
- test:
2062
- schema:
2063
- additionalProperties: false
2064
- type: object
2065
- properties:
2066
- test:
2067
- type: string
2068
- format: binary
2060
+ resources:
2061
+ test:
2062
+ schema:
2063
+ additionalProperties: false
2064
+ type: object
2065
+ properties:
2066
+ test:
2067
+ type: string
2068
+ format: binary
2069
2069
 
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
- }, `
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
+ }, `
2080
2080
  {
2081
2081
  "coreStyle": ".tux {
2082
2082
  color: rgb(0 0 0);
@@ -2122,87 +2122,88 @@ describe('traverseAppDirectory', () => {
2122
2122
  ",
2123
2123
  }
2124
2124
  `);
2125
- });
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');
2129
- });
2130
- });
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/');
2136
- });
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
2125
  });
2154
- await expect(() => resolveAppIdAndRemote(resolveFixture('apps/test'), 'notFound', null, app.id)).rejects.toThrow('App remote was not found');
2155
- });
2156
- });
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,
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');
2170
2129
  });
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([]);
2175
2130
  });
2176
- });
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: {},
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/');
2182
2136
  });
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
- },
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');
2191
2155
  });
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
2156
  });
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: {},
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([]);
2201
2175
  });
2202
- await expect(() => writeAppMessages(resolveFixture('apps/test-messages'), ['nl'], ['nl'], 'json')).rejects.toThrow('Missing translation');
2203
2176
  });
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');
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
+ });
2206
2207
  });
2207
2208
  });
2208
2209
  //# sourceMappingURL=app.test.js.map