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 () => {