@squiz/component-cli-lib 1.21.1-alpha.35 → 1.21.1-alpha.39

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.
@@ -1,4 +1,4 @@
1
- import { ComponentSetWebModelForCreate } from '@squiz/component-lib';
1
+ import { ComponentSetWebModelForCreate, Manifest } from '@squiz/component-lib';
2
2
  import { ContentApi } from '@squiz/component-web-api-lib';
3
3
  interface Config {
4
4
  managementServiceUrl: string;
@@ -23,3 +23,5 @@ export declare function deleteComponentSet(webPath: string): Promise<void>;
23
23
  export declare function addComponentSet(componentSet: ComponentSetWebModelForCreate): Promise<void>;
24
24
  export declare function addContentItem(contentItem: ContentApi.ContentItemWebModel): Promise<void>;
25
25
  export declare function deleteContentItem(contentItemId: string): Promise<void>;
26
+ export declare function deleteComponent(manifest: Manifest): Promise<void>;
27
+ export declare function deleteComponents(manifests: Manifest[]): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squiz/component-cli-lib",
3
- "version": "1.21.1-alpha.35",
3
+ "version": "1.21.1-alpha.39",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -13,12 +13,12 @@
13
13
  "author": "",
14
14
  "license": "ISC",
15
15
  "devDependencies": {
16
- "@squiz/component-lib": "1.21.1-alpha.35",
17
- "@squiz/component-web-api-lib": "1.21.1-alpha.35",
18
- "@squiz/dx-common-lib": "1.21.1-alpha.35",
19
- "@squiz/dx-json-schema-lib": "1.21.1-alpha.35",
20
- "@squiz/dx-logger-lib": "1.21.1-alpha.35",
21
- "@squiz/virus-scanner-lib": "1.21.1-alpha.35",
16
+ "@squiz/component-lib": "1.21.1-alpha.39",
17
+ "@squiz/component-web-api-lib": "1.21.1-alpha.39",
18
+ "@squiz/dx-common-lib": "1.21.1-alpha.39",
19
+ "@squiz/dx-json-schema-lib": "1.21.1-alpha.39",
20
+ "@squiz/dx-logger-lib": "1.21.1-alpha.39",
21
+ "@squiz/virus-scanner-lib": "1.21.1-alpha.39",
22
22
  "@types/cli-color": "2.0.2",
23
23
  "@types/express": "4.17.17",
24
24
  "@types/jest": "28.1.8",
@@ -32,12 +32,12 @@
32
32
  "typescript": "4.9.4"
33
33
  },
34
34
  "dependencies": {
35
- "@squiz/render-runtime-lib": "1.21.1-alpha.35",
35
+ "@squiz/render-runtime-lib": "1.21.1-alpha.39",
36
36
  "archiver": "5.3.1",
37
37
  "axios": "1.3.2",
38
38
  "cli-color": "^2.0.2",
39
39
  "open": "^8.4.0",
40
40
  "supertest": "^6.2.3"
41
41
  },
42
- "gitHead": "615376e3d0d55f8398129643c3e22a7b2b1d7664"
42
+ "gitHead": "52f09f966b5eaa35149786dd1f2c55bf9ad8bde5"
43
43
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @param {object} input
3
+ */
4
+ module.exports = async function (input) {
5
+ return `<div>Input: ${JSON.stringify(input)}</div>`;
6
+ };
@@ -0,0 +1,60 @@
1
+ {
2
+ "$schema": "http://localhost:3000/schemas/v1.json#",
3
+
4
+ "name": "cmp-property-order",
5
+ "version": "1.0.0",
6
+ "mainFunction": "main",
7
+ "displayName": "some-display-name",
8
+ "namespace": "smoke-test-components",
9
+ "description": "some-description",
10
+ "functions": [
11
+ {
12
+ "name": "main",
13
+ "entry": "main.js",
14
+ "input": {
15
+ "type": "object",
16
+ "properties": {
17
+ "input1": {
18
+ "type": "string"
19
+ },
20
+ "333": {
21
+ "type": "string"
22
+ },
23
+ "input333": {
24
+ "type": "string"
25
+ },
26
+ "\"": {
27
+ "type": "string"
28
+ },
29
+ "~": {
30
+ "type": "string"
31
+ },
32
+ "": {
33
+ "type": "string"
34
+ },
35
+ "$": {
36
+ "type": "string"
37
+ },
38
+ "111": {
39
+ "type": "string"
40
+ },
41
+ "input22": {
42
+ "type": "string"
43
+ },
44
+ "222": {
45
+ "type": "string"
46
+ },
47
+ "*": {
48
+ "type": "string"
49
+ },
50
+ "null": {
51
+ "type": "null",
52
+ "default": null
53
+ }
54
+ },
55
+ "required": []
56
+ },
57
+ "output": { "responseType": "html" }
58
+ }
59
+ ]
60
+ }
@@ -1,9 +1,9 @@
1
- import axios from 'axios';
1
+ import axios, { AxiosError } from 'axios';
2
2
  import path from 'path';
3
3
 
4
4
  import fsp from 'fs/promises';
5
5
  import { randomBytes } from 'crypto';
6
- import { ComponentSetWebModelForCreate, ManifestServiceForDev } from '@squiz/component-lib';
6
+ import { ComponentSetWebModelForCreate, Manifest, ManifestServiceForDev } from '@squiz/component-lib';
7
7
  import { parseEnvVarForVar } from '@squiz/dx-common-lib';
8
8
  import { ContentApi } from '@squiz/component-web-api-lib';
9
9
  import { config } from 'dotenv';
@@ -154,3 +154,20 @@ export async function deleteContentItem(contentItemId: string) {
154
154
  //no ops
155
155
  }
156
156
  }
