mirror of
https://github.com/Kong/insomnia.git
synced 2026-05-18 21:55:38 -04:00
feat: enable major features of the after-response script (#7411)
* feat: update data model and request-pane to support post-req-script * fix: unit test failed * feat: integrate post-request script to the engine - INS-3785,INS-3786 (#7329) * feat: integrate post-request script to the engine * refactor: some minor improvements * fix: lint error * chore: clean up typings * refactor: separate transforming into sync and async parts * use named args * fix: renaming pre-req vars, functions and 2 minor fixes * fix: the error message is updated * feat: add snippets for post-request scripting (#7395) * feat: enable extended assertion chains on `insomnia.response` (#7396) * feat: add snippets for post-request scripting * feat(sdk): support response.to.have assertion for verifying response * chore: fix lint error --------- Co-authored-by: jackkav <jackkav@gmail.com> * test: add tests for post-request scripts and post-request scripts - INS-3786 (#7331) * test: add some tests for post-req script and script engine * fix: incorrect script type * chore: refresh package-lock after merging * chore: clean up package-lock.json * fix: failed tests after rebasing * feat: support importing post-req script from Postman (#7423) * feat: support importing post-req script from Postman * fix: introduce post-req script property for merged changes * test: add a test case for importing scripts * fix: add missing fixture * chore: remove row after merging * chore: rename to after-response-script * fix test * refresh lock * update snapshot * extract pre request logic to function * refresh lock again * throw on base env * fix: revert the logic which rejects the case of unselected environment --------- Co-authored-by: jackkav <jackkav@gmail.com>
This commit is contained in:
44
package-lock.json
generated
44
package-lock.json
generated
@@ -5837,8 +5837,7 @@
|
||||
"node_modules/@types/deep-equal": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/deep-equal/-/deep-equal-1.0.4.tgz",
|
||||
"integrity": "sha512-tqdiS4otQP4KmY0PR3u6KbZ5EWvhNdUoS/jc93UuK23C220lOZ/9TvjfxdPcKvqwwDVtmtSCrnr0p/2dirAxkA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-tqdiS4otQP4KmY0PR3u6KbZ5EWvhNdUoS/jc93UuK23C220lOZ/9TvjfxdPcKvqwwDVtmtSCrnr0p/2dirAxkA=="
|
||||
},
|
||||
"node_modules/@types/dompurify": {
|
||||
"version": "3.0.5",
|
||||
@@ -10470,7 +10469,6 @@
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
|
||||
"integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"get-intrinsic": "^1.1.3",
|
||||
@@ -13438,7 +13436,6 @@
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
|
||||
"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -13551,7 +13548,6 @@
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
|
||||
"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -13642,7 +13638,6 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
|
||||
"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -13665,7 +13660,6 @@
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
|
||||
"integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"get-intrinsic": "^1.2.4"
|
||||
@@ -17174,7 +17168,6 @@
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
|
||||
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1"
|
||||
@@ -20114,7 +20107,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
|
||||
"integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"internal-slot": "^1.0.4"
|
||||
},
|
||||
@@ -22243,7 +22235,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
|
||||
"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-map": "^2.0.3",
|
||||
"is-set": "^2.0.3",
|
||||
@@ -23265,6 +23256,7 @@
|
||||
"version": "9.2.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/deep-equal": "^1.0.4",
|
||||
"@types/tv4": "^1.2.33",
|
||||
"@types/xml2js": "^0.4.14",
|
||||
"ajv": "^8.12.0",
|
||||
@@ -23272,6 +23264,7 @@
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"crypto-js": "^4.2.0",
|
||||
"csv-parse": "^5.5.5",
|
||||
"deep-equal": "^2.2.3",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.30.1",
|
||||
"tv4": "^1.3.0",
|
||||
@@ -23318,6 +23311,37 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"packages/insomnia-sdk/node_modules/deep-equal": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
|
||||
"integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==",
|
||||
"dependencies": {
|
||||
"array-buffer-byte-length": "^1.0.0",
|
||||
"call-bind": "^1.0.5",
|
||||
"es-get-iterator": "^1.1.3",
|
||||
"get-intrinsic": "^1.2.2",
|
||||
"is-arguments": "^1.1.1",
|
||||
"is-array-buffer": "^3.0.2",
|
||||
"is-date-object": "^1.0.5",
|
||||
"is-regex": "^1.1.4",
|
||||
"is-shared-array-buffer": "^1.0.2",
|
||||
"isarray": "^2.0.5",
|
||||
"object-is": "^1.1.5",
|
||||
"object-keys": "^1.1.1",
|
||||
"object.assign": "^4.1.4",
|
||||
"regexp.prototype.flags": "^1.5.1",
|
||||
"side-channel": "^1.0.4",
|
||||
"which-boxed-primitive": "^1.0.2",
|
||||
"which-collection": "^1.0.1",
|
||||
"which-typed-array": "^1.1.13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"packages/insomnia-sdk/node_modules/loupe": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.0.tgz",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/Kong/insomnia#readme",
|
||||
"dependencies": {
|
||||
"@types/deep-equal": "^1.0.4",
|
||||
"@types/tv4": "^1.2.33",
|
||||
"@types/xml2js": "^0.4.14",
|
||||
"ajv": "^8.12.0",
|
||||
@@ -27,6 +28,7 @@
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"crypto-js": "^4.2.0",
|
||||
"csv-parse": "^5.5.5",
|
||||
"deep-equal": "^2.2.3",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.30.1",
|
||||
"tv4": "^1.3.0",
|
||||
|
||||
@@ -62,5 +62,12 @@ describe('test request and response objects', () => {
|
||||
mimeFormat: '',
|
||||
mimeType: 'text/plain',
|
||||
});
|
||||
|
||||
// extended assertion chains
|
||||
resp.to.have.status(200);
|
||||
resp.to.have.status('OK');
|
||||
resp.to.have.header('header1');
|
||||
resp.to.have.jsonBody({ 'key': 888 });
|
||||
resp.to.have.body('{"key": 888}');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ import { unsupportedError } from './properties';
|
||||
import { Request as ScriptRequest, RequestOptions, toScriptRequestBody } from './request';
|
||||
import { RequestInfo } from './request-info';
|
||||
import { Response as ScriptResponse } from './response';
|
||||
import { readBodyFromPath, toScriptResponse } from './response';
|
||||
import { sendRequest } from './send-request';
|
||||
import { test } from './test';
|
||||
import { toUrlObject } from './urls';
|
||||
@@ -23,6 +24,7 @@ export class InsomniaObject {
|
||||
public request: ScriptRequest;
|
||||
public cookies: CookieObject;
|
||||
public info: RequestInfo;
|
||||
public response?: ScriptResponse;
|
||||
|
||||
private clientCertificates: ClientCertificate[];
|
||||
private _expect = expect;
|
||||
@@ -47,6 +49,7 @@ export class InsomniaObject {
|
||||
clientCertificates: ClientCertificate[];
|
||||
cookies: CookieObject;
|
||||
requestInfo: RequestInfo;
|
||||
response?: ScriptResponse;
|
||||
},
|
||||
log: (...msgs: any[]) => void,
|
||||
) {
|
||||
@@ -57,6 +60,7 @@ export class InsomniaObject {
|
||||
this._iterationData = rawObj.iterationData;
|
||||
this.variables = rawObj.variables;
|
||||
this.cookies = rawObj.cookies;
|
||||
this.response = rawObj.response;
|
||||
|
||||
this.info = rawObj.requestInfo;
|
||||
this.request = rawObj.request;
|
||||
@@ -108,11 +112,12 @@ export class InsomniaObject {
|
||||
clientCertificates: this.clientCertificates,
|
||||
cookieJar: this.cookies.jar().toInsomniaCookieJar(),
|
||||
info: this.info.toObject(),
|
||||
response: this.response ? this.response.toObject() : undefined,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function initInsomniaObject(
|
||||
export async function initInsomniaObject(
|
||||
rawObj: RequestContext,
|
||||
log: (...args: any[]) => void,
|
||||
) {
|
||||
@@ -206,6 +211,9 @@ export function initInsomniaObject(
|
||||
};
|
||||
const request = new ScriptRequest(reqOpt);
|
||||
|
||||
const responseBody = await readBodyFromPath(rawObj.response);
|
||||
const response = rawObj.response ? toScriptResponse(request, rawObj.response, responseBody) : undefined;
|
||||
|
||||
return new InsomniaObject(
|
||||
{
|
||||
globals,
|
||||
@@ -218,6 +226,7 @@ export function initInsomniaObject(
|
||||
clientCertificates: rawObj.clientCertificates,
|
||||
cookies,
|
||||
requestInfo,
|
||||
response,
|
||||
},
|
||||
log,
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { CookieJar as InsomniaCookieJar } from 'insomnia/src//models/cookie-jar'
|
||||
import { ClientCertificate } from 'insomnia/src/models/client-certificate';
|
||||
import type { Request } from 'insomnia/src/models/request';
|
||||
import { Settings } from 'insomnia/src/models/settings';
|
||||
import { sendCurlAndWriteTimelineError, sendCurlAndWriteTimelineResponse } from 'insomnia/src/network/network';
|
||||
|
||||
export interface RequestContext {
|
||||
request: Request;
|
||||
@@ -17,4 +18,6 @@ export interface RequestContext {
|
||||
settings: Settings;
|
||||
clientCertificates: ClientCertificate[];
|
||||
cookieJar: InsomniaCookieJar;
|
||||
// only for the after-response script
|
||||
response?: sendCurlAndWriteTimelineResponse | sendCurlAndWriteTimelineError;
|
||||
}
|
||||
|
||||
@@ -593,7 +593,7 @@ export function mergeRequestBody(
|
||||
|
||||
try {
|
||||
const textContent = updatedReqBody?.raw ? updatedReqBody?.raw :
|
||||
updatedReqBody?.graphql ? JSON.stringify(updatedReqBody?.graphql) : '';
|
||||
updatedReqBody?.graphql ? JSON.stringify(updatedReqBody?.graphql) : undefined;
|
||||
|
||||
return {
|
||||
mimeType: mimeType,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import deepEqual from 'deep-equal';
|
||||
import { RESPONSE_CODE_REASONS } from 'insomnia/src/common/constants';
|
||||
import { sendCurlAndWriteTimelineError, type sendCurlAndWriteTimelineResponse } from 'insomnia/src/network/network';
|
||||
|
||||
import { Cookie, CookieOptions } from './cookies';
|
||||
import { CookieList } from './cookies';
|
||||
@@ -15,7 +17,6 @@ export interface ResponseOptions {
|
||||
// ideally it should work in both browser and node
|
||||
stream?: Buffer | ArrayBuffer;
|
||||
responseTime: number;
|
||||
status?: string;
|
||||
originalRequest: Request;
|
||||
}
|
||||
|
||||
@@ -57,7 +58,7 @@ export class Response extends Property {
|
||||
);
|
||||
this.originalRequest = options.originalRequest;
|
||||
this.responseTime = options.responseTime;
|
||||
this.status = RESPONSE_CODE_REASONS[options.code];
|
||||
this.status = options.reason || RESPONSE_CODE_REASONS[options.code];
|
||||
this.stream = options.stream;
|
||||
}
|
||||
|
||||
@@ -80,7 +81,7 @@ export class Response extends Property {
|
||||
stream: response.stream,
|
||||
header: response.headers,
|
||||
code: response.statusCode,
|
||||
status: response.statusMessage,
|
||||
reason: response.statusMessage,
|
||||
responseTime: response.elapsedTime,
|
||||
originalRequest: response.originalRequest,
|
||||
});
|
||||
@@ -155,7 +156,7 @@ export class Response extends Property {
|
||||
try {
|
||||
return JSON.parse(this.body.toString(), reviver);
|
||||
} catch (e) {
|
||||
throw Error(`json: faile to parse: ${e}`);
|
||||
throw Error(`json: failed to parse: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,4 +183,104 @@ export class Response extends Property {
|
||||
text() {
|
||||
return this.body.toString();
|
||||
}
|
||||
|
||||
// Besides chai.expect, "to" is extended to support cases like:
|
||||
// insomnia.response.to.have.status(200);
|
||||
get to() {
|
||||
type valueType = boolean | number | string | object | undefined;
|
||||
const verify = (got: valueType, expected: valueType) => {
|
||||
if (['boolean', 'number', 'string', 'undefined'].includes(typeof got) && expected === got) {
|
||||
return;
|
||||
} else if (deepEqual(got, expected, { strict: true })) {
|
||||
return;
|
||||
}
|
||||
throw Error(`"${got}" is not equal to the expected value: "${expected}"`);
|
||||
};
|
||||
|
||||
return {
|
||||
// follows extend chai's chains for compatibility
|
||||
have: {
|
||||
status: (expected: number | string) => {
|
||||
if (typeof expected === 'string') {
|
||||
verify(this.status, expected);
|
||||
} else {
|
||||
verify(this.code, expected);
|
||||
}
|
||||
},
|
||||
header: (expected: string) => verify(
|
||||
this.headers.toObject().find(header => header.key === expected) !== undefined,
|
||||
true,
|
||||
),
|
||||
|
||||
body: (expected: string) => verify(this.text(), expected),
|
||||
jsonBody: (expected: object) => verify(this.json(), expected),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function toScriptResponse(
|
||||
originalRequest: Request,
|
||||
partialInsoResponse: sendCurlAndWriteTimelineResponse | sendCurlAndWriteTimelineError,
|
||||
responseBody: string,
|
||||
): Response | undefined {
|
||||
if ('error' in partialInsoResponse) {
|
||||
// it is sendCurlAndWriteTimelineError and basically doesn't contain anything useful
|
||||
return undefined;
|
||||
}
|
||||
const partialResponse = partialInsoResponse as sendCurlAndWriteTimelineResponse;
|
||||
|
||||
const headers = partialResponse.headers ?
|
||||
partialResponse.headers.map(
|
||||
insoHeader => ({
|
||||
key: insoHeader.name,
|
||||
value: insoHeader.value,
|
||||
}),
|
||||
{},
|
||||
)
|
||||
: [];
|
||||
|
||||
const insoCookieOptions = partialResponse.headers ?
|
||||
partialResponse.headers
|
||||
.filter(
|
||||
header => {
|
||||
return header.name.toLowerCase() === 'set-cookie';
|
||||
},
|
||||
{},
|
||||
).map(
|
||||
setCookieHeader => Cookie.parse(setCookieHeader.value)
|
||||
)
|
||||
: [];
|
||||
|
||||
const responseOption = {
|
||||
code: partialResponse.statusCode || 0,
|
||||
reason: partialResponse.statusMessage,
|
||||
header: headers,
|
||||
cookie: insoCookieOptions,
|
||||
body: responseBody,
|
||||
// stream is duplicated with body
|
||||
responseTime: partialResponse.elapsedTime,
|
||||
originalRequest,
|
||||
};
|
||||
|
||||
return new Response(responseOption);
|
||||
};
|
||||
|
||||
export async function readBodyFromPath(response: sendCurlAndWriteTimelineResponse | sendCurlAndWriteTimelineError | undefined) {
|
||||
// it allows to execute scripts (e.g., for testing) but body contains nothing
|
||||
if (!response || 'error' in response) {
|
||||
return '';
|
||||
} else if (!response.bodyPath) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const readResponseResult = await window.bridge.readCurlResponse({
|
||||
bodyPath: response.bodyPath,
|
||||
bodyCompression: response.bodyCompression,
|
||||
});
|
||||
|
||||
if (readResponseResult.error) {
|
||||
throw Error(`Failed to read body: ${readResponseResult.error}`);
|
||||
}
|
||||
return readResponseResult.body;
|
||||
}
|
||||
|
||||
@@ -244,7 +244,6 @@ async function curlOutputToResponse(
|
||||
body: '',
|
||||
stream: undefined,
|
||||
responseTime: result.patch.elapsedTime,
|
||||
status: lastRedirect.reason,
|
||||
originalRequest,
|
||||
});
|
||||
}
|
||||
@@ -266,7 +265,6 @@ async function curlOutputToResponse(
|
||||
// because it is inaccurate to differentiate if body is binary
|
||||
stream: undefined,
|
||||
responseTime: result.patch.elapsedTime,
|
||||
status: lastRedirect.reason,
|
||||
originalRequest,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
_type: export
|
||||
__export_format: 4
|
||||
__export_date: 2024-02-13T07:27:17.322Z
|
||||
__export_source: insomnia.desktop.app:v8.6.1
|
||||
resources:
|
||||
- _id: wrk_6b9b8455fd784462ae19cd51d7156f86
|
||||
parentId: null
|
||||
modified: 1707808692801
|
||||
created: 1707808692801
|
||||
name: After-response Scripts
|
||||
description: ""
|
||||
scope: collection
|
||||
_type: workspace
|
||||
- _id: req_244fe815da6c4342a17f0cfd98cf648c
|
||||
parentId: wrk_6b9b8455fd784462ae19cd51d7156f86
|
||||
modified: 1707809218855
|
||||
created: 1707808697304
|
||||
url: http://127.0.0.1:4010/echo
|
||||
name: tests with expect and test
|
||||
description: ""
|
||||
method: POST
|
||||
afterResponseScript: |-
|
||||
insomnia.test('happy tests', () => {
|
||||
insomnia.expect(200).to.eql(200);
|
||||
insomnia.expect('uname').to.be.a('string');
|
||||
insomnia.expect('a').to.have.lengthOf(1);
|
||||
insomnia.expect('xxx_customer_id_yyy').to.include("customer_id");
|
||||
insomnia.expect(201).to.be.oneOf([201,202]);
|
||||
insomnia.expect(199).to.be.below(200);
|
||||
// test objects
|
||||
insomnia.expect({a: 1, b: 2}).to.have.all.keys('a', 'b');
|
||||
insomnia.expect({a: 1, b: 2}).to.have.any.keys('a', 'b');
|
||||
insomnia.expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd');
|
||||
insomnia.expect({a: 1}).to.have.property('a');
|
||||
insomnia.expect({a: 1, b: 2}).to.be.a('object')
|
||||
.that.has.all.keys('a', 'b');
|
||||
});
|
||||
insomnia.test('unhappy tests', () => {
|
||||
insomnia.expect(199).to.eql(200);
|
||||
insomnia.expect(199).to.be.oneOf([201,202]);
|
||||
});
|
||||
body:
|
||||
mimeType: "application/json"
|
||||
text: |-
|
||||
{}
|
||||
parameters: []
|
||||
headers:
|
||||
- name: 'Content-Type'
|
||||
value: 'application/json'
|
||||
authentication: {}
|
||||
metaSortKey: -1707809028499
|
||||
isPrivate: false
|
||||
pathParameters: []
|
||||
settingStoreCookies: true
|
||||
settingSendCookies: true
|
||||
settingDisableRenderRequestBody: false
|
||||
settingEncodeUrl: true
|
||||
settingRebuildPath: true
|
||||
settingFollowRedirects: global
|
||||
_type: request
|
||||
- _id: req_244fe815da6c4342a17f0cfd98cf6401
|
||||
parentId: wrk_6b9b8455fd784462ae19cd51d7156f86
|
||||
modified: 1707809218855
|
||||
created: 1707808697304
|
||||
url: http://127.0.0.1:4010/echo
|
||||
name: persist environments
|
||||
description: ""
|
||||
method: POST
|
||||
afterResponseScript: |-
|
||||
insomnia.environment.set('__fromAfterScript', 'environment');
|
||||
insomnia.baseEnvironment.set('__fromAfterScript1', 'baseEnvironment');
|
||||
insomnia.collectionVariables.set('__fromAfterScript2', 'collection');
|
||||
body:
|
||||
mimeType: "application/json"
|
||||
text: |-
|
||||
{}
|
||||
parameters: []
|
||||
headers:
|
||||
- name: 'Content-Type'
|
||||
value: 'application/json'
|
||||
authentication: {}
|
||||
metaSortKey: -1707809028499
|
||||
isPrivate: false
|
||||
pathParameters: []
|
||||
settingStoreCookies: true
|
||||
settingSendCookies: true
|
||||
settingDisableRenderRequestBody: false
|
||||
settingEncodeUrl: true
|
||||
settingRebuildPath: true
|
||||
settingFollowRedirects: global
|
||||
_type: request
|
||||
- _id: env_f9ef1d097c5e00986051fcb4f7a921eea1a86916
|
||||
parentId: wrk_6b9b8455fd784462ae19cd51d7156f86
|
||||
modified: 1707808692805
|
||||
created: 1707808692805
|
||||
name: Base Environment
|
||||
data: {}
|
||||
dataPropertyOrder: null
|
||||
color: null
|
||||
isPrivate: false
|
||||
metaSortKey: 1707808692805
|
||||
_type: environment
|
||||
- _id: jar_f9ef1d097c5e00986051fcb4f7a921eea1a86916
|
||||
parentId: wrk_6b9b8455fd784462ae19cd51d7156f86
|
||||
modified: 1707808692807
|
||||
created: 1707808692807
|
||||
name: Default Jar
|
||||
cookies: []
|
||||
_type: cookie_jar
|
||||
@@ -0,0 +1,60 @@
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
import { loadFixture } from '../../playwright/paths';
|
||||
import { test } from '../../playwright/test';;
|
||||
|
||||
test.describe('after-response script features tests', async () => {
|
||||
test.slow(process.platform === 'darwin' || process.platform === 'win32', 'Slow app start on these platforms');
|
||||
|
||||
test.beforeEach(async ({ app, page }) => {
|
||||
const text = await loadFixture('after-response-collection.yaml');
|
||||
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
|
||||
|
||||
await page.getByRole('button', { name: 'Create in project' }).click();
|
||||
await page.getByRole('menuitemradio', { name: 'Import' }).click();
|
||||
await page.locator('[data-test-id="import-from-clipboard"]').click();
|
||||
await page.getByRole('button', { name: 'Scan' }).click();
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
|
||||
|
||||
await page.getByLabel('After-response Scripts').click();
|
||||
});
|
||||
|
||||
test('insomnia.test and insomnia.expect can work together', async ({ page }) => {
|
||||
const responsePane = page.getByTestId('response-pane');
|
||||
|
||||
await page.getByLabel('Request Collection').getByTestId('tests with expect and 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');
|
||||
await expect(responsePane).toContainText('✕ unhappy tests: AssertionError: expected 199 to deeply equal 200');
|
||||
});
|
||||
|
||||
test('environment and baseEnvironment can be persisted', async ({ page }) => {
|
||||
const statusTag = page.locator('[data-testid="response-status-tag"]:visible');
|
||||
await page.getByLabel('Request Collection').getByTestId('persist environments').press('Enter');
|
||||
|
||||
// send
|
||||
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
|
||||
|
||||
// verify response
|
||||
await page.waitForSelector('[data-testid="response-status-tag"]:visible');
|
||||
await expect(statusTag).toContainText('200 OK');
|
||||
|
||||
// verify persisted environment
|
||||
await page.getByLabel('Manage Environments').click();
|
||||
const responseBody = page.getByRole('dialog').getByTestId('CodeEditor').locator('.CodeMirror-line');
|
||||
const rows = await responseBody.allInnerTexts();
|
||||
const bodyJson = JSON.parse(rows.join(' '));
|
||||
|
||||
expect(bodyJson).toEqual({
|
||||
// no environment is selected so the environment value is not persisted
|
||||
'__fromAfterScript1': 'baseEnvironment',
|
||||
'__fromAfterScript2': 'collection',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -405,8 +405,8 @@ test.describe('pre-request features tests', async () => {
|
||||
// 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
|
||||
await expect(responsePane).toContainText('✓ happy tests');
|
||||
await expect(responsePane).toContainText('✕ unhappy tests: AssertionError: expected 199 to deeply equal 200');
|
||||
});
|
||||
|
||||
test('environment and baseEnvironment can be persisted', async ({ page }) => {
|
||||
|
||||
@@ -96,3 +96,37 @@ test.describe('test hidden window handling', async () => {
|
||||
await expect(statusTag).toContainText('200 OK');
|
||||
});
|
||||
});
|
||||
|
||||
test('window should be restarted if it hangs', async ({ app, page }) => {
|
||||
test.slow(process.platform === 'darwin' || process.platform === 'win32', 'Slow app start on these platforms');
|
||||
|
||||
// load collection
|
||||
const text = await loadFixture('pre-request-collection.yaml');
|
||||
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
|
||||
|
||||
await page.getByRole('button', { name: 'Create in project' }).click();
|
||||
await page.getByRole('menuitemradio', { name: 'Import' }).click();
|
||||
await page.locator('[data-test-id="import-from-clipboard"]').click();
|
||||
await page.getByRole('button', { name: 'Scan' }).click();
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
|
||||
|
||||
// update timeout
|
||||
await page.getByTestId('settings-button').click();
|
||||
await page.getByLabel('Request timeout (ms)').fill('100');
|
||||
await page.getByRole('button', { name: '' }).click();
|
||||
|
||||
// send the request with infinite loop script
|
||||
await page.getByText('Pre-request Scripts').click();
|
||||
await page.getByLabel('Request Collection').getByTestId('infinite loop').press('Enter');
|
||||
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
|
||||
await page.getByText('Timeout: Hidden browser window is not responding').click();
|
||||
|
||||
// send the another script with normal script
|
||||
await page.getByLabel('Request Collection').getByTestId('simple log').press('Enter');
|
||||
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
|
||||
|
||||
// it should still work
|
||||
const statusTag = page.locator('[data-testid="response-status-tag"]:visible');
|
||||
await page.waitForSelector('[data-testid="response-status-tag"]:visible');
|
||||
await expect(statusTag).toContainText('200 OK');
|
||||
});
|
||||
|
||||
@@ -200,7 +200,7 @@ describe('requestCreate()', () => {
|
||||
parentId: 'wrk_123',
|
||||
};
|
||||
const r = await models.request.create(patch);
|
||||
expect(Object.keys(r).length).toBe(23);
|
||||
expect(Object.keys(r).length).toBe(24);
|
||||
expect(r._id).toMatch(/^req_[a-zA-Z0-9]{32}$/);
|
||||
expect(r.created).toBeGreaterThanOrEqual(now);
|
||||
expect(r.modified).toBeGreaterThanOrEqual(now);
|
||||
|
||||
@@ -576,6 +576,7 @@ export async function getRenderedRequestAndContext(
|
||||
type: renderedRequest.type,
|
||||
url: renderedRequest.url,
|
||||
preRequestScript: renderedRequest.preRequestScript,
|
||||
afterResponseScript: renderedRequest.afterResponseScript,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export interface HiddenBrowserWindowToMainBridgeAPI {
|
||||
curlRequest: (options: any) => Promise<any>;
|
||||
readCurlResponse: (options: { bodyPath: string; bodyCompression: Compression }) => Promise<{ body: string; error: string }>;
|
||||
setBusy: (busy: boolean) => void;
|
||||
writeFile: (logPath: string, logContent: string) => Promise<void>;
|
||||
appendFile: (logPath: string, logContent: string) => Promise<void>;
|
||||
asyncTasksAllSettled: () => Promise<void>;
|
||||
resetAsyncTasks: () => void;
|
||||
stopMonitorAsyncTasks: () => void;
|
||||
@@ -115,8 +115,8 @@ const bridge: HiddenBrowserWindowToMainBridgeAPI = {
|
||||
setBusy: busy => ipcRenderer.send('set-hidden-window-busy-status', busy),
|
||||
// TODO: following methods are for simulating current behavior of running async tasks
|
||||
// in the future, it should be better to keep standard way of handling async tasks to avoid confusion
|
||||
writeFile: (logPath: string, logContent: string) => {
|
||||
return fs.promises.writeFile(logPath, logContent);
|
||||
appendFile: (logPath: string, logContent: string) => {
|
||||
return fs.promises.appendFile(logPath, logContent);
|
||||
},
|
||||
Promise: OriginalPromise,
|
||||
asyncTasksAllSettled,
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as _ from 'lodash';
|
||||
import { invariant } from '../src/utils/invariant';
|
||||
|
||||
export interface HiddenBrowserWindowBridgeAPI {
|
||||
runPreRequestScript: (options: { script: string; context: RequestContext }) => Promise<RequestContext>;
|
||||
runScript: (options: { script: string; context: RequestContext }) => Promise<RequestContext>;
|
||||
};
|
||||
|
||||
window.bridge.onmessage(async (data, callback) => {
|
||||
@@ -18,7 +18,7 @@ window.bridge.onmessage(async (data, callback) => {
|
||||
resolve({ error: 'Timeout: Running script took too long' });
|
||||
}, timeout);
|
||||
});
|
||||
const result = await window.bridge.Promise.race([timeoutPromise, runPreRequestScript(data)]);
|
||||
const result = await window.bridge.Promise.race([timeoutPromise, runScript(data)]);
|
||||
callback(result);
|
||||
} catch (err) {
|
||||
console.error('error', err);
|
||||
@@ -28,13 +28,13 @@ window.bridge.onmessage(async (data, callback) => {
|
||||
}
|
||||
});
|
||||
|
||||
const runPreRequestScript = async (
|
||||
const runScript = async (
|
||||
{ script, context }: { script: string; context: RequestContext },
|
||||
): Promise<RequestContext> => {
|
||||
console.log(script);
|
||||
const scriptConsole = new Console();
|
||||
|
||||
const executionContext = initInsomniaObject(context, scriptConsole.log);
|
||||
const executionContext = await initInsomniaObject(context, scriptConsole.log);
|
||||
|
||||
const evalInterceptor = (script: string) => {
|
||||
invariant(script && typeof script === 'string', 'eval is called with invalid or empty value');
|
||||
@@ -83,7 +83,7 @@ const runPreRequestScript = async (
|
||||
const updatedCertificates = mergeClientCertificates(context.clientCertificates, mutatedContextObject.request);
|
||||
const updatedCookieJar = mergeCookieJar(context.cookieJar, mutatedContextObject.cookieJar);
|
||||
|
||||
await window.bridge.writeFile(context.timelinePath, scriptConsole.dumpLogs());
|
||||
await window.bridge.appendFile(context.timelinePath, scriptConsole.dumpLogs());
|
||||
|
||||
console.log('mutatedInsomniaObject', mutatedContextObject);
|
||||
console.log('context', context);
|
||||
|
||||
@@ -22,6 +22,7 @@ describe('init()', () => {
|
||||
parameters: [],
|
||||
pathParameters: [],
|
||||
preRequestScript: '',
|
||||
afterResponseScript: '',
|
||||
url: '',
|
||||
settingStoreCookies: true,
|
||||
settingSendCookies: true,
|
||||
@@ -60,6 +61,7 @@ describe('create()', () => {
|
||||
parameters: [],
|
||||
pathParameters: [],
|
||||
preRequestScript: '',
|
||||
afterResponseScript: '',
|
||||
url: '',
|
||||
settingStoreCookies: true,
|
||||
settingSendCookies: true,
|
||||
@@ -394,6 +396,7 @@ describe('migrate()', () => {
|
||||
parameters: [],
|
||||
pathParameters: [],
|
||||
preRequestScript: '',
|
||||
afterResponseScript: '',
|
||||
parentId: null,
|
||||
body: {
|
||||
mimeType: '',
|
||||
|
||||
@@ -252,6 +252,7 @@ export interface BaseRequest {
|
||||
method: string;
|
||||
body: RequestBody;
|
||||
preRequestScript: string;
|
||||
afterResponseScript: string;
|
||||
parameters: RequestParameter[];
|
||||
pathParameters: RequestPathParameter[];
|
||||
headers: RequestHeader[];
|
||||
@@ -289,6 +290,7 @@ export function init(): BaseRequest {
|
||||
method: METHOD_GET,
|
||||
body: {},
|
||||
preRequestScript: '',
|
||||
afterResponseScript: '',
|
||||
parameters: [],
|
||||
headers: [],
|
||||
authentication: {},
|
||||
|
||||
@@ -14,7 +14,7 @@ export async function cancelRequestById(requestId: string) {
|
||||
console.log(`[network] Failed to cancel req=${requestId} because cancel function not found`);
|
||||
}
|
||||
|
||||
export const cancellableRunPreRequestScript = async (options: { script: string; context: RequestContext }) => {
|
||||
export const cancellableRunScript = async (options: { script: string; context: RequestContext }) => {
|
||||
const request = options.context.request;
|
||||
const requestId = request._id;
|
||||
|
||||
@@ -28,7 +28,7 @@ export const cancellableRunPreRequestScript = async (options: { script: string;
|
||||
try {
|
||||
const result = await cancellablePromise({
|
||||
signal: controller.signal,
|
||||
fn: window.main.hiddenBrowserWindow.runPreRequestScript(options),
|
||||
fn: window.main.hiddenBrowserWindow.runScript(options),
|
||||
});
|
||||
|
||||
return result as {
|
||||
|
||||
@@ -37,7 +37,7 @@ import {
|
||||
smartEncodeUrl,
|
||||
} from '../utils/url/querystring';
|
||||
import { getAuthHeader, getAuthObjectOrNull, getAuthQueryParams, isAuthEnabled } from './authentication';
|
||||
import { cancellableCurlRequest, cancellableRunPreRequestScript } from './cancellation';
|
||||
import { cancellableCurlRequest, cancellableRunScript } from './cancellation';
|
||||
import { filterClientCertificates } from './certificate';
|
||||
import { addSetCookiesToToughCookieJar } from './set-cookie-util';
|
||||
|
||||
@@ -104,23 +104,93 @@ export const fetchRequestData = async (requestId: string) => {
|
||||
const timelinePath = pathJoin(responsesDir, responseId + '.timeline');
|
||||
return { request, environment, settings, clientCertificates, caCert, activeEnvironmentId, timelinePath, responseId };
|
||||
};
|
||||
export const getPreRequestScriptOutput = async ({
|
||||
request,
|
||||
environment,
|
||||
settings,
|
||||
clientCertificates,
|
||||
timelinePath,
|
||||
responseId,
|
||||
}: Awaited<ReturnType<typeof fetchRequestData>>, workspaceId: string) => {
|
||||
const baseEnvironment = await models.environment.getOrCreateForParentId(workspaceId);
|
||||
const cookieJar = await models.cookieJar.getOrCreateForParentId(workspaceId);
|
||||
|
||||
export const tryToExecutePreRequestScript = async (
|
||||
request: Request,
|
||||
environment: Environment,
|
||||
timelinePath: string,
|
||||
responseId: string,
|
||||
baseEnvironment: Environment,
|
||||
clientCertificates: ClientCertificate[],
|
||||
cookieJar: CookieJar,
|
||||
) => {
|
||||
if (!request.preRequestScript) {
|
||||
return {
|
||||
request,
|
||||
environment: undefined,
|
||||
baseEnvironment: undefined,
|
||||
environment,
|
||||
baseEnvironment,
|
||||
clientCertificates,
|
||||
settings,
|
||||
};
|
||||
}
|
||||
const mutatedContext = await tryToExecutePreRequestScript({
|
||||
request,
|
||||
environment,
|
||||
timelinePath,
|
||||
responseId,
|
||||
baseEnvironment,
|
||||
clientCertificates,
|
||||
cookieJar,
|
||||
});
|
||||
if (!mutatedContext?.request) {
|
||||
// exiy early if there was a problem with the pre-request script
|
||||
// TODO: improve error message?
|
||||
return null;
|
||||
}
|
||||
|
||||
await savePatchesMadeByScript(mutatedContext, environment, baseEnvironment);
|
||||
return {
|
||||
request: mutatedContext.request,
|
||||
environment: mutatedContext.environment,
|
||||
baseEnvironment: mutatedContext.baseEnvironment || baseEnvironment,
|
||||
clientCertificates: mutatedContext.clientCertificates || clientCertificates,
|
||||
settings: mutatedContext.settings || settings,
|
||||
};
|
||||
};
|
||||
|
||||
export async function savePatchesMadeByScript(
|
||||
mutatedContext: Awaited<ReturnType<typeof tryToExecutePreRequestScript>>,
|
||||
environment: Environment,
|
||||
baseEnvironment: Environment,
|
||||
) {
|
||||
if (!mutatedContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
// persist updated cookieJar if needed
|
||||
if (mutatedContext.cookieJar) {
|
||||
await models.cookieJar.update(
|
||||
mutatedContext.cookieJar,
|
||||
{ cookies: mutatedContext.cookieJar.cookies },
|
||||
);
|
||||
}
|
||||
// when base environment is activated, `mutatedContext.environment` points to it
|
||||
const isActiveEnvironmentBase = mutatedContext.environment?._id === baseEnvironment._id;
|
||||
const hasEnvironmentAndIsNotBase = mutatedContext.environment && !isActiveEnvironmentBase;
|
||||
if (hasEnvironmentAndIsNotBase) {
|
||||
await models.environment.update(
|
||||
environment,
|
||||
{
|
||||
data: mutatedContext.environment.data,
|
||||
dataPropertyOrder: mutatedContext.environment.dataPropertyOrder,
|
||||
}
|
||||
);
|
||||
}
|
||||
if (mutatedContext.baseEnvironment) {
|
||||
await models.environment.update(
|
||||
baseEnvironment,
|
||||
{
|
||||
data: mutatedContext.baseEnvironment.data,
|
||||
dataPropertyOrder: mutatedContext.baseEnvironment.dataPropertyOrder,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
export const tryToExecuteScript = async (context: RequestAndContextAndOptionalResponse) => {
|
||||
const { script, request, environment, timelinePath, responseId, baseEnvironment, clientCertificates, cookieJar, response } = context;
|
||||
invariant(script, 'script must be provided');
|
||||
|
||||
const settings = await models.settings.get();
|
||||
|
||||
try {
|
||||
@@ -132,9 +202,13 @@ export const tryToExecutePreRequestScript = async (
|
||||
// TODO: restart the hidden browser window
|
||||
}, timeout + 1000);
|
||||
});
|
||||
|
||||
const preRequestPromise = cancellableRunPreRequestScript({
|
||||
script: request.preRequestScript,
|
||||
// const isBaseEnvironmentSelected = environment._id === baseEnvironment._id;
|
||||
// if (isBaseEnvironmentSelected) {
|
||||
// // postman models base env as no env and does not persist, so we could handle that case better, but for now we throw
|
||||
// throw new Error('Base environment cannot be selected for script execution. Please select an environment.');
|
||||
// }
|
||||
const executionPromise = cancellableRunScript({
|
||||
script,
|
||||
context: {
|
||||
request,
|
||||
timelinePath,
|
||||
@@ -148,9 +222,10 @@ export const tryToExecutePreRequestScript = async (
|
||||
clientCertificates,
|
||||
settings,
|
||||
cookieJar,
|
||||
response,
|
||||
},
|
||||
});
|
||||
const output = await Promise.race([timeoutPromise, preRequestPromise]) as {
|
||||
const output = await Promise.race([timeoutPromise, executionPromise]) as {
|
||||
request: Request;
|
||||
environment: Record<string, any>;
|
||||
baseEnvironment: Record<string, any>;
|
||||
@@ -158,7 +233,7 @@ export const tryToExecutePreRequestScript = async (
|
||||
clientCertificates: ClientCertificate[];
|
||||
cookieJar: CookieJar;
|
||||
};
|
||||
console.log('[network] Pre-request script succeeded', output);
|
||||
console.log('[network] script execution succeeded', output);
|
||||
|
||||
const envPropertyOrder = orderedJSON.parse(
|
||||
JSON.stringify(output.environment),
|
||||
@@ -185,7 +260,10 @@ export const tryToExecutePreRequestScript = async (
|
||||
cookieJar: output.cookieJar,
|
||||
};
|
||||
} catch (err) {
|
||||
await fs.promises.appendFile(timelinePath, JSON.stringify({ value: err.message, name: 'Text', timestamp: Date.now() }) + '\n');
|
||||
await fs.promises.appendFile(
|
||||
timelinePath,
|
||||
JSON.stringify({ value: err.message, name: 'Text', timestamp: Date.now() }) + '\n',
|
||||
);
|
||||
|
||||
const requestId = request._id;
|
||||
const responsePatch = {
|
||||
@@ -202,6 +280,30 @@ export const tryToExecutePreRequestScript = async (
|
||||
}
|
||||
};
|
||||
|
||||
interface RequestContextForScript {
|
||||
request: Request;
|
||||
environment: Environment;
|
||||
timelinePath: string;
|
||||
responseId: string;
|
||||
baseEnvironment: Environment;
|
||||
clientCertificates: ClientCertificate[];
|
||||
cookieJar: CookieJar;
|
||||
}
|
||||
type RequestAndContextAndResponse = RequestContextForScript & {
|
||||
response: sendCurlAndWriteTimelineError | sendCurlAndWriteTimelineResponse;
|
||||
};
|
||||
type RequestAndContextAndOptionalResponse = RequestContextForScript & {
|
||||
script: string;
|
||||
response?: sendCurlAndWriteTimelineError | sendCurlAndWriteTimelineResponse;
|
||||
};
|
||||
export async function tryToExecutePreRequestScript(context: RequestContextForScript) {
|
||||
return tryToExecuteScript({ script: context.request.preRequestScript, ...context });
|
||||
};
|
||||
|
||||
export async function tryToExecuteAfterResponseScript(context: RequestAndContextAndResponse) {
|
||||
return tryToExecuteScript({ script: context.request.afterResponseScript, ...context });
|
||||
}
|
||||
|
||||
export const tryToInterpolateRequest = async (
|
||||
request: Request,
|
||||
environment: string | Environment,
|
||||
@@ -235,6 +337,26 @@ export const tryToTransformRequestWithPlugins = async (renderResult: RequestAndC
|
||||
throw new Error(`Failed to transform request with plugins: ${request._id}`);
|
||||
}
|
||||
};
|
||||
|
||||
export interface sendCurlAndWriteTimelineError {
|
||||
_id: string;
|
||||
parentId: string;
|
||||
timelinePath: string;
|
||||
statusMessage: string;
|
||||
// additional
|
||||
url: string;
|
||||
error: string;
|
||||
elapsedTime: number;
|
||||
bytesRead: number;
|
||||
}
|
||||
|
||||
export interface sendCurlAndWriteTimelineResponse extends ResponsePatch {
|
||||
_id: string;
|
||||
parentId: string;
|
||||
timelinePath: string;
|
||||
statusMessage: string;
|
||||
}
|
||||
|
||||
export async function sendCurlAndWriteTimeline(
|
||||
renderedRequest: RenderedRequest,
|
||||
clientCertificates: ClientCertificate[],
|
||||
@@ -242,7 +364,7 @@ export async function sendCurlAndWriteTimeline(
|
||||
settings: Settings,
|
||||
timelinePath: string,
|
||||
responseId: string,
|
||||
) {
|
||||
): Promise<sendCurlAndWriteTimelineError | sendCurlAndWriteTimelineResponse> {
|
||||
const requestId = renderedRequest._id;
|
||||
const timelineStrings: string[] = [];
|
||||
const authentication = renderedRequest.authentication as RequestAuthentication;
|
||||
@@ -314,6 +436,7 @@ export async function sendCurlAndWriteTimeline(
|
||||
...patch,
|
||||
};
|
||||
}
|
||||
|
||||
export const responseTransform = async (patch: ResponsePatch, environmentId: string | null, renderedRequest: RenderedRequest, context: Record<string, any>) => {
|
||||
const response: ResponsePatch = {
|
||||
...patch,
|
||||
|
||||
@@ -197,6 +197,7 @@ describe('app.export.*', () => {
|
||||
parameters: [],
|
||||
pathParameters: [],
|
||||
preRequestScript: '',
|
||||
afterResponseScript: '',
|
||||
parentId: 'wrk_1',
|
||||
settingDisableRenderRequestBody: false,
|
||||
settingEncodeUrl: true,
|
||||
|
||||
@@ -71,7 +71,7 @@ const main: Window['main'] = {
|
||||
},
|
||||
},
|
||||
hiddenBrowserWindow: {
|
||||
runPreRequestScript: options => new Promise(async (resolve, reject) => {
|
||||
runScript: options => new Promise(async (resolve, reject) => {
|
||||
const isPortAlive = ports.get('hiddenWindowPort') !== undefined;
|
||||
await ipcRenderer.invoke('open-channel-to-hidden-browser-window', isPortAlive);
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import { Snippet } from 'codemirror';
|
||||
import { CookieObject, Environment, InsomniaObject, Request as ScriptRequest, RequestInfo, Url, Variables } from 'insomnia-sdk';
|
||||
import React, { FC, useRef } from 'react';
|
||||
|
||||
import { translateHandlersInScript } from '../../../../src/utils/importers/importers/postman';
|
||||
import { Settings } from '../../../models/settings';
|
||||
import { translateHandlersInScript } from '../../../utils/importers/importers/postman';
|
||||
import { Dropdown, DropdownButton, DropdownItem, DropdownSection, ItemContent } from '../base/dropdown';
|
||||
import { CodeEditor, CodeEditorHandle } from '../codemirror/code-editor';
|
||||
|
||||
@@ -58,6 +58,18 @@ const updateRequestAuth =
|
||||
);`;
|
||||
const requireAModule = "const atob = require('atob');";
|
||||
|
||||
const getStatusCode = 'const statusCode = insomnia.response.code;';
|
||||
const getStatusMsg = 'const status = insomnia.response.status;';
|
||||
const getRespTime = 'const responseTime = insomnia.response.responseTime;';
|
||||
const getJsonBody = 'const jsonBody = insomnia.response.json();';
|
||||
const getTextBody = 'const textBody = insomnia.response.text();';
|
||||
const findHeader =
|
||||
`const header = insomnia.response.headers.find(
|
||||
header => header.key === 'Content-Type',
|
||||
{},
|
||||
);`;
|
||||
const getCookies = 'const cookies = insomnia.response.cookies.toObject();';
|
||||
|
||||
const lintOptions = {
|
||||
globals: {
|
||||
// https://jshint.com/docs/options/
|
||||
@@ -80,7 +92,7 @@ const lintOptions = {
|
||||
// TODO: introduce this functionality for other objects, such as Url, UrlMatchPattern and so on
|
||||
// TODO: introduce function arguments
|
||||
// TODO: provide snippets for environment keys if possible
|
||||
function getPreRequestScriptSnippets(insomniaObject: InsomniaObject, path: string): Snippet[] {
|
||||
function getRequestScriptSnippets(insomniaObject: InsomniaObject, path: string): Snippet[] {
|
||||
let snippets: Snippet[] = [];
|
||||
|
||||
const refs = new Set();
|
||||
@@ -117,17 +129,17 @@ function getPreRequestScriptSnippets(insomniaObject: InsomniaObject, path: strin
|
||||
});
|
||||
} else if (Array.isArray(value)) {
|
||||
for (const item of value) {
|
||||
snippets = snippets.concat(getPreRequestScriptSnippets(item, `${path}.${key}`));
|
||||
snippets = snippets.concat(getRequestScriptSnippets(item, `${path}.${key}`));
|
||||
}
|
||||
} else {
|
||||
snippets = snippets.concat(getPreRequestScriptSnippets(value, `${path}.${key}`));
|
||||
snippets = snippets.concat(getRequestScriptSnippets(value, `${path}.${key}`));
|
||||
}
|
||||
}
|
||||
|
||||
return snippets;
|
||||
}
|
||||
|
||||
export const PreRequestScriptEditor: FC<Props> = ({
|
||||
export const RequestScriptEditor: FC<Props> = ({
|
||||
className,
|
||||
defaultValue,
|
||||
onChange,
|
||||
@@ -154,7 +166,7 @@ export const PreRequestScriptEditor: FC<Props> = ({
|
||||
};
|
||||
|
||||
// TODO(george): Add more to this object to provide improved autocomplete
|
||||
const preRequestScriptSnippets = getPreRequestScriptSnippets(
|
||||
const requestScriptSnippets = getRequestScriptSnippets(
|
||||
new InsomniaObject({
|
||||
globals: new Environment('globals', {}),
|
||||
iterationData: new Environment('iterationData', {}),
|
||||
@@ -199,8 +211,8 @@ export const PreRequestScriptEditor: FC<Props> = ({
|
||||
<div className='h-full flex flex-col'>
|
||||
<div className="flex-1">
|
||||
<CodeEditor
|
||||
id={`script-editor-${uniquenessKey}`}
|
||||
key={uniquenessKey}
|
||||
id="pre-request-script-editor"
|
||||
disableContextMenu={true}
|
||||
showPrettifyButton={true}
|
||||
uniquenessKey={uniquenessKey}
|
||||
@@ -211,7 +223,7 @@ export const PreRequestScriptEditor: FC<Props> = ({
|
||||
placeholder="..."
|
||||
lintOptions={lintOptions}
|
||||
ref={editorRef}
|
||||
getAutocompleteSnippets={() => preRequestScriptSnippets}
|
||||
getAutocompleteSnippets={() => requestScriptSnippets}
|
||||
onPaste={translateHandlersInScript}
|
||||
/>
|
||||
</div>
|
||||
@@ -380,6 +392,70 @@ export const PreRequestScriptEditor: FC<Props> = ({
|
||||
/>
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown
|
||||
aria-label='Response Handling'
|
||||
placement='top left'
|
||||
triggerButton={
|
||||
<DropdownButton>
|
||||
<ItemContent
|
||||
icon="code"
|
||||
label='Response Handling'
|
||||
/>
|
||||
</DropdownButton>
|
||||
}
|
||||
>
|
||||
<DropdownItem textValue='Get status code' arial-label={'Get status code'}>
|
||||
<ItemContent
|
||||
icon="circle-info"
|
||||
label='Get status code'
|
||||
onClick={() => addSnippet(getStatusCode)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Get status message' arial-label={'Get status message'}>
|
||||
<ItemContent
|
||||
icon="circle-info"
|
||||
label='Get status message'
|
||||
onClick={() => addSnippet(getStatusMsg)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Get response time' arial-label={'Get response time'}>
|
||||
<ItemContent
|
||||
icon="circle-info"
|
||||
label='Get response time'
|
||||
onClick={() => addSnippet(getRespTime)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Get body as JSON' arial-label={'Get body as JSON'}>
|
||||
<ItemContent
|
||||
icon="circle-info"
|
||||
label='Get body as JSON'
|
||||
onClick={() => addSnippet(getJsonBody)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Get body as text' arial-label={'Get body as text'}>
|
||||
<ItemContent
|
||||
icon="circle-info"
|
||||
label='Get body as text'
|
||||
onClick={() => addSnippet(getTextBody)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Find a header by name' arial-label={'Find a header by name'}>
|
||||
<ItemContent
|
||||
icon="circle-info"
|
||||
label='Find a header by name'
|
||||
onClick={() => addSnippet(findHeader)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
<DropdownItem textValue='Get cookies' arial-label={'Get cookies'}>
|
||||
<ItemContent
|
||||
icon="circle-info"
|
||||
label='Get cookies'
|
||||
onClick={() => addSnippet(getCookies)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown
|
||||
aria-label='Misc'
|
||||
placement='top left'
|
||||
@@ -19,9 +19,9 @@ import { AuthDropdown } from '../dropdowns/auth-dropdown';
|
||||
import { ContentTypeDropdown } from '../dropdowns/content-type-dropdown';
|
||||
import { AuthWrapper } from '../editors/auth/auth-wrapper';
|
||||
import { BodyEditor } from '../editors/body/body-editor';
|
||||
import { PreRequestScriptEditor } from '../editors/pre-request-script-editor';
|
||||
import { RequestHeadersEditor } from '../editors/request-headers-editor';
|
||||
import { RequestParametersEditor } from '../editors/request-parameters-editor';
|
||||
import { RequestScriptEditor } from '../editors/request-script-editor';
|
||||
import { ErrorBoundary } from '../error-boundary';
|
||||
import { Icon } from '../icon';
|
||||
import { MarkdownPreview } from '../markdown-preview';
|
||||
@@ -293,7 +293,7 @@ export const RequestPane: FC<Props> = ({
|
||||
key={uniqueKey}
|
||||
errorClassName="tall wide vertically-align font-error pad text-center"
|
||||
>
|
||||
<PreRequestScriptEditor
|
||||
<RequestScriptEditor
|
||||
uniquenessKey={uniqueKey}
|
||||
defaultValue={activeRequest.preRequestScript || ''}
|
||||
onChange={preRequestScript => patchRequest(requestId, { preRequestScript })}
|
||||
@@ -301,6 +301,33 @@ export const RequestPane: FC<Props> = ({
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</TabItem>
|
||||
<TabItem
|
||||
key="after-response-script"
|
||||
data-testid="after-response-script-tab"
|
||||
title={
|
||||
<div className='flex items-center gap-2'>
|
||||
After-response Script{' '}
|
||||
{activeRequest.afterResponseScript && (
|
||||
<span className="ml-2 p-2 border-solid border border-[--hl-md] rounded-lg">
|
||||
<span className="flex w-2 h-2 bg-green-500 rounded-full" />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
aria-label={'experimental'}
|
||||
>
|
||||
<ErrorBoundary
|
||||
key={uniqueKey}
|
||||
errorClassName="tall wide vertically-align font-error pad text-center"
|
||||
>
|
||||
<RequestScriptEditor
|
||||
uniquenessKey={uniqueKey}
|
||||
defaultValue={activeRequest.afterResponseScript || ''}
|
||||
onChange={afterResponseScript => patchRequest(requestId, { afterResponseScript })}
|
||||
settings={settings}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</TabItem>
|
||||
<TabItem
|
||||
key="docs"
|
||||
title={
|
||||
|
||||
@@ -26,7 +26,7 @@ import { Response } from '../../models/response';
|
||||
import { isWebSocketRequest, isWebSocketRequestId, WebSocketRequest } from '../../models/websocket-request';
|
||||
import { WebSocketResponse } from '../../models/websocket-response';
|
||||
import { getAuthHeader } from '../../network/authentication';
|
||||
import { fetchRequestData, responseTransform, sendCurlAndWriteTimeline, tryToExecutePreRequestScript, tryToInterpolateRequest, tryToTransformRequestWithPlugins } from '../../network/network';
|
||||
import { fetchRequestData, getPreRequestScriptOutput, responseTransform, savePatchesMadeByScript, sendCurlAndWriteTimeline, tryToExecuteAfterResponseScript, tryToInterpolateRequest, tryToTransformRequestWithPlugins } from '../../network/network';
|
||||
import { RenderErrorSubType } from '../../templating';
|
||||
import { invariant } from '../../utils/invariant';
|
||||
import { SegmentEvent } from '../analytics';
|
||||
@@ -363,69 +363,16 @@ export const sendAction: ActionFunction = async ({ request, params }) => {
|
||||
const { requestId, workspaceId } = params;
|
||||
invariant(typeof requestId === 'string', 'Request ID is required');
|
||||
invariant(workspaceId, 'Workspace ID is required');
|
||||
|
||||
const {
|
||||
request: req,
|
||||
environment,
|
||||
settings,
|
||||
clientCertificates,
|
||||
caCert,
|
||||
activeEnvironmentId,
|
||||
timelinePath,
|
||||
responseId,
|
||||
} = await fetchRequestData(requestId);
|
||||
const baseEnvironment = await models.environment.getOrCreateForParentId(workspaceId);
|
||||
const cookieJar = await models.cookieJar.getOrCreateForParentId(workspaceId);
|
||||
|
||||
const { shouldPromptForPathAfterResponse, ignoreUndefinedEnvVariable } = await request.json() as SendActionParams;
|
||||
try {
|
||||
const { shouldPromptForPathAfterResponse, ignoreUndefinedEnvVariable } = await request.json() as SendActionParams;
|
||||
const mutatedContext = await tryToExecutePreRequestScript(
|
||||
req,
|
||||
environment,
|
||||
timelinePath,
|
||||
responseId,
|
||||
baseEnvironment,
|
||||
clientCertificates,
|
||||
cookieJar,
|
||||
);
|
||||
if (!mutatedContext?.request) {
|
||||
// exiy early if there was a problem with the pre-request script
|
||||
// TODO: improve error message?
|
||||
const requestData = await fetchRequestData(requestId);
|
||||
const mutatedContext = await getPreRequestScriptOutput(requestData, workspaceId);
|
||||
if (mutatedContext === null) {
|
||||
return null;
|
||||
} else {
|
||||
// persist updated cookieJar if needed
|
||||
if (mutatedContext.cookieJar) {
|
||||
await models.cookieJar.update(
|
||||
mutatedContext.cookieJar,
|
||||
{ cookies: mutatedContext.cookieJar.cookies },
|
||||
);
|
||||
}
|
||||
// when base environment is activated, `mutatedContext.environment` points to it
|
||||
const isActiveEnvironmentBase = mutatedContext.environment?._id === baseEnvironment._id;
|
||||
const hasEnvironmentAndIsNotBase = mutatedContext.environment && !isActiveEnvironmentBase;
|
||||
if (hasEnvironmentAndIsNotBase) {
|
||||
await models.environment.update(
|
||||
environment,
|
||||
{
|
||||
data: mutatedContext.environment.data,
|
||||
dataPropertyOrder: mutatedContext.environment.dataPropertyOrder,
|
||||
}
|
||||
);
|
||||
}
|
||||
if (mutatedContext.baseEnvironment) {
|
||||
await models.environment.update(
|
||||
baseEnvironment,
|
||||
{
|
||||
data: mutatedContext.baseEnvironment.data,
|
||||
dataPropertyOrder: mutatedContext.baseEnvironment.dataPropertyOrder,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const renderedResult = await tryToInterpolateRequest(
|
||||
mutatedContext.request,
|
||||
mutatedContext.environment || environment._id,
|
||||
mutatedContext.environment,
|
||||
RENDER_PURPOSE_SEND,
|
||||
undefined,
|
||||
mutatedContext.baseEnvironment,
|
||||
@@ -448,30 +395,48 @@ export const sendAction: ActionFunction = async ({ request, params }) => {
|
||||
|
||||
const response = await sendCurlAndWriteTimeline(
|
||||
renderedRequest,
|
||||
mutatedContext.clientCertificates || clientCertificates,
|
||||
caCert,
|
||||
mutatedContext.settings || settings,
|
||||
timelinePath,
|
||||
responseId
|
||||
mutatedContext.clientCertificates,
|
||||
requestData.caCert,
|
||||
mutatedContext.settings,
|
||||
requestData.timelinePath,
|
||||
requestData.responseId
|
||||
);
|
||||
|
||||
const requestMeta = await models.requestMeta.getByParentId(requestId);
|
||||
invariant(requestMeta, 'RequestMeta not found');
|
||||
const responsePatch = await responseTransform(response, activeEnvironmentId, renderedRequest, renderedResult.context);
|
||||
const responsePatch = await responseTransform(response, requestData.activeEnvironmentId, renderedRequest, renderedResult.context);
|
||||
const is2XXWithBodyPath = responsePatch.statusCode && responsePatch.statusCode >= 200 && responsePatch.statusCode < 300 && responsePatch.bodyPath;
|
||||
const shouldWriteToFile = shouldPromptForPathAfterResponse && is2XXWithBodyPath;
|
||||
if (requestData.request.afterResponseScript) {
|
||||
const baseEnvironment = await models.environment.getOrCreateForParentId(workspaceId);
|
||||
const cookieJar = await models.cookieJar.getOrCreateForParentId(workspaceId);
|
||||
const postMutatedContext = await tryToExecuteAfterResponseScript({
|
||||
...requestData,
|
||||
...mutatedContext,
|
||||
baseEnvironment,
|
||||
cookieJar,
|
||||
response,
|
||||
});
|
||||
if (!postMutatedContext?.request) {
|
||||
// exiy early if there was a problem with the pre-request script
|
||||
// TODO: improve error message?
|
||||
return null;
|
||||
}
|
||||
await savePatchesMadeByScript(postMutatedContext, requestData.environment, baseEnvironment);
|
||||
}
|
||||
if (!shouldWriteToFile) {
|
||||
const response = await models.response.create(responsePatch, settings.maxHistoryResponses);
|
||||
const response = await models.response.create(responsePatch, requestData.settings.maxHistoryResponses);
|
||||
await models.requestMeta.update(requestMeta, { activeResponseId: response._id });
|
||||
// setLoading(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (requestMeta.downloadPath) {
|
||||
const header = getContentDispositionHeader(responsePatch.headers || []);
|
||||
const name = header
|
||||
? contentDisposition.parse(header.value).parameters.filename
|
||||
: `${req.name.replace(/\s/g, '-').toLowerCase()}.${responsePatch.contentType && mimeExtension(responsePatch.contentType) || 'unknown'}`;
|
||||
return writeToDownloadPath(path.join(requestMeta.downloadPath, name), responsePatch, requestMeta, settings.maxHistoryResponses);
|
||||
: `${requestData.request.name.replace(/\s/g, '-').toLowerCase()}.${responsePatch.contentType && mimeExtension(responsePatch.contentType) || 'unknown'}`;
|
||||
return writeToDownloadPath(path.join(requestMeta.downloadPath, name), responsePatch, requestMeta, requestData.settings.maxHistoryResponses);
|
||||
} else {
|
||||
const defaultPath = window.localStorage.getItem('insomnia.sendAndDownloadLocation');
|
||||
const { filePath } = await window.dialog.showSaveDialog({
|
||||
@@ -485,7 +450,7 @@ export const sendAction: ActionFunction = async ({ request, params }) => {
|
||||
return null;
|
||||
}
|
||||
window.localStorage.setItem('insomnia.sendAndDownloadLocation', filePath);
|
||||
return writeToDownloadPath(filePath, responsePatch, requestMeta, settings.maxHistoryResponses);
|
||||
return writeToDownloadPath(filePath, responsePatch, requestMeta, requestData.settings.maxHistoryResponses);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Failed to send request', e);
|
||||
|
||||
@@ -78,6 +78,7 @@ export interface ImportRequest<T extends {} = {}> extends Comment {
|
||||
queryString?: QueryString[];
|
||||
url?: string;
|
||||
preRequestScript?: string;
|
||||
afterResponseScript?: string;
|
||||
metaSortKey?: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -3842,6 +3842,7 @@ exports[`Fixtures Import postman api-key-default-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"addTo": "header",
|
||||
"disabled": false,
|
||||
@@ -3883,6 +3884,7 @@ exports[`Fixtures Import postman api-key-header-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"addTo": "header",
|
||||
"disabled": false,
|
||||
@@ -3924,6 +3926,7 @@ exports[`Fixtures Import postman api-key-queryParams-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"addTo": "queryParams",
|
||||
"disabled": false,
|
||||
@@ -3965,6 +3968,7 @@ exports[`Fixtures Import postman aws-signature-auth-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessKeyId": "aws-access-key",
|
||||
"disabled": false,
|
||||
@@ -4008,6 +4012,7 @@ exports[`Fixtures Import postman aws-signature-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessKeyId": "aws-access-key",
|
||||
"disabled": false,
|
||||
@@ -4051,6 +4056,7 @@ exports[`Fixtures Import postman basic-auth-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"password": "basic-password",
|
||||
@@ -4091,6 +4097,7 @@ exports[`Fixtures Import postman basic-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"password": "basic-password",
|
||||
@@ -4131,6 +4138,7 @@ exports[`Fixtures Import postman bearer-token-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"prefix": "",
|
||||
@@ -4171,6 +4179,7 @@ exports[`Fixtures Import postman bearer-token-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"prefix": "",
|
||||
@@ -4211,6 +4220,7 @@ exports[`Fixtures Import postman complex-url-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {},
|
||||
"description": "",
|
||||
@@ -4252,6 +4262,7 @@ exports[`Fixtures Import postman complex-url-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {},
|
||||
"description": "",
|
||||
@@ -4302,6 +4313,7 @@ exports[`Fixtures Import postman complex-v2_0_fromHeaders-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"prefix": "",
|
||||
@@ -4340,6 +4352,7 @@ exports[`Fixtures Import postman complex-v2_0_fromHeaders-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_2__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessKeyId": "<accessKeyId>",
|
||||
"disabled": false,
|
||||
@@ -4390,6 +4403,7 @@ exports[`Fixtures Import postman complex-v2_0_fromHeaders-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_3__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"password": "abc123",
|
||||
@@ -4428,6 +4442,7 @@ exports[`Fixtures Import postman complex-v2_0_fromHeaders-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_4__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"password": "",
|
||||
@@ -4473,6 +4488,7 @@ Child projects are provided as references; i.e. they only contain the <code>self
|
||||
{
|
||||
"_id": "__REQ_5__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "Callback%20URL",
|
||||
"consumerKey": "Consumer%20Key",
|
||||
@@ -4557,6 +4573,7 @@ exports[`Fixtures Import postman complex-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"password": "password",
|
||||
@@ -4593,6 +4610,7 @@ exports[`Fixtures Import postman complex-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_2__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"password": "password",
|
||||
@@ -4622,6 +4640,7 @@ exports[`Fixtures Import postman complex-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_3__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {
|
||||
"mimeType": "",
|
||||
@@ -4640,6 +4659,7 @@ exports[`Fixtures Import postman complex-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_4__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {},
|
||||
"description": "Request with empty raw body",
|
||||
@@ -4655,6 +4675,7 @@ exports[`Fixtures Import postman complex-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_5__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {},
|
||||
"description": "Request with unknown body",
|
||||
@@ -4670,6 +4691,7 @@ exports[`Fixtures Import postman complex-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_6__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {
|
||||
"mimeType": "application/graphql",
|
||||
@@ -4717,6 +4739,7 @@ exports[`Fixtures Import postman complex-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"password": "password",
|
||||
@@ -4759,6 +4782,7 @@ exports[`Fixtures Import postman complex-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_2__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"password": "password",
|
||||
@@ -4788,6 +4812,7 @@ exports[`Fixtures Import postman complex-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_3__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {
|
||||
"mimeType": "",
|
||||
@@ -4806,6 +4831,7 @@ exports[`Fixtures Import postman complex-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_4__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {},
|
||||
"description": "Request with unknown body",
|
||||
@@ -4821,6 +4847,7 @@ exports[`Fixtures Import postman complex-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_5__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {},
|
||||
"description": "Request with empty raw body",
|
||||
@@ -4836,6 +4863,7 @@ exports[`Fixtures Import postman complex-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_6__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {
|
||||
"mimeType": "application/graphql",
|
||||
@@ -4874,6 +4902,7 @@ exports[`Fixtures Import postman digest-auth-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"password": "guest",
|
||||
@@ -4914,6 +4943,7 @@ exports[`Fixtures Import postman digest-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"password": "guest",
|
||||
@@ -4954,6 +4984,7 @@ exports[`Fixtures Import postman faker-vars-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"disabled": false,
|
||||
"prefix": "",
|
||||
@@ -5009,6 +5040,7 @@ exports[`Fixtures Import postman minimal-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {},
|
||||
"description": "",
|
||||
@@ -5044,6 +5076,7 @@ exports[`Fixtures Import postman minimal-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {},
|
||||
"description": "",
|
||||
@@ -5079,6 +5112,7 @@ exports[`Fixtures Import postman oauth1_0-auth-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "",
|
||||
"consumerKey": "consumer-key-value",
|
||||
@@ -5109,6 +5143,7 @@ exports[`Fixtures Import postman oauth1_0-auth-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_2__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "",
|
||||
"consumerKey": "consumer-key-value",
|
||||
@@ -5139,6 +5174,7 @@ exports[`Fixtures Import postman oauth1_0-auth-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_3__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "",
|
||||
"consumerKey": "plaintext-consumer-key-value",
|
||||
@@ -5169,6 +5205,7 @@ exports[`Fixtures Import postman oauth1_0-auth-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_4__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "",
|
||||
"consumerKey": "sha256-consumer-key-value",
|
||||
@@ -5199,6 +5236,7 @@ exports[`Fixtures Import postman oauth1_0-auth-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_5__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "",
|
||||
"consumerKey": "sha1-consumer-key-value",
|
||||
@@ -5249,6 +5287,7 @@ exports[`Fixtures Import postman oauth1_0-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "",
|
||||
"consumerKey": "consumer-key-value",
|
||||
@@ -5279,6 +5318,7 @@ exports[`Fixtures Import postman oauth1_0-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_2__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "",
|
||||
"consumerKey": "consumer-key-value",
|
||||
@@ -5309,6 +5349,7 @@ exports[`Fixtures Import postman oauth1_0-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_3__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "",
|
||||
"consumerKey": "plaintext-consumer-key-value",
|
||||
@@ -5339,6 +5380,7 @@ exports[`Fixtures Import postman oauth1_0-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_4__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "",
|
||||
"consumerKey": "sha256-consumer-key-value",
|
||||
@@ -5369,6 +5411,7 @@ exports[`Fixtures Import postman oauth1_0-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_5__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"callback": "",
|
||||
"consumerKey": "sha1-consumer-key-value",
|
||||
@@ -5419,6 +5462,7 @@ exports[`Fixtures Import postman oauth2_0-auth-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessTokenUrl": "",
|
||||
"authorizationUrl": "",
|
||||
@@ -5442,6 +5486,7 @@ exports[`Fixtures Import postman oauth2_0-auth-v2_0-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_2__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessTokenUrl": "",
|
||||
"authorizationUrl": "",
|
||||
@@ -5485,6 +5530,7 @@ exports[`Fixtures Import postman oauth2_0-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessTokenUrl": "test",
|
||||
"authorizationUrl": "test",
|
||||
@@ -5517,6 +5563,7 @@ exports[`Fixtures Import postman oauth2_0-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_2__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessTokenUrl": "test",
|
||||
"authorizationUrl": "test",
|
||||
@@ -5549,6 +5596,7 @@ exports[`Fixtures Import postman oauth2_0-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_3__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessTokenUrl": "test",
|
||||
"authorizationUrl": "test",
|
||||
@@ -5581,6 +5629,7 @@ exports[`Fixtures Import postman oauth2_0-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_4__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessTokenUrl": "test",
|
||||
"authorizationUrl": "test",
|
||||
@@ -5613,6 +5662,7 @@ exports[`Fixtures Import postman oauth2_0-auth-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_5__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessTokenUrl": "test",
|
||||
"authorizationUrl": "test",
|
||||
@@ -5665,6 +5715,7 @@ exports[`Fixtures Import postman postman-export-oauth2-v2_1-input.json 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {
|
||||
"accessTokenUrl": "exampleAccessTokenUrl",
|
||||
"authorizationUrl": "exampleAuthorizeUrl",
|
||||
@@ -5698,6 +5749,42 @@ exports[`Fixtures Import postman postman-export-oauth2-v2_1-input.json 1`] = `
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Fixtures Import postman scripts-import-v2_1-input.json 1`] = `
|
||||
{
|
||||
"__export_date": "",
|
||||
"__export_format": 4,
|
||||
"__export_source": "insomnia.importers:v0.1.0",
|
||||
"_type": "export",
|
||||
"resources": [
|
||||
{
|
||||
"_id": "__GRP_1__",
|
||||
"_type": "request_group",
|
||||
"description": "",
|
||||
"environment": {},
|
||||
"metaSortKey": -1622117984000,
|
||||
"name": "New Collection",
|
||||
"parentId": "__WORKSPACE_ID__",
|
||||
},
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "console.log('this is test script');",
|
||||
"authentication": {},
|
||||
"body": {},
|
||||
"description": "",
|
||||
"headers": [],
|
||||
"metaSortKey": -1622117983999,
|
||||
"method": "GET",
|
||||
"name": "New Request",
|
||||
"parameters": [],
|
||||
"parentId": "__GRP_1__",
|
||||
"preRequestScript": "console.log('this is pre-request script');",
|
||||
"url": "httpbin.org/get",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Fixtures Import postman-env basic-input.json 1`] = `
|
||||
{
|
||||
"__export_date": "",
|
||||
@@ -8064,6 +8151,7 @@ exports[`Fixtures Import wsdl addition-input.wsdl 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {
|
||||
"mimeType": "text/xml",
|
||||
@@ -8147,6 +8235,7 @@ exports[`Fixtures Import wsdl calculator-input.wsdl 1`] = `
|
||||
{
|
||||
"_id": "__REQ_1__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {
|
||||
"mimeType": "text/xml",
|
||||
@@ -8201,6 +8290,7 @@ exports[`Fixtures Import wsdl calculator-input.wsdl 1`] = `
|
||||
{
|
||||
"_id": "__REQ_2__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {
|
||||
"mimeType": "text/xml",
|
||||
@@ -8255,6 +8345,7 @@ exports[`Fixtures Import wsdl calculator-input.wsdl 1`] = `
|
||||
{
|
||||
"_id": "__REQ_3__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {
|
||||
"mimeType": "text/xml",
|
||||
@@ -8309,6 +8400,7 @@ exports[`Fixtures Import wsdl calculator-input.wsdl 1`] = `
|
||||
{
|
||||
"_id": "__REQ_4__",
|
||||
"_type": "request",
|
||||
"afterResponseScript": "",
|
||||
"authentication": {},
|
||||
"body": {
|
||||
"mimeType": "text/xml",
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "c7c1ce35-b25b-4a79-85a7-8141e1f8cfba",
|
||||
"name": "New Collection",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
"_exporter_id": "30615465"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "New Request",
|
||||
"event": [
|
||||
{
|
||||
"listen": "prerequest",
|
||||
"script": {
|
||||
"exec": [
|
||||
"console.log('this is pre-request script');"
|
||||
],
|
||||
"type": "text/javascript",
|
||||
"packages": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"exec": [
|
||||
"console.log('this is test script');"
|
||||
],
|
||||
"type": "text/javascript",
|
||||
"packages": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "httpbin.org/get",
|
||||
"host": [
|
||||
"httpbin",
|
||||
"org"
|
||||
],
|
||||
"path": [
|
||||
"get"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -170,6 +170,27 @@ export class ImportPostman {
|
||||
return translateHandlersInScript(scriptContent);
|
||||
};
|
||||
|
||||
importAfterResponseScript = (events: EventList | undefined): string => {
|
||||
if (events == null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const afterResponseEvent = events.find(
|
||||
event => event.listen === 'test'
|
||||
);
|
||||
|
||||
const scriptOrRows = afterResponseEvent ? afterResponseEvent.script : '';
|
||||
if (!scriptOrRows) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const scriptContent = scriptOrRows.exec ?
|
||||
(Array.isArray(scriptOrRows.exec) ? scriptOrRows.exec.join('\n') : scriptOrRows.exec) :
|
||||
'';
|
||||
|
||||
return translateHandlersInScript(scriptContent);
|
||||
};
|
||||
|
||||
importRequestItem = (
|
||||
{ request, name = '', event }: Item,
|
||||
parentId: string,
|
||||
@@ -187,6 +208,8 @@ export class ImportPostman {
|
||||
}
|
||||
|
||||
const preRequestScript = this.importPreRequestScript(event);
|
||||
const afterResponseScript = this.importAfterResponseScript(event);
|
||||
|
||||
return {
|
||||
parentId,
|
||||
_id: `__REQ_${requestCount++}__`,
|
||||
@@ -205,6 +228,7 @@ export class ImportPostman {
|
||||
body: this.importBody(request.body, headers.find(({ key }) => key === 'Content-Type')?.value),
|
||||
authentication,
|
||||
preRequestScript,
|
||||
afterResponseScript,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user