Skip to content

Commit 2da1c38

Browse files
ihexxajackkav
authored andcommitted
feat(hidden-window): enable baseEnvironment in the pre-request scripting (Kong#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
1 parent 16d230c commit 2da1c38

9 files changed

Lines changed: 126 additions & 11 deletions

File tree

packages/insomnia-smoke-test/fixtures/smoke-test-collection.yaml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ resources:
177177
settingFollowRedirects: global
178178
_type: request
179179
- _id: req_89dade2ee9ee42fbb22d588783a9df3c
180-
parentId: wrk_5b5ab67830944ffcbec47528366ef403
180+
parentId: fld_01de564274824ecaad272330339ea6b2
181181
modified: 1636707449231
182182
created: 1636141014552
183183
url: http://127.0.0.1:4010/echo
@@ -202,7 +202,8 @@ resources:
202202
modified: 1636140994432
203203
created: 1636140994432
204204
name: Base Environment
205-
data: {}
205+
data:
206+
customValue: "fromEnvManager"
206207
dataPropertyOrder: null
207208
color: null
208209
isPrivate: false
@@ -264,8 +265,19 @@ resources:
264265
settingRebuildPath: true
265266
settingFollowRedirects: global
266267
_type: request
267-
- _id: req_0769dca686df49358082b2183dfa073d
268+
- _id: fld_01de564274824ecaad272330339ea6b2
268269
parentId: wrk_5b5ab67830944ffcbec47528366ef403
270+
modified: 1668533312225
271+
created: 1668533312225
272+
name: FolderWithEnv
273+
description: ""
274+
environment:
275+
customValue: "fromFolder"
276+
environmentPropertyOrder: null
277+
metaSortKey: -1668533312225
278+
_type: request_group
279+
- _id: req_0769dca686df49358082b2183dfa073d
280+
parentId: fld_01de564274824ecaad272330339ea6b2
269281
modified: 1643892278711
270282
created: 1643892270079
271283
url: http://127.0.0.1:4010/echo

packages/insomnia-smoke-test/tests/smoke/pre-request-script-ui.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,59 @@ test.describe('pre-request UI tests', async () => {
4545
predefined: 'updatedByScript',
4646
},
4747
},
48+
{
49+
name: 'environments / populate environments',
50+
preReqScript: `
51+
insomnia.baseEnvironment.set('fromBaseEnv', 'baseEnv');
52+
`,
53+
body: `{
54+
"fromBaseEnv": "{{ _.fromBaseEnv }}"
55+
}`,
56+
expectedBody: {
57+
fromBaseEnv: 'baseEnv',
58+
},
59+
},
60+
{
61+
name: 'environments / override base environments',
62+
preReqScript: `
63+
insomnia.baseEnvironment.set('scriptValue', 'fromBase');
64+
insomnia.environment.set('scriptValue', 'fromEnv');
65+
`,
66+
body: `{
67+
"scriptValue": "{{ _.scriptValue }}"
68+
}`,
69+
expectedBody: {
70+
scriptValue: 'fromEnv',
71+
},
72+
},
73+
{
74+
name: 'environments / override predefined base environment in script',
75+
preReqScript: `
76+
// "preDefinedValue" is already defined in the base environment modal.
77+
// but it is rewritten here
78+
insomnia.baseEnvironment.set('preDefinedValue', 'fromScript');
79+
`,
80+
body: `{
81+
"preDefinedValue": "{{ _.preDefinedValue }}"
82+
}`,
83+
expectedBody: {
84+
preDefinedValue: 'fromScript',
85+
},
86+
},
87+
{
88+
name: 'environments/ envrionment from script should be overidden by folder environment',
89+
preReqScript: `
90+
// "customValue" is already defined in the folder environment.
91+
// folder version will override the following wone
92+
insomnia.baseEnvironment.set('customValue', 'fromScript');
93+
`,
94+
body: `{
95+
"customValue": "{{ _.customValue }}"
96+
}`,
97+
expectedBody: {
98+
customValue: 'fromFolder',
99+
},
100+
},
48101
];
49102

