diff --git a/CHANGELOG.md b/CHANGELOG.md index ab37c73c..ebbbf938 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## [Unreleased] +- Warn for missing targets (#632 #391) + ## v1.30.4 - (2024-10-07) - Handle Postman API non-200 responses better (#660) diff --git a/README.md b/README.md index 4e71101b..1ebc91c7 100644 --- a/README.md +++ b/README.md @@ -137,9 +137,10 @@ Options: --filterFile Path/URL to openapi-format config file (oas-format-filter.json) [string] --envFile Path to the .env file to inject environment variables [string] --collectionName Overwrite OpenAPI title to set the Postman collection name [string] - --cliOptionsFile Path/URL to Portman CLI options file [string] + --cliOptionsFile Path/URL to Portman CLI options file [string] --ignoreCircularRefs Ignore circular references in OpenAPI spec (default: false) [boolean] --logAssignVariables Toggle logging of assigned variables (default: true) [boolean] + --warn/--no-warn Toggle warnings for missing openApiOperationIds (default: true) [boolean] --init Configure Portman CLI options in an interactive manner [string] --extraUnknownFormats Add extra unknown formats to json schema tests [array] ``` diff --git a/package-lock.json b/package-lock.json index 98227070..3d747bff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@apidevtools/swagger-parser": "^10.1.0", "@faker-js/faker": "5.5.3", "ajv": "^8.12.0", - "axios": "^1.6.5", + "axios": "^1.7.7", "chalk": "^4.1.2", "dot-object": "^2.1.5", "dotenv": "^10.0.0", @@ -2294,9 +2294,9 @@ "integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==" }, "node_modules/axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", diff --git a/package.json b/package.json index 94bd048d..84910a49 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "@apidevtools/swagger-parser": "^10.1.0", "@faker-js/faker": "5.5.3", "ajv": "^8.12.0", - "axios": "^1.6.5", + "axios": "^1.7.7", "chalk": "^4.1.2", "dot-object": "^2.1.5", "dotenv": "^10.0.0", diff --git a/src/Portman.ts b/src/Portman.ts index 3e5bf39c..5f263c8b 100644 --- a/src/Portman.ts +++ b/src/Portman.ts @@ -20,7 +20,7 @@ import { clearTmpDirectory, getConfig } from './lib' import { OpenApiFormatter, OpenApiParser } from './oas' import { PostmanParser } from './postman' import { IOpenApiToPostmanConfig, OpenApiToPostmanService, PostmanSyncService } from './services' -import { PortmanConfig, PortmanTestTypes } from './types' +import { PortmanConfig, PortmanTestTypes, Track } from './types' import { PortmanOptions } from './types/PortmanOptions' import { validate } from './utils/PortmanConfig.validator' import { PortmanError } from './utils/PortmanError' @@ -189,6 +189,7 @@ export class Portman { async after(): Promise { const { consoleLine, collectionFile } = this + await clearTmpDirectory() console.log(chalk.green(consoleLine)) @@ -199,6 +200,9 @@ export class Portman { ) console.log(chalk.green(consoleLine)) + + // Display warning + this.displayMissingTargets(this.testSuite.track) } async parseOpenApiSpec(): Promise { @@ -666,4 +670,34 @@ export class Portman { process.exit(1) } } + + displayMissingTargets = (track: Track): void => { + const { + consoleLine, + options: { warn } + } = this + + if (warn === false) { + return + } + + // Deduplicate missing targets + const uniqueOperationIds = Array.from(new Set(track.openApiOperationIds)) + const uniqueOperations = Array.from(new Set(track.openApiOperations)) + + if (uniqueOperationIds.length > 0 || uniqueOperations.length === 0) { + console.log( + chalk.yellow(`WARNING: The following targets are missing from the OpenAPI specification.`) + ) + if (uniqueOperationIds.length > 0) { + const idsList = uniqueOperationIds.join(', ') + console.log(chalk.yellow(`operationId:\t\t${idsList}`)) + } + if (uniqueOperations.length > 0) { + const opsList = uniqueOperations.join(', ') + console.log(chalk.yellow(`openApiOperation:\t${opsList}`)) + } + console.log(chalk.yellow(consoleLine)) + } + } } diff --git a/src/application/IntegrationTestWriter.ts b/src/application/IntegrationTestWriter.ts index 99f79057..cc5410d4 100644 --- a/src/application/IntegrationTestWriter.ts +++ b/src/application/IntegrationTestWriter.ts @@ -39,7 +39,10 @@ export class IntegrationTestWriter { const pmOperation = testSuite.postmanParser.getOperationById(openApiOperationId) - if (!pmOperation) return + if (!pmOperation) { + this.testSuite.track.openApiOperationIds.push(openApiOperationId) + return + } const folderId = variationWriter.variationFolder.id // const folderName = pmOperation.getParentFolderName() diff --git a/src/application/TestSuite.ts b/src/application/TestSuite.ts index 9b823ffd..02abde0a 100644 --- a/src/application/TestSuite.ts +++ b/src/application/TestSuite.ts @@ -36,6 +36,7 @@ import { ResponseTime, StatusCode, TestSuiteOptions, + Track, VariationTestConfig } from '../types' import { inRange } from '../utils' @@ -61,6 +62,9 @@ export class TestSuite { requestTestTypes: PortmanReqTestType[] + // Tracker + public track = { openApiOperationIds: [], openApiOperations: [] } as Track + constructor(testSuiteOptions: TestSuiteOptions) { const { oasParser, postmanParser, config, options } = testSuiteOptions @@ -168,10 +172,24 @@ export class TestSuite { if (openApiOperation) { pmOperations = this.postmanParser.getOperationsByPath(openApiOperation) + // Track missing operations + if (pmOperations.length === 0) { + this.track.openApiOperations.push(openApiOperation) + } } else if (openApiOperationId) { pmOperations = this.postmanParser.getOperationsByIds([openApiOperationId]) + + // Track missing operations + if (pmOperations.length === 0) { + this.track.openApiOperationIds.push(openApiOperationId) + } } else if (openApiOperationIds) { pmOperations = this.postmanParser.getOperationsByIds(openApiOperationIds) + + // Track missing operations + if (pmOperations.length === 0) { + this.track.openApiOperationIds.push(...openApiOperationIds) + } } if (settings?.excludeForOperations) { diff --git a/src/index.ts b/src/index.ts index 44c285b6..e23a9353 100644 --- a/src/index.ts +++ b/src/index.ts @@ -129,6 +129,10 @@ require('dotenv').config() describe: 'Toggle logging of assigned variables', type: 'boolean' }) + .option('warn', { + describe: 'Toggle warnings for missing openApiOperationIds', + type: 'boolean' + }) .option('init', { describe: 'Initialize Portman and generate a Portman CLI configuration file', type: 'boolean' @@ -232,6 +236,7 @@ require('dotenv').config() const oaOutput = options.oaOutput || '' const collectionName = options.collectionName || '' const logAssignVariables = options?.logAssignVariables + const warn = options?.warn || true const extraUnknownFormats = options?.extraUnknownFormats || [] const syncPostmanCollectionIds = options?.syncPostmanCollectionIds || false @@ -254,6 +259,7 @@ require('dotenv').config() oaOutput, collectionName, logAssignVariables, + warn, extraUnknownFormats, syncPostmanCollectionIds }) diff --git a/src/types/PortmanOptions.ts b/src/types/PortmanOptions.ts index b51c592b..027ec84c 100644 --- a/src/types/PortmanOptions.ts +++ b/src/types/PortmanOptions.ts @@ -32,6 +32,7 @@ export interface PortmanOptions { oaUrl?: string init?: boolean logAssignVariables?: boolean + warn?: boolean extraUnknownFormats?: string[] syncPostmanCollectionIds?: boolean } diff --git a/src/types/PortmanTestSuite.ts b/src/types/PortmanTestSuite.ts index ca275d2f..cbb95a9e 100644 --- a/src/types/PortmanTestSuite.ts +++ b/src/types/PortmanTestSuite.ts @@ -9,3 +9,7 @@ export type PortmanReqTestType = { export interface PortmanTestSuite { pmReqTestType?: PortmanReqTestType } +export interface Track { + openApiOperationIds: string[] + openApiOperations: string[] +}