Skip to content
Merged
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@
"update-lock-file": "update-lock-file @netcracker"
},
"dependencies": {
"@netcracker/qubership-apihub-api-unifier": "2.3.0",
"@netcracker/qubership-apihub-api-unifier": "dev",
"@netcracker/qubership-apihub-json-crawl": "1.0.4",
"fast-equals": "4.0.3"
},
"devDependencies": {
"@netcracker/qubership-apihub-compatibility-suites": "2.2.0",
"@netcracker/qubership-apihub-compatibility-suites": "dev",
"@netcracker/qubership-apihub-graphapi": "1.0.8",
"@netcracker/qubership-apihub-npm-gitflow": "3.1.0",
"@types/jest": "29.5.11",
Expand Down
32 changes: 19 additions & 13 deletions src/openapi/openapi3.rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,20 @@ export const openApi3Rules = (options: OpenApi3RulesOptions): CompareRules => {
'/*': operationAnnotationRule,
}

const pathItemObjectRules = (options: OpenApi3RulesOptions): CompareRules => ({
$: pathChangeClassifyRule,
mapping: options.mode === COMPARE_MODE_OPERATION ? singleOperationPathMappingResolver : pathMappingResolver,
'/description': { $: allAnnotation },
'/parameters': {
$: [nonBreaking, breaking, breaking],
mapping: paramMappingResolver(1),
...parametersRules,
},
'/servers': serversRules,
'/summary': { $: allAnnotation },
'/*': operationRule,
})

const componentsRule: CompareRules = {
$: allNonBreaking,
[START_NEW_COMPARE_SCOPE_RULE]: COMPARE_SCOPE_COMPONENTS,
Expand All @@ -412,6 +426,10 @@ export const openApi3Rules = (options: OpenApi3RulesOptions): CompareRules => {
...requestSchemaRules,
}),
},
'/pathItems': {
$: [nonBreaking, breaking, breaking],
'/*': pathItemObjectRules(options),
},
'/securitySchemes': {
$: [breaking, nonBreaking, breaking],
'/*': {
Expand All @@ -438,19 +456,7 @@ export const openApi3Rules = (options: OpenApi3RulesOptions): CompareRules => {
'/paths': {
$: allUnclassified,
mapping: options.mode === COMPARE_MODE_OPERATION ? singleOperationPathMappingResolver : pathMappingResolver,
'/*': {
$: pathChangeClassifyRule,
mapping: options.mode === COMPARE_MODE_OPERATION ? singleOperationPathMappingResolver : pathMappingResolver,
'/description': { $: allAnnotation },
'/parameters': {
$: [nonBreaking, breaking, breaking],
mapping: paramMappingResolver(1),
...parametersRules,
},
'/servers': serversRules,
'/summary': { $: allAnnotation },
'/*': operationRule,
},
'/*': pathItemObjectRules(options),
},
'/components': componentsRule,
'/security': {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -767,3 +767,59 @@ describe('Openapi3 General Operation Parameters', () => {
]))
})
})

const PATH_ITEM_PATH = [
'components',
'pathItems',
'UserOps',
]

describe('Openapi3.1 PathItems', () => {
test('Add method in path item', async () => {
const testId = 'add-method-in-path-item'
const result = await compareFiles(SUITE_ID, testId)
expect(result).toEqual(diffsMatcher([
expect.objectContaining({
action: DiffAction.add,
afterDeclarationPaths: [[...PATH_ITEM_PATH, 'post']],
type: nonBreaking,
}),
]))
})

test('Remove unused method in path item', async () => {
const testId = 'remove-unused-method-in-path-item'
const result = await compareFiles(SUITE_ID, testId)
expect(result).toEqual([])
})

test('Add unused method in path item', async () => {
const testId = 'add-unused-method-in-path-item'
const result = await compareFiles(SUITE_ID, testId)
expect(result).toEqual([])
})

test('Remove method in path item', async () => {
const testId = 'remove-method-in-path-item'
const result = await compareFiles(SUITE_ID, testId)
expect(result).toEqual(diffsMatcher([
expect.objectContaining({
action: DiffAction.remove,
beforeDeclarationPaths: [[...PATH_ITEM_PATH, 'post']],
type: breaking,
}),
]))
})

test('Replace inline path item to ref', async () => {
const testId = 'replace-inline-path-item-to-ref'
const result = await compareFiles(SUITE_ID, testId)
expect(result).toEqual([])
})

test('Replace ref path item to inline', async () => {
const testId = 'replace-ref-path-item-to-inline'
const result = await compareFiles(SUITE_ID, testId)
expect(result).toEqual([])
})
})
85 changes: 85 additions & 0 deletions test/pathItems.rules.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { apiDiff, ClassifierType, DiffAction } from '../src'
import { diffsMatcher } from './helper/matchers'

const COMPONENTS_RESPONSE_PATH = [
'components',
'pathItems',
'componentsPathItem',
'post',
'responses',
'200',
]

describe('Openapi3.1 Components PathItems Rules', () => {
test('reports changes to path items in components', async () => {
const before = {
'openapi': '3.1.0',
'paths': {
'/path1': {
'post': {
'responses': {
'200': {},
},
},
},
},
'components': {
'pathItems': {
'componentsPathItem': {
'post': {
'responses': {
'200': {
'description': 'Pet successfully added',
},
},
},
},
},
},
}

const after = {
'openapi': '3.1.0',
'paths': {
'/path1': {
'post': {
'responses': {
'200': {},
},
},
},
},
'components': {
'pathItems': {
'componentsPathItem': {
'post': {
'responses': {
'200': {
'description': 'new value',
},
},
},
},
},
},
}

const result = apiDiff(before, after)
expect(result.diffs).toEqual(diffsMatcher([
expect.objectContaining({
action: DiffAction.replace,
beforeValue: 'Pet successfully added',
afterValue: 'new value',
beforeDeclarationPaths: [[
...COMPONENTS_RESPONSE_PATH,
'description',
]],
afterDeclarationPaths: [[
...COMPONENTS_RESPONSE_PATH,
'description',
]],
type: ClassifierType.annotation,
}),
]))
})
})
Loading