biz-a-cli 2.3.57 → 2.3.59

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "biz-a-cli",
3
3
  "nameDev": "biz-a-cli-dev",
4
- "version": "2.3.57",
4
+ "version": "2.3.59",
5
5
  "versionDev": "0.0.34",
6
6
  "description": "",
7
7
  "main": "bin/index.js",
@@ -12,9 +12,9 @@
12
12
  },
13
13
  "scripts": {
14
14
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch a",
15
- "test1": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
15
+ "testOnce": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
16
16
  "dev": "node --watch server.js",
17
- "hub": "node --experimental-vm-modules bin/hub.js"
17
+ "hub": "set NODE_ENV=production && node --experimental-vm-modules bin/hub.js"
18
18
  },
19
19
  "author": "Imamatek",
20
20
  "license": "ISC",
@@ -41,7 +41,7 @@
41
41
  "socket.io-client": "^4.7.5",
42
42
  "socket.io-stream": "^0.9.1",
43
43
  "tar": "^7.4.0",
44
- "uglify-js": "^3.17.4",
44
+ "uglify-js": "^3.19.3",
45
45
  "web-push": "^3.6.7",
46
46
  "winston": "^3.13.0",
47
47
  "yargs": "^17.7.2"
@@ -55,6 +55,9 @@
55
55
  "<rootDir>/tests/**",
56
56
  "!<rootDir>/tests/mockData",
57
57
  "!<rootDir>/tests/mockData/**"
58
- ]
58
+ ],
59
+ "testPathIgnorePatterns": ["<rootDir>/node_modules", "<rootDir>/tests/mockData"],
60
+ "watchPathIgnorePatterns": ["<rootDir>/node_modules", "<rootDir>/tests/mockData"],
61
+ "coveragePathIgnorePatterns": ["<rootDir>/node_modules", "<rootDir>/tests/mockData", "<rootDir>/tests/mockData/**"]
59
62
  }
60
63
  }
