From 99ad3e5822285339a3da85ba31a67ccdb3525ec1 Mon Sep 17 00:00:00 2001 From: jamesgeorge007 Date: Tue, 19 Mar 2024 20:31:51 +0530 Subject: [PATCH 1/3] feat: add extended support for versioned entities in the CLI --- .../collection-level-headers-auth-coll.json | 12 +++---- .../hoppscotch-cli/src/options/test/env.ts | 2 +- packages/hoppscotch-cli/src/utils/mutators.ts | 36 +++++++++++++++++-- .../hoppscotch-data/src/collection/index.ts | 4 +-- 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/packages/hoppscotch-cli/src/__tests__/samples/collections/collection-level-headers-auth-coll.json b/packages/hoppscotch-cli/src/__tests__/samples/collections/collection-level-headers-auth-coll.json index 5e779482f5..ca986c8ae7 100644 --- a/packages/hoppscotch-cli/src/__tests__/samples/collections/collection-level-headers-auth-coll.json +++ b/packages/hoppscotch-cli/src/__tests__/samples/collections/collection-level-headers-auth-coll.json @@ -1,18 +1,18 @@ [ { - "v": 1, + "v": 2, "name": "CollectionA", "folders": [ { - "v": 1, + "v": 2, "name": "FolderA", "folders": [ { - "v": 1, + "v": 2, "name": "FolderB", "folders": [ { - "v": 1, + "v": 2, "name": "FolderC", "folders": [], "requests": [ @@ -153,11 +153,11 @@ } }, { - "v": 1, + "v": 2, "name": "CollectionB", "folders": [ { - "v": 1, + "v": 2, "name": "FolderA", "folders": [], "requests": [ diff --git a/packages/hoppscotch-cli/src/options/test/env.ts b/packages/hoppscotch-cli/src/options/test/env.ts index 1f0be6de41..2cec231a1d 100644 --- a/packages/hoppscotch-cli/src/options/test/env.ts +++ b/packages/hoppscotch-cli/src/options/test/env.ts @@ -47,7 +47,7 @@ export async function parseEnvsData(path: string) { if (HoppEnvKeyPairResult.success) { for (const [key, value] of Object.entries(HoppEnvKeyPairResult.data)) { - envPairs.push({ key, value }); + envPairs.push({ key, value, secret: false }); } } else if (HoppEnvExportObjectResult.type === "ok") { envPairs.push(...HoppEnvExportObjectResult.value.variables); diff --git a/packages/hoppscotch-cli/src/utils/mutators.ts b/packages/hoppscotch-cli/src/utils/mutators.ts index 79053ed129..1f8ffeacfd 100644 --- a/packages/hoppscotch-cli/src/utils/mutators.ts +++ b/packages/hoppscotch-cli/src/utils/mutators.ts @@ -2,7 +2,17 @@ import fs from "fs/promises"; import { FormDataEntry } from "../types/request"; import { error } from "../types/errors"; import { isRESTCollection, isHoppErrnoException } from "./checks"; -import { HoppCollection } from "@hoppscotch/data"; +import { + GQLHeader, + HoppCollection, + HoppGQLAuth, + HoppGQLRequest, + HoppRESTAuth, + HoppRESTHeaders, + HoppRESTRequest, +} from "@hoppscotch/data"; +import { z } from "zod"; +import { entityReference } from "verzod"; /** * Parses array of FormDataEntry to FormData. @@ -67,7 +77,11 @@ export async function parseCollectionData( ? contents : [contents]; - if (maybeArrayOfCollections.some((x) => !isRESTCollection(x))) { + const collectionSchemaParsedResult = z + .array(entityReference(HoppCollection)) + .safeParse(maybeArrayOfCollections); + + if (!collectionSchemaParsedResult.success) { throw error({ code: "MALFORMED_COLLECTION", path, @@ -75,5 +89,21 @@ export async function parseCollectionData( }); } - return maybeArrayOfCollections as HoppCollection[]; + return collectionSchemaParsedResult.data.map((collection) => { + const requestSchemaParsedResult = z + .array(entityReference(HoppRESTRequest)) + .safeParse(collection.requests); + if (!requestSchemaParsedResult.success) { + throw error({ + code: "MALFORMED_COLLECTION", + path, + data: "Please check the collection data.", + }); + } + + return { + ...collection, + requests: requestSchemaParsedResult.data, + }; + }); } diff --git a/packages/hoppscotch-data/src/collection/index.ts b/packages/hoppscotch-data/src/collection/index.ts index 47e5180c10..2cfd3d3484 100644 --- a/packages/hoppscotch-data/src/collection/index.ts +++ b/packages/hoppscotch-data/src/collection/index.ts @@ -9,7 +9,7 @@ import { translateToGQLRequest } from "../graphql" const versionedObject = z.object({ // v is a stringified number - v: z.string().regex(/^\d+$/).transform(Number), + v: z.number(), }) export const HoppCollection = createVersionedEntity({ @@ -26,7 +26,7 @@ export const HoppCollection = createVersionedEntity({ // For V1 we have to check the schema const result = V1_VERSION.schema.safeParse(data) - return result.success ? 0 : null + return result.success ? 1 : null }, }) From 1e3aca05abd791b9c69f62ecf800af7e9edc8890 Mon Sep 17 00:00:00 2001 From: jamesgeorge007 Date: Tue, 19 Mar 2024 23:21:57 +0530 Subject: [PATCH 2/3] test: increase coverage --- .../src/__tests__/commands/test.spec.ts | 101 +++++++++++++++--- .../samples/collections/coll-v1-req-v0.json | 27 +++++ .../samples/collections/coll-v1-req-v1.json | 48 +++++++++ .../samples/collections/coll-v2-req-v2.json | 54 ++++++++++ .../samples/collections/sample-coll.json | 26 +++++ .../samples/environments/env-v0.json | 9 ++ .../samples/environments/env-v1.json | 10 ++ 7 files changed, 259 insertions(+), 16 deletions(-) create mode 100644 packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v1-req-v0.json create mode 100644 packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v1-req-v1.json create mode 100644 packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v2-req-v2.json create mode 100644 packages/hoppscotch-cli/src/__tests__/samples/collections/sample-coll.json create mode 100644 packages/hoppscotch-cli/src/__tests__/samples/environments/env-v0.json create mode 100644 packages/hoppscotch-cli/src/__tests__/samples/environments/env-v1.json diff --git a/packages/hoppscotch-cli/src/__tests__/commands/test.spec.ts b/packages/hoppscotch-cli/src/__tests__/commands/test.spec.ts index 675e317509..9be424aa2d 100644 --- a/packages/hoppscotch-cli/src/__tests__/commands/test.spec.ts +++ b/packages/hoppscotch-cli/src/__tests__/commands/test.spec.ts @@ -20,7 +20,7 @@ describe("Test `hopp test ` command:", () => { const out = getErrorCode(stderr); expect(out).toBe("INVALID_ARGUMENT"); }); - }) + }); describe("Supplied collection export file validations", () => { test("Errors with the code `FILE_NOT_FOUND` if the supplied collection export file doesn't exist", async () => { @@ -66,6 +66,42 @@ describe("Test `hopp test ` command:", () => { }); }); + describe("Versioned entities", () => { + describe("Collections & Requests", () => { + const testFixtures = [ + { fileName: "coll-v1-req-v0.json", collVersion: 1, reqVersion: 0 }, + { fileName: "coll-v1-req-v1.json", collVersion: 1, reqVersion: 1 }, + { fileName: "coll-v2-req-v2.json", collVersion: 2, reqVersion: 2 }, + ]; + + testFixtures.forEach(({ collVersion, fileName, reqVersion }) => { + test(`Successfully processes a supplied collection export file where the collection is based on the "v${collVersion}" schema and the request following the "v${reqVersion}" schema`, async () => { + const args = `test ${getTestJsonFilePath(fileName, "collection")}`; + const { error } = await runCLI(args); + + expect(error).toBeNull(); + }); + }); + }); + + describe("Environments", () => { + const testFixtures = [ + { fileName: "env-v0.json", version: 0 }, + { fileName: "env-v1.json", version: 1 }, + ]; + + testFixtures.forEach(({ fileName, version }) => { + test(`Successfully processes the supplied collection and environment export files where the environment is based on the "v${version}" schema`, async () => { + const ENV_PATH = getTestJsonFilePath(fileName, "environment"); + const args = `test ${getTestJsonFilePath("sample-coll.json", "collection")} --env ${ENV_PATH}`; + const { error } = await runCLI(args); + + expect(error).toBeNull(); + }); + }); + }); + }); + test("Successfully processes a supplied collection export file of the expected format", async () => { const args = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`; const { error } = await runCLI(args); @@ -75,7 +111,8 @@ describe("Test `hopp test ` command:", () => { test("Successfully inherits headers and authorization set at the root collection", async () => { const args = `test ${getTestJsonFilePath( - "collection-level-headers-auth-coll.json", "collection" + "collection-level-headers-auth-coll.json", + "collection" )}`; const { error } = await runCLI(args); @@ -84,7 +121,8 @@ describe("Test `hopp test ` command:", () => { test("Persists environment variables set in the pre-request script for consumption in the test script", async () => { const args = `test ${getTestJsonFilePath( - "pre-req-script-env-var-persistence-coll.json", "collection" + "pre-req-script-env-var-persistence-coll.json", + "collection" )}`; const { error } = await runCLI(args); @@ -106,7 +144,8 @@ describe("Test `hopp test --env ` command:", () => { test("Errors with the code `INVALID_FILE_TYPE` if the supplied environment export file doesn't end with the `.json` extension", async () => { const args = `${VALID_TEST_ARGS} --env ${getTestJsonFilePath( - "notjson-coll.txt", "collection" + "notjson-coll.txt", + "collection" )}`; const { stderr } = await runCLI(args); @@ -123,7 +162,10 @@ describe("Test `hopp test --env ` command:", () => { }); test("Errors with the code `MALFORMED_ENV_FILE` on supplying a malformed environment export file", async () => { - const ENV_PATH = getTestJsonFilePath("malformed-envs.json", "environment"); + const ENV_PATH = getTestJsonFilePath( + "malformed-envs.json", + "environment" + ); const args = `${VALID_TEST_ARGS} --env ${ENV_PATH}`; const { stderr } = await runCLI(args); @@ -142,7 +184,10 @@ describe("Test `hopp test --env ` command:", () => { }); test("Successfully resolves values from the supplied environment export file", async () => { - const TESTS_PATH = getTestJsonFilePath("env-flag-tests-coll.json", "collection"); + const TESTS_PATH = getTestJsonFilePath( + "env-flag-tests-coll.json", + "collection" + ); const ENV_PATH = getTestJsonFilePath("env-flag-envs.json", "environment"); const args = `test ${TESTS_PATH} --env ${ENV_PATH}`; @@ -151,8 +196,14 @@ describe("Test `hopp test --env ` command:", () => { }); test("Successfully resolves environment variables referenced in the request body", async () => { - const COLL_PATH = getTestJsonFilePath("req-body-env-vars-coll.json", "collection"); - const ENVS_PATH = getTestJsonFilePath("req-body-env-vars-envs.json", "environment"); + const COLL_PATH = getTestJsonFilePath( + "req-body-env-vars-coll.json", + "collection" + ); + const ENVS_PATH = getTestJsonFilePath( + "req-body-env-vars-envs.json", + "environment" + ); const args = `test ${COLL_PATH} --env ${ENVS_PATH}`; const { error } = await runCLI(args); @@ -160,7 +211,10 @@ describe("Test `hopp test --env ` command:", () => { }); test("Works with shorth `-e` flag", async () => { - const TESTS_PATH = getTestJsonFilePath("env-flag-tests-coll.json", "collection"); + const TESTS_PATH = getTestJsonFilePath( + "env-flag-tests-coll.json", + "collection" + ); const ENV_PATH = getTestJsonFilePath("env-flag-envs.json", "environment"); const args = `test ${TESTS_PATH} -e ${ENV_PATH}`; @@ -183,7 +237,10 @@ describe("Test `hopp test --env ` command:", () => { secretHeaderValue: "secret-header-value", }; - const COLL_PATH = getTestJsonFilePath("secret-envs-coll.json", "collection"); + const COLL_PATH = getTestJsonFilePath( + "secret-envs-coll.json", + "collection" + ); const ENVS_PATH = getTestJsonFilePath("secret-envs.json", "environment"); const args = `test ${COLL_PATH} --env ${ENVS_PATH}`; @@ -197,8 +254,14 @@ describe("Test `hopp test --env ` command:", () => { // Prefers values specified in the environment export file over values set in the system environment test("Successfully picks the values for secret environment variables set directly in the environment export file and persists the environment variables set from the pre-request script", async () => { - const COLL_PATH = getTestJsonFilePath("secret-envs-coll.json", "collection"); - const ENVS_PATH = getTestJsonFilePath("secret-supplied-values-envs.json", "environment"); + const COLL_PATH = getTestJsonFilePath( + "secret-envs-coll.json", + "collection" + ); + const ENVS_PATH = getTestJsonFilePath( + "secret-supplied-values-envs.json", + "environment" + ); const args = `test ${COLL_PATH} --env ${ENVS_PATH}`; const { error, stdout } = await runCLI(args); @@ -212,9 +275,13 @@ describe("Test `hopp test --env ` command:", () => { // Values set from the scripting context takes the highest precedence test("Setting values for secret environment variables from the pre-request script overrides values set at the supplied environment export file", async () => { const COLL_PATH = getTestJsonFilePath( - "secret-envs-persistence-coll.json", "collection" + "secret-envs-persistence-coll.json", + "collection" + ); + const ENVS_PATH = getTestJsonFilePath( + "secret-supplied-values-envs.json", + "environment" ); - const ENVS_PATH = getTestJsonFilePath("secret-supplied-values-envs.json", "environment"); const args = `test ${COLL_PATH} --env ${ENVS_PATH}`; const { error, stdout } = await runCLI(args); @@ -227,10 +294,12 @@ describe("Test `hopp test --env ` command:", () => { test("Persists secret environment variable values set from the pre-request script for consumption in the request and post-request script context", async () => { const COLL_PATH = getTestJsonFilePath( - "secret-envs-persistence-scripting-coll.json", "collection" + "secret-envs-persistence-scripting-coll.json", + "collection" ); const ENVS_PATH = getTestJsonFilePath( - "secret-envs-persistence-scripting-envs.json", "environment" + "secret-envs-persistence-scripting-envs.json", + "environment" ); const args = `test ${COLL_PATH} --env ${ENVS_PATH}`; diff --git a/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v1-req-v0.json b/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v1-req-v0.json new file mode 100644 index 0000000000..6393ba6ad3 --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v1-req-v0.json @@ -0,0 +1,27 @@ +{ + "v": 1, + "name": "coll-v1", + "folders": [], + "requests": [ + { + "url": "https://httpbin.org", + "path": "/get", + "headers": [ + { "key": "Inactive-Header", "value": "Inactive Header", "active": false }, + { "key": "Authorization", "value": "Bearer token123", "active": true } + ], + "params": [ + { "key": "key", "value": "value", "active": true }, + { "key": "inactive-key", "value": "inactive-param", "active": false } + ], + "name": "req-v0", + "method": "GET", + "preRequestScript": "", + "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"Authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"Inactive-Header\"]).toBe(undefined)\n})", + "contentType": "application/json", + "body": "", + "auth": "Bearer Token", + "bearerToken": "token123" + } + ] +} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v1-req-v1.json b/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v1-req-v1.json new file mode 100644 index 0000000000..61f9adb52b --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v1-req-v1.json @@ -0,0 +1,48 @@ +{ + "v": 1, + "name": "coll-v1", + "folders": [], + "requests": [ + { + "v": "1", + "endpoint": "https://httpbin.org/get", + "headers": [ + { + "key": "Inactive-Header", + "value": "Inactive Header", + "active": false + }, + { + "key": "Authorization", + "value": "Bearer token123", + "active": true + } + ], + "params": [ + { + "key": "key", + "value": "value", + "active": true + }, + { + "key": "inactive-key", + "value": "inactive-param", + "active": false + } + ], + "name": "req-v1", + "method": "GET", + "preRequestScript": "", + "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"Authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"Inactive-Header\"]).toBe(undefined)\n})", + "body": { + "contentType": null, + "body": null + }, + "auth": { + "authType": "bearer", + "authActive": true, + "token": "token123" + } + } + ] +} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v2-req-v2.json b/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v2-req-v2.json new file mode 100644 index 0000000000..780373f828 --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v2-req-v2.json @@ -0,0 +1,54 @@ +{ + "v": 2, + "name": "coll-v2", + "folders": [], + "requests": [ + { + "v": "2", + "endpoint": "https://httpbin.org/get", + "headers": [ + { + "key": "Inactive-Header", + "value": "Inactive Header", + "active": false + }, + { + "key": "Authorization", + "value": "Bearer token123", + "active": true + } + ], + "params": [ + { + "key": "key", + "value": "value", + "active": true + }, + { + "key": "inactive-key", + "value": "inactive-param", + "active": false + } + ], + "name": "req-v2", + "method": "GET", + "preRequestScript": "", + "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"Authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"Inactive-Header\"]).toBe(undefined)\n})", + "body": { + "contentType": null, + "body": null + }, + "auth": { + "authType": "bearer", + "authActive": true, + "token": "token123" + }, + "requestVariables": [] + } + ], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [] +} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/samples/collections/sample-coll.json b/packages/hoppscotch-cli/src/__tests__/samples/collections/sample-coll.json new file mode 100644 index 0000000000..a85a8c8fb8 --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/samples/collections/sample-coll.json @@ -0,0 +1,26 @@ +{ + "v": 1, + "name": "tests", + "folders": [], + "requests": [ + { + "v": "2", + "endpoint": "<>", + "name": "", + "params": [], + "headers": [], + "method": "GET", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});", + "body": { + "contentType": null, + "body": null + }, + "requestVariables": [] + } + ] +} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v0.json b/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v0.json new file mode 100644 index 0000000000..55054f535e --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v0.json @@ -0,0 +1,9 @@ +{ + "name": "env-v0", + "variables": [ + { + "key": "baseUrl", + "value": "https://echo.hoppscotch.io" + } + ] +} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v1.json b/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v1.json new file mode 100644 index 0000000000..7be123a5ce --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v1.json @@ -0,0 +1,10 @@ +{ + "name": "env-v0", + "variables": [ + { + "key": "baseUrl", + "value": "https://echo.hoppscotch.io", + "secret": false + } + ] + } \ No newline at end of file From cd76cf5df652714e7fb8f5b8d908f0c68bd4ab00 Mon Sep 17 00:00:00 2001 From: jamesgeorge007 Date: Wed, 20 Mar 2024 00:07:32 +0530 Subject: [PATCH 3/3] chore: cleanup --- .../src/__tests__/commands/test.spec.ts | 1 + .../functions/checks/isRESTCollection.spec.ts | 84 ------------------- .../samples/collections/coll-v2-req-v3.json | 54 ++++++++++++ .../samples/collections/sample-coll.json | 2 +- .../samples/environments/env-v0.json | 2 +- .../samples/environments/env-v1.json | 2 +- packages/hoppscotch-cli/src/utils/checks.ts | 44 ---------- packages/hoppscotch-cli/src/utils/mutators.ts | 20 ++--- .../hoppscotch-data/src/collection/index.ts | 1 - 9 files changed, 65 insertions(+), 145 deletions(-) delete mode 100644 packages/hoppscotch-cli/src/__tests__/functions/checks/isRESTCollection.spec.ts create mode 100644 packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v2-req-v3.json diff --git a/packages/hoppscotch-cli/src/__tests__/commands/test.spec.ts b/packages/hoppscotch-cli/src/__tests__/commands/test.spec.ts index 9be424aa2d..25b3325d24 100644 --- a/packages/hoppscotch-cli/src/__tests__/commands/test.spec.ts +++ b/packages/hoppscotch-cli/src/__tests__/commands/test.spec.ts @@ -72,6 +72,7 @@ describe("Test `hopp test ` command:", () => { { fileName: "coll-v1-req-v0.json", collVersion: 1, reqVersion: 0 }, { fileName: "coll-v1-req-v1.json", collVersion: 1, reqVersion: 1 }, { fileName: "coll-v2-req-v2.json", collVersion: 2, reqVersion: 2 }, + { fileName: "coll-v2-req-v3.json", collVersion: 2, reqVersion: 3 }, ]; testFixtures.forEach(({ collVersion, fileName, reqVersion }) => { diff --git a/packages/hoppscotch-cli/src/__tests__/functions/checks/isRESTCollection.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/checks/isRESTCollection.spec.ts deleted file mode 100644 index b9b30e9aca..0000000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/checks/isRESTCollection.spec.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { isRESTCollection } from "../../../utils/checks"; - -describe("isRESTCollection", () => { - test("Undefined collection value.", () => { - expect(isRESTCollection(undefined)).toBeFalsy(); - }); - - test("Invalid id value.", () => { - expect( - isRESTCollection({ - v: 1, - name: "test", - id: 1, - }) - ).toBeFalsy(); - }); - - test("Invalid requests value.", () => { - expect( - isRESTCollection({ - v: 1, - name: "test", - id: "1", - requests: null, - }) - ).toBeFalsy(); - }); - - test("Invalid folders value.", () => { - expect( - isRESTCollection({ - v: 1, - name: "test", - id: "1", - requests: [], - folders: undefined, - }) - ).toBeFalsy(); - }); - - test("Invalid RESTCollection(s) in folders.", () => { - expect( - isRESTCollection({ - v: 1, - name: "test", - id: "1", - requests: [], - folders: [ - { - v: 1, - name: "test1", - id: "2", - requests: undefined, - folders: [], - }, - ], - }) - ).toBeFalsy(); - }); - - test("Invalid HoppRESTRequest(s) in requests.", () => { - expect( - isRESTCollection({ - v: 1, - name: "test", - id: "1", - requests: [{}], - folders: [], - }) - ).toBeFalsy(); - }); - - test("Valid RESTCollection.", () => { - expect( - isRESTCollection({ - v: 1, - name: "test", - id: "1", - requests: [], - folders: [], - }) - ).toBeTruthy(); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v2-req-v3.json b/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v2-req-v3.json new file mode 100644 index 0000000000..fcce134a8d --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/samples/collections/coll-v2-req-v3.json @@ -0,0 +1,54 @@ +{ + "v": 2, + "name": "coll-v2", + "folders": [], + "requests": [ + { + "v": "3", + "endpoint": "https://httpbin.org/get", + "headers": [ + { + "key": "Inactive-Header", + "value": "Inactive Header", + "active": false + }, + { + "key": "Authorization", + "value": "Bearer token123", + "active": true + } + ], + "params": [ + { + "key": "key", + "value": "value", + "active": true + }, + { + "key": "inactive-key", + "value": "inactive-param", + "active": false + } + ], + "name": "req-v3", + "method": "GET", + "preRequestScript": "", + "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"Authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"Inactive-Header\"]).toBe(undefined)\n})", + "body": { + "contentType": null, + "body": null + }, + "auth": { + "authType": "bearer", + "authActive": true, + "token": "token123" + }, + "requestVariables": [] + } + ], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [] +} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/samples/collections/sample-coll.json b/packages/hoppscotch-cli/src/__tests__/samples/collections/sample-coll.json index a85a8c8fb8..b0ca8cecf2 100644 --- a/packages/hoppscotch-cli/src/__tests__/samples/collections/sample-coll.json +++ b/packages/hoppscotch-cli/src/__tests__/samples/collections/sample-coll.json @@ -5,7 +5,7 @@ "requests": [ { "v": "2", - "endpoint": "<>", + "endpoint": "<>", "name": "", "params": [], "headers": [], diff --git a/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v0.json b/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v0.json index 55054f535e..16b232857c 100644 --- a/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v0.json +++ b/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v0.json @@ -2,7 +2,7 @@ "name": "env-v0", "variables": [ { - "key": "baseUrl", + "key": "baseURL", "value": "https://echo.hoppscotch.io" } ] diff --git a/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v1.json b/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v1.json index 7be123a5ce..4ab5aa65f7 100644 --- a/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v1.json +++ b/packages/hoppscotch-cli/src/__tests__/samples/environments/env-v1.json @@ -2,7 +2,7 @@ "name": "env-v0", "variables": [ { - "key": "baseUrl", + "key": "baseURL", "value": "https://echo.hoppscotch.io", "secret": false } diff --git a/packages/hoppscotch-cli/src/utils/checks.ts b/packages/hoppscotch-cli/src/utils/checks.ts index f935cbe4ac..083aab7f2e 100644 --- a/packages/hoppscotch-cli/src/utils/checks.ts +++ b/packages/hoppscotch-cli/src/utils/checks.ts @@ -1,5 +1,3 @@ -import { HoppCollection, isHoppRESTRequest } from "@hoppscotch/data"; -import * as A from "fp-ts/Array"; import { CommanderError } from "commander"; import { HoppCLIError, HoppErrnoException } from "../types/errors"; @@ -14,48 +12,6 @@ export const hasProperty =

( prop: P ): target is Record => prop in target; -/** - * Typeguard to check valid Hoppscotch REST Collection. - * @param param The object to be checked. - * @returns True, if unknown parameter is valid Hoppscotch REST Collection; - * False, otherwise. - */ -export const isRESTCollection = (param: unknown): param is HoppCollection => { - if (!!param && typeof param === "object") { - if (!hasProperty(param, "v") || typeof param.v !== "number") { - return false; - } - if (!hasProperty(param, "name") || typeof param.name !== "string") { - return false; - } - if (hasProperty(param, "id") && typeof param.id !== "string") { - return false; - } - if (!hasProperty(param, "requests") || !Array.isArray(param.requests)) { - return false; - } else { - // Checks each requests array to be valid HoppRESTRequest. - const checkRequests = A.every(isHoppRESTRequest)(param.requests); - if (!checkRequests) { - return false; - } - } - if (!hasProperty(param, "folders") || !Array.isArray(param.folders)) { - return false; - } else { - // Checks each folder to be valid REST collection. - const checkFolders = A.every(isRESTCollection)(param.folders); - if (!checkFolders) { - return false; - } - } - - return true; - } - - return false; -}; - /** * Checks if given error data is of type HoppCLIError, based on existence * of code property. diff --git a/packages/hoppscotch-cli/src/utils/mutators.ts b/packages/hoppscotch-cli/src/utils/mutators.ts index 1f8ffeacfd..91b1383f4e 100644 --- a/packages/hoppscotch-cli/src/utils/mutators.ts +++ b/packages/hoppscotch-cli/src/utils/mutators.ts @@ -1,18 +1,11 @@ +import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"; import fs from "fs/promises"; -import { FormDataEntry } from "../types/request"; -import { error } from "../types/errors"; -import { isRESTCollection, isHoppErrnoException } from "./checks"; -import { - GQLHeader, - HoppCollection, - HoppGQLAuth, - HoppGQLRequest, - HoppRESTAuth, - HoppRESTHeaders, - HoppRESTRequest, -} from "@hoppscotch/data"; -import { z } from "zod"; import { entityReference } from "verzod"; +import { z } from "zod"; + +import { error } from "../types/errors"; +import { FormDataEntry } from "../types/request"; +import { isHoppErrnoException } from "./checks"; /** * Parses array of FormDataEntry to FormData. @@ -93,6 +86,7 @@ export async function parseCollectionData( const requestSchemaParsedResult = z .array(entityReference(HoppRESTRequest)) .safeParse(collection.requests); + if (!requestSchemaParsedResult.success) { throw error({ code: "MALFORMED_COLLECTION", diff --git a/packages/hoppscotch-data/src/collection/index.ts b/packages/hoppscotch-data/src/collection/index.ts index 2cfd3d3484..7ed072c94d 100644 --- a/packages/hoppscotch-data/src/collection/index.ts +++ b/packages/hoppscotch-data/src/collection/index.ts @@ -8,7 +8,6 @@ import { translateToNewRequest } from "../rest" import { translateToGQLRequest } from "../graphql" const versionedObject = z.object({ - // v is a stringified number v: z.number(), })