Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,683 changes: 1,683 additions & 0 deletions __tests__/fixtures/crm-request-array31.yml

Large diffs are not rendered by default.

3,296 changes: 3,296 additions & 0 deletions __tests__/fixtures/crm-request-items31.yml

Large diffs are not rendered by default.

4,641 changes: 4,641 additions & 0 deletions __tests__/fixtures/crm31.yml

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions __tests__/testUtils/getOasMappedOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,35 @@ export const getOasMappedListArrayOperation = async (): Promise<OasMappedOperati
await oasParser.convert({ inputFile: oasYml })
return oasParser.mappedOperations[1]
}

export const getOasV31MappedOperation = async (): Promise<OasMappedOperation> => {
const oasYml = '__tests__/fixtures/crm31.yml'
const oasParser = new OpenApiParser()

await oasParser.convert({ inputFile: oasYml })
return oasParser.mappedOperations[2]
}

export const getOasV31MappedCreateOperation = async (): Promise<OasMappedOperation> => {
const oasYml = '__tests__/fixtures/crm31.yml'
const oasParser = new OpenApiParser()

await oasParser.convert({ inputFile: oasYml })
return oasParser.mappedOperations[1]
}

export const getOasV31MappedCreateArrayOperation = async (): Promise<OasMappedOperation> => {
const oasYml = '__tests__/fixtures/crm-request-items31.yml'
const oasParser = new OpenApiParser()

await oasParser.convert({ inputFile: oasYml })
return oasParser.mappedOperations[0]
}

