mirror of
https://github.com/sasjs/adapter.git
synced 2025-12-11 09:24:35 +00:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f13c7e5cf1 | ||
|
|
53a7b1c9e6 | ||
|
|
8c30cbff13 | ||
|
|
8f3a7f33f8 | ||
|
|
67ec27bab7 | ||
|
|
c1b200b0d8 | ||
|
|
e03ec996d6 | ||
|
|
ad8dbfd4ec | ||
|
|
15a774ff81 | ||
|
|
98114c5591 | ||
|
|
dffcb66d54 | ||
|
|
67c7147e62 | ||
|
|
50d1b4d824 | ||
|
|
cf1e3f3835 | ||
|
|
2f913e9363 | ||
|
|
05a9864df8 | ||
|
|
3a0d764dfa | ||
|
|
310087b895 | ||
|
|
dc39ecd4a8 | ||
|
|
99e192c5de | ||
|
|
b86658ef9b | ||
|
|
88f08e8864 | ||
|
|
80e5de5d65 | ||
|
|
665734b168 | ||
|
|
5543f467e6 | ||
|
|
a32c0879b3 |
150
package-lock.json
generated
150
package-lock.json
generated
@@ -1363,24 +1363,24 @@
|
||||
}
|
||||
},
|
||||
"@webpack-cli/configtest": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.1.tgz",
|
||||
"integrity": "sha512-B+4uBUYhpzDXmwuo3V9yBH6cISwxEI4J+NO5ggDaGEEHb0osY/R7MzeKc0bHURXQuZjMM4qD+bSJCKIuI3eNBQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.3.tgz",
|
||||
"integrity": "sha512-WQs0ep98FXX2XBAfQpRbY0Ma6ADw8JR6xoIkaIiJIzClGOMqVRvPCWqndTxf28DgFopWan0EKtHtg/5W1h0Zkw==",
|
||||
"dev": true
|
||||
},
|
||||
"@webpack-cli/info": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.2.tgz",
|
||||
"integrity": "sha512-5U9kUJHnwU+FhKH4PWGZuBC1hTEPYyxGSL5jjoBI96Gx8qcYJGOikpiIpFoTq8mmgX3im2zAo2wanv/alD74KQ==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.4.tgz",
|
||||
"integrity": "sha512-ogE2T4+pLhTTPS/8MM3IjHn0IYplKM4HbVNMCWA9N4NrdPzunwenpCsqKEXyejMfRu6K8mhauIPYf8ZxWG5O6g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"envinfo": "^7.7.3"
|
||||
}
|
||||
},
|
||||
"@webpack-cli/serve": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.3.0.tgz",
|
||||
"integrity": "sha512-k2p2VrONcYVX1wRRrf0f3X2VGltLWcv+JzXRBDmvCxGlCeESx4OXw91TsWeKOkp784uNoVQo313vxJFHXPPwfw==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.4.0.tgz",
|
||||
"integrity": "sha512-xgT/HqJ+uLWGX+Mzufusl3cgjAcnqYYskaB7o0vRcwOEfuu6hMzSILQpnIzFMGsTaeaX4Nnekl+6fadLbl1/Vg==",
|
||||
"dev": true
|
||||
},
|
||||
"@xtuc/ieee754": {
|
||||
@@ -1470,12 +1470,6 @@
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-colors": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
|
||||
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-escapes": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
|
||||
@@ -1786,12 +1780,6 @@
|
||||
"integrity": "sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw==",
|
||||
"dev": true
|
||||
},
|
||||
"big.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
|
||||
"dev": true
|
||||
},
|
||||
"bottleneck": {
|
||||
"version": "2.19.5",
|
||||
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
|
||||
@@ -2136,9 +2124,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"colorette": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
|
||||
"integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
|
||||
"integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==",
|
||||
"dev": true
|
||||
},
|
||||
"colors": {
|
||||
@@ -2610,12 +2598,6 @@
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
},
|
||||
"emojis-list": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
|
||||
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
@@ -2626,23 +2608,13 @@
|
||||
}
|
||||
},
|
||||
"enhanced-resolve": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
|
||||
"integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
|
||||
"version": "5.8.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.0.tgz",
|
||||
"integrity": "sha512-Sl3KRpJA8OpprrtaIswVki3cWPiPKxXuFxJXBp+zNb6s6VwNWwFRUdtmzd2ReUut8n+sCPx7QCtQ7w5wfJhSgQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"memory-fs": "^0.5.0",
|
||||
"tapable": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"enquirer": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
|
||||
"integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-colors": "^4.1.1"
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"env-ci": {
|
||||
@@ -2731,20 +2703,11 @@
|
||||
}
|
||||
},
|
||||
"envinfo": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.7.4.tgz",
|
||||
"integrity": "sha512-TQXTYFVVwwluWSFis6K2XKxgrD22jEv0FTuLCQI+OjH7rn93+iY0fSSFM5lrSxFY+H1+B0/cvvlamr3UsBivdQ==",
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
|
||||
"integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
|
||||
"dev": true
|
||||
},
|
||||
"errno": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
|
||||
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"prr": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
@@ -5053,17 +5016,6 @@
|
||||
"integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==",
|
||||
"dev": true
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
@@ -5213,16 +5165,6 @@
|
||||
"supports-hyperlinks": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"memory-fs": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
|
||||
"integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"errno": "^0.1.3",
|
||||
"readable-stream": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"meow": {
|
||||
"version": "8.1.2",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz",
|
||||
@@ -8040,12 +7982,6 @@
|
||||
"sisteransi": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"prr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
||||
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
|
||||
"dev": true
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
|
||||
@@ -9389,9 +9325,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"tapable": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
|
||||
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz",
|
||||
"integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==",
|
||||
"dev": true
|
||||
},
|
||||
"tar": {
|
||||
@@ -9681,14 +9617,13 @@
|
||||
}
|
||||
},
|
||||
"ts-loader": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.1.0.tgz",
|
||||
"integrity": "sha512-YiQipGGAFj2zBfqLhp28yUvPP9jUGqHxRzrGYuc82Z2wM27YIHbElXiaZDc93c3x0mz4zvBmS6q/DgExpdj37A==",
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.1.2.tgz",
|
||||
"integrity": "sha512-ryMgATvLLl+z8zQvdlm6Pep0slmwxFWIEnq/5VdiLVjqQXnFJgO+qNLGIIP+d2N2jsFZ9MibZCVDb2bSp7OmEA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
"enhanced-resolve": "^4.0.0",
|
||||
"loader-utils": "^2.0.0",
|
||||
"enhanced-resolve": "^5.0.0",
|
||||
"micromatch": "^4.0.0",
|
||||
"semver": "^7.3.4"
|
||||
},
|
||||
@@ -10076,9 +10011,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz",
|
||||
"integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
|
||||
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
|
||||
"dev": true
|
||||
},
|
||||
"v8-to-istanbul": {
|
||||
@@ -10264,18 +10199,17 @@
|
||||
}
|
||||
},
|
||||
"webpack-cli": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.5.0.tgz",
|
||||
"integrity": "sha512-wXg/ef6Ibstl2f50mnkcHblRPN/P9J4Nlod5Hg9HGFgSeF8rsqDGHJeVe4aR26q9l62TUJi6vmvC2Qz96YJw1Q==",
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.0.tgz",
|
||||
"integrity": "sha512-7bKr9182/sGfjFm+xdZSwgQuFjgEcy0iCTIBxRUeteJ2Kr8/Wz0qNJX+jw60LU36jApt4nmMkep6+W5AKhok6g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@discoveryjs/json-ext": "^0.5.0",
|
||||
"@webpack-cli/configtest": "^1.0.1",
|
||||
"@webpack-cli/info": "^1.2.2",
|
||||
"@webpack-cli/serve": "^1.3.0",
|
||||
"@webpack-cli/configtest": "^1.0.3",
|
||||
"@webpack-cli/info": "^1.2.4",
|
||||
"@webpack-cli/serve": "^1.4.0",
|
||||
"colorette": "^1.2.1",
|
||||
"commander": "^7.0.0",
|
||||
"enquirer": "^2.3.6",
|
||||
"execa": "^5.0.0",
|
||||
"fastest-levenshtein": "^1.0.12",
|
||||
"import-local": "^3.0.2",
|
||||
@@ -10286,9 +10220,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.1.0.tgz",
|
||||
"integrity": "sha512-pRxBna3MJe6HKnBGsDyMv8ETbptw3axEdYHoqNh7gu5oDcew8fs0xnivZGm06Ogk8zGAJ9VX+OPEr2GXEQK4dg==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
|
||||
"dev": true
|
||||
},
|
||||
"cross-spawn": {
|
||||
@@ -10320,9 +10254,9 @@
|
||||
}
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz",
|
||||
"integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
||||
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
|
||||
"dev": true
|
||||
},
|
||||
"human-signals": {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"build": "rimraf build && rimraf node && mkdir node && cp -r src/* node && webpack && rimraf build/src && rimraf node",
|
||||
"package:lib": "npm run build && cp ./package.json build && cd build && npm version \"5.0.0\" && npm pack",
|
||||
"publish:lib": "npm run build && cd build && npm publish",
|
||||
"lint:fix": "npx prettier --write 'src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}'",
|
||||
"lint": "npx prettier --check 'src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}'",
|
||||
"lint:fix": "npx prettier --write 'src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}' && npx prettier --write 'sasjs-tests/src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}'",
|
||||
"lint": "npx prettier --check 'src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}' && npx prettier --check 'sasjs-tests/src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}'",
|
||||
"test": "jest --silent --coverage",
|
||||
"prepublishOnly": "cp -r ./build/* . && rm -rf ./build",
|
||||
"postpublish": "git clean -fd",
|
||||
@@ -46,7 +46,7 @@
|
||||
"semantic-release": "^17.4.2",
|
||||
"terser-webpack-plugin": "^4.2.3",
|
||||
"ts-jest": "^25.5.1",
|
||||
"ts-loader": "^8.1.0",
|
||||
"ts-loader": "^9.1.2",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typedoc": "^0.20.35",
|
||||
@@ -54,7 +54,7 @@
|
||||
"typedoc-plugin-external-module-name": "^4.0.6",
|
||||
"typescript": "^3.9.9",
|
||||
"webpack": "^5.33.2",
|
||||
"webpack-cli": "^4.5.0"
|
||||
"webpack-cli": "^4.7.0"
|
||||
},
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": false
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}
|
||||
|
||||
97
sasjs-tests/package-lock.json
generated
97
sasjs-tests/package-lock.json
generated
@@ -2005,18 +2005,18 @@
|
||||
},
|
||||
"@sasjs/adapter": {
|
||||
"version": "file:../build/sasjs-adapter-5.0.0.tgz",
|
||||
"integrity": "sha512-1t+3LIL2BFw8HpZUPI9QM24801+JH4DCAu4eHoLLmytYhN72asMi1aVtgSDb1xiJYgpbTG7EK3qRpHIV8cEN8w==",
|
||||
"integrity": "sha512-DxoQbdJqzqOTIuT7qwSfAbmNTWdpOx5zGkiMuZBSwoi9lSsRNoARiWnJq5Vl6h4RXJlc/FVdBFt35RZm4Mc0ZQ==",
|
||||
"requires": {
|
||||
"@sasjs/utils": "^2.5.0",
|
||||
"@sasjs/utils": "^2.10.2",
|
||||
"axios": "^0.21.1",
|
||||
"form-data": "^3.0.0",
|
||||
"form-data": "^4.0.0",
|
||||
"https": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -2046,14 +2046,70 @@
|
||||
}
|
||||
},
|
||||
"@sasjs/utils": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.5.1.tgz",
|
||||
"integrity": "sha512-a3ISiUX8Yz7au4XYxq2KWf9ODT6nsIDbE4FEqS+AQ3McxZkfuAk4v+REXjOmIlcyQd4R4bufEK8XoB6AROn9sA==",
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.12.1.tgz",
|
||||
"integrity": "sha512-6gZS5zW0J70P7XaVuEczyfHVaVa8Ks/aWr4PIlpJcxWD0enJtCEmos2DdnezdSoNvODkPq/8rzMPqko5jaXK1Q==",
|
||||
"requires": {
|
||||
"@types/prompts": "^2.0.9",
|
||||
"@types/prompts": "^2.0.11",
|
||||
"chalk": "^4.1.1",
|
||||
"cli-table": "^0.3.6",
|
||||
"consola": "^2.15.0",
|
||||
"prompts": "^2.4.0",
|
||||
"prompts": "^2.4.1",
|
||||
"valid-url": "^1.0.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
|
||||
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
|
||||
},
|
||||
"prompts": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz",
|
||||
"integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==",
|
||||
"requires": {
|
||||
"kleur": "^3.0.3",
|
||||
"sisteransi": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@semantic-ui-react/event-stack": {
|
||||
@@ -2366,9 +2422,9 @@
|
||||
"integrity": "sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA=="
|
||||
},
|
||||
"@types/prompts": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.9.tgz",
|
||||
"integrity": "sha512-TORZP+FSjTYMWwKadftmqEn6bziN5RnfygehByGsjxoK5ydnClddtv6GikGWPvCm24oI+YBwck5WDxIIyNxUrA==",
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.11.tgz",
|
||||
"integrity": "sha512-dcF5L3rU9VfpLEJIV++FEyhGhuIpJllNEwllVuJ5g8eoVqjf048tW9+spivIwjzgPbtaGAl7mIZW3cmhDAq2UQ==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@@ -4460,6 +4516,14 @@
|
||||
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
||||
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="
|
||||
},
|
||||
"cli-table": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.6.tgz",
|
||||
"integrity": "sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==",
|
||||
"requires": {
|
||||
"colors": "1.0.3"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
|
||||
@@ -4568,6 +4632,11 @@
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
|
||||
"integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw=="
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
||||
"integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": ".",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@sasjs/adapter": "^2.2.4",
|
||||
"@sasjs/adapter": "file:../build/sasjs-adapter-5.0.0.tgz",
|
||||
"@sasjs/test-framework": "^1.4.0",
|
||||
"@types/jest": "^26.0.20",
|
||||
"@types/node": "^14.14.25",
|
||||
@@ -23,8 +23,8 @@
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"update:adapter": "cd .. && npm run package:lib && cd sasjs-tests && npm i ../build/sasjs-adapter-5.0.0.tgz",
|
||||
"deploy:tests": "npm run build && rsync -avhe ssh ./build/* --delete $SSH_ACCOUNT:$DEPLOY_PATH",
|
||||
"deploy": "npm run update:adapter && npm run deploy:tests"
|
||||
"deploy:tests": "rsync -avhe ssh ./build/* --delete $SSH_ACCOUNT:$DEPLOY_PATH",
|
||||
"deploy": "npm run update:adapter && npm run build && npm run deploy:tests"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import React, { ReactElement, useState, useContext, useEffect } from "react";
|
||||
import { TestSuiteRunner, TestSuite, AppContext } from "@sasjs/test-framework";
|
||||
import { basicTests } from "./testSuites/Basic";
|
||||
import { sendArrTests, sendObjTests } from "./testSuites/RequestData";
|
||||
import { specialCaseTests } from "./testSuites/SpecialCases";
|
||||
import { sasjsRequestTests } from "./testSuites/SasjsRequests";
|
||||
import "@sasjs/test-framework/dist/index.css";
|
||||
import { computeTests } from "./testSuites/Compute";
|
||||
import React, { ReactElement, useState, useContext, useEffect } from 'react'
|
||||
import { TestSuiteRunner, TestSuite, AppContext } from '@sasjs/test-framework'
|
||||
import { basicTests } from './testSuites/Basic'
|
||||
import { sendArrTests, sendObjTests } from './testSuites/RequestData'
|
||||
import { specialCaseTests } from './testSuites/SpecialCases'
|
||||
import { sasjsRequestTests } from './testSuites/SasjsRequests'
|
||||
import '@sasjs/test-framework/dist/index.css'
|
||||
import { computeTests } from './testSuites/Compute'
|
||||
|
||||
const App = (): ReactElement<{}> => {
|
||||
const { adapter, config } = useContext(AppContext);
|
||||
const [testSuites, setTestSuites] = useState<TestSuite[]>([]);
|
||||
const { adapter, config } = useContext(AppContext)
|
||||
const [testSuites, setTestSuites] = useState<TestSuite[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
if (adapter) {
|
||||
@@ -20,15 +20,15 @@ const App = (): ReactElement<{}> => {
|
||||
specialCaseTests(adapter),
|
||||
sasjsRequestTests(adapter),
|
||||
computeTests(adapter)
|
||||
]);
|
||||
])
|
||||
}
|
||||
}, [adapter, config]);
|
||||
}, [adapter, config])
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
{adapter && testSuites && <TestSuiteRunner testSuites={testSuites} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import React, { ReactElement, useState, useCallback, useContext } from "react";
|
||||
import "./Login.scss";
|
||||
import { AppContext } from "@sasjs/test-framework";
|
||||
import { Redirect } from "react-router-dom";
|
||||
import React, { ReactElement, useState, useCallback, useContext } from 'react'
|
||||
import './Login.scss'
|
||||
import { AppContext } from '@sasjs/test-framework'
|
||||
import { Redirect } from 'react-router-dom'
|
||||
|
||||
const Login = (): ReactElement<{}> => {
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const appContext = useContext(AppContext);
|
||||
const [username, setUsername] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const appContext = useContext(AppContext)
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
appContext.adapter.logIn(username, password).then((res) => {
|
||||
appContext.setIsLoggedIn(res.isLoggedIn);
|
||||
});
|
||||
appContext.setIsLoggedIn(res.isLoggedIn)
|
||||
})
|
||||
},
|
||||
[username, password, appContext]
|
||||
);
|
||||
)
|
||||
|
||||
return !appContext.isLoggedIn ? (
|
||||
<div className="login-container">
|
||||
@@ -48,7 +48,7 @@ const Login = (): ReactElement<{}> => {
|
||||
</div>
|
||||
) : (
|
||||
<Redirect to="/" />
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Login;
|
||||
export default Login
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import React, { ReactElement, useContext, FunctionComponent } from "react";
|
||||
import { Redirect, Route } from "react-router-dom";
|
||||
import { AppContext } from "@sasjs/test-framework";
|
||||
import React, { ReactElement, useContext, FunctionComponent } from 'react'
|
||||
import { Redirect, Route } from 'react-router-dom'
|
||||
import { AppContext } from '@sasjs/test-framework'
|
||||
|
||||
interface PrivateRouteProps {
|
||||
component: FunctionComponent;
|
||||
exact?: boolean;
|
||||
path: string;
|
||||
component: FunctionComponent
|
||||
exact?: boolean
|
||||
path: string
|
||||
}
|
||||
|
||||
const PrivateRoute = (
|
||||
props: PrivateRouteProps
|
||||
): ReactElement<PrivateRouteProps> => {
|
||||
const { component, path, exact } = props;
|
||||
const appContext = useContext(AppContext);
|
||||
const { component, path, exact } = props
|
||||
const appContext = useContext(AppContext)
|
||||
return appContext.isLoggedIn ? (
|
||||
<Route component={component} path={path} exact={exact} />
|
||||
) : (
|
||||
<Redirect to="/login" />
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default PrivateRoute;
|
||||
export default PrivateRoute
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { Route, HashRouter, Switch } from "react-router-dom";
|
||||
import "./index.scss";
|
||||
import * as serviceWorker from "./serviceWorker";
|
||||
import { AppProvider } from "@sasjs/test-framework";
|
||||
import PrivateRoute from "./PrivateRoute";
|
||||
import Login from "./Login";
|
||||
import App from "./App";
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Route, HashRouter, Switch } from 'react-router-dom'
|
||||
import './index.scss'
|
||||
import * as serviceWorker from './serviceWorker'
|
||||
import { AppProvider } from '@sasjs/test-framework'
|
||||
import PrivateRoute from './PrivateRoute'
|
||||
import Login from './Login'
|
||||
import App from './App'
|
||||
|
||||
ReactDOM.render(
|
||||
<AppProvider>
|
||||
@@ -17,10 +17,10 @@ ReactDOM.render(
|
||||
</Switch>
|
||||
</HashRouter>
|
||||
</AppProvider>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
document.getElementById('root')
|
||||
)
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
// Learn more about service workers: https://bit.ly/CRA-PWA
|
||||
serviceWorker.unregister();
|
||||
serviceWorker.unregister()
|
||||
|
||||
@@ -11,46 +11,46 @@
|
||||
// opt-in, read https://bit.ly/CRA-PWA
|
||||
|
||||
const isLocalhost = Boolean(
|
||||
window.location.hostname === "localhost" ||
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === "[::1]" ||
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.0/8 are considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||
)
|
||||
);
|
||||
)
|
||||
|
||||
export function register(config) {
|
||||
if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href)
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config);
|
||||
checkValidServiceWorker(swUrl, config)
|
||||
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log(
|
||||
"This web app is being served cache-first by a service " +
|
||||
"worker. To learn more, visit https://bit.ly/CRA-PWA"
|
||||
);
|
||||
});
|
||||
'This web app is being served cache-first by a service ' +
|
||||
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||
)
|
||||
})
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
registerValidSW(swUrl, config)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,83 +59,83 @@ function registerValidSW(swUrl, config) {
|
||||
.register(swUrl)
|
||||
.then((registration) => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
const installingWorker = registration.installing
|
||||
if (installingWorker == null) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === "installed") {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log(
|
||||
"New content is available and will be used when all " +
|
||||
"tabs for this page are closed. See https://bit.ly/CRA-PWA."
|
||||
);
|
||||
'New content is available and will be used when all ' +
|
||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
||||
)
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration);
|
||||
config.onUpdate(registration)
|
||||
}
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log("Content is cached for offline use.");
|
||||
console.log('Content is cached for offline use.')
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
config.onSuccess(registration)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error during service worker registration:", error);
|
||||
});
|
||||
console.error('Error during service worker registration:', error)
|
||||
})
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl, config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl, {
|
||||
headers: { "Service-Worker": "script" }
|
||||
headers: { 'Service-Worker': 'script' }
|
||||
})
|
||||
.then((response) => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get("content-type");
|
||||
const contentType = response.headers.get('content-type')
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null && contentType.indexOf("javascript") === -1)
|
||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
window.location.reload()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
registerValidSW(swUrl, config)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
"No internet connection found. App is running in offline mode."
|
||||
);
|
||||
});
|
||||
'No internet connection found. App is running in offline mode.'
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ("serviceWorker" in navigator) {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready
|
||||
.then((registration) => {
|
||||
registration.unregister();
|
||||
registration.unregister()
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error.message);
|
||||
});
|
||||
console.error(error.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import '@testing-library/jest-dom/extend-expect'
|
||||
|
||||
@@ -1,97 +1,102 @@
|
||||
import SASjs, { SASjsConfig } from "@sasjs/adapter";
|
||||
import { TestSuite } from "@sasjs/test-framework";
|
||||
import { ServerType } from "@sasjs/utils/types";
|
||||
import SASjs, { SASjsConfig } from '@sasjs/adapter'
|
||||
import { TestSuite } from '@sasjs/test-framework'
|
||||
import { ServerType } from '@sasjs/utils/types'
|
||||
|
||||
const stringData: any = { table1: [{ col1: "first col value" }] };
|
||||
const stringData: any = { table1: [{ col1: 'first col value' }] }
|
||||
|
||||
const defaultConfig: SASjsConfig = {
|
||||
serverUrl: window.location.origin,
|
||||
pathSAS9: "/SASStoredProcess/do",
|
||||
pathSASViya: "/SASJobExecution",
|
||||
appLoc: "/Public/seedapp",
|
||||
pathSAS9: '/SASStoredProcess/do',
|
||||
pathSASViya: '/SASJobExecution',
|
||||
appLoc: '/Public/seedapp',
|
||||
serverType: ServerType.SasViya,
|
||||
debug: false,
|
||||
contextName: "SAS Job Execution compute context",
|
||||
contextName: 'SAS Job Execution compute context',
|
||||
useComputeApi: false,
|
||||
allowInsecureRequests: false
|
||||
};
|
||||
}
|
||||
|
||||
const customConfig = {
|
||||
serverUrl: "http://url.com",
|
||||
pathSAS9: "sas9",
|
||||
pathSASViya: "viya",
|
||||
appLoc: "/Public/seedapp",
|
||||
serverUrl: 'http://url.com',
|
||||
pathSAS9: 'sas9',
|
||||
pathSASViya: 'viya',
|
||||
appLoc: '/Public/seedapp',
|
||||
serverType: ServerType.Sas9,
|
||||
debug: false
|
||||
};
|
||||
}
|
||||
|
||||
export const basicTests = (
|
||||
adapter: SASjs,
|
||||
userName: string,
|
||||
password: string
|
||||
): TestSuite => ({
|
||||
name: "Basic Tests",
|
||||
name: 'Basic Tests',
|
||||
tests: [
|
||||
{
|
||||
title: "Log in",
|
||||
description: "Should log the user in",
|
||||
title: 'Log in',
|
||||
description: 'Should log the user in',
|
||||
test: async () => {
|
||||
return adapter.logIn(userName, password);
|
||||
return adapter.logIn(userName, password)
|
||||
},
|
||||
assertion: (response: any) =>
|
||||
response && response.isLoggedIn && response.userName === userName
|
||||
},
|
||||
{
|
||||
title: "Multiple Log in attempts",
|
||||
title: 'Multiple Log in attempts',
|
||||
description:
|
||||
"Should fail on first attempt and should log the user in on second attempt",
|
||||
'Should fail on first attempt and should log the user in on second attempt',
|
||||
test: async () => {
|
||||
await adapter.logOut();
|
||||
await adapter.logIn("invalid", "invalid");
|
||||
return adapter.logIn(userName, password);
|
||||
await adapter.logOut()
|
||||
await adapter.logIn('invalid', 'invalid')
|
||||
return adapter.logIn(userName, password)
|
||||
},
|
||||
assertion: (response: any) =>
|
||||
response && response.isLoggedIn && response.userName === userName
|
||||
},
|
||||
{
|
||||
title: "Trigger login callback",
|
||||
title: 'Trigger login callback',
|
||||
description:
|
||||
"Should trigger required login callback and after successful login, it should finish the request",
|
||||
'Should trigger required login callback and after successful login, it should finish the request',
|
||||
test: async () => {
|
||||
await adapter.logOut();
|
||||
|
||||
return await adapter.request("common/sendArr", stringData, null, () => {
|
||||
adapter.logIn(userName, password);
|
||||
});
|
||||
await adapter.logOut()
|
||||
|
||||
return await adapter.request(
|
||||
'common/sendArr',
|
||||
stringData,
|
||||
undefined,
|
||||
() => {
|
||||
adapter.logIn(userName, password)
|
||||
}
|
||||
)
|
||||
},
|
||||
assertion: (response: any) => {
|
||||
return response.table1[0][0] === stringData.table1[0].col1;
|
||||
return response.table1[0][0] === stringData.table1[0].col1
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Request with debug on",
|
||||
title: 'Request with debug on',
|
||||
description:
|
||||
"Should complete successful request with debugging switched on",
|
||||
'Should complete successful request with debugging switched on',
|
||||
test: async () => {
|
||||
const config = {
|
||||
debug: true
|
||||
}
|
||||
|
||||
return await adapter.request("common/sendArr", stringData, config)
|
||||
return await adapter.request('common/sendArr', stringData, config)
|
||||
},
|
||||
assertion: (response: any) => {
|
||||
return response.table1[0][0] === stringData.table1[0].col1;
|
||||
return response.table1[0][0] === stringData.table1[0].col1
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Default config",
|
||||
title: 'Default config',
|
||||
description:
|
||||
"Should instantiate with default config when none is provided",
|
||||
'Should instantiate with default config when none is provided',
|
||||
test: async () => {
|
||||
return Promise.resolve(new SASjs());
|
||||
return Promise.resolve(new SASjs())
|
||||
},
|
||||
assertion: (sasjsInstance: SASjs) => {
|
||||
const sasjsConfig = sasjsInstance.getSasjsConfig();
|
||||
const sasjsConfig = sasjsInstance.getSasjsConfig()
|
||||
|
||||
return (
|
||||
sasjsConfig.serverUrl === defaultConfig.serverUrl &&
|
||||
@@ -100,17 +105,17 @@ export const basicTests = (
|
||||
sasjsConfig.appLoc === defaultConfig.appLoc &&
|
||||
sasjsConfig.serverType === defaultConfig.serverType &&
|
||||
sasjsConfig.debug === defaultConfig.debug
|
||||
);
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Custom config",
|
||||
description: "Should use fully custom config whenever supplied",
|
||||
title: 'Custom config',
|
||||
description: 'Should use fully custom config whenever supplied',
|
||||
test: async () => {
|
||||
return Promise.resolve(new SASjs(customConfig));
|
||||
return Promise.resolve(new SASjs(customConfig))
|
||||
},
|
||||
assertion: (sasjsInstance: SASjs) => {
|
||||
const sasjsConfig = sasjsInstance.getSasjsConfig();
|
||||
const sasjsConfig = sasjsInstance.getSasjsConfig()
|
||||
return (
|
||||
sasjsConfig.serverUrl === customConfig.serverUrl &&
|
||||
sasjsConfig.pathSAS9 === customConfig.pathSAS9 &&
|
||||
@@ -118,28 +123,28 @@ export const basicTests = (
|
||||
sasjsConfig.appLoc === customConfig.appLoc &&
|
||||
sasjsConfig.serverType === customConfig.serverType &&
|
||||
sasjsConfig.debug === customConfig.debug
|
||||
);
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Config overrides",
|
||||
description: "Should override default config with supplied properties",
|
||||
title: 'Config overrides',
|
||||
description: 'Should override default config with supplied properties',
|
||||
test: async () => {
|
||||
return Promise.resolve(
|
||||
new SASjs({ serverUrl: "http://test.com", debug: false })
|
||||
);
|
||||
new SASjs({ serverUrl: 'http://test.com', debug: false })
|
||||
)
|
||||
},
|
||||
assertion: (sasjsInstance: SASjs) => {
|
||||
const sasjsConfig = sasjsInstance.getSasjsConfig();
|
||||
const sasjsConfig = sasjsInstance.getSasjsConfig()
|
||||
return (
|
||||
sasjsConfig.serverUrl === "http://test.com" &&
|
||||
sasjsConfig.serverUrl === 'http://test.com' &&
|
||||
sasjsConfig.pathSAS9 === defaultConfig.pathSAS9 &&
|
||||
sasjsConfig.pathSASViya === defaultConfig.pathSASViya &&
|
||||
sasjsConfig.appLoc === defaultConfig.appLoc &&
|
||||
sasjsConfig.serverType === defaultConfig.serverType &&
|
||||
sasjsConfig.debug === false
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,106 +1,100 @@
|
||||
import SASjs from "@sasjs/adapter";
|
||||
import { TestSuite } from "@sasjs/test-framework";
|
||||
import SASjs from '@sasjs/adapter'
|
||||
import { TestSuite } from '@sasjs/test-framework'
|
||||
|
||||
export const computeTests = (adapter: SASjs): TestSuite => ({
|
||||
name: "Compute",
|
||||
name: 'Compute',
|
||||
tests: [
|
||||
{
|
||||
title: "Start Compute Job - not waiting for result",
|
||||
description: "Should start a compute job and return the session",
|
||||
title: 'Start Compute Job - not waiting for result',
|
||||
description: 'Should start a compute job and return the session',
|
||||
test: () => {
|
||||
const data: any = { table1: [{ col1: "first col value" }] };
|
||||
return adapter.startComputeJob("/Public/app/common/sendArr", data);
|
||||
const data: any = { table1: [{ col1: 'first col value' }] }
|
||||
return adapter.startComputeJob('/Public/app/common/sendArr', data)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const expectedProperties = ["id", "applicationName", "attributes"];
|
||||
return validate(expectedProperties, res);
|
||||
const expectedProperties = ['id', 'applicationName', 'attributes']
|
||||
return validate(expectedProperties, res)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Start Compute Job - waiting for result",
|
||||
description: "Should start a compute job and return the job",
|
||||
title: 'Start Compute Job - waiting for result',
|
||||
description: 'Should start a compute job and return the job',
|
||||
test: () => {
|
||||
const data: any = { table1: [{ col1: "first col value" }] };
|
||||
const data: any = { table1: [{ col1: 'first col value' }] }
|
||||
return adapter.startComputeJob(
|
||||
"/Public/app/common/sendArr",
|
||||
'/Public/app/common/sendArr',
|
||||
data,
|
||||
{},
|
||||
"",
|
||||
'',
|
||||
true
|
||||
);
|
||||
)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const expectedProperties = [
|
||||
"id",
|
||||
"state",
|
||||
"creationTimeStamp",
|
||||
"jobConditionCode"
|
||||
];
|
||||
return validate(expectedProperties, res.job);
|
||||
'id',
|
||||
'state',
|
||||
'creationTimeStamp',
|
||||
'jobConditionCode'
|
||||
]
|
||||
return validate(expectedProperties, res.job)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Execute Script Viya - complete job",
|
||||
description: "Should execute sas file and return log",
|
||||
title: 'Execute Script Viya - complete job',
|
||||
description: 'Should execute sas file and return log',
|
||||
test: () => {
|
||||
const fileLines = [
|
||||
`data;`,
|
||||
`do x=1 to 100;`,
|
||||
`output;`,
|
||||
`end;`,
|
||||
`run;`
|
||||
];
|
||||
const fileLines = [`data;`, `do x=1 to 100;`, `output;`, `end;`, `run;`]
|
||||
|
||||
return adapter.executeScriptSASViya(
|
||||
"sasCode.sas",
|
||||
'sasCode.sas',
|
||||
fileLines,
|
||||
"SAS Studio compute context",
|
||||
'SAS Studio compute context',
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const expectedLogContent = `1 data;\\n2 do x=1 to 100;\\n3 output;\\n4 end;\\n5 run;\\n\\n`;
|
||||
const expectedLogContent = `1 data;\\n2 do x=1 to 100;\\n3 output;\\n4 end;\\n5 run;\\n\\n`
|
||||
|
||||
return validateLog(expectedLogContent, res.log);
|
||||
return validateLog(expectedLogContent, res.log)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Execute Script Viya - failed job",
|
||||
description: "Should execute sas file and return log",
|
||||
title: 'Execute Script Viya - failed job',
|
||||
description: 'Should execute sas file and return log',
|
||||
test: () => {
|
||||
const fileLines = [`%abort;`];
|
||||
const fileLines = [`%abort;`]
|
||||
|
||||
return adapter
|
||||
.executeScriptSASViya(
|
||||
"sasCode.sas",
|
||||
'sasCode.sas',
|
||||
fileLines,
|
||||
"SAS Studio compute context",
|
||||
'SAS Studio compute context',
|
||||
undefined,
|
||||
true
|
||||
)
|
||||
.catch((err: any) => err);
|
||||
.catch((err: any) => err)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const expectedLogContent = `1 %abort;\\nERROR: The %ABORT statement is not valid in open code.\\n`;
|
||||
const expectedLogContent = `1 %abort;\\nERROR: The %ABORT statement is not valid in open code.\\n`
|
||||
|
||||
return validateLog(expectedLogContent, res.log);
|
||||
return validateLog(expectedLogContent, res.log)
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
})
|
||||
|
||||
const validateLog = (text: string, log: string): boolean => {
|
||||
const isValid = JSON.stringify(log).includes(text);
|
||||
const isValid = JSON.stringify(log).includes(text)
|
||||
|
||||
return isValid;
|
||||
};
|
||||
return isValid
|
||||
}
|
||||
|
||||
const validate = (expectedProperties: string[], data: any): boolean => {
|
||||
const actualProperties = Object.keys(data);
|
||||
const actualProperties = Object.keys(data)
|
||||
|
||||
const isValid = expectedProperties.every((property) =>
|
||||
actualProperties.includes(property)
|
||||
);
|
||||
return isValid;
|
||||
};
|
||||
)
|
||||
return isValid
|
||||
}
|
||||
|
||||
@@ -1,111 +1,112 @@
|
||||
import SASjs from "@sasjs/adapter";
|
||||
import { TestSuite } from "@sasjs/test-framework";
|
||||
import SASjs from '@sasjs/adapter'
|
||||
import { TestSuite } from '@sasjs/test-framework'
|
||||
|
||||
const stringData: any = { table1: [{ col1: "first col value" }] };
|
||||
const numericData: any = { table1: [{ col1: 3.14159265 }] };
|
||||
const stringData: any = { table1: [{ col1: 'first col value' }] }
|
||||
const numericData: any = { table1: [{ col1: 3.14159265 }] }
|
||||
const multiColumnData: any = {
|
||||
table1: [{ col1: 42, col2: 1.618, col3: "x", col4: "x" }]
|
||||
};
|
||||
table1: [{ col1: 42, col2: 1.618, col3: 'x', col4: 'x' }]
|
||||
}
|
||||
const multipleRowsWithNulls: any = {
|
||||
table1: [
|
||||
{ col1: 42, col2: null, col3: "x", col4: "" },
|
||||
{ col1: 42, col2: null, col3: "x", col4: "" },
|
||||
{ col1: 42, col2: null, col3: "x", col4: "" },
|
||||
{ col1: 42, col2: 1.62, col3: "x", col4: "x" },
|
||||
{ col1: 42, col2: 1.62, col3: "x", col4: "x" }
|
||||
{ col1: 42, col2: null, col3: 'x', col4: '' },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: '' },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: '' },
|
||||
{ col1: 42, col2: 1.62, col3: 'x', col4: 'x' },
|
||||
{ col1: 42, col2: 1.62, col3: 'x', col4: 'x' }
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
const multipleColumnsWithNulls: any = {
|
||||
table1: [
|
||||
{ col1: 42, col2: null, col3: "x", col4: null },
|
||||
{ col1: 42, col2: null, col3: "x", col4: null },
|
||||
{ col1: 42, col2: null, col3: "x", col4: null },
|
||||
{ col1: 42, col2: null, col3: "x", col4: "" },
|
||||
{ col1: 42, col2: null, col3: "x", col4: "" }
|
||||
{ col1: 42, col2: null, col3: 'x', col4: null },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: null },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: null },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: '' },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: '' }
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
const getLongStringData = (length = 32764) => {
|
||||
let x = "X";
|
||||
let x = 'X'
|
||||
for (let i = 1; i <= length; i++) {
|
||||
x = x + "X";
|
||||
x = x + 'X'
|
||||
}
|
||||
const data: any = { table1: [{ col1: x }] };
|
||||
return data;
|
||||
};
|
||||
const data: any = { table1: [{ col1: x }] }
|
||||
return data
|
||||
}
|
||||
|
||||
const getLargeObjectData = () => {
|
||||
const data = { table1: [{ big: "data" }] };
|
||||
const data = { table1: [{ big: 'data' }] }
|
||||
|
||||
for (let i = 1; i < 10000; i++) {
|
||||
data.table1.push(data.table1[0]);
|
||||
data.table1.push(data.table1[0])
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
return data
|
||||
}
|
||||
|
||||
export const sendArrTests = (adapter: SASjs): TestSuite => ({
|
||||
name: "sendArr",
|
||||
name: 'sendArr',
|
||||
tests: [
|
||||
{
|
||||
title: "Absolute paths",
|
||||
description: "Should work with absolute paths to SAS jobs",
|
||||
title: 'Absolute paths',
|
||||
description: 'Should work with absolute paths to SAS jobs',
|
||||
test: () => {
|
||||
return adapter.request("/Public/app/common/sendArr", stringData);
|
||||
return adapter.request('/Public/app/common/sendArr', stringData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return res.table1[0][0] === stringData.table1[0].col1;
|
||||
return res.table1[0][0] === stringData.table1[0].col1
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Single string value",
|
||||
description: "Should send an array with a single string value",
|
||||
title: 'Single string value',
|
||||
description: 'Should send an array with a single string value',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", stringData);
|
||||
return adapter.request('common/sendArr', stringData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return res.table1[0][0] === stringData.table1[0].col1;
|
||||
return res.table1[0][0] === stringData.table1[0].col1
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Long string value",
|
||||
title: 'Long string value',
|
||||
description:
|
||||
"Should send an array with a long string value under 32765 characters",
|
||||
'Should send an array with a long string value under 32765 characters',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", getLongStringData());
|
||||
return adapter.request('common/sendArr', getLongStringData())
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const longStringData = getLongStringData();
|
||||
return res.table1[0][0] === longStringData.table1[0].col1;
|
||||
const longStringData = getLongStringData()
|
||||
return res.table1[0][0] === longStringData.table1[0].col1
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Overly long string value",
|
||||
title: 'Overly long string value',
|
||||
description:
|
||||
"Should error out with long string values over 32765 characters",
|
||||
'Should error out with long string values over 32765 characters',
|
||||
test: () => {
|
||||
const data = getLongStringData(32767);
|
||||
return adapter.request("common/sendArr", data).catch((e) => e);
|
||||
const data = getLongStringData(32767)
|
||||
return adapter.request('common/sendArr', data).catch((e) => e)
|
||||
},
|
||||
assertion: (error: any) => {
|
||||
return !!error && !!error.error && !!error.error.message;
|
||||
return !!error && !!error.error && !!error.error.message
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Single numeric value",
|
||||
description: "Should send an array with a single numeric value",
|
||||
title: 'Single numeric value',
|
||||
description: 'Should send an array with a single numeric value',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", numericData);
|
||||
return adapter.request('common/sendArr', numericData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return res.table1[0][0] === numericData.table1[0].col1;
|
||||
return res.table1[0][0] === numericData.table1[0].col1
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Multiple columns",
|
||||
description: "Should handle data with multiple columns",
|
||||
title: 'Multiple columns',
|
||||
description: 'Should handle data with multiple columns',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", multiColumnData);
|
||||
return adapter.request('common/sendArr', multiColumnData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return (
|
||||
@@ -113,143 +114,141 @@ export const sendArrTests = (adapter: SASjs): TestSuite => ({
|
||||
res.table1[0][1] === multiColumnData.table1[0].col2 &&
|
||||
res.table1[0][2] === multiColumnData.table1[0].col3 &&
|
||||
res.table1[0][3] === multiColumnData.table1[0].col4
|
||||
);
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Multiple rows with nulls",
|
||||
description: "Should handle data with multiple rows with null values",
|
||||
title: 'Multiple rows with nulls',
|
||||
description: 'Should handle data with multiple rows with null values',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", multipleRowsWithNulls);
|
||||
return adapter.request('common/sendArr', multipleRowsWithNulls)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
let result = true;
|
||||
let result = true
|
||||
multipleRowsWithNulls.table1.forEach((_: any, index: number) => {
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][0] === multipleRowsWithNulls.table1[index].col1;
|
||||
res.table1[index][0] === multipleRowsWithNulls.table1[index].col1
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][1] === multipleRowsWithNulls.table1[index].col2;
|
||||
res.table1[index][1] === multipleRowsWithNulls.table1[index].col2
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][2] === multipleRowsWithNulls.table1[index].col3;
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][3] === multipleRowsWithNulls.table1[index].col4;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Multiple columns with nulls",
|
||||
description: "Should handle data with multiple columns with null values",
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", multipleColumnsWithNulls);
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
let result = true;
|
||||
multipleColumnsWithNulls.table1.forEach((_: any, index: number) => {
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][0] ===
|
||||
multipleColumnsWithNulls.table1[index].col1;
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][1] ===
|
||||
multipleColumnsWithNulls.table1[index].col2;
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][2] ===
|
||||
multipleColumnsWithNulls.table1[index].col3;
|
||||
res.table1[index][2] === multipleRowsWithNulls.table1[index].col3
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][3] ===
|
||||
(multipleColumnsWithNulls.table1[index].col4 || "");
|
||||
});
|
||||
return result;
|
||||
(multipleRowsWithNulls.table1[index].col4 || ' ')
|
||||
})
|
||||
return result
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Multiple columns with nulls',
|
||||
description: 'Should handle data with multiple columns with null values',
|
||||
test: () => {
|
||||
return adapter.request('common/sendArr', multipleColumnsWithNulls)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
let result = true
|
||||
multipleColumnsWithNulls.table1.forEach((_: any, index: number) => {
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][0] === multipleColumnsWithNulls.table1[index].col1
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][1] === multipleColumnsWithNulls.table1[index].col2
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][2] === multipleColumnsWithNulls.table1[index].col3
|
||||
result =
|
||||
result &&
|
||||
res.table1[index][3] ===
|
||||
(multipleColumnsWithNulls.table1[index].col4 || ' ')
|
||||
})
|
||||
return result
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
})
|
||||
|
||||
export const sendObjTests = (adapter: SASjs): TestSuite => ({
|
||||
name: "sendObj",
|
||||
name: 'sendObj',
|
||||
tests: [
|
||||
{
|
||||
title: "Invalid column name",
|
||||
description: "Should throw an error",
|
||||
title: 'Invalid column name',
|
||||
description: 'Should throw an error',
|
||||
test: async () => {
|
||||
const invalidData: any = {
|
||||
"1 invalid table": [{ col1: 42 }]
|
||||
};
|
||||
return adapter.request("common/sendObj", invalidData).catch((e) => e);
|
||||
'1 invalid table': [{ col1: 42 }]
|
||||
}
|
||||
return adapter.request('common/sendObj', invalidData).catch((e) => e)
|
||||
},
|
||||
assertion: (error: any) =>
|
||||
!!error && !!error.error && !!error.error.message
|
||||
},
|
||||
{
|
||||
title: "Single string value",
|
||||
description: "Should send an object with a single string value",
|
||||
title: 'Single string value',
|
||||
description: 'Should send an object with a single string value',
|
||||
test: () => {
|
||||
return adapter.request("common/sendObj", stringData);
|
||||
return adapter.request('common/sendObj', stringData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return res.table1[0].COL1 === stringData.table1[0].col1;
|
||||
return res.table1[0].COL1 === stringData.table1[0].col1
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Long string value",
|
||||
title: 'Long string value',
|
||||
description:
|
||||
"Should send an object with a long string value under 32765 characters",
|
||||
'Should send an object with a long string value under 32765 characters',
|
||||
test: () => {
|
||||
return adapter.request("common/sendObj", getLongStringData());
|
||||
return adapter.request('common/sendObj', getLongStringData())
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const longStringData = getLongStringData();
|
||||
return res.table1[0].COL1 === longStringData.table1[0].col1;
|
||||
const longStringData = getLongStringData()
|
||||
return res.table1[0].COL1 === longStringData.table1[0].col1
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Overly long string value",
|
||||
title: 'Overly long string value',
|
||||
description:
|
||||
"Should error out with long string values over 32765 characters",
|
||||
'Should error out with long string values over 32765 characters',
|
||||
test: () => {
|
||||
return adapter
|
||||
.request("common/sendObj", getLongStringData(32767))
|
||||
.catch((e) => e);
|
||||
.request('common/sendObj', getLongStringData(32767))
|
||||
.catch((e) => e)
|
||||
},
|
||||
assertion: (error: any) => {
|
||||
return !!error && !!error.error && !!error.error.message;
|
||||
return !!error && !!error.error && !!error.error.message
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Single numeric value",
|
||||
description: "Should send an object with a single numeric value",
|
||||
title: 'Single numeric value',
|
||||
description: 'Should send an object with a single numeric value',
|
||||
test: () => {
|
||||
return adapter.request("common/sendObj", numericData);
|
||||
return adapter.request('common/sendObj', numericData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return res.table1[0].COL1 === numericData.table1[0].col1;
|
||||
return res.table1[0].COL1 === numericData.table1[0].col1
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: "Large data volume",
|
||||
description: "Should send an object with a large amount of data",
|
||||
title: 'Large data volume',
|
||||
description: 'Should send an object with a large amount of data',
|
||||
test: () => {
|
||||
return adapter.request("common/sendObj", getLargeObjectData());
|
||||
return adapter.request('common/sendObj', getLargeObjectData())
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const data = getLargeObjectData();
|
||||
return res.table1[9000].BIG === data.table1[9000].big;
|
||||
const data = getLargeObjectData()
|
||||
return res.table1[9000].BIG === data.table1[9000].big
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Multiple columns",
|
||||
description: "Should handle data with multiple columns",
|
||||
title: 'Multiple columns',
|
||||
description: 'Should handle data with multiple columns',
|
||||
test: () => {
|
||||
return adapter.request("common/sendObj", multiColumnData);
|
||||
return adapter.request('common/sendObj', multiColumnData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return (
|
||||
@@ -257,62 +256,63 @@ export const sendObjTests = (adapter: SASjs): TestSuite => ({
|
||||
res.table1[0].COL2 === multiColumnData.table1[0].col2 &&
|
||||
res.table1[0].COL3 === multiColumnData.table1[0].col3 &&
|
||||
res.table1[0].COL4 === multiColumnData.table1[0].col4
|
||||
);
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Multiple rows with nulls",
|
||||
description: "Should handle data with multiple rows with null values",
|
||||
title: 'Multiple rows with nulls',
|
||||
description: 'Should handle data with multiple rows with null values',
|
||||
test: () => {
|
||||
return adapter.request("common/sendObj", multipleRowsWithNulls);
|
||||
return adapter.request('common/sendObj', multipleRowsWithNulls)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
let result = true;
|
||||
let result = true
|
||||
multipleRowsWithNulls.table1.forEach((_: any, index: number) => {
|
||||
result =
|
||||
result &&
|
||||
res.table1[index].COL1 === multipleRowsWithNulls.table1[index].col1;
|
||||
res.table1[index].COL1 === multipleRowsWithNulls.table1[index].col1
|
||||
result =
|
||||
result &&
|
||||
res.table1[index].COL2 === multipleRowsWithNulls.table1[index].col2;
|
||||
res.table1[index].COL2 === multipleRowsWithNulls.table1[index].col2
|
||||
result =
|
||||
result &&
|
||||
res.table1[index].COL3 === multipleRowsWithNulls.table1[index].col3;
|
||||
res.table1[index].COL3 === multipleRowsWithNulls.table1[index].col3
|
||||
result =
|
||||
result &&
|
||||
res.table1[index].COL4 === multipleRowsWithNulls.table1[index].col4;
|
||||
});
|
||||
return result;
|
||||
res.table1[index].COL4 ===
|
||||
(multipleRowsWithNulls.table1[index].col4 || ' ')
|
||||
})
|
||||
return result
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Multiple columns with nulls",
|
||||
description: "Should handle data with multiple columns with null values",
|
||||
title: 'Multiple columns with nulls',
|
||||
description: 'Should handle data with multiple columns with null values',
|
||||
test: () => {
|
||||
return adapter.request("common/sendObj", multipleColumnsWithNulls);
|
||||
return adapter.request('common/sendObj', multipleColumnsWithNulls)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
let result = true;
|
||||
let result = true
|
||||
multipleColumnsWithNulls.table1.forEach((_: any, index: number) => {
|
||||
result =
|
||||
result &&
|
||||
res.table1[index].COL1 ===
|
||||
multipleColumnsWithNulls.table1[index].col1;
|
||||
multipleColumnsWithNulls.table1[index].col1
|
||||
result =
|
||||
result &&
|
||||
res.table1[index].COL2 ===
|
||||
multipleColumnsWithNulls.table1[index].col2;
|
||||
multipleColumnsWithNulls.table1[index].col2
|
||||
result =
|
||||
result &&
|
||||
res.table1[index].COL3 ===
|
||||
multipleColumnsWithNulls.table1[index].col3;
|
||||
multipleColumnsWithNulls.table1[index].col3
|
||||
result =
|
||||
result &&
|
||||
res.table1[index].COL4 ===
|
||||
(multipleColumnsWithNulls.table1[index].col4 || "");
|
||||
});
|
||||
return result;
|
||||
(multipleColumnsWithNulls.table1[index].col4 || ' ')
|
||||
})
|
||||
return result
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
import SASjs from "@sasjs/adapter";
|
||||
import { TestSuite } from "@sasjs/test-framework";
|
||||
import SASjs from '@sasjs/adapter'
|
||||
import { TestSuite } from '@sasjs/test-framework'
|
||||
|
||||
const data: any = { table1: [{ col1: "first col value" }] };
|
||||
const data: any = { table1: [{ col1: 'first col value' }] }
|
||||
|
||||
export const sasjsRequestTests = (adapter: SASjs): TestSuite => ({
|
||||
name: "SASjs Requests",
|
||||
name: 'SASjs Requests',
|
||||
tests: [
|
||||
{
|
||||
title: "WORK tables",
|
||||
description: "Should get WORK tables after request",
|
||||
title: 'WORK tables',
|
||||
description: 'Should get WORK tables after request',
|
||||
test: async () => {
|
||||
return adapter.request("common/sendArr", data);
|
||||
return adapter.request('common/sendArr', data)
|
||||
},
|
||||
assertion: () => {
|
||||
const requests = adapter.getSasRequests();
|
||||
const requests = adapter.getSasRequests()
|
||||
if (adapter.getSasjsConfig().debug) {
|
||||
return requests[0].SASWORK !== null;
|
||||
return requests[0].SASWORK !== null
|
||||
} else {
|
||||
return requests[0].SASWORK === null;
|
||||
return requests[0].SASWORK === null
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Make error and capture log",
|
||||
title: 'Make error and capture log',
|
||||
description:
|
||||
"Should make an error and capture log, in the same time it is testing if debug override is working",
|
||||
'Should make an error and capture log, in the same time it is testing if debug override is working',
|
||||
test: async () => {
|
||||
return adapter
|
||||
.request("common/makeErr", data, { debug: true })
|
||||
.request('common/makeErr', data, { debug: true })
|
||||
.catch(() => {
|
||||
const sasRequests = adapter.getSasRequests();
|
||||
const sasRequests = adapter.getSasRequests()
|
||||
const makeErrRequest: any =
|
||||
sasRequests.find((req) => req.serviceLink.includes("makeErr")) ||
|
||||
null;
|
||||
sasRequests.find((req) => req.serviceLink.includes('makeErr')) ||
|
||||
null
|
||||
|
||||
if (!makeErrRequest) return false;
|
||||
if (!makeErrRequest) return false
|
||||
|
||||
return !!(
|
||||
makeErrRequest.logFile && makeErrRequest.logFile.length > 0
|
||||
);
|
||||
});
|
||||
)
|
||||
})
|
||||
},
|
||||
assertion: (response) => {
|
||||
return response;
|
||||
return response
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,91 +1,92 @@
|
||||
import SASjs from "@sasjs/adapter";
|
||||
import { TestSuite } from "@sasjs/test-framework";
|
||||
import SASjs from '@sasjs/adapter'
|
||||
import { TestSuite } from '@sasjs/test-framework'
|
||||
|
||||
const specialCharData: any = {
|
||||
table1: [
|
||||
{
|
||||
tab: "\t",
|
||||
lf: "\n",
|
||||
cr: "\r",
|
||||
semicolon: ";semi",
|
||||
percent: "%",
|
||||
tab: '\t',
|
||||
lf: '\n',
|
||||
cr: '\r',
|
||||
semicolon: ';semi',
|
||||
percent: '%',
|
||||
singleQuote: "'",
|
||||
doubleQuote: '"',
|
||||
crlf: "\r\n",
|
||||
euro: "€euro",
|
||||
banghash: "!#banghash"
|
||||
crlf: '\r\n',
|
||||
euro: '€euro',
|
||||
banghash: '!#banghash',
|
||||
dot: '.'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
const moreSpecialCharData: any = {
|
||||
table1: [
|
||||
{
|
||||
speech0: '"speech',
|
||||
pct: "%percent",
|
||||
pct: '%percent',
|
||||
speech: '"speech',
|
||||
slash: "\\slash",
|
||||
slashWithSpecial: "\\\tslash",
|
||||
macvar: "&sysuserid",
|
||||
chinese: "传/傳chinese",
|
||||
sigma: "Σsigma",
|
||||
at: "@at",
|
||||
serbian: "Српски",
|
||||
dollar: "$"
|
||||
slash: '\\slash',
|
||||
slashWithSpecial: '\\\tslash',
|
||||
macvar: '&sysuserid',
|
||||
chinese: '传/傳chinese',
|
||||
sigma: 'Σsigma',
|
||||
at: '@at',
|
||||
serbian: 'Српски',
|
||||
dollar: '$'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
const getWideData = () => {
|
||||
const cols: any = {};
|
||||
const cols: any = {}
|
||||
for (let i = 1; i <= 10000; i++) {
|
||||
cols["col" + i] = "test" + i;
|
||||
cols['col' + i] = 'test' + i
|
||||
}
|
||||
|
||||
const data: any = {
|
||||
table1: [cols]
|
||||
};
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
return data
|
||||
}
|
||||
|
||||
const getTables = () => {
|
||||
const tables: any = {};
|
||||
const tables: any = {}
|
||||
|
||||
for (let i = 1; i <= 100; i++) {
|
||||
tables["table" + i] = [{ col1: "x", col2: "x", col3: "x", col4: "x" }];
|
||||
tables['table' + i] = [{ col1: 'x', col2: 'x', col3: 'x', col4: 'x' }]
|
||||
}
|
||||
return tables;
|
||||
};
|
||||
return tables
|
||||
}
|
||||
|
||||
const getLargeDataset = () => {
|
||||
const rows: any = [];
|
||||
const rows: any = []
|
||||
const colData: string =
|
||||
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
for (let i = 1; i <= 10000; i++) {
|
||||
rows.push({ col1: colData, col2: colData, col3: colData, col4: colData });
|
||||
rows.push({ col1: colData, col2: colData, col3: colData, col4: colData })
|
||||
}
|
||||
|
||||
const data: any = {
|
||||
table1: rows
|
||||
};
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
return data
|
||||
}
|
||||
|
||||
const errorAndCsrfData: any = {
|
||||
error: [{ col1: "q", col2: "w", col3: "e", col4: "r" }],
|
||||
_csrf: [{ col1: "q", col2: "w", col3: "e", col4: "r" }]
|
||||
};
|
||||
error: [{ col1: 'q', col2: 'w', col3: 'e', col4: 'r' }],
|
||||
_csrf: [{ col1: 'q', col2: 'w', col3: 'e', col4: 'r' }]
|
||||
}
|
||||
|
||||
export const specialCaseTests = (adapter: SASjs): TestSuite => ({
|
||||
name: "Special Cases",
|
||||
name: 'Special Cases',
|
||||
tests: [
|
||||
{
|
||||
title: "Common special characters",
|
||||
description: "Should handle common special characters",
|
||||
title: 'Common special characters',
|
||||
description: 'Should handle common special characters',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", specialCharData);
|
||||
return adapter.request('common/sendArr', specialCharData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return (
|
||||
@@ -96,17 +97,18 @@ export const specialCaseTests = (adapter: SASjs): TestSuite => ({
|
||||
res.table1[0][4] === specialCharData.table1[0].percent &&
|
||||
res.table1[0][5] === specialCharData.table1[0].singleQuote &&
|
||||
res.table1[0][6] === specialCharData.table1[0].doubleQuote &&
|
||||
res.table1[0][7] === "\n" &&
|
||||
res.table1[0][7] === '\n' &&
|
||||
res.table1[0][8] === specialCharData.table1[0].euro &&
|
||||
res.table1[0][9] === specialCharData.table1[0].banghash
|
||||
);
|
||||
res.table1[0][9] === specialCharData.table1[0].banghash &&
|
||||
res.table1[0][10] === specialCharData.table1[0].dot
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Other special characters",
|
||||
description: "Should handle other special characters",
|
||||
title: 'Other special characters',
|
||||
description: 'Should handle other special characters',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", moreSpecialCharData);
|
||||
return adapter.request('common/sendArr', moreSpecialCharData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return (
|
||||
@@ -121,50 +123,50 @@ export const specialCaseTests = (adapter: SASjs): TestSuite => ({
|
||||
res.table1[0][8] === moreSpecialCharData.table1[0].at &&
|
||||
res.table1[0][9] === moreSpecialCharData.table1[0].serbian &&
|
||||
res.table1[0][10] === moreSpecialCharData.table1[0].dollar
|
||||
);
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Wide table with sendArr",
|
||||
description: "Should handle data with 10000 columns",
|
||||
title: 'Wide table with sendArr',
|
||||
description: 'Should handle data with 10000 columns',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", getWideData());
|
||||
return adapter.request('common/sendArr', getWideData())
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const data = getWideData();
|
||||
let result = true;
|
||||
const data = getWideData()
|
||||
let result = true
|
||||
for (let i = 0; i <= 10; i++) {
|
||||
result =
|
||||
result && res.table1[0][i] === data.table1[0]["col" + (i + 1)];
|
||||
result && res.table1[0][i] === data.table1[0]['col' + (i + 1)]
|
||||
}
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Wide table with sendObj",
|
||||
description: "Should handle data with 10000 columns",
|
||||
title: 'Wide table with sendObj',
|
||||
description: 'Should handle data with 10000 columns',
|
||||
test: () => {
|
||||
return adapter.request("common/sendObj", getWideData());
|
||||
return adapter.request('common/sendObj', getWideData())
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const data = getWideData();
|
||||
let result = true;
|
||||
const data = getWideData()
|
||||
let result = true
|
||||
for (let i = 0; i <= 10; i++) {
|
||||
result =
|
||||
result &&
|
||||
res.table1[0]["COL" + (i + 1)] === data.table1[0]["col" + (i + 1)];
|
||||
res.table1[0]['COL' + (i + 1)] === data.table1[0]['col' + (i + 1)]
|
||||
}
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Multiple tables",
|
||||
description: "Should handle data with 100 tables",
|
||||
title: 'Multiple tables',
|
||||
description: 'Should handle data with 100 tables',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", getTables());
|
||||
return adapter.request('common/sendArr', getTables())
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const data = getTables();
|
||||
const data = getTables()
|
||||
return (
|
||||
res.table1[0][0] === data.table1[0].col1 &&
|
||||
res.table1[0][1] === data.table1[0].col2 &&
|
||||
@@ -174,45 +176,45 @@ export const specialCaseTests = (adapter: SASjs): TestSuite => ({
|
||||
res.table50[0][1] === data.table50[0].col2 &&
|
||||
res.table50[0][2] === data.table50[0].col3 &&
|
||||
res.table50[0][3] === data.table50[0].col4
|
||||
);
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Large dataset with sendObj",
|
||||
description: "Should handle 5mb of data",
|
||||
title: 'Large dataset with sendObj',
|
||||
description: 'Should handle 5mb of data',
|
||||
test: () => {
|
||||
return adapter.request("common/sendObj", getLargeDataset());
|
||||
return adapter.request('common/sendObj', getLargeDataset())
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const data = getLargeDataset();
|
||||
let result = true;
|
||||
const data = getLargeDataset()
|
||||
let result = true
|
||||
for (let i = 0; i <= 10; i++) {
|
||||
result = result && res.table1[i][0] === data.table1[i][0];
|
||||
result = result && res.table1[i][0] === data.table1[i][0]
|
||||
}
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Large dataset with sendArr",
|
||||
description: "Should handle 5mb of data",
|
||||
title: 'Large dataset with sendArr',
|
||||
description: 'Should handle 5mb of data',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", getLargeDataset());
|
||||
return adapter.request('common/sendArr', getLargeDataset())
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
const data = getLargeDataset();
|
||||
let result = true;
|
||||
const data = getLargeDataset()
|
||||
let result = true
|
||||
for (let i = 0; i <= 10; i++) {
|
||||
result =
|
||||
result && res.table1[i][0] === Object.values(data.table1[i])[0];
|
||||
result && res.table1[i][0] === Object.values(data.table1[i])[0]
|
||||
}
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Error and _csrf tables with sendArr",
|
||||
description: "Should handle error and _csrf tables",
|
||||
title: 'Error and _csrf tables with sendArr',
|
||||
description: 'Should handle error and _csrf tables',
|
||||
test: () => {
|
||||
return adapter.request("common/sendArr", errorAndCsrfData);
|
||||
return adapter.request('common/sendArr', errorAndCsrfData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return (
|
||||
@@ -224,14 +226,14 @@ export const specialCaseTests = (adapter: SASjs): TestSuite => ({
|
||||
res._csrf[0][1] === errorAndCsrfData._csrf[0].col2 &&
|
||||
res._csrf[0][2] === errorAndCsrfData._csrf[0].col3 &&
|
||||
res._csrf[0][3] === errorAndCsrfData._csrf[0].col4
|
||||
);
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Error and _csrf tables with sendObj",
|
||||
description: "Should handle error and _csrf tables",
|
||||
title: 'Error and _csrf tables with sendObj',
|
||||
description: 'Should handle error and _csrf tables',
|
||||
test: () => {
|
||||
return adapter.request("common/sendObj", errorAndCsrfData);
|
||||
return adapter.request('common/sendObj', errorAndCsrfData)
|
||||
},
|
||||
assertion: (res: any) => {
|
||||
return (
|
||||
@@ -243,8 +245,8 @@ export const specialCaseTests = (adapter: SASjs): TestSuite => ({
|
||||
res._csrf[0].COL2 === errorAndCsrfData._csrf[0].col2 &&
|
||||
res._csrf[0].COL3 === errorAndCsrfData._csrf[0].col3 &&
|
||||
res._csrf[0].COL4 === errorAndCsrfData._csrf[0].col4
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
export const assert = (
|
||||
expression: boolean | (() => boolean),
|
||||
message = "Assertion failed"
|
||||
message = 'Assertion failed'
|
||||
) => {
|
||||
let result;
|
||||
let result
|
||||
try {
|
||||
if (typeof expression === "boolean") {
|
||||
result = expression;
|
||||
if (typeof expression === 'boolean') {
|
||||
result = expression
|
||||
} else {
|
||||
result = expression();
|
||||
result = expression()
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(message);
|
||||
throw new Error(message);
|
||||
console.error(message)
|
||||
throw new Error(message)
|
||||
}
|
||||
if (!!result) {
|
||||
return;
|
||||
return
|
||||
} else {
|
||||
console.error(message);
|
||||
throw new Error(message);
|
||||
console.error(message)
|
||||
throw new Error(message)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -314,9 +314,7 @@ export class ContextManager {
|
||||
contextId: string,
|
||||
accessToken?: string
|
||||
): Promise<ContextAllAttributes> {
|
||||
const {
|
||||
result: context
|
||||
} = await this.requestClient
|
||||
const { result: context } = await this.requestClient
|
||||
.get<ContextAllAttributes>(
|
||||
`${this.serverUrl}/compute/contexts/${contextId}`,
|
||||
accessToken
|
||||
|
||||
@@ -594,16 +594,15 @@ export class SASViyaApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
result: createFolderResponse
|
||||
} = await this.requestClient.post<Folder>(
|
||||
`/folders/folders?parentFolderUri=${parentFolderUri}`,
|
||||
{
|
||||
name: folderName,
|
||||
type: 'folder'
|
||||
},
|
||||
accessToken
|
||||
)
|
||||
const { result: createFolderResponse } =
|
||||
await this.requestClient.post<Folder>(
|
||||
`/folders/folders?parentFolderUri=${parentFolderUri}`,
|
||||
{
|
||||
name: folderName,
|
||||
type: 'folder'
|
||||
},
|
||||
accessToken
|
||||
)
|
||||
|
||||
// update folder map with newly created folder.
|
||||
await this.populateFolderMap(
|
||||
@@ -875,9 +874,7 @@ export class SASViyaApiClient {
|
||||
throw new Error(`URI of job definition was not found.`)
|
||||
}
|
||||
|
||||
const {
|
||||
result: jobDefinition
|
||||
} = await this.requestClient
|
||||
const { result: jobDefinition } = await this.requestClient
|
||||
.get<JobDefinition>(
|
||||
`${this.serverUrl}${jobDefinitionLink.href}`,
|
||||
accessToken
|
||||
@@ -1081,6 +1078,7 @@ export class SASViyaApiClient {
|
||||
) {
|
||||
let POLL_INTERVAL = 300
|
||||
let MAX_POLL_COUNT = 1000
|
||||
let MAX_ERROR_COUNT = 5
|
||||
|
||||
if (pollOptions) {
|
||||
POLL_INTERVAL = pollOptions.POLL_INTERVAL || POLL_INTERVAL
|
||||
@@ -1089,6 +1087,7 @@ export class SASViyaApiClient {
|
||||
|
||||
let postedJobState = ''
|
||||
let pollCount = 0
|
||||
let errorCount = 0
|
||||
const headers: any = {
|
||||
'Content-Type': 'application/json',
|
||||
'If-None-Match': etag
|
||||
@@ -1103,14 +1102,18 @@ export class SASViyaApiClient {
|
||||
|
||||
const { result: state } = await this.requestClient
|
||||
.get<string>(
|
||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=300`,
|
||||
accessToken,
|
||||
'text/plain',
|
||||
{},
|
||||
this.debug
|
||||
)
|
||||
.catch((err) => {
|
||||
throw prefixMessage(err, 'Error while getting job state. ')
|
||||
console.error(
|
||||
`Error fetching job state from ${this.serverUrl}${stateLink.href}. Starting poll, assuming job to be running.`,
|
||||
err
|
||||
)
|
||||
return { result: 'unavailable' }
|
||||
})
|
||||
|
||||
const currentState = state.trim()
|
||||
@@ -1125,25 +1128,40 @@ export class SASViyaApiClient {
|
||||
if (
|
||||
postedJobState === 'running' ||
|
||||
postedJobState === '' ||
|
||||
postedJobState === 'pending'
|
||||
postedJobState === 'pending' ||
|
||||
postedJobState === 'unavailable'
|
||||
) {
|
||||
if (stateLink) {
|
||||
const { result: jobState } = await this.requestClient
|
||||
.get<string>(
|
||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=300`,
|
||||
accessToken,
|
||||
'text/plain',
|
||||
{},
|
||||
this.debug
|
||||
)
|
||||
.catch((err) => {
|
||||
throw prefixMessage(
|
||||
err,
|
||||
'Error while getting job state after interval. '
|
||||
errorCount++
|
||||
if (
|
||||
pollCount >= MAX_POLL_COUNT ||
|
||||
errorCount >= MAX_ERROR_COUNT
|
||||
) {
|
||||
throw prefixMessage(
|
||||
err,
|
||||
'Error while getting job state after interval. '
|
||||
)
|
||||
}
|
||||
console.error(
|
||||
`Error fetching job state from ${this.serverUrl}${stateLink.href}. Resuming poll, assuming job to be running.`,
|
||||
err
|
||||
)
|
||||
return { result: 'unavailable' }
|
||||
})
|
||||
|
||||
postedJobState = jobState.trim()
|
||||
if (postedJobState != 'unavailable' && errorCount > 0) {
|
||||
errorCount = 0
|
||||
}
|
||||
|
||||
if (this.debug && printedState !== postedJobState) {
|
||||
console.log('Polling job status...')
|
||||
|
||||
@@ -91,10 +91,7 @@ export class SessionManager {
|
||||
}
|
||||
|
||||
private async createAndWaitForSession(accessToken?: string) {
|
||||
const {
|
||||
result: createdSession,
|
||||
etag
|
||||
} = await this.requestClient
|
||||
const { result: createdSession, etag } = await this.requestClient
|
||||
.post<Session>(
|
||||
`${this.serverUrl}/compute/contexts/${
|
||||
this.currentContext!.id
|
||||
|
||||
@@ -33,7 +33,7 @@ export class JesJobExecutor extends BaseJobExecutor {
|
||||
.then((response) => {
|
||||
this.appendRequest(response, sasJob, config.debug)
|
||||
|
||||
resolve(response.result)
|
||||
resolve(response)
|
||||
})
|
||||
.catch(async (e: Error) => {
|
||||
if (e instanceof JobExecutionError) {
|
||||
|
||||
@@ -71,10 +71,8 @@ export class WebJobExecutor extends BaseJobExecutor {
|
||||
} else {
|
||||
// param based approach
|
||||
try {
|
||||
const {
|
||||
formData: newFormData,
|
||||
requestParams: params
|
||||
} = generateTableUploadForm(formData, data)
|
||||
const { formData: newFormData, requestParams: params } =
|
||||
generateTableUploadForm(formData, data)
|
||||
formData = newFormData
|
||||
requestParams = { ...requestParams, ...params }
|
||||
} catch (e) {
|
||||
|
||||
@@ -214,9 +214,8 @@ export class RequestClient implements HttpClient {
|
||||
const headers = this.getHeaders(accessToken, 'application/json')
|
||||
|
||||
if (this.fileUploadCsrfToken?.value) {
|
||||
headers[
|
||||
this.fileUploadCsrfToken.headerName
|
||||
] = this.fileUploadCsrfToken.value
|
||||
headers[this.fileUploadCsrfToken.headerName] =
|
||||
this.fileUploadCsrfToken.value
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -333,9 +332,9 @@ export class RequestClient implements HttpClient {
|
||||
}
|
||||
|
||||
private parseCsrfToken = (response: AxiosResponse): CsrfToken | undefined => {
|
||||
const tokenHeader = (response.headers[
|
||||
'x-csrf-header'
|
||||
] as string)?.toLowerCase()
|
||||
const tokenHeader = (
|
||||
response.headers['x-csrf-header'] as string
|
||||
)?.toLowerCase()
|
||||
|
||||
if (tokenHeader) {
|
||||
const token = response.headers[tokenHeader]
|
||||
|
||||
@@ -28,12 +28,12 @@ describe('urlValidator', () => {
|
||||
it('should return false when the URL is null', () => {
|
||||
const url = null
|
||||
|
||||
expect(isUrl((url as unknown) as string)).toEqual(false)
|
||||
expect(isUrl(url as unknown as string)).toEqual(false)
|
||||
})
|
||||
|
||||
it('should return false when the URL is undefined', () => {
|
||||
const url = undefined
|
||||
|
||||
expect(isUrl((url as unknown) as string)).toEqual(false)
|
||||
expect(isUrl(url as unknown as string)).toEqual(false)
|
||||
})
|
||||
})
|
||||
|
||||
170
src/utils/convertToCsv.spec.ts
Normal file
170
src/utils/convertToCsv.spec.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import { convertToCSV } from './convertToCsv'
|
||||
|
||||
describe('convertToCsv', () => {
|
||||
it('should convert single quoted values', () => {
|
||||
const data = [
|
||||
{ foo: `'bar'`, bar: 'abc' },
|
||||
{ foo: 'sadf', bar: 'def' },
|
||||
{ foo: 'asd', bar: `'qwert'` }
|
||||
]
|
||||
|
||||
const expectedOutput = `foo:$char5. bar:$char7.\r\n"'bar'",abc\r\nsadf,def\r\nasd,"'qwert'"`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should convert double quoted values', () => {
|
||||
const data = [
|
||||
{ foo: `"bar"`, bar: 'abc' },
|
||||
{ foo: 'sadf', bar: 'def' },
|
||||
{ foo: 'asd', bar: `"qwert"` }
|
||||
]
|
||||
|
||||
const expectedOutput = `foo:$char5. bar:$char7.\r\n"""bar""",abc\r\nsadf,def\r\nasd,"""qwert"""`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should convert values with mixed quotes', () => {
|
||||
const data = [{ foo: `'blah'`, bar: `"blah"` }]
|
||||
|
||||
const expectedOutput = `foo:$char6. bar:$char6.\r\n"'blah'","""blah"""`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should convert values with mixed quotes', () => {
|
||||
const data = [{ foo: `'blah,"'`, bar: `"blah,blah" "` }]
|
||||
|
||||
const expectedOutput = `foo:$char8. bar:$char13.\r\n"'blah,""'","""blah,blah"" """`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should convert values with mixed quotes', () => {
|
||||
const data = [{ foo: `',''`, bar: `","` }]
|
||||
|
||||
const expectedOutput = `foo:$char4. bar:$char3.\r\n"',''",""","""`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should convert values with mixed quotes', () => {
|
||||
const data = [{ foo: `','`, bar: `,"` }]
|
||||
|
||||
const expectedOutput = `foo:$char3. bar:$char2.\r\n"','",","""`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should convert values with mixed quotes', () => {
|
||||
const data = [{ foo: `"`, bar: `'` }]
|
||||
|
||||
const expectedOutput = `foo:$char1. bar:$char1.\r\n"""","'"`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should convert values with mixed quotes', () => {
|
||||
const data = [{ foo: `,`, bar: `',` }]
|
||||
|
||||
const expectedOutput = `foo:$char1. bar:$char2.\r\n",","',"`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should convert values with number cases 1', () => {
|
||||
const data = [
|
||||
{ col1: 42, col2: null, col3: 'x', col4: null },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: null },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: null },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: '' },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: '' }
|
||||
]
|
||||
|
||||
const expectedOutput = `col1:best. col2:best. col3:$char1. col4:$char1.\r\n42,.,x,\r\n42,.,x,\r\n42,.,x,\r\n42,.,x,\r\n42,.,x,`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should convert values with number cases 2', () => {
|
||||
const data = [
|
||||
{ col1: 42, col2: null, col3: 'x', col4: '' },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: '' },
|
||||
{ col1: 42, col2: null, col3: 'x', col4: '' },
|
||||
{ col1: 42, col2: 1.62, col3: 'x', col4: 'x' },
|
||||
{ col1: 42, col2: 1.62, col3: 'x', col4: 'x' }
|
||||
]
|
||||
|
||||
const expectedOutput = `col1:best. col2:best. col3:$char1. col4:$char1.\r\n42,.,x,\r\n42,.,x,\r\n42,.,x,\r\n42,1.62,x,x\r\n42,1.62,x,x`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should convert values with common special characters', () => {
|
||||
expect(convertToCSV([{ tab: '\t' }])).toEqual(`tab:$char1.\r\n\"\t\"`)
|
||||
expect(convertToCSV([{ lf: '\n' }])).toEqual(`lf:$char1.\r\n\"\n\"`)
|
||||
expect(convertToCSV([{ semicolon: ';semi' }])).toEqual(
|
||||
`semicolon:$char5.\r\n;semi`
|
||||
)
|
||||
expect(convertToCSV([{ percent: '%' }])).toEqual(`percent:$char1.\r\n%`)
|
||||
expect(convertToCSV([{ singleQuote: "'" }])).toEqual(
|
||||
`singleQuote:$char1.\r\n\"'\"`
|
||||
)
|
||||
expect(convertToCSV([{ doubleQuote: '"' }])).toEqual(
|
||||
`doubleQuote:$char1.\r\n""""`
|
||||
)
|
||||
expect(convertToCSV([{ crlf: '\r\n' }])).toEqual(`crlf:$char2.\r\n\"\n\"`)
|
||||
expect(convertToCSV([{ euro: '€euro' }])).toEqual(`euro:$char7.\r\n€euro`)
|
||||
expect(convertToCSV([{ banghash: '!#banghash' }])).toEqual(
|
||||
`banghash:$char10.\r\n!#banghash`
|
||||
)
|
||||
})
|
||||
|
||||
it('should convert values with other special characters', () => {
|
||||
const data = [
|
||||
{
|
||||
speech0: '"speech',
|
||||
pct: '%percent',
|
||||
speech: '"speech',
|
||||
slash: '\\slash',
|
||||
slashWithSpecial: '\\\tslash',
|
||||
macvar: '&sysuserid',
|
||||
chinese: '传/傳chinese',
|
||||
sigma: 'Σsigma',
|
||||
at: '@at',
|
||||
serbian: 'Српски',
|
||||
dollar: '$'
|
||||
}
|
||||
]
|
||||
|
||||
const expectedOutput = `speech0:$char7. pct:$char8. speech:$char7. slash:$char6. slashWithSpecial:$char7. macvar:$char10. chinese:$char14. sigma:$char7. at:$char3. serbian:$char12. dollar:$char1.\r\n"""speech",%percent,"""speech",\\slash,\"\\\tslash\",&sysuserid,传/傳chinese,Σsigma,@at,Српски,$`
|
||||
|
||||
expect(convertToCSV(data)).toEqual(expectedOutput)
|
||||
|
||||
expect(convertToCSV([{ speech: 'menext' }])).toEqual(
|
||||
`speech:$char6.\r\nmenext`
|
||||
)
|
||||
expect(convertToCSV([{ speech: 'me\nnext' }])).toEqual(
|
||||
`speech:$char7.\r\n\"me\nnext\"`
|
||||
)
|
||||
expect(convertToCSV([{ speech: `me'next` }])).toEqual(
|
||||
`speech:$char7.\r\n\"me'next\"`
|
||||
)
|
||||
expect(convertToCSV([{ speech: `me"next` }])).toEqual(
|
||||
`speech:$char7.\r\n\"me""next\"`
|
||||
)
|
||||
expect(convertToCSV([{ speech: `me""next` }])).toEqual(
|
||||
`speech:$char8.\r\n\"me""""next\"`
|
||||
)
|
||||
expect(convertToCSV([{ slashWithSpecial: '\\\tslash' }])).toEqual(
|
||||
`slashWithSpecial:$char7.\r\n\"\\\tslash\"`
|
||||
)
|
||||
expect(convertToCSV([{ slashWithSpecial: '\\ \tslash' }])).toEqual(
|
||||
`slashWithSpecial:$char8.\r\n\"\\ \tslash\"`
|
||||
)
|
||||
expect(
|
||||
convertToCSV([{ slashWithSpecialExtra: '\\\ts\tl\ta\ts\t\th\t' }])
|
||||
).toEqual(`slashWithSpecialExtra:$char13.\r\n\"\\\ts\tl\ta\ts\t\th\t\"`)
|
||||
})
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Converts the given JSON object to a CSV string.
|
||||
* @param data - the JSON object to convert.
|
||||
* Converts the given JSON object array to a CSV string.
|
||||
* @param data - the array of JSON objects to convert.
|
||||
*/
|
||||
export const convertToCSV = (data: any) => {
|
||||
const replacer = (key: any, value: any) => (value === null ? '' : value)
|
||||
@@ -37,15 +37,7 @@ export const convertToCSV = (data: any) => {
|
||||
let byteSize
|
||||
|
||||
if (typeof row[field] === 'string') {
|
||||
let doubleQuotesFound = row[field]
|
||||
.split('')
|
||||
.filter((char: any) => char === '"')
|
||||
|
||||
byteSize = getByteSize(row[field])
|
||||
|
||||
if (doubleQuotesFound.length > 0) {
|
||||
byteSize += doubleQuotesFound.length
|
||||
}
|
||||
}
|
||||
|
||||
return byteSize
|
||||
@@ -61,7 +53,7 @@ export const convertToCSV = (data: any) => {
|
||||
)
|
||||
}
|
||||
|
||||
return `${field}:${firstFoundType === 'chars' ? '$' : ''}${
|
||||
return `${field}:${firstFoundType === 'chars' ? '$char' : ''}${
|
||||
longestValueForField
|
||||
? longestValueForField
|
||||
: firstFoundType === 'chars'
|
||||
@@ -73,35 +65,28 @@ export const convertToCSV = (data: any) => {
|
||||
if (invalidString) {
|
||||
return 'ERROR: LARGE STRING LENGTH'
|
||||
}
|
||||
|
||||
csvTest = data.map((row: any) => {
|
||||
const fields = Object.keys(row).map((fieldName, index) => {
|
||||
let value
|
||||
let containsSpecialChar = false
|
||||
const currentCell = row[fieldName]
|
||||
|
||||
if (JSON.stringify(currentCell).search(/(\\t|\\n|\\r)/gm) > -1) {
|
||||
value = currentCell.toString()
|
||||
containsSpecialChar = true
|
||||
} else {
|
||||
value = JSON.stringify(currentCell, replacer)
|
||||
}
|
||||
if (typeof currentCell === 'number') return currentCell
|
||||
|
||||
value = value.replace(/\\\\/gm, '\\')
|
||||
// stringify with replacer converts null values to empty strings
|
||||
value = currentCell === null ? '' : currentCell
|
||||
|
||||
if (containsSpecialChar) {
|
||||
if (value.includes(',') || value.includes('"')) {
|
||||
value = '"' + value + '"'
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
!value.includes(',') &&
|
||||
value.includes('"') &&
|
||||
!value.includes('\\"')
|
||||
) {
|
||||
value = value.substring(1, value.length - 1)
|
||||
}
|
||||
// if there any present, it should have preceding (") for escaping
|
||||
value = value.replace(/"/g, `""`)
|
||||
|
||||
value = value.replace(/\\"/gm, '""')
|
||||
// also wraps the value in double quotes
|
||||
value = `"${value}"`
|
||||
|
||||
if (
|
||||
value.substring(1, value.length - 1).search(/(\t|\n|\r|,|\'|\")/gm) < 0
|
||||
) {
|
||||
// Remove wrapping quotes for values that don't contain special characters
|
||||
value = value.substring(1, value.length - 1)
|
||||
}
|
||||
|
||||
value = value.replace(/\r\n/gm, '\n')
|
||||
|
||||
Reference in New Issue
Block a user