diff --git a/packages/insomnia-smoke-test/fixtures/pre-request-collection.yaml b/packages/insomnia-smoke-test/fixtures/pre-request-collection.yaml index d6beb5944..c5bbb3561 100644 --- a/packages/insomnia-smoke-test/fixtures/pre-request-collection.yaml +++ b/packages/insomnia-smoke-test/fixtures/pre-request-collection.yaml @@ -750,3 +750,49 @@ resources: "events": {{ _.events }} } _type: request + - _id: req_89dade2ee9ee42fbb22d588783a9df1 + parentId: fld_01de564274824ecaad272330339ea6b2 + modified: 1636707449231 + created: 1636141014552 + url: http://127.0.0.1:4010/echo + name: insomnia.test + description: "" + method: POST + parameters: [] + headers: + - name: 'Content-Type' + value: 'application/json' + authentication: {} + metaSortKey: -1636141014553 + isPrivate: false + settingStoreCookies: true + settingSendCookies: true + settingDisableRenderRequestBody: false + settingEncodeUrl: true + settingRebuildPath: true + settingFollowRedirects: global + preRequestScript: |- + insomnia.test('happy tests', () => { + pm.expect(200).to.eql(200); + pm.expect('uname').to.be.a('string'); + pm.expect('a').to.have.lengthOf(1); + pm.expect('xxx_customer_id_yyy').to.include("customer_id"); + pm.expect(201).to.be.oneOf([201,202]); + pm.expect(199).to.be.below(200); + // test objects + pm.expect({a: 1, b: 2}).to.have.all.keys('a', 'b'); + pm.expect({a: 1, b: 2}).to.have.any.keys('a', 'b'); + pm.expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd'); + pm.expect({a: 1}).to.have.property('a'); + pm.expect({a: 1, b: 2}).to.be.a('object') + .that.has.all.keys('a', 'b'); + }); + insomnia.test('unhappy tests', () => { + pm.expect(199).to.eql(200); + pm.expect(199).to.be.oneOf([201,202]); + }); + body: + mimeType: "application/json" + text: |- + {} + _type: request 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 247930fc2..2a028882b 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 @@ -344,6 +344,21 @@ test.describe('pre-request features tests', async () => { await page.getByRole('tab', { name: 'Timeline' }).click(); await expect(responsePane).toContainText('fixtures/certificates/fake.pfx'); // original proxy }); + + test('insomnia.test and insomnia.expect can work together ', async ({ page }) => { + const responsePane = page.getByTestId('response-pane'); + + await page.getByLabel('Request Collection').getByTestId('insomnia.test').press('Enter'); + + // send + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); + + // verify + await page.getByRole('tab', { name: 'Timeline' }).click(); + + await expect(responsePane).toContainText('✓ happy tests'); // original proxy + await expect(responsePane).toContainText('✕ unhappy tests: AssertionError: expected 199 to deeply equal 200'); // updated proxy + }); }); test.describe('unhappy paths', async () => { diff --git a/packages/insomnia/src/hidden-window.ts b/packages/insomnia/src/hidden-window.ts index c3db98cbe..a6f9f0cb1 100644 --- a/packages/insomnia/src/hidden-window.ts +++ b/packages/insomnia/src/hidden-window.ts @@ -36,9 +36,8 @@ const runPreRequestScript = async ( ): Promise => { console.log(script); - const executionContext = initInsomniaObject(context); - const log: string[] = []; // TODO: we should at least support info, debug, warn, error + const log: string[] = []; const consoleInterceptor = { log: (...args: any[]) => log.push( JSON.stringify({ @@ -49,6 +48,8 @@ const runPreRequestScript = async ( ), }; + const executionContext = initInsomniaObject(context, consoleInterceptor.log); + const evalInterceptor = (script: string) => { invariant(script && typeof script === 'string', 'eval is called with invalid or empty value'); const result = eval(script); diff --git a/packages/insomnia/src/sdk/objects/environments.ts b/packages/insomnia/src/sdk/objects/environments.ts index 9ed42f4cc..a98afab39 100644 --- a/packages/insomnia/src/sdk/objects/environments.ts +++ b/packages/insomnia/src/sdk/objects/environments.ts @@ -1,3 +1,4 @@ +import { getIntepolator } from './interpolator'; export class Environment { private kvs = new Map(); @@ -25,10 +26,9 @@ export class Environment { this.kvs.clear(); }; - // TODO: enable this after intepolator is introduced - // replaceIn = (template: string) => { - // return getIntepolator().render(template, this.toObject()); - // }; + replaceIn = (template: string) => { + return getIntepolator().render(template, this.toObject()); + }; toObject = () => { return Object.fromEntries(this.kvs.entries()); @@ -90,10 +90,10 @@ export class Variables { this.local.set(variableName, variableValue); }; - // replaceIn = (template: string) => { - // const context = this.toObject(); - // return getIntepolator().render(template, context); - // }; + replaceIn = (template: string) => { + const context = this.toObject(); + return getIntepolator().render(template, context); + }; toObject = () => { return [ diff --git a/packages/insomnia/src/sdk/objects/insomnia.ts b/packages/insomnia/src/sdk/objects/insomnia.ts index d5e969e5c..025804f1e 100644 --- a/packages/insomnia/src/sdk/objects/insomnia.ts +++ b/packages/insomnia/src/sdk/objects/insomnia.ts @@ -1,3 +1,5 @@ +import { expect } from 'chai'; + import { ClientCertificate } from '../../models/client-certificate'; import { RequestBodyParameter, RequestHeader } from '../../models/request'; import { Settings } from '../../models/settings'; @@ -8,6 +10,7 @@ import { unsupportedError } from './properties'; import { Request as ScriptRequest, RequestBodyOptions, RequestOptions } from './request'; import { Response as ScriptResponse } from './response'; import { sendRequest } from './send-request'; +import { test } from './test'; export class InsomniaObject { public environment: Environment; @@ -16,12 +19,16 @@ export class InsomniaObject { public variables: Variables; public request: ScriptRequest; private clientCertificates: ClientCertificate[]; + private _expect = expect; + private _test = test; // TODO: follows will be enabled after Insomnia supports them private _globals: Environment; private _iterationData: Environment; private _settings: Settings; + private _log: (...msgs: any[]) => void; + constructor( rawObj: { globals: Environment; @@ -33,6 +40,7 @@ export class InsomniaObject { settings: Settings; clientCertificates: ClientCertificate[]; }, + log: (...msgs: any[]) => void, ) { this._globals = rawObj.globals; this.environment = rawObj.environment; @@ -44,6 +52,8 @@ export class InsomniaObject { this.request = rawObj.request; this._settings = rawObj.settings; this.clientCertificates = rawObj.clientCertificates; + + this._log = log; } sendRequest( @@ -53,6 +63,14 @@ export class InsomniaObject { return sendRequest(request, cb, this._settings); } + test(msg: string, fn: () => void) { + this._test(msg, fn, this._log); + } + + expect(exp: boolean | number | string | object) { + return this._expect(exp); + } + // TODO: remove this after enabled globals get globals() { throw unsupportedError('globals', 'base environment'); @@ -84,6 +102,7 @@ export class InsomniaObject { export function initInsomniaObject( rawObj: RequestContext, + log: (...args: any[]) => void, ) { const globals = new Environment(rawObj.globals); const environment = new Environment(rawObj.environment); @@ -188,5 +207,6 @@ export function initInsomniaObject( settings: rawObj.settings, clientCertificates: rawObj.clientCertificates, }, + log, ); }; diff --git a/packages/insomnia/src/sdk/objects/interpolator.ts b/packages/insomnia/src/sdk/objects/interpolator.ts new file mode 100644 index 000000000..7d665aaaf --- /dev/null +++ b/packages/insomnia/src/sdk/objects/interpolator.ts @@ -0,0 +1,34 @@ +import { configure, type ConfigureOptions, type Environment as NunjuncksEnv } from 'nunjucks'; + +class Intepolator { + private engine: NunjuncksEnv; + + constructor(config: ConfigureOptions) { + this.engine = configure(config); + } + + render = (template: string, context: object) => { + // TODO: handle timeout + // TODO: support plugin? + return this.engine.renderString(template, context); + }; +} + +const intepolator = new Intepolator({ + autoescape: false, + // Don't escape HTML + throwOnUndefined: true, + // Strict mode + tags: { + blockStart: '{%', + blockEnd: '%}', + variableStart: '{{', + variableEnd: '}}', + commentStart: '{#', + commentEnd: '#}', + }, +}); + +export function getIntepolator() { + return intepolator; +} diff --git a/packages/insomnia/src/sdk/objects/request.ts b/packages/insomnia/src/sdk/objects/request.ts index 7ec0974c7..7d68b1f01 100644 --- a/packages/insomnia/src/sdk/objects/request.ts +++ b/packages/insomnia/src/sdk/objects/request.ts @@ -579,6 +579,7 @@ export function mergeRequests( {}, ), authentication: fromPreRequestAuth(updatedReq.auth), + preRequestScript: '', }; return { diff --git a/packages/insomnia/src/sdk/objects/test.ts b/packages/insomnia/src/sdk/objects/test.ts new file mode 100644 index 000000000..14b1e56eb --- /dev/null +++ b/packages/insomnia/src/sdk/objects/test.ts @@ -0,0 +1,12 @@ +export function test( + msg: string, + fn: () => void, + log: (message?: any, ...optionalParams: any[]) => void, +) { + try { + fn(); + log(`✓ ${msg}`); + } catch (e) { + log(`✕ ${msg}: ${e}`); + } +} diff --git a/packages/insomnia/src/ui/components/editors/pre-request-script-editor.tsx b/packages/insomnia/src/ui/components/editors/pre-request-script-editor.tsx index 6f179a3b6..1ab3cf563 100644 --- a/packages/insomnia/src/ui/components/editors/pre-request-script-editor.tsx +++ b/packages/insomnia/src/ui/components/editors/pre-request-script-editor.tsx @@ -172,7 +172,10 @@ export const PreRequestScriptEditor: FC = ({ }), settings, clientCertificates: [], - }), + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + (_msg: string, _fn: () => void) => { } + ), 'insomnia', );