From 4cba03e53faa129bcfd4a50f803c5b0faf76d945 Mon Sep 17 00:00:00 2001 From: Muhammed Ajmal M <55492635+ajmalmohad@users.noreply.github.com> Date: Tue, 23 Jan 2024 22:31:27 +0530 Subject: [PATCH] feat(js-sandbox): add `pw.env.unset` method (#3677) Co-authored-by: jamesgeorge007 --- .../src/components/http/TestResult.vue | 7 + .../src/helpers/terndoc/ecma.json | 3 +- .../src/helpers/terndoc/pw-pre.json | 1 + .../src/helpers/terndoc/pw-test.json | 1 + .../src/__tests__/preRequest.spec.ts | 7 +- .../src/__tests__/testing/envs/unset.spec.ts | 243 ++++++++++++++++++ .../src/__tests__/testing/test-runner.spec.ts | 4 +- packages/hoppscotch-js-sandbox/src/utils.ts | 113 ++++---- 8 files changed, 328 insertions(+), 51 deletions(-) create mode 100644 packages/hoppscotch-js-sandbox/src/__tests__/testing/envs/unset.spec.ts diff --git a/packages/hoppscotch-common/src/components/http/TestResult.vue b/packages/hoppscotch-common/src/components/http/TestResult.vue index 24b491bc3..a21b1b287 100644 --- a/packages/hoppscotch-common/src/components/http/TestResult.vue +++ b/packages/hoppscotch-common/src/components/http/TestResult.vue @@ -79,6 +79,13 @@ status="updations" global /> + ?", - "set": "fn(value: ?)" + "set": "fn(value: ?)", + "unset": "fn(value: ?)" }, "Promise.prototype": { "catch": { diff --git a/packages/hoppscotch-common/src/helpers/terndoc/pw-pre.json b/packages/hoppscotch-common/src/helpers/terndoc/pw-pre.json index 8a70a6c35..2a34c1834 100644 --- a/packages/hoppscotch-common/src/helpers/terndoc/pw-pre.json +++ b/packages/hoppscotch-common/src/helpers/terndoc/pw-pre.json @@ -3,6 +3,7 @@ "pw": { "env": { "set": "fn(key: string, value: string)", + "unset": "fn(key: string)", "get": "fn(key: string) -> string", "getResolve": "fn(key: string) -> string", "resolve": "fn(value: string) -> string" diff --git a/packages/hoppscotch-common/src/helpers/terndoc/pw-test.json b/packages/hoppscotch-common/src/helpers/terndoc/pw-test.json index 21137a65a..3b5883555 100644 --- a/packages/hoppscotch-common/src/helpers/terndoc/pw-test.json +++ b/packages/hoppscotch-common/src/helpers/terndoc/pw-test.json @@ -22,6 +22,7 @@ }, "env": { "set": "fn(key: string, value: string)", + "unset": "fn(key: string)", "get": "fn(key: string) -> string", "getResolve": "fn(key: string) -> string", "resolve": "fn(value: string) -> string" diff --git a/packages/hoppscotch-js-sandbox/src/__tests__/preRequest.spec.ts b/packages/hoppscotch-js-sandbox/src/__tests__/preRequest.spec.ts index d3c3cc9cd..cf7ce824a 100644 --- a/packages/hoppscotch-js-sandbox/src/__tests__/preRequest.spec.ts +++ b/packages/hoppscotch-js-sandbox/src/__tests__/preRequest.spec.ts @@ -1,8 +1,9 @@ -import { runPreRequestScript } from "~/pre-request/node-vm" import "@relmify/jest-fp-ts" -describe("execPreRequestScript", () => { - test("returns the updated envirionment properly", () => { +import { runPreRequestScript } from "~/pre-request/node-vm" + +describe("runPreRequestScript", () => { + test("returns the updated environment properly", () => { return expect( runPreRequestScript( ` diff --git a/packages/hoppscotch-js-sandbox/src/__tests__/testing/envs/unset.spec.ts b/packages/hoppscotch-js-sandbox/src/__tests__/testing/envs/unset.spec.ts new file mode 100644 index 000000000..aeda66d71 --- /dev/null +++ b/packages/hoppscotch-js-sandbox/src/__tests__/testing/envs/unset.spec.ts @@ -0,0 +1,243 @@ +import * as TE from "fp-ts/TaskEither" +import { pipe } from "fp-ts/function" + +import { runTestScript } from "~/test-runner/node-vm" +import { TestResponse, TestResult } from "~/types" + +const fakeResponse: TestResponse = { + status: 200, + body: "hoi", + headers: [], +} + +const func = (script: string, envs: TestResult["envs"]) => + pipe( + runTestScript(script, envs, fakeResponse), + TE.map((x) => x.envs) + ) + +const funcTest = (script: string, envs: TestResult["envs"]) => + pipe( + runTestScript(script, envs, fakeResponse), + TE.map((x) => x.tests) + ) + +describe("pw.env.unset", () => { + test("removes the variable set in selected environment correctly", () => { + return expect( + func( + ` + pw.env.unset("baseUrl") + `, + { + global: [], + selected: [ + { + key: "baseUrl", + value: "https://echo.hoppscotch.io", + }, + ], + } + )() + ).resolves.toEqualRight( + expect.objectContaining({ + selected: [], + }) + ) + }) + + test("removes the variable set in global environment correctly", () => { + return expect( + func( + ` + pw.env.unset("baseUrl") + `, + { + global: [ + { + key: "baseUrl", + value: "https://echo.hoppscotch.io", + }, + ], + selected: [], + } + )() + ).resolves.toEqualRight( + expect.objectContaining({ + global: [], + }) + ) + }) + + test("removes the variable from selected environment if the entry is present in both selected and global environments", () => { + return expect( + func( + ` + pw.env.unset("baseUrl") + `, + { + global: [ + { + key: "baseUrl", + value: "https://httpbin.org", + }, + ], + selected: [ + { + key: "baseUrl", + value: "https://echo.hoppscotch.io", + }, + ], + } + )() + ).resolves.toEqualRight( + expect.objectContaining({ + global: [ + { + key: "baseUrl", + value: "https://httpbin.org", + }, + ], + selected: [], + }) + ) + }) + + test("removes the initial occurrence of an entry if duplicate entries exist in the selected environment", () => { + return expect( + func( + ` + pw.env.unset("baseUrl") + `, + { + global: [ + { + key: "baseUrl", + value: "https://echo.hoppscotch.io", + }, + ], + selected: [ + { + key: "baseUrl", + value: "https://httpbin.org", + }, + { + key: "baseUrl", + value: "https://echo.hoppscotch.io", + }, + ], + } + )() + ).resolves.toEqualRight( + expect.objectContaining({ + global: [ + { + key: "baseUrl", + value: "https://echo.hoppscotch.io", + }, + ], + selected: [ + { + key: "baseUrl", + value: "https://echo.hoppscotch.io", + }, + ], + }) + ) + }) + + test("removes the initial occurrence of an entry if duplicate entries exist in the global environment", () => { + return expect( + func( + ` + pw.env.unset("baseUrl") + `, + { + global: [ + { + key: "baseUrl", + value: "https://httpbin.org/", + }, + { + key: "baseUrl", + value: "https://echo.hoppscotch.io", + }, + ], + selected: [], + } + )() + ).resolves.toEqualRight( + expect.objectContaining({ + global: [ + { + key: "baseUrl", + value: "https://echo.hoppscotch.io", + }, + ], + selected: [], + }) + ) + }) + + test("no change if attempting to delete non-existent keys", () => { + return expect( + func( + ` + pw.env.unset("baseUrl") + `, + { + global: [], + selected: [], + } + )() + ).resolves.toEqualRight( + expect.objectContaining({ + global: [], + selected: [], + }) + ) + }) + + test("keys should be a string", () => { + return expect( + func( + ` + pw.env.unset(5) + `, + { + global: [], + selected: [], + } + )() + ).resolves.toBeLeft() + }) + + test("set environment values are reflected in the script execution", () => { + return expect( + funcTest( + ` + pw.env.unset("baseUrl") + pw.expect(pw.env.get("baseUrl")).toBe(undefined) + `, + { + global: [], + selected: [ + { + key: "baseUrl", + value: "https://echo.hoppscotch.io", + }, + ], + } + )() + ).resolves.toEqualRight([ + expect.objectContaining({ + expectResults: [ + { + status: "pass", + message: "Expected 'undefined' to be 'undefined'", + }, + ], + }), + ]) + }) +}) diff --git a/packages/hoppscotch-js-sandbox/src/__tests__/testing/test-runner.spec.ts b/packages/hoppscotch-js-sandbox/src/__tests__/testing/test-runner.spec.ts index 234ab73e4..214ee7d6d 100644 --- a/packages/hoppscotch-js-sandbox/src/__tests__/testing/test-runner.spec.ts +++ b/packages/hoppscotch-js-sandbox/src/__tests__/testing/test-runner.spec.ts @@ -16,8 +16,8 @@ const func = (script: string, res: TestResponse) => TE.map((x) => x.tests) ) -describe("execTestScript function behavior", () => { - test("returns a resolved promise for a valid test scripts with all green", () => { +describe("runTestScript", () => { + test("returns a resolved promise for a valid test script with all green", () => { return expect( func( ` diff --git a/packages/hoppscotch-js-sandbox/src/utils.ts b/packages/hoppscotch-js-sandbox/src/utils.ts index 84dc59ff1..f7920ff88 100644 --- a/packages/hoppscotch-js-sandbox/src/utils.ts +++ b/packages/hoppscotch-js-sandbox/src/utils.ts @@ -18,6 +18,63 @@ const getEnv = (envName: string, envs: TestResult["envs"]) => { ) } +const findEnvIndex = ( + envName: string, + envList: SelectedEnvItem[] | GlobalEnvItem[] +): number => { + return envList.findIndex( + (envItem: SelectedEnvItem) => envItem.key === envName + ) +} + +const setEnv = ( + envName: string, + envValue: string, + envs: TestResult["envs"] +): TestResult["envs"] => { + const { global, selected } = envs + + const indexInSelected = findEnvIndex(envName, selected) + const indexInGlobal = findEnvIndex(envName, global) + + if (indexInSelected >= 0) { + selected[indexInSelected].value = envValue + } else if (indexInGlobal >= 0) { + global[indexInGlobal].value = envValue + } else { + selected.push({ + key: envName, + value: envValue, + }) + } + + return { + global, + selected, + } +} + +const unsetEnv = ( + envName: string, + envs: TestResult["envs"] +): TestResult["envs"] => { + const { global, selected } = envs + + const indexInSelected = findEnvIndex(envName, selected) + const indexInGlobal = findEnvIndex(envName, global) + + if (indexInSelected >= 0) { + selected.splice(indexInSelected, 1) + } else if (indexInGlobal >= 0) { + global.splice(indexInGlobal, 1) + } + + return { + global, + selected, + } +} + // Compiles shared scripting API methods for use in both pre and post request scripts const getSharedMethods = (envs: TestResult["envs"]) => { let updatedEnvs = envs @@ -79,6 +136,16 @@ const getSharedMethods = (envs: TestResult["envs"]) => { return undefined } + const envUnsetFn = (key: any) => { + if (typeof key !== "string") { + throw new Error("Expected key to be a string") + } + + updatedEnvs = unsetEnv(key, updatedEnvs) + + return undefined + } + const envResolveFn = (value: any) => { if (typeof value !== "string") { throw new Error("Expected value to be a string") @@ -101,6 +168,7 @@ const getSharedMethods = (envs: TestResult["envs"]) => { get: envGetFn, getResolve: envGetResolveFn, set: envSetFn, + unset: envUnsetFn, resolve: envResolveFn, }, }, @@ -108,51 +176,6 @@ const getSharedMethods = (envs: TestResult["envs"]) => { } } -const setEnv = ( - envName: string, - envValue: string, - envs: TestResult["envs"] -): TestResult["envs"] => { - const { global, selected } = envs - - const indexInSelected = selected.findIndex( - (x: SelectedEnvItem) => x.key === envName - ) - - // Found the match in selected - if (indexInSelected >= 0) { - selected[indexInSelected].value = envValue - - return { - global, - selected, - } - } - - const indexInGlobal = global.findIndex((x: GlobalEnvItem) => x.key == envName) - - // Found a match in globals - if (indexInGlobal >= 0) { - global[indexInGlobal].value = envValue - - return { - global, - selected, - } - } - - // Didn't find in both places, create a new variable in selected - selected.push({ - key: envName, - value: envValue, - }) - - return { - global, - selected, - } -} - export function preventCyclicObjects( obj: Record ): E.Left | E.Right> {