mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-03 10:40:06 +00:00
Merge branch 'master' of https://github.com/sasjs/adapter into api-execution
This commit is contained in:
164
sasjs-tests/package-lock.json
generated
164
sasjs-tests/package-lock.json
generated
@@ -1378,11 +1378,51 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sasjs/test-framework": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@sasjs/test-framework/-/test-framework-1.3.0.tgz",
|
||||
"integrity": "sha512-vrbRFUhNUShLlNFZO+XwVwFLXDLApQG9zOPx00xhQ8IUA0cSDFFmf2mP/KBdFCxa1REaR6GHvMctUj+xRZo9QQ==",
|
||||
"requires": {
|
||||
"@types/react-highlight.js": "^1.0.0",
|
||||
"moment": "^2.27.0",
|
||||
"react-highlight.js": "^1.0.7",
|
||||
"semantic-ui-css": "^2.4.1",
|
||||
"semantic-ui-react": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"@semantic-ui-react/event-stack": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.1.1.tgz",
|
||||
"integrity": "sha512-SA7VOu/tY3OkooR++mm9voeQrJpYXjJaMHO1aFCcSouS2xhqMR9Gnz0LEGLOR0h9ueWPBKaQzKIrx3FTTJZmUQ==",
|
||||
"requires": {
|
||||
"exenv": "^1.2.2",
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"@sheerun/mutationobserver-shim": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz",
|
||||
"integrity": "sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw=="
|
||||
},
|
||||
"@stardust-ui/react-component-event-listener": {
|
||||
"version": "0.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@stardust-ui/react-component-event-listener/-/react-component-event-listener-0.38.0.tgz",
|
||||
"integrity": "sha512-sIP/e0dyOrrlb8K7KWumfMxj/gAifswTBC4o68Aa+C/GA73ccRp/6W1VlHvF/dlOR4KLsA+5SKnhjH36xzPsWg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"@stardust-ui/react-component-ref": {
|
||||
"version": "0.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@stardust-ui/react-component-ref/-/react-component-ref-0.38.0.tgz",
|
||||
"integrity": "sha512-xjs6WnvJVueSIXMWw0C3oWIgAPpcD03qw43oGOjUXqFktvpNkB73JoKIhS4sCrtQxBdct75qqr4ZL6JiyPcESw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.6.3"
|
||||
}
|
||||
},
|
||||
"@svgr/babel-plugin-add-jsx-attribute": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz",
|
||||
@@ -1858,6 +1898,14 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-highlight.js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-highlight.js/-/react-highlight.js-1.0.0.tgz",
|
||||
"integrity": "sha512-5VXEuo2O9L66y/2GDQSGFTggQkpOvDc/p2ma1KHadu7o/H720HK3Fr83epd4wtQky7B/RoCPat0SKyhlhiUo7A==",
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-router": {
|
||||
"version": "5.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.8.tgz",
|
||||
@@ -3699,6 +3747,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"classnames": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
|
||||
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
|
||||
},
|
||||
"clean-css": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
|
||||
@@ -4117,6 +4170,15 @@
|
||||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"create-react-context": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz",
|
||||
"integrity": "sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==",
|
||||
"requires": {
|
||||
"gud": "^1.0.0",
|
||||
"warning": "^4.0.3"
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
||||
@@ -5641,6 +5703,11 @@
|
||||
"strip-eof": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"exenv": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
|
||||
"integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50="
|
||||
},
|
||||
"exit": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
|
||||
@@ -6510,6 +6577,11 @@
|
||||
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
|
||||
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE="
|
||||
},
|
||||
"gud": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz",
|
||||
"integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw=="
|
||||
},
|
||||
"gzip-size": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz",
|
||||
@@ -6654,6 +6726,11 @@
|
||||
"resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
|
||||
"integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
|
||||
},
|
||||
"highlight.js": {
|
||||
"version": "9.18.3",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz",
|
||||
"integrity": "sha512-zBZAmhSupHIl5sITeMqIJnYCDfAEc3Gdkqj65wC1lpI468MMQeeQkhcIAvk+RylAkxrCcI9xy9piHiXeQ1BdzQ=="
|
||||
},
|
||||
"history": {
|
||||
"version": "4.10.1",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
||||
@@ -8006,6 +8083,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
|
||||
"integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg=="
|
||||
},
|
||||
"js-base64": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.2.tgz",
|
||||
@@ -8155,6 +8237,11 @@
|
||||
"object.assign": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"keyboard-key": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz",
|
||||
"integrity": "sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ=="
|
||||
},
|
||||
"killable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
||||
@@ -8919,6 +9006,11 @@
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.27.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
|
||||
"integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@@ -9912,6 +10004,11 @@
|
||||
"ts-pnp": "^1.1.6"
|
||||
}
|
||||
},
|
||||
"popper.js": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
|
||||
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
|
||||
},
|
||||
"portfinder": {
|
||||
"version": "1.0.26",
|
||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz",
|
||||
@@ -11353,11 +11450,34 @@
|
||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz",
|
||||
"integrity": "sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA=="
|
||||
},
|
||||
"react-highlight.js": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/react-highlight.js/-/react-highlight.js-1.0.7.tgz",
|
||||
"integrity": "sha512-OVPKnV0ZvU+V//HExwbV8M9CWy49Eo/9y9pBN2OsNWUFPN6dE4YZBLmJW/5sM2DxI5v/QQLyxOnTnSSfGCP+9Q==",
|
||||
"requires": {
|
||||
"highlight.js": "^9.3.0",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"react-popper": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz",
|
||||
"integrity": "sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"create-react-context": "^0.3.0",
|
||||
"deep-equal": "^1.1.1",
|
||||
"popper.js": "^1.14.4",
|
||||
"prop-types": "^15.6.1",
|
||||
"typed-styles": "^0.0.7",
|
||||
"warning": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"react-router": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
|
||||
@@ -12097,6 +12217,32 @@
|
||||
"node-forge": "0.9.0"
|
||||
}
|
||||
},
|
||||
"semantic-ui-css": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/semantic-ui-css/-/semantic-ui-css-2.4.1.tgz",
|
||||
"integrity": "sha512-Pkp0p9oWOxlH0kODx7qFpIRYpK1T4WJOO4lNnpNPOoWKCrYsfHqYSKgk5fHfQtnWnsAKy7nLJMW02bgDWWFZFg==",
|
||||
"requires": {
|
||||
"jquery": "x.*"
|
||||
}
|
||||
},
|
||||
"semantic-ui-react": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-1.0.0.tgz",
|
||||
"integrity": "sha512-85mYHYuDBNa6la1BgKwuOSD1vcIPsFQEXRxGsZ9pUtE4iHlEcylF+x46NYHIGbBjlys63SpNH3PtK6VyZj9LBw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"@semantic-ui-react/event-stack": "^3.1.0",
|
||||
"@stardust-ui/react-component-event-listener": "~0.38.0",
|
||||
"@stardust-ui/react-component-ref": "~0.38.0",
|
||||
"classnames": "^2.2.6",
|
||||
"keyboard-key": "^1.0.4",
|
||||
"lodash": "^4.17.15",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.8.6",
|
||||
"react-popper": "^1.3.4",
|
||||
"shallowequal": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
@@ -12286,6 +12432,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"shallowequal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
|
||||
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
|
||||
},
|
||||
"shebang-command": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
|
||||
@@ -13454,6 +13605,11 @@
|
||||
"mime-types": "~2.1.24"
|
||||
}
|
||||
},
|
||||
"typed-styles": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz",
|
||||
"integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q=="
|
||||
},
|
||||
"typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
@@ -13755,6 +13911,14 @@
|
||||
"makeerror": "1.0.x"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.2.tgz",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@sasjs/adapter": "^1.0.5",
|
||||
"@sasjs/test-framework": "^1.3.0",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.5.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
.app {
|
||||
padding: 16px;
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.debug-toggle,
|
||||
.app-loc-input,
|
||||
.submit-button {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin: 16px;
|
||||
|
||||
&.app-loc {
|
||||
width: 20vw;
|
||||
}
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
padding: 16px;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.app-loc-input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.debug-toggle {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.label {
|
||||
padding: 0 8px;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
}
|
||||
|
||||
$height: 40px;
|
||||
$width: 70px;
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
width: $width;
|
||||
height: $height;
|
||||
|
||||
input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
input:checked + .knob {
|
||||
animation: colorChange 0.4s linear forwards;
|
||||
}
|
||||
input:checked + .knob:before {
|
||||
animation: turnON 0.4s linear forwards;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes colorChange {
|
||||
from {
|
||||
background-color: #ccc;
|
||||
}
|
||||
50% {
|
||||
background-color: #a4d9ad;
|
||||
}
|
||||
to {
|
||||
background-color: #4bd663;
|
||||
}
|
||||
}
|
||||
@keyframes turnON {
|
||||
from {
|
||||
transform: translateX(0px);
|
||||
}
|
||||
to {
|
||||
transform: translateX($width - ($height * 0.99));
|
||||
box-shadow: -10px 0px 44px 0px #434343;
|
||||
}
|
||||
}
|
||||
|
||||
.knob {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
border-radius: $height;
|
||||
}
|
||||
|
||||
.knob:before {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
content: "";
|
||||
left: $height * 0.1;
|
||||
top: $height * 0.1;
|
||||
width: ($height * 0.8);
|
||||
height: ($height * 0.8);
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,30 @@
|
||||
import React, { ReactElement, useState, useContext, useEffect } from "react";
|
||||
import "./App.scss";
|
||||
import TestSuiteRunner from "./TestSuiteRunner";
|
||||
import { AppContext } from "./context/AppContext";
|
||||
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";
|
||||
|
||||
const App = (): ReactElement<{}> => {
|
||||
const [appLoc, setAppLoc] = useState("");
|
||||
const [debug, setDebug] = useState(false);
|
||||
const { adapter } = useContext(AppContext);
|
||||
const { adapter, config } = useContext(AppContext);
|
||||
const [testSuites, setTestSuites] = useState<TestSuite[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (adapter) {
|
||||
adapter.setDebugState(debug);
|
||||
setTestSuites([
|
||||
basicTests(adapter, config.userName, config.password),
|
||||
sendArrTests(adapter),
|
||||
sendObjTests(adapter),
|
||||
specialCaseTests(adapter),
|
||||
sasjsRequestTests(adapter),
|
||||
]);
|
||||
}
|
||||
}, [debug, adapter]);
|
||||
|
||||
useEffect(() => {
|
||||
if (appLoc && adapter) {
|
||||
adapter.setSASjsConfig({ ...adapter.getSasjsConfig(), appLoc });
|
||||
}
|
||||
}, [appLoc, adapter]);
|
||||
|
||||
useEffect(() => {
|
||||
setAppLoc(adapter.getSasjsConfig().appLoc);
|
||||
}, [adapter]);
|
||||
}, [adapter, config]);
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<div className="controls">
|
||||
<div className="row">
|
||||
<label>Debug</label>
|
||||
<div className="debug-toggle">
|
||||
<label className="switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
onChange={(e) => setDebug(e.target.checked)}
|
||||
/>
|
||||
<span className="knob"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row app-loc">
|
||||
<label>App Loc</label>
|
||||
<input
|
||||
type="text"
|
||||
className="app-loc-input"
|
||||
value={appLoc}
|
||||
onChange={(e) => setAppLoc(e.target.value)}
|
||||
placeholder="AppLoc"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{adapter && <TestSuiteRunner adapter={adapter} />}
|
||||
{adapter && testSuites && <TestSuiteRunner testSuites={testSuites} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { ReactElement, useState, useCallback, useContext } from "react";
|
||||
import "./Login.scss";
|
||||
import { AppContext } from "./context/AppContext";
|
||||
import { AppContext } from "@sasjs/test-framework";
|
||||
import { Redirect } from "react-router-dom";
|
||||
|
||||
const Login = (): ReactElement<{}> => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { ReactElement, useContext, FunctionComponent } from "react";
|
||||
import { Redirect, Route } from "react-router-dom";
|
||||
import { AppContext } from "./context/AppContext";
|
||||
import { AppContext } from "@sasjs/test-framework";
|
||||
|
||||
interface PrivateRouteProps {
|
||||
component: FunctionComponent;
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
|
||||
.loading-spinner {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
padding: 10px;
|
||||
min-height: 80px;
|
||||
font-size: 2em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
import React, { useEffect, useState, ReactElement, useContext } from "react";
|
||||
import TestSuiteComponent from "./components/TestSuite";
|
||||
import TestSuiteCard from "./components/TestSuiteCard";
|
||||
import { TestSuite, Test } from "./types";
|
||||
import { basicTests } from "./testSuites/Basic";
|
||||
import "./TestSuiteRunner.scss";
|
||||
import SASjs from "@sasjs/adapter";
|
||||
import { AppContext } from "./context/AppContext";
|
||||
import { sendArrTests, sendObjTests } from "./testSuites/RequestData";
|
||||
import { specialCaseTests } from "./testSuites/SpecialCases";
|
||||
import { sasjsRequestTests } from "./testSuites/SasjsRequests";
|
||||
|
||||
interface TestSuiteRunnerProps {
|
||||
adapter: SASjs;
|
||||
}
|
||||
const TestSuiteRunner = (
|
||||
props: TestSuiteRunnerProps
|
||||
): ReactElement<TestSuiteRunnerProps> => {
|
||||
const { adapter } = props;
|
||||
const { config } = useContext(AppContext);
|
||||
const [testSuites, setTestSuites] = useState<TestSuite[]>([]);
|
||||
const [runTests, setRunTests] = useState(false);
|
||||
const [completedTestSuites, setCompletedTestSuites] = useState<
|
||||
{
|
||||
name: string;
|
||||
completedTests: {
|
||||
test: Test;
|
||||
result: boolean;
|
||||
error: Error | null;
|
||||
executionTime: number;
|
||||
}[];
|
||||
}[]
|
||||
>([]);
|
||||
const [currentTestSuite, setCurrentTestSuite] = useState<TestSuite | null>(
|
||||
(null as unknown) as TestSuite
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (adapter) {
|
||||
setTestSuites([
|
||||
basicTests(adapter, config.userName, config.password),
|
||||
sendArrTests(adapter),
|
||||
sendObjTests(adapter),
|
||||
specialCaseTests(adapter),
|
||||
sasjsRequestTests(adapter),
|
||||
]);
|
||||
setCompletedTestSuites([]);
|
||||
}
|
||||
}, [adapter]);
|
||||
|
||||
useEffect(() => {
|
||||
if (testSuites.length) {
|
||||
setCurrentTestSuite(testSuites[0]);
|
||||
}
|
||||
}, [testSuites]);
|
||||
|
||||
useEffect(() => {
|
||||
if (runTests) {
|
||||
setCompletedTestSuites([]);
|
||||
setCurrentTestSuite(testSuites[0]);
|
||||
}
|
||||
}, [runTests, testSuites]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="button-container">
|
||||
<button
|
||||
className={runTests ? "submit-button disabled" : "submit-button"}
|
||||
onClick={() => setRunTests(true)}
|
||||
disabled={runTests}
|
||||
>
|
||||
{runTests ? (
|
||||
<>
|
||||
<div className="loading-spinner"></div>Running tests...
|
||||
</>
|
||||
) : (
|
||||
"Run tests!"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
{completedTestSuites.map((completedTestSuite, index) => {
|
||||
return (
|
||||
<TestSuiteCard
|
||||
key={index}
|
||||
tests={completedTestSuite.completedTests}
|
||||
name={completedTestSuite.name}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{currentTestSuite && runTests && (
|
||||
<TestSuiteComponent
|
||||
{...currentTestSuite}
|
||||
onCompleted={(
|
||||
name,
|
||||
completedTests: {
|
||||
test: Test;
|
||||
result: boolean;
|
||||
error: Error | null;
|
||||
executionTime: number;
|
||||
}[]
|
||||
) => {
|
||||
const currentIndex = testSuites.indexOf(currentTestSuite);
|
||||
const nextIndex =
|
||||
currentIndex < testSuites.length - 1 ? currentIndex + 1 : -1;
|
||||
if (nextIndex >= 0) {
|
||||
setCurrentTestSuite(testSuites[nextIndex]);
|
||||
} else {
|
||||
setCurrentTestSuite(null);
|
||||
}
|
||||
const newCompletedTestSuites = [
|
||||
...completedTestSuites,
|
||||
{ name, completedTests },
|
||||
];
|
||||
setCompletedTestSuites(newCompletedTestSuites);
|
||||
|
||||
if (newCompletedTestSuites.length === testSuites.length) {
|
||||
setRunTests(false);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TestSuiteRunner;
|
||||
@@ -1,79 +0,0 @@
|
||||
import React, { ReactElement, useEffect, useState } from "react";
|
||||
import TestCard from "./TestCard";
|
||||
import { start } from "repl";
|
||||
|
||||
interface TestProps {
|
||||
title: string;
|
||||
description: string;
|
||||
beforeTest?: (...args: any) => Promise<any>;
|
||||
afterTest?: (...args: any) => Promise<any>;
|
||||
test: (context: any) => Promise<any>;
|
||||
assertion: (...args: any) => boolean;
|
||||
onCompleted: (payload: {
|
||||
result: boolean;
|
||||
error: Error | null;
|
||||
executionTime: number;
|
||||
}) => void;
|
||||
context: any;
|
||||
}
|
||||
|
||||
const getStatus = (isRunning: boolean, isPassed: boolean): string => {
|
||||
return isRunning ? "running" : isPassed ? "passed" : "failed";
|
||||
};
|
||||
|
||||
const Test = (props: TestProps): ReactElement<TestProps> => {
|
||||
const {
|
||||
title,
|
||||
description,
|
||||
test,
|
||||
beforeTest,
|
||||
afterTest,
|
||||
assertion,
|
||||
onCompleted,
|
||||
context,
|
||||
} = props;
|
||||
const beforeTestFunction = beforeTest ? beforeTest : () => Promise.resolve();
|
||||
const afterTestFunction = afterTest ? afterTest : () => Promise.resolve();
|
||||
const [isRunning, setIsRunning] = useState(false);
|
||||
const [isPassed, setIsPassed] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (test && assertion) {
|
||||
const startTime = new Date().valueOf();
|
||||
setIsRunning(true);
|
||||
setIsPassed(false);
|
||||
beforeTestFunction()
|
||||
.then(() => test(context))
|
||||
.then((res) => {
|
||||
setIsRunning(false);
|
||||
setIsPassed(assertion(res, context));
|
||||
return Promise.resolve(assertion(res, context));
|
||||
})
|
||||
.then((testResult) => {
|
||||
afterTestFunction();
|
||||
const endTime = new Date().valueOf();
|
||||
const executionTime = (endTime - startTime) / 1000;
|
||||
onCompleted({ result: testResult, error: null, executionTime });
|
||||
})
|
||||
.catch((e) => {
|
||||
setIsRunning(false);
|
||||
setIsPassed(false);
|
||||
console.error(e);
|
||||
const endTime = new Date().valueOf();
|
||||
const executionTime = (endTime - startTime) / 1000;
|
||||
onCompleted({ result: false, error: e, executionTime });
|
||||
});
|
||||
}
|
||||
}, [test, assertion]);
|
||||
|
||||
return (
|
||||
<TestCard
|
||||
title={title}
|
||||
description={description}
|
||||
status={getStatus(isRunning, isPassed)}
|
||||
error={null}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Test;
|
||||
@@ -1,62 +0,0 @@
|
||||
.test {
|
||||
display: inline-flex;
|
||||
padding: 8px;
|
||||
margin: 8px;
|
||||
flex-direction: column;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
width: 20%;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
color: #eee;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.description,
|
||||
.execution-time {
|
||||
color: #c6c0c0;
|
||||
padding: 8px 0;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.description {
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.execution-time {
|
||||
color: #f9e804;
|
||||
}
|
||||
|
||||
.icon {
|
||||
border-radius: 50%;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-right: 8px;
|
||||
display: inline-block;
|
||||
|
||||
&.running {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
&.passed {
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
&.failed {
|
||||
background-color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 900px) {
|
||||
.test {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 901px) and (max-width: 1280px) {
|
||||
.test {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import React, { ReactElement } from "react";
|
||||
import "./TestCard.scss";
|
||||
|
||||
interface TestCardProps {
|
||||
title: string;
|
||||
description: string;
|
||||
status: string;
|
||||
error: Error | null;
|
||||
executionTime?: number;
|
||||
}
|
||||
const TestCard = (props: TestCardProps): ReactElement<TestCardProps> => {
|
||||
const { title, description, status, error, executionTime } = props;
|
||||
|
||||
return (
|
||||
<div className="test">
|
||||
<code className="title">{title}</code>
|
||||
<span className="description">{description}</span>
|
||||
<span className="execution-time">
|
||||
{executionTime ? executionTime.toFixed(2) + "s" : ""}
|
||||
</span>
|
||||
{status === "running" && (
|
||||
<div>
|
||||
<span className="icon running"></span>Running...
|
||||
</div>
|
||||
)}
|
||||
{status === "passed" && (
|
||||
<div>
|
||||
<span className="icon passed"></span>Passed
|
||||
</div>
|
||||
)}
|
||||
{status === "failed" && (
|
||||
<>
|
||||
<div>
|
||||
<span className="icon failed"></span>Failed
|
||||
</div>
|
||||
{!!error && <code>{error.message}</code>}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TestCard;
|
||||
@@ -1,106 +0,0 @@
|
||||
import React, { ReactElement, useState, useEffect } from "react";
|
||||
import "./TestSuiteCard.scss";
|
||||
import { Test } from "../types";
|
||||
import TestComponent from "./Test";
|
||||
import TestCard from "./TestCard";
|
||||
|
||||
interface TestSuiteProps {
|
||||
name: string;
|
||||
tests: Test[];
|
||||
beforeAll?: (...args: any) => Promise<any>;
|
||||
afterAll?: (...args: any) => Promise<any>;
|
||||
onCompleted: (
|
||||
name: string,
|
||||
completedTests: {
|
||||
test: Test;
|
||||
result: boolean;
|
||||
error: Error | null;
|
||||
executionTime: number;
|
||||
}[]
|
||||
) => void;
|
||||
}
|
||||
const TestSuite = (props: TestSuiteProps): ReactElement<TestSuiteProps> => {
|
||||
const { name, tests, beforeAll, afterAll, onCompleted } = props;
|
||||
const [context, setContext] = useState<any>(null);
|
||||
const [completedTests, setCompletedTests] = useState<
|
||||
{
|
||||
test: Test;
|
||||
result: boolean;
|
||||
error: Error | null;
|
||||
executionTime: number;
|
||||
}[]
|
||||
>([]);
|
||||
const [currentTest, setCurrentTest] = useState<Test | null>(
|
||||
(null as unknown) as Test
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (beforeAll) {
|
||||
beforeAll().then((data) => setContext({ data }));
|
||||
}
|
||||
}, [beforeAll]);
|
||||
|
||||
useEffect(() => {
|
||||
if (tests.length) {
|
||||
setCurrentTest(tests[0]);
|
||||
}
|
||||
setCompletedTests([]);
|
||||
setContext(null);
|
||||
}, [tests]);
|
||||
|
||||
return (!!beforeAll && !!context) || !beforeAll ? (
|
||||
<div className="test-suite">
|
||||
<div className="test-suite-name running">{name}</div>
|
||||
{currentTest && (
|
||||
<TestComponent
|
||||
{...currentTest}
|
||||
context={context}
|
||||
onCompleted={(completedTest) => {
|
||||
const newCompleteTests = [
|
||||
...completedTests,
|
||||
{
|
||||
test: currentTest,
|
||||
result: completedTest.result,
|
||||
error: completedTest.error,
|
||||
executionTime: completedTest.executionTime,
|
||||
},
|
||||
];
|
||||
setCompletedTests(newCompleteTests);
|
||||
const currentIndex = tests.indexOf(currentTest);
|
||||
const nextIndex =
|
||||
currentIndex < tests.length - 1 ? currentIndex + 1 : -1;
|
||||
if (nextIndex >= 0) {
|
||||
setCurrentTest(tests[nextIndex]);
|
||||
} else {
|
||||
setCurrentTest(null);
|
||||
}
|
||||
if (newCompleteTests.length === tests.length) {
|
||||
if (afterAll) {
|
||||
afterAll().then(() => onCompleted(name, newCompleteTests));
|
||||
} else {
|
||||
onCompleted(name, newCompleteTests);
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{completedTests.map((completedTest, index) => {
|
||||
const { test, result, error } = completedTest;
|
||||
const { title, description } = test;
|
||||
return (
|
||||
<TestCard
|
||||
key={index}
|
||||
title={title}
|
||||
description={description}
|
||||
status={result === true ? "passed" : "failed"}
|
||||
error={error}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
|
||||
export default TestSuite;
|
||||
@@ -1,19 +0,0 @@
|
||||
.test-suite {
|
||||
.test-suite-name {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
color: #1f2027;
|
||||
|
||||
&.passed {
|
||||
color: green;
|
||||
}
|
||||
|
||||
&.failed {
|
||||
color: red;
|
||||
}
|
||||
|
||||
&.running {
|
||||
color: yellow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import React, { ReactElement } from "react";
|
||||
import "./TestSuiteCard.scss";
|
||||
import { Test } from "../types";
|
||||
import TestCard from "./TestCard";
|
||||
|
||||
interface TestSuiteCardProps {
|
||||
name: string;
|
||||
tests: {
|
||||
test: Test;
|
||||
result: boolean;
|
||||
error: Error | null;
|
||||
executionTime: number;
|
||||
}[];
|
||||
}
|
||||
const TestSuiteCard = (
|
||||
props: TestSuiteCardProps
|
||||
): ReactElement<TestSuiteCardProps> => {
|
||||
const { name, tests } = props;
|
||||
const overallStatus = tests.map((t) => t.result).reduce((x, y) => x && y);
|
||||
|
||||
return (
|
||||
<div className="test-suite">
|
||||
<div className={`test-suite-name ${overallStatus ? "passed" : "failed"}`}>
|
||||
{name}
|
||||
</div>
|
||||
{tests.map((completedTest, index) => {
|
||||
const { test, result, error, executionTime } = completedTest;
|
||||
const { title, description } = test;
|
||||
return (
|
||||
<TestCard
|
||||
key={index}
|
||||
title={title}
|
||||
description={description}
|
||||
status={result === true ? "passed" : "failed"}
|
||||
error={error}
|
||||
executionTime={executionTime}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TestSuiteCard;
|
||||
@@ -1,53 +0,0 @@
|
||||
import React, { createContext, useState, useEffect, ReactNode } from "react";
|
||||
import SASjs from "@sasjs/adapter";
|
||||
|
||||
export const AppContext = createContext<{
|
||||
config: any;
|
||||
sasJsConfig: any;
|
||||
isLoggedIn: boolean;
|
||||
setIsLoggedIn: (value: boolean) => void;
|
||||
adapter: SASjs;
|
||||
}>({
|
||||
config: null,
|
||||
sasJsConfig: null,
|
||||
isLoggedIn: false,
|
||||
setIsLoggedIn: (null as unknown) as (value: boolean) => void,
|
||||
adapter: (null as unknown) as SASjs,
|
||||
});
|
||||
|
||||
export const AppProvider = (props: { children: ReactNode }) => {
|
||||
const [config, setConfig] = useState<{ sasJsConfig: any }>({
|
||||
sasJsConfig: null,
|
||||
});
|
||||
|
||||
const [adapter, setAdapter] = useState<SASjs>((null as unknown) as SASjs);
|
||||
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("config.json")
|
||||
.then((res) => res.json())
|
||||
.then((configJson: any) => {
|
||||
setConfig(configJson);
|
||||
const sasjs = new SASjs(configJson.sasJsConfig);
|
||||
setAdapter(sasjs);
|
||||
sasjs.checkSession().then((response) => {
|
||||
setIsLoggedIn(response.isLoggedIn);
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AppContext.Provider
|
||||
value={{
|
||||
config,
|
||||
sasJsConfig: config.sasJsConfig,
|
||||
isLoggedIn,
|
||||
setIsLoggedIn,
|
||||
adapter,
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
@@ -3,7 +3,7 @@ import ReactDOM from "react-dom";
|
||||
import { Route, HashRouter, Switch } from "react-router-dom";
|
||||
import "./index.scss";
|
||||
import * as serviceWorker from "./serviceWorker";
|
||||
import { AppProvider } from "./context/AppContext";
|
||||
import { AppProvider } from "@sasjs/test-framework";
|
||||
import PrivateRoute from "./PrivateRoute";
|
||||
import Login from "./Login";
|
||||
import App from "./App";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import SASjs, { ServerType, SASjsConfig } from "@sasjs/adapter";
|
||||
import { TestSuite } from "../types";
|
||||
import { TestSuite } from "@sasjs/test-framework";
|
||||
|
||||
const defaultConfig: SASjsConfig = {
|
||||
serverUrl: window.location.origin,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import SASjs from "@sasjs/adapter";
|
||||
import { TestSuite } from "../types";
|
||||
import { TestSuite } from "@sasjs/test-framework";
|
||||
|
||||
const stringData: any = { table1: [{ col1: "first col value" }] };
|
||||
const numericData: any = { table1: [{ col1: 3.14159265 }] };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import SASjs from "@sasjs/adapter";
|
||||
import { TestSuite } from "../types";
|
||||
import { TestSuite } from "@sasjs/test-framework";
|
||||
|
||||
const data: any = { table1: [{ col1: "first col value" }] };
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import SASjs from "@sasjs/adapter";
|
||||
import { TestSuite } from "../types";
|
||||
import { TestSuite } from "@sasjs/test-framework";
|
||||
|
||||
const specialCharData: any = {
|
||||
table1: [
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
export interface Test {
|
||||
title: string;
|
||||
description: string;
|
||||
beforeTest?: (...args: any) => Promise<any>;
|
||||
afterTest?: (...args: any) => Promise<any>;
|
||||
test: (context?: any) => Promise<any>;
|
||||
assertion: (...args: any) => boolean;
|
||||
}
|
||||
|
||||
export interface TestSuite {
|
||||
name: string;
|
||||
tests: Test[];
|
||||
beforeAll?: (...args: any) => Promise<any>;
|
||||
afterAll?: (...args: any) => Promise<any>;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
export const uploadFile = (file: File, fileName: string, url: string) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const data = new FormData();
|
||||
data.append("file", file);
|
||||
data.append("filename", fileName);
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.withCredentials = true;
|
||||
xhr.addEventListener("readystatechange", function () {
|
||||
if (this.readyState === 4) {
|
||||
let response: any;
|
||||
try {
|
||||
response = JSON.parse(this.responseText);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
resolve(response);
|
||||
}
|
||||
});
|
||||
xhr.open("POST", url);
|
||||
xhr.setRequestHeader("cache-control", "no-cache");
|
||||
xhr.send(data);
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user