diff --git a/packages/hoppscotch-cli/README.md b/packages/hoppscotch-cli/README.md index 28a1efdb..aa9f0ec0 100644 --- a/packages/hoppscotch-cli/README.md +++ b/packages/hoppscotch-cli/README.md @@ -19,54 +19,74 @@ hopp [options or commands] arguments ## **Command Descriptions:** -1. #### **`hopp -v` / `hopp --ver`** +1. #### **`hopp -v` / `hopp --ver`** - - Prints out the current version of the Hoppscotch CLI + - Prints out the current version of the Hoppscotch CLI -2. #### **`hopp -h` / `hopp --help`** +2. #### **`hopp -h` / `hopp --help`** - - Displays the help text + - Displays the help text -3. #### **`hopp test [options] `** +3. #### **`hopp test [options] `** - - Interactive CLI to accept Hoppscotch collection JSON path - - Parses the collection JSON and executes each requests - - Executes pre-request script. - - Outputs the response of each request. - - Executes and outputs test-script response. + - Interactive CLI to accept Hoppscotch collection JSON path + - Parses the collection JSON and executes each requests + - Executes pre-request script. + - Outputs the response of each request. + - Executes and outputs test-script response. - #### Options: + #### Options: - ##### `-e ` / `--env ` + ##### `-e, --env ` - - Accepts path to env.json with contents in below format: + - Accepts path to env.json with contents in below format: - ```json - { - "ENV1": "value1", - "ENV2": "value2" - } - ``` + ```json + { + "ENV1": "value1", + "ENV2": "value2" + } + ``` - - You can now access those variables using `pw.env.get('')` + - You can now access those variables using `pw.env.get('')` - Taking the above example, `pw.env.get("ENV1")` will return `"value1"` + Taking the above example, `pw.env.get("ENV1")` will return `"value1"` - ##### `--iteration-count ` + #### `-d, --delay ` - - Accepts the number of iterations to run the collection + - Used to defer the execution of requests in a collection. - ##### `--iteration-data ` + #### `--token ` - - Accepts the path to a CSV file with contents in the below format: + - Expects a personal access token to be passed for establishing connection with your Hoppscotch account. - ```text - key1,key2,key3 - value1,value2,value3 - value4,value5,value6 - ``` + #### `--server ` - For every iteration the values will be replaced with the respective keys in the environment. For iteration 1 the value1,value2,value3 will be replaced and for iteration 2 value4,value5,value6 will be replaced and so on. + - URL of your self-hosted instance, if your collections are on a self-hosted instance. + + #### `--reporter-junit [path]` + + - Expects a file path to store the JUnit Report. + + ##### `--iteration-count ` + + - Accepts the number of iterations to run the collection + + ##### `--iteration-data ` + + - Accepts the path to a CSV file with contents in the below format: + + ```text + key1,key2,key3 + value1,value2,value3 + value4,value5,value6 + ``` + + For every iteration the values will be replaced with the respective keys in the environment. For iteration 1 the value1,value2,value3 will be replaced and for iteration 2 value4,value5,value6 will be replaced and so on. + + #### `--legacy-sandbox` + + - Opt out from the experimental scripting sandbox. ## Install diff --git a/packages/hoppscotch-cli/package.json b/packages/hoppscotch-cli/package.json index eb5e41cc..4de2985a 100644 --- a/packages/hoppscotch-cli/package.json +++ b/packages/hoppscotch-cli/package.json @@ -1,6 +1,6 @@ { "name": "@hoppscotch/cli", - "version": "0.21.0", + "version": "0.22.0", "description": "A CLI to run Hoppscotch test scripts in CI environments.", "homepage": "https://hoppscotch.io", "type": "module", diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/commands/__snapshots__/test.spec.ts.snap b/packages/hoppscotch-cli/src/__tests__/e2e/commands/__snapshots__/test.spec.ts.snap index 070d36bd..9c3e21c6 100644 --- a/packages/hoppscotch-cli/src/__tests__/e2e/commands/__snapshots__/test.spec.ts.snap +++ b/packages/hoppscotch-cli/src/__tests__/e2e/commands/__snapshots__/test.spec.ts.snap @@ -162,7 +162,7 @@ exports[`hopp test [options] > Test\`hopp test + TEST_SCRIPT_ERROR - Script execution failed: ReferenceError: 'status' is not defined]]> > Test\`hopp test + TEST_SCRIPT_ERROR - Script execution failed: ReferenceError: 'status' is not defined]]> { test("Invalid HoppCollection.", () => { return expect( - parseCollectionData( - "./src/__tests__/samples/malformed-collection2.json" - ) + parseCollectionData("./src/__tests__/samples/malformed-collection2.json") ).rejects.toMatchObject({ code: "MALFORMED_COLLECTION", }); diff --git a/packages/hoppscotch-cli/src/commands/test.ts b/packages/hoppscotch-cli/src/commands/test.ts index 3e40978c..52fec8bc 100644 --- a/packages/hoppscotch-cli/src/commands/test.ts +++ b/packages/hoppscotch-cli/src/commands/test.ts @@ -20,8 +20,14 @@ import { parseCollectionData } from "../utils/mutators"; export const test = (pathOrId: string, options: TestCmdOptions) => async () => { try { - const { delay, env, iterationCount, iterationData, reporterJunit } = - options; + const { + delay, + env, + iterationCount, + iterationData, + reporterJunit, + legacySandbox, + } = options; if ( iterationCount !== undefined && @@ -86,12 +92,15 @@ export const test = (pathOrId: string, options: TestCmdOptions) => async () => { .filter((item) => item.length > 0); } + const resolvedLegacySandbox = Boolean(legacySandbox); + const report = await collectionsRunner({ collections, envs, delay: resolvedDelay, iterationData: transformedIterationData, iterationCount, + legacySandbox: resolvedLegacySandbox, }); const hasSucceeded = collectionsRunnerResult(report, reporterJunit); diff --git a/packages/hoppscotch-cli/src/index.ts b/packages/hoppscotch-cli/src/index.ts index 7b92a47a..94d70ce3 100644 --- a/packages/hoppscotch-cli/src/index.ts +++ b/packages/hoppscotch-cli/src/index.ts @@ -78,6 +78,7 @@ program "--iteration-data ", "path to a CSV file for data-driven testing" ) + .option("--legacy-sandbox", "Opt out from the experimental scripting sandbox") .allowExcessArguments(false) .allowUnknownOption(false) .description("running hoppscotch collection.json file") diff --git a/packages/hoppscotch-cli/src/interfaces/response.ts b/packages/hoppscotch-cli/src/interfaces/response.ts index f85ed820..7c32e912 100644 --- a/packages/hoppscotch-cli/src/interfaces/response.ts +++ b/packages/hoppscotch-cli/src/interfaces/response.ts @@ -43,6 +43,7 @@ export interface TestScriptParams { testScript: string; response: TestResponse; envs: HoppEnvs; + legacySandbox: boolean; } /** diff --git a/packages/hoppscotch-cli/src/options/test/delay.ts b/packages/hoppscotch-cli/src/options/test/delay.ts index 75be423e..e9cf6537 100644 --- a/packages/hoppscotch-cli/src/options/test/delay.ts +++ b/packages/hoppscotch-cli/src/options/test/delay.ts @@ -1,14 +1,14 @@ import { error } from "../../types/errors"; export function parseDelayOption(delay: string): number { - const maybeInt = Number.parseInt(delay) + const maybeInt = Number.parseInt(delay); - if(!Number.isNaN(maybeInt)) { - return maybeInt + if (!Number.isNaN(maybeInt)) { + return maybeInt; } else { throw error({ code: "INVALID_ARGUMENT", data: "Expected '-d, --delay' value to be number", - }) + }); } } diff --git a/packages/hoppscotch-cli/src/types/collections.ts b/packages/hoppscotch-cli/src/types/collections.ts index 08c6ccb7..c3d67ebc 100644 --- a/packages/hoppscotch-cli/src/types/collections.ts +++ b/packages/hoppscotch-cli/src/types/collections.ts @@ -7,6 +7,7 @@ export type CollectionRunnerParam = { delay?: number; iterationData?: IterationDataItem[][]; iterationCount?: number; + legacySandbox: boolean; }; export type HoppCollectionFileExt = "json"; diff --git a/packages/hoppscotch-cli/src/types/commands.ts b/packages/hoppscotch-cli/src/types/commands.ts index e353cb7d..f53a1280 100644 --- a/packages/hoppscotch-cli/src/types/commands.ts +++ b/packages/hoppscotch-cli/src/types/commands.ts @@ -6,6 +6,7 @@ export type TestCmdOptions = { reporterJunit?: string; iterationCount?: number; iterationData?: string; + legacySandbox?: boolean; }; // Consumed in the collection `file_path_or_id` argument action handler diff --git a/packages/hoppscotch-cli/src/types/request.ts b/packages/hoppscotch-cli/src/types/request.ts index 0f6f780f..519ae292 100644 --- a/packages/hoppscotch-cli/src/types/request.ts +++ b/packages/hoppscotch-cli/src/types/request.ts @@ -37,4 +37,5 @@ export type ProcessRequestParams = { envs: HoppEnvs; path: string; delay: number; + legacySandbox: boolean; }; diff --git a/packages/hoppscotch-cli/src/utils/collections.ts b/packages/hoppscotch-cli/src/utils/collections.ts index 5c81d5d7..27f9d350 100644 --- a/packages/hoppscotch-cli/src/utils/collections.ts +++ b/packages/hoppscotch-cli/src/utils/collections.ts @@ -47,7 +47,14 @@ const { WARN, FAIL, INFO } = exceptionColors; export const collectionsRunner = async ( param: CollectionRunnerParam ): Promise => { - const { collections, envs, delay, iterationCount, iterationData } = param; + const { + collections, + envs, + delay, + iterationCount, + iterationData, + legacySandbox, + } = param; const resolvedDelay = delay ?? 0; @@ -87,7 +94,8 @@ export const collectionsRunner = async ( path, envs, resolvedDelay, - requestsReport + requestsReport, + legacySandbox ); } } @@ -100,7 +108,8 @@ const processCollection = async ( path: string, envs: HoppEnvs, delay: number, - requestsReport: RequestReport[] + requestsReport: RequestReport[], + legacySandbox?: boolean ) => { // Process each request in the collection for (const request of collection.requests) { @@ -111,6 +120,7 @@ const processCollection = async ( request: _request, envs, delay, + legacySandbox, }; // Request processing initiated message. @@ -156,7 +166,8 @@ const processCollection = async ( `${path}/${updatedFolder.name}`, envs, delay, - requestsReport + requestsReport, + legacySandbox ); } }; diff --git a/packages/hoppscotch-cli/src/utils/display.ts b/packages/hoppscotch-cli/src/utils/display.ts index 49620e4b..564512fd 100644 --- a/packages/hoppscotch-cli/src/utils/display.ts +++ b/packages/hoppscotch-cli/src/utils/display.ts @@ -120,7 +120,9 @@ export const printErrorsReport = ( errorsReport: HoppCLIError[] ) => { if (errorsReport.length > 0) { - const REPORTED_ERRORS_TITLE = FAIL(`\n${chalk.bold(path)} reported errors:`); + const REPORTED_ERRORS_TITLE = FAIL( + `\n${chalk.bold(path)} reported errors:` + ); group(REPORTED_ERRORS_TITLE); for (const errorReport of errorsReport) { diff --git a/packages/hoppscotch-cli/src/utils/functions/array.ts b/packages/hoppscotch-cli/src/utils/functions/array.ts index aa944906..f616d599 100644 --- a/packages/hoppscotch-cli/src/utils/functions/array.ts +++ b/packages/hoppscotch-cli/src/utils/functions/array.ts @@ -28,7 +28,7 @@ export const arrayFlatMap = export const tupleToRecord = < KeyType extends string | number | symbol, - ValueType + ValueType, >( tuples: [KeyType, ValueType][] ): Record => diff --git a/packages/hoppscotch-cli/src/utils/pre-request.ts b/packages/hoppscotch-cli/src/utils/pre-request.ts index 4f012278..62607814 100644 --- a/packages/hoppscotch-cli/src/utils/pre-request.ts +++ b/packages/hoppscotch-cli/src/utils/pre-request.ts @@ -44,15 +44,18 @@ import { calculateHawkHeader } from "@hoppscotch/data"; */ export const preRequestScriptRunner = ( request: HoppRESTRequest, - envs: HoppEnvs + envs: HoppEnvs, + legacySandbox: boolean ): TE.TaskEither< HoppCLIError, { effectiveRequest: EffectiveHoppRESTRequest } & { updatedEnvs: HoppEnvs } -> => - pipe( +> => { + const experimentalScriptingSandbox = !legacySandbox; + + return pipe( TE.of(request), TE.chain(({ preRequestScript }) => - runPreRequestScript(preRequestScript, envs) + runPreRequestScript(preRequestScript, envs, experimentalScriptingSandbox) ), TE.map( ({ selected, global }) => @@ -77,6 +80,7 @@ export const preRequestScriptRunner = ( }) ) ); +}; /** * Outputs an executable request format with environment variables applied diff --git a/packages/hoppscotch-cli/src/utils/request.ts b/packages/hoppscotch-cli/src/utils/request.ts index d769c5ac..0b78f77c 100644 --- a/packages/hoppscotch-cli/src/utils/request.ts +++ b/packages/hoppscotch-cli/src/utils/request.ts @@ -202,7 +202,7 @@ export const processRequest = params: ProcessRequestParams ): T.Task<{ envs: HoppEnvs; report: RequestReport }> => async () => { - const { envs, path, request, delay } = params; + const { envs, path, request, delay, legacySandbox } = params; // Initialising updatedEnvs with given parameter envs, will eventually get updated. const result = { @@ -235,7 +235,8 @@ export const processRequest = // Executing pre-request-script const preRequestRes = await preRequestScriptRunner( request, - processedEnvs + processedEnvs, + legacySandbox )(); if (E.isLeft(preRequestRes)) { printPreRequestRunner.fail(); @@ -287,7 +288,8 @@ export const processRequest = const testScriptParams = getTestScriptParams( _requestRunnerRes, request, - updatedEnvs + updatedEnvs, + legacySandbox ); // Executing test-runner. diff --git a/packages/hoppscotch-cli/src/utils/test.ts b/packages/hoppscotch-cli/src/utils/test.ts index e28609c2..69815952 100644 --- a/packages/hoppscotch-cli/src/utils/test.ts +++ b/packages/hoppscotch-cli/src/utils/test.ts @@ -37,9 +37,15 @@ export const testRunner = ( TE.bind("test_response", () => pipe( TE.of(testScriptData), - TE.chain(({ testScript, response, envs }) => - runTestScript(testScript, envs, response) - ) + TE.chain(({ testScript, response, envs, legacySandbox }) => { + const experimentalScriptingSandbox = !legacySandbox; + return runTestScript( + testScript, + envs, + response, + experimentalScriptingSandbox + ); + }) ) ), @@ -137,7 +143,8 @@ export const testDescriptorParser = ( export const getTestScriptParams = ( reqRunnerRes: RequestRunnerResponse, request: HoppRESTRequest, - envs: HoppEnvs + envs: HoppEnvs, + legacySandbox: boolean ) => { const testScriptParams: TestScriptParams = { testScript: request.testScript, @@ -146,7 +153,8 @@ export const getTestScriptParams = ( status: reqRunnerRes.status, headers: reqRunnerRes.headers, }, - envs: envs, + envs, + legacySandbox, }; return testScriptParams; }; diff --git a/packages/hoppscotch-common/locales/en.json b/packages/hoppscotch-common/locales/en.json index 677ba431..09a5572a 100644 --- a/packages/hoppscotch-common/locales/en.json +++ b/packages/hoppscotch-common/locales/en.json @@ -956,6 +956,7 @@ "ai_request_naming_style_pascal_case": "Pascal Case ( PascalCase )", "ai_request_naming_style_custom": "Custom", "ai_request_naming_style_custom_placeholder": "Enter your custom naming style template...", + "experimental_scripting_sandbox": "Experimental scripting sandbox", "sync": "Synchronise", "sync_collections": "Collections", "sync_description": "These settings are synced to cloud.", @@ -1851,5 +1852,9 @@ "update_billing_cycle": "Are you sure you want to update the billing cycle to {newBillingCycle}?" }, "cancel_subscription": "Cancel subscription" + }, + "app_console": { + "entries": "Console entries", + "no_entries": "No entries" } } diff --git a/packages/hoppscotch-common/package.json b/packages/hoppscotch-common/package.json index 5c82ef03..ec9a8196 100644 --- a/packages/hoppscotch-common/package.json +++ b/packages/hoppscotch-common/package.json @@ -34,12 +34,12 @@ "@codemirror/search": "6.5.6", "@codemirror/state": "6.4.1", "@codemirror/view": "6.25.1", - "@hoppscotch/plugin-appload": "github:CuriousCorrelation/tauri-plugin-appload", "@hoppscotch/codemirror-lang-graphql": "workspace:^", "@hoppscotch/data": "workspace:^", "@hoppscotch/httpsnippet": "3.0.7", "@hoppscotch/js-sandbox": "workspace:^", "@hoppscotch/kernel": "workspace:^", + "@hoppscotch/plugin-appload": "github:CuriousCorrelation/tauri-plugin-appload", "@hoppscotch/ui": "0.2.2", "@hoppscotch/vue-toasted": "0.1.0", "@lezer/highlight": "1.2.0", @@ -47,8 +47,8 @@ "@scure/base": "1.1.9", "@shopify/lang-jsonc": "1.0.0", "@tauri-apps/plugin-store": "2.2.0", - "@types/markdown-it": "14.1.2", "@types/hawk": "9.0.6", + "@types/markdown-it": "14.1.2", "@unhead/vue": "1.11.10", "@urql/core": "5.0.6", "@urql/devtools": "2.0.3", @@ -105,6 +105,7 @@ "verzod": "0.2.4", "vue": "3.5.12", "vue-i18n": "10.0.4", + "vue-json-pretty": "2.4.0", "vue-pdf-embed": "2.1.0", "vue-router": "4.4.5", "vue-tippy": "6.5.0", diff --git a/packages/hoppscotch-common/src/components.d.ts b/packages/hoppscotch-common/src/components.d.ts index 4ea41f4a..f460eebb 100644 --- a/packages/hoppscotch-common/src/components.d.ts +++ b/packages/hoppscotch-common/src/components.d.ts @@ -71,6 +71,9 @@ declare module 'vue' { CollectionsRequest: typeof import('./components/collections/Request.vue')['default'] CollectionsSaveRequest: typeof import('./components/collections/SaveRequest.vue')['default'] CollectionsTeamCollections: typeof import('./components/collections/TeamCollections.vue')['default'] + ConsoleItem: typeof import('./components/console/Item.vue')['default'] + ConsolePanel: typeof import('./components/console/Panel.vue')['default'] + ConsoleValue: typeof import('./components/console/Value.vue')['default'] CookiesAllModal: typeof import('./components/cookies/AllModal.vue')['default'] CookiesEditCookie: typeof import('./components/cookies/EditCookie.vue')['default'] Embeds: typeof import('./components/embeds/index.vue')['default'] diff --git a/packages/hoppscotch-common/src/components/console/Item.vue b/packages/hoppscotch-common/src/components/console/Item.vue new file mode 100644 index 00000000..68e803d7 --- /dev/null +++ b/packages/hoppscotch-common/src/components/console/Item.vue @@ -0,0 +1,61 @@ + + + diff --git a/packages/hoppscotch-common/src/components/console/Panel.vue b/packages/hoppscotch-common/src/components/console/Panel.vue new file mode 100644 index 00000000..363177a9 --- /dev/null +++ b/packages/hoppscotch-common/src/components/console/Panel.vue @@ -0,0 +1,55 @@ + + + diff --git a/packages/hoppscotch-common/src/components/console/Value.vue b/packages/hoppscotch-common/src/components/console/Value.vue new file mode 100644 index 00000000..2a257589 --- /dev/null +++ b/packages/hoppscotch-common/src/components/console/Value.vue @@ -0,0 +1,101 @@ + + + diff --git a/packages/hoppscotch-common/src/components/lenses/ResponseBodyRenderer.vue b/packages/hoppscotch-common/src/components/lenses/ResponseBodyRenderer.vue index cbd7f1cc..4395530d 100644 --- a/packages/hoppscotch-common/src/components/lenses/ResponseBodyRenderer.vue +++ b/packages/hoppscotch-common/src/components/lenses/ResponseBodyRenderer.vue @@ -49,19 +49,29 @@ :is-editable="false" /> + + +