package/tests/app.test.js CHANGED
@@ -47,14 +47,12 @@ describe('Biz-A Apps CLI', ()=>{
47
47
 
48
48
  describe('Add App', ()=>{
49
49
  const mockDataFolder = './tests/mockData/'
50
- const appName = 'mockApp'
51
- const appFolderName = mockDataFolder + appName+ '/';
52
50
 
53
- function mockValidTemplates(scriptList){
54
- fs.rmSync(appFolderName, {force: true, recursive: true})
55
- fs.mkdirSync(appFolderName, {recursive: true})
51
+ function mockValidTemplates(appName, scriptList){
52
+ fs.rmSync(mockDataFolder+'/'+appName, {force: true, recursive: true})
53
+ fs.mkdirSync(mockDataFolder+'/'+appName, {recursive: true})
56
54
  for (const [key, value] of Object.entries(scriptList)){
57
- fs.writeFileSync(appFolderName+key, value.act)
55
+ fs.writeFileSync(mockDataFolder+'/'+appName + '/' + key, value.act)
58
56
  }
59
57
  }
60
58
 
@@ -70,7 +68,7 @@ describe('Biz-A Apps CLI', ()=>{
70
68
  axios.post.mockResolvedValue({data: {success: true}, status: 200})
71
69
  }
72
70
 
73
- beforeEach(()=>{
71
+ beforeAll(()=>{
74
72
  fs.rmSync(mockDataFolder, {recursive: true, force: true})
75
73
  })
76
74
 
@@ -79,7 +77,7 @@ describe('Biz-A Apps CLI', ()=>{
79
77
  })
80
78
 
81
79
  const stressTestCount = 10;
82
- it.each(Array(stressTestCount).fill().map((v,i)=>i+1))(`shall compress and encrypt app scripts (stress test %p of ${stressTestCount})`, async ()=>{
80
+ it.each(Array(stressTestCount).fill().map((v,i)=>i+1))(`shall compress and encrypt app scripts (stress test %p of ${stressTestCount})`, async (testNo)=>{
83
81
  const mockScripts = {
84
82
  'a.js' : {
85
83
  act: 'get = function () {return {modelA: {}}}',
@@ -154,11 +152,12 @@ describe('Biz-A Apps CLI', ()=>{
154
152
  }
155
153
  }
156
154
 
157
- mockValidTemplates(mockScripts)
155
+ const appName = 'compressStressTest' + testNo
156
+ mockValidTemplates(appName, mockScripts)
158
157
  mockIssuerKeyResponse()
159
158
  const mockAESKey = Buffer.from('hAnHadaJXJaq/9fCFMNmjkrB61CBPXJid6vbtXgG8Ug=', 'base64')
160
159
 
161
- await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', appFolderName)
160
+ await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/' + appName)
162
161
 
163
162
  expect(axios.get.mock.calls).toHaveLength(1)
164
163
  const getArgs = axios.get.mock.calls[0]
@@ -233,6 +232,8 @@ describe('Biz-A Apps CLI', ()=>{
233
232
 
234
233
  expect(logSpy.mock.calls[0][0]).toContain(`Finished packing ${Object.keys(mockScripts).length} files into "./upload/${appName.toLowerCase()}.tgz"`)
235
234
  expect(logSpy.mock.calls[1][0]).toContain(`Finished uploading "./upload/${appName.toLocaleLowerCase()}.tgz"`)
235
+
236
+ // fs.rmSync(mockDataFolder + '/' + appName, {recursive: true, force: true})
236
237
  })
237
238
 
238
239
  /* it('Invalid script syntax', async ()=>{
@@ -290,57 +291,61 @@ describe('Biz-A Apps CLI', ()=>{
290
291
  'Invalid script syntax',
291
292
  {act: 'get = function () {return {modelA: {}}'}, // missing close closure at the end',
292
293
  ()=>{
293
- expect(logSpy.mock.calls.length).toBe(1)
294
+ expect(logSpy.mock.calls.length).toBe(5)
294
295
  expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
296
+ expect(logSpy.mock.calls[1][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
297
+ expect(logSpy.mock.calls[2][0]).toStrictEqual('a.js:1:38: SyntaxError: Unexpected token: eof, expected: punc «}»')
298
+ expect(logSpy.mock.calls[3][0]).toStrictEqual('Running script with Import function')
299
+ expect(logSpy.mock.calls[4][0]).toStrictEqual('===================\nEOF A.JS\n===================')
295
300
 
296
301
  expect(errorSpy.mock.calls.length).toBe(1)
297
- // expect(errorSpy.mock.calls[0][0]).toStrictEqual({e: 'a.js:1:38: SyntaxError: Unexpected token: eof, expected: punc «}»'})
298
- expect(errorSpy.mock.calls[0][0]).toStrictEqual('a.js:1:38: SyntaxError: Unexpected token: eof, expected: punc «}»')
302
+ expect(errorSpy.mock.calls[0][0]).toBe('a.js : SyntaxError: Unexpected end of input')
299
303
  }
300
304
  ],
301
305
  [
302
306
  'Failed to compile script with node sandbox and ES6 Import',
303
307
  {act: 'get = function () {return {modelA: {}}}\n modul.expor = get;\n'}, // wrong "module.export"
304
308
  ()=>{
305
- expect(logSpy.mock.calls.length).toBe(5)
309
+ expect(logSpy.mock.calls.length).toBe(6)
306
310
  expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
307
- expect(logSpy.mock.calls[1][0]).toBe('Minify : \nget=function(){return{modelA:{}}};modul.expor=get;')
308
- expect(logSpy.mock.calls[2][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
311
+ expect(logSpy.mock.calls[1][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
312
+ expect(logSpy.mock.calls[2][0]).toBe('Minify : \nget=function(){return{modelA:{}}};modul.expor=get;')
309
313
  expect(logSpy.mock.calls[3][0]).toBe("a.js : ReferenceError: modul is not defined")
310
314
  expect(logSpy.mock.calls[4][0]).toBe('Running script with Import function')
315
+ expect(logSpy.mock.calls[5][0]).toStrictEqual('===================\nEOF A.JS\n===================')
311
316
 
312
317
  expect(errorSpy.mock.calls.length).toBe(1)
313
- // expect(errorSpy.mock.calls[0][0]).toStrictEqual({e: 'a.js : ReferenceError: modul is not defined'}) // ES6 import error
314
- expect(errorSpy.mock.calls[0][0]).toStrictEqual('a.js : ReferenceError: modul is not defined')// ES6 import error
318
+ expect(errorSpy.mock.calls[0][0]).toStrictEqual('a.js : Error: Invalid data URI')// ES6 import error
315
319
  }
316
320
  ],
317
321
  [
318
322
  'Shall not allow empty script',
319
323
  {act: 'get = function () {}'}, // empty script
320
324
  ()=>{
321
- expect(logSpy.mock.calls.length).toBe(4)
325
+ expect(logSpy.mock.calls.length).toBe(5)
322
326
  expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
323
- expect(logSpy.mock.calls[1][0]).toBe('Minify : \nget=function(){};')
324
- expect(logSpy.mock.calls[2][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
327
+ expect(logSpy.mock.calls[1][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
328
+ expect(logSpy.mock.calls[2][0]).toBe('Minify : \nget=function(){};')
325
329
  expect(logSpy.mock.calls[3][0]).toBe('Running script with Import function')
330
+ expect(logSpy.mock.calls[4][0]).toStrictEqual('===================\nEOF A.JS\n===================')
326
331
 
327
332
  expect(errorSpy.mock.calls.length).toBe(1)
328
- // expect(errorSpy.mock.calls[0][0]).toStrictEqual({e: 'a.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result'})
329
333
  expect(errorSpy.mock.calls[0][0]).toStrictEqual('a.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result')
330
334
  }
331
335
  ],
332
336
  ]
333
337
  it.each(errorHandlingTestCases)('%p', async (name, scripts, expectedFn)=>{
334
- mockValidTemplates({'a.js' : scripts})
338
+ const appName = 'errorHandlingTest' + errorHandlingTestCases.findIndex(testCase => testCase[0] === name)
339
+ mockValidTemplates(appName, {'a.js' : scripts})
335
340
  mockIssuerKeyResponse()
336
- await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', appFolderName, "-v")
341
+ await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/' + appName, "-v")
337
342
  expectedFn()
338
343
  })
339
344
 
340
- it('Shall not allow empty app', async ()=>{
341
- mockValidTemplates({})
345
+ it('Shall not allow app without script template', async ()=>{
346
+ mockValidTemplates(expect.getState().currentTestName, {})
342
347
  mockIssuerKeyResponse()
343
- await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', appFolderName, "-v")
348
+ await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/' + expect.getState().currentTestName, "-v")
344
349
 
345
350
  expect(logSpy.mock.calls.length).toBe(0)
346
351
 
@@ -350,7 +355,7 @@ describe('Biz-A Apps CLI', ()=>{
350
355
 
351
356
  it('Shall recommend command', async ()=>{
352
357
  const exitSpy = jest.spyOn(process, 'exit').mockImplementation(()=>{})
353
- await runCommand('Add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', appFolderName, "-v")
358
+ await runCommand('Add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/NotExistFolder', "-v")
354
359
  expect(logSpy.mock.calls.length).toBe(0)
355
360
  expect(exitSpy).toHaveBeenCalledWith(1) // exit code = 1
356
361
  expect(errorSpy.mock.calls[errorSpy.mock.calls.length-1][0]).toBe('Did you mean add?')
@@ -419,4 +424,63 @@ describe('Biz-A Apps CLI', ()=>{
419
424
  })
420
425
  })
421
426
 
427
+ it('Shall have options', async ()=>{
428
+ jest.spyOn(process, 'exit').mockImplementation()
429
+ const appModule = await import('../bin/app.js')
430
+ expect(appModule.options).toStrictEqual({
431
+ "s" : {
432
+ alias: "server",
433
+ describe: `API or Server URL (ex: ${env.BIZA_SERVER_LINK} or http://192.168.1.1 or https://finaapi.imamatek.com)`,
434
+ type: "string",
435
+ demandOption: true,
436
+ default: 'http://localhost'
437
+ },
438
+ "i" : {
439
+ alias: "dbIndex",
440
+ default: 2,
441
+ describe: "database index",
442
+ type: "number",
443
+ demandOption: false
444
+ },
445
+ "sub": {
446
+ alias: "subdomain",
447
+ describe: "Subdomain",
448
+ type: "string",
449
+ demandOption: false
450
+ },
451
+ "p": {
452
+ alias: "apiPort",
453
+ default : 212,
454
+ describe: "FINA API Port",
455
+ type: "number",
456
+ demandOption: false,
457
+ }
458
+ })
459
+ expect(appModule.addCommandOptions).toStrictEqual({
460
+ 'd': {
461
+ alias: "workingDir",
462
+ describe: "Path to templates directory",
463
+ type: "string",
464
+ demandOption: false,
465
+ default: process.cwd(),
466
+ },
467
+ 'v': {
468
+ alias: "verbose",
469
+ describe: "Print info to console",
470
+ type: "boolean",
471
+ demandOption: false,
472
+ default: false,
473
+ }
474
+ })
475
+ expect(appModule.removeCommandOptions).toStrictEqual({
476
+ 'n': {
477
+ alias: "appName",
478
+ describe: "Application name",
479
+ type: "string",
480
+ demandOption: true,
481
+ default: ""
482
+ }
483
+ })
484
+ })
485
+
422
486
  })
@@ -0,0 +1,4 @@
1
+ [0605/214850.720:ERROR:registration_protocol_win.cc(108)] CreateFile: The system cannot find the file specified. (0x2)
2
+ [0605/214852.995:ERROR:registration_protocol_win.cc(108)] CreateFile: The system cannot find the file specified. (0x2)
3
+ [0605/220241.422:ERROR:registration_protocol_win.cc(108)] CreateFile: The system cannot find the file specified. (0x2)
4
+ [0605/220243.465:ERROR:registration_protocol_win.cc(108)] CreateFile: The system cannot find the file specified. (0x2)
@@ -0,0 +1,351 @@
1
+ import { Server as ioServer } from 'socket.io';
2
+ import { getAppData, onScriptChangeFromVsCode, onScriptChangeFromHubServer} from '../bin/deployEvent.js'
3
+ import { io as ioClient, Socket, Manager } from "socket.io-client";
4
+ import { expect, jest } from '@jest/globals';
5
+ import axios from "axios";
6
+ import { directHubEvent, getSocketCORSOrigin, CLIENT_ROOM } from '../bin/directHubEvent.js'
7
+ import { createDecipheriv } from 'node:crypto'
8
+ import { hubEvent } from '../bin/hubEvent.js';
9
+
10
+ describe('Deployment', () => {
11
+
12
+ const hostname = '127.0.0.1'
13
+ const port = 7778
14
+ const dbindex = 2
15
+ const subdomain = 'deploy'
16
+
17
+ const toPromise = (cb) => new Promise((resolve, reject) => {
18
+ cb(resolve)
19
+ setTimeout(() => reject(new Error('timeout')), 1000)
20
+ })
21
+
22
+ function freeSocketClient(sock){
23
+ if (sock) {
24
+ if (sock.connected) {
25
+ sock.off()
26
+ sock.disconnect()
27
+ }
28
+ sock.destroy()
29
+ sock = undefined
30
+ }
31
+ }
32
+
33
+ beforeEach(()=>{
34
+ jest.restoreAllMocks()
35
+ })
36
+
37
+ afterEach(()=>{
38
+ jest.restoreAllMocks()
39
+ })
40
+
41
+ it('shall allow origins', ()=>{
42
+ expect(getSocketCORSOrigin(hostname)).toStrictEqual([
43
+ 'https://biz-a.id',
44
+ 'https://test.biz-a.id',
45
+ /\.biz-a\.id$/,
46
+ 'vscode-file://vscode-app',
47
+ /\.vscode-cdn\.net$/,
48
+ `http://${hostname}:4200`,
49
+ 'http://localhost:4200'
50
+ ])
51
+ })
52
+
53
+ it('shall get app list from database', async ()=>{
54
+ // Failed : check for error message
55
+ const requestSpy = jest.spyOn(axios, 'request').mockResolvedValueOnce({
56
+ status: 200,
57
+ statusText: 'Success',
58
+ data: {"recordsTotal": 2}
59
+ })
60
+ let result = await getAppData({hostname, port, dbindex, secure: true})
61
+ expect(requestSpy).toHaveBeenCalledWith({
62
+ timeout: 30*1000,
63
+ baseURL: `https://${hostname}:${port}`,
64
+ url: 'fina/rest/TOrmMethod/%22list%22',
65
+ method: "POST",
66
+ "data" : {"dbIndex":2, "object":{"columns":[
67
+ {"title":"app","data":"SYS$APPS.APPNAME"},
68
+ {"title":"metadata","data":"SYS$APPS.METADATA"}
69
+ ]}}
70
+ })
71
+
72
+ expect(result.error).toBe('"undefined" is not valid JSON')
73
+ expect(result.apps).toStrictEqual([])
74
+
75
+ // Success : check for apps data
76
+ const expectedAppData = [
77
+ {'SYS$APPS.APPNAME': 'firstApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
78
+ {'SYS$APPS.APPNAME': 'secondApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
79
+ ]
80
+
81
+ requestSpy.mockResolvedValueOnce({
82
+ status: 200,
83
+ statusText: 'Success',
84
+ data: {
85
+ "recordsTotal": 2,
86
+ data: JSON.stringify(expectedAppData)
87
+ }
88
+ })
89
+ result = await getAppData({hostname, port, dbindex})
90
+ expect(result.error).toBe(null)
91
+ expect(result.apps).toStrictEqual(expectedAppData)
92
+ })
93
+
94
+ it('shall log connect and disconnect', async ()=>{
95
+ const logSpy = jest.spyOn(console, 'log').mockImplementation()
96
+ let vsCodeToCLISock
97
+ let serverSideSock
98
+ const socketServer = new ioServer(1234)// mocking of CLI socket server
99
+ directHubEvent(socketServer, {subdomain, hostname, port: 1234, secure: false, dbindex, server: 'mockServer'})
100
+ try {
101
+ vsCodeToCLISock = await toPromise((resolve)=>{
102
+ const sock = ioClient(`http://${hostname}:${1234}`, {reconnection: false, query: {isDeploy: true}}).on('connect', async ()=>{
103
+ serverSideSock = (await socketServer.fetchSockets()).find(s=>s.id==sock.id)
104
+ resolve(sock)
105
+ })
106
+ })
107
+ expect(logSpy).toHaveBeenCalledTimes(1)
108
+ expect(logSpy).toHaveBeenCalledWith('<Deployer> ' + vsCodeToCLISock.id, 'connected')
109
+
110
+ logSpy.mockReset()
111
+ serverSideSock.disconnect()
112
+ expect(logSpy).toHaveBeenCalledTimes(1)
113
+ expect(logSpy).toHaveBeenCalledWith('<Deployer> ' + vsCodeToCLISock.id, 'disconnected. Reason : server namespace disconnect')
114
+ }
115
+ finally {
116
+ socketServer.close()
117
+ freeSocketClient(vsCodeToCLISock)
118
+ logSpy.mockRestore()
119
+ }
120
+ })
121
+
122
+ describe('from vs code', ()=>{
123
+
124
+ let cliSocketServer // mocking of CLI socket server
125
+
126
+ beforeAll(()=>{
127
+ cliSocketServer = new ioServer(port)// mocking of CLI socket server
128
+ directHubEvent(cliSocketServer, {subdomain, hostname, port, secure: false, dbindex, server: 'mockServer'})
129
+ })
130
+
131
+ afterAll(async ()=>{
132
+ if (cliSocketServer) {
133
+ (await cliSocketServer.of('').sockets).forEach((sock)=>{sock.removeAllListeners()})
134
+ await cliSocketServer.close()
135
+ }
136
+ })
137
+
138
+ it('shall have "appList" listener', async ()=>{
139
+ let vsCodeToCLISock
140
+ try {
141
+ jest.spyOn(console, 'log').mockImplementation()
142
+ jest.spyOn(axios, 'request').mockResolvedValueOnce({
143
+ status: 200,
144
+ statusText: 'Success',
145
+ data: {
146
+ "recordsTotal": 2,
147
+ data: JSON.stringify([
148
+ {'SYS$APPS.APPNAME': 'firstApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
149
+ {'SYS$APPS.APPNAME': 'secondApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
150
+ ])
151
+ }
152
+ })
153
+
154
+ vsCodeToCLISock = await toPromise((resolve)=>{
155
+ const sock = ioClient(`http://${hostname}:${port}`, {query: {isDeploy:true}}).on('connect', ()=>{resolve(sock)})
156
+ })
157
+
158
+ const [error, apps] = await toPromise(resolve => {vsCodeToCLISock.emit('appList', {}, (err, data)=>{resolve([err, data])})});
159
+ expect(error).toBe(null);
160
+ expect(apps).toStrictEqual(['firstApp', 'secondApp']);
161
+ }
162
+ finally {
163
+ freeSocketClient(vsCodeToCLISock)
164
+ }
165
+ })
166
+
167
+ it('shall prepare deploy script', async ()=>{
168
+ let vsCodeToCLISock
169
+ let serverSideSock
170
+ let emitSpy
171
+ let broadcastSpy
172
+ let result
173
+ try {
174
+ jest.spyOn(console, 'log').mockImplementation()
175
+
176
+ vsCodeToCLISock = await toPromise((resolve)=>{
177
+ const sock = ioClient(`http://${hostname}:${port}`).on('connect', async ()=>{
178
+ serverSideSock = (await cliSocketServer.fetchSockets()).find((s)=>s.id==sock.id)
179
+
180
+ // if using socket.broadcast.emit()
181
+ // const mockedBroadcast = serverSideSock.newBroadcastOperator()
182
+ // broadcastSpy = jest.fn().mockReturnValue(mockedBroadcast) // mock it to return same broadcast object
183
+ // serverSideSock.newBroadcastOperator = broadcastSpy
184
+
185
+ // if using socket.to(roomName).emit()
186
+ const mockedBroadcast = serverSideSock.to(CLIENT_ROOM)
187
+ broadcastSpy = jest.spyOn(serverSideSock, 'to').mockReturnValue(mockedBroadcast) // mock it to return same broadcast object
188
+
189
+ emitSpy = jest.spyOn(mockedBroadcast, 'emit').mockImplementation()
190
+
191
+ resolve(sock)
192
+ })
193
+ })
194
+ const mockAESKey = Buffer.from('hAnHadaJXJaq/9fCFMNmjkrB61CBPXJid6vbtXgG8Ug=', 'base64')
195
+ const requestSpy = jest.spyOn(axios, 'request').mockResolvedValue({status: 200, statusText: 'Success', data: mockAESKey})
196
+ const deployData = {appName: 'app', fileName: 'filename.js', script: "put script here for testing"}
197
+
198
+ // Failed of empty script
199
+ emitSpy.mockReset()
200
+ result = await onScriptChangeFromVsCode(
201
+ serverSideSock,
202
+ 'https://mock.server.com',
203
+ [{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
204
+ {...deployData, ...{script: ""}}
205
+ )
206
+ expect(result.error).toBe("filename.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result")
207
+ expect(result.script).toBeUndefined()
208
+ expect(requestSpy).not.toHaveBeenCalled()
209
+ expect(emitSpy).not.toHaveBeenCalled()
210
+
211
+
212
+ // Failed of invalid script syntax
213
+ emitSpy.mockReset()
214
+ result = await onScriptChangeFromVsCode(
215
+ serverSideSock,
216
+ 'https://mock.server.com',
217
+ [{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
218
+ {...deployData, ...{script: "invalidScript"}}
219
+ )
220
+ expect(result.error).toBe("filename.js : ReferenceError: invalidScript is not defined")
221
+ expect(result.script).toBeUndefined()
222
+ expect(requestSpy).not.toHaveBeenCalled()
223
+ expect(emitSpy).not.toHaveBeenCalled()
224
+
225
+
226
+ // Success : prepare script for BizA Client
227
+ emitSpy.mockReset()
228
+ const validScript = "get = function () {return {tableName: ''}}"
229
+ result = await onScriptChangeFromVsCode(
230
+ serverSideSock,
231
+ 'https://mock.server.com',
232
+ [{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
233
+ {...deployData, ...{script: validScript}}
234
+ )
235
+ expect(requestSpy).toHaveBeenCalledWith({
236
+ timeout: 30*1000,
237
+ baseURL: 'https://mock.server.com',
238
+ url: 'api/acquirerKey',
239
+ method: "POST",
240
+ data : {"metadata": JSON.stringify({data: '', signature: ''})}
241
+ })
242
+ expect(result.error).toBe(null)
243
+
244
+ const cipherText = Buffer.from(result.script, 'base64')
245
+ const decipher = createDecipheriv('aes-256-cbc', mockAESKey, cipherText.subarray(0, 16))
246
+ const decryptedScript = Buffer.concat([decipher.update(cipherText.subarray(16)), decipher.final()]).toString()
247
+ expect(decryptedScript).toBe('{"tableName":""}')
248
+
249
+ expect(emitSpy).toHaveBeenCalledTimes(1)
250
+ expect(emitSpy).toHaveBeenCalledWith('scriptDeploy', {appName: 'app', fileName: 'filename.js', script: result.script})
251
+ }
252
+ finally {
253
+ freeSocketClient(vsCodeToCLISock)
254
+ if (broadcastSpy) broadcastSpy.mockRestore()
255
+ }
256
+ })
257
+
258
+ it('shall have "scriptChange" listener', async ()=>{
259
+ let vsCodeToCLISock;
260
+ try {
261
+ jest.spyOn(console, 'log').mockImplementation()
262
+ vsCodeToCLISock = await toPromise((resolve)=>{
263
+ const sock = ioClient(`http://${hostname}:${port}`, {query: {isDeploy:true}}).on('connect', ()=>{resolve(sock)})
264
+ });
265
+
266
+ const requestSpy = jest.spyOn(axios, 'request');
267
+ requestSpy.mockResolvedValueOnce({
268
+ status: 200,
269
+ statusText: 'Success',
270
+ data: {
271
+ "recordsTotal": 2,
272
+ data: JSON.stringify([
273
+ {'SYS$APPS.APPNAME': 'firstApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
274
+ {'SYS$APPS.APPNAME': 'secondApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
275
+ ])
276
+ }
277
+ });
278
+
279
+ const [error, script] = await toPromise(resolve => {vsCodeToCLISock.emit('scriptChange', {appName: 'firstApp', fileName: 'filename.js', script: ""}, (err, data)=>{resolve([err, data])})});
280
+ expect(error).toBe("filename.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result");
281
+ expect(script).toBeNull();
282
+ }
283
+ finally {
284
+ freeSocketClient(vsCodeToCLISock);
285
+ };
286
+ });
287
+
288
+ });
289
+
290
+ describe('from Hub Server', ()=>{
291
+
292
+ it('shall prepare deploy script', async ()=>{
293
+ let result;
294
+
295
+ const mockAESKey = Buffer.from('hAnHadaJXJaq/9fCFMNmjkrB61CBPXJid6vbtXgG8Ug=', 'base64')
296
+ const requestSpy = jest.spyOn(axios, 'request').mockResolvedValue({status: 200, statusText: 'Success', data: mockAESKey})
297
+ const deployData = {appName: 'app', fileName: 'filename.js', script: "put script here for testing"}
298
+
299
+ // Failed of empty script
300
+ result = await onScriptChangeFromHubServer(
301
+ 'https://mock.server.com',
302
+ [{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
303
+ {...deployData, ...{script: ""}}
304
+ )
305
+ expect(result.error).toBe("filename.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result")
306
+ expect(result.script).toBeUndefined()
307
+ expect(requestSpy).not.toHaveBeenCalled()
308
+
309
+
310
+ // Failed of invalid script syntax
311
+ result = await onScriptChangeFromHubServer(
312
+ 'https://mock.server.com',
313
+ [{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
314
+ {...deployData, ...{script: "invalidScript"}}
315
+ )
316
+ expect(result.error).toBe("filename.js : ReferenceError: invalidScript is not defined")
317
+ expect(result.script).toBeUndefined()
318
+ expect(requestSpy).not.toHaveBeenCalled()
319
+
320
+
321
+ // Success : prepare script for BizA Client
322
+ const validScript = "get = function () {return {tableName: ''}}"
323
+ result = await onScriptChangeFromHubServer(
324
+ 'https://mock.server.com',
325
+ [{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
326
+ {...deployData, ...{script: validScript}}
327
+ )
328
+ expect(requestSpy).toHaveBeenCalledWith({
329
+ timeout: 30*1000,
330
+ baseURL: 'https://mock.server.com',
331
+ url: 'api/acquirerKey',
332
+ method: "POST",
333
+ data : {"metadata": JSON.stringify({data: '', signature: ''})}
334
+ })
335
+ expect(result.error).toBe(null)
336
+
337
+ const cipherText = Buffer.from(result.script, 'base64')
338
+ const decipher = createDecipheriv('aes-256-cbc', mockAESKey, cipherText.subarray(0, 16))
339
+ const decryptedScript = Buffer.concat([decipher.update(cipherText.subarray(16)), decipher.final()]).toString()
340
+ expect(decryptedScript).toBe('{"tableName":""}')
341
+ });
342
+
343
+ it('shall have "scriptChange Listener"', ()=>{
344
+ const sock = new Socket(new Manager('', {autoConnect: false}), '');
345
+ hubEvent(sock, {subdomain, hostname, port, secure: false, dbindex, server: 'mockServer'}, ()=>{});
346
+ expect(sock.listeners('scriptChange').length).toBe(1);
347
+ });
348
+
349
+ });
350
+
351
+ })
package/tests/hub.test.js CHANGED
@@ -236,13 +236,14 @@ describe('Hub event tests', () => {
236
236
  cliSocketServer = new ioServer(9999)// mocking of CLI socket server
237
237
  directHubEvent(cliSocketServer, {subdomain, hostname: apiAddress, port, secure: false})
238
238
 
239
- clientToCliSocket = ioClient('http://localhost:9999')
239
+ clientToCliSocket = ioClient('http://localhost:9999', {query: {isClient:true}})
240
240
  })
241
241
 
242
- afterAll(()=>{
242
+ afterAll(async ()=>{
243
243
  freeSocketClient(clientToCliSocket)
244
244
  if (cliSocketServer) {
245
- cliSocketServer.close()
245
+ await cliSocketServer.of('').sockets.forEach((sock)=>sock.removeAllListeners())
246
+ await cliSocketServer.close()
246
247
  }
247
248
  })
248
249
 
@@ -259,7 +260,7 @@ describe('Hub event tests', () => {
259
260
  clientToCliSocket.emit(
260
261
  'apiRequest'
261
262
  , {subDomain: subdomain, method: 'POST', path: '/test', headers: {'req-header': 'aa'}, body: 'body of request', responseType: 'json'}
262
- , (res, err)=>{resolve([res, err])}
263
+ , (err, res)=>{resolve([err, res])}
263
264
  )
264
265
  })
265
266
 
@@ -300,7 +301,7 @@ describe('Hub event tests', () => {
300
301
  clientToCliSocket.emit(
301
302
  'apiRequest'
302
303
  , {subDomain: subdomain, method: 'POST', path: '/test', headers: {'req-header': 'aa'}, body: 'body of request', responseType: 'arraybuffer'}
303
- , (res, err)=>{resolve([res, err])}
304
+ , (err, res)=>{resolve([err, res])}
304
305
  )
305
306
  })
306
307
 
@@ -326,7 +327,7 @@ describe('Hub event tests', () => {
326
327
  clientToCliSocket.emit(
327
328
  'apiRequest'
328
329
  , {subDomain: 'wrong subdomain', method: 'POST', path: '/test', headers: {'req-header': 'aa'}, body: 'body of request'}
329
- , (res, err)=>{resolve([res, err])}
330
+ , (err, res)=>{resolve([err, res])}
330
331
  )
331
332
  })
332
333
 
@@ -376,7 +377,7 @@ describe('Hub event tests', () => {
376
377
  hubToCLISocket.emit(
377
378
  'apiRequest'
378
379
  , {subDomain: subdomain, method: 'POST', path: '/test', headers: {'req-header': 'aa'}, body: reqData, responseType: 'json'}
379
- , (res, err)=>{resolve([res, err])}
380
+ , (err, res)=>{resolve([err, res])}
380
381
  )
381
382
  })
382
383
  return {error, response}