@appsemble/cli 0.27.12 → 0.28.0
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/README.md +3 -3
- package/commands/app/delete.js +2 -10
- package/commands/app/export.js +2 -3
- package/commands/block/delete.js +2 -3
- package/commands/team/create.js +1 -2
- package/commands/team/delete.js +1 -2
- package/lib/app.d.ts +8 -1
- package/lib/app.js +21 -4
- package/lib/app.test.js +495 -23
- package/lib/asset.test.d.ts +1 -0
- package/lib/asset.test.js +101 -0
- package/lib/block.d.ts +2 -1
- package/lib/block.js +3 -2
- package/lib/block.test.js +52 -1
- package/lib/organization.js +5 -3
- package/lib/organization.test.d.ts +1 -0
- package/lib/organization.test.js +222 -0
- package/lib/resource.test.d.ts +1 -0
- package/lib/resource.test.js +391 -0
- package/lib/team.d.ts +6 -2
- package/lib/team.js +6 -4
- package/lib/team.test.d.ts +1 -0
- package/lib/team.test.js +606 -0
- package/lib/testUtils.d.ts +2 -0
- package/lib/testUtils.js +11 -0
- package/package.json +6 -6
- package/server/options/parseQuery.test.js +2 -0
- package/templates/apps/empty/app-definition.yaml +2 -2
- package/templates/blocks/mini-jsx/package.json +1 -1
- package/templates/blocks/preact/package.json +2 -2
- package/templates/blocks/vanilla/package.json +1 -1
package/lib/app.test.js
CHANGED
|
@@ -1,23 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { readFixture, resolveFixture } from '@appsemble/node-utils';
|
|
2
|
+
import { createServer, createTestUser, models, setArgv, useTestDatabase } from '@appsemble/server';
|
|
3
3
|
import { ISODateTimePattern } from '@appsemble/utils';
|
|
4
4
|
import { setTestApp } from 'axios-test-instance';
|
|
5
|
-
import
|
|
5
|
+
import FormData from 'form-data';
|
|
6
6
|
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
-
import { patchApp, publishApp, updateApp } from './app.js';
|
|
7
|
+
import { deleteApp, patchApp, publishApp, traverseAppDirectory, updateApp } from './app.js';
|
|
8
8
|
import { initAxios } from './initAxios.js';
|
|
9
|
+
import { authorizeCLI } from './testUtils.js';
|
|
9
10
|
const { App, AppBlockStyle, AppCollection, AppCollectionApp, AppMessages, AppOAuth2Secret, AppSamlSecret, AppScreenshot, AppServiceSecret, AppVariable, Asset, BlockVersion, Organization, OrganizationMember, Resource, } = models;
|
|
10
11
|
const argv = { host: 'http://localhost', secret: 'test', aesSecret: 'testSecret' };
|
|
11
12
|
let user;
|
|
12
13
|
let organization;
|
|
13
14
|
let testApp;
|
|
14
|
-
async function authorizeCLI(scopes) {
|
|
15
|
-
const OAuth2AuthorizationCode = await authorizeClientCredentials(scopes);
|
|
16
|
-
const { id, secret } = OAuth2AuthorizationCode;
|
|
17
|
-
await OAuth2AuthorizationCode.update({ secret: await hash(secret, 10) });
|
|
18
|
-
await authenticate(testApp.defaults.baseURL, scopes, `${id}:${secret}`);
|
|
19
|
-
return `${id}:${secret}`;
|
|
20
|
-
}
|
|
21
15
|
useTestDatabase(import.meta);
|
|
22
16
|
beforeAll(() => {
|
|
23
17
|
vi.useFakeTimers();
|
|
@@ -60,7 +54,7 @@ afterAll(() => {
|
|
|
60
54
|
describe('publishApp', () => {
|
|
61
55
|
it('should publish app', async () => {
|
|
62
56
|
vi.useRealTimers();
|
|
63
|
-
const clientCredentials = await authorizeCLI('apps:write resources:write');
|
|
57
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
64
58
|
await publishApp({
|
|
65
59
|
path: resolveFixture('apps/test'),
|
|
66
60
|
organization: organization.id,
|
|
@@ -145,6 +139,7 @@ describe('publishApp', () => {
|
|
|
145
139
|
"showAppDefinition": true,
|
|
146
140
|
"showAppsembleLogin": false,
|
|
147
141
|
"showAppsembleOAuth2Login": true,
|
|
142
|
+
"template": false,
|
|
148
143
|
"visibility": "unlisted",
|
|
149
144
|
"yaml": "name: Test App
|
|
150
145
|
defaultPage: Test Page
|
|
@@ -183,9 +178,23 @@ describe('publishApp', () => {
|
|
|
183
178
|
const asset = await Asset.findAll();
|
|
184
179
|
expect(asset).toStrictEqual([]);
|
|
185
180
|
});
|
|
181
|
+
it('should throw an error if the user doesn’t have enough scope permissions', async () => {
|
|
182
|
+
const clientCredentials = await authorizeCLI('blocks:write resources:write', testApp);
|
|
183
|
+
await expect(() => publishApp({
|
|
184
|
+
path: resolveFixture('apps/test'),
|
|
185
|
+
organization: organization.id,
|
|
186
|
+
remote: testApp.defaults.baseURL,
|
|
187
|
+
clientCredentials,
|
|
188
|
+
// Required defaults
|
|
189
|
+
visibility: 'unlisted',
|
|
190
|
+
iconBackground: '#ffffff',
|
|
191
|
+
})).rejects.toThrow('write EPIPE');
|
|
192
|
+
const app = await App.findOne();
|
|
193
|
+
expect(app).toBeNull();
|
|
194
|
+
});
|
|
186
195
|
it('should publish app with resources and assets', async () => {
|
|
187
196
|
vi.useRealTimers();
|
|
188
|
-
const clientCredentials = await authorizeCLI('apps:write resources:write');
|
|
197
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
189
198
|
await publishApp({
|
|
190
199
|
path: resolveFixture('apps/test'),
|
|
191
200
|
organization: organization.id,
|
|
@@ -273,6 +282,7 @@ describe('publishApp', () => {
|
|
|
273
282
|
"showAppDefinition": true,
|
|
274
283
|
"showAppsembleLogin": false,
|
|
275
284
|
"showAppsembleOAuth2Login": true,
|
|
285
|
+
"template": false,
|
|
276
286
|
"visibility": "unlisted",
|
|
277
287
|
"yaml": "name: Test App
|
|
278
288
|
defaultPage: Test Page
|
|
@@ -339,7 +349,7 @@ describe('publishApp', () => {
|
|
|
339
349
|
visibility: 'public',
|
|
340
350
|
});
|
|
341
351
|
vi.useRealTimers();
|
|
342
|
-
const clientCredentials = await authorizeCLI('apps:write resources:write');
|
|
352
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
343
353
|
await publishApp({
|
|
344
354
|
path: resolveFixture('apps/test'),
|
|
345
355
|
organization: organization.id,
|
|
@@ -426,6 +436,7 @@ describe('publishApp', () => {
|
|
|
426
436
|
"showAppDefinition": true,
|
|
427
437
|
"showAppsembleLogin": false,
|
|
428
438
|
"showAppsembleOAuth2Login": true,
|
|
439
|
+
"template": true,
|
|
429
440
|
"visibility": "public",
|
|
430
441
|
"yaml": "name: Test App
|
|
431
442
|
defaultPage: Test Page
|
|
@@ -497,7 +508,7 @@ describe('publishApp', () => {
|
|
|
497
508
|
});
|
|
498
509
|
it('should publish app with app variant patches applied', async () => {
|
|
499
510
|
vi.useRealTimers();
|
|
500
|
-
const clientCredentials = await authorizeCLI('apps:write resources:write');
|
|
511
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
501
512
|
await publishApp({
|
|
502
513
|
path: resolveFixture('apps/test'),
|
|
503
514
|
organization: organization.id,
|
|
@@ -580,6 +591,7 @@ describe('publishApp', () => {
|
|
|
580
591
|
"showAppDefinition": true,
|
|
581
592
|
"showAppsembleLogin": false,
|
|
582
593
|
"showAppsembleOAuth2Login": true,
|
|
594
|
+
"template": false,
|
|
583
595
|
"visibility": "unlisted",
|
|
584
596
|
"yaml": "name: Test App
|
|
585
597
|
defaultPage: Test Page
|
|
@@ -635,7 +647,7 @@ describe('publishApp', () => {
|
|
|
635
647
|
});
|
|
636
648
|
it('should publish app variables and secrets', async () => {
|
|
637
649
|
vi.useRealTimers();
|
|
638
|
-
const clientCredentials = await authorizeCLI('apps:write resources:write');
|
|
650
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
639
651
|
process.env.TEST_VARIABLE_1 = 'test-variable-1';
|
|
640
652
|
process.env.TEST_VARIABLE_2 = 'test-variable-2';
|
|
641
653
|
process.env.TEST_SECRET = 'test-secret';
|
|
@@ -769,6 +781,28 @@ describe('publishApp', () => {
|
|
|
769
781
|
userInfoUrl: 'http://localhost:1234',
|
|
770
782
|
});
|
|
771
783
|
});
|
|
784
|
+
it('should validate and throw if there’s an error before publishing an app', async () => {
|
|
785
|
+
await BlockVersion.destroy({
|
|
786
|
+
where: {
|
|
787
|
+
version: '0.0.0',
|
|
788
|
+
OrganizationId: 'appsemble',
|
|
789
|
+
name: 'test',
|
|
790
|
+
},
|
|
791
|
+
});
|
|
792
|
+
vi.useRealTimers();
|
|
793
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
794
|
+
await expect(() => publishApp({
|
|
795
|
+
path: resolveFixture('apps/test'),
|
|
796
|
+
organization: organization.id,
|
|
797
|
+
remote: testApp.defaults.baseURL,
|
|
798
|
+
clientCredentials,
|
|
799
|
+
// Required defaults
|
|
800
|
+
visibility: 'unlisted',
|
|
801
|
+
iconBackground: '#ffffff',
|
|
802
|
+
})).rejects.toThrow('is not a known block type');
|
|
803
|
+
const app = await App.findOne();
|
|
804
|
+
expect(app).toBeNull();
|
|
805
|
+
});
|
|
772
806
|
});
|
|
773
807
|
describe('updateApp', () => {
|
|
774
808
|
let app;
|
|
@@ -784,7 +818,7 @@ describe('updateApp', () => {
|
|
|
784
818
|
});
|
|
785
819
|
it('should update app', async () => {
|
|
786
820
|
vi.useRealTimers();
|
|
787
|
-
const clientCredentials = await authorizeCLI('apps:write resources:write');
|
|
821
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
788
822
|
await updateApp({
|
|
789
823
|
id: app.id,
|
|
790
824
|
path: resolveFixture('apps/test'),
|
|
@@ -870,6 +904,7 @@ describe('updateApp', () => {
|
|
|
870
904
|
"showAppDefinition": false,
|
|
871
905
|
"showAppsembleLogin": false,
|
|
872
906
|
"showAppsembleOAuth2Login": true,
|
|
907
|
+
"template": false,
|
|
873
908
|
"visibility": "unlisted",
|
|
874
909
|
"yaml": "name: Test App
|
|
875
910
|
defaultPage: Test Page
|
|
@@ -910,7 +945,7 @@ describe('updateApp', () => {
|
|
|
910
945
|
});
|
|
911
946
|
it('should update app with resources and assets', async () => {
|
|
912
947
|
vi.useRealTimers();
|
|
913
|
-
const clientCredentials = await authorizeCLI('apps:write resources:write');
|
|
948
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
914
949
|
await updateApp({
|
|
915
950
|
id: app.id,
|
|
916
951
|
path: resolveFixture('apps/test'),
|
|
@@ -999,6 +1034,7 @@ describe('updateApp', () => {
|
|
|
999
1034
|
"showAppDefinition": false,
|
|
1000
1035
|
"showAppsembleLogin": false,
|
|
1001
1036
|
"showAppsembleOAuth2Login": true,
|
|
1037
|
+
"template": false,
|
|
1002
1038
|
"visibility": "unlisted",
|
|
1003
1039
|
"yaml": "name: Test App
|
|
1004
1040
|
defaultPage: Test Page
|
|
@@ -1065,7 +1101,7 @@ describe('updateApp', () => {
|
|
|
1065
1101
|
visibility: 'public',
|
|
1066
1102
|
});
|
|
1067
1103
|
vi.useRealTimers();
|
|
1068
|
-
const clientCredentials = await authorizeCLI('apps:write resources:write');
|
|
1104
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
1069
1105
|
await updateApp({
|
|
1070
1106
|
path: resolveFixture('apps/test'),
|
|
1071
1107
|
id: app.id,
|
|
@@ -1153,6 +1189,7 @@ describe('updateApp', () => {
|
|
|
1153
1189
|
"showAppDefinition": false,
|
|
1154
1190
|
"showAppsembleLogin": false,
|
|
1155
1191
|
"showAppsembleOAuth2Login": true,
|
|
1192
|
+
"template": true,
|
|
1156
1193
|
"visibility": "public",
|
|
1157
1194
|
"yaml": "name: Test App
|
|
1158
1195
|
defaultPage: Test Page
|
|
@@ -1225,7 +1262,7 @@ describe('updateApp', () => {
|
|
|
1225
1262
|
});
|
|
1226
1263
|
it('should update app with app variant patches applied', async () => {
|
|
1227
1264
|
vi.useRealTimers();
|
|
1228
|
-
const clientCredentials = await authorizeCLI('apps:write resources:write');
|
|
1265
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
1229
1266
|
await updateApp({
|
|
1230
1267
|
path: resolveFixture('apps/test'),
|
|
1231
1268
|
id: app.id,
|
|
@@ -1309,6 +1346,7 @@ describe('updateApp', () => {
|
|
|
1309
1346
|
"showAppDefinition": false,
|
|
1310
1347
|
"showAppsembleLogin": false,
|
|
1311
1348
|
"showAppsembleOAuth2Login": true,
|
|
1349
|
+
"template": false,
|
|
1312
1350
|
"visibility": "unlisted",
|
|
1313
1351
|
"yaml": "name: Test App
|
|
1314
1352
|
defaultPage: Test Page
|
|
@@ -1364,7 +1402,7 @@ describe('updateApp', () => {
|
|
|
1364
1402
|
});
|
|
1365
1403
|
it('should update app variables and secrets', async () => {
|
|
1366
1404
|
vi.useRealTimers();
|
|
1367
|
-
const clientCredentials = await authorizeCLI('apps:write resources:write');
|
|
1405
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
1368
1406
|
process.env.TEST_VARIABLE_1 = 'test-variable-1';
|
|
1369
1407
|
process.env.TEST_VARIABLE_2 = 'test-variable-2';
|
|
1370
1408
|
process.env.TEST_SECRET = 'test-secret';
|
|
@@ -1499,6 +1537,238 @@ describe('updateApp', () => {
|
|
|
1499
1537
|
userInfoUrl: 'http://localhost:1234',
|
|
1500
1538
|
});
|
|
1501
1539
|
});
|
|
1540
|
+
it('should update an app with `app.locked` set to `fullLock` if force is specified', async () => {
|
|
1541
|
+
await app.update({ locked: 'fullLock' });
|
|
1542
|
+
const clientCredentials = await authorizeCLI('apps:write', testApp);
|
|
1543
|
+
await updateApp({
|
|
1544
|
+
path: resolveFixture('apps/test'),
|
|
1545
|
+
force: true,
|
|
1546
|
+
remote: testApp.defaults.baseURL,
|
|
1547
|
+
id: app.id,
|
|
1548
|
+
clientCredentials,
|
|
1549
|
+
visibility: 'public',
|
|
1550
|
+
iconBackground: '#fff999',
|
|
1551
|
+
});
|
|
1552
|
+
await app.reload();
|
|
1553
|
+
expect(app).toMatchInlineSnapshot(`
|
|
1554
|
+
{
|
|
1555
|
+
"$created": "1970-01-01T00:00:00.000Z",
|
|
1556
|
+
"$updated": "1970-01-01T00:00:00.000Z",
|
|
1557
|
+
"OrganizationId": "testorganization",
|
|
1558
|
+
"OrganizationName": undefined,
|
|
1559
|
+
"controllerCode": null,
|
|
1560
|
+
"controllerImplementations": null,
|
|
1561
|
+
"coreStyle": ".tux {
|
|
1562
|
+
color: rgb(0 0 0);
|
|
1563
|
+
}
|
|
1564
|
+
",
|
|
1565
|
+
"definition": {
|
|
1566
|
+
"defaultPage": "Test Page",
|
|
1567
|
+
"name": "Test App",
|
|
1568
|
+
"pages": [
|
|
1569
|
+
{
|
|
1570
|
+
"blocks": [
|
|
1571
|
+
{
|
|
1572
|
+
"type": "test",
|
|
1573
|
+
"version": "0.0.0",
|
|
1574
|
+
},
|
|
1575
|
+
],
|
|
1576
|
+
"name": "Test Page",
|
|
1577
|
+
},
|
|
1578
|
+
],
|
|
1579
|
+
"resources": {
|
|
1580
|
+
"test": {
|
|
1581
|
+
"schema": {
|
|
1582
|
+
"additionalProperties": false,
|
|
1583
|
+
"properties": {
|
|
1584
|
+
"test": {
|
|
1585
|
+
"format": "binary",
|
|
1586
|
+
"type": "string",
|
|
1587
|
+
},
|
|
1588
|
+
},
|
|
1589
|
+
"type": "object",
|
|
1590
|
+
},
|
|
1591
|
+
},
|
|
1592
|
+
},
|
|
1593
|
+
},
|
|
1594
|
+
"demoMode": false,
|
|
1595
|
+
"domain": null,
|
|
1596
|
+
"emailName": null,
|
|
1597
|
+
"enableSelfRegistration": true,
|
|
1598
|
+
"enableUnsecuredServiceSecrets": false,
|
|
1599
|
+
"googleAnalyticsID": null,
|
|
1600
|
+
"hasClonableAssets": undefined,
|
|
1601
|
+
"hasClonableResources": undefined,
|
|
1602
|
+
"hasIcon": true,
|
|
1603
|
+
"hasMaskableIcon": true,
|
|
1604
|
+
"iconBackground": "#fff999",
|
|
1605
|
+
"iconUrl": "/api/apps/1/icon?maskable=true&updated=1970-01-01T00%3A00%3A00.000Z",
|
|
1606
|
+
"id": 1,
|
|
1607
|
+
"locked": "fullLock",
|
|
1608
|
+
"messages": undefined,
|
|
1609
|
+
"path": "test-app",
|
|
1610
|
+
"rating": undefined,
|
|
1611
|
+
"readmeUrl": undefined,
|
|
1612
|
+
"screenshotUrls": undefined,
|
|
1613
|
+
"sentryDsn": null,
|
|
1614
|
+
"sentryEnvironment": null,
|
|
1615
|
+
"sharedStyle": ".tux {
|
|
1616
|
+
color: rgb(0 0 0);
|
|
1617
|
+
}
|
|
1618
|
+
",
|
|
1619
|
+
"showAppDefinition": false,
|
|
1620
|
+
"showAppsembleLogin": false,
|
|
1621
|
+
"showAppsembleOAuth2Login": true,
|
|
1622
|
+
"template": false,
|
|
1623
|
+
"visibility": "public",
|
|
1624
|
+
"yaml": "name: Test App
|
|
1625
|
+
defaultPage: Test Page
|
|
1626
|
+
resources:
|
|
1627
|
+
test:
|
|
1628
|
+
schema:
|
|
1629
|
+
additionalProperties: false
|
|
1630
|
+
type: object
|
|
1631
|
+
properties:
|
|
1632
|
+
test:
|
|
1633
|
+
type: string
|
|
1634
|
+
format: binary
|
|
1635
|
+
pages:
|
|
1636
|
+
- name: Test Page
|
|
1637
|
+
blocks:
|
|
1638
|
+
- type: test
|
|
1639
|
+
version: 0.0.0
|
|
1640
|
+
",
|
|
1641
|
+
}
|
|
1642
|
+
`);
|
|
1643
|
+
});
|
|
1644
|
+
it('should not update an app if the `app.locked` is set to `fullLock`', async () => {
|
|
1645
|
+
await app.update({ locked: 'fullLock' });
|
|
1646
|
+
const clientCredentials = await authorizeCLI('apps:write', testApp);
|
|
1647
|
+
await expect(updateApp({
|
|
1648
|
+
path: resolveFixture('apps/test'),
|
|
1649
|
+
force: false,
|
|
1650
|
+
remote: testApp.defaults.baseURL,
|
|
1651
|
+
id: app.id,
|
|
1652
|
+
clientCredentials,
|
|
1653
|
+
visibility: 'public',
|
|
1654
|
+
iconBackground: '#fff999',
|
|
1655
|
+
})).rejects.toThrow('Request failed with status code 403');
|
|
1656
|
+
await app.reload();
|
|
1657
|
+
expect(app).toMatchInlineSnapshot(`
|
|
1658
|
+
{
|
|
1659
|
+
"$created": "1970-01-01T00:00:00.000Z",
|
|
1660
|
+
"$updated": "1970-01-01T00:00:00.000Z",
|
|
1661
|
+
"OrganizationId": "testorganization",
|
|
1662
|
+
"OrganizationName": undefined,
|
|
1663
|
+
"controllerCode": null,
|
|
1664
|
+
"controllerImplementations": null,
|
|
1665
|
+
"coreStyle": undefined,
|
|
1666
|
+
"definition": {
|
|
1667
|
+
"defaultPage": "Test Page",
|
|
1668
|
+
"name": "Test App",
|
|
1669
|
+
},
|
|
1670
|
+
"demoMode": false,
|
|
1671
|
+
"domain": null,
|
|
1672
|
+
"emailName": null,
|
|
1673
|
+
"enableSelfRegistration": true,
|
|
1674
|
+
"enableUnsecuredServiceSecrets": false,
|
|
1675
|
+
"googleAnalyticsID": null,
|
|
1676
|
+
"hasClonableAssets": undefined,
|
|
1677
|
+
"hasClonableResources": undefined,
|
|
1678
|
+
"hasIcon": false,
|
|
1679
|
+
"hasMaskableIcon": false,
|
|
1680
|
+
"iconBackground": "#ffffff",
|
|
1681
|
+
"iconUrl": null,
|
|
1682
|
+
"id": 1,
|
|
1683
|
+
"locked": "fullLock",
|
|
1684
|
+
"messages": undefined,
|
|
1685
|
+
"path": "test-app",
|
|
1686
|
+
"rating": undefined,
|
|
1687
|
+
"readmeUrl": undefined,
|
|
1688
|
+
"screenshotUrls": undefined,
|
|
1689
|
+
"sentryDsn": null,
|
|
1690
|
+
"sentryEnvironment": null,
|
|
1691
|
+
"sharedStyle": undefined,
|
|
1692
|
+
"showAppDefinition": false,
|
|
1693
|
+
"showAppsembleLogin": false,
|
|
1694
|
+
"showAppsembleOAuth2Login": true,
|
|
1695
|
+
"template": false,
|
|
1696
|
+
"visibility": "public",
|
|
1697
|
+
"yaml": "name: Test App
|
|
1698
|
+
defaultPage: Test Page
|
|
1699
|
+
",
|
|
1700
|
+
}
|
|
1701
|
+
`);
|
|
1702
|
+
});
|
|
1703
|
+
it('should validate and throw if there’s an error before updating an app', async () => {
|
|
1704
|
+
await BlockVersion.destroy({
|
|
1705
|
+
where: {
|
|
1706
|
+
version: '0.0.0',
|
|
1707
|
+
OrganizationId: 'appsemble',
|
|
1708
|
+
name: 'test',
|
|
1709
|
+
},
|
|
1710
|
+
});
|
|
1711
|
+
vi.useRealTimers();
|
|
1712
|
+
const clientCredentials = await authorizeCLI('apps:write resources:write', testApp);
|
|
1713
|
+
await expect(updateApp({
|
|
1714
|
+
path: resolveFixture('apps/test'),
|
|
1715
|
+
id: app.id,
|
|
1716
|
+
force: false,
|
|
1717
|
+
remote: testApp.defaults.baseURL,
|
|
1718
|
+
clientCredentials,
|
|
1719
|
+
// Required defaults
|
|
1720
|
+
visibility: 'unlisted',
|
|
1721
|
+
iconBackground: '#ffffff',
|
|
1722
|
+
})).rejects.toThrow('is not a known block type');
|
|
1723
|
+
vi.useFakeTimers();
|
|
1724
|
+
await app.reload();
|
|
1725
|
+
expect(app.dataValues).toMatchInlineSnapshot(`
|
|
1726
|
+
{
|
|
1727
|
+
"OrganizationId": "testorganization",
|
|
1728
|
+
"controllerCode": null,
|
|
1729
|
+
"controllerImplementations": null,
|
|
1730
|
+
"coreStyle": null,
|
|
1731
|
+
"created": 1970-01-01T00:00:00.000Z,
|
|
1732
|
+
"definition": {
|
|
1733
|
+
"defaultPage": "Test Page",
|
|
1734
|
+
"name": "Test App",
|
|
1735
|
+
},
|
|
1736
|
+
"deleted": null,
|
|
1737
|
+
"demoMode": false,
|
|
1738
|
+
"domain": null,
|
|
1739
|
+
"emailHost": null,
|
|
1740
|
+
"emailName": null,
|
|
1741
|
+
"emailPassword": null,
|
|
1742
|
+
"emailPort": 587,
|
|
1743
|
+
"emailSecure": true,
|
|
1744
|
+
"emailUser": null,
|
|
1745
|
+
"enableSelfRegistration": true,
|
|
1746
|
+
"enableUnsecuredServiceSecrets": false,
|
|
1747
|
+
"googleAnalyticsID": null,
|
|
1748
|
+
"icon": null,
|
|
1749
|
+
"iconBackground": null,
|
|
1750
|
+
"id": 1,
|
|
1751
|
+
"locked": "unlocked",
|
|
1752
|
+
"maskableIcon": null,
|
|
1753
|
+
"path": "test-app",
|
|
1754
|
+
"scimEnabled": false,
|
|
1755
|
+
"scimToken": null,
|
|
1756
|
+
"sentryDsn": null,
|
|
1757
|
+
"sentryEnvironment": null,
|
|
1758
|
+
"sharedStyle": null,
|
|
1759
|
+
"showAppDefinition": false,
|
|
1760
|
+
"showAppsembleLogin": false,
|
|
1761
|
+
"showAppsembleOAuth2Login": true,
|
|
1762
|
+
"sslCertificate": null,
|
|
1763
|
+
"sslKey": null,
|
|
1764
|
+
"template": false,
|
|
1765
|
+
"updated": 1970-01-01T00:00:00.000Z,
|
|
1766
|
+
"vapidPrivateKey": "b",
|
|
1767
|
+
"vapidPublicKey": "a",
|
|
1768
|
+
"visibility": "public",
|
|
1769
|
+
}
|
|
1770
|
+
`);
|
|
1771
|
+
});
|
|
1502
1772
|
});
|
|
1503
1773
|
describe('patchApp', () => {
|
|
1504
1774
|
it('should apply patches to app', async () => {
|
|
@@ -1522,7 +1792,7 @@ describe('patchApp', () => {
|
|
|
1522
1792
|
visibility: 'public',
|
|
1523
1793
|
OrganizationId: organization.id,
|
|
1524
1794
|
}, { raw: true });
|
|
1525
|
-
await authorizeCLI('apps:write');
|
|
1795
|
+
await authorizeCLI('apps:write', testApp);
|
|
1526
1796
|
await patchApp({
|
|
1527
1797
|
...patches,
|
|
1528
1798
|
remote: testApp.defaults.baseURL,
|
|
@@ -1609,7 +1879,7 @@ describe('patchApp', () => {
|
|
|
1609
1879
|
OrganizationId: organization.id,
|
|
1610
1880
|
[key]: from,
|
|
1611
1881
|
}, { raw: true });
|
|
1612
|
-
await authorizeCLI('apps:write');
|
|
1882
|
+
await authorizeCLI('apps:write', testApp);
|
|
1613
1883
|
await patchApp({
|
|
1614
1884
|
[key]: to,
|
|
1615
1885
|
remote: testApp.defaults.baseURL,
|
|
@@ -1619,5 +1889,207 @@ describe('patchApp', () => {
|
|
|
1619
1889
|
await app.reload();
|
|
1620
1890
|
expect(app.dataValues[key]).toStrictEqual(to);
|
|
1621
1891
|
});
|
|
1892
|
+
it('should not apply a patch if the `app.locked` is set to `fullLock`', async () => {
|
|
1893
|
+
const app = await App.create({
|
|
1894
|
+
path: 'test-app',
|
|
1895
|
+
definition: { name: 'Test App', defaultPage: 'Test Page' },
|
|
1896
|
+
vapidPublicKey: 'a',
|
|
1897
|
+
vapidPrivateKey: 'b',
|
|
1898
|
+
visibility: 'public',
|
|
1899
|
+
OrganizationId: organization.id,
|
|
1900
|
+
locked: 'fullLock',
|
|
1901
|
+
showAppDefinition: false,
|
|
1902
|
+
}, { raw: true });
|
|
1903
|
+
await authorizeCLI('apps:write', testApp);
|
|
1904
|
+
await patchApp({
|
|
1905
|
+
remote: testApp.defaults.baseURL,
|
|
1906
|
+
id: app.id,
|
|
1907
|
+
showAppDefinition: true,
|
|
1908
|
+
});
|
|
1909
|
+
expect(app.dataValues.showAppDefinition).toBe(false);
|
|
1910
|
+
await app.reload();
|
|
1911
|
+
expect(app.dataValues.showAppDefinition).toBe(false);
|
|
1912
|
+
});
|
|
1913
|
+
it('should apply a patch if the `app.locked` is set to `fullLock` and `force` is specified', async () => {
|
|
1914
|
+
const app = await App.create({
|
|
1915
|
+
path: 'test-app',
|
|
1916
|
+
definition: { name: 'Test App', defaultPage: 'Test Page' },
|
|
1917
|
+
vapidPublicKey: 'a',
|
|
1918
|
+
vapidPrivateKey: 'b',
|
|
1919
|
+
visibility: 'public',
|
|
1920
|
+
OrganizationId: organization.id,
|
|
1921
|
+
locked: 'fullLock',
|
|
1922
|
+
showAppDefinition: false,
|
|
1923
|
+
}, { raw: true });
|
|
1924
|
+
await authorizeCLI('apps:write', testApp);
|
|
1925
|
+
await patchApp({
|
|
1926
|
+
remote: testApp.defaults.baseURL,
|
|
1927
|
+
id: app.id,
|
|
1928
|
+
showAppDefinition: true,
|
|
1929
|
+
force: true,
|
|
1930
|
+
});
|
|
1931
|
+
expect(app.dataValues.showAppDefinition).toBe(false);
|
|
1932
|
+
await app.reload();
|
|
1933
|
+
expect(app.dataValues.showAppDefinition).toBe(true);
|
|
1934
|
+
});
|
|
1935
|
+
});
|
|
1936
|
+
describe('traverseAppDirectory', () => {
|
|
1937
|
+
it('should read the app definition and appsembleRC from the directory', async () => {
|
|
1938
|
+
const formData = new FormData();
|
|
1939
|
+
const [appsembleContext, appsembleRC, yaml, app] = await traverseAppDirectory(resolveFixture('apps/test'), 'test', formData);
|
|
1940
|
+
expect(appsembleContext).toMatchInlineSnapshot({
|
|
1941
|
+
icon: expect.any(String),
|
|
1942
|
+
maskableIcon: expect.any(String),
|
|
1943
|
+
}, `
|
|
1944
|
+
{
|
|
1945
|
+
"appLock": "studioLock",
|
|
1946
|
+
"assets": true,
|
|
1947
|
+
"assetsClonable": true,
|
|
1948
|
+
"collections": [
|
|
1949
|
+
1,
|
|
1950
|
+
],
|
|
1951
|
+
"demoMode": true,
|
|
1952
|
+
"googleAnalyticsId": "test",
|
|
1953
|
+
"icon": Any<String>,
|
|
1954
|
+
"iconBackground": "#000000",
|
|
1955
|
+
"id": 1,
|
|
1956
|
+
"maskableIcon": Any<String>,
|
|
1957
|
+
"organization": "testorganization",
|
|
1958
|
+
"resources": true,
|
|
1959
|
+
"sentryDsn": "https://public@sentry.example.com/1",
|
|
1960
|
+
"sentryEnvironment": "test",
|
|
1961
|
+
"showAppDefinition": true,
|
|
1962
|
+
"template": true,
|
|
1963
|
+
"visibility": "public",
|
|
1964
|
+
}
|
|
1965
|
+
`);
|
|
1966
|
+
expect(appsembleRC).toMatchInlineSnapshot({
|
|
1967
|
+
context: {
|
|
1968
|
+
test: {
|
|
1969
|
+
icon: expect.any(String),
|
|
1970
|
+
maskableIcon: expect.any(String),
|
|
1971
|
+
},
|
|
1972
|
+
},
|
|
1973
|
+
}, `
|
|
1974
|
+
{
|
|
1975
|
+
"context": {
|
|
1976
|
+
"test": {
|
|
1977
|
+
"appLock": "studioLock",
|
|
1978
|
+
"assets": true,
|
|
1979
|
+
"assetsClonable": true,
|
|
1980
|
+
"collections": [
|
|
1981
|
+
1,
|
|
1982
|
+
],
|
|
1983
|
+
"demoMode": true,
|
|
1984
|
+
"googleAnalyticsId": "test",
|
|
1985
|
+
"icon": Any<String>,
|
|
1986
|
+
"iconBackground": "#000000",
|
|
1987
|
+
"id": 1,
|
|
1988
|
+
"maskableIcon": Any<String>,
|
|
1989
|
+
"organization": "testorganization",
|
|
1990
|
+
"resources": true,
|
|
1991
|
+
"sentryDsn": "https://public@sentry.example.com/1",
|
|
1992
|
+
"sentryEnvironment": "test",
|
|
1993
|
+
"showAppDefinition": true,
|
|
1994
|
+
"template": true,
|
|
1995
|
+
"visibility": "public",
|
|
1996
|
+
},
|
|
1997
|
+
},
|
|
1998
|
+
}
|
|
1999
|
+
`);
|
|
2000
|
+
expect(yaml).toMatchInlineSnapshot(`
|
|
2001
|
+
"name: Test App
|
|
2002
|
+
defaultPage: Test Page
|
|
2003
|
+
|
|
2004
|
+
resources:
|
|
2005
|
+
test:
|
|
2006
|
+
schema:
|
|
2007
|
+
additionalProperties: false
|
|
2008
|
+
type: object
|
|
2009
|
+
properties:
|
|
2010
|
+
test:
|
|
2011
|
+
type: string
|
|
2012
|
+
format: binary
|
|
2013
|
+
|
|
2014
|
+
pages:
|
|
2015
|
+
- name: Test Page
|
|
2016
|
+
blocks:
|
|
2017
|
+
- type: test
|
|
2018
|
+
version: 0.0.0
|
|
2019
|
+
"
|
|
2020
|
+
`);
|
|
2021
|
+
expect(app).toMatchInlineSnapshot({
|
|
2022
|
+
iconUrl: expect.any(String),
|
|
2023
|
+
}, `
|
|
2024
|
+
{
|
|
2025
|
+
"coreStyle": ".tux {
|
|
2026
|
+
color: rgb(0 0 0);
|
|
2027
|
+
}
|
|
2028
|
+
",
|
|
2029
|
+
"definition": {
|
|
2030
|
+
"defaultPage": "Test Page",
|
|
2031
|
+
"name": "Test App",
|
|
2032
|
+
"pages": [
|
|
2033
|
+
{
|
|
2034
|
+
"blocks": [
|
|
2035
|
+
{
|
|
2036
|
+
"type": "test",
|
|
2037
|
+
"version": "0.0.0",
|
|
2038
|
+
},
|
|
2039
|
+
],
|
|
2040
|
+
"name": "Test Page",
|
|
2041
|
+
},
|
|
2042
|
+
],
|
|
2043
|
+
"resources": {
|
|
2044
|
+
"test": {
|
|
2045
|
+
"schema": {
|
|
2046
|
+
"additionalProperties": false,
|
|
2047
|
+
"properties": {
|
|
2048
|
+
"test": {
|
|
2049
|
+
"format": "binary",
|
|
2050
|
+
"type": "string",
|
|
2051
|
+
},
|
|
2052
|
+
},
|
|
2053
|
+
"type": "object",
|
|
2054
|
+
},
|
|
2055
|
+
},
|
|
2056
|
+
},
|
|
2057
|
+
},
|
|
2058
|
+
"iconUrl": Any<String>,
|
|
2059
|
+
"readmeUrl": "README.md",
|
|
2060
|
+
"screenshotUrls": [
|
|
2061
|
+
"test_en-us.png",
|
|
2062
|
+
],
|
|
2063
|
+
"sharedStyle": ".tux {
|
|
2064
|
+
color: rgb(0 0 0);
|
|
2065
|
+
}
|
|
2066
|
+
",
|
|
2067
|
+
}
|
|
2068
|
+
`);
|
|
2069
|
+
});
|
|
2070
|
+
it('should return an error if no app-definition is found in the given directory', async () => {
|
|
2071
|
+
const formData = new FormData();
|
|
2072
|
+
await expect(() => traverseAppDirectory(resolveFixture('apps/empty'), null, formData)).rejects.toThrow('No app definition found');
|
|
2073
|
+
});
|
|
2074
|
+
});
|
|
2075
|
+
describe('deleteApp', () => {
|
|
2076
|
+
it('should throw if an error occurs', async () => {
|
|
2077
|
+
const clientCredentials = await authorizeCLI('apps:delete', testApp);
|
|
2078
|
+
await expect(() => deleteApp({ id: 1, remote: testApp.defaults.baseURL, clientCredentials })).rejects.toThrow('Request failed with status code 404');
|
|
2079
|
+
});
|
|
2080
|
+
it('should delete an app', async () => {
|
|
2081
|
+
const app = await App.create({
|
|
2082
|
+
path: 'test-app',
|
|
2083
|
+
definition: { name: 'Test App', defaultPage: 'Test Page' },
|
|
2084
|
+
vapidPublicKey: 'a',
|
|
2085
|
+
vapidPrivateKey: 'b',
|
|
2086
|
+
visibility: 'public',
|
|
2087
|
+
OrganizationId: organization.id,
|
|
2088
|
+
});
|
|
2089
|
+
const clientCredentials = await authorizeCLI('apps:delete', testApp);
|
|
2090
|
+
await deleteApp({ id: app.id, remote: testApp.defaults.baseURL, clientCredentials });
|
|
2091
|
+
const foundApps = await App.findAll();
|
|
2092
|
+
expect(foundApps).toStrictEqual([]);
|
|
2093
|
+
});
|
|
1622
2094
|
});
|
|
1623
2095
|
//# sourceMappingURL=app.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|