From 95f524bbcebef8e6f52a8f91c1fc56dd0b0be22c Mon Sep 17 00:00:00 2001 From: George He Date: Tue, 21 Jan 2025 17:13:23 +0800 Subject: [PATCH] fix(sdk): misc fixes and improvements (#8297) * fix: include multiline and fileName in the multipart req body * fix: reject setting null to insomnia.variables * fix: comment * fix: also update the scriptExecutor with getExistingConsole * feat: support escape sequences for formatting in console * fix: update test ouput * refactor: support escape seqs * fix: cli smoke test failed --- packages/insomnia-inso/src/cli.test.ts | 2 +- packages/insomnia-sdk/src/objects/console.ts | 19 ++++++++- .../insomnia-sdk/src/objects/environments.ts | 16 +++++-- packages/insomnia-sdk/src/objects/request.ts | 42 ++++++++++++++----- packages/insomnia-sdk/src/objects/response.ts | 3 +- packages/insomnia-sdk/src/objects/test.ts | 2 +- packages/insomnia-sdk/src/objects/urls.ts | 16 ++++++- .../after-response-script-features.test.ts | 2 +- .../smoke/pre-request-script-features.test.ts | 2 +- packages/insomnia/src/hidden-window.ts | 4 +- packages/insomnia/src/scriptExecutor.ts | 4 +- 11 files changed, 86 insertions(+), 26 deletions(-) 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 () => { diff --git a/packages/insomnia-sdk/src/objects/console.ts b/packages/insomnia-sdk/src/objects/console.ts index 2ca41908704..dbb011af246 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() { } @@ -14,8 +14,14 @@ export class Console { // TODO: support replacing substitution printLog = (rows: Row[], level: LogLevel, ...values: any) => { try { + const content = values.map( + (value: any) => { + return typeof value === 'string' ? value : JSON.stringify(value, null, 2); + } + ).join(' '); + const row = { - value: `${level}: ` + values.map((a: any) => JSON.stringify(a, null, 2)).join('\n'), + value: `${level}: ${content}`, name: 'Text', timestamp: Date.now(), }; @@ -66,3 +72,12 @@ export class Console { .map(row => JSON.stringify(row) + '\n'); }; } + +let builtInConsole = new Console(); +export function getExistingConsole() { + 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..d06f47cb804 100644 --- a/packages/insomnia-sdk/src/objects/environments.ts +++ b/packages/insomnia-sdk/src/objects/environments.ts @@ -1,8 +1,9 @@ +import { getExistingConsole } from './console'; import { getInterpolator } from './interpolator'; export class Environment { private _name: string; - private kvs = new Map(); + private kvs = new Map(); constructor(name: string, jsonObject: object | undefined) { this._name = name; @@ -21,7 +22,11 @@ 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) { + getExistingConsole().warn(`Variable "${variableName}" has a null value`); + return; + } this.kvs.set(variableName, variableValue); }; @@ -94,7 +99,12 @@ export class Variables { return finalVal; }; - set = (variableName: string, variableValue: boolean | number | string) => { + set = (variableName: string, variableValue: boolean | number | string | undefined | null) => { + if (variableValue === null) { + getExistingConsole().warn(`Variable "${variableName}" has a null value`); + return; + } + this.localVars.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, `; + 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/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-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-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 }) => { 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'); }); 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 => { - const scriptConsole = new Console(); + const scriptConsole = getNewConsole(); const executionContext = await initInsomniaObject(context, scriptConsole.log); 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 => { // console.log(script); - const scriptConsole = new Console(); + const scriptConsole = getNewConsole(); const executionContext = await initInsomniaObject(context, scriptConsole.log);