@@ -28,6 +28,7 @@ const { formatDataPath, checkIsCorrectType, isKnownType } = require('./common/sc
28
28
APP_JSON = 'application/json' ,
29
29
APP_JS = 'application/javascript' ,
30
30
TEXT_XML = 'text/xml' ,
31
+ APP_XML = 'application/xml' ,
31
32
TEXT_PLAIN = 'text/plain' ,
32
33
TEXT_HTML = 'text/html' ,
33
34
FORM_DATA = 'multipart/form-data' ,
@@ -1914,6 +1915,7 @@ module.exports = {
1914
1915
else if ( contentObj . hasOwnProperty ( APP_JSON ) ) { bodyType = APP_JSON ; }
1915
1916
else if ( contentObj . hasOwnProperty ( TEXT_HTML ) ) { bodyType = TEXT_HTML ; }
1916
1917
else if ( contentObj . hasOwnProperty ( TEXT_PLAIN ) ) { bodyType = TEXT_PLAIN ; }
1918
+ else if ( contentObj . hasOwnProperty ( APP_XML ) ) { bodyType = APP_XML ; }
1917
1919
else if ( contentObj . hasOwnProperty ( TEXT_XML ) ) { bodyType = TEXT_XML ; }
1918
1920
else {
1919
1921
// take the first property it has
@@ -1934,12 +1936,29 @@ module.exports = {
1934
1936
} ;
1935
1937
}
1936
1938
else {
1939
+ let getXmlVersionContent = ( bodyContent ) => {
1940
+ const regExp = new RegExp ( '([<\\?xml]+[\\s{1,}]+[version="\\d.\\d"]+[\\sencoding="]+.{1,15}"\\?>)' ) ;
1941
+ let xmlBody = bodyContent ;
1942
+
1943
+ if ( ! bodyContent . match ( regExp ) ) {
1944
+ const versionContent = '<?xml version="1.0" encoding="UTF-8"?>\n' ;
1945
+ xmlBody = versionContent + xmlBody ;
1946
+ }
1947
+ return xmlBody ;
1948
+ } ;
1949
+
1937
1950
bodyData = this . convertToPmBodyData ( contentObj [ bodyType ] , requestType , bodyType ,
1938
1951
PARAMETER_SOURCE . REQUEST , options . indentCharacter , components , options , schemaCache ) ;
1939
1952
1953
+ bodyData = ( bodyType === TEXT_XML || bodyType === APP_XML ) ?
1954
+ getXmlVersionContent ( bodyData ) :
1955
+ bodyData ;
1956
+
1940
1957
updateOptions = {
1941
1958
mode : rDataMode ,
1942
- raw : JSON . stringify ( bodyData , null , options . indentCharacter )
1959
+ raw : bodyType !== APP_JSON ?
1960
+ bodyData . toString ( ) :
1961
+ JSON . stringify ( bodyData , null , options . indentCharacter )
1943
1962
} ;
1944
1963
}
1945
1964
@@ -2611,11 +2630,15 @@ module.exports = {
2611
2630
matchedPath ,
2612
2631
matchedPathJsonPath ,
2613
2632
schemaPathItems = schema . paths ,
2633
+ pathToMatchServer ,
2614
2634
filteredPathItemsArray = [ ] ;
2615
2635
2616
2636
// Return no matches for invalid url (if unable to decode parsed url)
2617
2637
try {
2618
2638
pathToMatch = decodeURI ( parsedUrl . pathname ) ;
2639
+ if ( ! _ . isNil ( parsedUrl . hash ) ) {
2640
+ pathToMatch += parsedUrl . hash ;
2641
+ }
2619
2642
}
2620
2643
catch ( e ) {
2621
2644
console . warn (
@@ -2654,9 +2677,16 @@ module.exports = {
2654
2677
}
2655
2678
return accumulator ;
2656
2679
} , [ ] ) ;
2657
-
2680
+ let schemaMatchResult = { match : false } ;
2658
2681
// check if path and pathToMatch match (non-null)
2659
- let schemaMatchResult = this . getPostmanUrlSchemaMatchScore ( pathToMatch , path , options ) ;
2682
+ // check in explicit (local defined) servers
2683
+ if ( pathItemObject [ method . toLowerCase ( ) ] . servers ) {
2684
+ pathToMatchServer = this . handleExplicitServersPathToMatch ( pathToMatch , path ) ;
2685
+ schemaMatchResult = this . getPostmanUrlSchemaMatchScore ( pathToMatchServer , path , options ) ;
2686
+ }
2687
+ else {
2688
+ schemaMatchResult = this . getPostmanUrlSchemaMatchScore ( pathToMatch , path , options ) ;
2689
+ }
2660
2690
if ( ! schemaMatchResult . match ) {
2661
2691
// there was no reasonable match b/w the postman path and this schema path
2662
2692
return true ;
@@ -3322,7 +3352,7 @@ module.exports = {
3322
3352
3323
3353
/**
3324
3354
*
3325
- * @param {* } determinedPathVariables the key/determined-value pairs of the path variables (from Postman)
3355
+ * @param {* } matchedPathData the matchedPath data
3326
3356
* @param {* } transactionPathPrefix the jsonpath for this validation (will be prepended to all identified mismatches)
3327
3357
* @param {* } schemaPath the applicable pathItem defined at the schema level
3328
3358
* @param {* } components the components + paths from the OAS spec that need to be used to resolve $refs
@@ -3333,7 +3363,7 @@ module.exports = {
3333
3363
* @returns {array } mismatches (in the callback)
3334
3364
*/
3335
3365
checkPathVariables : function (
3336
- determinedPathVariables ,
3366
+ matchedPathData ,
3337
3367
transactionPathPrefix ,
3338
3368
schemaPath ,
3339
3369
components ,
@@ -3347,7 +3377,9 @@ module.exports = {
3347
3377
var mismatchProperty = 'PATHVARIABLE' ,
3348
3378
// all path variables defined in this path. acc. to the spec, all path params are required
3349
3379
schemaPathVariables ,
3350
- pmPathVariables ;
3380
+ pmPathVariables ,
3381
+ determinedPathVariables = matchedPathData . pathVariables ,
3382
+ unmatchedVariablesFromTransaction = matchedPathData . unmatchedVariablesFromTransaction ;
3351
3383
3352
3384
if ( options . validationPropertiesToIgnore . includes ( mismatchProperty ) ) {
3353
3385
return callback ( null , [ ] ) ;
@@ -3413,17 +3445,41 @@ module.exports = {
3413
3445
} , ( err , res ) => {
3414
3446
let mismatches = [ ] ,
3415
3447
mismatchObj ;
3448
+ const unmatchedSchemaVariableNames = determinedPathVariables . filter ( ( pathVariable ) => {
3449
+ return ! pathVariable . _varMatched ;
3450
+ } ) . map ( ( schemaPathVar ) => {
3451
+ return schemaPathVar . key ;
3452
+ } ) ;
3416
3453
3417
3454
if ( err ) {
3418
3455
return callback ( err ) ;
3419
3456
}
3420
3457
3421
3458
// go through required schemaPathVariables, and params that aren't found in the given transaction are errors
3422
- _ . each ( schemaPathVariables , ( pathVar ) => {
3459
+ _ . each ( schemaPathVariables , ( pathVar , index ) => {
3423
3460
if ( ! _ . find ( determinedPathVariables , ( param ) => {
3424
3461
// only consider variable matching if url path variables is not allowed
3425
3462
return param . key === pathVar . name && ( options . allowUrlPathVarMatching || param . _varMatched ) ;
3426
3463
} ) ) {
3464
+ let reasonCode = 'MISSING_IN_REQUEST' ,
3465
+ reason ,
3466
+ actualValue ,
3467
+ currentUnmatchedVariableInTransaction = unmatchedVariablesFromTransaction [ index ] ,
3468
+ isInvalidValue = currentUnmatchedVariableInTransaction !== undefined ;
3469
+
3470
+ if ( unmatchedSchemaVariableNames . length > 0 && isInvalidValue ) {
3471
+ reason = `The ${ currentUnmatchedVariableInTransaction . key } path variable does not match with ` +
3472
+ `path variable expected (${ unmatchedSchemaVariableNames [ index ] } ) in the schema at this position` ;
3473
+ actualValue = {
3474
+ key : currentUnmatchedVariableInTransaction . key ,
3475
+ description : this . getParameterDescription ( currentUnmatchedVariableInTransaction ) ,
3476
+ value : currentUnmatchedVariableInTransaction . value
3477
+ } ;
3478
+ }
3479
+ else {
3480
+ reason = `The required path variable "${ pathVar . name } " was not found in the transaction` ;
3481
+ actualValue = null ;
3482
+ }
3427
3483
3428
3484
// assign parameter example(s) as schema examples;
3429
3485
this . assignParameterExamples ( pathVar ) ;
@@ -3432,14 +3488,14 @@ module.exports = {
3432
3488
property : mismatchProperty ,
3433
3489
transactionJsonPath : transactionPathPrefix ,
3434
3490
schemaJsonPath : pathVar . pathPrefix ,
3435
- reasonCode : 'MISSING_IN_REQUEST' ,
3436
- reason : `The required path variable " ${ pathVar . name } " was not found in the transaction`
3491
+ reasonCode,
3492
+ reason
3437
3493
} ;
3438
3494
3439
3495
if ( options . suggestAvailableFixes ) {
3440
3496
mismatchObj . suggestedFix = {
3441
3497
key : pathVar . name ,
3442
- actualValue : null ,
3498
+ actualValue,
3443
3499
suggestedValue : {
3444
3500
key : pathVar . name ,
3445
3501
value : safeSchemaFaker ( pathVar . schema || { } , 'example' , PROCESSING_TYPE . VALIDATION ,
@@ -4439,6 +4495,32 @@ module.exports = {
4439
4495
} ) ;
4440
4496
} ,
4441
4497
4498
+ /**
4499
+ * Takes in the postman path and the schema path
4500
+ * takes from the path the number of segments present in the schema path
4501
+ * and returns the last segments from the path to match in an string format
4502
+ *
4503
+ * @param {string } pathToMatch - parsed path (exclude host and params) from the Postman request
4504
+ * @param {string } schemaPath - schema path from the OAS spec (exclude servers object)
4505
+ * @returns {string } only the selected segments from the pathToMatch
4506
+ */
4507
+ handleExplicitServersPathToMatch : function ( pathToMatch , schemaPath ) {
4508
+ let pathTMatchSlice ,
4509
+ schemaPathArr = _ . reject ( schemaPath . split ( '/' ) , ( segment ) => {
4510
+ return segment === '' ;
4511
+ } ) ,
4512
+ schemaPathSegments = schemaPathArr . length ,
4513
+ pathToMatchArr = _ . reject ( pathToMatch . split ( '/' ) , ( segment ) => {
4514
+ return segment === '' ;
4515
+ } ) ,
4516
+ pathToMatchSegments = pathToMatchArr . length ;
4517
+ if ( pathToMatchSegments < schemaPathSegments ) {
4518
+ return pathToMatch ;
4519
+ }
4520
+ pathTMatchSlice = pathToMatchArr . slice ( pathToMatchArr . length - schemaPathSegments , pathToMatchArr . length ) ;
4521
+ return pathTMatchSlice . join ( '/' ) ;
4522
+ } ,
4523
+
4442
4524
/**
4443
4525
* @param {string } postmanPath - parsed path (exclude host and params) from the Postman request
4444
4526
* @param {string } schemaPath - schema path from the OAS spec (exclude servers object)
0 commit comments