Browse Source

refactor(scripting-revamp): migrate `js-sandbox` to `web worker/Node vm` based implementation (#3619)

James George 1 year ago
parent
commit
bdfa14fa54

+ 1 - 1
packages/hoppscotch-cli/jest.config.ts

@@ -147,7 +147,7 @@ module.exports = {
   // The glob patterns Jest uses to detect test files
   testMatch: [
     // "**/__tests__/**/*.[jt]s?(x)",
-    "**/src/__tests__/**/*.*.ts",
+    "**/src/__tests__/commands/**/*.*.ts",
   ],
 
   // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped

+ 2 - 1
packages/hoppscotch-cli/package.json

@@ -19,8 +19,9 @@
     "debugger": "node debugger.js 9999",
     "prepublish": "pnpm exec tsup",
     "prettier-format": "prettier --config .prettierrc 'src/**/*.ts' --write",
+    "test": "pnpm run build && jest && rm -rf dist",
     "do-typecheck": "pnpm exec tsc --noEmit",
-    "test": "pnpm run build && jest && rm -rf dist"
+    "do-test": "pnpm test"
   },
   "keywords": [
     "cli",

+ 2 - 3
packages/hoppscotch-cli/src/__tests__/commands/test.spec.ts

@@ -28,7 +28,7 @@ describe("Test 'hopp test <file>' command:", () => {
 
     expect(out).toBe<HoppErrorCode>("UNKNOWN_ERROR");
   });
-  
+
   test("Malformed collection file.", async () => {
     const cmd = `node ./bin/hopp test ${getTestJsonFilePath(
       "malformed-collection2.json"
@@ -106,7 +106,7 @@ describe("Test 'hopp test <file> --env <file>' command:", () => {
     const TESTS_PATH = getTestJsonFilePath("env-flag-tests.json");
     const ENV_PATH = getTestJsonFilePath("env-flag-envs.json");
     const cmd = `node ./bin/hopp test ${TESTS_PATH} --env ${ENV_PATH}`;
-    const { error } = await execAsync(cmd);
+    const { error, stdout } = await execAsync(cmd);
 
     expect(error).toBeNull();
   });
@@ -129,7 +129,6 @@ describe("Test 'hopp test <file> --delay <delay_in_ms>' command:", () => {
     const cmd = `${VALID_TEST_CMD} --delay 'NaN'`;
     const { stderr } = await execAsync(cmd);
     const out = getErrorCode(stderr);
-    console.log("invalid value thing", out)
     expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
   });
 

+ 0 - 1
packages/hoppscotch-cli/src/__tests__/samples/env-flag-envs.json

@@ -1,7 +1,6 @@
 {
   "URL": "https://echo.hoppscotch.io",
   "HOST": "echo.hoppscotch.io",
-  "X-COUNTRY": "IN",
   "BODY_VALUE": "body_value",
   "BODY_KEY": "body_key"
 }

+ 1 - 1
packages/hoppscotch-cli/src/__tests__/samples/env-flag-tests.json

@@ -12,7 +12,7 @@
       "method": "POST",
       "auth": { "authType": "none", "authActive": true },
       "preRequestScript": "",
-      "testScript": "const HOST = pw.env.get(\"HOST\");\nconst UNSET_ENV = pw.env.get(\"UNSET_ENV\");\nconst EXPECTED_URL = \"https://echo.hoppscotch.io\";\nconst URL = pw.env.get(\"URL\");\nconst X_COUNTRY = pw.env.get(\"X-COUNTRY\");\nconst BODY_VALUE = pw.env.get(\"BODY_VALUE\");\n\n// Check JSON response property\npw.test(\"Check headers properties.\", ()=> {\n    pw.expect(pw.response.body.headers.host).toBe(HOST);\n\t   pw.expect(pw.response.body.headers[\"x-country\"]).toBe(X_COUNTRY);  \n});\n\npw.test(\"Check data properties.\", () => {\n\tconst DATA = pw.response.body.data;\n  \n    pw.expect(DATA).toBeType(\"string\");\n    pw.expect(JSON.parse(DATA).body_key).toBe(BODY_VALUE);\n});\n\npw.test(\"Check request URL.\", () => {\n  pw.expect(URL).toBe(EXPECTED_URL);\n})\n\npw.test(\"Check unset ENV.\", () => {\n  pw.expect(UNSET_ENV).toBeType(\"undefined\");\n})",
+      "testScript": "const HOST = pw.env.get(\"HOST\");\nconst UNSET_ENV = pw.env.get(\"UNSET_ENV\");\nconst EXPECTED_URL = \"https://echo.hoppscotch.io\";\nconst URL = pw.env.get(\"URL\");\nconst BODY_VALUE = pw.env.get(\"BODY_VALUE\");\n\n// Check JSON response property\npw.test(\"Check headers properties.\", ()=> {\n    pw.expect(pw.response.body.headers.host).toBe(HOST);\n});\n\npw.test(\"Check data properties.\", () => {\n\tconst DATA = pw.response.body.data;\n  \n    pw.expect(DATA).toBeType(\"string\");\n    pw.expect(JSON.parse(DATA).body_key).toBe(BODY_VALUE);\n});\n\npw.test(\"Check request URL.\", () => {\n  pw.expect(URL).toBe(EXPECTED_URL);\n})\n\npw.test(\"Check unset ENV.\", () => {\n  pw.expect(UNSET_ENV).toBeType(\"undefined\");\n})",
       "body": {
         "contentType": "application/json",
         "body": "{\n  \"<<BODY_KEY>>\":\"<<BODY_VALUE>>\"\n}"

+ 10 - 9
packages/hoppscotch-cli/src/utils/pre-request.ts

@@ -6,23 +6,24 @@ import {
   parseTemplateString,
   parseTemplateStringE,
 } from "@hoppscotch/data";
-import { runPreRequestScript } from "@hoppscotch/js-sandbox";
-import { flow, pipe } from "fp-ts/function";
-import * as TE from "fp-ts/TaskEither";
-import * as E from "fp-ts/Either";
-import * as RA from "fp-ts/ReadonlyArray";
+import { runPreRequestScript } from "@hoppscotch/js-sandbox/node";
 import * as A from "fp-ts/Array";
+import * as E from "fp-ts/Either";
 import * as O from "fp-ts/Option";
+import * as RA from "fp-ts/ReadonlyArray";
+import * as TE from "fp-ts/TaskEither";
+import { flow, pipe } from "fp-ts/function";
 import * as S from "fp-ts/string";
 import qs from "qs";
+
 import { EffectiveHoppRESTRequest } from "../interfaces/request";
-import { error, HoppCLIError } from "../types/errors";
+import { HoppCLIError, error } from "../types/errors";
 import { HoppEnvs } from "../types/request";
+import { PreRequestMetrics } from "../types/response";
 import { isHoppCLIError } from "./checks";
-import { tupleToRecord, arraySort, arrayFlatMap } from "./functions/array";
-import { toFormData } from "./mutators";
+import { arrayFlatMap, arraySort, tupleToRecord } from "./functions/array";
 import { getEffectiveFinalMetaData } from "./getters";
-import { PreRequestMetrics } from "../types/response";
+import { toFormData } from "./mutators";
 
 /**
  * Runs pre-request-script runner over given request which extracts set ENVs and

+ 9 - 7
packages/hoppscotch-cli/src/utils/test.ts

@@ -1,17 +1,19 @@
 import { HoppRESTRequest } from "@hoppscotch/data";
-import { execTestScript, TestDescriptor } from "@hoppscotch/js-sandbox";
-import { hrtime } from "process";
-import { flow, pipe } from "fp-ts/function";
-import * as RA from "fp-ts/ReadonlyArray";
+import { TestDescriptor } from "@hoppscotch/js-sandbox";
+import { runTestScript } from "@hoppscotch/js-sandbox/node";
 import * as A from "fp-ts/Array";
-import * as TE from "fp-ts/TaskEither";
+import * as RA from "fp-ts/ReadonlyArray";
 import * as T from "fp-ts/Task";
+import * as TE from "fp-ts/TaskEither";
+import { flow, pipe } from "fp-ts/function";
+import { hrtime } from "process";
+
 import {
   RequestRunnerResponse,
   TestReport,
   TestScriptParams,
 } from "../interfaces/response";
-import { error, HoppCLIError } from "../types/errors";
+import { HoppCLIError, error } from "../types/errors";
 import { HoppEnvs } from "../types/request";
 import { ExpectResult, TestMetrics, TestRunnerRes } from "../types/response";
 import { getDurationInSeconds } from "./getters";
@@ -36,7 +38,7 @@ export const testRunner = (
       pipe(
         TE.of(testScriptData),
         TE.chain(({ testScript, response, envs }) =>
-          execTestScript(testScript, envs, response)
+          runTestScript(testScript, envs, response)
         )
       )
     ),

+ 21 - 23
packages/hoppscotch-common/src/helpers/RequestRunner.ts

@@ -1,26 +1,15 @@
-import { Observable, Subject } from "rxjs"
-import { filter } from "rxjs/operators"
-import { flow, pipe } from "fp-ts/function"
-import * as O from "fp-ts/Option"
-import * as A from "fp-ts/Array"
 import { Environment } from "@hoppscotch/data"
-import {
-  SandboxTestResult,
-  runTestScript,
-  TestDescriptor,
-} from "@hoppscotch/js-sandbox"
+import { SandboxTestResult, TestDescriptor } from "@hoppscotch/js-sandbox"
+import { runTestScript } from "@hoppscotch/js-sandbox/web"
+import * as A from "fp-ts/Array"
 import * as E from "fp-ts/Either"
+import * as O from "fp-ts/Option"
+import { flow, pipe } from "fp-ts/function"
 import { cloneDeep } from "lodash-es"
-import {
-  getCombinedEnvVariables,
-  getFinalEnvsFromPreRequest,
-} from "./preRequest"
-import { getEffectiveRESTRequest } from "./utils/EffectiveURL"
-import { HoppRESTResponse } from "./types/HoppRESTResponse"
-import { createRESTNetworkRequestStream } from "./network"
-import { HoppTestData, HoppTestResult } from "./types/HoppTestResult"
-import { isJSONContentType } from "./utils/contenttypes"
-import { updateTeamEnvironment } from "./backend/mutations/TeamEnvironment"
+import { Observable, Subject } from "rxjs"
+import { filter } from "rxjs/operators"
+import { Ref } from "vue"
+
 import {
   environmentsStore,
   getCurrentEnvironment,
@@ -29,9 +18,18 @@ import {
   setGlobalEnvVariables,
   updateEnvironment,
 } from "~/newstore/environments"
-import { Ref } from "vue"
 import { HoppTab } from "~/services/tab"
+import { updateTeamEnvironment } from "./backend/mutations/TeamEnvironment"
+import { createRESTNetworkRequestStream } from "./network"
+import {
+  getCombinedEnvVariables,
+  getFinalEnvsFromPreRequest,
+} from "./preRequest"
 import { HoppRESTDocument } from "./rest/document"
+import { HoppRESTResponse } from "./types/HoppRESTResponse"
+import { HoppTestData, HoppTestResult } from "./types/HoppTestResult"
+import { getEffectiveRESTRequest } from "./utils/EffectiveURL"
+import { isJSONContentType } from "./utils/contenttypes"
 
 const getTestableBody = (
   res: HoppRESTResponse & { type: "success" | "fail" }
@@ -89,7 +87,7 @@ export function runRESTRequest$(
   const res = getFinalEnvsFromPreRequest(
     tab.value.document.request.preRequestScript,
     getCombinedEnvVariables()
-  )().then((envs) => {
+  ).then((envs) => {
     if (cancelCalled) return E.left("cancellation" as const)
 
     if (E.isLeft(envs)) {
@@ -125,7 +123,7 @@ export function runRESTRequest$(
               body: getTestableBody(res),
               headers: res.headers,
             }
-          )()
+          )
 
           if (E.isRight(runResult)) {
             tab.value.document.testResults = translateToSandboxTestResults(

+ 6 - 2
packages/hoppscotch-common/src/helpers/preRequest.ts

@@ -1,10 +1,13 @@
-import { runPreRequestScript } from "@hoppscotch/js-sandbox"
+import * as E from "fp-ts/Either"
+import { runPreRequestScript } from "@hoppscotch/js-sandbox/web"
 import { Environment } from "@hoppscotch/data"
 import { cloneDeep } from "lodash-es"
+
 import {
   getCurrentEnvironment,
   getGlobalVariables,
 } from "~/newstore/environments"
+import { TestResult } from "@hoppscotch/js-sandbox"
 
 export const getCombinedEnvVariables = () => ({
   global: cloneDeep(getGlobalVariables()),
@@ -17,4 +20,5 @@ export const getFinalEnvsFromPreRequest = (
     global: Environment["variables"]
     selected: Environment["variables"]
   }
-) => runPreRequestScript(script, envs)
+): Promise<E.Either<string, TestResult["envs"]>> =>
+  runPreRequestScript(script, envs)

+ 2 - 0
packages/hoppscotch-js-sandbox/index.d.ts

@@ -0,0 +1,2 @@
+export { default } from "./dist/types/index.d.ts"
+export * from "./dist/types/index.d.ts"

Some files were not shown because too many files changed in this diff