diff --git a/packages/testkit-backend/.gitignore b/packages/testkit-backend/.gitignore
new file mode 100644
index 000000000..2173e574c
--- /dev/null
+++ b/packages/testkit-backend/.gitignore
@@ -0,0 +1 @@
+public/index.js
diff --git a/packages/testkit-backend/package-lock.json b/packages/testkit-backend/package-lock.json
index d57669890..219d83d0c 100644
--- a/packages/testkit-backend/package-lock.json
+++ b/packages/testkit-backend/package-lock.json
@@ -4,11 +4,365 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+ "@rollup/plugin-commonjs": {
+ "version": "21.0.1",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz",
+ "integrity": "sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==",
+ "dev": true,
+ "requires": {
+ "@rollup/pluginutils": "^3.1.0",
+ "commondir": "^1.0.1",
+ "estree-walker": "^2.0.1",
+ "glob": "^7.1.6",
+ "is-reference": "^1.2.1",
+ "magic-string": "^0.25.7",
+ "resolve": "^1.17.0"
+ },
+ "dependencies": {
+ "estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true
+ }
+ }
+ },
+ "@rollup/plugin-inject": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-4.0.3.tgz",
+ "integrity": "sha512-lzMXmj0LZjd67MI+M8H9dk/oCxR0TYqYAdZ6ZOejWQLSUtud+FUPu4NCMAO8KyWWAalFo8ean7yFHCMvCNsCZw==",
+ "dev": true,
+ "requires": {
+ "@rollup/pluginutils": "^3.1.0",
+ "estree-walker": "^2.0.1",
+ "magic-string": "^0.25.7"
+ },
+ "dependencies": {
+ "estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true
+ }
+ }
+ },
+ "@rollup/plugin-node-resolve": {
+ "version": "13.0.6",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.6.tgz",
+ "integrity": "sha512-sFsPDMPd4gMqnh2gS0uIxELnoRUp5kBl5knxD2EO0778G1oOJv4G1vyT2cpWz75OU2jDVcXhjVUuTAczGyFNKA==",
+ "dev": true,
+ "requires": {
+ "@rollup/pluginutils": "^3.1.0",
+ "@types/resolve": "1.17.1",
+ "builtin-modules": "^3.1.0",
+ "deepmerge": "^4.2.2",
+ "is-module": "^1.0.0",
+ "resolve": "^1.19.0"
+ }
+ },
+ "@rollup/pluginutils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
+ "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
+ "dev": true,
+ "requires": {
+ "@types/estree": "0.0.39",
+ "estree-walker": "^1.0.1",
+ "picomatch": "^2.2.2"
+ }
+ },
+ "@types/estree": {
+ "version": "0.0.39",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
+ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+ "dev": true
+ },
+ "@types/node": {
+ "version": "16.11.7",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz",
+ "integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==",
+ "dev": true
+ },
+ "@types/resolve": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
+ "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "builtin-modules": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
+ "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
+ "dev": true
+ },
+ "colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
+ },
+ "commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "deepmerge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+ "dev": true
+ },
"esm": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
"dev": true
+ },
+ "estree-walker": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
+ "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
+ "dev": true
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "is-core-module": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
+ "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "is-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+ "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
+ "dev": true
+ },
+ "is-reference": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
+ "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
+ "dev": true,
+ "requires": {
+ "@types/estree": "*"
+ }
+ },
+ "magic-string": {
+ "version": "0.25.7",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
+ "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
+ "dev": true,
+ "requires": {
+ "sourcemap-codec": "^1.4.4"
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
+ "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
+ },
+ "node-static": {
+ "version": "0.7.11",
+ "resolved": "https://registry.npmjs.org/node-static/-/node-static-0.7.11.tgz",
+ "integrity": "sha512-zfWC/gICcqb74D9ndyvxZWaI1jzcoHmf4UTHWQchBNuNMxdBLJMDiUgZ1tjGLEIe/BMhj2DxKD8HOuc2062pDQ==",
+ "requires": {
+ "colors": ">=0.6.0",
+ "mime": "^1.2.9",
+ "optimist": ">=0.3.4"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "optimist": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "requires": {
+ "minimist": "~0.0.1",
+ "wordwrap": "~0.0.2"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
+ "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
+ "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
+ "dev": true,
+ "requires": {
+ "is-core-module": "^2.2.0",
+ "path-parse": "^1.0.6"
+ }
+ },
+ "rollup": {
+ "version": "2.59.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.59.0.tgz",
+ "integrity": "sha512-l7s90JQhCQ6JyZjKgo7Lq1dKh2RxatOM+Jr6a9F7WbS9WgKbocyUSeLmZl8evAse7y96Ae98L2k1cBOwWD8nHw==",
+ "dev": true,
+ "requires": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "rollup-plugin-inject-process-env": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-inject-process-env/-/rollup-plugin-inject-process-env-1.3.1.tgz",
+ "integrity": "sha512-kKDoL30IZr0wxbNVJjq+OS92RJSKRbKV6B5eNW4q3mZTFqoWDh6lHy+mPDYuuGuERFNKXkG+AKxvYqC9+DRpKQ==",
+ "dev": true,
+ "requires": {
+ "magic-string": "^0.25.7"
+ }
+ },
+ "rollup-plugin-polyfill-node": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.7.0.tgz",
+ "integrity": "sha512-iJLZDfvxcQh3SpC0OiYlZG9ik26aRM29hiC2sARbAPXYunB8rzW8GtVaWuJgiCtX1hNAo/OaYvVXfPp15fMs7g==",
+ "dev": true,
+ "requires": {
+ "@rollup/plugin-inject": "^4.0.0"
+ }
+ },
+ "sourcemap-codec": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+ "dev": true
+ },
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "ws": {
+ "version": "8.2.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
+ "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA=="
}
}
}
diff --git a/packages/testkit-backend/package.json b/packages/testkit-backend/package.json
index 8d050630c..8e68ae0fd 100644
--- a/packages/testkit-backend/package.json
+++ b/packages/testkit-backend/package.json
@@ -4,10 +4,16 @@
"description": "Backend for the testkit test framework",
"main": "src/main.js",
"private": true,
+ "browser": {
+ "./src/controller/remote.js": "./src/controller/interface.js",
+ "./src/channel/socket.js": "./src/controller/interface.js"
+ },
"type": "module",
"scripts": {
- "start": "node -r esm src/main.js",
- "clean": "rm -fr node_modules"
+ "build": "rollup src/index.js --config rollup.config.js",
+ "start": "node -r esm src/index.js",
+ "clean": "rm -fr node_modules public/index.js",
+ "prepare": "npm run build"
},
"repository": {
"type": "git",
@@ -24,10 +30,17 @@
},
"homepage": "https://github.com/neo4j/neo4j-javascript-driver#readme",
"dependencies": {
+ "neo4j-driver": "4.4.0-dev",
"neo4j-driver-lite": "4.4.0-dev",
- "neo4j-driver": "4.4.0-dev"
+ "node-static": "^0.7.11",
+ "ws": "^8.2.3"
},
"devDependencies": {
- "esm": "^3.2.25"
+ "@rollup/plugin-commonjs": "^21.0.1",
+ "@rollup/plugin-node-resolve": "^13.0.6",
+ "esm": "^3.2.25",
+ "rollup": "^2.59.0",
+ "rollup-plugin-inject-process-env": "^1.3.1",
+ "rollup-plugin-polyfill-node": "^0.7.0"
}
}
diff --git a/packages/testkit-backend/public/index.html b/packages/testkit-backend/public/index.html
new file mode 100644
index 000000000..275aaed53
--- /dev/null
+++ b/packages/testkit-backend/public/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+ Example
+
+
+
+
\ No newline at end of file
diff --git a/packages/testkit-backend/rollup.config.js b/packages/testkit-backend/rollup.config.js
new file mode 100644
index 000000000..ae5295236
--- /dev/null
+++ b/packages/testkit-backend/rollup.config.js
@@ -0,0 +1,28 @@
+import nodeResolve from '@rollup/plugin-node-resolve'
+import commonjs from '@rollup/plugin-commonjs'
+import polyfillNode from 'rollup-plugin-polyfill-node'
+import injectProcessEnv from 'rollup-plugin-inject-process-env'
+
+export default {
+ input: 'src/index.js',
+ output: {
+ dir: 'public',
+ format: 'umd',
+ name: 'testkitbackend'
+ },
+ plugins: [
+ nodeResolve({
+ browser: true,
+ preferBuiltins: false
+ }),
+ commonjs(),
+ polyfillNode({
+ }),
+ injectProcessEnv({
+ ...process.env,
+ TEST_ENVIRONMENT: 'LOCAL',
+ CHANNEL_TYPE: 'WEBSOCKET',
+ BACKEND_PORT: process.env.WEB_SERVER_PORT || 8000
+ })
+ ]
+}
diff --git a/packages/testkit-backend/src/backend.js b/packages/testkit-backend/src/backend.js
new file mode 100644
index 000000000..f1f8983cd
--- /dev/null
+++ b/packages/testkit-backend/src/backend.js
@@ -0,0 +1,43 @@
+import Channel from './channel'
+import Controller from './controller'
+
+/**
+ * Binds Channel and Controller
+ */
+export default class Backend {
+ /**
+ *
+ * @param {function():Controller} newController The controller factory function
+ * @param {function():Channel} newChannel The channel factory function
+ */
+ constructor (newController, newChannel) {
+ this._channel = newChannel()
+ this._controller = newController()
+
+ this._controller.on('response', ({ contextId, response }) => {
+ this._channel.writeResponse(contextId, response)
+ })
+
+ this._channel.on('contextOpen', ({ contextId }) => this._controller.openContext(contextId))
+ this._channel.on('contextClose', ({ contextId }) => this._controller.closeContext(contextId))
+
+ this._channel.on('request', ({ contextId, request }) => {
+ try {
+ this._controller.handle(contextId, request)
+ } catch (e) {
+ this._channel.writeBackendError(contextId, e)
+ }
+ })
+ }
+
+ start () {
+ this._controller.start()
+ this._channel.start()
+ }
+
+ stop () {
+ this._channel.stop()
+ this._controller.stop()
+ }
+
+}
diff --git a/packages/testkit-backend/src/channel/index.js b/packages/testkit-backend/src/channel/index.js
new file mode 100644
index 000000000..3f6350362
--- /dev/null
+++ b/packages/testkit-backend/src/channel/index.js
@@ -0,0 +1,17 @@
+import Channel from "./interface"
+import SocketChannel from "./socket"
+import WebSocketChannel from "./websocket"
+/**
+ * Channels are the pieces of code responsible for communicating with testkit.
+ *
+ * {@link SocketChannel} is a server socket implementation meant to be used to talk directly to the
+ * testkit server.
+ *
+ * {@link WebSocketChannel} is a client implementation used for connection to other testkit-backend for receiving
+ * messages.
+ */
+export default Channel
+export {
+ SocketChannel,
+ WebSocketChannel
+}
diff --git a/packages/testkit-backend/src/channel/interface.js b/packages/testkit-backend/src/channel/interface.js
new file mode 100644
index 000000000..9cadfdea1
--- /dev/null
+++ b/packages/testkit-backend/src/channel/interface.js
@@ -0,0 +1,30 @@
+import { EventEmitter } from "events"
+
+/**
+ * Defines the interface used for receiving commands form teskit.
+ *
+ * This is a thin layer only responsible for receiving and sending messages from and to testkit.
+ *
+ * @event contextOpen This event is triggered when a new testkit client starts its work.
+ * @event contextClose This event is triggered when an existing client finishes it work
+ * @event request This event is triggered when the channel receives a request
+ */
+export default class Channel extends EventEmitter {
+
+ start () {
+ throw Error('Not implemented')
+ }
+
+ stop () {
+ throw Error('Not implemented')
+ }
+
+ writeResponse (contextId, response) {
+ throw Error('Not implemented')
+ }
+
+ writeBackendError (contextId, error) {
+ this.writeResponse(contextId, { name: 'BackendError', data: { msg: error } })
+ }
+
+}
diff --git a/packages/testkit-backend/src/channel/socket.js b/packages/testkit-backend/src/channel/socket.js
new file mode 100644
index 000000000..37e440688
--- /dev/null
+++ b/packages/testkit-backend/src/channel/socket.js
@@ -0,0 +1,83 @@
+import Channel from './interface'
+import net from 'net'
+import { randomBytes } from 'crypto'
+import Protocol from './testkit-protocol'
+
+function generateRandomId () {
+ return randomBytes(16).toString('hex')
+}
+
+/**
+ * This is communication channel handles the direct communication with TestKit using its protocol.
+ *
+ * This implementation is meant to be run in NodeJS, it doesn't support Browser.
+ */
+export default class SocketChannel extends Channel {
+ constructor(port, newProtocol = stream => new Protocol(stream), newId = generateRandomId ) {
+ super()
+ this._newProtocol = newProtocol
+ this._server = null
+ this._newId = newId
+ this._clients = new Map()
+ this._port = port
+ }
+
+ start () {
+ if (!this._server) {
+ this._server = net.createServer(this._handleConnection.bind(this))
+
+ this._server.listen(this._port, () => {
+ console.log('Listening')
+ })
+
+ this._server.on('close', () => this.emit('close'))
+ }
+ }
+
+ _handleConnection(connection) {
+ console.log('Backend connected')
+
+ const contextId = this._newId()
+ const protocol = this._newProtocol(connection)
+
+ this._clients.set(contextId, {
+ protocol,
+ connection
+ })
+
+ this.emit('contextOpen', { contextId })
+ protocol.on('request', request => this.emit('request', { contextId, request }) )
+ protocol.on('error', e => this._writeBackendError(contextId, e))
+
+ connection.on('end', () => {
+ if (this._clients.has(contextId)) {
+ this._clients.get(contextId).protocol.stop()
+ }
+ this._clients.delete(contextId)
+ this.emit('contextClose', { contextId })
+ })
+
+ protocol.start()
+ }
+
+ writeResponse (contextId, response) {
+ if (this._clients.has(contextId)) {
+ const { protocol, connection } = this._clients.get(contextId)
+ const chunk = protocol.serializeResponse(response)
+ connection.write(chunk, 'utf8', () => {})
+ }
+ }
+
+ writeBackendError (contextId, error) {
+ this.writeResponse(contextId, { name: 'BackendError', data: { msg: error } })
+ }
+
+ stop () {
+ if (this._server) {
+ this._server.close()
+ this._server = null
+ this._clients.forEach(client => client.protocol.stop())
+ this._clients = new Map()
+ }
+ }
+}
diff --git a/packages/testkit-backend/src/channel/testkit-protocol.js b/packages/testkit-backend/src/channel/testkit-protocol.js
new file mode 100644
index 000000000..bacc41e64
--- /dev/null
+++ b/packages/testkit-backend/src/channel/testkit-protocol.js
@@ -0,0 +1,80 @@
+import readline from 'readline'
+import EventEmitter from 'events'
+
+export default class Protocol extends EventEmitter {
+ constructor (stream) {
+ super()
+ this._inRequest = false
+ this._request = ''
+ this._stream = stream
+ this._readlineInterface = null
+ }
+
+ start() {
+ if (!this._readlineInterface) {
+ this._readlineInterface = readline.createInterface(this._stream, null)
+ this._readlineInterface.on('line', this._processLine.bind(this))
+ }
+ }
+
+ stop () {
+ if (this._readlineInterface) {
+ this._readlineInterface.off('line', this._processLine.bind(this))
+ this._readlineInterface = null
+ }
+ }
+
+ // Called whenever a new line is received.
+ _processLine (line) {
+ switch (line) {
+ case '#request begin':
+ if (this._inRequest) {
+ throw new Error('Already in request')
+ }
+ this._inRequest = true
+ break
+ case '#request end':
+ if (!this._inRequest) {
+ throw new Error('End while not in request')
+ }
+ try {
+ this._emitRequest()
+ } catch (e) {
+ console.log('error', e)
+ this._emitError(e)
+ }
+ this._request = ''
+ this._inRequest = false
+ break
+ default:
+ if (!this._inRequest) {
+ this._emitError(new Error('Line while not in request'))
+ }
+ this._request += line
+ break
+ }
+ }
+
+ _emitError(e) {
+ this.emit('error', e)
+ }
+
+ serializeResponse (response) {
+ console.log('> writing response', response)
+ const responseStr = this._stringify(response)
+ return ['#response begin', responseStr, '#response end'].join('\n') + '\n'
+ }
+
+ _emitRequest () {
+ const request = JSON.parse(this._request)
+ const { name, data } = request
+ console.log('> Got request ' + name, data)
+ this.emit('request', { name, data })
+ }
+
+ _stringify (val) {
+ return JSON.stringify(val, (_, value) =>
+ typeof value === 'bigint' ? `${value}n` : value
+ )
+ }
+}
diff --git a/packages/testkit-backend/src/channel/websocket.js b/packages/testkit-backend/src/channel/websocket.js
new file mode 100644
index 000000000..4c8281dfa
--- /dev/null
+++ b/packages/testkit-backend/src/channel/websocket.js
@@ -0,0 +1,62 @@
+import Channel from "./interface"
+
+/**
+ * This communication channel is meant to connect to other instances of the `testkit-backend` for receiving its events.
+ *
+ * This channel is only supported in browsers since it depends on WebSocket client to be available globally.
+ */
+export default class WebSocketChannel extends Channel {
+
+ constructor(address) {
+ super()
+ this._adddress = address
+ this._ws = null
+ }
+
+ start () {
+ if(!this._ws) {
+ this._ws = new WebSocket(this._adddress)
+ this._ws.onmessage = ({ data: message }) => {
+ console.log(message)
+ console.debug('[WebSocketChannel] Received messsage', message)
+ const { messageType, contextId, data } = JSON.parse(message)
+
+ switch (messageType) {
+ case 'contextOpen':
+ case 'contextClose':
+ this.emit(messageType, data)
+ break
+ case 'request':
+ this.emit(messageType, { contextId, request: data })
+ break
+ default:
+ console.error(`[WebSocketChannel] ${messageType} is not a valid message type`)
+ }
+ }
+
+ this._ws.onclose = () => this.emit('close')
+ }
+ }
+
+ stop () {
+ if(this._ws) {
+ this._ws.close()
+ this._ws = null
+ }
+ }
+
+ writeResponse (contextId, response) {
+ if (this._ws) {
+ console.debug('[WebSocketChannel] Writing response', { contextId, response })
+ return this._ws.send(this._serialize({ contextId, response }))
+ }
+ console.error('[WebSocketChannel] Websocket is not connected')
+ }
+
+ _serialize (val) {
+ return JSON.stringify(val, (_, value) =>
+ typeof value === 'bigint' ? `${value}n` : value
+ )
+ }
+
+}
diff --git a/packages/testkit-backend/src/controller/index.js b/packages/testkit-backend/src/controller/index.js
new file mode 100644
index 000000000..6fc687335
--- /dev/null
+++ b/packages/testkit-backend/src/controller/index.js
@@ -0,0 +1,15 @@
+import Controller from './interface'
+import LocalController from './local'
+import RemoteController from './remote'
+
+/**
+ * Controllers are pieces of code responsible for redirecting requests to the correct handler.
+ *
+ * {@link LocalController} delegates the requests to be handled by local handlers.
+ * {@link RemoteController} delegates the requests to be handled by remote clients by forwarding the requests over websockets.
+ */
+export default Controller
+export {
+ LocalController,
+ RemoteController
+}
diff --git a/packages/testkit-backend/src/controller/interface.js b/packages/testkit-backend/src/controller/interface.js
new file mode 100644
index 000000000..3de0cb961
--- /dev/null
+++ b/packages/testkit-backend/src/controller/interface.js
@@ -0,0 +1,30 @@
+import { EventEmitter } from 'events'
+
+/**
+ * Controller is the unit responsible for redirecting the requests to the correct handler and managing the
+ * creation and destruction of the request contexts.
+ *
+ * @event response Event triggered whith response to the request handled.
+ */
+export default class Controller extends EventEmitter {
+
+ start () {
+
+ }
+
+ stop () {
+
+ }
+
+ openContext (contextId) {
+ throw new Error('not implemented')
+ }
+
+ closeContext (contextId) {
+ throw new Error('not implemented')
+ }
+
+ handle(contextId, request) {
+ throw new Error('not implemented')
+ }
+}
diff --git a/packages/testkit-backend/src/controller/local.js b/packages/testkit-backend/src/controller/local.js
new file mode 100644
index 000000000..aed4a4a80
--- /dev/null
+++ b/packages/testkit-backend/src/controller/local.js
@@ -0,0 +1,70 @@
+import Context from '../context'
+import Controller from './interface'
+
+
+/**
+ * Local controller handles the requests locally by redirecting them to the correct request handler/service.
+ *
+ * This controller is used when testing browser and locally.
+ */
+export default class LocalController extends Controller {
+
+ constructor(requestHandlers = {}) {
+ super()
+ this._requestHandlers = requestHandlers
+ this._contexts = new Map()
+ }
+
+ openContext (contextId) {
+ this._contexts.set(contextId, new Context())
+ }
+
+ closeContext (contextId) {
+ this._contexts.delete(contextId)
+ }
+
+ handle (contextId, { name, data }) {
+ if (!this._contexts.has(contextId)) {
+ throw new Error(`Context ${contextId} does not exist`)
+ } else if (!(name in this._requestHandlers)) {
+ console.log('Unknown request: ' + name)
+ console.log(stringify(data))
+ throw new Error(`Unknown request: ${name}`)
+ }
+
+ this._requestHandlers[name](this._contexts.get(contextId), data, {
+ writeResponse: (name, data) => this._writeResponse(contextId, name, data),
+ writeError: (e) => this._writeError(contextId, e),
+ writeBackendError: (msg) => this._writeBackendError(contextId, msg)
+ })
+
+ }
+
+ _writeResponse (contextId, name, data) {
+ console.log('> writing response', name, data)
+ let response = {
+ name: name,
+ data: data
+ }
+
+ this.emit('response', { contextId, response })
+ }
+
+ _writeBackendError (contextId, msg) {
+ this._writeResponse(contextId, 'BackendError', { msg: msg })
+ }
+
+ _writeError (contextId, e) {
+ if (e.name) {
+ const id = this._contexts.get(contextId).addError(e)
+ this._writeResponse(contextId, 'DriverError', {
+ id,
+ msg: e.message + ' (' + e.code + ')',
+ code: e.code
+ })
+ return
+ }
+ this._writeBackendError(contextId, e)
+ }
+
+}
diff --git a/packages/testkit-backend/src/controller/remote.js b/packages/testkit-backend/src/controller/remote.js
new file mode 100644
index 000000000..fc13fedf1
--- /dev/null
+++ b/packages/testkit-backend/src/controller/remote.js
@@ -0,0 +1,138 @@
+import Controller from "./interface"
+import { WebSocketServer } from "ws"
+import { createServer } from "http"
+import { Server } from "node-static"
+
+/**
+ * RemoteController handles the requests by sending them a remote client.
+ *
+ * This controller requires a client to be connected. Otherwise, it will reply with a BackendError
+ * to every incoming request.
+ *
+ * This controller can only be used in Node since it depends on {@link createServer}, {@link WebSocketServer} and {@link Server}
+ */
+export default class RemoteController extends Controller {
+ constructor(port) {
+ super()
+ this._staticServer = new Server('./public')
+ this._port = port
+ this._wss = null
+ this._ws = null
+ this._http = null
+ }
+
+ start () {
+ if (!this._http) {
+ this._http = createServer(safeRun((request, response) => {
+ request.addListener('end', safeRun(() => {
+ this._staticServer.serve(request, response)
+ })).resume()
+ }))
+
+ this._http.listen(this._port)
+ }
+ if (!this._wss) {
+ this._wss = new WebSocketServer({ server: this._http })
+ this._wss.on('connection', safeRun( ws => this._handleClientConnection(ws)))
+ this._wss.on('error', safeRun(error => {
+ console.error('[RemoteController] Server error', error)
+ }))
+ }
+
+ }
+
+ stop () {
+ if (this._ws) {
+ this._ws.close()
+ this._ws = null
+ }
+
+ if(this._wss) {
+ this._wss.close()
+ this._wss = null
+ }
+
+ if (this._http) {
+ this._http.close()
+ this._http = null
+ }
+ }
+
+ openContext (contextId) {
+ this._forwardToConnectedClient('contextOpen', contextId, { contextId })
+ }
+
+ closeContext (contextId) {
+ this._forwardToConnectedClient('contextClose', contextId, { contextId })
+ }
+
+ handle (contextId, request) {
+ this._forwardToConnectedClient('request', contextId, request)
+ }
+
+ _handleClientConnection (ws) {
+ if (this._ws) {
+ console.warn('[RemoteController] Client socket already exists, new connection will be discarded')
+ return
+ }
+ console.log('[RemoteController] Registering client')
+
+ this._ws = ws
+ this._ws.on('message', safeRun(buffer => {
+ const message = JSON.parse(buffer.toString())
+ console.debug('[RemoteController] Received messsage', message)
+ const { contextId, response } = message
+ this._writeResponse(contextId, response)
+ }))
+
+ this._ws.on('close', () => {
+ console.log('[RemoteController] Client connection closed')
+ this._ws = null
+ })
+
+ this._ws.on('error', safeRun(error => {
+ console.error('[RemoteController] Client connection error', error)
+ }))
+
+ console.log('[RemoteController] Client registred')
+ }
+
+ _forwardToConnectedClient (messageType, contextId, data) {
+ if (this._ws) {
+ const message = {
+ messageType,
+ contextId,
+ data
+ }
+
+ console.info(`[RemoteController] Sending message`, message)
+ return this._ws.send(JSON.stringify(message))
+ }
+ console.error('[RemoteController] There is no client connected')
+ this._writeBackendError(contextId, 'No testkit-backend client connected')
+ }
+
+ _writeResponse (contextId, response) {
+ console.log('> writing response', response)
+
+ this.emit('response', { contextId, response })
+ }
+
+ _writeBackendError (contextId, msg) {
+ this._writeResponse(contextId, { name: 'BackendError', data: { msg: msg } })
+ }
+
+}
+
+
+function safeRun (func) {
+ return function () {
+ const args = [...arguments]
+ try {
+ return func.apply(null, args)
+ } catch (error) {
+ console.error(`Error in function '${func.name}' called with arguments: ${JSON.stringify(args)}.`, error)
+ throw error
+ }
+ }
+}
diff --git a/packages/testkit-backend/src/index.js b/packages/testkit-backend/src/index.js
new file mode 100644
index 000000000..e4f3928f7
--- /dev/null
+++ b/packages/testkit-backend/src/index.js
@@ -0,0 +1,46 @@
+import Backend from './backend'
+import { SocketChannel, WebSocketChannel } from './channel'
+import { LocalController, RemoteController } from './controller'
+import * as REQUEST_HANDLERS from './request-handlers'
+
+/**
+ * Responsible for configure and run the backend server.
+ */
+function main( ) {
+ const testEnviroment = process.env.TEST_ENVIRONMENT || 'LOCAL'
+ const channelType = process.env.CHANNEL_TYPE || 'SOCKET'
+ const backendPort = process.env.BACKEND_PORT || 9876
+ const webserverPort = process.env.WEB_SERVER_PORT || 8000
+
+ const newChannel = () => {
+ if ( channelType.toUpperCase() === 'WEBSOCKET' ) {
+ return new WebSocketChannel(new URL(`ws://localhost:${backendPort}`))
+
+ }
+ return new SocketChannel(backendPort)
+ }
+
+ const newController = () => {
+ if ( testEnviroment.toUpperCase() === 'REMOTE' ) {
+ return new RemoteController(webserverPort)
+ }
+ return new LocalController(REQUEST_HANDLERS)
+ }
+
+ const backend = new Backend(newController, newChannel)
+
+ backend.start()
+
+ if (process.on) {
+ // cleaning up
+ process.on('exit', backend.stop.bind(backend));
+
+ // Capturing signals
+ process.on('SIGINT', process.exit.bind(process));
+ process.on('SIGUSR1', process.exit.bind(process));
+ process.on('SIGUSR2', process.exit.bind(process));
+ process.on('uncaughtException', process.exit.bind(process));
+ }
+}
+
+main()
diff --git a/packages/testkit-backend/src/main.js b/packages/testkit-backend/src/main.js
deleted file mode 100644
index abf0315bf..000000000
--- a/packages/testkit-backend/src/main.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import net from 'net'
-import readline from 'readline'
-import Context from './context.js'
-import * as requestHandlers from './request-handlers.js'
-
-class Backend {
- constructor ({ writer }) {
- console.log('Backend connected')
- this._inRequest = false
- this._request = ''
- // Event handlers need to be bound to this instance
- this.onLine = this.onLine.bind(this)
- this._writer = writer
- this._context = new Context()
- }
-
- // Called whenever a new line is received.
- onLine (line) {
- switch (line) {
- case '#request begin':
- if (this._inRequest) {
- throw new Error('Already in request')
- }
- this._inRequest = true
- break
- case '#request end':
- if (!this._inRequest) {
- throw new Error('End while not in request')
- }
- try {
- this._handleRequest(this._request)
- } catch (e) {
- this._writeBackendError(e)
- }
- this._request = ''
- this._inRequest = false
- break
- default:
- if (!this._inRequest) {
- throw new Error('Line while not in request')
- }
- this._request += line
- break
- }
- }
-
- _handleRequest (request) {
- request = JSON.parse(request)
- const { name, data } = request
- console.log('> Got request ' + name, data)
-
- if (name in requestHandlers) {
- requestHandlers[name](this._context, data, {
- writeResponse: this._writeResponse.bind(this),
- writeError: this._writeError.bind(this),
- writeBackendError: this._writeBackendError.bind(this)
- })
- return
- }
-
- this._writeBackendError('Unknown request: ' + name)
- console.log('Unknown request: ' + name)
- console.log(stringify(data))
- }
-
- _writeResponse (name, data) {
- console.log('> writing response', name, data)
- let response = {
- name: name,
- data: data
- }
- response = stringify(response)
- const lines = ['#response begin', response, '#response end']
- this._writer(lines)
- }
-
- _writeBackendError (msg) {
- this._writeResponse('BackendError', { msg: msg })
- }
-
- _writeError (e) {
- if (e.name) {
- const id = this._context.addError(e)
- this._writeResponse('DriverError', {
- id,
- msg: e.message + ' (' + e.code + ')',
- code: e.code
- })
- return
- }
- this._writeBackendError(e)
- }
-}
-
-function stringify (val) {
- return JSON.stringify(val, (_, value) =>
- typeof value === 'bigint' ? `${value}n` : value
- )
-}
-
-function server () {
- const server = net.createServer(conn => {
- const backend = new Backend({
- writer: lines => {
- const chunk = lines.join('\n') + '\n'
- conn.write(chunk, 'utf8', () => {})
- }
- })
- conn.setEncoding('utf8')
- const iface = readline.createInterface(conn, null)
- iface.on('line', backend.onLine)
- })
- server.listen(9876, () => {
- console.log('Listening')
- })
-}
-server()
diff --git a/packages/testkit-backend/src/request-handlers.js b/packages/testkit-backend/src/request-handlers.js
index 0b3064c7d..857bf4a5e 100644
--- a/packages/testkit-backend/src/request-handlers.js
+++ b/packages/testkit-backend/src/request-handlers.js
@@ -5,13 +5,16 @@ import { shouldRunTest } from './skipped-tests'
import tls from 'tls'
const SUPPORTED_TLS = (() => {
- const min = Number(tls.DEFAULT_MIN_VERSION.split('TLSv')[1])
- const max = Number(tls.DEFAULT_MAX_VERSION.split('TLSv')[1])
- const result = [];
- for (let version = min > 1 ? min : 1.1; version <= max; version = Number((version + 0.1).toFixed(1)) ) {
- result.push(`Feature:TLS:${version.toFixed(1)}`)
+ if (tls.DEFAULT_MAX_VERSION) {
+ const min = Number(tls.DEFAULT_MIN_VERSION.split('TLSv')[1])
+ const max = Number(tls.DEFAULT_MAX_VERSION.split('TLSv')[1])
+ const result = [];
+ for (let version = min > 1 ? min : 1.1; version <= max; version = Number((version + 0.1).toFixed(1)) ) {
+ result.push(`Feature:TLS:${version.toFixed(1)}`)
+ }
+ return result;
}
- return result;
+ return [];
})();
export function NewDriver (context, data, { writeResponse }) {
diff --git a/testkit/backend.py b/testkit/backend.py
index 949022814..304f08a57 100644
--- a/testkit/backend.py
+++ b/testkit/backend.py
@@ -3,8 +3,28 @@
Assumes driver and backend has been built.
Responsible for starting the test backend.
"""
-from common import run_in_driver_repo
+from common import (
+ open_proccess_in_driver_repo,
+ is_browser,
+)
import os
+import time
if __name__ == "__main__":
- run_in_driver_repo(["npm", "run", "start-testkit-backend"], env=os.environ)
+ print("starting backend")
+ if is_browser():
+ print("Testkit should test browser")
+ os.environ["TEST_ENVIRONMENT"] = "REMOTE"
+
+ print("npm run start-testkit-backend")
+ with open_proccess_in_driver_repo([
+ "npm", "run", "start-testkit-backend"
+ ], env=os.environ) as backend:
+ if (is_browser()):
+ time.sleep(5)
+ print("openning firefox")
+ with open_proccess_in_driver_repo([
+ "firefox", "-headless", "http://localhost:8000"
+ ]) as firefox:
+ firefox.wait()
+ backend.wait()
diff --git a/testkit/common.py b/testkit/common.py
index 611d84c11..a6e58adff 100644
--- a/testkit/common.py
+++ b/testkit/common.py
@@ -3,15 +3,22 @@
"""
import subprocess
import os
+import sys
DRIVER_REPO = "/home/driver/repo/"
-def run(args, env=None, cwd=None):
+def is_enabled(value):
+ return value.lower() in (
+ "y", "yes", "t", "true", "1", "on"
+ )
+
+
+def run(args, env=None, cwd=None, check=True):
subprocess.run(
- args, universal_newlines=True, stderr=subprocess.STDOUT,
- check=True, env=env, cwd=cwd)
+ args, universal_newlines=True, stderr=sys.stderr, stdout=sys.stdout,
+ check=check, env=env, cwd=cwd)
def run_in(cwd):
@@ -20,9 +27,18 @@ def _runIn(args, env=None):
return _runIn
-def run_in_driver_repo(args, env=None):
- return run(args, env, DRIVER_REPO)
+def run_in_driver_repo(args, env=None, check=True):
+ return run(args, env, DRIVER_REPO, check=check)
+
+
+def open_proccess_in_driver_repo(args, env=None):
+ return subprocess.Popen(args, cwd=DRIVER_REPO, env=env, stderr=sys.stderr,
+ stdout=sys.stdout)
def is_lite():
- return os.environ.get("TEST_DRIVER_LITE", "False").upper() in ["TRUE", "1"]
+ return is_enabled(os.environ.get("TEST_DRIVER_LITE", "false"))
+
+
+def is_browser():
+ return is_enabled(os.environ.get("TEST_DRIVER_BROWSER", "false"))
diff --git a/testkit/integration.py b/testkit/integration.py
index 3c1b3465e..1af24054e 100644
--- a/testkit/integration.py
+++ b/testkit/integration.py
@@ -1,13 +1,10 @@
import os
-from common import run_in_driver_repo, is_lite
-
-
-def should_test_browser():
- return os.environ.get("TEST_DRIVER_SKIP_BROWSER", "false").lower() not in (
- "y", "yes", "t", "true", "1", "on"
- )
-
+from common import (
+ is_browser,
+ is_lite,
+ run_in_driver_repo,
+)
if __name__ == "__main__":
os.environ["TEST_NEO4J_IPV6_ENABLED"] = "False"
@@ -17,7 +14,7 @@ def should_test_browser():
else:
ignore = "--ignore=neo4j-driver-lite"
- run_in_driver_repo(["npm", "run", "test::integration", "--", ignore])
-
- if should_test_browser():
+ if is_browser():
run_in_driver_repo(["npm", "run", "test::browser", "--", ignore])
+ else:
+ run_in_driver_repo(["npm", "run", "test::integration", "--", ignore])
diff --git a/testkit/stress.py b/testkit/stress.py
index 77fac8dab..7481e6bae 100644
--- a/testkit/stress.py
+++ b/testkit/stress.py
@@ -1,5 +1,9 @@
import os
-from common import run_in_driver_repo, is_lite
+from common import (
+ is_browser,
+ is_lite,
+ run_in_driver_repo,
+)
if __name__ == "__main__":
@@ -7,9 +11,10 @@
os.environ["RUNNING_TIME_IN_SECONDS"] = \
os.environ.get("TEST_NEO4J_STRESS_DURATION", 0)
- if is_lite():
- ignore = "--ignore=neo4j-driver"
- else:
- ignore = "--ignore=neo4j-driver-lite"
+ if not is_browser():
+ if is_lite():
+ ignore = "--ignore=neo4j-driver"
+ else:
+ ignore = "--ignore=neo4j-driver-lite"
- run_in_driver_repo(["npm", "run", "test::stress", "--", ignore])
+ run_in_driver_repo(["npm", "run", "test::stress", "--", ignore])