@@ -2,6 +2,7 @@ var _ = require('lodash'),
22 uuid = require ( 'uuid' ) ,
33 Response = require ( 'postman-collection' ) . Response ,
44 visualizer = require ( '../../visualizer' ) ,
5+ resolveSecrets = require ( '../resolve-secrets' ) . resolveSecrets ,
56
67 /**
78 * List of request properties which can be mutated via pre-request
@@ -121,7 +122,11 @@ module.exports = {
121122 stopOnFailure = this . options . stopOnFailure ,
122123 delay = _ . get ( this . options , 'delay.item' ) ,
123124
124- ctxTemplate ;
125+ ctxTemplate ,
126+ self = this ,
127+ secretResolvers = this . state . secretResolvers ,
128+ secretResolutionPayload ,
129+ executeItemFlow ;
125130
126131 // validate minimum parameters required for the command to work
127132 if ( ! ( item && coords ) ) {
@@ -134,160 +139,197 @@ module.exports = {
134139 // here we code to queue prerequest script, then make a request and then execute test script
135140 this . triggers . beforeItem ( null , coords , item ) ;
136141
137- this . queueDelay ( function ( ) {
142+ // Build payload for secret resolution
143+ // Only scan environment, globals, and collectionVariables for secrets
144+ secretResolutionPayload = {
145+ item,
146+ environment,
147+ globals,
148+ collectionVariables
149+ } ;
150+
151+ /**
152+ * Execute the main item flow (delay, prerequest, request, test)
153+ */
154+ executeItemFlow = function ( ) {
155+ self . queueDelay ( function ( ) {
138156 // create the context object for scripts to run
139- ctxTemplate = {
140- collectionVariables : collectionVariables ,
141- vaultSecrets : vaultSecrets ,
142- _variables : _variables ,
143- globals : globals ,
144- environment : environment ,
145- data : data ,
146- request : item . request
147- } ;
148-
149- // @todo make it less nested by coding Instruction.thenQueue
150- this . queue ( 'event' , {
151- name : 'prerequest' ,
152- item : item ,
153- coords : coords ,
154- context : ctxTemplate ,
155- // No need to include vaultSecrets here as runtime takes care of tracking internally
156- trackContext : [ 'globals' , 'environment' , 'collectionVariables' ] ,
157- stopOnScriptError : stopOnError ,
158- stopOnFailure : stopOnFailure
159- } ) . done ( function ( prereqExecutions , prereqExecutionError , shouldSkipExecution ) {
160- // if stop on error is marked and script executions had an error,
161- // do not proceed with more commands, instead we bail out
162- if ( ( stopOnError || stopOnFailure ) && prereqExecutionError ) {
163- this . triggers . item ( null , coords , item ) ; // @todo - should this trigger receive error?
164-
165- return callback && callback . call ( this , prereqExecutionError , {
166- prerequest : prereqExecutions
167- } ) ;
168- }
169-
170- if ( shouldSkipExecution ) {
171- this . triggers . item ( prereqExecutionError , coords , item , null , { isSkipped : true } ) ;
172-
173- return callback && callback . call ( this , prereqExecutionError , {
174- prerequest : prereqExecutions
175- } ) ;
176- }
177-
178- // update allowed request mutation properties with the mutated context
179- // @note from this point forward, make sure this mutated
180- // request instance is used for upcoming commands.
181- ALLOWED_REQUEST_MUTATIONS . forEach ( function ( property ) {
182- if ( _ . has ( ctxTemplate , [ 'request' , property ] ) ) {
183- item . request [ property ] = ctxTemplate . request [ property ] ;
184- }
185-
186- // update property's parent reference
187- if ( item . request [ property ] && typeof item . request [ property ] . setParent === 'function' ) {
188- item . request [ property ] . setParent ( item . request ) ;
189- }
190- } ) ;
191-
192- this . queue ( 'request' , {
157+ ctxTemplate = {
158+ collectionVariables : collectionVariables ,
159+ vaultSecrets : vaultSecrets ,
160+ _variables : _variables ,
161+ globals : globals ,
162+ environment : environment ,
163+ data : data ,
164+ request : item . request
165+ } ;
166+
167+ // @todo make it less nested by coding Instruction.thenQueue
168+ this . queue ( 'event' , {
169+ name : 'prerequest' ,
193170 item : item ,
194- vaultSecrets : ctxTemplate . vaultSecrets ,
195- globals : ctxTemplate . globals ,
196- environment : ctxTemplate . environment ,
197- collectionVariables : ctxTemplate . collectionVariables ,
198- _variables : ctxTemplate . _variables ,
199- data : ctxTemplate . data ,
200171 coords : coords ,
201- source : 'collection' ,
202- secretResolver : this . state . secretResolver
203- } ) . done ( function ( result , requestError ) {
204- ! result && ( result = { } ) ;
205-
206- var request = result . request ,
207- response = result . response ,
208- cookies = result . cookies ;
209-
210- if ( ( stopOnError || stopOnFailure ) && requestError ) {
172+ context : ctxTemplate ,
173+ // No need to include vaultSecrets here as runtime takes care of tracking internally
174+ trackContext : [ 'globals' , 'environment' , 'collectionVariables' ] ,
175+ stopOnScriptError : stopOnError ,
176+ stopOnFailure : stopOnFailure
177+ } ) . done ( function ( prereqExecutions , prereqExecutionError , shouldSkipExecution ) {
178+ // if stop on error is marked and script executions had an error,
179+ // do not proceed with more commands, instead we bail out
180+ if ( ( stopOnError || stopOnFailure ) && prereqExecutionError ) {
211181 this . triggers . item ( null , coords , item ) ; // @todo - should this trigger receive error?
212182
213- return callback && callback . call ( this , requestError , {
214- request
183+ return callback && callback . call ( this , prereqExecutionError , {
184+ prerequest : prereqExecutions
215185 } ) ;
216186 }
217187
218- // also the test object requires the updated request object (since auth helpers may modify it)
219- request && ( ctxTemplate . request = request ) ;
188+ if ( shouldSkipExecution ) {
189+ this . triggers . item ( prereqExecutionError , coords , item , null , { isSkipped : true } ) ;
220190
221- // @note convert response instance to plain object.
222- // we want to avoid calling Response.toJSON() which triggers toJSON on Response.stream buffer.
223- // Because that increases the size of stringified object by 3 times.
224- // Also, that increases the total number of tokens (buffer.data) whereas Buffer.toString
225- // generates a single string that is easier to stringify and sent over the UVM bridge.
226- response && ( ctxTemplate . response = getResponseJSON ( response ) ) ;
191+ return callback && callback . call ( this , prereqExecutionError , {
192+ prerequest : prereqExecutions
193+ } ) ;
194+ }
227195
228- // set cookies for this transaction
229- cookies && ( ctxTemplate . cookies = cookies ) ;
196+ // update allowed request mutation properties with the mutated context
197+ // @note from this point forward, make sure this mutated
198+ // request instance is used for upcoming commands.
199+ ALLOWED_REQUEST_MUTATIONS . forEach ( function ( property ) {
200+ if ( _ . has ( ctxTemplate , [ 'request' , property ] ) ) {
201+ item . request [ property ] = ctxTemplate . request [ property ] ;
202+ }
230203
231- // the context template also has a test object to store assertions
232- ctxTemplate . tests = { } ; // @todo remove
204+ // update property's parent reference
205+ if ( item . request [ property ] && typeof item . request [ property ] . setParent === 'function' ) {
206+ item . request [ property ] . setParent ( item . request ) ;
207+ }
208+ } ) ;
233209
234- this . queue ( 'event' , {
235- name : 'test' ,
210+ this . queue ( 'request' , {
236211 item : item ,
212+ vaultSecrets : ctxTemplate . vaultSecrets ,
213+ globals : ctxTemplate . globals ,
214+ environment : ctxTemplate . environment ,
215+ collectionVariables : ctxTemplate . collectionVariables ,
216+ _variables : ctxTemplate . _variables ,
217+ data : ctxTemplate . data ,
237218 coords : coords ,
238- context : ctxTemplate ,
239- // No need to include vaultSecrets here as runtime takes care of tracking internally
240- trackContext : [ 'tests' , 'globals' , 'environment' , 'collectionVariables' ] ,
241- stopOnScriptError : stopOnError ,
242- abortOnFailure : abortOnFailure ,
243- stopOnFailure : stopOnFailure
244- } ) . done ( function ( testExecutions , testExecutionError ) {
245- var visualizerData = extractVisualizerData ( prereqExecutions , testExecutions ) ,
246- visualizerResult ;
247-
248- if ( visualizerData ) {
249- visualizer . processTemplate ( visualizerData . template ,
250- visualizerData . data ,
251- visualizerData . options ,
252- function ( err , processedTemplate ) {
253- visualizerResult = {
254- // bubble up the errors while processing template through visualizer result
255- error : err ,
219+ source : 'collection'
220+ } ) . done ( function ( result , requestError ) {
221+ ! result && ( result = { } ) ;
222+
223+ var request = result . request ,
224+ response = result . response ,
225+ cookies = result . cookies ;
256226
257- // add processed template and data to visualizer result
258- processedTemplate : processedTemplate ,
259- data : visualizerData . data
260- } ;
227+ if ( ( stopOnError || stopOnFailure ) && requestError ) {
228+ this . triggers . item ( null , coords , item ) ; // @todo - should this trigger receive error?
261229
262- // trigger an event saying that item has been processed
263- this . triggers . item ( null , coords , item , visualizerResult ) ;
264- } . bind ( this ) ) ;
230+ return callback && callback . call ( this , requestError , {
231+ request
232+ } ) ;
265233 }
266- else {
234+
235+ // also the test object requires the updated request object
236+ // (since auth helpers may modify it)
237+ request && ( ctxTemplate . request = request ) ;
238+
239+ // @note convert response instance to plain object.
240+ // we want to avoid calling Response.toJSON() which triggers
241+ // toJSON on Response.stream buffer.
242+ // Because that increases the size of stringified object by 3 times.
243+ // Also, that increases the total number of tokens (buffer.data) whereas Buffer.toString
244+ // generates a single string that is easier to stringify and sent over the UVM bridge.
245+ response && ( ctxTemplate . response = getResponseJSON ( response ) ) ;
246+
247+ // set cookies for this transaction
248+ cookies && ( ctxTemplate . cookies = cookies ) ;
249+
250+ // the context template also has a test object to store assertions
251+ ctxTemplate . tests = { } ; // @todo remove
252+
253+ this . queue ( 'event' , {
254+ name : 'test' ,
255+ item : item ,
256+ coords : coords ,
257+ context : ctxTemplate ,
258+ // No need to include vaultSecrets here as runtime takes care of tracking internally
259+ trackContext : [ 'tests' , 'globals' , 'environment' , 'collectionVariables' ] ,
260+ stopOnScriptError : stopOnError ,
261+ abortOnFailure : abortOnFailure ,
262+ stopOnFailure : stopOnFailure
263+ } ) . done ( function ( testExecutions , testExecutionError ) {
264+ var visualizerData = extractVisualizerData ( prereqExecutions , testExecutions ) ,
265+ visualizerResult ;
266+
267+ if ( visualizerData ) {
268+ visualizer . processTemplate ( visualizerData . template ,
269+ visualizerData . data ,
270+ visualizerData . options ,
271+ function ( err , processedTemplate ) {
272+ visualizerResult = {
273+ // bubble up the errors while processing template through visualizer result
274+ error : err ,
275+
276+ // add processed template and data to visualizer result
277+ processedTemplate : processedTemplate ,
278+ data : visualizerData . data
279+ } ;
280+
281+ // trigger an event saying that item has been processed
282+ this . triggers . item ( null , coords , item , visualizerResult ) ;
283+ } . bind ( this ) ) ;
284+ }
285+ else {
267286 // trigger an event saying that item has been processed
268287 // @todo - should this trigger receive error?
269- this . triggers . item ( null , coords , item , null ) ;
270- }
271-
272- // reset mutated request with original request instance
273- // @note request mutations are not persisted across iterations
274- item . request = originalRequest ;
275-
276- callback && callback . call ( this , ( ( stopOnError || stopOnFailure ) && testExecutionError ) ?
277- testExecutionError : null , {
278- prerequest : prereqExecutions ,
279- request : request ,
280- response : response ,
281- test : testExecutions
288+ this . triggers . item ( null , coords , item , null ) ;
289+ }
290+
291+ // reset mutated request with original request instance
292+ // @note request mutations are not persisted across iterations
293+ item . request = originalRequest ;
294+
295+ callback && callback . call ( this , ( ( stopOnError || stopOnFailure ) && testExecutionError ) ?
296+ testExecutionError : null , {
297+ prerequest : prereqExecutions ,
298+ request : request ,
299+ response : response ,
300+ test : testExecutions
301+ } ) ;
282302 } ) ;
283303 } ) ;
284304 } ) ;
305+ } . bind ( self ) , {
306+ time : delay ,
307+ source : 'item' ,
308+ cursor : coords
309+ } , next ) ;
310+ } ;
311+
312+ // Resolve secrets before pre-request scripts so scripts can access resolved values via related pm APIs
313+ if ( secretResolvers ) {
314+ resolveSecrets ( secretResolutionPayload , secretResolvers , function ( err ) {
315+ if ( err ) {
316+ // Secret resolution failed - this is fatal for the current item
317+ // (same pattern as pre-request script skip)
318+ self . triggers . item ( err , coords , item , null , { isSecretResolutionFailed : true } ) ;
319+
320+ callback && callback . call ( self , err , {
321+ request : null
322+ } ) ;
323+
324+ return next ( ) ;
325+ }
326+
327+ executeItemFlow ( ) ;
285328 } ) ;
286- } . bind ( this ) , {
287- time : delay ,
288- source : 'item' ,
289- cursor : coords
290- } , next ) ;
329+ }
330+ else {
331+ executeItemFlow ( ) ;
332+ }
291333 }
292334 }
293335} ;
0 commit comments