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
This commit is contained in:
George He
2025-01-21 17:13:23 +08:00
committed by GitHub
parent 78a97f4bfb
commit 95f524bbce
11 changed files with 86 additions and 26 deletions

View File

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

View File

@@ -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;
}

View File

@@ -1,8 +1,9 @@
import { getExistingConsole } from './console';
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;
@@ -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);
};

View File

@@ -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,
};
},
{},
),
};

View File

@@ -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}');

View File

@@ -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',
});
}

View File

@@ -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');
}

View File

@@ -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 }) => {

View File

@@ -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');
});

View File

@@ -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);

View File

@@ -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);