├── .babelrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── media └── screenshot.png ├── package.json ├── src ├── bin │ └── graphql-doc-check.js ├── parser.js ├── printer.js └── retriever.js └── test ├── fixtures └── parser.fixture.js ├── mocha.opts ├── parser.test.js ├── printer.test.js └── retriever.test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | coverage 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | test 3 | .babelrc 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.12" 4 | - "4.0" 5 | - "4.1" 6 | - "iojs" 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## [0.2.0] 5 | ### Added 6 | - Deprecation reason check 7 | - HTTP Header option 8 | - Changelog file 9 | 10 | ### Changed 11 | - Moved CLI script to `/bin` in prep for exposing module. 12 | - Unifies data structure across retriever, parser and printer. 13 | - Tidies up some code and adds missing comments 14 | - Git now ignores `npm-debug.log` 15 | - Makes screenshot URL in README absolute 16 | 17 | 18 | ## [0.1.1] - Feb 13 2016 19 | ### Added 20 | - Travis CI config file 21 | 22 | ### Changed 23 | - Added screenshot to README 24 | - Registered executable in package.json 25 | 26 | 27 | ## 0.1.0 - Feb 13 2016 28 | - Initial Commit 29 | 30 | 31 | [Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.2.0...HEAD 32 | [0.2.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.1.1...0.2.0 33 | [0.1.1]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.1.0...v0.1.1 34 | [0.1.0]: https://github.com/JordanAdams/graphql-doc-check/tree/v0.1.0 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Jordan Adams 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GraphQL Documentation Check 2 | ======== 3 | 4 | [![Build Status](https://travis-ci.org/JordanAdams/graphql-doc-check.svg?branch=master)](https://travis-ci.org/JordanAdams/graphql-doc-check) 5 | [![Dependency Status](https://david-dm.org/jordanadams/graphql-doc-check.svg)](https://david-dm.org/jordanadams/graphql-doc-check) 6 | [![npm](https://img.shields.io/npm/v/graphql-doc-check.svg)](https://www.npmjs.com/package/graphql-doc-check) 7 | [![Gitter](https://badges.gitter.im/JordanAdams/graphql-doc-check.svg)](https://gitter.im/JordanAdams/graphql-doc-check?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 8 | 9 | Quickly find any missing documentation in your GraphQL API using introspection. Performs inspections remotely, without any need to access code. 10 | 11 | ![Example screenshot](https://raw.githubusercontent.com/JordanAdams/graphql-doc-check/master/media/screenshot.png) 12 | 13 | ## Installation 14 | 15 | npm install -g graphql-doc-check 16 | 17 | ## Usage 18 | 19 | Calling `graphql-doc-check` without any arguments will assume that your GraphQL 20 | API is running at `http://localhost:80/graphql`. 21 | 22 | $ graphql-doc-check 23 | 24 | Alternatively, you can pass a URL to check. 25 | 26 | $ graphql-doc-check https://example.com/graph 27 | 28 | For more info, check the help or read [the wiki](https://github.com/JordanAdams/graphql-doc-check/wiki). 29 | 30 | $ graphql-doc-check -h 31 | 32 | Results are shown in a tree structure with fields missing documentation in red. 33 | 34 | Type1 35 | ├─ field1 [missing | properties] 36 | │ ├─ arg1 37 | │ ├─ arg2 38 | └─ field2 39 | └─ arg3 [description] 40 | 41 | 42 | ## License 43 | 44 | Copyright (c) 2016, Jordan Adams 45 | 46 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 47 | 48 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 49 | -------------------------------------------------------------------------------- /media/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JordanAdams/graphql-doc-check/53f0f25136176596d151dae55b203ae6f37c69c3/media/screenshot.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-doc-check", 3 | "version": "0.2.0", 4 | "description": "Check for missing documentation in your GraphQL Schema", 5 | "author": "Jordan Adams ", 6 | "license": "ISC", 7 | "main": "dist/bin/graphql-doc-check.js", 8 | "bin": { 9 | "graphql-doc-check": "dist/bin/graphql-doc-check.js" 10 | }, 11 | "scripts": { 12 | "clean": "rm -rf dist", 13 | "build": "npm run clean && babel src -d dist", 14 | "prepublish": "npm run build", 15 | "test": "mocha", 16 | "coverage": "babel-node node_modules/isparta/bin/isparta cover --report text node_modules/mocha/bin/_mocha -- --reporter landing" 17 | }, 18 | "dependencies": { 19 | "ascii-tree": "^0.3.0", 20 | "chalk": "^1.1.1", 21 | "lodash": "^4.3.0", 22 | "request-promise": "^2.0.0", 23 | "yargs": "^4.1.0" 24 | }, 25 | "devDependencies": { 26 | "babel": "^6.5.1", 27 | "babel-cli": "^6.5.1", 28 | "babel-eslint": "^4.1.8", 29 | "babel-preset-es2015": "^6.5.0", 30 | "babel-preset-stage-0": "^6.5.0", 31 | "babel-register": "^6.5.2", 32 | "expect": "^1.14.0", 33 | "isparta": "^4.0.0", 34 | "mocha": "^2.4.5", 35 | "sinon": "^1.17.3", 36 | "sinon-as-promised": "^4.0.0", 37 | "standard": "^6.0.4" 38 | }, 39 | "standard": { 40 | "parser": "babel-eslint" 41 | }, 42 | "config": { 43 | "blanket": { 44 | "pattern": "src" 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/bin/graphql-doc-check.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import yargs from 'yargs' 4 | import request from 'request-promise' 5 | import retriever from '../retriever' 6 | import printer from '../printer' 7 | import parser from '../parser' 8 | 9 | // Parse arguments & options 10 | const argv = yargs 11 | .version() 12 | .usage('Usage: graphql-doc-check [options]') 13 | .option('H', { 14 | alias: 'header', 15 | describe: 'Add a HTTP request header', 16 | type: 'array', 17 | default: [] 18 | }) 19 | .help().alias('h', 'help') 20 | .argv 21 | 22 | // Parse header options 23 | const headers = argv.header.reduce((acc, header) => { 24 | if (/.*?:.*?/.test(header) === false) { 25 | console.error('Unable to parse header: ' + header) 26 | process.exit(1) 27 | } 28 | 29 | const [name, value] = header.split(':') 30 | acc[name] = value 31 | 32 | return acc 33 | }, {}) 34 | 35 | // Retrieve schema and print results 36 | const options = { headers } 37 | retriever(request).get(argv._[0], options) 38 | .then(schema => parser.parse(schema)) 39 | .then(results => printer.print(results)) 40 | .then(output => console.log(output)) 41 | -------------------------------------------------------------------------------- /src/parser.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | const parser = function () { 4 | /** 5 | * Determines if a type should be ignored from parsing 6 | * 7 | * @param {Object} type Type to check 8 | * @return {Boolean} Should be ignored? 9 | */ 10 | const typeShouldBeIgnored = (type) => { 11 | const ignores = [ 12 | '__Type', 13 | '__Field', 14 | '__InputValue', 15 | '__EnumValue', 16 | '__Directive' 17 | ] 18 | 19 | if (ignores.indexOf(type.name) >= 0) { 20 | return true 21 | } 22 | 23 | return false 24 | } 25 | 26 | /** 27 | * Makes a documentation result for a schema item 28 | * 29 | * @param {Object} item Schema item (type, field or arg) 30 | * @return {Object} Result 31 | */ 32 | const makeDocumentationResult = (item) => { 33 | const missing = [] 34 | 35 | if (_.isEmpty(item.description)) { 36 | missing.push('description') 37 | } 38 | 39 | if (item.isDeprecated && _.isEmpty(item.deprecationReason)) { 40 | missing.push('deprecationReason') 41 | } 42 | 43 | return { name: item.name, missing } 44 | } 45 | 46 | return { 47 | /** 48 | * Parses field arguments in a schema 49 | * 50 | * @param {Array} args Field arguments to parse 51 | * @return {Array} Parsed field arguments 52 | */ 53 | parseArgs (args) { 54 | return _ 55 | .chain(args) 56 | .map(makeDocumentationResult) 57 | .reject(result => _.isEmpty(result.missing)) 58 | .value() 59 | }, 60 | 61 | /** 62 | * Parses fields in a schema 63 | * 64 | * @param {Array} fields Fields to parse 65 | * @return {Array} Parsed fields 66 | */ 67 | parseFields (fields) { 68 | return _ 69 | .chain(fields) 70 | .map(field => { 71 | const args = this.parseArgs(field.args) 72 | 73 | field = makeDocumentationResult(field) 74 | field.args = args 75 | 76 | return field 77 | }) 78 | .filter(field => { 79 | if (_.isEmpty(field.missing) === false) return true 80 | if (_.isEmpty(field.args) === false) return true 81 | 82 | return false 83 | }) 84 | .value() 85 | }, 86 | 87 | /** 88 | * Parses types in a schema 89 | * 90 | * @param {Array} types Types to parse 91 | * @return {Array} Parsed types 92 | */ 93 | parseTypes (types) { 94 | return _ 95 | .chain(types) 96 | .reject(typeShouldBeIgnored) 97 | .map(type => { 98 | const fields = this.parseFields(type.fields) 99 | 100 | type = makeDocumentationResult(type) 101 | type.fields = fields 102 | 103 | return type 104 | }) 105 | .filter(type => { 106 | if (_.isEmpty(type.missing) === false) return true 107 | if (_.isEmpty(type.fields) === false) return true 108 | 109 | return false 110 | }) 111 | .value() 112 | }, 113 | 114 | /** 115 | * Parse a given schema 116 | * @param {Object} schema Schema to parse 117 | * @return {Object} Parsed schema 118 | */ 119 | parse (schema) { 120 | schema.types = this.parseTypes(schema.types) 121 | 122 | return schema 123 | } 124 | } 125 | } 126 | 127 | export default parser() 128 | -------------------------------------------------------------------------------- /src/printer.js: -------------------------------------------------------------------------------- 1 | import asciiTree from 'ascii-tree' 2 | import chalk from 'chalk' 3 | 4 | const printer = { 5 | missingTotal: 0, 6 | 7 | /** 8 | * Renders a schema's results 9 | * 10 | * @param {Object} schema Schema to render 11 | * @return {String} Result output 12 | */ 13 | print (results) { 14 | this.missingTotal = 0 15 | 16 | const typeTrees = this.renderTypes(results.types) 17 | .map(type => asciiTree.generate(type)) 18 | .join('\n\n') 19 | 20 | return this.renderHeading() + '\n\n' + typeTrees 21 | }, 22 | 23 | /** 24 | * Renders the heading 25 | * 26 | * @return {String} Heading 27 | */ 28 | renderHeading () { 29 | switch (this.missingTotal) { 30 | case 0: return chalk.green('✔︎ No fields are missing documentation') 31 | case 1: return chalk.yellow('✘ Found 1 field with missing documentation') 32 | default: return chalk.yellow(`✘ Found ${this.missingTotal} fields with missing documentation`) 33 | } 34 | }, 35 | 36 | /** 37 | * Render a list of types 38 | * 39 | * @param {Array} types Types to render 40 | * @return {Array} Rendered types 41 | */ 42 | renderTypes (types) { 43 | return types.map(type => { 44 | let output = this.renderResultLine(type) 45 | 46 | const fields = this.renderFields(type.fields) 47 | if (fields) { 48 | output += `\n${fields}` 49 | } 50 | 51 | return `#${output}` 52 | }) 53 | }, 54 | 55 | /** 56 | * Render a list of fields 57 | * 58 | * @param {Array} fields Fields to render 59 | * @return {String} Rendered fields 60 | */ 61 | renderFields (fields) { 62 | return fields.map(field => { 63 | let output = this.renderResultLine(field) 64 | 65 | const args = this.renderArgs(field.args) 66 | if (args) { 67 | output += `\n${args}` 68 | } 69 | 70 | return `##${output}` 71 | }).join('\n') 72 | }, 73 | 74 | /** 75 | * Render a list of arguments 76 | * 77 | * @param {Array} args Args to render 78 | * @return {String} Rendered args 79 | */ 80 | renderArgs (args) { 81 | return args.map(arg => { 82 | return '###' + this.renderResultLine(arg) 83 | }).join('\n') 84 | }, 85 | 86 | /** 87 | * Renders a single result line: "name [prop1 | prop2]" 88 | * 89 | * @param {Object} ... Result to render 90 | * @return {String} Rendered result line 91 | */ 92 | renderResultLine ({ name, missing }) { 93 | if (missing.length > 0) { 94 | this.missingTotal++ 95 | const missingList = this.renderMissingList(missing) 96 | return chalk.red(name) + ' ' + chalk.gray(missingList) 97 | } 98 | 99 | return name 100 | }, 101 | 102 | /** 103 | * Render a missing list: "[prop1 | prop2]" 104 | * 105 | * @param {Array} missing Missing props 106 | * @return {String} Rendered missing props 107 | */ 108 | renderMissingList (missing) { 109 | return '[' + missing.join(' | ') + ']' 110 | } 111 | } 112 | 113 | export default printer 114 | -------------------------------------------------------------------------------- /src/retriever.js: -------------------------------------------------------------------------------- 1 | const query = `query { 2 | schema: __schema { 3 | types { 4 | kind 5 | name 6 | description 7 | fields { 8 | name 9 | description 10 | isDeprecated 11 | deprecationReason 12 | args { 13 | name 14 | description 15 | } 16 | } 17 | } 18 | } 19 | }` 20 | 21 | export default (request) => { 22 | return { 23 | /** 24 | * Get a GraphQL schema at the given URL 25 | * 26 | * @param {String} url GraphQL API URL 27 | * @return {Promise} Schema object 28 | */ 29 | get: (url = 'http://localhost/graphql', options = {}) => { 30 | const requestOptions = { 31 | url, 32 | qs: { query }, 33 | headers: options.headers || {}, 34 | json: true 35 | } 36 | 37 | return request(requestOptions) 38 | .then( 39 | res => res.data.schema, 40 | () => { 41 | console.error(`Unable to connect to ${url}.`) 42 | process.exit(1) 43 | } 44 | ) 45 | .catch(() => { 46 | console.log(`GraphQL schema not found at ${url}.`) 47 | process.exit(1) 48 | }) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/fixtures/parser.fixture.js: -------------------------------------------------------------------------------- 1 | const args = [ 2 | { 3 | name: 'arg1', 4 | description: null 5 | }, 6 | { 7 | name: 'arg2', 8 | description: '' 9 | }, 10 | { 11 | name: 'arg3', 12 | description: 'ignore me' 13 | } 14 | ] 15 | 16 | const fields = [ 17 | { 18 | name: 'field1', 19 | description: '', 20 | isDeprecated: false, 21 | deprecationReason: null 22 | }, 23 | { 24 | name: 'field2', 25 | description: 'Args has missing. Keep me', 26 | isDeprecated: false, 27 | deprecationReason: null, 28 | args: [ 29 | { name: 'arg1', description: '' } 30 | ] 31 | }, 32 | { 33 | name: 'field2', 34 | description: 'I have a desc. Ignore me', 35 | isDeprecated: false, 36 | deprecationReason: null 37 | }, 38 | { 39 | name: 'field3', 40 | description: 'I\'m depricated but don\'t have a reason. Keep me', 41 | isDeprecated: true, 42 | deprecationReason: null 43 | }, 44 | { 45 | name: 'field4', 46 | description: 'I\'m depricated and have a reason. Ignore me', 47 | isDeprecated: true, 48 | deprecationReason: 'Example' 49 | } 50 | ] 51 | 52 | const types = [ 53 | { 54 | name: '__Field', 55 | description: 'Known built-in type. Should be ignored', 56 | fields: [ { name: 'field', description: '' } ] 57 | }, 58 | { 59 | name: 'type1', 60 | description: '' 61 | }, 62 | { 63 | name: 'type2', 64 | description: 'Fields has missing. Keep me', 65 | fields: [ 66 | { name: 'field1', description: '', args: [] } 67 | ] 68 | }, 69 | { 70 | name: 'type3', 71 | description: 'Field Args has missing. Keep me', 72 | fields: [ 73 | { 74 | name: 'field2', 75 | description: 'I\'m a field', 76 | args: [ { name: 'arg1', description: '' } ] 77 | } 78 | ] 79 | }, 80 | { 81 | name: 'type4', 82 | description: 'I have a description. Ignore me' 83 | } 84 | ] 85 | 86 | export default { args, fields, types } 87 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --recursive 2 | --compilers js:babel-register 3 | --reporter nyan 4 | -b 5 | -------------------------------------------------------------------------------- /test/parser.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import expect from 'expect' 4 | import parser from '../src/parser' 5 | import fixtures from './fixtures/parser.fixture.js' 6 | 7 | describe('parser', function () { 8 | it('should parse field arguments', function () { 9 | expect(parser.parseArgs(fixtures.args)).toEqual([ 10 | { 11 | name: 'arg1', 12 | missing: ['description'] 13 | }, { 14 | name: 'arg2', 15 | missing: ['description'] 16 | } 17 | ]) 18 | }) 19 | 20 | it('should parse fields', function () { 21 | expect(parser.parseFields(fixtures.fields)).toEqual([ 22 | { 23 | args: [], 24 | name: 'field1', 25 | missing: ['description'] 26 | }, 27 | { 28 | name: 'field2', 29 | missing: [], 30 | args: [ 31 | { name: 'arg1', missing: ['description'] } 32 | ] 33 | }, 34 | { 35 | name: 'field3', 36 | missing: ['deprecationReason'], 37 | args: [] 38 | } 39 | ]) 40 | }) 41 | 42 | it('should parse types', function () { 43 | expect(parser.parseTypes(fixtures.types)).toEqual([ 44 | { 45 | name: 'type1', 46 | missing: ['description'], 47 | fields: [] 48 | }, 49 | { 50 | name: 'type2', 51 | missing: [], 52 | fields: [ 53 | { name: 'field1', missing: ['description'], args: [] } 54 | ] 55 | }, 56 | { 57 | name: 'type3', 58 | missing: [], 59 | fields: [ 60 | { 61 | name: 'field2', 62 | missing: [], 63 | args: [ 64 | { name: 'arg1', missing: ['description'] } 65 | ] 66 | } 67 | ] 68 | } 69 | ]) 70 | }) 71 | 72 | it('should parse a schema', function () { 73 | const schema = { types: fixtures.types } 74 | 75 | expect(parser.parse(schema)).toEqual({ 76 | types: [ 77 | { 78 | name: 'type1', 79 | missing: ['description'], 80 | fields: [] 81 | }, 82 | { 83 | name: 'type2', 84 | missing: [], 85 | fields: [ 86 | { name: 'field1', missing: ['description'], args: [] } 87 | ] 88 | }, 89 | { 90 | name: 'type3', 91 | missing: [], 92 | fields: [ 93 | { 94 | name: 'field2', 95 | missing: [], 96 | args: [ 97 | { name: 'arg1', missing: ['description'] } 98 | ] 99 | } 100 | ] 101 | } 102 | ] 103 | }) 104 | }) 105 | }) 106 | -------------------------------------------------------------------------------- /test/printer.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import expect from 'expect' 4 | import chalk from 'chalk' 5 | import printer from '../src/printer' 6 | 7 | describe('printer', function () { 8 | const results = { 9 | types: [ 10 | { name: 'type1', missing: ['description'], fields: [] }, 11 | { 12 | name: 'type2', 13 | missing: [], 14 | fields: [ 15 | { name: 'field1', missing: ['description'], args: [] }, 16 | { 17 | name: 'field2', 18 | missing: [], 19 | args: [ 20 | { name: 'arg1', missing: ['description'] } 21 | ] 22 | } 23 | ] 24 | } 25 | ] 26 | } 27 | 28 | const expected = [ 29 | chalk.yellow('✘ Found 3 fields with missing documentation') + '\n\n', 30 | chalk.red('type1') + ' ' + chalk.gray('[description]') + '\n\n', 31 | 'type2\r\n', 32 | '├─ ' + chalk.red('field1') + ' ' + chalk.gray('[description]') + '\r\n', 33 | '└─ field2\r\n', 34 | ' └─ ' + chalk.red('arg1') + ' ' + chalk.gray('[description]') 35 | ].join('') 36 | 37 | it('should make results for missing docs', function () { 38 | expect(printer.print(results)) 39 | .toEqual(expected) 40 | }) 41 | 42 | it('should make results for 1 field with missing docs', function () { 43 | const tweakedResults = { 44 | types: results.types.slice(0, 1) 45 | } 46 | 47 | expect(printer.print(tweakedResults)) 48 | .toEqual([ 49 | chalk.yellow('✘ Found 1 field with missing documentation') + '\n\n', 50 | chalk.red('type1') + ' ' + chalk.gray('[description]') 51 | ].join('')) 52 | }) 53 | 54 | it('should make results for no missing docs', function () { 55 | expect(printer.print({ types: [] })) 56 | .toEqual(chalk.green('✔︎ No fields are missing documentation') + '\n\n') 57 | }) 58 | }) 59 | -------------------------------------------------------------------------------- /test/retriever.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import expect from 'expect' 4 | import sinon from 'sinon' 5 | import 'sinon-as-promised' 6 | import retriever from '../src/retriever' 7 | 8 | describe('retriever', function (done) { 9 | it('should retrieve a schema', function (done) { 10 | const request = sinon.stub().resolves({ 11 | data: { schema: {} } 12 | }) 13 | 14 | retriever(request).get() 15 | .then(() => { 16 | expect(request.calledOnce).toEqual(true) 17 | done() 18 | }) 19 | .catch(console.error) 20 | }) 21 | }) 22 | --------------------------------------------------------------------------------