157
+
158
+ export async function deleteComponent(manifest: Manifest) {
159
+ try {
160
+ await managementService.delete(`/component/${manifest.getName()}`);
161
+ await contentService.delete(
162
+ `/content-schema/${manifest.getName()}/${manifest.getVersion()}/${manifest.getComponentFunctionByName().name}`,
163
+ );
164
+ } catch (error) {
165
+ if ((error as AxiosError).response?.status !== 404) {
166
+ throw error;
167
+ }
168
+ }
169
+ }
170
+
171
+ export async function deleteComponents(manifests: Manifest[]) {
172
+ await Promise.all(manifests.map((manifest) => deleteComponent(manifest)));
173
+ }
@@ -1,16 +1,16 @@
1
1
  import { uploadComponentFolder } from '../index';
2
2
  import configObj, {
3
- renderService,
4
3
  managementService,
4
+ renderService,
5
5
  getTestComponents,
6
6
  createFile,
7
+ deleteComponents,
7
8
  removeFile,
8
9
  addComponentSet,
9
10
  deleteComponentSet,
10
11
  addContentItem,
11
12
  deleteContentItem,
12
13
  managementServiceRoot,
13
- contentService,
14
14
  } from './helper';
15
15
 
16
16
  import path from 'path';
@@ -19,7 +19,6 @@ import { logger } from '../upload-component-folder';
19
19
  import { ComponentSetWebModelForCreate } from '@squiz/component-lib';
20
20
  import fsp from 'fs/promises';
21
21
  import { randomUUID } from 'crypto';
22
- import { AxiosError } from 'axios';
23
22
 
24
23
  const webPath = 'set-' + randomUUID();
25
24
  const contentItemId = randomUUID();
@@ -36,18 +35,8 @@ describe('uploading a component', () => {
36
35
  // clean up the component added by the test
37
36
  await deleteComponentSet(webPath);
38
37
  await deleteContentItem(contentItemId);
39
-
40
- for (const manifest of await getTestComponents()) {
41
- await managementService.delete(`/component/${manifest.getName()}`).catch(() => null);
42
- await contentService
43
- .delete(
44
- `/content-schema/${manifest.getName()}/${manifest.getVersion()}/${
45
- manifest.getComponentFunctionByName().name
46
- }`,
47
- )
48
- .catch(() => null);
49
- }
50
- // clean up the test componnet files
38
+ await deleteComponents(await getTestComponents());
39
+ // clean up the test component files
51
40
  await fsp.rm(testFilesDir, { force: true, recursive: true });
52
41
  logger.silent = false;
53
42
  });
