biz-a-cli 2.3.63 → 2.3.65

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.63",
4
+ "version": "2.3.65",
5
5
  "versionDev": "0.0.34",
6
6
  "description": "",
7
7
  "main": "bin/index.js",
@@ -56,8 +56,18 @@
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
+ "testPathIgnorePatterns": [
60
+ "<rootDir>/node_modules",
61
+ "<rootDir>/tests/mockData"
62
+ ],
63
+ "watchPathIgnorePatterns": [
64
+ "<rootDir>/node_modules",
65
+ "<rootDir>/tests/mockData"
66
+ ],
67
+ "coveragePathIgnorePatterns": [
68
+ "<rootDir>/node_modules",
69
+ "<rootDir>/tests/mockData",
70
+ "<rootDir>/tests/mockData/**"
71
+ ]
62
72
  }
63
73
  }
@@ -12,6 +12,7 @@ dayjs.default.extend(customParseFormat)
12
12
  dayjs.default.extend(timezone)
13
13
  dayjs.default.extend(utc)
14
14
 
15
+ export const AXIOS_TIMEOUT = 30 * 1000;
15
16
  const logger = createLogger({
16
17
  level: 'info',
17
18
  transports: [
@@ -66,7 +67,8 @@ export function getTableObj(model, tableName) {
66
67
  export function options(apiConfig) {
67
68
  return {
68
69
  headers: { 'content-type': 'text/plain' },
69
- params: { subdomain: apiConfig.subdomain }
70
+ params: { subdomain: apiConfig.subdomain },
71
+ timeout: apiConfig.timeout ?? AXIOS_TIMEOUT //SCY BZ 4316
70
72
  };
71
73
  }
72
74
 
@@ -163,17 +165,21 @@ export async function extractFunctionScript(selectedConfig, data) {
163
165
  const scriptFn = runScriptInThisContext(data[0].script);
164
166
  if (!scriptFn().functions) return
165
167
 
168
+ const axiosInstance = axios.create({ timeout: AXIOS_TIMEOUT });
169
+
166
170
  let lib = {
167
- axios: axios.default,
171
+ // axios: axios.default,
172
+ axios: axiosInstance, //SCY BZ 4316
168
173
  dayjs: dayjs.default,
169
174
  crypto: crypto,
170
175
  log: logger,
171
- data: {sendModel, queryData, crudData, genId, getUrlAndParam}
176
+ data: { sendModel, queryData, crudData, genId, getUrlAndParam }
172
177
  }
173
178
 
174
179
  if (scriptFn().functions.useLibrary) {
175
180
  Object.assign(lib, await setLibrary(config, scriptFn().functions.useLibrary(), lib));
176
181
  }
182
+
177
183
  return scriptFn(lib).functions;
178
184
  }
179
185
 
@@ -187,7 +193,6 @@ export function getQueryDataPrmsParameters(column, value) {
187
193
 
188
194
  export async function queryDataPromise(config, column, value) {
189
195
  let param = getQueryDataPrmsParameters(column, value);
190
- // let param = getQueryDataPrmsParameters(d);
191
196
 
192
197
  return await queryData(param, config, true);
193
198
  }
package/tests/app.test.js CHANGED
@@ -6,14 +6,15 @@ import { createDecipheriv } from 'node:crypto'
6
6
  import * as tar from "tar"
7
7
  import { env } from "../envs/env.js"
8
8
 
9
- describe('Biz-A Apps CLI', ()=>{
9
+ describe('Biz-A Apps CLI', () => {
10
+ let originalOptions, originalCWD, axios, child_process;
11
+ let returnedCode = 0;
10
12
 
11
- let originalOptions, originalCWD, axios
12
13
  const logSpy = jest.spyOn(global.console, 'log').mockImplementation()
13
14
  const errorSpy = jest.spyOn(global.console, 'error').mockImplementation()
14
15
 
15
- async function runCommand(...options){
16
- process.argv[1] = process.cwd()+'\\bin' // mock the key root folder
16
+ async function runCommand(...options) {
17
+ process.argv[1] = process.cwd() + '\\bin' // mock the key root folder
17
18
  process.argv = [process.argv[0], process.argv[1], ...options]
18
19
  await import('../bin/app.js')
19
20
 
@@ -25,79 +26,90 @@ describe('Biz-A Apps CLI', ()=>{
25
26
  await new Promise(process.nextTick) // wait for all import promise (including ES6 import promises) to be resolved
26
27
  }
27
28
 
28
- beforeEach(async ()=>{
29
+ beforeEach(async () => {
29
30
  originalOptions = process.argv
30
31
  originalCWD = process.cwd()
31
32
 
32
33
  // mock default export first with unstable_mockModule
33
- jest.unstable_mockModule('axios', ()=>{return {default: jest.fn()}})
34
+ jest.unstable_mockModule('axios', () => { return { default: jest.fn() } })
34
35
  axios = (await import('axios')).default
35
36
 
36
37
  // then we can mock classes, functions, variables, and objects inside mocked module when doing dynamic import using jest.fn()
37
38
  axios.get = jest.fn()
38
39
  axios.post = jest.fn()
40
+
41
+ jest.unstable_mockModule('node:child_process', () => ({
42
+ spawn: jest.fn().mockReturnValue({
43
+ on: jest.fn((event, callback) => {
44
+ if (event === "close") {
45
+ callback(returnedCode);
46
+ }
47
+ })
48
+ })
49
+ }));
50
+ child_process = (await import('node:child_process'));
39
51
  })
40
52
 
41
- afterEach(()=>{
53
+ afterEach(() => {
42
54
  jest.resetModules()
43
55
  jest.resetAllMocks()
44
56
  process.argv = originalOptions
45
57
  process.chdir(originalCWD)
46
58
  })
47
59
 
48
- describe('Add App', ()=>{
60
+ describe('Add App', () => {
49
61
  const mockDataFolder = './tests/mockData/'
50
62
 
51
- function mockValidTemplates(appName, scriptList){
52
- fs.rmSync(mockDataFolder+'/'+appName, {force: true, recursive: true})
53
- fs.mkdirSync(mockDataFolder+'/'+appName, {recursive: true})
54
- for (const [key, value] of Object.entries(scriptList)){
55
- fs.writeFileSync(mockDataFolder+'/'+appName + '/' + key, value.act)
63
+ function mockValidTemplates(appName, scriptList) {
64
+ fs.rmSync(mockDataFolder + '/' + appName, { force: true, recursive: true })
65
+ fs.mkdirSync(mockDataFolder + '/' + appName, { recursive: true })
66
+ for (const [key, value] of Object.entries(scriptList)) {
67
+ fs.writeFileSync(mockDataFolder + '/' + appName + '/' + key, value.act)
56
68
  }
57
69
  }
58
70
 
59
- function mockIssuerKeyResponse(){
71
+ function mockIssuerKeyResponse() {
60
72
  axios.get.mockResolvedValue({
61
- data:{
73
+ data: {
62
74
  // this data containing 'mockAESKey', which is encrypted using CLI Private key
63
75
  data: 'eyJpc3N1ZXIiOnsia2V5IjoidEVmZlRwbGpsRW9seVRVcnpEQUs4b05mZEg0T2p2VE9MOHZ4c0p3MkRISC9LY09WV2t0SG5kWmxxUXJURUdoWGtoWUFtQjBobmw1RU5xdFh2TXNjcHFCMnd6eXZJUy9OdUpxeFdBQmE4Y21QbXYyUHBqRFV3eUd5LzJzbFBybG00aGJjbjJWamFPRVJiMHFpclZFNGhZVDluNlFwSnR1ZUp1NXcrVG9JN0V1eC9wdkZHeWVaOU1ham5hSTVtcVliZkNsT0pEZnV3MkpuU1RGNk1kbWg0MURualNuYk5nWkJhSjF2VWw2U1lmVDREeVJoVTkrUER6UTRMZ0xPZXlVYUlTVHQwWnpQWDIyeGI5Nlo3NlE0ZFNGUzhwRzRJRk0vMFpHbnI5eXB0NmNhRFlseW5VUWVFOHVJMklJMnpZcjFNdE12RnkzaDEyUU5Za0tLS3NaaVNRV00vQXRPTm5sa00rcjFKSFpMZW42b3lKYlV1cEgvRmZxQmViQWdRUThLcUVENnN2UlljSXBKOWh3UlJDb2RvNmlHaVVTMUVZZnh2N3pFMDhwL281Q2JmdFRKTXpISjh3T1JZbkdaTDh5cWttT2V0Y3dJL0p6U2dGVDNST2E5V3ZMRkFHWkIrcWdEOTBNeGhwT3kyVzRlbS9lUVBpeHNadDR2UGl2T1l0QVZYZTBLL0lJR0tlZ3VRZ0NzeUZENkRmajQxYkNXbm9oUEgzNWl1Y2h1cGxKVUhsSmszMTRqLytkbTBieEZ6MWFzdDBKanVaRFp3bkVSeVJVbTNFSWZNU2kxVGRRaXRWRjI2bFJ3a1NwK0VSRHh0ZllHWCs3V1U3OUhyUFF3MHBuU3NzU29FbVFzQ2VXU0dFc1AwbEtpTlBjLzBCeDNzbjdNMnJpMzJmZUZLRHM9In0sImFjcXVpcmVyIjp7ImRhdGEiOiJtT1NabzB0N0ZZb2M2a0tuZlNURk04S3VHcUtzLzU2MGtERGdldDMrRW9UTUZZaW5sbThwRFRqc2xVK2VoWnRidk1TejJ1bmNPck5rQ1phQy9LM0JrbmM5T3BZTDZ2SXVGNmY2alZrbjJDS25xbnRnUXBqUkY4T2dYK3NEKzhLbnBMVll2QmhMdkJydjI2RTBHTnk5YTNwbCt2MHNna3EycXJoeUJCeVc3VnpRL3h1Y2FCdDRrUjE0N2FpaTlSaThvUXEzRU1kZ3BPN2crYmxLMFk3eGt5ekQ2YU1JSDFSR1lSMTgwaU94akVqYVpiVE1uQkUwS1RJUnBEMnkwL25MTU5VTHZTUlBraVMyTUh5cmI1QWJCbWNQR1hzVUVvZFc0OHM0QVdmS2hZRldLbzV5anQwZlhCVCtUbEdaWmYrcDJINnRzSVNUYjZSKzlHWFk5c1EzNE5IdmFCRTZtNzlURUVQWTNkeUl3Vm5WQTIzR0FqL211bzI5M2dMTlp0R090ZWcrR1VlWXIzWXViQUZnL2VrN0NyTThGdGRQZC92R3NjdlJ4bkNEYnhmU3U3YXUzUFd1RFB5djk0ZjhXaXVMcWlKUGFQRmFZaUE4SW1lZklnY2ROKzMrTWZDRkdyR1dsWHlZM1pxVVI5NEhteGVjd1Q5Q256N2g2NHc0L3c0b0c5bU9CWmVsRk14dzlxUVlOWTZ5ZzRrakRBa2xUK29GMUszd213VUpPVTlhc3NCVEQ1SXZONlJRSEV0SU02ZmhKY1R0Zm5tK3l0Y201b3hjY3ZrN2tlVDExR2xjVi9Oa3EwNDRKb0NFL0drbzV2TWovQ29ERklJd0VjSENnQ1RvVGE0SForcWUzTWc2Wm1CazhvL2pwV3VFbTF5anJMcUdMSmFOTEJXNjlTUT0iLCJzaWduYXR1cmUiOiJzZDJXYnNDVy9oeXlMMnIzcmVhSFcyZndzVy85THVKNkp6MW0zUUNkWVA1NkZUU1ovSHM4c0Z6V2hmdVhtS1JJdEd5cnA4RGxMNTJkVkw1eTNnYmRIc0VoMDRITDhiWXIwS2lFU2RlbnVPMnoyZkdBWTlsclVjRC92alpZNlAwOHBVQTBEbXIreTk2UjQzdGVhTnZaMkplMklMWW1GZzdNOGF2cDZJZWk5WllzUmxyMFg2TmlzcUlXTWxDeHZOLzdadGNzcWQ3QndtWEhZRmlQWVkxaC9KTUtJdEREZnBneGgzU3RITlZQb01JU09FcTVkbGVRMjJNaTlPL2trZ2pkcmlBRDZsZ1hCZ214Q0FDaE5VQzVEZW5vUVIwQUlTREMvTW9udVA5ZldoMktwMkV2SlRGakR0eUJFdFZZekZZME82NEcxOVNhSFRnRmdxTFd2eXJDL2gzK1BqREIyTTdxOFBXOWVDNjlwM0ZCdUt1R0U3aTkrTmpKeWh4eFJoWWlxbW5MWjFxN3lFUzNudkIrNjJHRDZrUlR6YU5zdjFCUTRFSVpBR1NSaUF4d3o0aWo0ZldtdWJhaEd2WGlseGUzYzE1S09aa0RzcWRpQklIL1RWYzc1TUVBUVYrVVNlbXNEUnF2eUZ3ZFBobW9oM25KeVdmbFdsMU05eVNhdU1MaUFPV2c1bXhhSkdqQ0NtMGV5SHZaWUFFOFNWUjViWFJOZjIrNkpBQUJ2Mk5iSEJIVEJxM3V1cWpEVFZZdFZTRmQ3QmsvUS9NdVRiQnNjYUNqVUtybmtMcUpDTEw4akV0NnJlQnJLdlNPZll1c0txWHBWRmZMV1dHd1ZWSEViTzZVQ0xYTmIzY0c1MXRuNmpOS3NmN29wQXhBTFhUNFRXVjk0RjB6KzRpMjNYOD0ifX0=',
64
76
  // sign using BizA Server PrivateKey, to be verified by BizA CLI using Server PublicKey
65
77
  signature: 'Y9Vs9mOV5fqjcX1ZQh8N0vubV6J5+rx1Lvcrb8T9nBONMJIS74lqRdnO4a84rDCXdda0QOJs5750OdE69/ognriSqdvJ5qjb4sjYAuzXmbxGOuU4ptWMAl9CVfi7JdISdXaDMn5o2E9SuuQLwBMUvX6a9p93/L+TK/pSLuv3cwZqaCtiyhsZV1Q1mSz5xpEfGZR//0Vdaj7pZYZ7CDjQAiq6tMc1Mm7azDmxEwDmNqTMvPKJusGTTHvIFH9MbGTsHgq7DzhsGBVW0fyQGx4ycqB5u9D9j9YffjdlFZ3xncxgq/NVHJzHPbosrG2blW3yWr0Sg4P34AAOhNMtAbbrZfa5HYQrGLB5MbOY3s8EiXItufKzz5xTKDVdLER7kWk6th+a7c548TfqWkrkepPEvgBgmGoMw/PvXFsMVMKqRoF31lN7tumKnVyVzz/EwrsVVc7QrsJxfODHgU0bNNxi6gEb+prqKy0ZWmWwtf7coLWq/ybC2yFMrqUjymoJBGvNoLBURihD2m645+qudNlcJlLoyTs8B3KRCwFKtBH2X9eW5ZzDpIQAXDge6Bz/668Xg6DB8TzvpNr0sPOkuXXSKhQnb0SkR7QTHzpFDcg88Ur9Nnnh9aSZZRj1nRo5LawNto+9684SzpIfbjzAnbTHLQ6oY28SIdihKVjc0wj9BZk='
66
78
  }
67
79
  })
68
- axios.post.mockResolvedValue({data: {success: true}, status: 200})
80
+ axios.post.mockResolvedValue({ data: { success: true }, status: 200 })
69
81
  }
70
82
 
71
- beforeAll(()=>{
72
- fs.rmSync(mockDataFolder, {recursive: true, force: true})
83
+ beforeAll(() => {
84
+ fs.rmSync(mockDataFolder, { recursive: true, force: true })
73
85
  })
74
86
 
75
- afterAll(()=>{
76
- fs.rmSync(mockDataFolder, {recursive: true, force: true})
87
+ afterAll(() => {
88
+ fs.rmSync(mockDataFolder, { recursive: true, force: true })
77
89
  })
78
90
 
79
91
  const stressTestCount = 10;
80
- it.each(Array(stressTestCount).fill().map((v,i)=>i+1))(`shall compress and encrypt app scripts (stress test %p of ${stressTestCount})`, async (testNo)=>{
92
+ it.each(Array(stressTestCount).fill().map((v, i) => i + 1))(`shall compress and encrypt app scripts (stress test %p of ${stressTestCount})`, async (testNo) => {
81
93
  const mockScripts = {
82
- 'a.js' : {
94
+ 'a.js': {
83
95
  act: 'get = function () {return {modelA: {}}}',
84
96
  exp: '{"modelA":{}}'
85
97
  },
86
- 'b.js' : {
98
+ 'b.js': {
87
99
  act: 'const get = function () {\nreturn {"modelB": {id: null}}};',
88
100
  exp: '{"modelB":{"id":null}}'
89
101
  },
90
- 'c.js' : {
102
+ 'c.js': {
91
103
  act: 'let get = function () {return {modelC: {}, function: {func: () => { \nreturn ["lib"];\n}\n}}};',
92
104
  exp: '{"modelC":{},"function":{"func":["window.Function","","return[\\\"lib\\\"]"]}}'
93
105
  },
94
- 'd.js' : {
106
+ 'd.js': {
95
107
  act: 'var get = function () {return {model: {}, tableName: "", fields: [], function: {}}};\nmodule.exports = get;',
96
108
  exp: '{"model":{},"tableName":"","fields":[],"function":{}}'
97
109
  },
98
- 'menu.json' : {
110
+ 'menu.json': {
99
111
  // act: JSON.stringify([
100
- act: `[
112
+ act: `[
101
113
  {"menuName": "", "caption": "Home", "link": ["./main"],"subMenu": []},
102
114
  {"menuName": "", "caption": "Personalia","link": [], "subMenu": [
103
115
  {"menuName": "","caption": "Data Master","link": [], "subMenu": []},
@@ -191,7 +203,7 @@ describe('Biz-A Apps CLI', ()=>{
191
203
  tar.t({
192
204
  strict: true
193
205
  , sync: true
194
- , onReadEntry: entry=>{
206
+ , onReadEntry: entry => {
195
207
  const chunks = [];
196
208
  entry.on('data', chunk => chunks.push(chunk));
197
209
  entry.on('end', () => {
@@ -205,10 +217,10 @@ describe('Biz-A Apps CLI', ()=>{
205
217
  })
206
218
  }
207
219
  })
208
- .on('finish', ()=>stream.end())
220
+ .on('finish', () => stream.end())
209
221
  )
210
222
  await finished(stream) // wait for untar process to finish
211
- for (const [fileName, script] of Object.entries(decryptScripts)){
223
+ for (const [fileName, script] of Object.entries(decryptScripts)) {
212
224
  expect(script).toBe(mockScripts[fileName].exp)
213
225
  }
214
226
 
@@ -228,7 +240,7 @@ describe('Biz-A Apps CLI', ()=>{
228
240
  expect(apiParams[3]).toHaveProperty('menu') // shall save "menu.json" as App.metadata
229
241
  expect(apiParams[3].menu).not.toBeNull() // IV (initialize vector) using 16 random bytes
230
242
 
231
- expect(postArgs[2]).toStrictEqual({"headers": {"Content-Type": "text/plain"}})
243
+ expect(postArgs[2]).toStrictEqual({ "headers": { "Content-Type": "text/plain" } })
232
244
 
233
245
  expect(logSpy.mock.calls[0][0]).toContain(`Finished packing ${Object.keys(mockScripts).length} files into "./upload/${appName.toLowerCase()}.tgz"`)
234
246
  expect(logSpy.mock.calls[1][0]).toContain(`Finished uploading "./upload/${appName.toLocaleLowerCase()}.tgz"`)
@@ -236,61 +248,61 @@ describe('Biz-A Apps CLI', ()=>{
236
248
  // fs.rmSync(mockDataFolder + '/' + appName, {recursive: true, force: true})
237
249
  })
238
250
 
239
- /* it('Invalid script syntax', async ()=>{
240
- mockValidTemplates({
241
- 'a.js' : {act: 'get = function () {return {modelA: {}}'} // missing close closure at the end
242
- })
243
- mockIssuerKeyResponse()
244
- await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', appFolderName, "-v")
245
-
246
- expect(logSpy.mock.calls.length).toBe(1)
247
- expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
248
-
249
- expect(errorSpy.mock.calls.length).toBe(1)
250
- expect(errorSpy.mock.calls[0][0]).toBe('a.js : SyntaxError: Unexpected token: eof, expected: punc «}»')
251
- })
252
-
253
- it('Failed to compile script with node sandbox and ES6 Import', async ()=>{
254
- mockValidTemplates({
255
- 'a.js' : {act: 'get = function () {return {modelA: {}}}\n modul.expor = get;\n'} // wrong "module.export"
256
- })
257
- mockIssuerKeyResponse()
258
- await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', appFolderName, "-v")
259
-
260
- expect(logSpy.mock.calls.length).toBe(5)
261
- expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
262
- expect(logSpy.mock.calls[1][0]).toBe('Minify : \nget=function(){return{modelA:{}}};modul.expor=get;')
263
- expect(logSpy.mock.calls[2][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
264
- expect(logSpy.mock.calls[3][0]).toBe('a.js : ReferenceError: modul is not defined')
265
- expect(logSpy.mock.calls[4][0]).toBe('Running script with Import function')
266
-
267
- expect(errorSpy.mock.calls.length).toBe(1)
268
- expect(errorSpy.mock.calls[0][0]).toBe("a.js : ReferenceError: modul is not defined") // ES6 import error
269
- })
270
-
271
- it('Shall not allow empty script', async ()=>{
272
- mockValidTemplates({
273
- 'a.js' : {act: 'get = function () {}'} // empty script
274
- })
275
- mockIssuerKeyResponse()
276
- await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', appFolderName, "-v")
277
-
278
- expect(logSpy.mock.calls.length).toBe(4)
279
- expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
280
- expect(logSpy.mock.calls[1][0]).toBe('Minify : \nget=function(){};')
281
- expect(logSpy.mock.calls[2][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
282
- expect(logSpy.mock.calls[3][0]).toBe('Running script with Import function')
283
-
284
- expect(errorSpy.mock.calls.length).toBe(1)
285
- expect(errorSpy.mock.calls[0][0]).toBe('a.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result') // ES6 import error
286
- }) */
251
+ /* it('Invalid script syntax', async ()=>{
252
+ mockValidTemplates({
253
+ 'a.js' : {act: 'get = function () {return {modelA: {}}'} // missing close closure at the end
254
+ })
255
+ mockIssuerKeyResponse()
256
+ await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', appFolderName, "-v")
257
+
258
+ expect(logSpy.mock.calls.length).toBe(1)
259
+ expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
260
+
261
+ expect(errorSpy.mock.calls.length).toBe(1)
262
+ expect(errorSpy.mock.calls[0][0]).toBe('a.js : SyntaxError: Unexpected token: eof, expected: punc «}»')
263
+ })
264
+
265
+ it('Failed to compile script with node sandbox and ES6 Import', async ()=>{
266
+ mockValidTemplates({
267
+ 'a.js' : {act: 'get = function () {return {modelA: {}}}\n modul.expor = get;\n'} // wrong "module.export"
268
+ })
269
+ mockIssuerKeyResponse()
270
+ await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', appFolderName, "-v")
271
+
272
+ expect(logSpy.mock.calls.length).toBe(5)
273
+ expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
274
+ expect(logSpy.mock.calls[1][0]).toBe('Minify : \nget=function(){return{modelA:{}}};modul.expor=get;')
275
+ expect(logSpy.mock.calls[2][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
276
+ expect(logSpy.mock.calls[3][0]).toBe('a.js : ReferenceError: modul is not defined')
277
+ expect(logSpy.mock.calls[4][0]).toBe('Running script with Import function')
278
+
279
+ expect(errorSpy.mock.calls.length).toBe(1)
280
+ expect(errorSpy.mock.calls[0][0]).toBe("a.js : ReferenceError: modul is not defined") // ES6 import error
281
+ })
282
+
283
+ it('Shall not allow empty script', async ()=>{
284
+ mockValidTemplates({
285
+ 'a.js' : {act: 'get = function () {}'} // empty script
286
+ })
287
+ mockIssuerKeyResponse()
288
+ await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', appFolderName, "-v")
289
+
290
+ expect(logSpy.mock.calls.length).toBe(4)
291
+ expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
292
+ expect(logSpy.mock.calls[1][0]).toBe('Minify : \nget=function(){};')
293
+ expect(logSpy.mock.calls[2][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
294
+ expect(logSpy.mock.calls[3][0]).toBe('Running script with Import function')
295
+
296
+ expect(errorSpy.mock.calls.length).toBe(1)
297
+ expect(errorSpy.mock.calls[0][0]).toBe('a.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result') // ES6 import error
298
+ }) */
287
299
 
288
300
  const errorHandlingTestCases = [
289
301
  // [test case name, scripts, expectedFn()]
290
302
  [
291
303
  'Invalid script syntax',
292
- {act: 'get = function () {return {modelA: {}}'}, // missing close closure at the end',
293
- ()=>{
304
+ { act: 'get = function () {return {modelA: {}}' }, // missing close closure at the end',
305
+ () => {
294
306
  expect(logSpy.mock.calls.length).toBe(5)
295
307
  expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
296
308
  expect(logSpy.mock.calls[1][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
@@ -304,8 +316,8 @@ describe('Biz-A Apps CLI', ()=>{
304
316
  ],
305
317
  [
306
318
  'Failed to compile script with node sandbox and ES6 Import',
307
- {act: 'get = function () {return {modelA: {}}}\n modul.expor = get;\n'}, // wrong "module.export"
308
- ()=>{
319
+ { act: 'get = function () {return {modelA: {}}}\n modul.expor = get;\n' }, // wrong "module.export"
320
+ () => {
309
321
  expect(logSpy.mock.calls.length).toBe(6)
310
322
  expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
311
323
  expect(logSpy.mock.calls[1][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
@@ -320,8 +332,8 @@ describe('Biz-A Apps CLI', ()=>{
320
332
  ],
321
333
  [
322
334
  'Shall not allow empty script',
323
- {act: 'get = function () {}'}, // empty script
324
- ()=>{
335
+ { act: 'get = function () {}' }, // empty script
336
+ () => {
325
337
  expect(logSpy.mock.calls.length).toBe(5)
326
338
  expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
327
339
  expect(logSpy.mock.calls[1][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
@@ -334,15 +346,15 @@ describe('Biz-A Apps CLI', ()=>{
334
346
  }
335
347
  ],
336
348
  ]
337
- it.each(errorHandlingTestCases)('%p', async (name, scripts, expectedFn)=>{
349
+ it.each(errorHandlingTestCases)('%p', async (name, scripts, expectedFn) => {
338
350
  const appName = 'errorHandlingTest' + errorHandlingTestCases.findIndex(testCase => testCase[0] === name)
339
- mockValidTemplates(appName, {'a.js' : scripts})
351
+ mockValidTemplates(appName, { 'a.js': scripts })
340
352
  mockIssuerKeyResponse()
341
353
  await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/' + appName, "-v")
342
354
  expectedFn()
343
355
  })
344
356
 
345
- it('Shall not allow app without script template', async ()=>{
357
+ it('Shall not allow app without script template', async () => {
346
358
  mockValidTemplates(expect.getState().currentTestName, {})
347
359
  mockIssuerKeyResponse()
348
360
  await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/' + expect.getState().currentTestName, "-v")
@@ -353,89 +365,106 @@ describe('Biz-A Apps CLI', ()=>{
353
365
  expect(errorSpy.mock.calls[0][0]).toBe('Nothing to upload. Please recheck your app folder.')
354
366
  })
355
367
 
356
- it('Shall recommend command', async ()=>{
357
- const exitSpy = jest.spyOn(process, 'exit').mockImplementation(()=>{})
368
+ it('Shall recommend command', async () => {
369
+ const exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => { })
358
370
  await runCommand('Add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/NotExistFolder', "-v")
359
371
  expect(logSpy.mock.calls.length).toBe(0)
360
372
  expect(exitSpy).toHaveBeenCalledWith(1) // exit code = 1
361
- expect(errorSpy.mock.calls[errorSpy.mock.calls.length-1][0]).toBe('Did you mean add?')
373
+ expect(errorSpy.mock.calls[errorSpy.mock.calls.length - 1][0]).toBe('Did you mean add?')
362
374
  })
363
375
 
364
- it('Shall have minimun one command', async ()=>{
376
+ it('Shall have minimun one command', async () => {
365
377
  const exitSpy = jest.spyOn(process, 'exit').mockImplementation()
366
378
  await runCommand('-s', 'https://a.b.c', '-i', 2)
367
379
  expect(logSpy.mock.calls.length).toBe(0)
368
380
  expect(exitSpy).toHaveBeenCalledWith(1)
369
- expect(errorSpy.mock.calls[errorSpy.mock.calls.length-1][0]).toBe('You need at least one command before moving on')
381
+ expect(errorSpy.mock.calls[errorSpy.mock.calls.length - 1][0]).toBe('You need at least one command before moving on')
370
382
  })
371
383
 
372
- it('Shall use strict command and options', async ()=>{
384
+ it('Shall use strict command and options', async () => {
373
385
  const exitSpy = jest.spyOn(process, 'exit').mockImplementation()
374
386
  await runCommand('Unknown Command', '-s', 'https://a.b.c', '-i', 2)
375
387
  expect(logSpy.mock.calls.length).toBe(0)
376
388
  expect(exitSpy).toHaveBeenCalledWith(1)
377
- expect(errorSpy.mock.calls[errorSpy.mock.calls.length-1][0]).toBe('Unknown argument: Unknown Command')
389
+ expect(errorSpy.mock.calls[errorSpy.mock.calls.length - 1][0]).toBe('Unknown argument: Unknown Command')
390
+ })
391
+
392
+ it('Shall not continue add biz a template if code is not zero', async () => { //SCY BZ 4331
393
+ returnedCode = 1;
394
+
395
+ const mockScripts = {
396
+ 'a.js': {
397
+ act: 'get = function () {return {modelA: {}}}',
398
+ exp: '{"modelA":{}}'
399
+ }
400
+ }
401
+ const appName = 'compressStressTest1';
402
+
403
+ mockValidTemplates(appName, mockScripts);
404
+ await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/' + appName)
405
+
406
+ expect(errorSpy.mock.calls[errorSpy.mock.calls.length - 1][0]).toBe('Biz-A Add aborted')
378
407
  })
379
408
  })
380
409
 
381
- describe('Remove App', ()=>{
382
- it('shall remove specific apps', async ()=>{
383
- axios.post.mockResolvedValue({data: {success: true}, status: 200})
410
+ describe('Remove App', () => {
411
+ it('shall remove specific apps', async () => {
412
+ axios.post.mockResolvedValue({ data: { success: true }, status: 200 })
384
413
 
385
414
  await runCommand('remove', '-s', 'https://finaapi.imamatek.com', '-p', '1205', '-i', '1', '-n', 'myApp')
386
415
 
387
416
  expect(axios.post.mock.calls).toHaveLength(1)
388
417
  expect(axios.post).toHaveBeenCalledWith(
389
418
  'https://finaapi.imamatek.com:1205/fina/rest/TOrmMethod/%22deleteApp%22',
390
- {_parameters: [1, 'myapp']},
391
- {headers: {'Content-Type': 'text/plain'}}
419
+ { _parameters: [1, 'myapp'] },
420
+ { headers: { 'Content-Type': 'text/plain' } }
392
421
  )
393
422
  expect(logSpy).toHaveBeenCalledWith('myapp removed')
394
423
  })
395
424
 
396
- it('shall remove multiple apps', async ()=>{
397
- axios.post.mockResolvedValue({data: {success: true, _f: 'notExistApp'}, status: 200})
425
+ it('shall remove multiple apps', async () => {
426
+ axios.post.mockResolvedValue({ data: { success: true, _f: 'notExistApp' }, status: 200 })
398
427
 
399
428
  await runCommand('remove', '-i', '2', '-s', 'https://www.AA.io', '-p', '2708', '-n', 'firstApp, notExistApp, secondApp')
400
429
 
401
430
  expect(axios.post.mock.calls).toHaveLength(1)
402
431
  expect(axios.post).toHaveBeenCalledWith(
403
432
  'https://www.AA.io:2708/fina/rest/TOrmMethod/%22deleteApp%22',
404
- {_parameters: [2, 'firstapp,notexistapp,secondapp']},
405
- {headers: {'Content-Type': 'text/plain'}}
433
+ { _parameters: [2, 'firstapp,notexistapp,secondapp'] },
434
+ { headers: { 'Content-Type': 'text/plain' } }
406
435
  )
407
436
  expect(logSpy).toHaveBeenCalledWith('firstapp removed')
408
437
  expect(logSpy).toHaveBeenCalledWith('secondapp removed')
409
438
  expect(logSpy).toHaveBeenCalledWith('notexistapp not found')
410
439
  })
411
440
 
412
- it('shall remove all apps', async ()=>{
413
- axios.post.mockResolvedValue({data: {success: true}, _f: '', status: 200})
441
+ it('shall remove all apps', async () => {
442
+ axios.post.mockResolvedValue({ data: { success: true }, _f: '', status: 200 })
414
443
 
415
444
  await runCommand('remove', '-s', 'https://finaapi.imamatek.com', '-p', '1205', '-i', '2')
416
445
 
417
446
  expect(axios.post.mock.calls).toHaveLength(1)
418
447
  expect(axios.post).toHaveBeenCalledWith(
419
448
  'https://finaapi.imamatek.com:1205/fina/rest/TOrmMethod/%22deleteApp%22',
420
- {_parameters: [2, '']},
421
- {headers: {'Content-Type': 'text/plain'}}
449
+ { _parameters: [2, ''] },
450
+ { headers: { 'Content-Type': 'text/plain' } }
422
451
  )
423
452
  expect(logSpy).toHaveBeenCalledWith('All apps removed')
424
453
  })
425
454
  })
426
455
 
427
- it('Shall have options', async ()=>{
456
+ it('Shall have options', async () => {
428
457
  jest.spyOn(process, 'exit').mockImplementation()
429
458
  const appModule = await import('../bin/app.js')
430
459
  expect(appModule.options).toStrictEqual({
431
- "s" : {
460
+ "s": {
432
461
  alias: "server",
433
462
  describe: `API or Server URL (ex: ${env.BIZA_SERVER_LINK} or http://192.168.1.1 or https://finaapi.imamatek.com)`,
434
463
  type: "string",
435
464
  demandOption: true,
436
465
  default: 'http://localhost'
437
466
  },
438
- "i" : {
467
+ "i": {
439
468
  alias: "dbIndex",
440
469
  default: 2,
441
470
  describe: "database index",
@@ -450,7 +479,7 @@ describe('Biz-A Apps CLI', ()=>{
450
479
  },
451
480
  "p": {
452
481
  alias: "apiPort",
453
- default : 212,
482
+ default: 212,
454
483
  describe: "FINA API Port",
455
484
  type: "number",
456
485
  demandOption: false,
@@ -482,5 +511,4 @@ describe('Biz-A Apps CLI', ()=>{
482
511
  }
483
512
  })
484
513
  })
485
-
486
514
  })