@squiz/component-cli-lib 1.2.1-alpha.107 → 1.2.1-alpha.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +0 -730
  2. package/jest.config.ts +3 -11
  3. package/lib/index.d.ts +1 -2
  4. package/lib/index.js +79 -5
  5. package/lib/index.js.map +1 -1
  6. package/lib/{component-dev-folder-structures.spec.d.ts → test.d.ts} +0 -0
  7. package/lib/test.js +12 -0
  8. package/lib/test.js.map +1 -0
  9. package/lib/utils/zipDirectory.d.ts +1 -0
  10. package/lib/utils/zipDirectory.js +32 -0
  11. package/lib/utils/zipDirectory.js.map +1 -0
  12. package/package.json +16 -22
  13. package/src/index.ts +90 -2
  14. package/src/test.ts +9 -0
  15. package/src/utils/zipDirectory.ts +31 -0
  16. package/tsconfig.json +1 -6
  17. package/tsconfig.tsbuildinfo +1 -1
  18. package/.gitlab-ci.yml +0 -115
  19. package/jest.integration.config.ts +0 -17
  20. package/lib/component-dev-folder-structures.spec.js +0 -58
  21. package/lib/component-dev-folder-structures.spec.js.map +0 -1
  22. package/lib/component-dev.d.ts +0 -16
  23. package/lib/component-dev.js +0 -49
  24. package/lib/component-dev.js.map +0 -1
  25. package/lib/component-dev.spec.d.ts +0 -1
  26. package/lib/component-dev.spec.js +0 -54
  27. package/lib/component-dev.spec.js.map +0 -1
  28. package/lib/integration-tests/__components__/big-package/manifest.json +0 -35
  29. package/lib/integration-tests/__components__/cmp-static-file-test/manifest.json +0 -39
  30. package/lib/integration-tests/__components__/invalid-manifest/manifest.json +0 -27
  31. package/lib/integration-tests/helper.d.ts +0 -19
  32. package/lib/integration-tests/helper.js +0 -73
  33. package/lib/integration-tests/helper.js.map +0 -1
  34. package/lib/integration-tests/service-deployment.spec.d.ts +0 -1
  35. package/lib/integration-tests/service-deployment.spec.js +0 -36
  36. package/lib/integration-tests/service-deployment.spec.js.map +0 -1
  37. package/lib/integration-tests/test-setup.d.ts +0 -0
  38. package/lib/integration-tests/test-setup.js +0 -3
  39. package/lib/integration-tests/test-setup.js.map +0 -1
  40. package/lib/integration-tests/upload-and-render-component.spec.d.ts +0 -1
  41. package/lib/integration-tests/upload-and-render-component.spec.js +0 -141
  42. package/lib/integration-tests/upload-and-render-component.spec.js.map +0 -1
  43. package/lib/upload-component-folder.d.ts +0 -3
  44. package/lib/upload-component-folder.js +0 -131
  45. package/lib/upload-component-folder.js.map +0 -1
  46. package/src/component-dev-folder-structures.spec.ts +0 -69
  47. package/src/component-dev.spec.ts +0 -59
  48. package/src/component-dev.ts +0 -60
  49. package/src/integration-tests/__components__/big-package/manifest.json +0 -36
  50. package/src/integration-tests/__components__/big-package/render-json.js +0 -5
  51. package/src/integration-tests/__components__/cmp-static-file-test/main.js +0 -10
  52. package/src/integration-tests/__components__/cmp-static-file-test/manifest.json +0 -42
  53. package/src/integration-tests/__components__/cmp-static-file-test/public/static-library-file.js +0 -1
  54. package/src/integration-tests/__components__/invalid-manifest/main.js +0 -7
  55. package/src/integration-tests/__components__/invalid-manifest/manifest.json +0 -29
  56. package/src/integration-tests/__components__/invalid-upload/main.js +0 -7
  57. package/src/integration-tests/helper.ts +0 -79
  58. package/src/integration-tests/service-deployment.spec.ts +0 -45
  59. package/src/integration-tests/test-setup.ts +0 -1
  60. package/src/integration-tests/upload-and-render-component.spec.ts +0 -173
  61. package/src/upload-component-folder.ts +0 -145