50103
for (let i = 0; i < testCases.length; i++) {

packages/insomnia/src/common/render.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ interface RenderRequest<T extends Request | GrpcRequest | WebSocketRequest> {
298298

299299
interface BaseRenderContextOptions {
300300
environment?: string | Environment;
301+
baseEnvironment?: Environment;
301302
purpose?: RenderPurpose;
302303
extraInfo?: ExtraRenderInfo;
303304
}
@@ -309,6 +310,7 @@ export async function getRenderContext(
309310
{
310311
request,
311312
environment,
313+
baseEnvironment,
312314
ancestors: _ancestors,
313315
purpose,
314316
extraInfo,
@@ -322,7 +324,7 @@ export async function getRenderContext(
322324
throw new Error('Failed to render. Could not find workspace');
323325
}
324326

325-
const rootEnvironment = await models.environment.getOrCreateForParentId(
327+
const rootEnvironment = baseEnvironment || await models.environment.getOrCreateForParentId(
326328
workspace ? workspace._id : 'n/a',
327329
);
328330
const subEnvironmentId = environment ?
@@ -466,6 +468,7 @@ export async function getRenderedRequestAndContext(
466468
{
467469
request,
468470
environment,
471+
baseEnvironment,
469472
extraInfo,
470473
purpose,
471474
}: RenderRequestOptions,
@@ -474,7 +477,7 @@ export async function getRenderedRequestAndContext(
474477
const workspace = ancestors.find(isWorkspace);
475478
const parentId = workspace ? workspace._id : 'n/a';
476479
const cookieJar = await models.cookieJar.getOrCreateForParentId(parentId);
477-
const renderContext = await getRenderContext({ request, environment, ancestors, purpose, extraInfo });
480+
const renderContext = await getRenderContext({ request, environment, ancestors, purpose, extraInfo, baseEnvironment });
478481

479482
// HACK: Switch '#}' to '# }' to prevent Nunjucks from barfing
480483
// https://github.com/kong/insomnia/issues/895

packages/insomnia/src/hidden-window.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,6 @@ const runPreRequestScript = async (
5353
return {
5454
...context,
5555
environment: mutatedContextObject.environment,
56+
baseEnvironment: mutatedContextObject.baseEnvironment,
5657
};
5758
};

packages/insomnia/src/main/window-utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export async function createHiddenBrowserWindow(): Promise<ElectronBrowserWindow
7171
const hiddenBrowserWindow = new BrowserWindow({
7272
show: false,
7373
title: 'HiddenBrowserWindow',
74+
width: DEFAULT_WIDTH,
75+
height: DEFAULT_HEIGHT,
76+
minHeight: MINIMUM_HEIGHT,
77+
minWidth: MINIMUM_WIDTH,
7478
webPreferences: {
7579
contextIsolation: true,
7680
nodeIntegration: true,

packages/insomnia/src/network/cancellation.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { CurlRequestOptions, CurlRequestOutput } from '../main/network/libcurl-promise';
22
import { Request } from '../models/request';
33
import { RequestContext } from '../sdk/objects/insomnia';
4+
45
const cancelRequestFunctionMap = new Map<string, () => void>();
56
export async function cancelRequestById(requestId: string) {
67
const cancel = cancelRequestFunctionMap.get(requestId);
@@ -30,6 +31,7 @@ export const cancellableRunPreRequestScript = async (options: { script: string;
3031
return result as {
3132
request: Request;
3233
environment: object;
34+
baseEnvironment: object;
3335
};
3436
} catch (err) {
3537
if (err.name === 'AbortError') {
@@ -62,6 +64,7 @@ export const cancellableCurlRequest = async (requestOptions: CurlRequestOptions)
6264
return { statusMessage: 'Error', error: err.message || 'Something went wrong' };
6365
}
6466
};
67+
6568
const cancellablePromise = ({ signal, fn }: { signal: AbortSignal; fn: Promise<any> }) => {
6669
if (signal?.aborted) {
6770
return Promise.reject(new DOMException('Aborted', 'AbortError'));

packages/insomnia/src/network/network.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,31 @@ export const fetchRequestData = async (requestId: string) => {
7373
return { request, environment, settings, clientCertificates, caCert, activeEnvironmentId, timelinePath, responseId };
7474
};
7575

76-
export const tryToExecutePreRequestScript = async (request: Request, environment: Environment, timelinePath: string, responseId: string) => {
76+
export const tryToExecutePreRequestScript = async (
77+
request: Request,
78+
environment: Environment,
79+
timelinePath: string,
80+
responseId: string,
81+
baseEnvironment: Environment,
82+
) => {
7783
if (!request.preRequestScript) {
7884
return {
7985
request,
8086
environment: undefined,
87+
baseEnvironment: undefined,
8188
};
8289
}
90+
8391
try {
8492
const output = await cancellableRunPreRequestScript({
8593
script: request.preRequestScript,
8694
context: {
8795
request,
8896
timelinePath,
89-
environment: environment?.data || {},
97+
// it inputs empty environment data when active environment is the base environment
98+
// this is more deterministic and avoids that script accidently manipulates baseEnvironment instead of environment
99+
environment: environment._id === baseEnvironment._id ? {} : (environment?.data || {}),
100+
baseEnvironment: baseEnvironment?.data || {},
90101
},
91102
});
92103
console.log('[network] Pre-request script succeeded', output);
@@ -98,10 +109,18 @@ export const tryToExecutePreRequestScript = async (request: Request, environment
98109
);
99110
environment.data = output.environment;
100111
environment.dataPropertyOrder = envPropertyOrder.map;
112+
const baseEnvPropertyOrder = orderedJSON.parse(
113+
JSON.stringify(output.baseEnvironment),
114+
JSON_ORDER_PREFIX,
115+
JSON_ORDER_SEPARATOR,
116+
);
117+
baseEnvironment.data = output.baseEnvironment;
118+
baseEnvironment.dataPropertyOrder = baseEnvPropertyOrder.map;
101119

102120
return {
103121
request: output.request,
104-
environment: environment,
122+
environment,
123+
baseEnvironment,
105124
};
106125
} catch (err) {
107126
await fs.promises.appendFile(timelinePath, JSON.stringify({ value: err.message, name: 'Text', timestamp: Date.now() }) + '\n');
@@ -126,12 +145,14 @@ export const tryToInterpolateRequest = async (
126145
request: Request,
127146
environment: string | Environment,
128147
purpose?: RenderPurpose,
129-
extraInfo?: ExtraRenderInfo
148+
extraInfo?: ExtraRenderInfo,
149+
baseEnvironment?: Environment,
130150
) => {
131151
try {
132152
return await getRenderedRequestAndContext({
133153
request: request,
134154
environment,
155+
baseEnvironment,
135156
purpose,
136157
extraInfo,
137158
});

packages/insomnia/src/sdk/objects/insomnia.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,29 @@ export interface RequestContext {
55
request: Request;
66
timelinePath: string;
77
environment?: object;
8+
baseEnvironment?: object;
89
}
910

1011
export class InsomniaObject {
1112
public environment: Environment;
13+
public collectionVariables: Environment;
14+
public baseEnvironment: Environment;
1215

1316
constructor(
1417
rawObj: {
1518
environment: Environment;
19+
baseEnvironment: Environment;
1620
},
1721
) {
1822
this.environment = rawObj.environment;
23+
this.baseEnvironment = rawObj.baseEnvironment;
24+
this.collectionVariables = this.baseEnvironment; // collectionVariables is mapped to baseEnvironment
1925
}
2026

2127
toObject = () => {
2228
return {
2329
environment: this.environment.toObject(),
30+
baseEnvironment: this.baseEnvironment.toObject(),
2431
};
2532
};
2633
}
@@ -29,10 +36,12 @@ export function initInsomniaObject(
2936
rawObj: RequestContext,
3037
) {
3138
const environment = new Environment(rawObj.environment);
39+
const baseEnvironment = new Environment(rawObj.baseEnvironment);
3240

3341
return new InsomniaObject(
3442
{
3543
environment,
44+
baseEnvironment,
3645
},
3746
);
3847
};

packages/insomnia/src/ui/routes/request.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,15 +369,24 @@ export const sendAction: ActionFunction = async ({ request, params }) => {
369369
timelinePath,
370370
responseId,
371371
} = await fetchRequestData(requestId);
372+
const baseEnvironment = await models.environment.getOrCreateForParentId(workspaceId);
373+
372374
try {
373375
const { shouldPromptForPathAfterResponse } = await request.json() as SendActionParams;
374-
const mutatedContext = await tryToExecutePreRequestScript(req, environment, timelinePath, responseId);
376+
const mutatedContext = await tryToExecutePreRequestScript(req, environment, timelinePath, responseId, baseEnvironment);
375377
if (!mutatedContext?.request) {
376378
// exiy early if there was a problem with the pre-request script
377379
// TODO: improve error message?
378380
return null;
379381
}
380-
const renderedResult = await tryToInterpolateRequest(mutatedContext.request, mutatedContext.environment || environment._id, RENDER_PURPOSE_SEND);
382+
383+
const renderedResult = await tryToInterpolateRequest(
384+
mutatedContext.request,
385+
mutatedContext.environment || environment._id,
386+
RENDER_PURPOSE_SEND,
387+
undefined,
388+
mutatedContext.baseEnvironment,
389+
);
381390
const renderedRequest = await tryToTransformRequestWithPlugins(renderedResult);
382391

383392
// TODO: remove this temporary hack to support GraphQL variables in the request body properly

0 commit comments

Comments
 (0)