mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 06:39:48 +00:00
feat(hidden-window): enable baseEnvironment in the pre-request scripting (#7102)
* feat(hidden-window): enable baseEnvironment in the pre-request scripting * fix: input empty selected environment data to avoid incorrect environment manipulation and overriding * test: add a test for folder environments overriding * fix: smoke tests failed because of env overriding
This commit is contained in:
parent
62a73fa3ec
commit
d7a0bc1e58
@ -177,7 +177,7 @@ resources:
|
||||
settingFollowRedirects: global
|
||||
_type: request
|
||||
- _id: req_89dade2ee9ee42fbb22d588783a9df3c
|
||||
parentId: wrk_5b5ab67830944ffcbec47528366ef403
|
||||
parentId: fld_01de564274824ecaad272330339ea6b2
|
||||
modified: 1636707449231
|
||||
created: 1636141014552
|
||||
url: http://127.0.0.1:4010/echo
|
||||
@ -202,7 +202,8 @@ resources:
|
||||
modified: 1636140994432
|
||||
created: 1636140994432
|
||||
name: Base Environment
|
||||
data: {}
|
||||
data:
|
||||
customValue: "fromEnvManager"
|
||||
dataPropertyOrder: null
|
||||
color: null
|
||||
isPrivate: false
|
||||
@ -264,8 +265,19 @@ resources:
|
||||
settingRebuildPath: true
|
||||
settingFollowRedirects: global
|
||||
_type: request
|
||||
- _id: req_0769dca686df49358082b2183dfa073d
|
||||
- _id: fld_01de564274824ecaad272330339ea6b2
|
||||
parentId: wrk_5b5ab67830944ffcbec47528366ef403
|
||||
modified: 1668533312225
|
||||
created: 1668533312225
|
||||
name: FolderWithEnv
|
||||
description: ""
|
||||
environment:
|
||||
customValue: "fromFolder"
|
||||
environmentPropertyOrder: null
|
||||
metaSortKey: -1668533312225
|
||||
_type: request_group
|
||||
- _id: req_0769dca686df49358082b2183dfa073d
|
||||
parentId: fld_01de564274824ecaad272330339ea6b2
|
||||
modified: 1643892278711
|
||||
created: 1643892270079
|
||||
url: http://127.0.0.1:4010/echo
|
||||
|
@ -45,6 +45,59 @@ test.describe('pre-request UI tests', async () => {
|
||||
predefined: 'updatedByScript',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'environments / populate environments',
|
||||
preReqScript: `
|
||||
insomnia.baseEnvironment.set('fromBaseEnv', 'baseEnv');
|
||||
`,
|
||||
body: `{
|
||||
"fromBaseEnv": "{{ _.fromBaseEnv }}"
|
||||
}`,
|
||||
expectedBody: {
|
||||
fromBaseEnv: 'baseEnv',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'environments / override base environments',
|
||||
preReqScript: `
|
||||
insomnia.baseEnvironment.set('scriptValue', 'fromBase');
|
||||
insomnia.environment.set('scriptValue', 'fromEnv');
|
||||
`,
|
||||
body: `{
|
||||
"scriptValue": "{{ _.scriptValue }}"
|
||||
}`,
|
||||
expectedBody: {
|
||||
scriptValue: 'fromEnv',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'environments / override predefined base environment in script',
|
||||
preReqScript: `
|
||||
// "preDefinedValue" is already defined in the base environment modal.
|
||||
// but it is rewritten here
|
||||
insomnia.baseEnvironment.set('preDefinedValue', 'fromScript');
|
||||
`,
|
||||
body: `{
|
||||
"preDefinedValue": "{{ _.preDefinedValue }}"
|
||||
}`,
|
||||
expectedBody: {
|
||||
preDefinedValue: 'fromScript',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'environments/ envrionment from script should be overidden by folder environment',
|
||||
preReqScript: `
|
||||
// "customValue" is already defined in the folder environment.
|
||||
// folder version will override the following wone
|
||||
insomnia.baseEnvironment.set('customValue', 'fromScript');
|
||||
`,
|
||||
body: `{
|
||||
"customValue": "{{ _.customValue }}"
|
||||
}`,
|
||||
expectedBody: {
|
||||
customValue: 'fromFolder',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < testCases.length; i++) {
|
||||
|
@ -298,6 +298,7 @@ interface RenderRequest<T extends Request | GrpcRequest | WebSocketRequest> {
|
||||
|
||||
interface BaseRenderContextOptions {
|
||||
environment?: string | Environment;
|
||||
baseEnvironment?: Environment;
|
||||
purpose?: RenderPurpose;
|
||||
extraInfo?: ExtraRenderInfo;
|
||||
}
|
||||
@ -309,6 +310,7 @@ export async function getRenderContext(
|
||||
{
|
||||
request,
|
||||
environment,
|
||||
baseEnvironment,
|
||||
ancestors: _ancestors,
|
||||
purpose,
|
||||
extraInfo,
|
||||
@ -322,7 +324,7 @@ export async function getRenderContext(
|
||||
throw new Error('Failed to render. Could not find workspace');
|
||||
}
|
||||
|
||||
const rootEnvironment = await models.environment.getOrCreateForParentId(
|
||||
const rootEnvironment = baseEnvironment || await models.environment.getOrCreateForParentId(
|
||||
workspace ? workspace._id : 'n/a',
|
||||
);
|
||||
const subEnvironmentId = environment ?
|
||||
@ -466,6 +468,7 @@ export async function getRenderedRequestAndContext(
|
||||
{
|
||||
request,
|
||||
environment,
|
||||
baseEnvironment,
|
||||
extraInfo,
|
||||
purpose,
|
||||
}: RenderRequestOptions,
|
||||
@ -474,7 +477,7 @@ export async function getRenderedRequestAndContext(
|
||||
const workspace = ancestors.find(isWorkspace);
|
||||
const parentId = workspace ? workspace._id : 'n/a';
|
||||
const cookieJar = await models.cookieJar.getOrCreateForParentId(parentId);
|
||||
const renderContext = await getRenderContext({ request, environment, ancestors, purpose, extraInfo });
|
||||
const renderContext = await getRenderContext({ request, environment, ancestors, purpose, extraInfo, baseEnvironment });
|
||||
|
||||
// HACK: Switch '#}' to '# }' to prevent Nunjucks from barfing
|
||||
// https://github.com/kong/insomnia/issues/895
|
||||
|
@ -53,5 +53,6 @@ const runPreRequestScript = async (
|
||||
return {
|
||||
...context,
|
||||
environment: mutatedContextObject.environment,
|
||||
baseEnvironment: mutatedContextObject.baseEnvironment,
|
||||
};
|
||||
};
|
||||
|
@ -71,6 +71,10 @@ export async function createHiddenBrowserWindow(): Promise<ElectronBrowserWindow
|
||||
const hiddenBrowserWindow = new BrowserWindow({
|
||||
show: false,
|
||||
title: 'HiddenBrowserWindow',
|
||||
width: DEFAULT_WIDTH,
|
||||
height: DEFAULT_HEIGHT,
|
||||
minHeight: MINIMUM_HEIGHT,
|
||||
minWidth: MINIMUM_WIDTH,
|
||||
webPreferences: {
|
||||
contextIsolation: true,
|
||||
nodeIntegration: true,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import type { CurlRequestOptions, CurlRequestOutput } from '../main/network/libcurl-promise';
|
||||
import { Request } from '../models/request';
|
||||
import { RequestContext } from '../sdk/objects/insomnia';
|
||||
|
||||
const cancelRequestFunctionMap = new Map<string, () => void>();
|
||||
export async function cancelRequestById(requestId: string) {
|
||||
const cancel = cancelRequestFunctionMap.get(requestId);
|
||||
@ -30,6 +31,7 @@ export const cancellableRunPreRequestScript = async (options: { script: string;
|
||||
return result as {
|
||||
request: Request;
|
||||
environment: object;
|
||||
baseEnvironment: object;
|
||||
};
|
||||
} catch (err) {
|
||||
if (err.name === 'AbortError') {
|
||||
@ -62,6 +64,7 @@ export const cancellableCurlRequest = async (requestOptions: CurlRequestOptions)
|
||||
return { statusMessage: 'Error', error: err.message || 'Something went wrong' };
|
||||
}
|
||||
};
|
||||
|
||||
const cancellablePromise = ({ signal, fn }: { signal: AbortSignal; fn: Promise<any> }) => {
|
||||
if (signal?.aborted) {
|
||||
return Promise.reject(new DOMException('Aborted', 'AbortError'));
|
||||
|
@ -73,20 +73,31 @@ export const fetchRequestData = async (requestId: string) => {
|
||||
return { request, environment, settings, clientCertificates, caCert, activeEnvironmentId, timelinePath, responseId };
|
||||
};
|
||||
|
||||
export const tryToExecutePreRequestScript = async (request: Request, environment: Environment, timelinePath: string, responseId: string) => {
|
||||
export const tryToExecutePreRequestScript = async (
|
||||
request: Request,
|
||||
environment: Environment,
|
||||
timelinePath: string,
|
||||
responseId: string,
|
||||
baseEnvironment: Environment,
|
||||
) => {
|
||||
if (!request.preRequestScript) {
|
||||
return {
|
||||
request,
|
||||
environment: undefined,
|
||||
baseEnvironment: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const output = await cancellableRunPreRequestScript({
|
||||
script: request.preRequestScript,
|
||||
context: {
|
||||
request,
|
||||
timelinePath,
|
||||
environment: environment?.data || {},
|
||||
// it inputs empty environment data when active environment is the base environment
|
||||
// this is more deterministic and avoids that script accidently manipulates baseEnvironment instead of environment
|
||||
environment: environment._id === baseEnvironment._id ? {} : (environment?.data || {}),
|
||||
baseEnvironment: baseEnvironment?.data || {},
|
||||
},
|
||||
});
|
||||
console.log('[network] Pre-request script succeeded', output);
|
||||
@ -98,10 +109,18 @@ export const tryToExecutePreRequestScript = async (request: Request, environment
|
||||
);
|
||||
environment.data = output.environment;
|
||||
environment.dataPropertyOrder = envPropertyOrder.map;
|
||||
const baseEnvPropertyOrder = orderedJSON.parse(
|
||||
JSON.stringify(output.baseEnvironment),
|
||||
JSON_ORDER_PREFIX,
|
||||
JSON_ORDER_SEPARATOR,
|
||||
);
|
||||
baseEnvironment.data = output.baseEnvironment;
|
||||
baseEnvironment.dataPropertyOrder = baseEnvPropertyOrder.map;
|
||||
|
||||
return {
|
||||
request: output.request,
|
||||
environment: environment,
|
||||
environment,
|
||||
baseEnvironment,
|
||||
};
|
||||
} catch (err) {
|
||||
await fs.promises.appendFile(timelinePath, JSON.stringify({ value: err.message, name: 'Text', timestamp: Date.now() }) + '\n');
|
||||
@ -126,12 +145,14 @@ export const tryToInterpolateRequest = async (
|
||||
request: Request,
|
||||
environment: string | Environment,
|
||||
purpose?: RenderPurpose,
|
||||
extraInfo?: ExtraRenderInfo
|
||||
extraInfo?: ExtraRenderInfo,
|
||||
baseEnvironment?: Environment,
|
||||
) => {
|
||||
try {
|
||||
return await getRenderedRequestAndContext({
|
||||
request: request,
|
||||
environment,
|
||||
baseEnvironment,
|
||||
purpose,
|
||||
extraInfo,
|
||||
});
|
||||
|
@ -5,22 +5,29 @@ export interface RequestContext {
|
||||
request: Request;
|
||||
timelinePath: string;
|
||||
environment?: object;
|
||||
baseEnvironment?: object;
|
||||
}
|
||||
|
||||
export class InsomniaObject {
|
||||
public environment: Environment;
|
||||
public collectionVariables: Environment;
|
||||
public baseEnvironment: Environment;
|
||||
|
||||
constructor(
|
||||
rawObj: {
|
||||
environment: Environment;
|
||||
baseEnvironment: Environment;
|
||||
},
|
||||
) {
|
||||
this.environment = rawObj.environment;
|
||||
this.baseEnvironment = rawObj.baseEnvironment;
|
||||
this.collectionVariables = this.baseEnvironment; // collectionVariables is mapped to baseEnvironment
|
||||
}
|
||||
|
||||
toObject = () => {
|
||||
return {
|
||||
environment: this.environment.toObject(),
|
||||
baseEnvironment: this.baseEnvironment.toObject(),
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -29,10 +36,12 @@ export function initInsomniaObject(
|
||||
rawObj: RequestContext,
|
||||
) {
|
||||
const environment = new Environment(rawObj.environment);
|
||||
const baseEnvironment = new Environment(rawObj.baseEnvironment);
|
||||
|
||||
return new InsomniaObject(
|
||||
{
|
||||
environment,
|
||||
baseEnvironment,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
@ -369,15 +369,24 @@ export const sendAction: ActionFunction = async ({ request, params }) => {
|
||||
timelinePath,
|
||||
responseId,
|
||||
} = await fetchRequestData(requestId);
|
||||
const baseEnvironment = await models.environment.getOrCreateForParentId(workspaceId);
|
||||
|
||||
try {
|
||||
const { shouldPromptForPathAfterResponse } = await request.json() as SendActionParams;
|
||||
const mutatedContext = await tryToExecutePreRequestScript(req, environment, timelinePath, responseId);
|
||||
const mutatedContext = await tryToExecutePreRequestScript(req, environment, timelinePath, responseId, baseEnvironment);
|
||||
if (!mutatedContext?.request) {
|
||||
// exiy early if there was a problem with the pre-request script
|
||||
// TODO: improve error message?
|
||||
return null;
|
||||
}
|
||||
const renderedResult = await tryToInterpolateRequest(mutatedContext.request, mutatedContext.environment || environment._id, RENDER_PURPOSE_SEND);
|
||||
|
||||
const renderedResult = await tryToInterpolateRequest(
|
||||
mutatedContext.request,
|
||||
mutatedContext.environment || environment._id,
|
||||
RENDER_PURPOSE_SEND,
|
||||
undefined,
|
||||
mutatedContext.baseEnvironment,
|
||||
);
|
||||
const renderedRequest = await tryToTransformRequestWithPlugins(renderedResult);
|
||||
|
||||
// TODO: remove this temporary hack to support GraphQL variables in the request body properly
|
||||
|
Loading…
Reference in New Issue
Block a user