├── test ├── mocha.opts ├── index.test.js └── fixtures │ ├── api-paths.yaml │ └── integration-tests.json ├── .npmrc ├── .gitattributes ├── src ├── parameters │ └── index.js ├── lib │ ├── swagger │ │ ├── get-paths.js │ │ └── get-operations.js │ └── postman │ │ └── get-paths-and-methods.js ├── index.js ├── paths │ └── index.js └── methods │ └── index.js ├── .gitignore ├── CHANGELOG.md ├── .babelrc ├── .nycrc ├── .travis.yml ├── LICENSE ├── README.md ├── package.json └── CODE_OF_CONDUCT.md /test/mocha.opts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.js text eol=lf -------------------------------------------------------------------------------- /src/parameters/index.js: -------------------------------------------------------------------------------- 1 | module.exports = () => 0; 2 | -------------------------------------------------------------------------------- /src/lib/swagger/get-paths.js: -------------------------------------------------------------------------------- 1 | module.exports = api => api.getPaths(); 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | node_modules/ 3 | coverage/ 4 | .nyc_output/ 5 | dist/ 6 | *.tgz -------------------------------------------------------------------------------- /src/lib/swagger/get-operations.js: -------------------------------------------------------------------------------- 1 | module.exports = api => 2 | api 3 | .getPaths() 4 | .reduce((result, path) => result.concat(path.getOperations()), []); 5 | -------------------------------------------------------------------------------- /src/lib/postman/get-paths-and-methods.js: -------------------------------------------------------------------------------- 1 | module.exports = tests => { 2 | return tests.items.members.map(member => { 3 | return { 4 | path: `/${member.request.url.path.join("/")}`, 5 | method: member.request.method 6 | }; 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [1.1.0](https://github.com/abelmokadem/swagger-coverage-postman/compare/v1.0.0...v1.1.0) (2018-07-05) 2 | 3 | 4 | ### Features 5 | 6 | * **summary:** Add methods coverage to summary ([3f090f6](https://github.com/abelmokadem/swagger-coverage-postman/commit/3f090f6)) 7 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "targets": { 7 | "node": "6" 8 | } 9 | } 10 | ] 11 | ], 12 | "env": { 13 | "test": { 14 | "plugins": [ 15 | "istanbul" 16 | ] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "all": true, 3 | "check-coverage": true, 4 | "branches": 100, 5 | "functions": 100, 6 | "lines": 100, 7 | "statements": 100, 8 | "reporter": [ 9 | "text", 10 | "lcov" 11 | ], 12 | "instrument": false, 13 | "sourceMap": false, 14 | "require": [ 15 | "babel-register" 16 | ], 17 | "include": [ 18 | "src" 19 | ] 20 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: 3 | directories: 4 | - node_modules 5 | notifications: 6 | email: false 7 | node_js: 8 | - '10' 9 | - '9' 10 | - '8' 11 | - '7' 12 | - '6' 13 | branches: 14 | only: 15 | - master 16 | before_script: 17 | - npm prune 18 | - npm install -g npx 19 | script: 20 | - npm run validate 21 | after_success: 22 | - npm run report-coverage 23 | - npm run travis-deploy-once "npm run release" 24 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const sway = require("sway"); 4 | const Collection = require("postman-collection").Collection; 5 | 6 | const getPathsCoverage = require("./paths"); 7 | const getMethodsCoverage = require("./methods"); 8 | const getParametersCoverage = require("./parameters"); 9 | 10 | exports.summary = async (api, tests) => { 11 | const swaggerApi = await sway.create({ definition: api }); 12 | const postmanCollection = new Collection(tests); 13 | 14 | return { 15 | paths: getPathsCoverage(swaggerApi, postmanCollection), 16 | methods: getMethodsCoverage(swaggerApi, postmanCollection), 17 | parameters: getParametersCoverage(swaggerApi, postmanCollection) 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /src/paths/index.js: -------------------------------------------------------------------------------- 1 | const getPathsAndMethods = require("../lib/postman/get-paths-and-methods"); 2 | const getPaths = require("../lib/swagger/get-paths"); 3 | 4 | /** 5 | * 6 | * @param {SwaggerApi} api 7 | * @param {Collection} tests 8 | */ 9 | module.exports = (api, tests) => { 10 | const pathAndMethodsCoveredInTests = getPathsAndMethods(tests); 11 | const apiPaths = getPaths(api); 12 | 13 | return apiPaths 14 | .map( 15 | apiPath => 16 | !!pathAndMethodsCoveredInTests.find(({ path }) => { 17 | return !!apiPath.regexp.test(path); 18 | }) 19 | ) 20 | .reduce( 21 | (total, result, index, results) => 22 | result ? total + 1 / results.length : total, 23 | 0 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /src/methods/index.js: -------------------------------------------------------------------------------- 1 | const getOperations = require("../lib/swagger/get-operations"); 2 | const getPathAndMethods = require("../lib/postman/get-paths-and-methods"); 3 | 4 | /** 5 | * 6 | * @param {SwaggerApi} api 7 | * @param {Collection} tests 8 | */ 9 | module.exports = (api, tests) => { 10 | const pathAndMethodsCoveredInTests = getPathAndMethods(tests); 11 | const apiOperations = getOperations(api); 12 | 13 | return apiOperations 14 | .map( 15 | apiOperation => 16 | !!pathAndMethodsCoveredInTests.find(({ path, method }) => { 17 | return ( 18 | !!apiOperation.pathObject.regexp.test(path) && 19 | method.toLowerCase() === apiOperation.method.toLowerCase() 20 | ); 21 | }) 22 | ) 23 | .reduce( 24 | (total, result, index, results) => 25 | result ? total + 1 / results.length : total, 26 | 0 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const path = require("path"); 4 | const coverage = require("../src"); 5 | const expect = require("chai").expect; 6 | const refParser = require("json-schema-ref-parser"); 7 | 8 | it("should generate a coverage summary", async () => { 9 | const apiFile = path.join(__dirname, "fixtures/api-paths.yaml"); 10 | const api = await refParser.dereference(apiFile); 11 | 12 | const integrationTestsFile = path.join( 13 | __dirname, 14 | "fixtures/integration-tests.json" 15 | ); 16 | const integrationTests = require(integrationTestsFile); 17 | 18 | const result = await coverage.summary(api, integrationTests); 19 | 20 | expect(result.paths).to.be.equal(1 / 2, "Paths coverage should be 0.5"); 21 | expect(result.methods).to.be.equal(1 / 3, "Methods coverage should be 0.33"); 22 | expect(result.parameters).to.be.equal(0, "Parameters coverage should be 0"); 23 | }); 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 mvashwinkumar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/fixtures/api-paths.yaml: -------------------------------------------------------------------------------- 1 | swagger: '2.0' 2 | info: 3 | version: '1.4' 4 | title: Pass Through API 5 | description: 'A simple hello world API' 6 | 7 | basePath: "/blueprint/examples/3" 8 | 9 | paths: 10 | /echo/{firstName}: 11 | get: 12 | consumes: 13 | - application/json 14 | parameters: 15 | - name: firstName 16 | in: path 17 | required: true 18 | type: string 19 | responses: 20 | '200': 21 | description: 200 response 22 | schema: 23 | type: string 24 | /echo/{firstName}/{lastName}: 25 | get: 26 | consumes: 27 | - application/json 28 | parameters: 29 | - name: firstName 30 | in: path 31 | required: true 32 | type: string 33 | - name: lastName 34 | in: path 35 | required: true 36 | type: string 37 | responses: 38 | '200': 39 | description: 200 response 40 | schema: 41 | type: string 42 | post: 43 | consumes: 44 | - application/json 45 | parameters: 46 | - name: firstName 47 | in: path 48 | required: true 49 | type: string 50 | - name: lastName 51 | in: path 52 | required: true 53 | type: string 54 | responses: 55 | '200': 56 | description: 200 response 57 | schema: 58 | type: string 59 | -------------------------------------------------------------------------------- /test/fixtures/integration-tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "variables": [], 3 | "info": { 4 | "name": "blueprint examples 3", 5 | "_postman_id": "35a78331-141d-d651-57c3-98cf5710daec", 6 | "description": "", 7 | "schema": 8 | "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" 9 | }, 10 | "item": [ 11 | { 12 | "name": "GET /blueprint/examples/3/echo/1/2", 13 | "request": { 14 | "url": "https://{{host}}/blueprint/examples/3/echo/1/2", 15 | "method": "GET", 16 | "header": [], 17 | "body": {} 18 | }, 19 | "response": [] 20 | }, 21 | { 22 | "name": "GET /blueprint/examples/3/echo/1/2", 23 | "request": { 24 | "url": "https://{{host}}/blueprint/examples/3/echo/1/2", 25 | "method": "GET", 26 | "header": [], 27 | "body": {} 28 | }, 29 | "response": [] 30 | }, 31 | { 32 | "name": "GET /blueprint/examples/3/echo/1/2?v=illegal&z=parameter", 33 | "request": { 34 | "url": 35 | "https://{{host}}/blueprint/examples/3/echo/1/2?v=illegal&z=parameter", 36 | "method": "GET", 37 | "header": [], 38 | "body": {} 39 | }, 40 | "response": [] 41 | }, 42 | { 43 | "name": "POST /blueprint/examples/3/echo", 44 | "request": { 45 | "url": "https://{{host}}/blueprint/examples/3/echo", 46 | "method": "POST", 47 | "header": [], 48 | "body": {} 49 | }, 50 | "response": [] 51 | } 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # swagger-coverage-postman 2 | 3 | [![Travis](https://img.shields.io/travis/abelmokadem/swagger-coverage-postman.svg?style=flat-square)](https://travis-ci.org/abelmokadem/swagger-coverage-postman) 4 | [![Codecov](https://img.shields.io/codecov/c/github/abelmokadem/swagger-coverage-postman.svg?style=flat-square)](https://codecov.io/gh/abelmokadem/swagger-coverage-postman) 5 | [![version](https://img.shields.io/npm/v/swagger-coverage-postman.svg?style=flat-square)](http://npm.im/swagger-coverage-postman) 6 | [![downloads](https://img.shields.io/npm/dm/swagger-coverage-postman.svg?style=flat-square)](http://npm-stat.com/charts.html?package=swagger-coverage-postman&from=2016-01-01) 7 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](http://opensource.org/licenses/MIT) 8 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release) 9 | 10 | 11 | Generate API coverage between your Swagger definition and Postman collection 12 | 13 | ## Usage 14 | 15 | ```bash 16 | npm install --save swagger-coverage-postman 17 | ``` 18 | 19 | ```javascript 20 | const coverage = require("swagger-coverage-postman"); 21 | const refParser = require("json-schema-ref-parser"); 22 | 23 | // Load swagger file 24 | const apiFile = path.join(__dirname, "api.yaml"); 25 | const api = await refParser.dereference(apiFile); 26 | 27 | // Load postman integration test file 28 | const integrationTestsFile = path.join(__dirname, "integration-tests.json"); 29 | const integrationTests = require(integrationTestsFile); 30 | 31 | // Calculate coverage summary 32 | const coverageSummary = await coverage.summary(api, integrationTests); 33 | 34 | console.log(coverageSummary); 35 | // { paths: 1, methods: 0.86, parameters: 0.15 } 36 | ``` 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swagger-coverage-postman", 3 | "version": "1.1.0", 4 | "description": "Generate API coverage between your Swagger definition and Postman collection", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "commit": "git-cz", 8 | "prebuild": "rimraf dist", 9 | "build": "npm-run-all --parallel build:*", 10 | "build:main": "babel --copy-files --out-dir dist --ignore *.test.js src", 11 | "lint": "npx prettier -l '{src,test}/**/*.{js,json}'", 12 | "lint:fix": "npx prettier --write '{src,test}/**/*.{js,json}'", 13 | "report-coverage": "cat ./coverage/lcov.info | codecov", 14 | "test": "cross-env NODE_ENV=test nyc mocha --compilers js:babel-core/register", 15 | "watch:test": "mocha --compilers js:babel-core/register --watch", 16 | "validate": "npm-run-all --parallel lint test build", 17 | "release": "semantic-release", 18 | "travis-deploy-once": "travis-deploy-once" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/abelmokadem/swagger-coverage-postman.git" 23 | }, 24 | "release": { 25 | "verifyConditions": [ 26 | "@semantic-release/changelog", 27 | "@semantic-release/npm", 28 | "@semantic-release/git" 29 | ], 30 | "prepare": [ 31 | "@semantic-release/changelog", 32 | "@semantic-release/npm", 33 | "@semantic-release/git" 34 | ] 35 | }, 36 | "keywords": [ 37 | "open source", 38 | "npm", 39 | "library", 40 | "boilerplate", 41 | "starter kit", 42 | "module builder" 43 | ], 44 | "files": [ 45 | "dist" 46 | ], 47 | "author": "Ash Belmokadem ", 48 | "license": "MIT", 49 | "bugs": { 50 | "url": "https://github.com/abelmokadem/swagger-coverage-postman/issues" 51 | }, 52 | "homepage": "https://github.com/abelmokadem/swagger-coverage-postman", 53 | "devDependencies": { 54 | "@semantic-release/changelog": "^2.1.1", 55 | "@semantic-release/git": "^6.0.1", 56 | "@semantic-release/npm": "^3.3.4", 57 | "babel-cli": "^6.18.0", 58 | "babel-plugin-istanbul": "^3.0.0", 59 | "babel-preset-env": "^1.7.0", 60 | "babel-register": "^6.18.0", 61 | "chai": "^3.5.0", 62 | "codecov": "^1.0.1", 63 | "commitizen": "^2.9.0", 64 | "cross-env": "^3.1.3", 65 | "cz-conventional-changelog": "^1.2.0", 66 | "ghooks": "^1.3.2", 67 | "json-schema-ref-parser": "^5.0.3", 68 | "mocha": "^3.2.0", 69 | "npm-run-all": "^3.1.2", 70 | "nyc": "^10.0.0", 71 | "prettier": "^1.13.7", 72 | "rimraf": "^2.5.4", 73 | "semantic-release": "^15.6.3", 74 | "validate-commit-msg": "^2.8.2", 75 | "travis-deploy-once": "^5.0.1" 76 | }, 77 | "config": { 78 | "commitizen": { 79 | "path": "cz-conventional-changelog" 80 | }, 81 | "ghooks": { 82 | "pre-commit": "npm run validate", 83 | "commit-msg": "validate-commit-msg" 84 | } 85 | }, 86 | "dependencies": { 87 | "postman-collection": "^3.1.1", 88 | "sway": "^1.0.0", 89 | "underscore": "^1.8.3" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at mvashwinkumar@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ --------------------------------------------------------------------------------