@@ -1,59 +0,0 @@
1
- import { routeTests, TestHelpers } from '@squiz/render-runtime-lib';
2
- import { startDevelopmentRender } from './component-dev';
3
- import supertest from 'supertest';
4
- import { Server } from 'http';
5
-
6
- jest.setTimeout(20_000);
7
-
8
- describe('component-dev', () => {
9
- describe('accessing local dev routes', () => {
10
- let server: Server;
11
- let request: supertest.SuperTest<supertest.Test>;
12
- beforeAll(async () => {
13
- server = startDevelopmentRender(TestHelpers.getTestComponentFolder(), { port: 0 });
14
- request = supertest(server);
15
- });
16
-
17
- afterAll(async () => {
18
- server.close();
19
- });
20
-
21
- it('should fail validation when requesting a function with a missing entry file', async () => {
22
- const response = await request.get(
23
- '/r/set/unit-test-components/test-component/1.0.3/non-existent-entry-file?something=not-used',
24
- );
25
-
26
- expect(response.body).toEqual({
27
- message: '"main\'s" entry file "missing-entry-file.js" is inaccessible',
28
- });
29
- expect(response.statusCode).toEqual(500);
30
- });
31
-
32
- describe('definition routes', () => {
33
- const server = startDevelopmentRender(TestHelpers.getTestComponentFolder(), { port: 0 });
34
- const request = () => supertest(server);
35
- routeTests.definition(request, 'http://localhost:0');
36
- afterAll(() => {
37
- server.close();
38
- });
39
- });
40
-
41
- describe('static routes', () => {
42
- const server = startDevelopmentRender(TestHelpers.getTestComponentFolder(), { port: 0 });
43
- const request = () => supertest(server);
44
- routeTests.static(request);
45
- afterAll(() => {
46
- server.close();
47
- });
48
- });
49
-
50
- describe('render routes', () => {
51
- const server = startDevelopmentRender(TestHelpers.getTestComponentFolder(), { port: 0 });
52
- const request = () => supertest(server);
53
- routeTests.render(request, 'http://localhost:0');
54
- afterAll(() => {
55
- server.close();
56
- });
57
- });
58
- });
59
- });
@@ -1,60 +0,0 @@
1
- import {
2
- ComponentPreviewService,
3
- ComponentRunnerServiceWithWorkers,
4
- setupRenderRuntimeServer,
5
- } from '@squiz/render-runtime-lib';
6
- import { getLogger, LoggerOptions } from '@squiz/dx-logger-lib';
7
- import path from 'path';
8
- import { ComponentFunctionService, ComponentSetServiceForLocalDev, ManifestServiceForDev } from '@squiz/component-lib';
9
-
10
- /**
11
- * startDevelopmentRender starts a dev-mode render stack for any
12
- * local directory. This should start an express server on a random unused port
13
- * which can be accessed for viewing the component in development.
14
- *
15
- * @param {string} componentPath - The directory with the component to be rendered
16
- * @param {object} options - Additional configuration for the dev stack
17
- * @returns a function to stop the render stack
18
- */
19
- export function startDevelopmentRender(
20
- componentPath: string,
21
- options: { port: number; previewFile?: string; loggingFormat?: LoggerOptions['format'] },
22
- ) {
23
- const logger = getLogger({ name: 'component-dev', format: options.loggingFormat || 'human' });
24
- const rootUrl = `http://localhost:${options.port}`;
25
- const dataMountPoint = path.resolve(process.cwd(), componentPath);
26
-
27
- const componentRunnerService = new ComponentRunnerServiceWithWorkers(
28
- {
29
- dataMountPoint,
30
- shouldCacheResponses: false,
31
- workerTimeout: 5_000,
32
- },
33
- logger,
34
- );
35
- const webServer = setupRenderRuntimeServer(
36
- {
37
- logger,
38
- componentRunnerService,
39
- componentSetService: new ComponentSetServiceForLocalDev(logger),
40
- componentFunctionService: new ComponentFunctionService(rootUrl),
41
- componentPreviewService: new ComponentPreviewService(options.previewFile),
42
- manifestService: new ManifestServiceForDev(dataMountPoint, logger),
43
- },
44
- { rootUrl },
45
- );
46
-
47
- const server = webServer.listen(options.port, () => {
48
- logger.info(`Component development webserver started on port ${options.port}`);
49
- });
50
-
51
- server.on('close', async () => {
52
- await componentRunnerService.stop();
53
- });
54
-
55
- process.on('SIGINT', () => {
56
- server.close();
57
- });
58
-
59
- return server;
60
- }
@@ -1,36 +0,0 @@
1
- {
2
- "$schema": "http://localhost:3000/schemas/v1.json#",
3
-
4
- "name": "big-package",
5
- "version": "1.0.2",
6
- "main-function": "render-json",
7
- "namespace": "smoke-test-components",
8
- "display-name": "some-display-name",
9
- "description": "some-description",
10
- "functions": [
11
- {
12
- "name": "render-json",
13
- "entry": "render-json.js",
14
- "input": {
15
- "type": "object",
16
- "properties": {
17
- "something": {
18
- "type": "string"
19
- }
20
- },
21
- "required": ["something"]
22
- },
23
- "output": {
24
- "response-type": "json",
25
- "definition": {
26
- "properties": {
27
- "my-prop": {
28
- "type": "string"
29
- }
30
- },
31
- "required": ["my-prop"]
32
- }
33
- }
34
- }
35
- ]
36
- }
@@ -1,5 +0,0 @@
1
- module.exports = async function () {
2
- return {
3
- 'my-prop': 'test value for my-prop',
4
- };
5
- };
@@ -1,10 +0,0 @@
1
- /**
2
- * @param {object} input
3
- * @param {ComponentInfo} info
4
- */
5
- module.exports = async function (input, info) {
6
- return (
7
- `<div>Input: ${input.something}</div>` +
8
- `<div>${info.ctx.componentName} ${info.ctx.version} ${info.ctx.getStaticResourceUrl('birthday-cake.png')}</div>`
9
- );
10
- };
@@ -1,42 +0,0 @@
1
- {
2
- "$schema": "http://localhost:3000/schemas/v1.json#",
3
-
4
- "name": "cmp-static-file-test",
5
- "version": "1.0.0",
6
- "main-function": "main",
7
- "namespace": "smoke-test-components",
8
- "display-name": "some-display-name",
9
- "description": "some-description",
10
- "functions": [
11
- {
12
- "entry": "main.js",
13
- "name": "main",
14
- "input": {
15
- "type": "object",
16
- "properties": {
17
- "something": {
18
- "type": "string"
19
- }
20
- },
21
- "required": ["something"]
22
- },
23
- "output": {
24
- "response-type": "html",
25
-
26
- "static-files": [
27
- {
28
- "location": "header",
29
- "file": {
30
- "filepath": "static-library-file.js",
31
- "type": "js"
32
- }
33
- }
34
- ]
35
- }
36
- }
37
- ],
38
-
39
- "static-files": {
40
- "location-root": "public"
41
- }
42
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * @param {object} input
3
- * @param {ComponentInfo} info
4
- */
5
- module.exports = async function (input, info) {
6
- return '<div>test</div>';
7
- };
@@ -1,29 +0,0 @@
1
- {
2
- "$schema": "http://localhost:3000/schemas/v1.json#",
3
-
4
- "name": "invalid-manifes@t",
5
- "version": "1.0.0",
6
- "main-function": "main",
7
- "namespace": "smoke-test-components",
8
- "display-name": "some-display-name",
9
- "description": "some-description",
10
-
11
- "functions": [
12
- {
13
- "entry": "main.js",
14
- "name": "main",
15
- "input": {
16
- "type": "object",
17
- "properties": {
18
- "something": {
19
- "type": "string"
20
- }
21
- },
22
- "required": ["something"]
23
- },
24
- "output": {
25
- "response-type": "html"
26
- }
27
- }
28
- ]
29
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * @param {object} input
3
- * @param {ComponentInfo} info
4
- */
5
- module.exports = async function (input, info) {
6
- return '<div>test</div>';
7
- };
@@ -1,79 +0,0 @@
1
- import axios from 'axios';
2
- import fs from 'fs';
3
- import path from 'path';
4
-
5
- import fsp from 'fs/promises';
6
- import { randomBytes } from 'crypto';
7
- import { ComponentSetWebModel } from '@squiz/component-lib';
8
- import { parseEnvVarForVar } from '@squiz/dx-common-lib';
9
- import { config } from 'dotenv';
10
-
11
- config();
12
-
13
- interface Config {
14
- managementServiceUrl: string;
15
- renderServiceUrl: string;
16
- ci_buildVersion: string;
17
- ci_buildBranch: string;
18
- }
19
-
20
- const configObj: Config = {
21
- managementServiceUrl: parseEnvVarForVar('COMPONENT_MANAGEMENT_SERVICE_URL').replace(/\/+$/, ''),
22
- renderServiceUrl: parseEnvVarForVar('COMPONENT_RENDER_SERVICE_URL').replace(/\/+$/, ''),
23
- ci_buildVersion: parseEnvVarForVar('CI_COMMIT_SHORT_SHA'),
24
- ci_buildBranch: parseEnvVarForVar('CI_COMMIT_REF_NAME'),
25
- };
26
-
27
- export default configObj;
28
-
29
- export const managementService = axios.create({
30
- baseURL: configObj.managementServiceUrl + '/v1',
31
- });
32
-
33
- export const managementServiceRoot = axios.create({
34
- baseURL: configObj.managementServiceUrl,
35
- });
36
-
37
- export const renderService = axios.create({
38
- baseURL: configObj.renderServiceUrl,
39
- });
40
-
41
- export const ci_buildVersion = configObj.ci_buildVersion;
42
- export const ci_buildBranch = configObj.ci_buildBranch;
43
-
44
- export function getTestComponents(): string[] {
45
- const componets = [];
46
- const componentsDir = path.join(__dirname, '/__components__/');
47
- const files = fs.readdirSync(componentsDir);
48
- for (const file of files) {
49
- const stat = fs.statSync(path.join(componentsDir, file));
50
- if (stat.isDirectory() && file.substring(0, 4) === 'cmp-') {
51
- componets.push(file);
52
- }
53
- }
54
- return componets;
55
- }
56
- export async function createFile(filePath: string, sizeInMB: number) {
57
- const content = randomBytes(sizeInMB * 1000000);
58
- await fsp.writeFile(`${filePath}`, content);
59
- }
60
-
61
- export function removeFile(filePath: string) {
62
- fsp.unlink(filePath);
63
- }
64
-
65
- export async function deleteComponentSet(webPath: string) {
66
- try {
67
- await managementService.delete(`/component-set/${webPath}`);
68
- } catch (error) {
69
- // no ops
70
- }
71
- }
72
-
73
- export async function addComponentSet(componentSet: ComponentSetWebModel) {
74
- try {
75
- await managementService.post(`/component-set`, componentSet);
76
- } catch (error) {
77
- //no ops
78
- }
79
- }
@@ -1,45 +0,0 @@
1
- import { renderService, managementService, managementServiceRoot, ci_buildVersion, ci_buildBranch } from './helper';
2
-
3
- interface HealthInfo {
4
- status: string;
5
- buildVersion: string;
6
- buildBranch: string;
7
- }
8
-
9
- describe('Verify latest services deployments', () => {
10
- it('Should have latest Management API service', async () => {
11
- const response: HealthInfo = (await managementServiceRoot.get('/health')).data;
12
- expect(response.buildVersion).toBe(ci_buildVersion);
13
- expect(response.buildBranch).toBe(ci_buildBranch);
14
- });
15
-
16
- it('Should return 200 for Management API docs', async () => {
17
- const req = await managementService.get('/docs');
18
- expect(req.status).toBe(200);
19
- expect(req.headers['content-type']).toEqual('text/html; charset=utf-8');
20
- });
21
-
22
- it('Should return 200 for Management API docs.json', async () => {
23
- const req = await managementService.get('/docs.json');
24
- expect(req.status).toBe(200);
25
- expect(req.headers['content-type']).toEqual('application/json; charset=UTF-8');
26
- });
27
-
28
- it('Should have latest Render Runtime service', async () => {
29
- const response: HealthInfo = (await renderService.get('/health')).data;
30
- expect(response.buildVersion).toBe(ci_buildVersion);
31
- expect(response.buildBranch).toBe(ci_buildBranch);
32
- });
33
-
34
- it('Should return 200 for Render Runtime API docs', async () => {
35
- const req = await renderService.get('/docs');
36
- expect(req.status).toBe(200);
37
- expect(req.headers['content-type']).toEqual('text/html; charset=utf-8');
38
- });
39
-
40
- it('Should return 200 for Render Runtime API docs.json', async () => {
41
- const req = await renderService.get('/docs.json');
42
- expect(req.status).toBe(200);
43
- expect(req.headers['content-type']).toEqual('application/json; charset=UTF-8');
44
- });
45
- });
@@ -1 +0,0 @@
1
- jest.setTimeout(60_000);
@@ -1,173 +0,0 @@
1
- import { uploadComponentFolder } from '../index';
2
- import configObj, {
3
- renderService,
4
- managementService,
5
- getTestComponents,
6
- createFile,
7
- removeFile,
8
- addComponentSet,
9
- deleteComponentSet,
10
- } from './helper';
11
- import color from 'cli-color';
12
- import path from 'path';
13
- import supertest from 'supertest';
14
- import { logger } from '../upload-component-folder';
15
- import { ComponentSetWebModel } from '@squiz/component-lib';
16
- import fsp from 'fs/promises';
17
-
18
- const mockConsoleError = jest.fn();
19
- const mockConsoleLog = jest.fn();
20
-
21
- const orgConsoleError = console.error;
22
- const webPath = 'set';
23
- const testFilesDir = path.resolve(__dirname, 'test-files');
24
-
25
- beforeAll(async () => {
26
- await fsp.rm(testFilesDir, { force: true, recursive: true });
27
- await fsp.mkdir(testFilesDir);
28
- });
29
-
30
- afterAll(async () => {
31
- // clean up the component added by the test
32
- await deleteComponentSet(webPath);
33
-
34
- for (const componentName of getTestComponents()) {
35
- try {
36
- await managementService.delete(`/component/smoke-test-components/${componentName}`);
37
- } catch {
38
- // no op
39
- }
40
- }
41
-
42
- // clean up the test componnet files
43
- await fsp.rm(testFilesDir, { force: true, recursive: true });
44
- });
45
-
46
- describe('Test isolated test cases', () => {
47
- beforeEach(() => {
48
- jest.spyOn(logger, 'error').mockImplementation(mockConsoleError);
49
- jest.spyOn(logger, 'info').mockImplementation(mockConsoleLog);
50
- });
51
-
52
- it('Should fail uploading a component without manifest.json', async () => {
53
- mockConsoleError.mockClear();
54
- const componentPath = path.join(__dirname, '/__components__/invalid-upload');
55
- await uploadComponentFolder(
56
- componentPath,
57
- configObj.managementServiceUrl + '/v1',
58
- configObj.renderServiceUrl,
59
- testFilesDir,
60
- );
61
- expect(mockConsoleError.mock.calls[0][0]).toEqual(color.red('manifest could not be found'));
62
- });
63
-
64
- it('Should fail uploading a component that has invalid manifest.json', async () => {
65
- mockConsoleError.mockClear();
66
- const componentPath = path.join(__dirname, '/__components__/invalid-manifest');
67
- await uploadComponentFolder(
68
- componentPath,
69
- configObj.managementServiceUrl + '/v1',
70
- configObj.renderServiceUrl,
71
- testFilesDir,
72
- );
73
- expect(mockConsoleError.mock.calls[0][0]).toEqual(
74
- color.red('failed validation: /name pattern must match pattern "^[a-zA-Z0-9_\\-]+$"'),
75
- );
76
- });
77
-
78
- it('Should fail uploading the component that has size more than 100MB', async () => {
79
- mockConsoleError.mockClear();
80
- const componentPath = path.join(__dirname, '/__components__/big-package');
81
- const filePath = `${componentPath}/105mb-file`;
82
- await createFile(filePath, 105); // Higher limit has been used because compression reduces the size if you use closer to 100MB
83
- await uploadComponentFolder(
84
- componentPath,
85
- configObj.managementServiceUrl + '/v1',
86
- configObj.renderServiceUrl,
87
- testFilesDir,
88
- );
89
- expect(mockConsoleError.mock.calls[0][0]).toEqual(
90
- color.red(['File size exceeds the maximum limit of 100MB'].join('')),
91
- );
92
- removeFile(filePath);
93
- });
94
- });
95
-
96
- describe('Deploy basic component having a static file', () => {
97
- // component to deploy for this test
98
- const componentPath = path.join(__dirname, '/__components__/cmp-static-file-test');
99
-
100
- beforeAll(async () => {
101
- await deleteComponentSet(webPath);
102
- for (const componentName of getTestComponents()) {
103
- try {
104
- await managementService.delete(`/component/${componentName}`);
105
- } catch {
106
- // no op
107
- }
108
- }
109
- });
110
-
111
- beforeEach(() => {
112
- console.error = mockConsoleError;
113
- console.log = mockConsoleLog;
114
- });
115
-
116
- afterEach(() => {
117
- console.error = orgConsoleError;
118
- });
119
-
120
- it('Should upload the component and return a valid url to preview', async () => {
121
- await uploadComponentFolder(
122
- componentPath,
123
- configObj.managementServiceUrl + '/v1',
124
- configObj.renderServiceUrl,
125
- testFilesDir,
126
- );
127
-
128
- const uploadedComponent = '<a href="/r/set/smoke-test-components/cmp-static-file-test/1.0.0">1.0.0</a>';
129
- const get = await supertest(configObj.renderServiceUrl).get('/');
130
- expect(get.status).toEqual(200);
131
- expect((get as any)?.res?.text).toContain(uploadedComponent);
132
- });
133
-
134
- it('Should fail upload the component with same version', async () => {
135
- mockConsoleError.mockClear();
136
- await uploadComponentFolder(
137
- componentPath,
138
- configObj.managementServiceUrl + '/v1',
139
- configObj.renderServiceUrl,
140
- testFilesDir,
141
- );
142
- expect(mockConsoleError.mock.calls[0][0]).toEqual(
143
- color.red('Cannot upload component version, smoke-test-components/cmp-static-file-test 1.0.0 already exists'),
144
- );
145
- });
146
-
147
- it('Should render component', async () => {
148
- const componentSet: ComponentSetWebModel = {
149
- webPath,
150
- displayName: 'Set',
151
- description: 'Set description',
152
- headers: {},
153
- envVars: {},
154
- components: {
155
- 'smoke-test-components/cmp-static-file-test': [{ envVars: {}, version: '1.0.0' }],
156
- },
157
- };
158
-
159
- await addComponentSet(componentSet);
160
-
161
- const response = await renderService.get(
162
- '/r/set/smoke-test-components/cmp-static-file-test/1.0.0/?something=hello',
163
- );
164
- expect(response.status).toEqual(200);
165
- expect(response.data).toEqual(
166
- [
167
- '<div>Input: hello</div>',
168
- '<div>smoke-test-components/cmp-static-file-test 1.0.0 ',
169
- `${configObj.renderServiceUrl}/s/smoke-test-components/cmp-static-file-test/1.0.0/birthday-cake.png</div>`,
170
- ].join(''),
171
- );
172
- });
173
- });