From c85eafbbb85c47091fcb746c3d2de266f45b359d Mon Sep 17 00:00:00 2001
From: George He <hexxa@outlook.com>
Date: Wed, 15 Jan 2025 11:16:24 +0800
Subject: [PATCH 1/8] fix: include multiline and fileName in the multipart req
 body

---
 packages/insomnia-sdk/src/objects/console.ts  | 14 ++++++-
 .../insomnia-sdk/src/objects/environments.ts  |  5 +++
 packages/insomnia-sdk/src/objects/request.ts  | 42 ++++++++++++++-----
 packages/insomnia-sdk/src/objects/response.ts |  3 +-
 packages/insomnia-sdk/src/objects/urls.ts     | 16 ++++++-
 packages/insomnia/src/hidden-window.ts        |  4 +-
 6 files changed, 68 insertions(+), 16 deletions(-)

diff --git a/packages/insomnia-sdk/src/objects/console.ts b/packages/insomnia-sdk/src/objects/console.ts
index 2ca41908704..5fd130289e4 100644
--- a/packages/insomnia-sdk/src/objects/console.ts
+++ b/packages/insomnia-sdk/src/objects/console.ts
@@ -14,8 +14,11 @@ export class Console {
     // TODO: support replacing substitution
     printLog = (rows: Row[], level: LogLevel, ...values: any) => {
         try {
+            const content = values.map((a: any) => JSON.stringify(a, null, 2).replace('\\n', '\n'))
+                .join(' ');
             const row = {
-                value: `${level}: ` + values.map((a: any) => JSON.stringify(a, null, 2)).join('\n'),
+                // TODO: also support formating e.g. \t
+                value: `${level}: ${content}`,
                 name: 'Text',
                 timestamp: Date.now(),
             };
@@ -66,3 +69,12 @@ export class Console {
             .map(row => JSON.stringify(row) + '\n');
     };
 }
+
+let builtInConsole = new Console();
+export function getConsole() {
+    return builtInConsole;
+}
+export function getNewConsole() {
+    builtInConsole = new Console();
+    return builtInConsole;
+}
diff --git a/packages/insomnia-sdk/src/objects/environments.ts b/packages/insomnia-sdk/src/objects/environments.ts
index a071163e324..4936cd3aaf0 100644
--- a/packages/insomnia-sdk/src/objects/environments.ts
+++ b/packages/insomnia-sdk/src/objects/environments.ts
@@ -1,3 +1,4 @@
+import { getConsole } from './console';
 import { getInterpolator } from './interpolator';
 
 export class Environment {
@@ -22,6 +23,10 @@ export class Environment {
     };
 
     set = (variableName: string, variableValue: boolean | number | string) => {
+        if (variableValue === null) {
+            getConsole().warn(`Variable "${variableName}" has a null value`);
+            return;
+        }
         this.kvs.set(variableName, variableValue);
     };
 
diff --git a/packages/insomnia-sdk/src/objects/request.ts b/packages/insomnia-sdk/src/objects/request.ts
index d12bda0645e..f6d19308f3c 100644
--- a/packages/insomnia-sdk/src/objects/request.ts
+++ b/packages/insomnia-sdk/src/objects/request.ts
@@ -17,10 +17,10 @@ export type RequestBodyMode = undefined | 'formdata' | 'urlencoded' | 'raw' | 'f
 export interface RequestBodyOptions {
     mode: RequestBodyMode;
     file?: string;
-    formdata?: { key: string; value: string; type?: string }[];
-    graphql?: { query: string; operationName: string; variables: object };
+    formdata?: { key: string; value: string; type?: string; disabled?: boolean }[];
+    graphql?: { query: string; operationName: string; variables: object; disabled?: boolean };
     raw?: string;
-    urlencoded?: { key: string; value: string; type?: string }[];
+    urlencoded?: { key: string; value: string; type?: string; disabled?: boolean; multiline?: boolean | string; fileName?: string }[];
     options?: object;
 }
 
@@ -29,11 +29,12 @@ export class FormParam extends Property {
     value: string;
     type?: string;
 
-    constructor(options: { key: string; value: string; type?: string }) {
+    constructor(options: { key: string; value: string; type?: string; disabled?: boolean }) {
         super();
         this.key = options.key;
         this.value = options.value;
         this.type = options.type;
+        this.disabled = options.disabled;
     }
 
     static _postman_propertyAllowsMultipleValues() {
@@ -49,7 +50,7 @@ export class FormParam extends Property {
     // }
 
     override toJSON() {
-        return { key: this.key, value: this.value, type: this.type };
+        return { key: this.key, value: this.value, type: this.type, disabled: this.disabled };
     }
 
     override toString() {
@@ -91,7 +92,14 @@ function getClassFields(opts: RequestBodyOptions) {
                 QueryParam,
                 undefined,
                 opts.urlencoded
-                    .map(entry => ({ key: entry.key, value: entry.value, type: entry.type }))
+                    .map(entry => ({
+                        key: entry.key,
+                        value: entry.value,
+                        type: entry.type,
+                        disabled: entry.disabled,
+                        fileName: entry.fileName,
+                        multiline: entry.multiline,
+                    }))
                     .map(kv => new QueryParam(kv)),
             );
         }
@@ -569,7 +577,14 @@ export function toScriptRequestBody(insomniaReqBody: InsomniaRequestBody): Reque
         reqBodyOpt = {
             mode: 'urlencoded',
             urlencoded: insomniaReqBody.params.map(
-                (param: RequestBodyParameter) => ({ key: param.name, value: param.value, type: param.type })
+                (param: RequestBodyParameter) => ({
+                    key: param.name,
+                    value: param.value,
+                    type: param.type,
+                    multiline: param.multiline,
+                    disabled: param.disabled,
+                    fileName: param.fileName,
+                })
             ),
         };
     }
@@ -621,9 +636,16 @@ export function mergeRequestBody(
             text: textContent,
             fileName: updatedReqBody?.file,
             params: updatedReqBody?.urlencoded?.map(
-                (param: { key: string; value: string; type?: string }) => (
-                    { name: param.key, value: param.value, type: param.type }
-                ),
+                (param: QueryParam) => {
+                    return {
+                        name: param.key,
+                        value: param.value,
+                        type: param.type,
+                        fileName: param.fileName,
+                        multiline: param.multiline,
+                        disabled: param.disabled,
+                    };
+                },
                 {},
             ),
         };
diff --git a/packages/insomnia-sdk/src/objects/response.ts b/packages/insomnia-sdk/src/objects/response.ts
index 893e5423371..57013e91086 100644
--- a/packages/insomnia-sdk/src/objects/response.ts
+++ b/packages/insomnia-sdk/src/objects/response.ts
@@ -158,7 +158,7 @@ export class Response extends Property {
             throw Error('dataURI(): response body is not defined');
         }
 
-        return `data:${contentInfo.contentType};baseg4, <base64-encoded-body>`;
+        return `data:${contentInfo.contentType};baseg4, ${bodyInBase64}`;
     }
 
     // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -184,7 +184,6 @@ export class Response extends Property {
         try {
             const contentLength = this.headers.get('Content-Length');
             // TODO: improve this by manual counting
-            console.log(this.headers.get('Content-Length'));
             return contentLength == null ? -1 : parseInt(contentLength.valueOf());
         } catch (e) {
             throw Error('size: ${e}');
diff --git a/packages/insomnia-sdk/src/objects/urls.ts b/packages/insomnia-sdk/src/objects/urls.ts
index e25bd639a1e..d9c1cf68563 100644
--- a/packages/insomnia-sdk/src/objects/urls.ts
+++ b/packages/insomnia-sdk/src/objects/urls.ts
@@ -9,6 +9,10 @@ export function setUrlSearchParams(provider: any) {
 export interface QueryParamOptions {
     key: string;
     value: string;
+    type?: string;
+    multiline?: string | boolean;
+    disabled?: boolean;
+    fileName?: string;
 }
 
 export class QueryParam extends Property {
@@ -17,8 +21,12 @@ export class QueryParam extends Property {
     key: string;
     value: string;
     type?: string;
+    // the `multiline` and `fileName` are properties from Insomnia
+    // they are added here to avoid being dropped
+    multiline?: string | boolean;
+    fileName?: string;
 
-    constructor(options: { key: string; value: string; type?: string } | string) {
+    constructor(options: QueryParamOptions | string) {
         super();
 
         if (typeof options === 'string') {
@@ -27,6 +35,9 @@ export class QueryParam extends Property {
                 this.key = optionsObj.key;
                 this.value = optionsObj.value;
                 this.type = optionsObj.type;
+                this.multiline = optionsObj.multiline;
+                this.disabled = optionsObj.disabled;
+                this.fileName = optionsObj.fileName;
             } catch (e) {
                 throw Error(`invalid QueryParam options ${e}`);
             }
@@ -34,6 +45,9 @@ export class QueryParam extends Property {
             this.key = options.key;
             this.value = options.value;
             this.type = options.type;
+            this.multiline = options.multiline;
+            this.disabled = options.disabled;
+            this.fileName = options.fileName;
         } else {
             throw Error('unknown options for new QueryParam');
         }
diff --git a/packages/insomnia/src/hidden-window.ts b/packages/insomnia/src/hidden-window.ts
index 2938e77eb13..4f4912bde33 100644
--- a/packages/insomnia/src/hidden-window.ts
+++ b/packages/insomnia/src/hidden-window.ts
@@ -1,7 +1,7 @@
 import * as Sentry from '@sentry/electron/renderer';
 import { SENTRY_OPTIONS } from 'insomnia/src/common/sentry';
 import { initInsomniaObject, InsomniaObject } from 'insomnia-sdk';
-import { Console, mergeClientCertificates, mergeCookieJar, mergeRequests, mergeSettings, type RequestContext } from 'insomnia-sdk';
+import { getNewConsole, mergeClientCertificates, mergeCookieJar, mergeRequests, mergeSettings, type RequestContext } from 'insomnia-sdk';
 import * as _ from 'lodash';
 
 export interface HiddenBrowserWindowBridgeAPI {
@@ -48,7 +48,7 @@ function translateTestHandlers(script: string): string {
 const runScript = async (
   { script, context }: { script: string; context: RequestContext },
 ): Promise<RequestContext> => {
-  const scriptConsole = new Console();
+  const scriptConsole = getNewConsole();
 
   const executionContext = await initInsomniaObject(context, scriptConsole.log);
 

From 7cc9969c61ed9f3ba9844883b27dd0aecff343dd Mon Sep 17 00:00:00 2001
From: George He <hexxa@outlook.com>
Date: Wed, 15 Jan 2025 15:34:13 +0800
Subject: [PATCH 2/8] fix: reject setting null to insomnia.variables

---
 packages/insomnia-sdk/src/objects/environments.ts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/packages/insomnia-sdk/src/objects/environments.ts b/packages/insomnia-sdk/src/objects/environments.ts
index 4936cd3aaf0..d9d2d31a362 100644
--- a/packages/insomnia-sdk/src/objects/environments.ts
+++ b/packages/insomnia-sdk/src/objects/environments.ts
@@ -100,6 +100,11 @@ export class Variables {
     };
 
     set = (variableName: string, variableValue: boolean | number | string) => {
+        if (variableValue === null) {
+            getConsole().warn(`Variable "${variableName}" has a null value`);
+            return;
+        }
+
         this.localVars.set(variableName, variableValue);
     };
 

From f5fce10bd3172857fc4aea732ff35cc332700476 Mon Sep 17 00:00:00 2001
From: George He <hexxa@outlook.com>
Date: Wed, 15 Jan 2025 17:58:11 +0800
Subject: [PATCH 3/8] fix: comment

---
 packages/insomnia-sdk/src/objects/environments.ts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/insomnia-sdk/src/objects/environments.ts b/packages/insomnia-sdk/src/objects/environments.ts
index d9d2d31a362..14d03c4f5f6 100644
--- a/packages/insomnia-sdk/src/objects/environments.ts
+++ b/packages/insomnia-sdk/src/objects/environments.ts
@@ -3,7 +3,7 @@ import { getInterpolator } from './interpolator';
 
 export class Environment {
     private _name: string;
-    private kvs = new Map<string, boolean | number | string>();
+    private kvs = new Map<string, boolean | number | string | undefined>();
 
     constructor(name: string, jsonObject: object | undefined) {
         this._name = name;
@@ -22,7 +22,7 @@ export class Environment {
         return this.kvs.get(variableName);
     };
 
-    set = (variableName: string, variableValue: boolean | number | string) => {
+    set = (variableName: string, variableValue: boolean | number | string | undefined | null) => {
         if (variableValue === null) {
             getConsole().warn(`Variable "${variableName}" has a null value`);
             return;
@@ -99,7 +99,7 @@ export class Variables {
         return finalVal;
     };
 
-    set = (variableName: string, variableValue: boolean | number | string) => {
+    set = (variableName: string, variableValue: boolean | number | string | undefined | null) => {
         if (variableValue === null) {
             getConsole().warn(`Variable "${variableName}" has a null value`);
             return;

From c4c92542fa298812a7e1ee991100d1f3740874aa Mon Sep 17 00:00:00 2001
From: George He <hexxa@outlook.com>
Date: Thu, 16 Jan 2025 17:07:56 +0800
Subject: [PATCH 4/8] fix: also update the scriptExecutor with
 getExistingConsole

---
 packages/insomnia-sdk/src/objects/console.ts      | 4 ++--
 packages/insomnia-sdk/src/objects/environments.ts | 6 +++---
 packages/insomnia-sdk/src/objects/test.ts         | 2 +-
 packages/insomnia/src/scriptExecutor.ts           | 4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/packages/insomnia-sdk/src/objects/console.ts b/packages/insomnia-sdk/src/objects/console.ts
index 5fd130289e4..06056275785 100644
--- a/packages/insomnia-sdk/src/objects/console.ts
+++ b/packages/insomnia-sdk/src/objects/console.ts
@@ -6,7 +6,7 @@ export interface Row {
     timestamp: number;
 }
 
-export class Console {
+class Console {
     rows: Row[] = [];
 
     constructor() { }
@@ -71,7 +71,7 @@ export class Console {
 }
 
 let builtInConsole = new Console();
-export function getConsole() {
+export function getExistingConsole() {
     return builtInConsole;
 }
 export function getNewConsole() {
diff --git a/packages/insomnia-sdk/src/objects/environments.ts b/packages/insomnia-sdk/src/objects/environments.ts
index 14d03c4f5f6..d06f47cb804 100644
--- a/packages/insomnia-sdk/src/objects/environments.ts
+++ b/packages/insomnia-sdk/src/objects/environments.ts
@@ -1,4 +1,4 @@
-import { getConsole } from './console';
+import { getExistingConsole } from './console';
 import { getInterpolator } from './interpolator';
 
 export class Environment {
@@ -24,7 +24,7 @@ export class Environment {
 
     set = (variableName: string, variableValue: boolean | number | string | undefined | null) => {
         if (variableValue === null) {
-            getConsole().warn(`Variable "${variableName}" has a null value`);
+            getExistingConsole().warn(`Variable "${variableName}" has a null value`);
             return;
         }
         this.kvs.set(variableName, variableValue);
@@ -101,7 +101,7 @@ export class Variables {
 
     set = (variableName: string, variableValue: boolean | number | string | undefined | null) => {
         if (variableValue === null) {
-            getConsole().warn(`Variable "${variableName}" has a null value`);
+            getExistingConsole().warn(`Variable "${variableName}" has a null value`);
             return;
         }
 
diff --git a/packages/insomnia-sdk/src/objects/test.ts b/packages/insomnia-sdk/src/objects/test.ts
index d924fc82ec3..9ce051b2c25 100644
--- a/packages/insomnia-sdk/src/objects/test.ts
+++ b/packages/insomnia-sdk/src/objects/test.ts
@@ -20,7 +20,7 @@ export async function test(
             testCase: msg,
             status: 'failed',
             executionTime,
-            errorMessage: `${e}`,
+            errorMessage: `error: ${e} | ACTUAL: ${e.actual} | EXPECTED: ${e.expected}`,
             category: 'unknown',
         });
     }
diff --git a/packages/insomnia/src/scriptExecutor.ts b/packages/insomnia/src/scriptExecutor.ts
index 2b35e7cc1f1..3c4e02ed93c 100644
--- a/packages/insomnia/src/scriptExecutor.ts
+++ b/packages/insomnia/src/scriptExecutor.ts
@@ -1,7 +1,7 @@
 import { appendFile } from 'node:fs/promises';
 
 import { initInsomniaObject, InsomniaObject } from 'insomnia-sdk';
-import { Console, mergeClientCertificates, mergeCookieJar, mergeRequests, mergeSettings, type RequestContext } from 'insomnia-sdk';
+import { getNewConsole, mergeClientCertificates, mergeCookieJar, mergeRequests, mergeSettings, type RequestContext } from 'insomnia-sdk';
 import * as _ from 'lodash';
 
 import { invariant } from '../src/utils/invariant';
@@ -11,7 +11,7 @@ export const runScript = async (
   { script, context }: { script: string; context: RequestContext },
 ): Promise<RequestContext> => {
   // console.log(script);
-  const scriptConsole = new Console();
+  const scriptConsole = getNewConsole();
 
   const executionContext = await initInsomniaObject(context, scriptConsole.log);
 

From 99d35c6b5f726f6368589ca941cf296eb657da44 Mon Sep 17 00:00:00 2001
From: George He <hexxa@outlook.com>
Date: Fri, 17 Jan 2025 14:08:50 +0800
Subject: [PATCH 5/8] feat: support escape sequences for formatting in console

---
 packages/insomnia-sdk/src/objects/console.ts  | 23 ++++++++++++++++---
 .../after-response-script-features.test.ts    |  2 +-
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/packages/insomnia-sdk/src/objects/console.ts b/packages/insomnia-sdk/src/objects/console.ts
index 06056275785..507641ed0d0 100644
--- a/packages/insomnia-sdk/src/objects/console.ts
+++ b/packages/insomnia-sdk/src/objects/console.ts
@@ -6,6 +6,13 @@ export interface Row {
     timestamp: number;
 }
 
+const escapeMap: Record<string, string> = {
+    '\\f': '\f',
+    '\\n': '\n',
+    '\\t': '\t',
+    '\\v': '\v',
+};
+
 class Console {
     rows: Row[] = [];
 
@@ -14,10 +21,20 @@ class Console {
     // TODO: support replacing substitution
     printLog = (rows: Row[], level: LogLevel, ...values: any) => {
         try {
-            const content = values.map((a: any) => JSON.stringify(a, null, 2).replace('\\n', '\n'))
-                .join(' ');
+            const content = values.map(
+                (value: any) => {
+                    const valueStr = JSON.stringify(value, null, 2);
+
+                    let escapedValueStr = valueStr;
+                    Object.keys(escapeMap).forEach(toEscape => {
+                        escapedValueStr = escapedValueStr.replace(toEscape, escapeMap[toEscape]);
+                    });
+
+                    return escapedValueStr;
+                }
+            ).join(' ');
+
             const row = {
-                // TODO: also support formating e.g. \t
                 value: `${level}: ${content}`,
                 name: 'Text',
                 timestamp: Date.now(),
diff --git a/packages/insomnia-smoke-test/tests/smoke/after-response-script-features.test.ts b/packages/insomnia-smoke-test/tests/smoke/after-response-script-features.test.ts
index 984368e2627..acb4de82a49 100644
--- a/packages/insomnia-smoke-test/tests/smoke/after-response-script-features.test.ts
+++ b/packages/insomnia-smoke-test/tests/smoke/after-response-script-features.test.ts
@@ -29,7 +29,7 @@ test.describe('after-response script features tests', async () => {
 
         const responsePane = page.getByTestId('response-pane');
         await expect(responsePane).toContainText('PASS');
-        await expect(responsePane).toContainText('FAILunhappy tests | AssertionError: expected 199 to deeply equal 200After-response Test');
+        await expect(responsePane).toContainText('FAILunhappy tests | error: AssertionError: expected 199 to deeply equal 200 | ACTUAL: 199 | EXPECTED: 200');
     });
 
     test('environment and baseEnvironment can be persisted', async ({ page }) => {

From 37c9bdd98d86f76ed129c1001858fa1dad41cdf8 Mon Sep 17 00:00:00 2001
From: George He <hexxa@outlook.com>
Date: Fri, 17 Jan 2025 14:28:57 +0800
Subject: [PATCH 6/8] fix: update test ouput

---
 .../tests/smoke/pre-request-script-features.test.ts             | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/insomnia-smoke-test/tests/smoke/pre-request-script-features.test.ts b/packages/insomnia-smoke-test/tests/smoke/pre-request-script-features.test.ts
index c609eb132a6..75b769d2b7f 100644
--- a/packages/insomnia-smoke-test/tests/smoke/pre-request-script-features.test.ts
+++ b/packages/insomnia-smoke-test/tests/smoke/pre-request-script-features.test.ts
@@ -410,7 +410,7 @@ test.describe('pre-request features tests', async () => {
         await page.getByRole('tab', { name: 'Tests' }).click();
 
         const responsePane = page.getByTestId('response-pane');
-        expect(responsePane).toContainText('FAILunhappy tests | AssertionError: expected 199 to deeply equal 200Pre-request Test');
+        expect(responsePane).toContainText('FAILunhappy tests | error: AssertionError: expected 199 to deeply equal 200 | ACTUAL: 199 | EXPECTED: 200Pre-request Test');
         expect(responsePane).toContainText('PASShappy tests');
     });
 

From 9fbae4fac1f43acf544308e3ad8e9b88347e2b57 Mon Sep 17 00:00:00 2001
From: George He <hexxa@outlook.com>
Date: Fri, 17 Jan 2025 15:07:30 +0800
Subject: [PATCH 7/8] refactor: support escape seqs

---
 packages/insomnia-sdk/src/objects/console.ts | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/packages/insomnia-sdk/src/objects/console.ts b/packages/insomnia-sdk/src/objects/console.ts
index 507641ed0d0..dbb011af246 100644
--- a/packages/insomnia-sdk/src/objects/console.ts
+++ b/packages/insomnia-sdk/src/objects/console.ts
@@ -6,13 +6,6 @@ export interface Row {
     timestamp: number;
 }
 
-const escapeMap: Record<string, string> = {
-    '\\f': '\f',
-    '\\n': '\n',
-    '\\t': '\t',
-    '\\v': '\v',
-};
-
 class Console {
     rows: Row[] = [];
 
@@ -23,14 +16,7 @@ class Console {
         try {
             const content = values.map(
                 (value: any) => {
-                    const valueStr = JSON.stringify(value, null, 2);
-
-                    let escapedValueStr = valueStr;
-                    Object.keys(escapeMap).forEach(toEscape => {
-                        escapedValueStr = escapedValueStr.replace(toEscape, escapeMap[toEscape]);
-                    });
-
-                    return escapedValueStr;
+                    return typeof value === 'string' ? value : JSON.stringify(value, null, 2);
                 }
             ).join(' ');
 

From 42413812639f58f1602531ca164338fa4f197c60 Mon Sep 17 00:00:00 2001
From: George He <hexxa@outlook.com>
Date: Mon, 20 Jan 2025 11:45:09 +0800
Subject: [PATCH 8/8] fix: cli smoke test failed

---
 packages/insomnia-inso/src/cli.test.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/insomnia-inso/src/cli.test.ts b/packages/insomnia-inso/src/cli.test.ts
index 3dd73d95a04..9ba3e4a9b8d 100644
--- a/packages/insomnia-inso/src/cli.test.ts
+++ b/packages/insomnia-inso/src/cli.test.ts
@@ -116,7 +116,7 @@ describe('inso dev bundle', () => {
       if (result.code !== 0) {
         console.log(result);
       }
-      expect(result.stdout).toContain('log: "we did it: 200"');
+      expect(result.stdout).toContain('log: we did it: 200');
     });
 
     it('iterationData and iterationCount args work', async () => {