Skip to content

Commit 6a8f806

Browse files
committed
Merge branch 'release/7.48.0'
2 parents 86446d1 + 793db38 commit 6a8f806

File tree

7 files changed

+168
-21
lines changed

7 files changed

+168
-21
lines changed

CHANGELOG.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
7.48.0:
2+
date: 2025-09-25
3+
new features:
4+
- >-
5+
GH-1530 Pass any stored referenced request metadata and root item id to
6+
nested request resolver
7+
fixed bugs:
8+
- >-
9+
GH-1529 Prevent crashes from nested request events after root request is
10+
aborted
11+
112
7.47.1:
213
date: 2025-09-19
314
chores:

lib/runner/extensions/event.command.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,8 @@ module.exports = {
293293

294294
isNestedRequest = this.state.nestedRequest !== undefined,
295295

296-
rootItemId = isNestedRequest ? this.state.nestedRequest.rootItemId : item.id,
296+
rootItemId = isNestedRequest && this.state.nestedRequest.rootItem ?
297+
this.state.nestedRequest.rootItem.id : item.id,
297298

298299
// create copy of cursor so we don't leak script ids outside `event.command`
299300
// and across scripts

lib/runner/index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,10 @@ _.assign(Runner.prototype, {
7373
* @param {Number} [options.nestedRequest.rootCursor] - The cursor of the root request that spun up this
7474
* nested request runner. This is recursively passed down to keep track of which execution started the chain
7575
* and modify cursors for all nested req events for reporters built on top of postman-runtime.
76-
* @param {Number} [options.nestedRequest.rootItemId] - The id of the root item that spawned this nested request.
76+
* @param {Number} [options.nestedRequest.rootItem] - The root item that spawned this nested request.
7777
* Used by vault to get consent for root request and determine whether vault access check was performed even once
78-
* throughout the chain.
78+
* throughout the chain. And by request resolver bridge to receive any stored metadata like name/location of
79+
* the request being resolved
7980
* @param {Number} [options.nestedRequest.hasVaultAccess] - Mutated and set by any nested or parent request
8081
* to indicate whether vault access check has been performed.
8182
* @param {Number} [options.nestedRequest.invocationCount] - The number of requests currently accummulated

lib/runner/nested-request.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function runNestedRequest ({ executionId, isExecutionSkipped, vaultSecrets, item
2727
self.state.nestedRequest = _.defaults(self.state.nestedRequest || {}, {
2828
isNestedRequest: true,
2929
rootCursor: cursor,
30-
rootItemId: item.id,
30+
rootItem: item,
3131
invocationCount: 0
3232
});
3333

@@ -39,8 +39,23 @@ function runNestedRequest ({ executionId, isExecutionSkipped, vaultSecrets, item
3939
' calls have been reached for this request.'));
4040
}
4141

42+
let rootRequestEventsList = self.state.nestedRequest.rootItem.events?.all?.() || [],
43+
nestedRequestMeta = null,
44+
context = { rootItemId: self.state.nestedRequest.rootItem.id };
45+
46+
for (const event of rootRequestEventsList) {
47+
if (event.script?.requests?.[requestToRunId]) {
48+
nestedRequestMeta = event.script.requests[requestToRunId];
49+
break;
50+
}
51+
}
52+
53+
if (nestedRequestMeta) {
54+
context.nestedRequestMeta = nestedRequestMeta;
55+
}
56+
4257
// Should fetch the request from the consumer of postman-runtime & resolve scripts and variables
43-
requestResolver(requestToRunId, function (err, collection) {
58+
requestResolver(requestToRunId, context, function (err, collection) {
4459
if (err) {
4560
return dispatchErrorToListener(err);
4661
}
@@ -159,7 +174,7 @@ function runNestedRequest ({ executionId, isExecutionSkipped, vaultSecrets, item
159174
// For nested requests, the request event should bubble up to the parent.
160175
// This event is merely used for notifying the consumer that a nested request was sent
161176
// similar to pm.sendRequest. So the consumer can work this into logs & any other logic.
162-
if (typeof self.triggers.request === 'function') {
177+
if (typeof self.triggers.request === 'function' && self.state && self.state.nestedRequest) {
163178
self.triggers.request(err, self.state.nestedRequest.rootCursor, ...rest);
164179
}
165180
},

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "postman-runtime",
3-
"version": "7.47.1",
3+
"version": "7.48.0",
44
"description": "Underlying library of executing Postman Collections",
55
"author": "Postman Inc.",
66
"license": "Apache-2.0",

test/integration/runner-spec/run-collection-request.test.js

Lines changed: 131 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const sdk = require('postman-collection'),
2+
sinon = require('sinon').createSandbox(),
23
collectionRunner = require('../../../lib/runner');
34

45
describe('pm.execution.runRequest handling', function () {
@@ -30,7 +31,7 @@ describe('pm.execution.runRequest handling', function () {
3031
new collectionRunner().run(collection,
3132
{
3233
script: {
33-
requestResolver (_requestId, callback) {
34+
requestResolver (_requestId, _nestedRequestContext, callback) {
3435
callback(null, {
3536
item: {
3637
id: 'nested-request-id',
@@ -89,6 +90,66 @@ describe('pm.execution.runRequest handling', function () {
8990
});
9091
});
9192

93+
it('should provide req metadata from event.requests object to resolver along with root req id', function (done) {
94+
const requestsMeta = {
95+
// Refer to postman-collection package to know more about this field
96+
'nested-request-id': {
97+
location: ['Collection Name', 'Folder Name', 'Request Name']
98+
}
99+
},
100+
collection = new sdk.Collection({
101+
item: [{
102+
id: 'root-request-id',
103+
event: [{
104+
listen: 'prerequest',
105+
script: {
106+
exec: `
107+
await pm.execution.runRequest("nested-request-id");
108+
await pm.execution.runRequest("nested-request-id-without-fallback");
109+
`,
110+
requests: requestsMeta
111+
}
112+
}],
113+
request: {
114+
url: 'https://postman-echo.com/get',
115+
method: 'GET'
116+
}
117+
}]
118+
});
119+
120+
new collectionRunner().run(collection, {
121+
script: {
122+
requestResolver: (nestedRequestId, nestedRequestContext, callback) => {
123+
expect(typeof callback).to.eql('function');
124+
expect(nestedRequestContext).to.be.ok;
125+
expect(nestedRequestContext.rootItemId).to.eql('root-request-id');
126+
127+
if (nestedRequestId === 'nested-request-id') {
128+
expect(nestedRequestContext.nestedRequestMeta).to.eql(requestsMeta['nested-request-id']);
129+
}
130+
131+
if (nestedRequestId === 'nested-request-id-without-fallback') {
132+
// Should be empty for this request
133+
expect(nestedRequestContext.nestedRequestMeta).to.not.be.ok;
134+
}
135+
136+
return callback(null, {
137+
item: {
138+
id: 'nested-request-id',
139+
request: { url: 'https://postman-echo.com/post', method: 'POST' }
140+
}
141+
});
142+
}
143+
}
144+
}, function (_err, run) {
145+
run.start({
146+
done (err) {
147+
done(err);
148+
}
149+
});
150+
});
151+
});
152+
92153
it('should handle for exceptions thrown from nested request parsing or uncaught errors', function (done) {
93154
const collection = new sdk.Collection({
94155
item: [{
@@ -116,7 +177,7 @@ describe('pm.execution.runRequest handling', function () {
116177
new collectionRunner().run(collection,
117178
{
118179
script: {
119-
requestResolver (_requestId, callback) {
180+
requestResolver (_requestId, _nestedRequestContext, callback) {
120181
callback(null, {
121182
item: {
122183
id: 'nested-request-id',
@@ -171,7 +232,7 @@ describe('pm.execution.runRequest handling', function () {
171232
new collectionRunner().run(collection,
172233
{
173234
script: {
174-
requestResolver (_requestId, callback) {
235+
requestResolver (_requestId, _nestedRequestContext, callback) {
175236
callback(null, {
176237
item: {
177238
id: 'nested-request-id',
@@ -236,7 +297,7 @@ describe('pm.execution.runRequest handling', function () {
236297
new collectionRunner().run(collection,
237298
{
238299
script: {
239-
requestResolver (_requestId, callback) {
300+
requestResolver (_requestId, _nestedRequestContext, callback) {
240301
callback(null, {
241302
item: {
242303
id: 'nested-request-id',
@@ -330,7 +391,7 @@ describe('pm.execution.runRequest handling', function () {
330391
new collectionRunner().run(collection,
331392
{
332393
script: {
333-
requestResolver (_requestId, callback) {
394+
requestResolver (_requestId, _nestedRequestContext, callback) {
334395
callback(null, {
335396
item: {
336397
id: 'nested-request-id',
@@ -411,7 +472,7 @@ describe('pm.execution.runRequest handling', function () {
411472
new collectionRunner().run(collection,
412473
{
413474
script: {
414-
requestResolver (_requestId, callback) {
475+
requestResolver (_requestId, _nestedRequestContext, callback) {
415476
callback(null, {
416477
item: {
417478
id: 'nested-request-id',
@@ -476,7 +537,7 @@ describe('pm.execution.runRequest handling', function () {
476537
new collectionRunner().run(collection,
477538
{
478539
script: {
479-
requestResolver (_requestId, callback) {
540+
requestResolver (_requestId, _nestedRequestContext, callback) {
480541
callback(null, {
481542
item: {
482543
id: 'nested-request-id',
@@ -526,7 +587,7 @@ describe('pm.execution.runRequest handling', function () {
526587
new collectionRunner().run(collection,
527588
{
528589
script: {
529-
requestResolver (_requestId, callback) {
590+
requestResolver (_requestId, _nestedRequestContext, callback) {
530591
callback(null, {
531592
item: {
532593
id: 'nested-request-id',
@@ -594,7 +655,7 @@ describe('pm.execution.runRequest handling', function () {
594655
new collectionRunner().run(collection,
595656
{
596657
script: {
597-
requestResolver (_requestId, callback) {
658+
requestResolver (_requestId, _nestedRequestContext, callback) {
598659
callback(null, {
599660
item: {
600661
id: 'nested-request-id',
@@ -682,7 +743,7 @@ describe('pm.execution.runRequest handling', function () {
682743
{
683744
vaultSecrets: vaultSecrets,
684745
script: {
685-
requestResolver (_requestId, callback) {
746+
requestResolver (_requestId, _nestedRequestContext, callback) {
686747
callback(null, {
687748
item: {
688749
id: 'nested-request-id',
@@ -760,7 +821,7 @@ describe('pm.execution.runRequest handling', function () {
760821
new collectionRunner().run(collection,
761822
{
762823
script: {
763-
requestResolver (_requestId, callback) {
824+
requestResolver (_requestId, _nestedRequestContext, callback) {
764825
callback(null, {
765826
item: {
766827
id: 'nested-request-id',
@@ -832,7 +893,7 @@ describe('pm.execution.runRequest handling', function () {
832893
new collectionRunner().run(collection,
833894
{
834895
script: {
835-
requestResolver (_requestId, callback) {
896+
requestResolver (_requestId, _nestedRequestContext, callback) {
836897
callback(null, {
837898
item: {
838899
id: 'nested-request-id',
@@ -885,4 +946,62 @@ describe('pm.execution.runRequest handling', function () {
885946
});
886947
});
887948
});
949+
950+
it('should not invoke any events if root request is cancelled', function (done) {
951+
const collection = new sdk.Collection({
952+
item: [{
953+
event: [
954+
{
955+
listen: 'prerequest',
956+
script: { exec: 'await pm.execution.runRequest("nested-request-id");' }
957+
}
958+
],
959+
request: {
960+
url: 'https://postman-echo.com/get',
961+
method: 'GET'
962+
}
963+
}]
964+
});
965+
966+
new collectionRunner().run(collection,
967+
{
968+
script: {
969+
requestResolver (_requestId, _nestedRequestContext, callback) {
970+
callback(null, {
971+
item: {
972+
id: 'nested-request-id',
973+
request: {
974+
url: 'https://postman-echo.com/post',
975+
method: 'POST'
976+
}
977+
}
978+
});
979+
}
980+
}
981+
},
982+
function (_err, run) {
983+
const callbacks = {
984+
start: sinon.spy(),
985+
abort: sinon.spy(),
986+
request: sinon.spy()
987+
};
988+
989+
callbacks.done = sinon.spy(function () {
990+
expect(run.state.nestedRequest).to.be.undefined;
991+
expect(callbacks).to.be.ok;
992+
expect(callbacks.done.getCall(0).args[0]).to.be.null;
993+
expect(callbacks).to.nested.include({
994+
'start.calledOnce': true,
995+
'abort.calledOnce': true,
996+
'request.calledOnce': false
997+
});
998+
999+
return done();
1000+
});
1001+
1002+
run.start(callbacks);
1003+
// Abort root run
1004+
run.abort();
1005+
});
1006+
});
8881007
});

0 commit comments

Comments
 (0)