export const getOasV31MappedListArrayOperation = async (): Promise<OasMappedOperation> => {
const oasYml = '__tests__/fixtures/crm-request-array.yml'
const oasParser = new OpenApiParser()

await oasParser.convert({ inputFile: oasYml })
return oasParser.mappedOperations[1]
}
11 changes: 7 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"@apidevtools/swagger-parser": "^10.1.1",
"@faker-js/faker": "5.5.3",
"ajv": "^8.17.1",
"ajv-draft-04": "^1.0.0",
"axios": "^1.12.0",
"chalk": "^4.1.2",
"dot-object": "^2.1.5",
Expand All @@ -82,7 +83,7 @@
"node-emoji": "^1.11.0",
"openapi-format": "^1.28.0",
"openapi-to-postmanv2": "5.0.0",
"openapi-types": "9.1.0",
"openapi-types": "^12.1.3",
"ora": "^5.4.1",
"pluralize": "^8.0.0",
"postman-collection": "5.0.2",
Expand Down
6 changes: 3 additions & 3 deletions src/__tests__/Portman.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import SwaggerParser from '@apidevtools/swagger-parser'
import fs from 'fs-extra'
import * as Either from 'fp-ts/lib/Either'
import { ValidationError } from '@apideck/better-ajv-errors'
import { OpenAPIV3 } from 'openapi-types'
import { OpenAPI } from 'openapi-types'
import { CollectionDefinition } from 'postman-collection'
import * as mockOAS from '../../__tests__/fixtures/mockOAS.json'
import * as mockPostman from '../../__tests__/fixtures/mockPostman.json'
Expand Down Expand Up @@ -56,10 +56,10 @@ describe('Portman', () => {
// mock conversions
jest
.spyOn(SwaggerParser.prototype, 'dereference')
.mockImplementation(() => Promise.resolve(mockOAS as OpenAPIV3.Document))
.mockImplementation(() => Promise.resolve(mockOAS as OpenAPI.Document))
jest
.spyOn(SwaggerParser.prototype, 'bundle')
.mockImplementation(() => Promise.resolve(mockOAS as OpenAPIV3.Document))
.mockImplementation(() => Promise.resolve(mockOAS as OpenAPI.Document))
jest
.spyOn(OpenApiToPostmanService.prototype, 'convert')
.mockImplementation(() => Promise.resolve(mockPostman))
Expand Down
32 changes: 21 additions & 11 deletions src/application/Fuzzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '../types'
import traverse from 'neotraverse/legacy'
import { TestSuite, VariationWriter } from './'
import { OpenAPIV3 } from 'openapi-types'
import { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types'
import { getByPath, getJsonContentType } from '../utils'
import { QueryParam } from 'postman-collection'
import { PostmanDynamicVarGenerator } from '../services/PostmanDynamicVarGenerator'
Expand Down Expand Up @@ -54,14 +54,18 @@ export class Fuzzer {
if (!oaOperation?.schema?.requestBody) return

// Analyse request body & content-type
const reqBody = oaOperation?.schema?.requestBody as unknown as OpenAPIV3.RequestBodyObject
const reqBody = oaOperation?.schema?.requestBody as unknown as
| OpenAPIV3.RequestBodyObject
| OpenAPIV3_1.RequestBodyObject
const jsonContentType = getJsonContentType(Object.keys(reqBody?.content))

// No JSON content-type defined
if (!jsonContentType) return

// Analyse JSON schema
const schema = reqBody?.content?.[jsonContentType]?.schema as OpenAPIV3.SchemaObject
const schema = reqBody?.content?.[jsonContentType]?.schema as
| OpenAPIV3.SchemaObject
| OpenAPIV3_1.SchemaObject
const fuzzItems = this.analyzeFuzzJsonSchema(schema)

const fuzzReqBodySet = fuzzingSet.filter(fuzz => fuzz?.requestBody) as fuzzingConfig[]
Expand Down Expand Up @@ -136,7 +140,9 @@ export class Fuzzer {
// No request query params defined
if (!oaOperation?.queryParams) return

const reqQueryParams = oaOperation?.queryParams as unknown as OpenAPIV3.ParameterObject[]
const reqQueryParams = oaOperation?.queryParams as unknown as
| OpenAPIV3.ParameterObject[]
| OpenAPIV3_1.ParameterObject[]
reqQueryParams.map(queryParam => {
// Analyse query param schema
const fuzzItems = this.analyzeQuerySchema(queryParam)
Expand Down Expand Up @@ -214,7 +220,9 @@ export class Fuzzer {
// No request headers defined
if (!oaOperation?.requestHeaders) return

const reqHeaders = oaOperation?.requestHeaders as unknown as OpenAPIV3.ParameterObject[]
const reqHeaders = oaOperation?.requestHeaders as unknown as
| OpenAPIV3.ParameterObject[]
| OpenAPIV3_1.ParameterObject[]
reqHeaders.map(header => {
// Analyse header schema
const fuzzItems = this.analyzeHeaderSchema(header)
Expand Down Expand Up @@ -808,7 +816,7 @@ export class Fuzzer {
}

public analyzeFuzzJsonSchema(
originalJsonSchema: OpenAPIV3.SchemaObject | undefined
originalJsonSchema: OpenAPIV3.SchemaObject | OpenAPIV3_1.SchemaObject | undefined
): FuzzingSchemaItems | null {
const fuzzItems = {
fuzzType: PortmanFuzzTypes.requestBody,
Expand All @@ -821,7 +829,9 @@ export class Fuzzer {

if (!originalJsonSchema) return fuzzItems
// Copy jsonSchema to keep the original jsonSchema untouched
const jsonSchema = { ...originalJsonSchema } as OpenAPIV3.SchemaObject
const jsonSchema = { ...originalJsonSchema } as
| OpenAPIV3.SchemaObject
| OpenAPIV3_1.SchemaObject

const skipSchemaKeys = ['properties', 'items', 'allOf', 'anyOf', 'oneOf']
traverse(jsonSchema).forEach(function (node) {
Expand Down Expand Up @@ -958,7 +968,7 @@ export class Fuzzer {
}

public analyzeQuerySchema(
queryParam: OpenAPIV3.ParameterObject | undefined
queryParam: OpenAPIV3.ParameterObject | OpenAPIV3_1.ParameterObject | undefined
): FuzzingSchemaItems | null {
const fuzzItems = {
fuzzType: PortmanFuzzTypes.requestQueryParam,
Expand All @@ -971,7 +981,7 @@ export class Fuzzer {

if (!queryParam?.schema || !queryParam.name) return fuzzItems

const schema = queryParam?.schema as OpenAPIV3.BaseSchemaObject
const schema = queryParam?.schema as OpenAPIV3.BaseSchemaObject | OpenAPIV3_1.BaseSchemaObject

// Register all fuzz-able items
if (queryParam?.required) {
Expand Down Expand Up @@ -1010,7 +1020,7 @@ export class Fuzzer {
}

public analyzeHeaderSchema(
header: OpenAPIV3.ParameterObject | undefined
header: OpenAPIV3.ParameterObject | OpenAPIV3_1.ParameterObject | undefined
): FuzzingSchemaItems | null {
const fuzzItems = {
fuzzType: PortmanFuzzTypes.requestHeader,
Expand All @@ -1023,7 +1033,7 @@ export class Fuzzer {

if (!header?.schema || !header.name) return fuzzItems

const schema = header?.schema as OpenAPIV3.BaseSchemaObject
const schema = header?.schema as OpenAPIV3.BaseSchemaObject | OpenAPIV3_1.BaseSchemaObject

// Register all fuzz-able items
if (header?.required) {
Expand Down
25 changes: 18 additions & 7 deletions src/application/TestSuite.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OpenAPIV3 } from 'openapi-types'
import { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types'
import { Collection, Header } from 'postman-collection'
import {
applyOverwrites,
Expand Down Expand Up @@ -120,7 +120,9 @@ export class TestSuite {
const reqInfo = parseOpenApiRequest(contractTest.openApiRequest)
let reqContentType = reqInfo?.contentType
if (reqContentType && reqContentType.includes('*') && operation.schema?.requestBody) {
const reqObj = operation.schema.requestBody as OpenAPIV3.RequestBodyObject
const reqObj = operation.schema.requestBody as
| OpenAPIV3.RequestBodyObject
| OpenAPIV3_1.RequestBodyObject
const matchCt = Object.keys(reqObj.content || {}).find(ct =>
matchWildcard(ct, reqContentType as string)
)
Expand All @@ -133,7 +135,9 @@ export class TestSuite {
value: reqContentType
} as Header)

const reqBodyObj = operation.schema.requestBody as OpenAPIV3.RequestBodyObject
const reqBodyObj = operation.schema.requestBody as
| OpenAPIV3.RequestBodyObject
| OpenAPIV3_1.RequestBodyObject
const example = getRequestBodyExample(reqBodyObj, reqContentType)
if (example && pmOperation.item.request.body) {
pmOperation.item.request.body.mode = 'raw'
Expand All @@ -158,7 +162,9 @@ export class TestSuite {
respContentType.includes('*') &&
operation.schema?.responses?.[respCode]
) {
const respObj = operation.schema.responses[respCode] as OpenAPIV3.ResponseObject
const respObj = operation.schema.responses[respCode] as
| OpenAPIV3.ResponseObject
| OpenAPIV3_1.ResponseObject
const matchCt = Object.keys(respObj.content || {}).find(ct =>
matchWildcard(ct, respContentType as string)
)
Expand Down Expand Up @@ -319,7 +325,7 @@ export class TestSuite {

const responseKey = response[0][0]
const responseCode = parseInt(responseKey) as number
const responseObject = response[0][1] as OpenAPIV3.ResponseObject
const responseObject = response[0][1] as OpenAPIV3.ResponseObject | OpenAPIV3_1.ResponseObject

// List excludeForOperations
const optStatusSuccess = contractTest['statusSuccess']
Expand Down Expand Up @@ -379,7 +385,10 @@ export class TestSuite {

// Add response content checks
if (responseObject.content) {
const processContent = (contentType: string, content: OpenAPIV3.MediaTypeObject): void => {
const processContent = (
contentType: string,
content: OpenAPIV3.MediaTypeObject | OpenAPIV3_1.MediaTypeObject
): void => {
// Add contentType check
if (
optContentType &&
Expand Down Expand Up @@ -445,7 +454,9 @@ export class TestSuite {
// Early skip if no schema defined
if (!headerKey) continue

const header = responseObject.headers[headerKey] as OpenAPIV3.HeaderObject
const header = responseObject.headers[headerKey] as
| OpenAPIV3.HeaderObject
| OpenAPIV3_1.HeaderObject
const headerRequired = header.required || false
const headerName = headerKey as string

Expand Down
6 changes: 3 additions & 3 deletions src/application/globals/renamePostmanCollection.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { PortmanOptions } from '../../types'
import { OpenAPIV3 } from 'openapi-types'
import { OpenAPI } from 'openapi-types'

export const renamePostmanCollection = (
oas: OpenAPIV3.Document,
oas: OpenAPI.Document,
options: PortmanOptions
): OpenAPIV3.Document => {
): OpenAPI.Document => {
if (!oas?.info?.title) {
throw new Error(`OpenAPI title is required. Please ensure your OpenAPI document has title.`)
}
Expand Down
Loading
Loading