@@ -102,22 +91,9 @@ describe('uploading a component', () => {
102
91
 
103
92
  describe('Deploy a basic component having a input with multiline format', () => {
104
93
  beforeAll(async () => {
105
- try {
106
- await deleteComponentSet(webPath);
107
- await deleteContentItem(contentItemId);
108
- for (const manifest of await getTestComponents()) {
109
- await managementService.delete(`/component/${manifest.getName()}`);
110
- await contentService.delete(
111
- `/content-schema/${manifest.getName()}/${manifest.getVersion()}/${
112
- manifest.getComponentFunctionByName().name
113
- }`,
114
- );
115
- }
116
- } catch (error: unknown) {
117
- if ((error as AxiosError).response?.status !== 404) {
118
- throw error;
119
- }
120
- }
94
+ await deleteComponentSet(webPath);
95
+ await deleteContentItem(contentItemId);
96
+ await deleteComponents(await getTestComponents());
121
97
  });
122
98
 
123
99
  it('Should upload the component and return a valid url to preview', async () => {
@@ -178,22 +154,9 @@ describe('uploading a component', () => {
178
154
 
179
155
  describe('Deploy a basic component with input format matrix-asset-uri', () => {
180
156
  beforeAll(async () => {
181
- try {
182
- await deleteComponentSet(webPath);
183
- await deleteContentItem(contentItemId);
184
- for (const manifest of await getTestComponents()) {
185
- await managementService.delete(`/component/${manifest.getName()}`);
186
- await contentService.delete(
187
- `/content-schema/${manifest.getName()}/${manifest.getVersion()}/${
188
- manifest.getComponentFunctionByName().name
189
- }`,
190
- );
191
- }
192
- } catch (error) {
193
- if ((error as AxiosError).response?.status !== 404) {
194
- throw error;
195
- }
196
- }
157
+ await deleteComponentSet(webPath);
158
+ await deleteContentItem(contentItemId);
159
+ await deleteComponents(await getTestComponents());
197
160
  });
198
161
  it('Should upload the component and return a valid url to preview', async () => {
199
162
  const componentPath = path.join(__dirname, '/__components__/matrix-asset-uri');
@@ -245,22 +208,9 @@ describe('uploading a component', () => {
245
208
  const componentPath = path.join(__dirname, '/__components__/cmp-static-file-test');
246
209
 
247
210
  beforeAll(async () => {
248
- try {
249
- await deleteComponentSet(webPath);
250
- await deleteContentItem(contentItemId);
251
- for (const manifest of await getTestComponents()) {
252
- await managementService.delete(`/component/${manifest.getName()}`);
253
- await contentService.delete(
254
- `/content-schema/${manifest.getName()}/${manifest.getVersion()}/${
255
- manifest.getComponentFunctionByName().name
256
- }`,
257
- );
258
- }
259
- } catch (error) {
260
- if ((error as AxiosError).response?.status !== 404) {
261
- throw error;
262
- }
263
- }
211
+ await deleteComponentSet(webPath);
212
+ await deleteContentItem(contentItemId);
213
+ await deleteComponents(await getTestComponents());
264
214
  });
265
215
 
266
216
  it('Should upload the component and return a valid url to preview', async () => {
@@ -371,22 +321,9 @@ describe('uploading a component', () => {
371
321
  const componentPath = path.join(__dirname, '/__components__/cmp-no-api-key');
372
322
 
373
323
  beforeAll(async () => {
374
- try {
375
- await deleteComponentSet(webPath);
376
- await deleteContentItem(contentItemId);
377
- for (const manifest of await getTestComponents()) {
378
- await managementService.delete(`/component/${manifest.getName()}`);
379
- await contentService.delete(
380
- `/content-schema/${manifest.getName()}/${manifest.getVersion()}/${
381
- manifest.getComponentFunctionByName().name
382
- }`,
383
- );
384
- }
385
- } catch (error) {
386
- if ((error as AxiosError).response?.status !== 404) {
387
- throw error;
388
- }
389
- }
324
+ await deleteComponentSet(webPath);
325
+ await deleteContentItem(contentItemId);
326
+ await deleteComponents(await getTestComponents());
390
327
  });
391
328
 
392
329
  it('Should upload the component and return a valid url', async () => {
@@ -432,4 +369,55 @@ describe('uploading a component', () => {
432
369
  expect(response.data).toEqual(false);
433
370
  });
434
371
  });
372
+
373
+ describe('Deploy component with properties defined in a specific order', () => {
374
+ // component to deploy for this test
375
+ const componentPath = path.join(__dirname, '/__components__/cmp-property-order');
376
+
377
+ beforeAll(async () => {
378
+ await deleteComponentSet(webPath);
379
+ await deleteContentItem(contentItemId);
380
+ await deleteComponents(await getTestComponents());
381
+
382
+ await uploadComponentFolder(managementServiceRoot, configObj.managementServiceUrl, componentPath, testFilesDir);
383
+ });
384
+
385
+ it('Should preserve input field order when uploading schema to content store', async () => {
386
+ const response = await supertest(configObj.contentServiceUrl).get(
387
+ '/content-schema/smoke-test-components/cmp-property-order/1.0.0/main',
388
+ );
389
+
390
+ // Relates to DEVX-891, property order is preserved so that we can reliably draw a UI from it.
391
+ //
392
+ // The sequence here is important and should follow the rules defined here:
393
+ // * https://tc39.es/ecma262/#sec-ordinaryownpropertykeys
394
+ // * https://stackoverflow.com/a/38218582
395
+ //
396
+ // Per EMCA-262 numeric keys appear first in ascending order but all other keys should appear
397
+ // in the order they were originally defined, they should not be affected by them being stored in
398
+ // a JSONB DB column or anything else.
399
+ //
400
+ // Asserting on the encoded contents of the response to avoid any decoding in the test having
401
+ // a potential influence on the outcome.
402
+ const expectedProperties =
403
+ '"111":{"type":"string"},' +
404
+ '"222":{"type":"string"},' +
405
+ '"333":{"type":"string"},' +
406
+ '"input1":{"type":"string"},' +
407
+ '"input333":{"type":"string"},' +
408
+ '"\\"":{"type":"string"},' +
409
+ '"~":{"type":"string"},' +
410
+ '"":{"type":"string"},' +
411
+ '"$":{"type":"string"},' +
412
+ '"input22":{"type":"string"},' +
413
+ '"*":{"type":"string"},' +
414
+ '"null":{"type":"null","default":null}';
415
+
416
+ expect(response.status).toEqual(200);
417
+ expect(response.text).toEqual(
418
+ `{"name":"smoke-test-components/cmp-property-order/1.0.0/main",` +
419
+ `"schema":{"type":"object","properties":{${expectedProperties}},"required":[]},"contentSchemaType":"component"}`,
420
+ );
421
+ });
422
+ });
435
423
  });