From 04784e038edf23a3adec355bd80146e294d5896d Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Fri, 5 Oct 2018 15:43:02 +0200 Subject: [PATCH 01/22] refactor: convert options into a JSON file --- src/cli.js | 1 + src/dredd.js | 10 +-- src/options.js | 206 ----------------------------------------------- src/options.json | 154 +++++++++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 211 deletions(-) delete mode 100644 src/options.js create mode 100644 src/options.json diff --git a/src/cli.js b/src/cli.js index 52aac15cb..6d909a44e 100644 --- a/src/cli.js +++ b/src/cli.js @@ -2,6 +2,7 @@ const console = require('console'); // Stubbed in tests by proxyquire const fs = require('fs'); const optimist = require('optimist'); const os = require('os'); +const clone = require('clone'); const spawnArgs = require('spawn-args'); const spawnSync = require('cross-spawn').sync; diff --git a/src/dredd.js b/src/dredd.js index b42e6a3d0..1777a837b 100644 --- a/src/dredd.js +++ b/src/dredd.js @@ -12,7 +12,7 @@ const logger = require('./logger'); const Runner = require('./transaction-runner'); const { applyConfiguration } = require('./configuration'); -let options = require('./options'); +const options = require('./options'); const PROXY_ENV_VARIABLES = ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY']; const FILE_DOWNLOAD_TIMEOUT = 5000; @@ -189,11 +189,11 @@ API description document (or documents) not found on path: } downloadFile(fileUrl, callback) { - options = clone(this.configuration.http); - options.url = fileUrl; - options.timeout = FILE_DOWNLOAD_TIMEOUT; + const opts = clone(this.configuration.http); + opts.url = fileUrl; + opts.timeout = FILE_DOWNLOAD_TIMEOUT; - request.get(options, (downloadError, res, body) => { + request.get(opts, (downloadError, res, body) => { let err; if (downloadError) { logger.debug(`Downloading ${fileUrl} errored:`, `${downloadError}` || downloadError.code); diff --git a/src/options.js b/src/options.js deleted file mode 100644 index 9ca0bf5a7..000000000 --- a/src/options.js +++ /dev/null @@ -1,206 +0,0 @@ -const options = { - 'dry-run': { - alias: 'y', - description: 'Do not run any real HTTP transaction, only parse API description document and compile transactions.', - default: null - }, - - hookfiles: { - alias: 'f', - description: `Specifies a pattern to match files with before/after hooks for running tests. -Files are executed in alphabetical order.`, - default: null - }, - - language: { - alias: 'a', - description: 'Language of hookfiles. Possible options are: nodejs, ruby, python, php, perl, go, rust', - default: 'nodejs' - }, - - sandbox: { - alias: 'b', - description: 'Load and run non trusted hooks code in sandboxed container', - default: false - }, - - server: { - alias: 'g', - description: 'Run API backend server command and kill it after Dredd execution. E.g. `rails server`', - default: null - }, - - 'server-wait': { - description: 'Set delay time in seconds between running a server and test run.', - default: 3 - }, - - init: { - alias: 'i', - description: 'Run interactive configuration. Creates dredd.yml configuration file.', - default: false - }, - - custom: { - alias: 'j', - description: 'Pass custom key-value configuration data delimited by a colon. E.g. -j \'a:b\'', - default: [] - }, - - names: { - alias: 'n', - description: 'Only list names of requests (for use in a hookfile). No requests are made.', - default: false - }, - - only: { - alias: 'x', - description: 'Run only specified transaction name. Can be used multiple times', - default: [] - }, - - reporter: { - alias: 'r', - description: `Output additional report format. This option can be used -multiple times to add multiple reporters. -Options: xunit, nyan, dot, markdown, html, apiary.\n`, - default: [] - }, - - output: { - alias: 'o', - description: ` -Specifies output file when using additional file-based reporter. -This option can be used multiple times if multiple file-based reporters are used.\n`, - default: [] - }, - - header: { - alias: 'h', - description: ` -Extra header to include in every request. -This option can be used multiple times to add multiple headers.\n`, - default: [] - }, - - sorted: { - alias: 's', - description: ` -Sorts requests in a sensible way so that objects are not modified before they are created. -Order: CONNECT, OPTIONS, POST, GET, HEAD, PUT, PATCH, DELETE, TRACE.\n`, - default: false - }, - - user: { - alias: 'u', - description: 'Basic Auth credentials in the form username:password.\n', - default: null - }, - - 'inline-errors': { - alias: 'e', - description: ` -Determines whether failures and errors are displayed as they -occur (true) or aggregated and displayed at the end (false).\n`, - default: false - }, - - details: { - alias: 'd', - description: 'Determines whether request/response details are included in passing tests.\n', - default: false - }, - - method: { - alias: 'm', - description: ` -Restrict tests to a particular HTTP method (GET, PUT, POST, DELETE, PATCH). -This option can be used multiple times to allow multiple methods.\n`, - default: [] - }, - - color: { - alias: 'c', - description: 'Determines whether console output should include colors.\n', - default: true - }, - - level: { - alias: 'l', - description: 'The level of logging to output. Options: silly, debug, verbose, info, warn, error.\n', - default: 'info' - }, - - timestamp: { - alias: 't', - description: 'Determines whether console output should include timestamps.\n', - default: false - }, - - silent: { - alias: 'q', - description: 'Silences commandline output.\n', - default: false - }, - - path: { - alias: 'p', - description: 'Additional API description paths or URLs. Can be used multiple times with glob pattern for paths.', - default: [] - }, - - help: { - description: 'Show usage information.\n' - }, - - version: { - description: 'Show version number.\n' - }, - - 'hooks-worker-timeout': { - description: 'How long to wait for hooks worker to start. [ms]', - default: 5000 - }, - - 'hooks-worker-connect-timeout': { - description: 'Total hook worker connection timeout (includes all retries). [ms]', - default: 1500 - }, - - 'hooks-worker-connect-retry': { - description: 'How long to wait between attempts to connect to hooks worker. [ms]', - default: 500 - }, - - 'hooks-worker-after-connect-wait': { - description: 'How long to wait between connecting to hooks worker and start of testing. [ms]', - default: 100 - }, - - 'hooks-worker-term-timeout': { - description: 'How long to wait between trying to terminate hooks worker and killing it. [ms]', - default: 5000 - }, - - 'hooks-worker-term-retry': { - description: 'How long to wait between attempts to terminate hooks worker. [ms]', - default: 500 - }, - - 'hooks-worker-handler-host': { - description: 'Host of the hook worker.', - default: '127.0.0.1' - }, - - 'hooks-worker-handler-port': { - description: 'Port of the hook worker.', - default: 61321 - }, - - config: { - description: 'Path to dredd.yml config file.', - default: './dredd.yml' - } -}; - -module.exports = options; diff --git a/src/options.json b/src/options.json new file mode 100644 index 000000000..18ad6972e --- /dev/null +++ b/src/options.json @@ -0,0 +1,154 @@ +{ + "dry-run": { + "alias": "y", + "description": "Do not run any real HTTP transaction, only parse API description document and compile transactions.", + "default": null + }, + "hookfiles": { + "alias": "f", + "description": "Specifies a pattern to match files with before/after hooks for running tests. Files are executed in alphabetical order.", + "default": null + }, + "language": { + "alias": "a", + "description": "Language of hookfiles. Possible options are: nodejs, ruby, python, php, perl, go, rust", + "default": "nodejs" + }, + "sandbox": { + "alias": "b", + "description": "Load and run non trusted hooks code in sandboxed container", + "default": false + }, + "server": { + "alias": "g", + "description": "Run API backend server command and kill it after Dredd execution. E.g. `rails server`", + "default": null + }, + "server-wait": { + "description": "Set delay time in seconds between running a server and test run.", + "default": 3 + }, + "init": { + "alias": "i", + "description": "Run interactive configuration. Creates dredd.yml configuration file.", + "default": false + }, + "custom": { + "alias": "j", + "description": "Pass custom key-value configuration data delimited by a colon. E.g. -j 'a:b'", + "default": [] + }, + "names": { + "alias": "n", + "description": "Only list names of requests (for use in a hookfile). No requests are made.", + "default": false + }, + "only": { + "alias": "x", + "description": "Run only specified transaction name. Can be used multiple times", + "default": [] + }, + "reporter": { + "alias": "r", + "description": "Output additional report format. This option can be used multiple times to add multiple reporters. Options: xunit, nyan, dot, markdown, html, apiary.", + "default": [] + }, + "output": { + "alias": "o", + "description": "Specifies output file when using additional file-based reporter. This option can be used multiple times if multiple file-based reporters are used.", + "default": [] + }, + "header": { + "alias": "h", + "description": "Extra header to include in every request. This option can be used multiple times to add multiple headers.", + "default": [] + }, + "sorted": { + "alias": "s", + "description": "Sorts requests in a sensible way so that objects are not modified before they are created. Order: CONNECT, OPTIONS, POST, GET, HEAD, PUT, PATCH, DELETE, TRACE.", + "default": false + }, + "user": { + "alias": "u", + "description": "Basic Auth credentials in the form username:password.", + "default": null + }, + "inline-errors": { + "alias": "e", + "description": "Determines whether failures and errors are displayed as they occur (true) or aggregated and displayed at the end (false).", + "default": false + }, + "details": { + "alias": "d", + "description": "Determines whether request/response details are included in passing tests.", + "default": false + }, + "method": { + "alias": "m", + "description": "Restrict tests to a particular HTTP method (GET, PUT, POST, DELETE, PATCH). This option can be used multiple times to allow multiple methods.", + "default": [] + }, + "color": { + "alias": "c", + "description": "Determines whether console output should include colors.", + "default": true + }, + "level": { + "alias": "l", + "description": "The level of logging to output. Options: silly, debug, verbose, info, warn, error.", + "default": "info" + }, + "timestamp": { + "alias": "t", + "description": "Determines whether console output should include timestamps.", + "default": false + }, + "silent": { + "alias": "q", + "description": "Silences commandline output.", + "default": false + }, + "path": { + "alias": "p", + "description": "Additional API description paths or URLs. Can be used multiple times with glob pattern for paths.", + "default": [] + }, + "help": { + "description": "Show usage information." }, "version": { + "description": "Show version number." }, "hooks-worker-timeout": { + "description": "How long to wait for hooks worker to start. [ms]", + "default": 5000 + }, + "hooks-worker-connect-timeout": { + "description": "Total hook worker connection timeout (includes all retries). [ms]", + "default": 1500 + }, + "hooks-worker-connect-retry": { + "description": "How long to wait between attempts to connect to hooks worker. [ms]", + "default": 500 + }, + "hooks-worker-after-connect-wait": { + "description": "How long to wait between connecting to hooks worker and start of testing. [ms]", + "default": 100 + }, + "hooks-worker-term-timeout": { + "description": "How long to wait between trying to terminate hooks worker and killing it. [ms]", + "default": 5000 + }, + "hooks-worker-term-retry": { + "description": "How long to wait between attempts to terminate hooks worker. [ms]", + "default": 500 + }, + "hooks-worker-handler-host": { + "description": "Host of the hook worker.", + "default": "127.0.0.1" + }, + "hooks-worker-handler-port": { + "description": "Port of the hook worker.", + "default": 61321 + }, + "config": { + "description": "Path to dredd.yml config file.", + "default": "./dredd.yml" + } +} From 1be7da68fe37e6f85da9535bca0c807fa4ee1ade Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Tue, 16 Oct 2018 16:06:33 +0200 Subject: [PATCH 02/22] docs: use .rst, remove JS exts, assume JS in the env --- docs/conf.py | 213 ++----------------------------------------- docs/install-node.sh | 20 ---- readthedocs.yml | 4 + 3 files changed, 12 insertions(+), 225 deletions(-) delete mode 100755 docs/install-node.sh create mode 100644 readthedocs.yml diff --git a/docs/conf.py b/docs/conf.py index 77c212662..04e2d2d8a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,16 +22,13 @@ IS_READTHEDOCS = os.environ.get('READTHEDOCS') == 'True' +if IS_READTHEDOCS: + subprocess.check_call('npm install', cwd=project_dir, shell=True) + docs_dir = os.path.dirname(__file__) project_dir = os.path.join(docs_dir, '..') node_modules_bin_dir = os.path.join(project_dir, 'node_modules', '.bin') -if IS_READTHEDOCS: - installation_output = subprocess.getoutput('bash ' + os.path.join(docs_dir, 'install-node.sh')) - node_bin = installation_output.splitlines()[-1].strip() -else: - node_bin = 'node' - with open(os.path.join(project_dir, 'package.json')) as f: package_json = json.load(f) @@ -47,8 +44,7 @@ # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: -source_suffix = '.md' -source_parsers = {'.md': CommonMarkParser} +source_suffix = '.rst' # The master document. master_doc = 'index' @@ -85,12 +81,7 @@ def get_release(): # Semantic Release wasn't able to determine a new version number, # either because of some error or because there are no changes which # would bump the version number. Stick to the latest released version. - if IS_READTHEDOCS: - npm_bin = node_bin.replace('/bin/node', '/bin/npm') - command = '{} {} view dredd version'.format(node_bin, npm_bin) - else: - command = 'npm view dredd version' - return subprocess.getoutput(command).strip() + return subprocess.getoutput('npm view dredd version').strip() # The full version, including alpha/beta/rc tags. release = get_release() @@ -116,10 +107,10 @@ def get_release(): # -- Options for HTML output ---------------------------------------------- -# The theme to use for HTML and HTML Help pages. See the documentation for +# The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. if IS_READTHEDOCS: - # equals to default RTD theme + # equals to the default RTD theme html_theme = 'default' else: # emulates the default RTD theme for local development @@ -171,195 +162,7 @@ def get_release(): # -- Custom Extensions ---------------------------------------------------- def setup(app): - # Lets Hercule (https://www.npmjs.com/package/hercule) and Node.js scripts - # from the 'docs/_extensions' directory to process each document before - # it gets processed by Sphinx - init_js_extensions(app) - - # Fixing how references (local links) work with Markdown - app.connect('doctree-read', collect_ref_data) - app.connect('doctree-resolved', process_refs) - - # Better support for Markdown (see https://recommonmark.readthedocs.io/en/latest/auto_structify.html) - app.add_config_value('recommonmark_config', { - 'enable_eval_rst': True, - 'enable_auto_toc_tree': True, - 'auto_toc_tree_section': 'Contents', - }, True) - app.add_transform(AutoStructify) - - -# -- Markdown References -------------------------------------------------- - -def collect_ref_data(app, doctree): - """ - Finds all anchors and references (local links) within documents, - and saves them as meta data - """ - filename = doctree.attributes['source'].replace(docs_dir, '').lstrip('/') - docname = filename.replace('.md', '') - - anchors = [] - references = [] - - for node in doctree.traverse(nodes.raw): - if 'name=' in node.rawsource: - match = re.search(r'name="([^\"]+)', node.rawsource) - if match: - anchors.append(match.group(1)) - elif 'id=' in node.rawsource: - match = re.search(r'id="([^\"]+)', node.rawsource) - if match: - anchors.append(match.group(1)) - - for node in doctree.traverse(nodes.section): - for target in frozenset(node.attributes.get('ids', [])): - anchors.append(target) - - for node in doctree.traverse(nodes.reference): - uri = node.get('refuri') - if uri and not uri.startswith(('http://', 'https://')): - references.append(to_reference(uri, basedoc=docname)) - - app.env.metadata[docname]['anchors'] = anchors - app.env.metadata[docname]['references'] = references - -def process_refs(app, doctree, docname): - """ - Fixes all references (local links) within documents, breaks the build - if it finds any links to non-existent documents or anchors. - """ - for reference in app.env.metadata[docname]['references']: - referenced_docname, anchor = parse_reference(reference) - - if referenced_docname not in app.env.metadata: - message = "Document '{}' is referenced from '{}', but it could not be found" - raise SphinxError(message.format(referenced_docname, docname)) - - if anchor and anchor not in app.env.metadata[referenced_docname]['anchors']: - message = "Section '{}#{}' is referenced from '{}', but it could not be found" - raise SphinxError(message.format(referenced_docname, anchor, docname)) - - for node in doctree.traverse(nodes.reference): - uri = node.get('refuri') - if to_reference(uri, basedoc=docname) == reference: - node['refuri'] = to_uri(app, referenced_docname, anchor) - -def to_uri(app, docname, anchor=None): - uri = '' - - if IS_READTHEDOCS: - language = app.config.language or 'en' - version_name = os.environ.get('READTHEDOCS_VERSION') - uri = '/{}/{}'.format(language, version_name) - - uri += '/{}.html'.format(docname) - if anchor: - uri += '#{}'.format(anchor) - - return uri - -def to_reference(uri, basedoc=None): - """ - Helper function, compiles a 'reference' from given URI and base - document name - """ - if '#' in uri: - filename, anchor = uri.split('#', 1) - filename = filename or basedoc - else: - filename = uri or basedoc - anchor = None - - if not filename: - message = "For self references like '{}' you need to provide the 'basedoc' argument".format(uri) - raise ValueError(message) - - reference = os.path.splitext(filename.lstrip('/'))[0] - if anchor: - reference += '#' + anchor - return reference - -def parse_reference(reference): - """ - Helper function, parses a 'reference' to document name and anchor - """ - if '#' in reference: - docname, anchor = reference.split('#', 1) - else: - docname = reference - anchor = None - return docname, anchor - - -# -- JavaScript Extensions ------------------------------------------------ - -js_extensions_dir = os.path.join(docs_dir, '_extensions') -js_extensions = [] -js_interpreters = { - '.js': [node_bin], - '.coffee': [node_bin, os.path.join(node_modules_bin_dir, 'coffee')] -} - -def init_js_extensions(app): - """ - Looks up and registers the Node.js extensions - - Loads Node.js scripts from the 'docs/_extensions' directory, assigns - interpreters to them (node vs. coffee) and registers the 'run_js_extensions' - function. - """ - app.info(console.bold('initializing Node.js extensions... '), nonl=True) - for basename in sorted(os.listdir(js_extensions_dir)): - _, ext = os.path.splitext(basename) - - if ext in js_interpreters.keys(): - filename = os.path.join(js_extensions_dir, basename) - command = js_interpreters[ext] + [filename] - js_extensions.append((basename, command)) - - app.connect('source-read', run_js_extensions) - app.info('{} found'.format(len(js_extensions))) - app.verbose('JavaScript extensions: ' + ', '.join(dict(js_extensions).keys())) - -def run_js_extensions(app, docname, source_list): - """ - Lets all registered Node.js extensions to process given document source - - Executed for each document after the source gets read. Sequentially feeds - stdin of each registered Node.js with the source and continues with whatever - the extension sends to stdout. The extensions are provided with the document - name as the first CLI argument. - - Hercule (https://www.npmjs.com/package/hercule) is built-in as if it was - the first Node.js extension in the pipeline. - """ - source = source_list[0] - - app.verbose(console.bold("runnning JavaScript extension 'hercule'... ") + console.blue(docname)) - command = [node_bin, os.path.join(node_modules_bin_dir, 'hercule'), '--relative=' + docs_dir, '--stdin'] - source = run_extension('hercule', command, source) - - for basename, command in js_extensions: - app.verbose(console.bold("runnning JavaScript extension '{}'... ".format(basename)) + console.blue(docname)) - source = run_extension(basename, command + [docname], source) - - source_list[0] = source - -def run_extension(extension_name, command, source): - """ - Runs given command as a subprocess and lets it to modify given source - """ - proc = subprocess.Popen(command, stdout=subprocess.PIPE, stdin=subprocess.PIPE) - proc.stdin.write(source.encode('utf-8')) - proc.stdin.close() - - source = proc.stdout.read().decode('utf-8') - exit_status = proc.wait() - if exit_status: - message = "JavaScript extension '{}' finished with non-zero exit status: {}" - raise SphinxError(message.format(extension_name, exit_status)) - return source + pass # -- Hacks ---------------------------------------------------------------- diff --git a/docs/install-node.sh b/docs/install-node.sh deleted file mode 100755 index 539d24d18..000000000 --- a/docs/install-node.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# In the ReadTheDocs build, this file is ran by Sphinx' conf.py to install -# support for Node.js. - -set -e - - -if [ "$READTHEDOCS" = 'True' ]; then - if [ ! -d ~/.nvm ]; then - git clone git://github.com/creationix/nvm.git ~/.nvm - fi - . ~/.nvm/nvm.sh - - nvm install 10 - nvm use 10 - - npm install --no-optional - - echo $(which node) -fi diff --git a/readthedocs.yml b/readthedocs.yml new file mode 100644 index 000000000..d97e42fc5 --- /dev/null +++ b/readthedocs.yml @@ -0,0 +1,4 @@ +build: + image: latest +python: + version: 3.6 From b1883f9e7482652f9b2e24f12f414339e47212bf Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Tue, 16 Oct 2018 16:07:53 +0200 Subject: [PATCH 03/22] docs: lint docs by doc8 --- doc8.ini | 4 ++++ docs/requirements.txt | 2 +- package.json | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 doc8.ini diff --git a/doc8.ini b/doc8.ini new file mode 100644 index 000000000..06d3cb304 --- /dev/null +++ b/doc8.ini @@ -0,0 +1,4 @@ +[doc8] +# Do not check line length. This project relies on writing in an editor with +# word wrap turned on. No explicit newlines, please. +ignore=D001 diff --git a/docs/requirements.txt b/docs/requirements.txt index 4f4b4e224..86c63efb4 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,6 @@ sphinx==1.5.6 sphinx-autobuild==0.7.1 sphinx-rtd-theme==0.2.4 -recommonmark==0.4.0 pygments-markdown-lexer==0.1.0.dev39 pygments-apiblueprint==0.1.0 +doc8==0.8.0 diff --git a/package.json b/package.json index d490aac12..a60d76ee4 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "build": "babel ./src --out-dir ./lib/", "build:watch": "babel ./src --out-dir ./lib/ --watch", "coveralls": "scripts/coveralls.sh", - "docs:lint": "sphinx-build -nW -b linkcheck docs docs/_build/", + "docs:lint": "doc8 && sphinx-build -nW -b linkcheck docs docs/_build/", "docs:build": "sphinx-build -nW -b html docs docs/_build/", "docs:serve": "sphinx-autobuild docs docs/_build/", "lint": "conventional-changelog-lint --from=master && eslint .", From f35272470791e0c1ffdcf770b69969cc462a1651 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Tue, 16 Oct 2018 18:50:38 +0200 Subject: [PATCH 04/22] chore: fix minor typo --- docs/redirects.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/redirects.yml b/docs/redirects.yml index 3d4281474..0ae03ceb5 100644 --- a/docs/redirects.yml +++ b/docs/redirects.yml @@ -3,7 +3,7 @@ # to Dredd maintainers to keep this list in sync with reality. # # You can use https://github.com/honzajavorek/rtd-redirects to programmatically -# upload the redirects to ReadTheDocs admin interface. +# upload the redirects to the ReadTheDocs admin interface. redirects: # removed pages "/example/": "/quickstart.html" From ab504b0f00da9dd98a7aaa5ace9ddb0f43fa638e Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Tue, 16 Oct 2018 18:55:07 +0200 Subject: [PATCH 05/22] docs: rename docs files to .rst --- .github/{CONTRIBUTING.md => CONTRIBUTING.rst} | 0 docs/{contributing.md => contributing.rst} | 0 docs/{data-structures.md => data-structures.rst} | 0 docs/{hooks-go.md => hooks-go.rst} | 0 docs/{hooks-js-sandbox.md => hooks-js-sandbox.rst} | 0 docs/{hooks-new-language.md => hooks-new-language.rst} | 0 docs/{hooks-nodejs.md => hooks-nodejs.rst} | 0 docs/{hooks-perl.md => hooks-perl.rst} | 0 docs/{hooks-php.md => hooks-php.rst} | 0 docs/{hooks-python.md => hooks-python.rst} | 0 docs/{hooks-ruby.md => hooks-ruby.rst} | 0 docs/{hooks-rust.md => hooks-rust.rst} | 0 docs/{hooks.md => hooks.rst} | 0 docs/{how-it-works.md => how-it-works.rst} | 0 docs/{how-to-guides.md => how-to-guides.rst} | 0 docs/{index.md => index.rst} | 0 docs/{installation.md => installation.rst} | 0 docs/{quickstart.md => quickstart.rst} | 0 docs/{usage-js.md => usage-js.rst} | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename .github/{CONTRIBUTING.md => CONTRIBUTING.rst} (100%) rename docs/{contributing.md => contributing.rst} (100%) rename docs/{data-structures.md => data-structures.rst} (100%) rename docs/{hooks-go.md => hooks-go.rst} (100%) rename docs/{hooks-js-sandbox.md => hooks-js-sandbox.rst} (100%) rename docs/{hooks-new-language.md => hooks-new-language.rst} (100%) rename docs/{hooks-nodejs.md => hooks-nodejs.rst} (100%) rename docs/{hooks-perl.md => hooks-perl.rst} (100%) rename docs/{hooks-php.md => hooks-php.rst} (100%) rename docs/{hooks-python.md => hooks-python.rst} (100%) rename docs/{hooks-ruby.md => hooks-ruby.rst} (100%) rename docs/{hooks-rust.md => hooks-rust.rst} (100%) rename docs/{hooks.md => hooks.rst} (100%) rename docs/{how-it-works.md => how-it-works.rst} (100%) rename docs/{how-to-guides.md => how-to-guides.rst} (100%) rename docs/{index.md => index.rst} (100%) rename docs/{installation.md => installation.rst} (100%) rename docs/{quickstart.md => quickstart.rst} (100%) rename docs/{usage-js.md => usage-js.rst} (100%) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.rst similarity index 100% rename from .github/CONTRIBUTING.md rename to .github/CONTRIBUTING.rst diff --git a/docs/contributing.md b/docs/contributing.rst similarity index 100% rename from docs/contributing.md rename to docs/contributing.rst diff --git a/docs/data-structures.md b/docs/data-structures.rst similarity index 100% rename from docs/data-structures.md rename to docs/data-structures.rst diff --git a/docs/hooks-go.md b/docs/hooks-go.rst similarity index 100% rename from docs/hooks-go.md rename to docs/hooks-go.rst diff --git a/docs/hooks-js-sandbox.md b/docs/hooks-js-sandbox.rst similarity index 100% rename from docs/hooks-js-sandbox.md rename to docs/hooks-js-sandbox.rst diff --git a/docs/hooks-new-language.md b/docs/hooks-new-language.rst similarity index 100% rename from docs/hooks-new-language.md rename to docs/hooks-new-language.rst diff --git a/docs/hooks-nodejs.md b/docs/hooks-nodejs.rst similarity index 100% rename from docs/hooks-nodejs.md rename to docs/hooks-nodejs.rst diff --git a/docs/hooks-perl.md b/docs/hooks-perl.rst similarity index 100% rename from docs/hooks-perl.md rename to docs/hooks-perl.rst diff --git a/docs/hooks-php.md b/docs/hooks-php.rst similarity index 100% rename from docs/hooks-php.md rename to docs/hooks-php.rst diff --git a/docs/hooks-python.md b/docs/hooks-python.rst similarity index 100% rename from docs/hooks-python.md rename to docs/hooks-python.rst diff --git a/docs/hooks-ruby.md b/docs/hooks-ruby.rst similarity index 100% rename from docs/hooks-ruby.md rename to docs/hooks-ruby.rst diff --git a/docs/hooks-rust.md b/docs/hooks-rust.rst similarity index 100% rename from docs/hooks-rust.md rename to docs/hooks-rust.rst diff --git a/docs/hooks.md b/docs/hooks.rst similarity index 100% rename from docs/hooks.md rename to docs/hooks.rst diff --git a/docs/how-it-works.md b/docs/how-it-works.rst similarity index 100% rename from docs/how-it-works.md rename to docs/how-it-works.rst diff --git a/docs/how-to-guides.md b/docs/how-to-guides.rst similarity index 100% rename from docs/how-to-guides.md rename to docs/how-to-guides.rst diff --git a/docs/index.md b/docs/index.rst similarity index 100% rename from docs/index.md rename to docs/index.rst diff --git a/docs/installation.md b/docs/installation.rst similarity index 100% rename from docs/installation.md rename to docs/installation.rst diff --git a/docs/quickstart.md b/docs/quickstart.rst similarity index 100% rename from docs/quickstart.md rename to docs/quickstart.rst diff --git a/docs/usage-js.md b/docs/usage-js.rst similarity index 100% rename from docs/usage-js.md rename to docs/usage-js.rst From e1b8b53a3488c2204fc633a8d3f1231419cb0081 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Tue, 16 Oct 2018 18:57:41 +0200 Subject: [PATCH 06/22] docs: convert docs files to reStructuredText --- .github/CONTRIBUTING.rst | 415 ++++++------ docs/contributing.rst | 2 +- docs/data-structures.rst | 435 +++++++------ docs/hooks-go.rst | 364 ++++++----- docs/hooks-js-sandbox.rst | 145 ++--- docs/hooks-new-language.rst | 160 +++-- docs/hooks-nodejs.rst | 426 +++++++------ docs/hooks-perl.rst | 315 ++++----- docs/hooks-php.rst | 250 ++++---- docs/hooks-python.rst | 286 +++++---- docs/hooks-ruby.rst | 291 +++++---- docs/hooks-rust.rst | 319 +++++----- docs/hooks.rst | 129 ++-- docs/how-it-works.rst | 340 +++++----- docs/how-to-guides.rst | 1196 ++++++++++++++++++----------------- docs/index.rst | 188 +++--- docs/installation.rst | 137 ++-- docs/quickstart.rst | 199 +++--- docs/usage-cli.rst | 109 ++++ docs/usage-js.rst | 141 +++-- 20 files changed, 3068 insertions(+), 2779 deletions(-) create mode 100644 docs/usage-cli.rst diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index a65b26b96..7d326f1d3 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -1,345 +1,290 @@ -# Contributing Guidelines +.. _contributing: -## Quick Start +Contributing Guidelines +======================= -### Ideas +Quick Start +----------- -- File an [issue][issues]. -- Explain why you want the feature. How does it help you? What for do you want the feature? +Ideas +~~~~~ -### Bugs +- File an `issue `__. +- Explain why you want the feature. How does it help you? What for do you want the feature? -- File an [issue][issues]. -- Ideally, write a failing test and send it as a Pull Request. +Bugs +~~~~ -### Coding +- File an `issue `__. +- Ideally, write a failing test and send it as a Pull Request. -- Dredd is written in JavaScript [ES2015+](https://tc39.github.io/ecma262/). -- Dredd uses [Semantic Release and Conventional Changelog](#sem-rel). +Coding +~~~~~~ -#### Recommended Workflow +- Dredd is written in JavaScript `ES2015+ `__. +- Dredd uses :ref:`sem-rel`. -1. Fork Dredd. -2. Create a feature branch. -3. Write tests. -4. Write code. -5. Lint what you created: `npm run lint` -6. Send a Pull Request. -7. Make sure [test coverage][] didn't drop and all CI builds are passing. +Recommended Workflow +^^^^^^^^^^^^^^^^^^^^ - -#### Semantic Release and Conventional Changelog +1. Fork Dredd. +2. Create a feature branch. +3. Write tests. +4. Write code. +5. Lint what you created: ``npm run lint`` +6. Send a Pull Request. +7. Make sure `test coverage `__ didn’t drop and all CI builds are passing. -Releasing of new Dredd versions to npm is automatically managed by [Semantic Release][]. -Semantic Release makes sure correct version numbers get bumped according to the **meaning** -of your changes once your PR gets merged to `master`. +.. _sem-rel: -To make it work, it's necessary to follow [Conventional Changelog][]. That basically -means all commit messages in the project should follow a particular format: +Semantic Release and Conventional Changelog +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``` -: -``` +Releasing of new Dredd versions to npm is automatically managed by `Semantic Release `__. Semantic Release makes sure correct version numbers get bumped according to the **meaning** of your changes once your PR gets merged to ``master``. -Where `` is: +To make it work, it’s necessary to follow `Conventional Changelog `__. That basically means all commit messages in the project should follow a particular format:: -- `feat` - New functionality added -- `fix` - Broken functionality fixed -- `perf` - Performance improved -- `docs` - Documentation added/removed/improved/... -- `chore` - Package setup, CI setup, ... -- `refactor` - Changes in code, but no changes in behavior -- `test` - Tests added/removed/improved/... + : -In the rare cases when your changes break backwards compatibility, the message -must include string `BREAKING CHANGE:`. That will result in bumping the major version. +Where ```` is: -Seems hard? +- ``feat`` - New functionality added +- ``fix`` - Broken functionality fixed +- ``perf`` - Performance improved +- ``docs`` - Documentation added/removed/improved/… +- ``chore`` - Package setup, CI setup, … +- ``refactor`` - Changes in code, but no changes in behavior +- ``test`` - Tests added/removed/improved/… -- See [existing commits][] as a reference -- [Commitizen CLI][] can help you to create correct commit messages -- `npm run lint` validates format of your messages +In the rare cases when your changes break backwards compatibility, the message must include string ``BREAKING CHANGE:``. That will result in bumping the major version. -## Handbook for Contributors and Maintainers +Seems hard? -### Maintainers +- See `existing commits `__ as a reference +- `Commitizen CLI `__ can help you to create correct commit messages +- ``npm run lint`` validates format of your messages -[Apiary][] is the main author and maintainer of Dredd's [upstream repository][]. -Currently responsible people are: +Handbook for Contributors and Maintainers +----------------------------------------- -- [@netmilk](https://github.com/netmilk) - product decisions, feature requests -- [@honzajavorek](https://github.com/honzajavorek) - lead of development -- [@michalholasek](https://github.com/michalholasek) - team member +Maintainers +~~~~~~~~~~~ -### Programming Language +`Apiary `__ is the main author and maintainer of Dredd’s `upstream repository `__. Currently responsible people are: -Dredd is written in [JavaScript (ES2015+)][] and is meant -to be ran on server using Node.js. Before publishing to the npm registry, it is -compiled to plain ES5 JavaScript code (throwaway `lib` directory). +- [@netmilk](https://github.com/netmilk) - product decisions, feature requests +- [@honzajavorek](https://github.com/honzajavorek) - lead of development +- [@michalholasek](https://github.com/michalholasek) - team member -Tests need pre-compiled every time because some integration tests use code -linked from `lib`. This is certainly a flaw and it slows down day-to-day development, -but untill we streamline our build pipeline, the `lib` dependency is necessary. +Programming Language +~~~~~~~~~~~~~~~~~~~~ -Also mind that [CoffeeScript][] is production dependency (not dev dependency), -because it's needed for running user-provided hooks written in CoffeeScript. +Dredd is written in `JavaScript (ES2015+) `__ and is meant to be ran on server using Node.js. Before publishing to the npm registry, it is compiled to plain ES5 JavaScript code (throwaway ``lib`` directory). -### Compiled vs pure JavaScript +Tests need pre-compiled every time because some integration tests use code linked from ``lib``. This is certainly a flaw and it slows down day-to-day development, but until we streamline our build pipeline, the ``lib`` dependency is necessary. -Dredd uses [Drafter][] for parsing [API Blueprint][] documents. Drafter is written in C++11 and needs to be compiled during installation. Because that can cause a lot of problems in some environments, there's also pure JavaScript version of the parser, [drafter.js][]. Drafter.js is fully equivalent, but it can have slower performance. Therefore there's [drafter-npm][] package, which tries to compile the C++11 version of the parser and uses the JavaScript equivalent in case of failure. +Also mind that `CoffeeScript `__ is production dependency (not dev dependency), because it’s needed for running user-provided hooks written in CoffeeScript. -Dredd depends on the [drafter-npm][] package. That's the reason why you can see `node-gyp` errors and failures during the installation process, even though when it's done, Dredd seems to normally work and correctly parses API Blueprint documents. +.. _compiled-vs-pure-javascript: -#### Forcing the JavaScript version +Compiled vs pure JavaScript +~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The `--no-optional` option forces the JavaScript version of Drafter and avoids any compilation attempts when installing Dredd: +Dredd uses `Drafter `__ for parsing `API Blueprint `__ documents. Drafter is written in C++11 and needs to be compiled during installation. Because that can cause a lot of problems in some environments, there’s also pure JavaScript version of the parser, `drafter.js `__. Drafter.js is fully equivalent, but it can have slower performance. Therefore there’s `drafter-npm `__ package, which tries to compile the C++11 version of the parser and uses the JavaScript equivalent in case of failure. -```sh -$ npm install -g dredd --no-optional -``` +Dredd depends on the `drafter-npm `__ package. That’s the reason why you can see ``node-gyp`` errors and failures during the installation process, even though when it’s done, Dredd seems to normally work and correctly parses API Blueprint documents. -#### Troubleshooting the compilation +Forcing the JavaScript version +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you need the performance of the C++11 parser, but you are struggling to get it installed, it's usually because of the following problems: +The ``--no-optional`` option forces the JavaScript version of Drafter and avoids any compilation attempts when installing Dredd: -- **Your machine is missing a C++11 compiler.** See how to fix this on [Windows][Windows C++11] or [Travis CI][Travis CI C++11]. -- **npm was used with Python 3.** `node-gyp`, which performs the compilation, doesn't support Python 3. If your default Python is 3 (see `python --version`), [tell npm to use an older version][npm Python]. +.. code:: sh -### Supported Node.js Versions + $ npm install -g dredd --no-optional -Given the [table with LTS schedule](https://github.com/nodejs/Release), only versions marked as **Maintenance** or **Active** are supported, until their **Maintenance End**. The testing matrix of Dredd's CI builds must contain all currently supported versions and must not contain any unsupported versions. The same applies for the underlying libraries, such as [Dredd Transactions][] or [Gavel.js][]. +Troubleshooting the compilation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -In following files the latest supported Node.js version should be used: +If you need the performance of the C++11 parser, but you are struggling to get it installed, it’s usually because of the following problems: -- `appveyor.yml` - Windows CI builds -- `docs/install-node.sh` - ReadTheDocs docs builds +- **Your machine is missing a C++11 compiler.** See how to fix this on `Windows `__ or `Travis CI `__. +- **npm was used with Python 3.** ``node-gyp``, which performs the compilation, doesn’t support Python 3. If your default Python is 3 (see ``python --version``), `tell npm to use an older version `__. -### Dependencies +Supported Node.js Versions +~~~~~~~~~~~~~~~~~~~~~~~~~~ -New versions of dependencies are monitored by [David][] and/or [Greenkeeper][]. Security issues are monitored by [Snyk][]. +Given the `table with LTS schedule `__, only versions marked as **Maintenance** or **Active** are supported, until their **Maintenance End**. The testing matrix of Dredd’s CI builds must contain all currently supported versions and must not contain any unsupported versions. The same applies for the underlying libraries, such as `Dredd Transactions `__ or `Gavel.js `__. -Dependencies should not be specified in a loose way - only exact versions are allowed. Any changes to dependencies (version upgrades included) must be approved by Oracle before merged to `master`. Dredd maintainers take care of the approval. For transparency, PRs with pending dependency approval are labeled respectively. +In following files the latest supported Node.js version should be used: -The internal Oracle policies about dependencies pay attention mainly to licenses. Before adding a new dependency or upgrading an existing one try to [make sure](https://github.com/davglass/license-checker) the project and all its transitive dependencies feature standard permissive licenses, including correct copyright holders and license texts. +- ``appveyor.yml`` - Windows CI builds +- ``docs/install-node.sh`` - ReadTheDocs docs builds -### Versioning +Dependencies +~~~~~~~~~~~~ -Dredd follows [Semantic Versioning][]. To ensure certain stability of Dredd installations (e.g. in CI builds), users can pin their version. They can also use release tags: +New versions of dependencies are monitored by `David `__ and/or `Greenkeeper `__. Security issues are monitored by `Snyk `__. -- `npm install dredd` - Installs the latest published version including experimental pre-release versions. -- `npm install dredd@stable` - Skips experimental pre-release versions. +Dependencies should not be specified in a loose way - only exact versions are allowed. Any changes to dependencies (version upgrades included) must be approved by Oracle before merged to ``master``. Dredd maintainers take care of the approval. For transparency, PRs with pending dependency approval are labeled respectively. -When releasing, make sure you respect the tagging: +The internal Oracle policies about dependencies pay attention mainly to licenses. Before adding a new dependency or upgrading an existing one try to `make sure `__ the project and all its transitive dependencies feature standard permissive licenses, including correct copyright holders and license texts. -- To release pre-release, e.g. `42.1.0-pre.7`, use just `npm publish`. -- To release any other version, e.g. `42.1.0`, use `npm publish && npm dist-tag add dredd@42.1.0 stable`. +Versioning +~~~~~~~~~~ -Releasing process for standard versions is currently automated by [Semantic Release][]. Releasing process for pre-releases is not automated and needs to be done manually, ideally from a special git branch. +Dredd follows `Semantic Versioning `__. To ensure certain stability of Dredd installations (e.g. in CI builds), users can pin their version. They can also use release tags: -### Testing +- ``npm install dredd`` - Installs the latest published version including experimental pre-release versions. +- ``npm install dredd@stable`` - Skips experimental pre-release versions. -Use `npm test` to run all tests. Dredd uses [Mocha][] as a test framework. -It's default options are in the `test/mocha.opts` file. +When releasing, make sure you respect the tagging: -### Windows +- To release pre-release, e.g. ``42.1.0-pre.7``, use just ``npm publish``. +- To release any other version, e.g. ``42.1.0``, use ``npm publish && npm dist-tag add dredd@42.1.0 stable``. -Dredd is tested on the [AppVeyor][], a Windows-based CI. There are still [several known limitations][windows issues] when using Dredd on Windows, but the intention is to support it without any compromises. Any help with fixing problems on Windows is greatly appreciated! +Releasing process for standard versions is currently automated by `Semantic Release `__. Releasing process for pre-releases is not automated and needs to be done manually, ideally from a special git branch. -### Linting +Testing +~~~~~~~ -Dredd uses [eslint][] to lint the JavaScript codebase. We are using [Airbnb's styleguide](https://github.com/airbnb/javascript) -rules as a baseline with several rules disabled to allow us to have dirty -post-decaffeinate code temporarily. +Use ``npm test`` to run all tests. Dredd uses `Mocha `__ as a test framework. It’s default options are in the ``test/mocha.opts`` file. -Linter is optional for local development to make easy prototyping and work -with unpolished code, but it's enforced on CI level. It is recommended you -integrate [eslint][] with your favorite editor so you see violations -immediately during coding. +Windows +~~~~~~~ -### Changelog +Dredd is tested on the `AppVeyor `__, a Windows-based CI. There are still `several known limitations `__ when using Dredd on Windows, but the intention is to support it without any compromises. Any help with fixing problems on Windows is greatly appreciated! -Changelog is in form of [GitHub Releases][]. Currently it's automatically -generated by [Semantic Release][]. See [above](#sem-rel) to learn -about how it works. +Linting +~~~~~~~ -### Documentation +Dredd uses `eslint `__ to lint the JavaScript codebase. We are using `Airbnb’s styleguide `__ rules as a baseline with several rules disabled to allow us to have dirty post-decaffeinate code temporarily. -Dredd's documentation is written in [Markdown][] using [Sphinx][]. [ReadTheDocs][] is used to build and publish the documentation: +Linter is optional for local development to make easy prototyping and work with unpolished code, but it’s enforced on CI level. It is recommended you integrate `eslint `__ with your favorite editor so you see violations immediately during coding. -- [https://dredd.readthedocs.io](https://dredd.readthedocs.io) - preferred long URL -- [https://dredd.rtfd.io](https://dredd.rtfd.io) - preferred short URL +Changelog +~~~~~~~~~ -Source of the documentation can be found in the [docs][] directory. To render Dredd's documentation on your computer, you need Python 3 and Node.js installed. +Changelog is in form of `GitHub Releases `__. Currently it’s automatically generated by `Semantic Release `__. See `above <#sem-rel>`__ to learn about how it works. -#### Installation and Development +Documentation +~~~~~~~~~~~~~ -1. Make sure `node` is an executable and `npm install` has been done for the Dredd directory. Extensions to the docs are written in Node.js and Sphinx needs to have a way to execute them. -2. [Get Python 3](https://www.python.org/downloads/). On macOS, run `brew install python3`. [ReadTheDocs][] build the docs with Python 3.5, so make sure you have that or higher. -3. Create a [virtual environment](https://docs.python.org/3/library/venv.html) and activate it: +Dredd’s documentation is written in `Markdown `__ using `Sphinx `__. `ReadTheDocs `__ is used to build and publish the documentation: - ```sh - python3 -m venv ./venv - . ./env/bin/activate - ``` +- https://dredd.readthedocs.io - preferred long URL +- https://dredd.rtfd.io - preferred short URL -4. Install dependencies for the docs: `pip install -r docs/requirements.txt` +Source of the documentation can be found in the `docs `__ directory. To render Dredd’s documentation on your computer, you need Python 3 and Node.js installed. -Once installed, you may use following commands: +Installation and Development +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. Make sure ``node`` is an executable and ``npm install`` has been done for the Dredd directory. Extensions to the docs are written in Node.js and Sphinx needs to have a way to execute them. +2. `Get Python 3 `__. On macOS, run ``brew install python3``. `ReadTheDocs `__ build the docs with Python 3.5, so make sure you have that or higher. +3. Create a `virtual environment `__ and activate it: -- `npm run docs:build` - Builds the documentation -- `npm run docs:serve` - Runs live preview of the documentation on `http://127.0.0.1:8000` + .. code:: sh -#### Installation on ReadTheDocs + python3 -m venv ./venv + . ./env/bin/activate -The final documentation gets deployed on the [ReadTheDocs][]. The service, however, does not support Node.js. Therefore on ReadTheDocs, the `conf.py` configuration file for Sphinx runs `docs/install-node.sh`, which installs Node.js locally, using [nvm][]. +4. Install dependencies for the docs: ``pip install -r docs/requirements.txt`` -#### ToC and Markdown +Once installed, you may use following commands: -Traditionally, Sphinx only supported the [reStructuredText][] format. Thanks to the [recommonmark][] project it's possible to use also [Markdown][], _almost_ as a format native to Sphinx. Dredd's docs are using the [AutoStructify][] extension to be able to specify _toctree_ and other stuff specific to reStructuredText. The ToC is generated from the _Contents_ section in the `docs/index.md` file. +- ``npm run docs:build`` - Builds the documentation +- ``npm run docs:serve`` - Runs live preview of the documentation on ``http://127.0.0.1:8000`` -[recommonmark]: https://github.com/rtfd/recommonmark -[AutoStructify]: https://recommonmark.readthedocs.io/en/latest/auto_structify.html +Installation on ReadTheDocs +^^^^^^^^^^^^^^^^^^^^^^^^^^^ -#### Node.js Extensions +The final documentation gets deployed on the `ReadTheDocs `__. The service, however, does not support Node.js. Therefore on ReadTheDocs, the ``conf.py`` configuration file for Sphinx runs ``docs/install-node.sh``, which installs Node.js locally, using `nvm `__. -There are some extensions hooked into the build process of [Sphinx][], modifying how the documents are processed. They're written in Node.js, because: +ToC and Markdown +^^^^^^^^^^^^^^^^ -- It's better to have them in the same language as Dredd. -- This way they're able to import source files (e.g. `src/options.js`). +Traditionally, Sphinx only supported the `reStructuredText `__ format. Thanks to the `recommonmark `__ project it’s possible to use also `Markdown `__, *almost* as a format native to Sphinx. Dredd’s docs are using the `AutoStructify `__ extension to be able to specify *toctree* and other stuff specific to reStructuredText. The ToC is generated from the *Contents* section in the ``docs/index.md`` file. - +Node.js Extensions +^^^^^^^^^^^^^^^^^^ -By default, [Hercule][] is attached as an extension, which means you can use the :\[Title](link.md) syntax for including other Markdown files. All other extensions are custom and are automatically loaded from the `docs/_extensions` directory. +There are some extensions hooked into the build process of `Sphinx `__, modifying how the documents are processed. They’re written in Node.js, because: -The extension is expected to be a `.js` or `.coffee` script file, which takes `docname` as an argument, reads the Markdown document from `stdin`, modifies it, and then prints it to `stdout`. When in need of templating, extensions are expected to use the bundled `ect` templating engine. +- It’s better to have them in the same language as Dredd. +- This way they’re able to import source files (e.g. ``src/options.js``). -[Hercule]: https://www.npmjs.com/package/hercule +By default, `Hercule `__ is attached as an extension, which means you can use the ``:[Title](link.md)`` syntax for including other Markdown files. All other extensions are custom and are automatically loaded from the ``docs/_extensions`` directory. -#### Local References +The extension is expected to be a ``.js`` or ``.coffee`` script file, which takes ``docname`` as an argument, reads the Markdown document from ``stdin``, modifies it, and then prints it to ``stdout``. When in need of templating, extensions are expected to use the bundled ``ect`` templating engine. -Currently the [recommonmark][] project has still some limitations in how references to local files work. That's why Dredd's docs have a custom implementation, which also checks whether the destination exists and fails the build in case of broken link. You can use following syntax: +Local References +^^^^^^^^^^^^^^^^ -- `[Title](link.md)` to link to other documents -- `[Title](link.md#section)` to link to sections of other documents +Currently the `recommonmark `__ project has still some limitations in how references to local files work. That’s why Dredd’s docs have a custom implementation, which also checks whether the destination exists and fails the build in case of broken link. You can use following syntax: -Any `id` HTML attributes generated for headings or manual `` anchors are considered as valid targets. While this feels very natural for a seasoned writer of Markdown, mind that it is much more error prone then [reStructuredText][]'s references. +- ``[Title](link.md)`` to link to other documents +- ``[Title](link.md#section)`` to link to sections of other documents -#### Redirects +Any ``id`` HTML attributes generated for headings or manual ```` anchors are considered as valid targets. While this feels very natural for a seasoned writer of Markdown, mind that it is much more error prone then `reStructuredText `__\ ’s references. -Redirects are documented in the `docs/redirects.yml` file. They need to be manually set in the [ReadTheDocs administration](https://readthedocs.org/dashboard/dredd/redirects/). It's up to Dredd maintainers to keep the list in sync with reality. +Redirects +^^^^^^^^^ -You can use the [rtd-redirects](https://github.com/honzajavorek/rtd-redirects) tool to programmatically upload the redirects from `docs/redirects.yml` to ReadTheDocs admin interface. +Redirects are documented in the ``docs/redirects.yml`` file. They need to be manually set in the `ReadTheDocs administration `__. It’s up to Dredd maintainers to keep the list in sync with reality. -#### Symlinked Contributing Docs +You can use the `rtd-redirects `__ tool to programmatically upload the redirects from ``docs/redirects.yml`` to ReadTheDocs admin interface. -The `docs/contributing.md` file is a [symbolic link][] to the -`.github/CONTRIBUTING.md` file, where the actual content lives. -This is to be able to serve the same content also as -[GitHub contributing guidelines][] when someone opens a Pull Request. +Symlinked Contributing Docs +^^^^^^^^^^^^^^^^^^^^^^^^^^^ -[symbolic link]: https://en.wikipedia.org/wiki/Symbolic_link -[GitHub contributing guidelines]: https://blog.github.com/2012-09-17-contributing-guidelines/ +The ``docs/contributing.md`` file is a `symbolic link `__ to the ``.github/CONTRIBUTING.md`` file, where the actual content lives. This is to be able to serve the same content also as `GitHub contributing guidelines `__ when someone opens a Pull Request. -### Coverage +Coverage +~~~~~~~~ -Dredd strives for as much test coverage as possible. [Coveralls][] help us to -monitor how successful we are in achieving the goal. If a Pull Request -introduces drop in coverage, it won't be accepted unless the author or reviewer -provides a good reason why an exception should be made. +Dredd strives for as much test coverage as possible. `Coveralls `__ help us to monitor how successful we are in achieving the goal. If a Pull Request introduces drop in coverage, it won’t be accepted unless the author or reviewer provides a good reason why an exception should be made. The Travis CI build uses following commands to deliver coverage reports: -- `npm run test:coverage` - Tests Dredd and creates the `./coverage/lcov.info` file -- `npm run coveralls` - Uploads the `./coverage/lcov.info` file to Coveralls +- ``npm run test:coverage`` - Tests Dredd and creates the ``./coverage/lcov.info`` file +- ``npm run coveralls`` - Uploads the ``./coverage/lcov.info`` file to Coveralls The first mentioned command goes like this: -1. [istanbul][] is used to instrument and cover the JavaScript code. -2. We run the tests on the instrumented code using Mocha with a special lcov reporter, - which gives us information about which lines were executed in a standard lcov format. -3. Because some integration tests execute the `bin/dredd` script in - a subprocess, we collect the coverage stats also in this file. The results - are appended to a dedicated lcov file. -4. All lcov files are then merged into one using [lcov-result-merger][] - and sent to Coveralls. +1. `istanbul `__ is used to instrument and cover the JavaScript code. +2. We run the tests on the instrumented code using Mocha with a special lcov reporter, which gives us information about which lines were executed in a standard lcov format. +3. Because some integration tests execute the ``bin/dredd`` script in a subprocess, we collect the coverage stats also in this file. The results are appended to a dedicated lcov file. +4. All lcov files are then merged into one using `lcov-result-merger `__ and sent to Coveralls. -#### Notes +Notes +^^^^^ -- Hand-made combined Mocha reporter is used to achieve running tests and collecting - coverage at the same time. -- Both Dredd code and the combined reporter decide whether to collect coverage - or not according to contents of the `COVERAGE_DIR` environment variable, which - sets the directory for temporary LCOV files created during coverage collection. - (If set, collecting takes place.) +- Hand-made combined Mocha reporter is used to achieve running tests and collecting coverage at the same time. +- Both Dredd code and the combined reporter decide whether to collect coverage or not according to contents of the ``COVERAGE_DIR`` environment variable, which sets the directory for temporary LCOV files created during coverage collection. (If set, collecting takes place.) +.. _hacking-apiary-reporter: -### Hacking Apiary Reporter +Hacking Apiary Reporter +~~~~~~~~~~~~~~~~~~~~~~~ -If you want to build something on top of the Apiary Reporter, note that it uses a public API described in following documents: +If you want to build something on top of the Apiary Reporter, note that +it uses a public API described in following documents: -- [Apiary Tests API for anonymous test reports][] -- [Apiary Tests API for authenticated test reports][] +- `Apiary Tests API for anonymous test reports `__ +- `Apiary Tests API for authenticated test reports `__ Following data are sent over the wire to Apiary: -- [Apiary Reporter Test Data](data-structures.md#apiary-reporter-test-data) +- `Apiary Reporter Test Data `__ There is also one environment variable you could find useful: -- `APIARY_API_URL='https://api.apiary.io'` - Allows to override host of the Apiary Tests API. - -### Misc Tips - -- When using long CLI options in tests or documentation, please always use the notation with `=` - wherever possible. For example, use `--path=/dev/null`, not `--path /dev/null`. - While both should work, the version with `=` feels - more like standard GNU-style long options and it makes arrays of arguments for `spawn` more readable. -- Using `127.0.0.1` (in code, tests, documentation) is preferred over `localhost` (see [#586](https://github.com/apiaryio/dredd/issues/586)). -- Prefer explicit `
` tags instead of [two spaces][md-two-spaces] at the end of the line when writing documentation in Markdown. - - -[Apiary]: https://apiary.io/ -[Dredd Transactions]: https://github.com/apiaryio/dredd-transactions -[Gavel.js]: https://github.com/apiaryio/gavel.js/ - -[Semantic Versioning]: https://semver.org/ -[JavaScript (ES2015+)]: https://tc39.github.io/ecma262/ -[eslint]: https://eslint.org/ -[CoffeeScript]: https://coffeescript.org -[Coveralls]: https://coveralls.io/github/apiaryio/dredd -[istanbul]: https://github.com/gotwarlost/istanbul -[lcov-result-merger]: https://github.com/mweibel/lcov-result-merger -[Markdown]: https://en.wikipedia.org/wiki/Markdown -[Sphinx]: http://www.sphinx-doc.org/ -[ReadTheDocs]: https://readthedocs.org/ -[test coverage]: https://coveralls.io/github/apiaryio/dredd -[Mocha]: https://mochajs.org/ -[Semantic Release]: https://github.com/semantic-release/semantic-release -[Conventional Changelog]: https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#user-content--git-commit-guidelines -[Commitizen CLI]: https://github.com/commitizen/cz-cli -[md-two-spaces]: https://daringfireball.net/projects/markdown/syntax#p -[AppVeyor]: https://www.appveyor.com/ -[nvm]: https://github.com/creationix/nvm -[reStructuredText]: http://www.sphinx-doc.org/en/stable/rest.html -[David]: https://david-dm.org/apiaryio/dredd -[Greenkeeper]: https://greenkeeper.io/ -[Snyk]: https://snyk.io/test/npm/dredd - -[Drafter]: https://github.com/apiaryio/drafter -[API Blueprint]: https://apiblueprint.org/ -[drafter.js]: https://github.com/apiaryio/drafter.js -[drafter-npm]: https://github.com/apiaryio/drafter-npm/ -[Windows C++11]: https://github.com/apiaryio/drafter/wiki/Building-on-Windows -[Travis CI C++11]: https://github.com/apiaryio/protagonist/blob/master/.travis.yml -[npm Python]: http://stackoverflow.com/a/22433804/325365 - -[existing commits]: https://github.com/apiaryio/dredd/commits/master -[docs]: https://github.com/apiaryio/dredd/tree/master/docs -[GitHub Releases]: https://github.com/apiaryio/dredd/releases - -[upstream repository]: https://github.com/apiaryio/dredd -[issues]: https://github.com/apiaryio/dredd/issues -[windows issues]: https://github.com/apiaryio/dredd/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3AWindows%20 - -[Apiary Tests API for anonymous test reports]: https://github.com/apiaryio/dredd/blob/master/ApiaryReportingApiAnonymous.apib -[Apiary Tests API for authenticated test reports]: https://github.com/apiaryio/dredd/blob/master/ApiaryReportingApi.apib +- ``APIARY_API_URL='https://api.apiary.io'`` - Allows to override host of the Apiary Tests API. + +Misc Tips +~~~~~~~~~ + +- When using long CLI options in tests or documentation, please always use the notation with ``=`` wherever possible. For example, use ``--path=/dev/null``, not ``--path /dev/null``. While both should work, the version with ``=`` feels more like standard GNU-style long options and it makes arrays of arguments for ``spawn`` more readable. +- Using ``127.0.0.1`` (in code, tests, documentation) is preferred over ``localhost`` (see `#586 `__). +- Prefer explicit ``
`` tags instead of `two spaces `__ at the end of the line when writing documentation in Markdown. diff --git a/docs/contributing.rst b/docs/contributing.rst index e6afed186..43a190a8c 120000 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -1 +1 @@ -../.github/CONTRIBUTING.md \ No newline at end of file +../.github/CONTRIBUTING.rst \ No newline at end of file diff --git a/docs/data-structures.rst b/docs/data-structures.rst index 524d38aa2..5b18b5350 100644 --- a/docs/data-structures.rst +++ b/docs/data-structures.rst @@ -1,206 +1,229 @@ -# Data Structures - -Documentation of various data structures in both [Gavel.js][] and Dredd. [MSON notation](https://github.com/apiaryio/mson) is used to describe the data structures. - - -## Transaction (object) - -Transaction object is passed as a first argument to [hook functions](hooks.md) and is one of the main public interfaces in Dredd. - -- id: `GET (200) /greetings` - identifier for this transaction -- name: `./api-description.apib > My API > Greetings > Hello, world! > Retrieve Message > Example 2` (string) - reference to the transaction definition in the original API description document (see also [Dredd Transactions][]) -- origin (object) - reference to the transaction definition in the original API description document (see also [Dredd Transactions][]) - - filename: `./api-description.apib` (string) - - apiName: `My Api` (string) - - resourceGroupName: `Greetings` (string) - - resourceName: `Hello, world!` (string) - - actionName: `Retrieve Message` (string) - - exampleName: `Example 2` (string) -- host: `127.0.0.1` (string) - server hostname without port number -- port: `3000` (number) - server port number -- protocol: `https:` (enum[string]) - server protocol - - `https:` (string) - - `http:` (string) -- fullPath: `/message` (string) - expanded [URI Template][] with parameters (if any) used for the HTTP request Dredd performs to the tested server -- request (object) - the HTTP request Dredd performs to the tested server, taken from the API description - - body: `Hello world!\n` (string) - - bodyEncoding (enum) - can be manually set in [hooks](hooks.md) - - `utf-8` (string) - indicates `body` contains a textual content encoded in UTF-8 - - `base64` (string) - indicates `body` contains a binary content encoded in Base64 - - headers (object) - keys are HTTP header names, values are HTTP header contents - - uri: `/message` (string) - request URI as it was written in API description - - method: `POST` (string) -- expected (object) - the HTTP response Dredd expects to get from the tested server - - statusCode: `200` (string) - - headers (object) - keys are HTTP header names, values are HTTP header contents - - body (string) - - bodySchema (object) - JSON Schema of the response body -- real (object) - the HTTP response Dredd gets from the tested server (present only in `after` hooks) - - statusCode: `200` (string) - - headers (object) - keys are HTTP header names, values are HTTP header contents - - body (string) - - bodyEncoding (enum) - - `utf-8` (string) - indicates `body` contains a textual content encoded in UTF-8 - - `base64` (string) - indicates `body` contains a binary content encoded in Base64 -- skip: `false` (boolean) - can be set to `true` and the transaction will be skipped -- fail: `false` (enum) - can be set to `true` or string and the transaction will fail - - (string) - failure message with details why the transaction failed - - (boolean) -- test ([Transaction Test][]) - test data passed to Dredd's reporters -- results ([Transaction Results][]) - testing results - - -## Transaction Test (object) - -- start (Date) - start of the test -- end (Date) - end of the test -- duration (number) - duration of the test in milliseconds -- startedAt (number) - unix timestamp, [transaction][].startedAt -- title (string) - [transaction][].id -- request (object) - [transaction][].request -- actual (object) - [transaction][].real -- expected (object) - [transaction][].expected -- status (enum) - whether the validation passed or not, defaults to empty string - - `pass` (string) - - `fail` (string) - - `skip` (string) -- message (string) - concatenation of all messages from all [Gavel Errors](#gavel-error) in `results` or Dredd's custom message (e.g. "failed in before hook") -- results (Dredd's [transaction][].results) -- valid (boolean) -- origin (object) - [transaction][].origin - - -## Transaction Results (object) - -This is a cousin of the [Gavel Validation Result](#gavel-validation-result). - -- general (object) - contains Dredd's custom messages (e.g. "test was skipped"), formatted the same way like those from Gavel - - results (array[[Gavel Error][]]) -- statusCode ([Gavel Validator Output][]) -- headers ([Gavel Validator Output][]) -- body ([Gavel Validator Output][]) - - -## Gavel Validation Result (object) - -Can be seen also [here](https://relishapp.com/apiary/gavel/docs/javascript/request-async-api#validate). - -- statusCode ([Gavel Validator Output][]) -- headers ([Gavel Validator Output][]) -- body ([Gavel Validator Output][]) -- version (string) - version number of the Gavel Validation Result structure - - -## Gavel Validator Output (object) - -Can be seen also [here](https://relishapp.com/apiary/gavel/docs/data-validators-and-output-format#validators-output-format). - -- results (array[[Gavel Error][]]) -- realType (string) - media type -- expectedType (string) - media type -- validator (string) - validator class name -- rawData (enum) - raw output of the validator, has different structure for every validator and is saved and used in Apiary to render graphical diff by [gavel2html](https://github.com/apiaryio/gavel2html/) - - ([JsonSchema Validation Result][]) - - ([TextDiff Validation Result][]) - - -## JsonSchema Validation Result (object) - -The validation error is based on format provided by [Amanda][] and is also "documented" [here](https://github.com/apiaryio/Amanda/blob/master/docs/json/objects/error.md). Although for validation of draft4 JSON Schema Gavel uses [tv4][] library, the output then gets reshaped into the structure of Amanda's errors. - -This validation result is returned not only when validating against [JSON Schema][], but also when validating against JSON example or when validating HTTP headers. - -- length: `0` (number, default) - number of error properties -- errorMessages (object) - doesn't seem to ever contain anything or be used for anything -- *0* (object) - validation error details, property is always a string containing a number (0, 1, 2, ...) - - property (array[string]) - path to the problematic property in format of [json-pointer's `parse()` output](https://github.com/manuelstofer/json-pointer#user-content-parsestr) - - propertyValue (mixed) - real value of the problematic property (can be also `undefined` etc.) - - attributeName: `enum`, `required` (string) - name of the relevant JSON Schema attribute, which triggered the error - - attributeValue (mixed) - value of the relevant JSON Schema attribute, which triggered the error - - message (string) - error message (in case of tv4 it contains [JSON Pointer][] to the problematic property and for both Amanda and tv4 it can directly mention property names and/or values) - - validator: `enum` (string) - the same as `attributeName` - - validatorName: `error`, `enum` (string) - the same as `attributeName` - - validatorValue (mixed) - the same as `attributeValue` - - -## TextDiff Validation Result (string) - -Block of text which looks extremely similar to the standard GNU diff/patch format. Result of the [`patch_toText()` function of the `google-diff-match-patch` library](https://github.com/google/diff-match-patch/wiki/API#user-content-patch_totextpatches--text). - - -## Gavel Error (object) - -Can also be seen as part of Gavel Validator Output [here](https://relishapp.com/apiary/gavel/docs/data-validators-and-output-format#validators-output-format). - -- pointer (string) - [JSON Pointer][] path -- severity (string) - severity of the error -- message (string) - error message - - -## Apiary Reporter Test Data (object) - -- testRunId (string) - ID of the [test run](#apiary-test-run), recieved from Apiary -- origin (object) - [test][].origin -- duration (number) - duration of the test in milliseconds -- result (string) - [test][].status -- startedAt (number) - [test][].startedAt -- resultData (object) - - request (object) - [test][].request - - realResponse (object) - [test][].actual - - expectedResponse (object) - [test][].expected - - result ([Transaction Results][]) - [test][].results - -## Internal Apiary Data Structures - -These are private data structures used in Apiary internally and they are documented incompletely. They're present in this document just to provide better insight on what and how Apiary internally saves. It is closely related to what you can see in documentation for [Apiary Tests API for anonymous test reports][] and [Apiary Tests API for authenticated test reports][]. - - -### Apiary Test Run (object) - -Also known as `stats` in Dredd's code. - -- result - - tests: `0` (number, default) - total number of tests - - failures: `0` (number, default) - - errors: `0` (number, default) - - passes: `0` (number, default) - - skipped: `0` (number, default) - - start: `0` (number, default) - - end: `0` (number, default) - - duration: `0` (number, default) - - -### Apiary Test Step (object) - -- resultData - - request (object) - [test][].request - - realResponse (object) - [test][].actual - - expectedResponse (object) - [test][].expected - - result ([Transaction Results][]) - [test][].results - - -[Transaction]: #transaction -[Transaction Test]: #transaction-test -[Transaction Results]: #transaction-results -[Gavel Validation Result]: #gavel-validation-result -[Gavel Validator Output]: #gavel-validator-output -[JsonSchema Validation Result]: #jsonschema-validation-result -[TextDiff Validation Result]: #textdiff-validation-result -[Gavel Error]: #gavel-error -[Apiary Reporter Test Data]: #apiary-reporter-test-data -[Apiary Test Run]: #apiary-test-run-result -[Apiary Test Step]: #apiary-test-step-resultdata - -[transaction]: #transaction -[test]: #transaction-test - -[Amanda]: https://github.com/apiaryio/Amanda -[tv4]: https://github.com/geraintluff/tv4 -[Gavel.js]: https://github.com/apiaryio/gavel.js -[URI Template]: https://tools.ietf.org/html/rfc6570 -[JSON Pointer]: https://tools.ietf.org/html/rfc6901 -[JSON Schema]: http://json-schema.org/ - -[Apiary Tests API for anonymous test reports]: https://github.com/apiaryio/dredd/blob/master/ApiaryReportingApiAnonymous.apib -[Apiary Tests API for authenticated test reports]: https://github.com/apiaryio/dredd/blob/master/ApiaryReportingApi.apib -[Dredd Transactions]: https://github.com/apiaryio/dredd-transactions#user-content-data-structures +.. _data-structures: + +Data Structures +=============== + +Documentation of various data structures in both `Gavel.js `__ and Dredd. `MSON notation `__ is used to describe the data structures. + +.. _transaction: + +Transaction (object) +-------------------- + +Transaction object is passed as a first argument to :ref:`hook functions ` and is one of the main public interfaces in Dredd. + +- id: ``GET (200) /greetings`` - identifier for this transaction +- name: ``./api-description.apib > My API > Greetings > Hello, world! > Retrieve Message > Example 2`` (string) - reference to the transaction definition in the original API description document (see also `Dredd Transactions `__) +- origin (object) - reference to the transaction definition in the original API description document (see also `Dredd Transactions `__) + + - filename: ``./api-description.apib`` (string) + - apiName: ``My Api`` (string) + - resourceGroupName: ``Greetings`` (string) + - resourceName: ``Hello, world!`` (string) + - actionName: ``Retrieve Message`` (string) + - exampleName: ``Example 2`` (string) + +- host: ``127.0.0.1`` (string) - server hostname without port number +- port: ``3000`` (number) - server port number +- protocol: ``https:`` (enum[string]) - server protocol + + - ``https:`` (string) + - ``http:`` (string) + +- fullPath: ``/message`` (string) - expanded `URI Template `__ with parameters (if any) used for the HTTP request Dredd performs to the tested server +- request (object) - the HTTP request Dredd performs to the tested server, taken from the API description + + - body: ``Hello world!\n`` (string) + - bodyEncoding (enum) - can be manually set in :ref:`hooks ` + + - ``utf-8`` (string) - indicates ``body`` contains a textual content encoded in UTF-8 + - ``base64`` (string) - indicates ``body`` contains a binary content encoded in Base64 + + - headers (object) - keys are HTTP header names, values are HTTP header contents + - uri: ``/message`` (string) - request URI as it was written in API description + - method: ``POST`` (string) + +- expected (object) - the HTTP response Dredd expects to get from the tested server + + - statusCode: ``200`` (string) + - headers (object) - keys are HTTP header names, values are HTTP header contents + - body (string) + - bodySchema (object) - JSON Schema of the response body + +- real (object) - the HTTP response Dredd gets from the tested server (present only in ``after`` hooks) + + - statusCode: ``200`` (string) + - headers (object) - keys are HTTP header names, values are HTTP header contents + - body (string) + - bodyEncoding (enum) + + - ``utf-8`` (string) - indicates ``body`` contains a textual content encoded in UTF-8 + - ``base64`` (string) - indicates ``body`` contains a binary content encoded in Base64 + +- skip: ``false`` (boolean) - can be set to ``true`` and the transaction will be skipped +- fail: ``false`` (enum) - can be set to ``true`` or string and the transaction will fail + + - (string) - failure message with details why the transaction failed + - (boolean) + +- test (:ref:`transaction-test`) - test data passed to Dredd’s reporters +- results (:ref:`transaction-results`) - testing results + +.. _transaction-test: + +Transaction Test (object) +------------------------- + +- start (Date) - start of the test +- end (Date) - end of the test +- duration (number) - duration of the test in milliseconds +- startedAt (number) - unix timestamp, :ref:`transaction `.startedAt +- title (string) - :ref:`transaction `.id +- request (object) - :ref:`transaction `.request +- actual (object) - :ref:`transaction `.real +- expected (object) - :ref:`transaction `.expected +- status (enum) - whether the validation passed or not, defaults to empty string + + - ``pass`` (string) + - ``fail`` (string) + - ``skip`` (string) + +- message (string) - concatenation of all messages from all :ref:`gavel-error` in ``results`` or Dredd’s custom message (e.g. “failed in before hook”) +- results (Dredd’s :ref:`transaction `.results) +- valid (boolean) +- origin (object) - :ref:`transaction `.origin + +.. _transaction-results: + +Transaction Results (object) +---------------------------- + +This is a cousin of the :ref:`gavel-validation-result`. + +- general (object) - contains Dredd’s custom messages (e.g. “test was skipped”), formatted the same way like those from Gavel + + - results (array[:ref:`gavel-error`]) + +- statusCode (:ref:`gavel-validator-output`) +- headers (:ref:`gavel-validator-output`) +- body (:ref:`gavel-validator-output`) + +.. _gavel-validation-result: + +Gavel Validation Result (object) +-------------------------------- + +Can be seen also `here `__. + +- statusCode (:ref:`gavel-validator-output`) +- headers (:ref:`gavel-validator-output`) +- body (:ref:`gavel-validator-output`) +- version (string) - version number of the Gavel Validation Result structure + +.. _gavel-validator-output: + +Gavel Validator Output (object) +------------------------------- + +Can be seen also `here `__. + +- results (array[:ref:`gavel-error`]) +- realType (string) - media type +- expectedType (string) - media type +- validator (string) - validator class name +- rawData (enum) - raw output of the validator, has different structure for every validator and is saved and used in Apiary to render graphical diff by `gavel2html `__ + + - (:ref:`jsonschema-validation-result`) + - (:ref:`textdiff-validation-result`) + +.. _jsonschema-validation-result: + +JsonSchema Validation Result (object) +------------------------------------- + +The validation error is based on format provided by `Amanda `__ and is also “documented” `here `__. Although for validation of draft4 JSON Schema Gavel uses `tv4 `__ library, the output then gets reshaped into the structure of Amanda’s errors. + +This validation result is returned not only when validating against `JSON Schema `__, but also when validating against JSON example or when validating HTTP headers. + +- length: ``0`` (number, default) - number of error properties +- errorMessages (object) - doesn’t seem to ever contain anything or be used for anything +- *0* (object) - validation error details, property is always a string containing a number (0, 1, 2, …) + + - property (array[string]) - path to the problematic property in format of `json-pointer’s ``parse()`` output `__ + - propertyValue (mixed) - real value of the problematic property (can be also ``undefined`` etc.) + - attributeName: ``enum``, ``required`` (string) - name of the relevant JSON Schema attribute, which triggered the error + - attributeValue (mixed) - value of the relevant JSON Schema attribute, which triggered the error + - message (string) - error message (in case of tv4 it contains `JSON Pointer `__ to the problematic property and for both Amanda and tv4 it can directly mention property names and/or values) + - validator: ``enum`` (string) - the same as ``attributeName`` + - validatorName: ``error``, ``enum`` (string) - the same as ``attributeName`` + - validatorValue (mixed) - the same as ``attributeValue`` + +.. _textdiff-validation-result: + +TextDiff Validation Result (string) +----------------------------------- + +Block of text which looks extremely similar to the standard GNU diff/patch format. Result of the ``patch_toText()`` function of the ``google-diff-match-patch`` library (`docs `__). + +.. _gavel-error: + +Gavel Error (object) +-------------------- + +Can also be seen as part of Gavel Validator Output `here `__. + +- pointer (string) - `JSON Pointer `__ path +- severity (string) - severity of the error +- message (string) - error message + +.. _apiary-reporter-test-data: + +Apiary Reporter Test Data (object) +---------------------------------- + +- testRunId (string) - ID of the :ref:`test run `, recieved from Apiary +- origin (object) - :ref:`test `.origin +- duration (number) - duration of the test in milliseconds +- result (string) - :ref:`test `.status +- startedAt (number) - :ref:`test `.startedAt +- resultData (object) + + - request (object) - :ref:`test `.request + - realResponse (object) - :ref:`test `.actual + - expectedResponse (object) - :ref:`test `.expected + - result (:ref:`transaction-results`) - :ref:`test `.results + +Internal Apiary Data Structures +------------------------------- + +These are private data structures used in Apiary internally and they are documented incompletely. They’re present in this document just to provide better insight on what and how Apiary internally saves. It is closely related to what you can see in documentation for `Apiary Tests API for anonymous test reports `__ and `Apiary Tests API for authenticated test reports `__. + +.. _apiary-test-run: + +Apiary Test Run (object) +~~~~~~~~~~~~~~~~~~~~~~~~ + +Also known as ``stats`` in Dredd’s code. + +- result + + - tests: ``0`` (number, default) - total number of tests + - failures: ``0`` (number, default) + - errors: ``0`` (number, default) + - passes: ``0`` (number, default) + - skipped: ``0`` (number, default) + - start: ``0`` (number, default) + - end: ``0`` (number, default) + - duration: ``0`` (number, default) + +.. _apiary-test-step: + +Apiary Test Step (object) +~~~~~~~~~~~~~~~~~~~~~~~~~ + +- resultData + + - request (object) - :ref:`test `.request + - realResponse (object) - :ref:`test `.actual + - expectedResponse (object) - :ref:`test `.expected + - result (:ref:`transaction-results`) - :ref:`test `.results diff --git a/docs/hooks-go.rst b/docs/hooks-go.rst index a4f13cf2c..da7b3b001 100644 --- a/docs/hooks-go.rst +++ b/docs/hooks-go.rst @@ -1,203 +1,221 @@ -# Writing Dredd Hooks In Go +.. _hooks-go: -[![Godoc Reference](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](https://godoc.org/github.com/snikch/goodman) +Writing Dredd Hooks In Go +========================= -[GitHub repository](https://github.com/snikch/goodman) +|Godoc Reference| -Go hooks are using [Dredd's hooks handler socket interface](hooks-new-language.md). For using Go hooks in Dredd you have to have [Dredd already installed](quickstart.md). The Go library is called `goodman`. +`GitHub repository `__ -## Installation +Go hooks are using :ref:`Dredd’s hooks handler socket interface `. For using Go hooks in Dredd you have to have :ref:`Dredd already installed `. The Go library is called ``goodman``. -``` -$ go get github.com/snikch/goodman/cmd/goodman -``` +Installation +------------ -## Usage +:: -Using Dredd with Go is slightly different to other languages, as a binary needs to be compiled for execution. The --hookfiles flags should point to compiled hook binaries. See below for an example hooks.go file to get an idea of what the source file behind the go binary would look like. + $ go get github.com/snikch/goodman/cmd/goodman -``` -$ dredd apiary.apib http://127.0.0.1:3000 --server=./go-lang-web-server-to-test --language=go --hookfiles=./hook-file-binary -``` +Usage +----- -## API Reference +Using Dredd with Go is slightly different to other languages, as a binary needs to be compiled for execution. The –hookfiles flags should point to compiled hook binaries. See below for an example hooks.go file to get an idea of what the source file behind the go binary would look like. -In order to get a general idea of how the Go Hooks work, the main executable from the package $GOPATH/bin/goodman is an HTTP Server that Dredd communicates with and an RPC client. Each hookfile then acts as a corresponding RPC server. So when Dredd notifies the Hooks server what transaction event is occuring the hooks server will execute all registered hooks on each of the hookfiles RPC servers. +:: -You’ll need to know a few things about the `Server` type in the hooks package. + $ dredd apiary.apib http://127.0.0.1:3000 --server=./go-lang-web-server-to-test --language=go --hookfiles=./hook-file-binary -1. The `hooks.Server` type is how you can define event callbacks such as `beforeEach`, `afterAll`, etc. +API Reference +------------- -2. To get a `hooks.Server` struct you must do the following +In order to get a general idea of how the Go Hooks work, the main executable from the package $GOPATH/bin/goodman is an HTTP Server that Dredd communicates with and an RPC client. Each hookfile then acts as a corresponding RPC server. So when Dredd notifies the Hooks server what transaction event is occuring the hooks server will execute all registered hooks on each of the hookfiles RPC servers. -```go -package main +You’ll need to know a few things about the ``Server`` type in the hooks package. -import ( - "github.com/snikch/goodman/hooks" - trans "github.com/snikch/goodman/transaction" -) +1. The ``hooks.Server`` type is how you can define event callbacks such as ``beforeEach``, ``afterAll``, etc. -func main() { - h := hooks.NewHooks() - server := hooks.NewServer(hooks.NewHooksRunner(h)) +2. To get a ``hooks.Server`` struct you must do the following - // Define all your event callbacks here +.. code:: go - // server.Serve() will block and allow the goodman server to run your defined - // event callbacks - server.Serve() - // You must close the listener at end of main() - defer server.Listener.Close() -} -``` + package main -2. Callbacks receive a `Transaction` instance, or an array of them + import ( + "github.com/snikch/goodman/hooks" + trans "github.com/snikch/goodman/transaction" + ) -3. A `Server` will run your `Runner` and handle receiving events on the dredd socket. + func main() { + h := hooks.NewHooks() + server := hooks.NewServer(hooks.NewHooksRunner(h)) -### Runner Callback Events + // Define all your event callbacks here -The `Runner` type has the following callback methods. + // server.Serve() will block and allow the goodman server to run your defined + // event callbacks + server.Serve() + // You must close the listener at end of main() + defer server.Listener.Close() + } -1. `BeforeEach`, `BeforeEachValidation`, `AfterEach` - - accepts a function as a first argument passing a [Transaction object](data-structures.md#transaction) as a first argument +2. Callbacks receive a ``Transaction`` instance, or an array of them -2. `Before`, `BeforeValidation`, `After` - - accepts [transaction name](hooks.md#getting-transaction-names) as a first argument - - accepts a function as a second argument passing a [Transaction object](data-structures.md#transaction) as a first argument of it +3. A ``Server`` will run your ``Runner`` and handle receiving events on the dredd socket. -3. `BeforeAll`, `AfterAll` - - accepts a function as a first argument passing a Slice of [Transaction objects](data-structures.md#transaction) as a first argument +Runner Callback Events +~~~~~~~~~~~~~~~~~~~~~~ -Refer to [Dredd execution lifecycle](how-it-works.md#execution-life-cycle) to find when each hook callback is executed. +The ``Runner`` type has the following callback methods. -### Using the Go API +1. ``BeforeEach``, ``BeforeEachValidation``, ``AfterEach`` + + - accepts a function as a first argument passing a :ref:`Transaction object ` as a first argument + +2. ``Before``, ``BeforeValidation``, ``After`` + + - accepts :ref:`transaction name ` as a first argument + - accepts a function as a second argument passing a :ref:`Transaction object ` as a first argument of it + +3. ``BeforeAll``, ``AfterAll`` + + - accepts a function as a first argument passing a Slice of :ref:`Transaction objects ` as a first argument + +Refer to :ref:`Dredd execution lifecycle ` to find when each hook callback is executed. + +Using the Go API +~~~~~~~~~~~~~~~~ Example usage of all methods. -```go -package main - -import ( - "fmt" - - "github.com/snikch/goodman/hooks" - trans "github.com/snikch/goodman/transaction" -) - -func main() { - h := hooks.NewHooks() - server := hooks.NewServer(hooks.NewHooksRunner(h)) - h.BeforeAll(func(t []*trans.Transaction) { - fmt.Println("before all modification") - }) - h.BeforeEach(func(t *trans.Transaction) { - fmt.Println("before each modification") - }) - h.Before("/message > GET", func(t *trans.Transaction) { - fmt.Println("before modification") - }) - h.BeforeEachValidation(func(t *trans.Transaction) { - fmt.Println("before each validation modification") - }) - h.BeforeValidation("/message > GET", func(t *trans.Transaction) { - fmt.Println("before validation modification") - }) - h.After("/message > GET", func(t *trans.Transaction) { - fmt.Println("after modification") - }) - h.AfterEach(func(t *trans.Transaction) { - fmt.Println("after each modification") - }) - h.AfterAll(func(t []*trans.Transaction) { - fmt.Println("after all modification") - }) - server.Serve() - defer server.Listener.Close() -} -``` - -## Examples - -### How to Skip Tests - -Any test step can be skipped by setting the `Skip` property of the `Transaction` instance to `true`. - -```go -package main - -import ( - "fmt" - - "github.com/snikch/goodman/hooks" - trans "github.com/snikch/goodman/transaction" -) - -func main() { - h := hooks.NewHooks() - server := hooks.NewServer(hooks.NewHooksRunner(h)) - h.Before("Machines > Machines collection > Get Machines", func(t *trans.Transaction) { - t.Skip = true - }) - server.Serve() - defer server.Listener.Close() -} -``` - -### Failing Tests Programmatically - -You can fail any step by setting the `Fail` field of the `Transaction` instance to `true` or any string with a descriptive message. - -```go -package main - -import ( - "fmt" - - "github.com/snikch/goodman/hooks" - trans "github.com/snikch/goodman/transaction" -) - -func main() { - h := hooks.NewHooks() - server := hooks.NewServer(hooks.NewHooksRunner(h)) - h.Before("Machines > Machines collection > Get Machines", func(t *trans.Transaction) { - t.Fail = true - }) - h.Before("Machines > Machines collection > Post Machines", func(t *trans.Transaction) { - t.Fail = "POST is broken" - }) - server.Serve() - defer server.Listener.Close() -} -``` - -### Modifying the Request Body Prior to Execution - -```go -package main - -import ( - "fmt" - - "github.com/snikch/goodman/hooks" - trans "github.com/snikch/goodman/transaction" -) - -func main() { - h := hooks.NewHooks() - server := hooks.NewServer(hooks.NewHooksRunner(h)) - h.Before("Machines > Machines collection > Get Machines", func(t *trans.Transaction) { - body := map[string]interface{}{} - json.Unmarshal([]byte(t.Request.Body), &body) - - body["someKey"] = "new value" - - newBody, _ := json.Marshal(body) - t.Request.body = string(newBody) - }) - server.Serve() - defer server.Listener.Close() -} -``` +.. code:: go + + package main + + import ( + "fmt" + + "github.com/snikch/goodman/hooks" + trans "github.com/snikch/goodman/transaction" + ) + + func main() { + h := hooks.NewHooks() + server := hooks.NewServer(hooks.NewHooksRunner(h)) + h.BeforeAll(func(t []*trans.Transaction) { + fmt.Println("before all modification") + }) + h.BeforeEach(func(t *trans.Transaction) { + fmt.Println("before each modification") + }) + h.Before("/message > GET", func(t *trans.Transaction) { + fmt.Println("before modification") + }) + h.BeforeEachValidation(func(t *trans.Transaction) { + fmt.Println("before each validation modification") + }) + h.BeforeValidation("/message > GET", func(t *trans.Transaction) { + fmt.Println("before validation modification") + }) + h.After("/message > GET", func(t *trans.Transaction) { + fmt.Println("after modification") + }) + h.AfterEach(func(t *trans.Transaction) { + fmt.Println("after each modification") + }) + h.AfterAll(func(t []*trans.Transaction) { + fmt.Println("after all modification") + }) + server.Serve() + defer server.Listener.Close() + } + +Examples +-------- + +How to Skip Tests +~~~~~~~~~~~~~~~~~ + +Any test step can be skipped by setting the ``Skip`` property of the ``Transaction`` instance to ``true``. + +.. code:: go + + package main + + import ( + "fmt" + + "github.com/snikch/goodman/hooks" + trans "github.com/snikch/goodman/transaction" + ) + + func main() { + h := hooks.NewHooks() + server := hooks.NewServer(hooks.NewHooksRunner(h)) + h.Before("Machines > Machines collection > Get Machines", func(t *trans.Transaction) { + t.Skip = true + }) + server.Serve() + defer server.Listener.Close() + } + +Failing Tests Programmatically +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can fail any step by setting the ``Fail`` field of the ``Transaction`` instance to ``true`` or any string with a descriptive message. + +.. code:: go + + package main + + import ( + "fmt" + + "github.com/snikch/goodman/hooks" + trans "github.com/snikch/goodman/transaction" + ) + + func main() { + h := hooks.NewHooks() + server := hooks.NewServer(hooks.NewHooksRunner(h)) + h.Before("Machines > Machines collection > Get Machines", func(t *trans.Transaction) { + t.Fail = true + }) + h.Before("Machines > Machines collection > Post Machines", func(t *trans.Transaction) { + t.Fail = "POST is broken" + }) + server.Serve() + defer server.Listener.Close() + } + +Modifying the Request Body Prior to Execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: go + + package main + + import ( + "fmt" + + "github.com/snikch/goodman/hooks" + trans "github.com/snikch/goodman/transaction" + ) + + func main() { + h := hooks.NewHooks() + server := hooks.NewServer(hooks.NewHooksRunner(h)) + h.Before("Machines > Machines collection > Get Machines", func(t *trans.Transaction) { + body := map[string]interface{}{} + json.Unmarshal([]byte(t.Request.Body), &body) + + body["someKey"] = "new value" + + newBody, _ := json.Marshal(body) + t.Request.body = string(newBody) + }) + server.Serve() + defer server.Listener.Close() + } + +.. |Godoc Reference| image:: http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square + :target: https://godoc.org/github.com/snikch/goodman diff --git a/docs/hooks-js-sandbox.rst b/docs/hooks-js-sandbox.rst index 49c6a701b..fe57fd742 100644 --- a/docs/hooks-js-sandbox.rst +++ b/docs/hooks-js-sandbox.rst @@ -1,101 +1,104 @@ -# JavaScript Hooks In Sandbox Mode +.. _hooks-js-sandbox: -## Usage +JavaScript Hooks In Sandbox Mode +================================ -``` -$ dredd apiary.apib http://127.0.0.1:3000 --sandbox --hookfiles=./hooks*.js -``` +Usage +----- -### Dredd JS API Option +:: + + $ dredd apiary.apib http://127.0.0.1:3000 --sandbox --hookfiles=./hooks*.js + +Dredd JS API Option +~~~~~~~~~~~~~~~~~~~ Sandbox mode can be enabled in Dredd JavaScript API -```javascript -var Dredd = require('dredd'); -var configuration = { - server: "http://127.0.0.1", - options: { - path: "./test/fixtures/single-get.apib", - sandbox: true, - hookfiles: ['./test/fixtures/sandboxed-hook.js'] - } -}; -var dredd = new Dredd(configuration); +.. code:: javascript + + var Dredd = require('dredd'); + var configuration = { + server: "http://127.0.0.1", + options: { + path: "./test/fixtures/single-get.apib", + sandbox: true, + hookfiles: ['./test/fixtures/sandboxed-hook.js'] + } + }; + var dredd = new Dredd(configuration); + + dredd.run(function (error, stats) { + // your callback code here + }); -dredd.run(function (error, stats) { - // your callback code here -}); -``` +Sandboxed JavaScript Hooks API reference +---------------------------------------- -## Sandboxed JavaScript Hooks API reference +The Sandbox mode can be used for running untrusted hook code. It can be activated with a CLI switch or with the JS API. In each hook file you can use following functions: -The Sandbox mode can be used for running untrusted hook code. It can be activated with a CLI switch or with the JS API. -In each hook file you can use following functions: +``beforeAll(function)`` -`beforeAll(function)` +``beforeEach(function)`` -`beforeEach(function)` +``before(transactionName, function)`` -`before(transactionName, function)` +``beforeEachValidation(function)`` -`beforeEachValidation(function)` +``beforeValidation(transactionName, function)`` -`beforeValidation(transactionName, function)` +``after(transactionName, function)`` -`after(transactionName, function)` +``afterEach(function)`` -`afterEach(function)` +``afterAll(function)`` -`afterAll(function)` +``log(string)`` -`log(string)` +- A :ref:`Transaction Object ` is passed as a first argument to the hook function for ``before``, ``after``, ``beforeEach``, ``afterEach``, ``beforeValidation`` and ``beforeEachValidation``. +- An array of Transaction Objects is passed to ``beforeAll`` and ``afterAll``. +- Sandboxed hooks don’t have an asynchronous API. Loading and running of each hook happens in it’s own isolated, sandboxed context. +- Hook maximum execution time is 500ms. +- Memory limit is 1M +- You can access global ``stash`` object variables in each separate hook file. ``stash`` is passed between contexts of each hook function execution. This ``stash`` object purpose is to allow *transportation* of user defined values of type ``String``, ``Number``, ``Boolean``, ``null`` or ``Object`` and ``Array`` (no ``Functions`` or callbacks). +- Hook code is evaluated with ``"use strict"`` directive - `details at MDN `__ +- Sandboxed mode does not support hooks written in CoffeScript language +- You can print to console (via Dredd’s logger) with ``log`` function, taking into account the used logging level ``--level`` option (levels: ``error > warn > hook > info``) -- A [Transaction Object](data-structures.md#transaction) is passed as a first argument to the hook function for `before`, `after`, `beforeEach`, `afterEach`, `beforeValidation` and `beforeEachValidation`. -- An array of Transaction Objects is passed to `beforeAll` and `afterAll`. -- Sandboxed hooks don't have an asynchronous API. Loading and running of each hook happens in it's own isolated, sandboxed context. -- Hook maximum execution time is 500ms. -- Memory limit is 1M -- You can access global `stash` object variables in each separate hook file. - `stash` is passed between contexts of each hook function execution. - This `stash` object purpose is to allow _transportation_ of user defined values - of type `String`, `Number`, `Boolean`, `null` or `Object` and `Array` (no `Functions` or callbacks). -- Hook code is evaluated with `"use strict"` directive - [details at MDN](https://mdn.io/use+strict) -- Sandboxed mode does not support hooks written in CoffeScript language -- You can print to console (via Dredd's logger) with `log` function, taking into account the used logging level `--level` option (levels: `error > warn > hook > info`) +Request Stash in Sandbox Mode +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. code:: javascript -### Request Stash in Sandbox Mode + after('First action', function (transaction) { + stash['id'] = JSON.parse(transaction.real.response); + }); -```javascript -after('First action', function (transaction) { - stash['id'] = JSON.parse(transaction.real.response); -}); + before('Second action', function (transaction) { + newBody = JSON.parse(transaction.request.body); + newBody['id'] = stash['id']; + transaction.request.body = JSON.stringify(newBody); + }); -before('Second action', function (transaction) { - newBody = JSON.parse(transaction.request.body); - newBody['id'] = stash['id']; - transaction.request.body = JSON.stringify(newBody); -}); -``` +Hook function context is not shared +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -### Hook function context is not shared +When **sandboxed**, hook function **context is not shared** between even the same step hook functions. -When __sandboxed__, hook function __context is not shared__ between even the same step hook functions. +Note: **This is wrong**. It throws an exception. -Note: __This is wrong__. It throws an exception. +.. code:: javascript -```javascript -var myObject = {}; + var myObject = {}; -after('First action', function (transaction) { - myObject['id'] = JSON.parse(transaction.real.response); -}); + after('First action', function (transaction) { + myObject['id'] = JSON.parse(transaction.real.response); + }); -before('Second action', function (transaction) { - newBody = JSON.parse(transaction.request.body); - newBody['id'] = myObject['id']; - transaction.request.body = JSON.stringify(newBody); -}); -``` + before('Second action', function (transaction) { + newBody = JSON.parse(transaction.request.body); + newBody['id'] = myObject['id']; + transaction.request.body = JSON.stringify(newBody); + }); -This will explode with: `ReferenceError: myObject is not defined` +This will explode with: ``ReferenceError: myObject is not defined`` diff --git a/docs/hooks-new-language.rst b/docs/hooks-new-language.rst index 3ebba01f5..0ab564ba8 100644 --- a/docs/hooks-new-language.rst +++ b/docs/hooks-new-language.rst @@ -1,90 +1,120 @@ -# Writing Dredd hook handler for new language +.. _hooks-new-language: -## Dredd hooks handler client +Writing Dredd hook handler for new language +=========================================== + +Dredd hooks handler client +-------------------------- Dredd comes with concept of hooks language abstraction bridge via simple TCP socket. -When you run Dredd with `--language` argument, it runs the command in argument and tries to connect to `http://127.0.0.1:61321`. If connection to the hook handling server wasn't successful, it exits with exit code `3`. +When you run Dredd with ``--language`` argument, it runs the command in argument and tries to connect to ``http://127.0.0.1:61321``. If connection to the hook handling server wasn’t successful, it exits with exit code ``3``. -Dredd internally registers a function for each [type of hooks](hooks.md#types-of-hooks) and when this function is executed it assigns execution `uuid` to that event, serializes received function parameters (a [Transaction object](data-structures.md#transaction) or an Array of it), sends it to the TCP socket to be handled (executed) in other language and waits until message with same `uuid` is received. After data reception it assigns received `data` back to the transaction, so other language can interact with transactions same way like [native Node.js hooks](hooks-nodejs.md). +Dredd internally registers a function for each :ref:`type of hooks ` and when this function is executed it assigns execution ``uuid`` to that event, serializes received function parameters (a :ref:`Transaction object ` or an Array of it), sends it to the TCP socket to be handled (executed) in other language and waits until message with same ``uuid`` is received. After data reception it assigns received ``data`` back to the transaction, so other language can interact with transactions same way like :ref:`native Node.js hooks `. -## Language agnostic test suite +Language agnostic test suite +---------------------------- -Dredd hooks language abstraction bridge comes with [the language agnostic test suite](https://github.com/apiaryio/dredd-hooks-template). It's written in Gherkin - language for writing [Cucumber](https://github.com/cucumber/cucumber/wiki/A-Table-Of-Content) scenarios and [Aruba CLI testing framework](https://github.com/cucumber/aruba) and it tests your new language handler integration with CLI Dredd and expected behavior from user's perspective. +Dredd hooks language abstraction bridge comes with `the language agnostic test suite `__. It’s written in Gherkin - language for writing `Cucumber `__ scenarios and `Aruba CLI testing framework `__ and it tests your new language handler integration with CLI Dredd and expected behavior from user’s perspective. -## What to implement +What to implement +----------------- If you want to write a hook handler for your language you will have to implement: -- CLI Command runnning TCP socket server - - [Must return message `Starting` to stdout](https://github.com/apiaryio/dredd-hooks-template/blob/master/features/tcp_server.feature#L5) -- Hooks API in your language for registering code being executed during the [Dredd lifecycle](how-it-works.md#execution-life-cycle): - - before all transactions - - before each transaction - - before transaction - - before each transaction validation - - before transaction validation - - after transaction - - after each transaction - - after all transactions -- When CLI command is executed - - It loads files passed in alphabetical order with paths resolved to absolute form - - It exposes API similar to those in [Ruby](hooks-ruby.md), [Python](hooks-python.md) and [Node.js](hooks-nodejs.md) to each loaded file - - It registers functions declared in files for later execution - - starts a TCP socket server and starts listening on `http://127.0.0.1:61321`. -- When any data is received by the server - - Adds every received character to a buffer - - When delimiting newline (`\n`) character is received - - It parses the [message](#tcp-socket-message-format) in the buffer as JSON - - It looks for `event` key in received object and executes appropriate registered hooks functions - - When the hook function is being executed - - It passes value of `data` key from received object to the executed function - - Hook function is able to modify data - - When function was executed - - It should serialize message to JSON - - Send the serialized message back to the socket with same `uuid` as received - - Send a newline character as message delimiter - -## Termination +- CLI Command runnning TCP socket server + + - `Must return message ``Starting`` to stdout `__ + +- Hooks API in your language for registering code being executed during the :ref:`Dredd lifecycle `: + + - before all transactions + - before each transaction + - before transaction + - before each transaction validation + - before transaction validation + - after transaction + - after each transaction + - after all transactions + +- When CLI command is executed + + - It loads files passed in alphabetical order with paths resolved to absolute form + + - It exposes API similar to those in :ref:`Ruby `, :ref:`Python ` and :ref:`Node.js ` to each loaded file + - It registers functions declared in files for later execution + + - starts a TCP socket server and starts listening on ``http://127.0.0.1:61321``. + +- When any data is received by the server + + - Adds every received character to a buffer + - When delimiting newline (``\n``) character is received + + - It parses the :ref:`message ` in the buffer as JSON + - It looks for ``event`` key in received object and executes appropriate registered hooks functions + + - When the hook function is being executed + + - It passes value of ``data`` key from received object to the executed function + - Hook function is able to modify data + + - When function was executed + + - It should serialize message to JSON + - Send the serialized message back to the socket with same ``uuid`` as received + - Send a newline character as message delimiter + +Termination +----------- When the testing is done, Dredd signals the hook handler process to terminate. This is done repeatedly with delays. When termination timeout is over, Dredd loses its patience and kills the process forcefully. -- **retry delays** can be configured by [`--hooks-worker-term-retry`](usage-cli.md#hooks-worker-term-retry) -- **timeout** can be configured by [`--hooks-worker-term-timeout`](usage-cli.md#hooks-worker-term-timeout) +- **retry delays** can be configured by ``--hooks-worker-term-retry`` (:ref:`docs `) +- **timeout** can be configured by ``--hooks-worker-term-timeout`` (:ref:`docs `) + +On Linux or macOS, Dredd uses the ``SIGTERM`` signal to tell the hook handler process it should terminate. On Windows, where signals do not exist, Dredd sends the ``END OF TEXT`` character (``\u0003``, which is ASCII representation of Ctrl+C) to standard input of the process. + +.. _tcp-socket-message-format: + +TCP Socket Message format +------------------------- + +- transaction (object) + + - uuid: ``234567-asdfghjkl`` (string) - Id used for event unique identification on both server and client sides + - event: ``event`` (enum) - Event type -On Linux or macOS, Dredd uses the `SIGTERM` signal to tell the hook handler process it should terminate. On Windows, where signals do not exist, Dredd sends the `END OF TEXT` character (`\u0003`, which is ASCII representation of Ctrl+C) to standard input of the process. + - beforeAll (string) - Signals the hook handler to run the ``beforeAll`` hooks + - beforeEach (string) - Signals the hook handler to run the ``beforeEach`` and ``before`` hooks + - beforeEachValidation (string) - Signals the hook handler to run the ``beforeEachValidation`` and ``beforeValidation`` hooks + - afterEach (string) - Signals the hook handler to run the ``after`` and ``afterEach`` hooks + - afterAll (string) - Signals the hook handler to run the ``afterAll`` hooks -## TCP Socket Message format + - data (enum) - Data passed as a argument to the function -- transaction (object) - - uuid: `234567-asdfghjkl` (string) - Id used for event unique identification on both server and client sides - - event: `event` (enum) - Event type - - beforeAll (string) - Signals the hook handler to run the `beforeAll` hooks - - beforeEach (string) - Signals the hook handler to run the `beforeEach` and `before` hooks - - beforeEachValidation (string) - Signals the hook handler to run the `beforeEachValidation` and `beforeValidation` hooks - - afterEach (string) - Signals the hook handler to run the `after` and `afterEach` hooks - - afterAll (string) - Signals the hook handler to run the `afterAll` hooks - - data (enum) - Data passed as a argument to the function - - (object) - Single Transaction object - - (array) - An array of Transaction objects, containing all transactions in the API description. Sent for `beforeAll` and `afterAll` events + - (object) - Single Transaction object + - (array) - An array of Transaction objects, containing all transactions in the API description. Sent for ``beforeAll`` and ``afterAll`` events -## Configuration Options +Configuration Options +--------------------- There are several configuration options, which can help you during development: -- `--hooks-worker-timeout` - [docs](usage-cli.md#hooks-worker-timeout) -- `--hooks-worker-connect-timeout` - [docs](usage-cli.md#hooks-worker-connect-timeout) -- `--hooks-worker-connect-retry` - [docs](usage-cli.md#hooks-worker-connect-retry) -- `--hooks-worker-after-connect-wait` - [docs](usage-cli.md#hooks-worker-after-connect-wait) -- `--hooks-worker-term-timeout` - [docs](usage-cli.md#hooks-worker-term-timeout) -- `--hooks-worker-term-retry` - [docs](usage-cli.md#hooks-worker-term-retry) -- `--hooks-worker-handler-host` - [docs](usage-cli.md#hooks-worker-handler-host) -- `--hooks-worker-handler-port` - [docs](usage-cli.md#hooks-worker-handler-port) +- ``--hooks-worker-timeout`` - :ref:`docs ` +- ``--hooks-worker-connect-timeout`` - :ref:`docs ` +- ``--hooks-worker-connect-retry`` - :ref:`docs ` +- ``--hooks-worker-after-connect-wait`` - :ref:`docs ` +- ``--hooks-worker-term-timeout`` - :ref:`docs ` +- ``--hooks-worker-term-retry`` - :ref:`docs ` +- ``--hooks-worker-handler-host`` - :ref:`docs ` +- ``--hooks-worker-handler-port`` - :ref:`docs ` -## Need help? No problem! +Need help? No problem! +---------------------- If you have any questions, please: -- Have a look at the [Ruby](https://github.com/apiaryio/dredd-hooks-ruby), [Python](https://github.com/apiaryio/dredd-hooks-python), [Perl](https://github.com/ungrim97/Dredd-Hooks), and [PHP](https://github.com/ddelnano/dredd-hooks-php) hook handlers codebase for inspiration -- If you’re writing a hook handler for a compiled language, check out the [Go](https://github.com/snikch/goodman) implementation -- File an [issue in Dredd repository](https://github.com/apiaryio/dredd/issues/new) +- Have a look at the `Ruby `__, `Python `__, `Perl `__, and `PHP `__ hook handlers codebase for inspiration +- If you’re writing a hook handler for a compiled language, check out the `Go `__ implementation +- File an `issue in Dredd repository `__ diff --git a/docs/hooks-nodejs.rst b/docs/hooks-nodejs.rst index 337ce0298..bee4755a4 100644 --- a/docs/hooks-nodejs.rst +++ b/docs/hooks-nodejs.rst @@ -1,272 +1,292 @@ -# Writing Dredd Hooks In Node.js +.. _hooks-nodejs: -## Usage +Writing Dredd Hooks In Node.js +============================== -``` -$ dredd apiary.apib http://127.0.0.1:30000 --hookfiles=./hooks*.js -``` +Usage +----- -## API Reference +:: -- For `before`, `after`, `beforeValidation`, `beforeEach`, `afterEach` and `beforeEachValidation` a [Transaction Object](hooks.md#transaction-object-structure) is passed as the first argument to the hook function. -- An array of Transaction Objects is passed to `beforeAll` and `afterAll`. -- The second argument is an optional callback function for async execution. -- Any modifications on the `transaction` object are propagated to the actual HTTP transactions. -- You can use `hooks.log` function inside the hook function to print - yours debug messages and other information. + $ dredd apiary.apib http://127.0.0.1:30000 --hookfiles=./hooks*.js -- [`configuration`](usage-js.md#configuration-object-for-dredd-class) object is populated on the `hooks` object +API Reference +------------- -### Sync API +- For ``before``, ``after``, ``beforeValidation``, ``beforeEach``, ``afterEach`` and ``beforeEachValidation`` a :ref:`Transaction Object ` is passed as the first argument to the hook function. +- An array of Transaction Objects is passed to ``beforeAll`` and ``afterAll``. +- The second argument is an optional callback function for async execution. +- Any modifications on the ``transaction`` object are propagated to the actual HTTP transactions. +- You can use ``hooks.log`` function inside the hook function to print yours debug messages and other information. -```javascript -var hooks = require('hooks'); +- ``configuration`` (:ref:`docs `) object is populated on the ``hooks`` object -hooks.beforeAll(function (transactions) { - hooks.log('before all'); -}); +Sync API +~~~~~~~~ -hooks.beforeEach(function (transaction) { - hooks.log('before each'); -}); +.. code:: javascript -hooks.before("Machines > Machines collection > Get Machines", function (transaction) { - hooks.log("before"); -}); + var hooks = require('hooks'); -hooks.beforeEachValidation(function (transaction) { - hooks.log('before each validation'); -}); + hooks.beforeAll(function (transactions) { + hooks.log('before all'); + }); -hooks.beforeValidation("Machines > Machines collection > Get Machines", function (transaction) { - hooks.log("before validation"); -}); + hooks.beforeEach(function (transaction) { + hooks.log('before each'); + }); -hooks.after("Machines > Machines collection > Get Machines", function (transaction) { - hooks.log("after"); -}); + hooks.before("Machines > Machines collection > Get Machines", function (transaction) { + hooks.log("before"); + }); -hooks.afterEach(function (transaction) { - hooks.log('after each'); -}); + hooks.beforeEachValidation(function (transaction) { + hooks.log('before each validation'); + }); -hooks.afterAll(function (transactions) { - hooks.log('after all'); -}) -``` + hooks.beforeValidation("Machines > Machines collection > Get Machines", function (transaction) { + hooks.log("before validation"); + }); -### Async API + hooks.after("Machines > Machines collection > Get Machines", function (transaction) { + hooks.log("after"); + }); + + hooks.afterEach(function (transaction) { + hooks.log('after each'); + }); + + hooks.afterAll(function (transactions) { + hooks.log('after all'); + }) + +Async API +~~~~~~~~~ When the callback is used in the hook function, callbacks can handle asynchronous function calls. -```javascript -var hooks = require('hooks'); +.. code:: javascript + + var hooks = require('hooks'); + + hooks.beforeAll(function (transactions, done) { + hooks.log('before all'); + done(); + }); + + hooks.beforeEach(function (transaction, done) { + hooks.log('before each'); + done(); + }); -hooks.beforeAll(function (transactions, done) { - hooks.log('before all'); - done(); -}); + hooks.before("Machines > Machines collection > Get Machines", function (transaction, done) { + hooks.log("before"); + done(); + }); -hooks.beforeEach(function (transaction, done) { - hooks.log('before each'); - done(); -}); + hooks.beforeEachValidation(function (transaction, done) { + hooks.log('before each validation'); + done(); + }); -hooks.before("Machines > Machines collection > Get Machines", function (transaction, done) { - hooks.log("before"); - done(); -}); + hooks.beforeValidation("Machines > Machines collection > Get Machines", function (transaction, done) { + hooks.log("before validation"); + done(); + }); -hooks.beforeEachValidation(function (transaction, done) { - hooks.log('before each validation'); - done(); -}); + hooks.after("Machines > Machines collection > Get Machines", function (transaction, done) { + hooks.log("after"); + done(); + }); -hooks.beforeValidation("Machines > Machines collection > Get Machines", function (transaction, done) { - hooks.log("before validation"); - done(); -}); + hooks.afterEach(function (transaction, done) { + hooks.log('after each'); + done(); + }); -hooks.after("Machines > Machines collection > Get Machines", function (transaction, done) { - hooks.log("after"); - done(); -}); + hooks.afterAll(function (transactions, done) { + hooks.log('after all'); + done(); + }) -hooks.afterEach(function (transaction, done) { - hooks.log('after each'); - done(); -}); +Examples +-------- -hooks.afterAll(function (transactions, done) { - hooks.log('after all'); - done(); -}) -``` +How to Skip Tests +~~~~~~~~~~~~~~~~~ -## Examples +Any test step can be skipped by setting ``skip`` property of the ``transaction`` object to ``true``. -### How to Skip Tests +.. code:: javascript -Any test step can be skipped by setting `skip` property of the `transaction` object to `true`. + var before = require('hooks').before; -```javascript -var before = require('hooks').before; + before("Machines > Machines collection > Get Machines", function (transaction) { + transaction.skip = true; + }); -before("Machines > Machines collection > Get Machines", function (transaction) { - transaction.skip = true; -}); -``` +.. _sharing-data-between-steps-in-request-stash: -### Sharing Data Between Steps in Request Stash +Sharing Data Between Steps in Request Stash +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You may pass data between test steps using the response stash. -```javascript -var hooks = require('hooks'); -var before = hooks.before; -var after = hooks.after; +.. code:: javascript + + var hooks = require('hooks'); + var before = hooks.before; + var after = hooks.after; + + var responseStash = {}; + + after("Machines > Machines collection > Create Machine", function (transaction) { + + // saving HTTP response to the stash + responseStash[transaction.name] = transaction.real; + }); + + + before("Machines > Machine > Delete a machine", function (transaction) { + //reusing data from previous response here + var machineId = JSON.parse(responseStash['Machines > Machines collection > Create Machine'])['id']; + + //replacing id in URL with stashed id from previous response + var url = transaction.fullPath; + transaction.fullPath = url.replace('42', machineId); + }); + +Failing Tests Programmatically +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can fail any step by setting ``fail`` property on ``transaction`` object to ``true`` or any string with descriptive message. + +.. code:: javascript + + var before = require('hooks').before; + + before("Machines > Machines collection > Get Machines", function (transaction) { + transaction.fail = "Some failing message"; + }); + +.. _using-chai-assertions: + +Using Chai Assertions +~~~~~~~~~~~~~~~~~~~~~ + +Inside hook files, you can require `Chai `__ and use its ``assert``, ``should`` or ``expect`` interface in hooks and write your custom expectations. Dredd catches Chai’s expectation error in hooks and makes transaction to fail. -var responseStash = {}; +.. code:: javascript -after("Machines > Machines collection > Create Machine", function (transaction) { + var hooks = require('hooks'); + var before = hooks.before; + var assert = require('chai').assert; - // saving HTTP response to the stash - responseStash[transaction.name] = transaction.real; -}); + after("Machines > Machines collection > Get Machines", function (transaction) { + assert.isBelow(transaction.real.body.length, 100); + }); +.. _modifying-transaction-request-body-prior-to-execution: -before("Machines > Machine > Delete a machine", function (transaction) { - //reusing data from previous response here - var machineId = JSON.parse(responseStash['Machines > Machines collection > Create Machine'])['id']; +Modifying Transaction Request Body Prior to Execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - //replacing id in URL with stashed id from previous response - var url = transaction.fullPath; - transaction.fullPath = url.replace('42', machineId); -}); -``` +.. code:: javascript -### Failing Tests Programmatically + var hooks = require('hooks'); + var before = hooks.before; -You can fail any step by setting `fail` property on `transaction` object to `true` or any string with descriptive message. + before("Machines > Machines collection > Get Machines", function (transaction) { + // parse request body from API description + var requestBody = JSON.parse(transaction.request.body); -```javascript -var before = require('hooks').before; + // modify request body here + requestBody['someKey'] = 'someNewValue'; -before("Machines > Machines collection > Get Machines", function (transaction) { - transaction.fail = "Some failing message"; -}); -``` + // stringify the new body to request + transaction.request.body = JSON.stringify(requestBody); + }); -### Using Chai Assertions +Modifying Multipart Transaction Request Body Prior to Execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Inside hook files, you can require [Chai](http://www.chaijs.com/) and use its `assert`, `should` or `expect` interface in hooks and write your custom expectations. Dredd catches Chai's expectation error in hooks and makes transaction to fail. +Dependencies: - `multi-part `__ - `stream-to-string `__ -```javascript -var hooks = require('hooks'); -var before = hooks.before; -var assert = require('chai').assert; +.. code:: javascript -after("Machines > Machines collection > Get Machines", function (transaction) { - assert.isBelow(transaction.real.body.length, 100); -}); -``` + const hooks = require('hooks'); + const fs = require('fs'); + const Multipart = require('multi-part'); + const streamToString = require('stream-to-string'); -### Modifying Transaction Request Body Prior to Execution + var before = hooks.before; -```javascript -var hooks = require('hooks'); -var before = hooks.before; + before("Machines > Machines collection > Create Machines", async function (transaction, done) { + const form = new Multipart(); + form.append('title', 'Foo'); + form.append('photo', fs.createReadStream('./bar.jpg')); + transaction.request.body = await streamToString(form.getStream()); + transaction.request.headers['Content-Type'] = form.getHeaders()['content-type']; + done(); + }); -before("Machines > Machines collection > Get Machines", function (transaction) { - // parse request body from API description - var requestBody = JSON.parse(transaction.request.body); +Adding or Changing URI Query Parameters to All Requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // modify request body here - requestBody['someKey'] = 'someNewValue'; +.. code:: javascript - // stringify the new body to request - transaction.request.body = JSON.stringify(requestBody); -}); -``` + var hooks = require('hooks'); -### Modifying Multipart Transaction Request Body Prior to Execution + hooks.beforeEach(function (transaction) { + // add query parameter to each transaction here + var paramToAdd = "api-key=23456" + if(transaction.fullPath.indexOf('?') > -1){ + transaction.fullPath += "&" + paramToAdd; + } else{ + transaction.fullPath += "?" + paramToAdd; + } + }); -Dependencies: -- [multi-part](https://www.npmjs.com/package/multi-part) -- [stream-to-string](https://www.npmjs.com/package/stream-to-string) +Handling sessions +~~~~~~~~~~~~~~~~~ -```javascript -const hooks = require('hooks'); -const fs = require('fs'); -const Multipart = require('multi-part'); -const streamToString = require('stream-to-string'); +.. code:: javascript -var before = hooks.before; + var hooks = require('hooks'); + var stash = {}; -before("Machines > Machines collection > Create Machines", async function (transaction, done) { - const form = new Multipart(); - form.append('title', 'Foo'); - form.append('photo', fs.createReadStream('./bar.jpg')); - transaction.request.body = await streamToString(form.getStream()); - transaction.request.headers['Content-Type'] = form.getHeaders()['content-type']; - done(); -}); -``` + // hook to retrieve session on a login + hooks.after('Auth > /remoteauth/userpass > POST', function (transaction) { + stash['token'] = JSON.parse(transaction.real.body)['sessionId']; + }); -### Adding or Changing URI Query Parameters to All Requests + // hook to set the session cookie in all following requests + hooks.beforeEach(function (transaction) { + if(stash['token'] != undefined){ + transaction.request['headers']['Cookie'] = "id=" + stash['token']; + }; + }); -```javascript -var hooks = require('hooks'); +Remove trailing newline character in expected *plain text* bodies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -hooks.beforeEach(function (transaction) { - // add query parameter to each transaction here - var paramToAdd = "api-key=23456" - if(transaction.fullPath.indexOf('?') > -1){ - transaction.fullPath += "&" + paramToAdd; - } else{ - transaction.fullPath += "?" + paramToAdd; - } -}); -``` +.. code:: javascript -### Handling sessions + var hooks = require('hooks'); -```javascript -var hooks = require('hooks'); -var stash = {}; + hooks.beforeEach(function(transaction) { + if (transaction.expected.headers['Content-Type'] === 'text/plain') { + transaction.expected.body = transaction.expected.body.replace(/^\s+|\s+$/g, ""); + } + }); -// hook to retrieve session on a login -hooks.after('Auth > /remoteauth/userpass > POST', function (transaction) { - stash['token'] = JSON.parse(transaction.real.body)['sessionId']; -}); +Using Babel +~~~~~~~~~~~ -// hook to set the session cookie in all following requests -hooks.beforeEach(function (transaction) { - if(stash['token'] != undefined){ - transaction.request['headers']['Cookie'] = "id=" + stash['token']; - }; -}); -``` +With this workaround you can use `Babel `__ for support of all the latest JS syntactic coolness in Dredd hooks: +:: -### Remove trailing newline character in expected _plain text_ bodies - -```javascript -var hooks = require('hooks'); - -hooks.beforeEach(function(transaction) { - if (transaction.expected.headers['Content-Type'] === 'text/plain') { - transaction.expected.body = transaction.expected.body.replace(/^\s+|\s+$/g, ""); - } -}); -``` - -### Using Babel - -With this workaround you can use [Babel](https://babeljs.io/) for support of all the latest JS syntactic coolness in Dredd hooks: - -``` -npm install -g babel-cli babel-preset-es2015 -echo '{ "presets": ["es2015"] }' > .babelrc -babel-node `which dredd` test/fixtures/single-get.apib http://127.0.0.1:3000 --hookfiles=./es2015.js -``` + npm install -g babel-cli babel-preset-es2015 + echo '{ "presets": ["es2015"] }' > .babelrc + babel-node `which dredd` test/fixtures/single-get.apib http://127.0.0.1:3000 --hookfiles=./es2015.js diff --git a/docs/hooks-perl.rst b/docs/hooks-perl.rst index 18ac46024..8e21e609c 100644 --- a/docs/hooks-perl.rst +++ b/docs/hooks-perl.rst @@ -1,214 +1,233 @@ -# Writing Dredd Hooks In Perl +.. _hooks-perl: -[![Build Status](https://api.travis-ci.org/ungrim97/Dredd-Hooks.svg?branch=master)](https://api.travis-ci.org/ungrim97/Dredd-Hooks.svg?branch=master) +Writing Dredd Hooks In Perl +=========================== -[GitHub repository](https://github.com/ungrim97/Dredd-Hooks) +|Build Status| -Perl hooks are using [Dredd's hooks handler socket interface](hooks-new-language.md). For using Perl hooks in Dredd you have to have [Dredd already installed](quickstart.md) +`GitHub repository `__ -## Installation +Perl hooks are using :ref:`Dredd’s hooks handler socket interface `. For using Perl hooks in Dredd you have to have :ref:`Dredd already installed ` -``` -$ cpanm Dredd::Hooks -``` +Installation +------------ -## Usage +:: -``` -$ dredd apiary.apib http://127.0.0.1:3000 --language=dredd-hooks-perl --hookfiles=./hooks*.pl -``` + $ cpanm Dredd::Hooks -## API Reference +Usage +----- -Module `Dredd::Hooks::Methods` imports following decorators: +:: -1. `beforeEach`, `beforeEachValidation`, `afterEach` - - wraps a function and passes [Transaction object](data-structures.md#transaction) as a first argument to it + $ dredd apiary.apib http://127.0.0.1:3000 --language=dredd-hooks-perl --hookfiles=./hooks*.pl -2. `before`, `beforeValidation`, `after` - - accepts [transaction name](hooks.md#getting-transaction-names) as a first argument - - wraps a function and sends a [Transaction object](data-structures.md#transaction) as a first argument to it +API Reference +------------- -3. `beforeAll`, `afterAll` - - wraps a function and passes an Array of [Transaction objects](data-structures.md#transaction) as a first argument to it +Module ``Dredd::Hooks::Methods`` imports following decorators: -Refer to [Dredd execution life-cycle](how-it-works.md#execution-life-cycle) to find when is each hook function executed. +1. ``beforeEach``, ``beforeEachValidation``, ``afterEach`` -### Using Perl API + - wraps a function and passes :ref:`Transaction object ` as a first argument to it + +2. ``before``, ``beforeValidation``, ``after`` + + - accepts :ref:`transaction name ` as a first argument + - wraps a function and sends a :ref:`Transaction object ` as a first argument to it + +3. ``beforeAll``, ``afterAll`` + + - wraps a function and passes an Array of :ref:`Transaction objects ` as a first argument to it + +Refer to :ref:`Dredd execution life-cycle ` to find when is each hook function executed. + +Using Perl API +~~~~~~~~~~~~~~ Example usage of all methods in -```perl -use Dredd::Hooks::Methods; +.. code:: perl + + use Dredd::Hooks::Methods; -beforeAll( sub { - print 'before all' -}); + beforeAll( sub { + print 'before all' + }); -beforeEach( sub { - print 'before each' -}) + beforeEach( sub { + print 'before each' + }) -before( "Machines > Machines collection > Get Machines" => sub { - print 'before' -}); + before( "Machines > Machines collection > Get Machines" => sub { + print 'before' + }); -beforeEachValidation(sub { - print 'before each validation' -}); + beforeEachValidation(sub { + print 'before each validation' + }); -beforeValidation( "Machines > Machines collection > Get Machines" => sub { - print 'before validations' -}); + beforeValidation( "Machines > Machines collection > Get Machines" => sub { + print 'before validations' + }); -after( "Machines > Machines collection > Get Machines" => sub { - print 'after' -}); + after( "Machines > Machines collection > Get Machines" => sub { + print 'after' + }); -afterEach( sub { - print 'after_each' -}); + afterEach( sub { + print 'after_each' + }); -afterAll( sub { - print 'after_all' -}); + afterAll( sub { + print 'after_all' + }); -``` +Examples +-------- -## Examples +How to Skip Tests +~~~~~~~~~~~~~~~~~ -### How to Skip Tests +Any test step can be skipped by setting ``skip`` property of the ``transaction`` object to ``true``. -Any test step can be skipped by setting `skip` property of the `transaction` object to `true`. +.. code:: perl -```perl -use Dredd::Hooks::Methods; -use Types::Serialiser; + use Dredd::Hooks::Methods; + use Types::Serialiser; -before("Machines > Machines collection > Get Machines" => sub { - my ($transaction) = @_; + before("Machines > Machines collection > Get Machines" => sub { + my ($transaction) = @_; - $transaction->{skip} = Types::Serialiser::true; -}); -``` + $transaction->{skip} = Types::Serialiser::true; + }); -### Sharing Data Between Steps in Request Stash +Sharing Data Between Steps in Request Stash +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you want to test some API workflow, you may pass data between test steps using the response stash. -```perl -use JSON; -use Dredd::Hooks::Methods; +.. code:: perl + + use JSON; + use Dredd::Hooks::Methods; + + my $response_stash = {}; + + after("Machines > Machines collection > Create Machine" => sub { + my ($transaction) = @_; + + # saving HTTP response to the stash + $response_stash->{$transaction->{name}} = $transaction->{real} + }); + + before("Machines > Machine > Delete a machine" => sub { + my ($transaction) = @_; + #reusing data from previous response here + my $parsed_body = JSON->decode_json( + $response_stash->{'Machines > Machines collection > Create Machine'} + ); + my $machine_id = $parsed_body->{id}; + #replacing id in URL with stashed id from previous response + $transaction->{fullPath} =~ s/42/$machine_id/; + }); + +Failing Tests Programmatically +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -my $response_stash = {}; +You can fail any step by setting ``fail`` property on ``transaction`` object to ``true`` or any string with descriptive message. -after("Machines > Machines collection > Create Machine" => sub { - my ($transaction) = @_; +.. code:: perl - # saving HTTP response to the stash - $response_stash->{$transaction->{name}} = $transaction->{real} -}); + use Dredd::Hooks::Methods; -before("Machines > Machine > Delete a machine" => sub { - my ($transaction) = @_; - #reusing data from previous response here - my $parsed_body = JSON->decode_json( - $response_stash->{'Machines > Machines collection > Create Machine'} - ); - my $machine_id = $parsed_body->{id}; - #replacing id in URL with stashed id from previous response - $transaction->{fullPath} =~ s/42/$machine_id/; -}); -``` + before("Machines > Machines collection > Get Machines" => sub { + my ($transaction) = @_; + $transaction->{fail} = "Some failing message"; + }); -### Failing Tests Programmatically +Modifying Transaction Request Body Prior to Execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can fail any step by setting `fail` property on `transaction` object to `true` or any string with descriptive message. +.. code:: perl -```perl -use Dredd::Hooks::Methods; + use JSON; + use Dredd::Hooks::Methods; -before("Machines > Machines collection > Get Machines" => sub { - my ($transaction) = @_; - $transaction->{fail} = "Some failing message"; -}); -``` + before("Machines > Machines collection > Get Machines" => sub { + my ($transaction) = @_; -### Modifying Transaction Request Body Prior to Execution + # parse request body from API description + my $request_body = JSON->decode_json($transaction->{request}{body}); -```perl -use JSON; -use Dredd::Hooks::Methods; + # modify request body here + $request_body->{someKey} = 'some new value'; -before("Machines > Machines collection > Get Machines" => sub { - my ($transaction) = @_; + # stringify the new body to request + $transaction->{request}{body} = JSON->encode_json($request_body); + }); - # parse request body from API description - my $request_body = JSON->decode_json($transaction->{request}{body}); +Adding or Changing URI Query Parameters to All Requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - # modify request body here - $request_body->{someKey} = 'some new value'; +.. code:: perl - # stringify the new body to request - $transaction->{request}{body} = JSON->encode_json($request_body); -}); -``` + use Dredd::Hooks::Methods; -### Adding or Changing URI Query Parameters to All Requests + beforeEach( sub { + my ($transaction) = @_; + # add query parameter to each transaction here + my $param_to_add = "api-key=23456"; -```perl -use Dredd::Hooks::Methods; + if ($transaction->{fullPath} =~ m/?/){ + $transaction->{fullPath} .= "&$param_to_add"; + } else { + $transaction->{fullPath} .= "?$param_to_add"; + } + }); -beforeEach( sub { - my ($transaction) = @_; - # add query parameter to each transaction here - my $param_to_add = "api-key=23456"; +Handling sessions +~~~~~~~~~~~~~~~~~ - if ($transaction->{fullPath} =~ m/?/){ - $transaction->{fullPath} .= "&$param_to_add"; - } else { - $transaction->{fullPath} .= "?$param_to_add"; - } -}); -``` +.. code:: perl -### Handling sessions + use JSON; + use Dredd::Hooks::Methods; -```perl -use JSON; -use Dredd::Hooks::Methods; + my $stash = {} -my $stash = {} + # hook to retrieve session on a login + after('Auth > /remoteauth/userpass > POST' => sub { + my ($transaction) = @_; -# hook to retrieve session on a login -after('Auth > /remoteauth/userpass > POST' => sub { - my ($transaction) = @_; + my $parsed_body = JSON->decode_json($transaction->{real}{body}); + my $stash->{token} = $parsed_body->{sessionId}; + )}; - my $parsed_body = JSON->decode_json($transaction->{real}{body}); - my $stash->{token} = $parsed_body->{sessionId}; -)}; + # hook to set the session cookie in all following requests + beforeEach( sub { + my ($transaction) = @_; -# hook to set the session cookie in all following requests -beforeEach( sub { - my ($transaction) = @_; + if (exists $stash->{token}){ + $transaction->{request}{headers}{Cookie} = "id=".$stash{token}; + } + }); - if (exists $stash->{token}){ - $transaction->{request}{headers}{Cookie} = "id=".$stash{token}; - } -}); -``` +Remove trailing newline character in expected *plain text* bodies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. code:: perl -### Remove trailing newline character in expected _plain text_ bodies + use Dredd::Hooks::Methods; -```perl -use Dredd::Hooks::Methods; + beforeEach( + my ($transaction) = @_; -beforeEach( - my ($transaction) = @_; + if( $transaction->{expected}{headers}{Content-Type} eq 'text/plain'){ + $transaction->{expected}{body} = chomp($transaction->{expected}{body}); + } + }); - if( $transaction->{expected}{headers}{Content-Type} eq 'text/plain'){ - $transaction->{expected}{body} = chomp($transaction->{expected}{body}); - } -}); -``` +.. |Build Status| image:: https://api.travis-ci.org/ungrim97/Dredd-Hooks.svg?branch=master + :target: https://api.travis-ci.org/ungrim97/Dredd-Hooks.svg?branch=master diff --git a/docs/hooks-php.rst b/docs/hooks-php.rst index 9942fa07c..bbe10cb69 100644 --- a/docs/hooks-php.rst +++ b/docs/hooks-php.rst @@ -1,200 +1,216 @@ -# Writing Dredd Hooks In PHP +.. _hooks-php: -[![Build Status](https://travis-ci.org/ddelnano/dredd-hooks-php.svg?branch=master)](https://travis-ci.org/ddelnano/dredd-hooks-php) +Writing Dredd Hooks In PHP +========================== -[GitHub repository](https://github.com/ddelnano/dredd-hooks-php) +|Build Status| -PHP hooks are using [Dredd's hooks handler socket interface](hooks-new-language.md). For using PHP hooks in Dredd you have to have [Dredd already installed](quickstart.md) +`GitHub repository `__ -## Installation +PHP hooks are using :ref:`Dredd’s hooks handler socket interface `. For using PHP hooks in Dredd you have to have :ref:`Dredd already installed ` -### Requirements - - php version >= 5.4 +Installation +------------ + +Requirements +~~~~~~~~~~~~ + +- php version >= 5.4 Installing dredd-hooks-php can be easily installed through the package manager, composer. -``` -$ composer require ddelnano/dredd-hooks-php --dev -``` +:: + + $ composer require ddelnano/dredd-hooks-php --dev + +Usage +----- + +:: + + $ dredd apiary.apib http://127.0.0.1:3000 --language=vendor/bin/dredd-hooks-php --hookfiles=./hooks*.php + +API Reference +------------- + +The ``Dredd\Hooks`` class provides the static methods listed below to create hooks + +1. ``beforeEach``, ``beforeEachValidation``, ``afterEach`` + + - accepts a closure as a first argument passing a :ref:`Transaction object ` as a first argument + +2. ``before``, ``beforeValidation``, ``after`` + + - accepts :ref:`transaction name ` as a first argument + - accepts a block as a second argument passing a :ref:`Transaction object ` as a first argument of it -## Usage +3. ``beforeAll``, ``afterAll`` -``` -$ dredd apiary.apib http://127.0.0.1:3000 --language=vendor/bin/dredd-hooks-php --hookfiles=./hooks*.php -``` + - accepts a block as a first argument passing an Array of :ref:`Transaction objects ` as a first argument -## API Reference +Refer to :ref:`Dredd execution lifecycle ` to find when is each hook function executed. -The `Dredd\Hooks` class provides the static methods listed below to create hooks +Using PHP API +~~~~~~~~~~~~~ -1. `beforeEach`, `beforeEachValidation`, `afterEach` - - accepts a closure as a first argument passing a [Transaction object](data-structures.md#transaction) as a first argument +Example usage of all methods. **Very Important** The ``$transaction`` variable passed to the closure **MUST** be a reference. Otherwise the ``$transaction`` variable will be passed by value when the closure is executed and the changes will not be reflected. -2. `before`, `beforeValidation`, `after` - - accepts [transaction name](hooks.md#getting-transaction-names) as a first argument - - accepts a block as a second argument passing a [Transaction object](data-structures.md#transaction) as a first argument of it +.. code:: php -3. `beforeAll`, `afterAll` - - accepts a block as a first argument passing an Array of [Transaction objects](data-structures.md#transaction) as a first argument + Machines collection > Get Machines", function(&$transaction) { -Hooks::beforeAll(function(&$transaction) { + echo "before"; + }); - echo "before all"; -}); + Hooks::beforeEachValidation(function(&$transaction) { -Hooks::beforeEach(function(&$transaction) { + echo "before each validation"; + }); - echo "before each"; -}); + Hooks::beforeValidation("Machines > Machines collection > Get Machines", function(&$transaction) { -Hooks::before("Machines > Machines collection > Get Machines", function(&$transaction) { + echo "before validation"; + }); - echo "before"; -}); -Hooks::beforeEachValidation(function(&$transaction) { + Hooks::after("Machines > Machines collection > Get Machines", function(&$transaction) { - echo "before each validation"; -}); + echo "after"; + }); -Hooks::beforeValidation("Machines > Machines collection > Get Machines", function(&$transaction) { + Hooks::afterEach(function(&$transaction) { - echo "before validation"; -}); + echo "after each"; + }); + Hooks::afterAll(function(&$transaction) { -Hooks::after("Machines > Machines collection > Get Machines", function(&$transaction) { + echo "after all"; + }); - echo "after"; -}); +Examples +-------- -Hooks::afterEach(function(&$transaction) { +In the `dredd-hooks-php repository `__ there is an example laravel application with instructions in the `wiki `__ - echo "after each"; -}); +How to Skip Tests +~~~~~~~~~~~~~~~~~ -Hooks::afterAll(function(&$transaction) { +Any test step can be skipped by setting ``skip`` property of the ``transaction`` object to ``true``. - echo "after all"; -}); +.. code:: php -``` + Machines collection > Get Machines", function(&$transaction) { -Any test step can be skipped by setting `skip` property of the `transaction` object to `true`. + $transaction->skip = true; + }); -```php - Machines collection > Get Machines", function(&$transaction) { + skip = true; -}); -``` + use Dredd\Hooks; -### Failing Tests Programmatically -You can fail any step by setting `fail` property on `transaction` object to `true` or any string with descriptive message. + Hooks::before("Machines > Machines collection > Get Machines", function(&$transaction) { -```php -fail = true; + }); -use Dredd\Hooks; +Modifying Transaction Request Body Prior to Execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. code:: php -Hooks::before("Machines > Machines collection > Get Machines", function(&$transaction) { + fail = true; -}); -``` + use Dredd\Hooks; -### Modifying Transaction Request Body Prior to Execution + Hooks::before("Machines > Machines collection > Get Machines", function(&$transaction) { -```php -request->body; -use Dredd\Hooks; + $requestBody['someKey'] = 'new value'; -Hooks::before("Machines > Machines collection > Get Machines", function(&$transaction) { + $transaction->request->body = json_encode($requestBody); + }); - $requestBody = $transaction->request->body; +Adding or Changing URI Query Parameters to All Requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - $requestBody['someKey'] = 'new value'; +.. code:: php - $transaction->request->body = json_encode($requestBody); -}); -``` + fullPath, "?") { - $paramToAdd = 'api-key=23456'; + $transaction->fullPath .= "&{$paramToAdd}"; + } - if (strpos($transaction->fullPath, "?") { + else { - $transaction->fullPath .= "&{$paramToAdd}"; - } + $transaction->fullPath .= "?{$paramToAdd}"; + } + }); - else { +Handling sessions +~~~~~~~~~~~~~~~~~ - $transaction->fullPath .= "?{$paramToAdd}"; - } -}); -``` +.. code:: php -### Handling sessions + /remoteauto/userpass", function(&$transaction) use (&$stash) { -Hooks::after("Auth > /remoteauto/userpass", function(&$transaction) use (&$stash) { + $parsedBody = json_decode($transaction->real->body); - $parsedBody = json_decode($transaction->real->body); + $stash['token'] = $parseBody->sessionId; + }); - $stash['token'] = $parseBody->sessionId; -}); + Hooks::beforeEach(function(&$transaction) use (&$stash) { -Hooks::beforeEach(function(&$transaction) use (&$stash) { + if ($transaction->token) { - if ($transaction->token) { + $transaction->request->headers->Cookie = "id={$stash['token']}s"; + } + }); - $transaction->request->headers->Cookie = "id={$stash['token']}s"; - } -}); -``` +.. |Build Status| image:: https://travis-ci.org/ddelnano/dredd-hooks-php.svg?branch=master + :target: https://travis-ci.org/ddelnano/dredd-hooks-php diff --git a/docs/hooks-python.rst b/docs/hooks-python.rst index a7c4d56e4..1ce341c1d 100644 --- a/docs/hooks-python.rst +++ b/docs/hooks-python.rst @@ -1,198 +1,214 @@ -# Writing Dredd Hooks In Python +.. _hooks-python: -[![Build Status](https://travis-ci.org/apiaryio/dredd-hooks-python.svg?branch=master)](https://travis-ci.org/apiaryio/dredd-hooks-python) +Writing Dredd Hooks In Python +============================= +|Build Status| -[GitHub repository](https://github.com/apiaryio/dredd-hooks-python) +`GitHub repository `__ -Python hooks are using [Dredd's hooks handler socket interface](hooks-new-language.md). For using Python hooks in Dredd you have to have [Dredd already installed](quickstart.md) +Python hooks are using :ref:`Dredd’s hooks handler socket interface `. For using Python hooks in Dredd you have to have :ref:`Dredd already installed ` -## Installation +Installation +------------ -``` -$ pip install dredd_hooks -``` +:: -## Usage + $ pip install dredd_hooks -``` -$ dredd apiary.apib http://127.0.0.1:3000 --language=python --hookfiles=./hooks*.py -``` +Usage +----- -## API Reference +:: -Module `dredd_hooks` imports following decorators: + $ dredd apiary.apib http://127.0.0.1:3000 --language=python --hookfiles=./hooks*.py -1. `before_each`, `before_each_validation`, `after_each` - - wraps a function and passes [Transaction object](data-structures.md#transaction) as a first argument to it +API Reference +------------- -2. `before`, `before_validation`, `after` - - accepts [transaction name](hooks.md#getting-transaction-names) as a first argument - - wraps a function and sends a [Transaction object](data-structures.md#transaction) as a first argument to it +Module ``dredd_hooks`` imports following decorators: -3. `before_all`, `after_all` - - wraps a function and passes an Array of [Transaction objects](data-structures.md#transaction) as a first argument to it +1. ``before_each``, ``before_each_validation``, ``after_each`` + - wraps a function and passes :ref:`Transaction object ` as a first argument to it -Refer to [Dredd execution life-cycle](how-it-works.md#execution-life-cycle) to find when is each hook function executed. +2. ``before``, ``before_validation``, ``after`` -### Using Python API + - accepts :ref:`transaction name ` as a first argument + - wraps a function and sends a :ref:`Transaction object ` as a first argument to it + +3. ``before_all``, ``after_all`` + + - wraps a function and passes an Array of :ref:`Transaction objects ` as a first argument to it + +Refer to :ref:`Dredd execution life-cycle ` to find when is each hook function executed. + +Using Python API +~~~~~~~~~~~~~~~~ Example usage of all methods in -```python -import dredd_hooks as hooks +.. code:: python + + import dredd_hooks as hooks -@hooks.before_all -def my_before_all_hook(transactions): - print('before all') + @hooks.before_all + def my_before_all_hook(transactions): + print('before all') -@hooks.before_each -def my_before_each_hook(transaction): - print('before each') + @hooks.before_each + def my_before_each_hook(transaction): + print('before each') -@hooks.before -def my_before_hook(transaction): - print('before') + @hooks.before + def my_before_hook(transaction): + print('before') -@hooks.before_each_validation -def my_before_each_validation_hook(transaction): - print('before each validation') + @hooks.before_each_validation + def my_before_each_validation_hook(transaction): + print('before each validation') -@hooks.before_validation -def my_before_validation_hook(transaction): - print('before validations') + @hooks.before_validation + def my_before_validation_hook(transaction): + print('before validations') -@hooks.after -def my_after_hook(transaction): - print('after') + @hooks.after + def my_after_hook(transaction): + print('after') -@hooks.after_each -def my_after_each(transaction): - print('after_each') + @hooks.after_each + def my_after_each(transaction): + print('after_each') -@hooks.after_all -def my_after_all_hook(transactions): - print('after_all') + @hooks.after_all + def my_after_all_hook(transactions): + print('after_all') -``` +Examples +-------- -## Examples +More complex examples are to be found in the Github repository `under the examples directory `__. If you want to share your own, don’t hesitate and sumbit a PR. -More complex examples are to be found in the Github repository -[under the examples directory](https://github.com/apiaryio/dredd-hooks-python/tree/master/examples). If you want to share your own, don't hesitate and sumbit a PR. +How to Skip Tests +~~~~~~~~~~~~~~~~~ -### How to Skip Tests +Any test step can be skipped by setting ``skip`` property of the ``transaction`` object to ``true``. -Any test step can be skipped by setting `skip` property of the `transaction` object to `true`. +.. code:: python -```python -import dredd_hooks as hooks + import dredd_hooks as hooks -@hooks.before("Machines > Machines collection > Get Machines") -def skip_test(transaction): - transaction['skip'] = True -``` + @hooks.before("Machines > Machines collection > Get Machines") + def skip_test(transaction): + transaction['skip'] = True -### Sharing Data Between Steps in Request Stash +Sharing Data Between Steps in Request Stash +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you want to test some API workflow, you may pass data between test steps using the response stash. -```python -import json -import dredd_hooks as hooks +.. code:: python + + import json + import dredd_hooks as hooks + + response_stash = {} + + @hooks.after("Machines > Machines collection > Create Machine") + def save_response_to_stash(transaction): + # saving HTTP response to the stash + response_stash[transaction['name']] = transaction['real'] + + @hooks.before("Machines > Machine > Delete a machine") + def add_machine_id_to_request(transaction): + #reusing data from previous response here + parsed_body = json.loads(response_stash['Machines > Machines collection > Create Machine']) + machine_id = parsed_body['id'] + #replacing id in URL with stashed id from previous response + transaction['fullPath'] = transaction['fullPath'].replace('42', machine_id) + +Failing Tests Programmatically +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can fail any step by setting ``fail`` property on ``transaction`` object to ``true`` or any string with descriptive message. -response_stash = {} +.. code:: python -@hooks.after("Machines > Machines collection > Create Machine") -def save_response_to_stash(transaction): - # saving HTTP response to the stash - response_stash[transaction['name']] = transaction['real'] + import dredd_hooks as hooks -@hooks.before("Machines > Machine > Delete a machine") -def add_machine_id_to_request(transaction): - #reusing data from previous response here - parsed_body = json.loads(response_stash['Machines > Machines collection > Create Machine']) - machine_id = parsed_body['id'] - #replacing id in URL with stashed id from previous response - transaction['fullPath'] = transaction['fullPath'].replace('42', machine_id) -``` + @hooks.before("Machines > Machines collection > Get Machines") + def fail_transaction(transaction): + transaction['fail'] = "Some failing message" -### Failing Tests Programmatically +Modifying Transaction Request Body Prior to Execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can fail any step by setting `fail` property on `transaction` object to `true` or any string with descriptive message. +.. code:: python -```python -import dredd_hooks as hooks + import json + import dredd_hooks as hooks -@hooks.before("Machines > Machines collection > Get Machines") -def fail_transaction(transaction): - transaction['fail'] = "Some failing message" -``` + @hooks.before("Machines > Machines collection > Get Machines") + def add_value_to_body(transaction): + # parse request body from API description + request_body = json.loads(transaction['request']['body']) -### Modifying Transaction Request Body Prior to Execution + # modify request body here + request_body['someKey'] = 'some new value' -```python -import json -import dredd_hooks as hooks + # stringify the new body to request + transaction['request']['body'] = json.dumps(request_body) -@hooks.before("Machines > Machines collection > Get Machines") -def add_value_to_body(transaction): - # parse request body from API description - request_body = json.loads(transaction['request']['body']) +Adding or Changing URI Query Parameters to All Requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - # modify request body here - request_body['someKey'] = 'some new value' +.. code:: python - # stringify the new body to request - transaction['request']['body'] = json.dumps(request_body) -``` + import dredd_hooks as hooks -### Adding or Changing URI Query Parameters to All Requests + @hooks.before_each + def add_api_key(transaction): + # add query parameter to each transaction here + param_to_add = "api-key=23456" -```python -import dredd_hooks as hooks + if '?' in transaction['fullPath']: + transaction['fullPath'] = ''.join((transaction['fullPath'], "&", param_to_add)) + else: + transaction['fullPath'] = ''.join((transaction['fullPath'], "?", param_to_add)) -@hooks.before_each -def add_api_key(transaction): - # add query parameter to each transaction here - param_to_add = "api-key=23456" +Handling sessions +~~~~~~~~~~~~~~~~~ - if '?' in transaction['fullPath']: - transaction['fullPath'] = ''.join((transaction['fullPath'], "&", param_to_add)) - else: - transaction['fullPath'] = ''.join((transaction['fullPath'], "?", param_to_add)) -``` +.. code:: python -### Handling sessions + import json + import dredd_hooks as hooks -```python -import json -import dredd_hooks as hooks + stash = {} -stash = {} + # hook to retrieve session on a login + @hooks.after('Auth > /remoteauth/userpass > POST') + def stash_session_id(transaction): + parsed_body = json.loads(transaction['real']['body']) + stash['token'] = parsed_body['sessionId'] -# hook to retrieve session on a login -@hooks.after('Auth > /remoteauth/userpass > POST') -def stash_session_id(transaction): - parsed_body = json.loads(transaction['real']['body']) - stash['token'] = parsed_body['sessionId'] + # hook to set the session cookie in all following requests + @hooks.before_each + def add_session_cookie(transaction): + if 'token' in stash: + transaction['request']['headers']['Cookie'] = "id=" + stash['token'] -# hook to set the session cookie in all following requests -@hooks.before_each -def add_session_cookie(transaction): - if 'token' in stash: - transaction['request']['headers']['Cookie'] = "id=" + stash['token'] -``` +Remove trailing newline character in expected *plain text* bodies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. code:: python -### Remove trailing newline character in expected _plain text_ bodies + import dredd_hooks as hooks -```python -import dredd_hooks as hooks + @hooks.before_each + def remove_trailing_newline(transaction): + if transaction['expected']['headers']['Content-Type'] == 'text/plain': + transaction['expected']['body'] = transaction['expected']['body'].rstrip() -@hooks.before_each -def remove_trailing_newline(transaction): - if transaction['expected']['headers']['Content-Type'] == 'text/plain': - transaction['expected']['body'] = transaction['expected']['body'].rstrip() -``` +.. |Build Status| image:: https://travis-ci.org/apiaryio/dredd-hooks-python.svg?branch=master + :target: https://travis-ci.org/apiaryio/dredd-hooks-python diff --git a/docs/hooks-ruby.rst b/docs/hooks-ruby.rst index 423362a9b..48cad2d01 100644 --- a/docs/hooks-ruby.rst +++ b/docs/hooks-ruby.rst @@ -1,198 +1,217 @@ -# Writing Dredd Hooks In Ruby +.. _hooks-ruby: -[![Build Status](https://travis-ci.org/apiaryio/dredd-hooks-ruby.svg?branch=master)](https://travis-ci.org/apiaryio/dredd-hooks-ruby) +Writing Dredd Hooks In Ruby +=========================== -[GitHub repository](https://github.com/apiaryio/dredd-hooks-ruby) +|Build Status| -Ruby hooks are using [Dredd's hooks handler socket interface](hooks-new-language.md). For using Ruby hooks in Dredd you have to have [Dredd already installed](quickstart.md) +`GitHub repository `__ -## Installation +Ruby hooks are using :ref:`Dredd’s hooks handler socket interface `. For using Ruby hooks in Dredd you have to have :ref:`Dredd already installed ` -``` -$ gem install dredd_hooks -``` +Installation +------------ -## Usage +:: -``` -$ dredd apiary.apib http://127.0.0.1:3000 --language=ruby --hookfiles=./hooks*.rb -``` + $ gem install dredd_hooks -## API Reference +Usage +----- -Including module `Dredd::Hooks:Methods` expands current scope with methods +:: -1. `@before_each`, `before_each_validation`, `after_each` - - accepts a block as a first argument passing a [Transaction object](data-structures.md#transaction) as a first argument + $ dredd apiary.apib http://127.0.0.1:3000 --language=ruby --hookfiles=./hooks*.rb -2. `before`, `before_validation`, `after` - - accepts [transaction name](hooks.md#getting-transaction-names) as a first argument - - accepts a block as a second argument passing a [Transaction object](data-structures.md#transaction) as a first argument of it +API Reference +------------- -3. `before_all`, `after_all` - - accepts a block as a first argument passing an Array of [Transaction objects](data-structures.md#transaction) as a first argument +Including module ``Dredd::Hooks:Methods`` expands current scope with methods +1. ``@before_each``, ``before_each_validation``, ``after_each`` -Refer to [Dredd execution lifecycle](how-it-works.md#execution-life-cycle) to find when is each hook function executed. + - accepts a block as a first argument passing a :ref:`Transaction object ` as a first argument -### Using Ruby API +2. ``before``, ``before_validation``, ``after`` + + - accepts :ref:`transaction name ` as a first argument + - accepts a block as a second argument passing a :ref:`Transaction object ` as a first argument of it + +3. ``before_all``, ``after_all`` + + - accepts a block as a first argument passing an Array of :ref:`Transaction objects ` as a first argument + +Refer to :ref:`Dredd execution lifecycle ` to find when is each hook function executed. + +Using Ruby API +~~~~~~~~~~~~~~ Example usage of all methods in -```ruby -include DreddHooks::Methods +.. code:: ruby + + include DreddHooks::Methods + + before_all do |transactions| + puts 'before all' + end -before_all do |transactions| - puts 'before all' -end + before_each do |transaction| + puts 'before each' + end -before_each do |transaction| - puts 'before each' -end + before "Machines > Machines collection > Get Machines" do |transaction| + puts 'before' + end -before "Machines > Machines collection > Get Machines" do |transaction| - puts 'before' -end + before_each_validation do |transaction| + puts 'before each validation' + end -before_each_validation do |transaction| - puts 'before each validation' -end + before_validation "Machines > Machines collection > Get Machines" do |transaction| + puts 'before validations' + end -before_validation "Machines > Machines collection > Get Machines" do |transaction| - puts 'before validations' -end + after "Machines > Machines collection > Get Machines" do |transaction| + puts 'after' + end -after "Machines > Machines collection > Get Machines" do |transaction| - puts 'after' -end + after_each do |transaction| + puts 'after_each' + end -after_each do |transaction| - puts 'after_each' -end + after_all do |transactions| + puts 'after_all' + end -after_all do |transactions| - puts 'after_all' -end -``` +Examples +-------- -## Examples +How to Skip Tests +~~~~~~~~~~~~~~~~~ -### How to Skip Tests +Any test step can be skipped by setting ``skip`` property of the ``transaction`` object to ``true``. -Any test step can be skipped by setting `skip` property of the `transaction` object to `true`. +.. code:: ruby -```ruby -include DreddHooks::Methods + include DreddHooks::Methods -before "Machines > Machines collection > Get Machines" do |transaction| - transaction['skip'] = true -end -``` + before "Machines > Machines collection > Get Machines" do |transaction| + transaction['skip'] = true + end -### Sharing Data Between Steps in Request Stash +Sharing Data Between Steps in Request Stash +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you want to test some API workflow, you may pass data between test steps using the response stash. -```ruby -require 'json' -include DreddHooks::Methods +.. code:: ruby + + require 'json' + include DreddHooks::Methods + + response_stash = {} + + after "Machines > Machines collection > Create Machine" do |transaction| + # saving HTTP response to the stash + response_stash[transaction['name']] = transaction['real'] + do + + before "Machines > Machine > Delete a machine" do |transaction| + #reusing data from previous response here + parsed_body = JSON.parse response_stash['Machines > Machines collection > Create Machine'] + machine_id = parsed_body['id'] + + #replacing id in URL with stashed id from previous response + transaction['fullPath'].gsub! '42', machine_id + end + +Failing Tests Programmatically +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -response_stash = {} +You can fail any step by setting ``fail`` property on ``transaction`` object to ``true`` or any string with descriptive message. -after "Machines > Machines collection > Create Machine" do |transaction| - # saving HTTP response to the stash - response_stash[transaction['name']] = transaction['real'] -do +.. code:: ruby -before "Machines > Machine > Delete a machine" do |transaction| - #reusing data from previous response here - parsed_body = JSON.parse response_stash['Machines > Machines collection > Create Machine'] - machine_id = parsed_body['id'] + include DreddHooks::Methods - #replacing id in URL with stashed id from previous response - transaction['fullPath'].gsub! '42', machine_id -end -``` + before "Machines > Machines collection > Get Machines" do |transaction| + transaction['fail'] = "Some failing message" + end -### Failing Tests Programmatically +Modifying Transaction Request Body Prior to Execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can fail any step by setting `fail` property on `transaction` object to `true` or any string with descriptive message. +.. code:: ruby -```ruby -include DreddHooks::Methods + require 'json' + include DreddHooks::Methods -before "Machines > Machines collection > Get Machines" do |transaction| - transaction['fail'] = "Some failing message" -end -``` + before "Machines > Machines collection > Get Machines" do |transaction| + # parse request body from API description + request_body = JSON.parse transaction['request']['body'] -### Modifying Transaction Request Body Prior to Execution + # modify request body here + request_body['someKey'] = 'some new value' -```ruby -require 'json' -include DreddHooks::Methods + # stringify the new body to request + transaction['request']['body'] = request_body.to_json + end -before "Machines > Machines collection > Get Machines" do |transaction| - # parse request body from API description - request_body = JSON.parse transaction['request']['body'] +Adding or Changing URI Query Parameters to All Requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - # modify request body here - request_body['someKey'] = 'some new value' +.. code:: ruby - # stringify the new body to request - transaction['request']['body'] = request_body.to_json -end -``` + include DreddHooks::Methods -### Adding or Changing URI Query Parameters to All Requests + hooks.before_each do |transaction| -```ruby -include DreddHooks::Methods + # add query parameter to each transaction here + param_to_add = "api-key=23456" -hooks.before_each do |transaction| + if transaction['fullPath'].include('?') + transaction['fullPath'] += "&" + param_to_add + else + transaction['fullPath'] += "?" + param_to_add + end + end - # add query parameter to each transaction here - param_to_add = "api-key=23456" +Handling sessions +~~~~~~~~~~~~~~~~~ - if transaction['fullPath'].include('?') - transaction['fullPath'] += "&" + param_to_add - else - transaction['fullPath'] += "?" + param_to_add - end -end -``` +.. code:: ruby -### Handling sessions + require 'json' + include DreddHooks::Methods -```ruby -require 'json' -include DreddHooks::Methods + stash = {} -stash = {} + # hook to retrieve session on a login + hooks.after 'Auth > /remoteauth/userpass > POST' do |transaction| + parsed_body = JSON.parse transaction['real']['body'] + stash['token'] = parsed_body['sessionId'] + end -# hook to retrieve session on a login -hooks.after 'Auth > /remoteauth/userpass > POST' do |transaction| - parsed_body = JSON.parse transaction['real']['body'] - stash['token'] = parsed_body['sessionId'] -end + # hook to set the session cookie in all following requests + hooks.beforeEach do |transaction| + unless stash['token'].nil? + transaction['request']['headers']['Cookie'] = "id=" + stash['token'] + end + end -# hook to set the session cookie in all following requests -hooks.beforeEach do |transaction| - unless stash['token'].nil? - transaction['request']['headers']['Cookie'] = "id=" + stash['token'] - end -end -``` +Remove trailing newline character for in expected plain text bodies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. code:: ruby -### Remove trailing newline character for in expected plain text bodies + include DreddHooks::Methods -```ruby -include DreddHooks::Methods + before_each do |transaction| + if transaction['expected']['headers']['Content-Type'] == 'text/plain' + transaction['expected']['body'] = transaction['expected']['body'].gsub(/^\s+|\s+$/g, "") + end + end -before_each do |transaction| - if transaction['expected']['headers']['Content-Type'] == 'text/plain' - transaction['expected']['body'] = transaction['expected']['body'].gsub(/^\s+|\s+$/g, "") - end -end -``` +.. |Build Status| image:: https://travis-ci.org/apiaryio/dredd-hooks-ruby.svg?branch=master + :target: https://travis-ci.org/apiaryio/dredd-hooks-ruby diff --git a/docs/hooks-rust.rst b/docs/hooks-rust.rst index ac2cb24b4..67abbd637 100644 --- a/docs/hooks-rust.rst +++ b/docs/hooks-rust.rst @@ -1,180 +1,197 @@ -# Writing Dredd Hooks In Rust +.. _hooks-rust: -[![Crates.io](https://img.shields.io/crates/v/dredd-hooks.svg)](https://crates.io/crates/dredd-hooks) +Writing Dredd Hooks In Rust +=========================== -[GitHub repository](https://github.com/hobofan/dredd-hooks-rust) +|Crates.io| -Rust hooks are using [Dredd's hooks handler socket interface](hooks-new-language.md). For using Rust hooks in Dredd you have to have [Dredd already installed](quickstart.md). The Rust library is called `dredd-hooks` and the correspondig binary `dredd-hooks-rust`. +`GitHub repository `__ -## Installation +Rust hooks are using :ref:`Dredd’s hooks handler socket interface `. For using Rust hooks in Dredd you have to have :ref:`Dredd already installed `. The Rust library is called ``dredd-hooks`` and the correspondig binary ``dredd-hooks-rust``. -``` -$ cargo install dredd-hooks -``` +Installation +------------ -## Usage +:: -Using Dredd with Rust is slightly different to other languages, as a binary needs to be compiled for execution. The --hookfiles flags should point to compiled hook binaries. See below for an example hooks.rs file to get an idea of what the source file behind the Rust binary would look like. + $ cargo install dredd-hooks -``` -$ dredd apiary.apib http://127.0.0.1:3000 --server=./rust-web-server-to-test --language=rust --hookfiles=./hook-file-binary -``` +Usage +----- -## API Reference +Using Dredd with Rust is slightly different to other languages, as a binary needs to be compiled for execution. The –hookfiles flags should point to compiled hook binaries. See below for an example hooks.rs file to get an idea of what the source file behind the Rust binary would look like. -In order to get a general idea of how the Rust Hooks work, the main executable from the package `dredd-hooks` is an HTTP Server that Dredd communicates with and an RPC client. Each hookfile then acts as a corresponding RPC server. So when Dredd notifies the Hooks server what transaction event is occuring the hooks server will execute all registered hooks on each of the hookfiles RPC servers. +:: -You’ll need to know a few things about the `HooksServer` type in the `dredd-hooks` package. + $ dredd apiary.apib http://127.0.0.1:3000 --server=./rust-web-server-to-test --language=rust --hookfiles=./hook-file-binary -1. The `HooksServer` type is how you can define event callbacks such as `beforeEach`, `afterAll`, etc.. +API Reference +------------- -2. To get a `HooksServer` struct you must do the following; +In order to get a general idea of how the Rust Hooks work, the main executable from the package ``dredd-hooks`` is an HTTP Server that Dredd communicates with and an RPC client. Each hookfile then acts as a corresponding RPC server. So when Dredd notifies the Hooks server what transaction event is occuring the hooks server will execute all registered hooks on each of the hookfiles RPC servers. -```rust -extern crate dredd_hooks; +You’ll need to know a few things about the ``HooksServer`` type in the ``dredd-hooks`` package. -use dredd_hooks::{HooksServer}; +1. The ``HooksServer`` type is how you can define event callbacks such as ``beforeEach``, ``afterAll``, etc.. -fn main() { - let mut hooks = HooksServer::new(); +2. To get a ``HooksServer`` struct you must do the following; - // Define all your event callbacks here +.. code:: rust - // HooksServer::start_from_env will block and allow the RPC server - // to receive messages from the main `dredd-hooks-rust` process. - HooksServer::start_from_env(hooks); -} -``` + extern crate dredd_hooks; -3. Callbacks receive a `Transaction` instance, or an array of them. + use dredd_hooks::{HooksServer}; -### Runner Callback Events + fn main() { + let mut hooks = HooksServer::new(); -The `HooksServer` type has the following callback methods. + // Define all your event callbacks here -1. `before_each`, `before_each_validation`, `after_each` - - accepts a function as a first argument passing a [Transaction object](data-structures.md#transaction) as a first argument + // HooksServer::start_from_env will block and allow the RPC server + // to receive messages from the main `dredd-hooks-rust` process. + HooksServer::start_from_env(hooks); + } -2. `before`, `before_validation`, `after` - - accepts [transaction name](hooks.md#getting-transaction-names) as a first argument - - accepts a function as a second argument passing a [Transaction object](data-structures.md#transaction) as a first argument of it +3. Callbacks receive a ``Transaction`` instance, or an array of them. -3. `before_all`, `after_all` - - accepts a function as a first argument passing a `Vec` of [Transaction objects](data-structures.md#transaction) as a first argument +Runner Callback Events +~~~~~~~~~~~~~~~~~~~~~~ -Refer to [Dredd execution lifecycle](how-it-works.md#execution-life-cycle) to find when each hook callback is executed. +The ``HooksServer`` type has the following callback methods. -### Using the Rust API +1. ``before_each``, ``before_each_validation``, ``after_each`` + + - accepts a function as a first argument passing a :ref:`Transaction object ` as a first argument + +2. ``before``, ``before_validation``, ``after`` + + - accepts :ref:`transaction name ` as a first argument + - accepts a function as a second argument passing a :ref:`Transaction object ` as a first argument of it + +3. ``before_all``, ``after_all`` + + - accepts a function as a first argument passing a ``Vec`` of :ref:`Transaction objects ` as a first argument + +Refer to :ref:`Dredd execution lifecycle ` to find when each hook callback is executed. + +Using the Rust API +~~~~~~~~~~~~~~~~~~ Example usage of all methods. -```rust -extern crate dredd_hooks; - -use dredd_hooks::{HooksServer}; - -fn main() { - let mut hooks = HooksServer::new(); - hooks.before("/message > GET", Box::new(move |tr| { - println!("before hook handled"); - tr - })); - hooks.after("/message > GET", Box::new(move |tr| { - println!("after hook handled"); - tr - })); - hooks.before_validation("/message > GET", Box::new(move |tr| { - println!("before validation hook handled"); - tr - })); - hooks.before_all(Box::new(move |tr| { - println!("before all hook handled"); - tr - })); - hooks.after_all(Box::new(move |tr| { - println!("after all hook handled"); - tr - })); - hooks.before_each(Box::new(move |tr| { - println!("before each hook handled"); - tr - })); - hooks.before_each_validation(Box::new(move |tr| { - println!("before each validation hook handled"); - tr - })); - hooks.after_each(Box::new(move |tr| { - println!("after each hook handled"); - tr - })); - HooksServer::start_from_env(hooks); -} -``` - -## Examples - -### How to Skip Tests - -Any test step can be skipped by setting the value of the `skip` field of the `Transaction` instance to `true`. - -```rust -extern crate dredd_hooks; - -use dredd_hooks::{HooksServer}; - -fn main() { - let mut hooks = HooksServer::new(); - - // Runs only before the "/message > GET" test. - hooks.before("/message > GET", Box::new(|mut tr| { - // Set the skip flag on this test. - tr.insert("skip".to_owned(), true.into()); - // Hooks must always return the (modified) Transaction(s) that were passed in. - tr - })); - HooksServer::start_from_env(hooks); -} -``` - -### Failing Tests Programmatically - -You can fail any step by setting the value of the `fail` field of the `Transaction` instance to `true` or any string with a descriptive message. - -```rust -extern crate dredd_hooks; - -use dredd_hooks::{HooksServer}; - -fn main() { - let mut hooks = HooksServer::new(); - hooks.before("/message > GET", Box::new(|mut tr| { - // .into() can be used as an easy way to convert - // your value into the desired Json type. - tr.insert("fail".to_owned(), "Yay! Failed!".into()); - tr - })); - HooksServer::start_from_env(hooks); -} -``` - -### Modifying the Request Body Prior to Execution - -```rust -extern crate dredd_hooks; - -use dredd_hooks::{HooksServer}; - -fn main() { - let mut hooks = HooksServer::new(); - hooks.before("/message > GET", Box::new(|mut tr| { - // Try to access the "request" key as an object. - // (This will panic should the "request" key not be present.) - tr["request"].as_object_mut().unwrap() - .insert("body".to_owned(), "Hello World!".into()); - - tr - })); - HooksServer::start_from_env(hooks); -} - -``` +.. code:: rust + + extern crate dredd_hooks; + + use dredd_hooks::{HooksServer}; + + fn main() { + let mut hooks = HooksServer::new(); + hooks.before("/message > GET", Box::new(move |tr| { + println!("before hook handled"); + tr + })); + hooks.after("/message > GET", Box::new(move |tr| { + println!("after hook handled"); + tr + })); + hooks.before_validation("/message > GET", Box::new(move |tr| { + println!("before validation hook handled"); + tr + })); + hooks.before_all(Box::new(move |tr| { + println!("before all hook handled"); + tr + })); + hooks.after_all(Box::new(move |tr| { + println!("after all hook handled"); + tr + })); + hooks.before_each(Box::new(move |tr| { + println!("before each hook handled"); + tr + })); + hooks.before_each_validation(Box::new(move |tr| { + println!("before each validation hook handled"); + tr + })); + hooks.after_each(Box::new(move |tr| { + println!("after each hook handled"); + tr + })); + HooksServer::start_from_env(hooks); + } + +Examples +-------- + +How to Skip Tests +~~~~~~~~~~~~~~~~~ + +Any test step can be skipped by setting the value of the ``skip`` field of the ``Transaction`` instance to ``true``. + +.. code:: rust + + extern crate dredd_hooks; + + use dredd_hooks::{HooksServer}; + + fn main() { + let mut hooks = HooksServer::new(); + + // Runs only before the "/message > GET" test. + hooks.before("/message > GET", Box::new(|mut tr| { + // Set the skip flag on this test. + tr.insert("skip".to_owned(), true.into()); + // Hooks must always return the (modified) Transaction(s) that were passed in. + tr + })); + HooksServer::start_from_env(hooks); + } + +Failing Tests Programmatically +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can fail any step by setting the value of the ``fail`` field of the ``Transaction`` instance to ``true`` or any string with a descriptive message. + +.. code:: rust + + extern crate dredd_hooks; + + use dredd_hooks::{HooksServer}; + + fn main() { + let mut hooks = HooksServer::new(); + hooks.before("/message > GET", Box::new(|mut tr| { + // .into() can be used as an easy way to convert + // your value into the desired Json type. + tr.insert("fail".to_owned(), "Yay! Failed!".into()); + tr + })); + HooksServer::start_from_env(hooks); + } + +Modifying the Request Body Prior to Execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: rust + + extern crate dredd_hooks; + + use dredd_hooks::{HooksServer}; + + fn main() { + let mut hooks = HooksServer::new(); + hooks.before("/message > GET", Box::new(|mut tr| { + // Try to access the "request" key as an object. + // (This will panic should the "request" key not be present.) + tr["request"].as_object_mut().unwrap() + .insert("body".to_owned(), "Hello World!".into()); + + tr + })); + HooksServer::start_from_env(hooks); + } + +.. |Crates.io| image:: https://img.shields.io/crates/v/dredd-hooks.svg + :target: https://crates.io/crates/dredd-hooks diff --git a/docs/hooks.rst b/docs/hooks.rst index 5eb0758f8..e0852d3d0 100644 --- a/docs/hooks.rst +++ b/docs/hooks.rst @@ -1,100 +1,105 @@ -# Hook Scripts +.. _hooks: -Similar to any other testing framework, Dredd supports executing code around each test step. -Hooks are code blocks executed in defined stage of [execution lifecycle](how-it-works.md#execution-life-cycle). -In the hooks code you have an access to compiled HTTP [transaction object](#transaction-object-structure) which you can modify. +Hook Scripts +============ + +Similar to any other testing framework, Dredd supports executing code around each test step. Hooks are code blocks executed in defined stage of :ref:`execution lifecycle `. In the hooks code you have an access to compiled HTTP :ref:`transaction object ` which you can modify. Hooks are usually used for: -- loading db fixtures -- cleanup after test step or steps -- handling authentication and sessions -- passing data between transactions (saving state from responses to _stash_) -- modifying request generated from API description -- changing generated expectations -- setting custom expectations -- debugging via logging stuff +- loading db fixtures +- cleanup after test step or steps +- handling authentication and sessions +- passing data between transactions (saving state from responses to *stash*) +- modifying request generated from API description +- changing generated expectations +- setting custom expectations +- debugging via logging stuff -## Languages +Languages +--------- You can interact with your server implementation in following languages: -- [Go](hooks-go.md) -- [JavaScript (Sandboxed)](hooks-js-sandbox.md) -- [Node.js](hooks-nodejs.md) -- [Perl](hooks-perl.md) -- [PHP](hooks-php.md) -- [Python](hooks-python.md) -- [Ruby](hooks-ruby.md) -- [Rust](hooks-rust.md) - -Dredd doesn't speak your language? [**It's very easy to write support for your language.**](hooks-new-language.md) Your contribution is more than welcome! +- :ref:`Go ` +- :ref:`JavaScript (Sandboxed) ` +- :ref:`Node.js ` +- :ref:`Perl ` +- :ref:`PHP ` +- :ref:`Python ` +- :ref:`Ruby ` +- :ref:`Rust ` +Dredd doesn’t speak your language? :ref:`It’s very easy to write support for your language. ` Your contribution is more than welcome! -## Using Hook Files +Using Hook Files +---------------- -To use a hook file with Dredd, use the `--hookfiles` flag in the command line. -You can use this flag multiple times or use a [glob](https://www.npmjs.com/package/glob) expression for loading multiple hook files. Dredd executes hook files in alphabetical order. +To use a hook file with Dredd, use the ``--hookfiles`` flag in the command line. You can use this flag multiple times or use a `glob `__ expression for loading multiple hook files. Dredd executes hook files in alphabetical order. Example: -```sh -$ dredd single-get.apib http://machines.apiary.io --hookfiles=*_hooks.* -``` +.. code:: sh + + $ dredd single-get.apib http://machines.apiary.io --hookfiles=*_hooks.* + +.. _getting-transaction-names: -## Getting Transaction Names +Getting Transaction Names +------------------------- -For addressing specific test steps is used the __transaction names__ of the compiled HTTP transactions (_actions_) from the API description. +For addressing specific test steps is used the **transaction names** of the compiled HTTP transactions (*actions*) from the API description. -In order to retrieve transaction names please run Dredd with the `--names` argument last and it will print all available names of transactions. +In order to retrieve transaction names please run Dredd with the ``--names`` argument last and it will print all available names of transactions. -For example, given an API Blueprint file `api-description.apib` as following: +For example, given an API Blueprint file ``api-description.apib`` as following: -```apiblueprint -FORMAT: 1A +.. code:: apiblueprint -# Machines API + FORMAT: 1A -# Group Machines + # Machines API -# Machines collection [/machines] + # Group Machines -## Get Machines [GET] + # Machines collection [/machines] -- Response 200 (application/json; charset=utf-8) + ## Get Machines [GET] - [{"type": "bulldozer", "name": "willy"}] + - Response 200 (application/json; charset=utf-8) -``` + [{"type": "bulldozer", "name": "willy"}] Run this command to retrieve all transaction names: -```sh -$ dredd single-get.apib http://machines.apiary.io --names -info: Machines > Machines collection > Get Machines -``` +.. code:: sh -The `Machines > Machines collection > Get Machines` is the name of a transaction which you can use in your hooks. The same approach works also for Swagger documents. + $ dredd single-get.apib http://machines.apiary.io --names + info: Machines > Machines collection > Get Machines -## Types of Hooks +The ``Machines > Machines collection > Get Machines`` is the name of a transaction which you can use in your hooks. The same approach works also for Swagger documents. -Dredd supports following types of hooks: +.. _types-of-hooks: + +Types of Hooks +-------------- -- `beforeAll` called at the beginning of the whole test run -- `beforeEach` called before each HTTP transaction -- `before` called before some specific HTTP transaction -- `beforeEachValidation` called before each HTTP transaction is validated -- `beforeValidation` called before some specific HTTP transaction is validated -- `after` called after some specific HTTP transaction regardless its result -- `afterEach` called after each HTTP transaction -- `afterAll` called after whole test run +Dredd supports following types of hooks: -Refer to [Dredd execution lifecycle](how-it-works.md#execution-life-cycle) when is each hook executed. +- ``beforeAll`` called at the beginning of the whole test run +- ``beforeEach`` called before each HTTP transaction +- ``before`` called before some specific HTTP transaction +- ``beforeEachValidation`` called before each HTTP transaction is validated +- ``beforeValidation`` called before some specific HTTP transaction is validated +- ``after`` called after some specific HTTP transaction regardless its result +- ``afterEach`` called after each HTTP transaction +- ``afterAll`` called after whole test run -### Transaction Object Structure +Refer to :ref:`Dredd execution lifecycle ` when is each hook executed. -The main purpose of hooks is to work with the transaction object they get as the first argument, in order to inspect or modify Dredd's behavior. See [transaction object reference](data-structures.md#transaction) to learn more about its contents. +.. _transaction-object-structure: +Transaction Object Structure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -[UTC ISO 8601]: http://wikipedia.org/wiki/ISO_8601 -[Gavel]: https://relishapp.com/apiary/gavel/docs +The main purpose of hooks is to work with the transaction object they get as the first argument, in order to inspect or modify Dredd’s behavior. See :ref:`transaction object reference ` to learn more about its contents. diff --git a/docs/how-it-works.rst b/docs/how-it-works.rst index d342f5945..bd945809b 100644 --- a/docs/how-it-works.rst +++ b/docs/how-it-works.rst @@ -1,4 +1,7 @@ -# How It Works +.. _how-it-works: + +How It Works +============ In a nutshell, Dredd does following: @@ -8,261 +11,250 @@ In a nutshell, Dredd does following: 4. checks whether API responses match the documented responses, 5. reports the results. -## Versioning +Versioning +---------- + +Dredd follows `Semantic Versioning `__. To ensure certain stability of your Dredd installation (e.g. in CI), pin the version accordingly. You can also use release tags: -Dredd follows [Semantic Versioning][]. To ensure certain stability of your Dredd installation (e.g. in CI), pin the version accordingly. You can also use release tags: +- ``npm install dredd`` - Installs the latest published version including experimental pre-release versions. +- ``npm install dredd@stable`` - Skips experimental pre-release versions. Recommended for CI installations. -- `npm install dredd` - Installs the latest published version including experimental pre-release versions. -- `npm install dredd@stable` - Skips experimental pre-release versions. Recommended for CI installations. +If the ``User-Agent`` header isn’t overridden in the API description document, Dredd uses it for sending information about its version number along with every HTTP request it does. -If the `User-Agent` header isn't overridden in the API description document, Dredd uses it for sending information about its version number along with every HTTP request it does. +.. _execution-life-cycle: -## Execution Life Cycle +Execution Life Cycle +-------------------- Following execution life cycle documentation should help you to understand how Dredd works internally and which action goes after which. 1. Load and parse API description documents - - Report parse errors and warnings + + - Report parse errors and warnings + 2. Pre-run API description check - - Missing example values for URI template parameters - - Required parameters present in URI - - Report non-parseable JSON bodies - - Report invalid URI parameters - - Report invalid URI templates + + - Missing example values for URI template parameters + - Required parameters present in URI + - Report non-parseable JSON bodies + - Report invalid URI parameters + - Report invalid URI templates + 3. Compile HTTP transactions from API description documents - - Inherit headers - - Inherit parameters - - Expand URI templates with parameters -4. Load [hooks](hooks.md) + + - Inherit headers + - Inherit parameters + - Expand URI templates with parameters + +4. Load :ref:`hooks ` 5. Test run - - Report test run `start` - - Run `beforeAll` hooks - - For each compiled transaction: - - Report `test start` - - Run `beforeEach` hook - - Run `before` hook - - Send HTTP request - - Receive HTTP response - - Run `beforeEachValidation` hook - - Run `beforeValidation` hook - - [Perform validation](#automatic-expectations) - - Run `after` hook - - Run `afterEach` hook - - Report `test end` with result for in-progress reporting - - Run `afterAll` hooks -6. Report test run `end` with result statistics -## Automatic Expectations + - Report test run ``start`` + - Run ``beforeAll`` hooks + - For each compiled transaction: + + - Report ``test start`` + - Run ``beforeEach`` hook + - Run ``before`` hook + - Send HTTP request + - Receive HTTP response + - Run ``beforeEachValidation`` hook + - Run ``beforeValidation`` hook + - :ref:`Perform validation ` + - Run ``after`` hook + - Run ``afterEach`` hook + - Report ``test end`` with result for in-progress reporting + + - Run ``afterAll`` hooks + +6. Report test run ``end`` with result statistics -Dredd automatically generates expectations on HTTP responses based on examples in the API description with use of [Gavel.js][] library. Please refer to [Gavel][] rules if you want know more. +.. _automatic-expectations: -### Response Headers Expectations +Automatic Expectations +---------------------- -- All headers specified in the API description must be present in the response. -- Names of headers are validated in the case-insensitive way. -- Only values of headers significant for content negotiation are validated. -- All other headers values can differ. +Dredd automatically generates expectations on HTTP responses based on examples in the API description with use of `Gavel.js `__ library. Please refer to `Gavel `__ rules if you want know more. -When using [Swagger][], headers are taken from [`response.headers`][response-headers]. HTTP headers significant for content negotiation are inferred according to following rules: +Response Headers Expectations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [`produces`][produces] is propagated as response's `Content-Type` header. -- Response's `Content-Type` header overrides any `produces`. +- All headers specified in the API description must be present in the response. +- Names of headers are validated in the case-insensitive way. +- Only values of headers significant for content negotiation are validated. +- All other headers values can differ. -### Response Body Expectations +When using `Swagger `__, headers are taken from ```response.headers`` `__. HTTP headers significant for content negotiation are inferred according to following rules: + +- ```produces`` `__ is propagated as response’s ``Content-Type`` header. +- Response’s ``Content-Type`` header overrides any ``produces``. + +Response Body Expectations +~~~~~~~~~~~~~~~~~~~~~~~~~~ If the HTTP response body is JSON, Dredd validates only its structure. Bodies in any other format are validated as plain text. -To validate the structure Dredd uses [JSON Schema][] inferred from the API description under test. The effective JSON Schema is taken from following places (the order goes from the highest priority to the lowest): +To validate the structure Dredd uses `JSON Schema `__ inferred from the API description under test. The effective JSON Schema is taken from following places (the order goes from the highest priority to the lowest): + +API Blueprint +^^^^^^^^^^^^^ -#### API Blueprint +1. `Schema `__ section - provided custom JSON Schema (`Draft v4 `__ and `v3 `__) will be used. +2. `Attributes `__ section with data structure description in `MSON `__ - API Blueprint parser automatically generates JSON Schema from MSON. +3. `Body `__ section with sample JSON payload - `Gavel.js `__, which is responsible for validation in Dredd, automatically infers some basic expectations described below. -1. [`+ Schema`][schema-section] section - provided custom JSON Schema ([Draft v4][] and [v3][Draft v3]) will be used. -2. [`+ Attributes`][attributes-section] section with data structure description in [MSON][] - API Blueprint parser automatically generates JSON Schema from MSON. -3. [`+ Body`][body-section] section with sample JSON payload - [Gavel.js][], which is responsible for validation in Dredd, automatically infers some basic expectations described below. +This order `exactly follows the API Blueprint specification `__. -This order [exactly follows the API Blueprint specification][body-schema-attributes]. +Swagger +^^^^^^^ -#### Swagger +1. ``response.schema`` (`docs `__) - provided JSON Schema will be used. +2. ``response.examples`` (`docs `__) with sample JSON payload - `Gavel.js `__, which is responsible for validation in Dredd, automatically infers some basic expectations described below. -1. [`response.schema`][response-schema] - provided JSON Schema will be used. -2. [`response.examples`][response-examples] with sample JSON payload - [Gavel.js][], which is responsible for validation in Dredd, automatically infers some basic expectations described below. +.. _gavels-expectations: - +Gavel’s Expectations +^^^^^^^^^^^^^^^^^^^^ -#### Gavel's Expectations +- All JSON keys on any level given in the sample must be present in the response’s JSON. +- Response’s JSON values must be of the same JSON primitive type. +- All JSON values can differ. +- Arrays can have additional items, type or structure of the items is not validated. +- Plain text must match perfectly. -- All JSON keys on any level given in the sample must be present in the response's JSON. -- Response's JSON values must be of the same JSON primitive type. -- All JSON values can differ. -- Arrays can have additional items, type or structure of the items is not validated. -- Plain text must match perfectly. +Custom Expectations +~~~~~~~~~~~~~~~~~~~ -### Custom Expectations +You can make your own custom expectations in :ref:`hooks `. For instance, check out how to employ :ref:`Chai.js assertions `. -You can make your own custom expectations in [hooks](hooks.md). For instance, check out how to employ [Chai.js assertions](hooks-nodejs.md#using-chai-assertions). +Making Your API Description Ready for Testing +--------------------------------------------- -## Making Your API Description Ready for Testing +It’s very likely that your API description document will not be testable **as is**. This section should help you to learn how to solve the most common issues. -It's very likely that your API description document will not be testable __as is__. This section should help you to learn how to solve the most common issues. +URI Parameters +~~~~~~~~~~~~~~ -### URI Parameters +Both `API Blueprint `__ and `Swagger `__ allow usage of URI templates (API Blueprint fully implements `RFC6570 `__, Swagger templates are much simpler). In order to have an API description which is testable, you need to describe all required parameters used in URI (path or query) and provide sample values to make Dredd able to expand URI templates with given sample values. Following rules apply when Dredd interpolates variables in a templated URI, ordered by precedence: -Both [API Blueprint][] and [Swagger][] allow usage of URI templates (API Blueprint fully implements [RFC6570][], Swagger templates are much simpler). In order to have an API description which is testable, you need to describe all required parameters used in URI (path or query) and provide sample values to make Dredd able to expand URI templates with given sample values. Following rules apply when Dredd interpolates variables in a templated URI, ordered by precedence: +1. Sample value, in Swagger available as the ``x-example`` vendor extension property (:ref:`docs `). +2. Value of ``default``. +3. First value from ``enum``. -1. Sample value (available in Swagger as [`x-example` vendor extension property](how-to-guides.md#example-values-for-request-parameters)). -2. Value of `default`. -3. First value from `enum`. +If Dredd isn’t able to infer any value for a required parameter, it will terminate the test run and complain that the parameter is *ambiguous*. -If Dredd isn't able to infer any value for a required parameter, it will terminate the test run and complain that the parameter is _ambiguous_. + **Note:** The implementation of API Blueprint’s request-specific parameters is still in progress and there’s only experimental support for it in Dredd as of now. -> **Note:** The implementation of API Blueprint's request-specific parameters is still in progress and there's only experimental support for it in Dredd as of now. +Request Headers +~~~~~~~~~~~~~~~ -### Request Headers +In `Swagger `__ documents, HTTP headers are inferred from ``"in": "header"`` parameters (`docs `__). HTTP headers significant for content negotiation are inferred according to following rules: -In [Swagger][] documents, HTTP headers are inferred from [`"in": "header"` parameters][parameters]. HTTP headers significant for content negotiation are inferred according to following rules: +- ``consumes`` (`docs `__) is propagated as request’s ``Content-Type`` header. +- ``produces`` (`docs `__) is propagated as request’s ``Accept`` header. +- If request body parameters are specified as ``"in": "formData"``, request’s ``Content-Type`` header is set to ``application/x-www-form-urlencoded``. -- [`consumes`][consumes] is propagated as request's `Content-Type` header. -- [`produces`][produces] is propagated as request's `Accept` header. -- If request body parameters are specified as `"in": "formData"`, request's `Content-Type` header is set to `application/x-www-form-urlencoded`. +.. -> **Note:** Processing `"in": "header"` parameters and inferring `application/x-www-form-urlencoded` from `"in": "formData"` parameters is not implemented yet ([apiaryio/fury-adapter-swagger#68](https://github.com/apiaryio/fury-adapter-swagger/issues/68), [apiaryio/fury-adapter-swagger#67](https://github.com/apiaryio/fury-adapter-swagger/issues/67)). + **Note:** Processing ``"in": "header"`` parameters and inferring ``application/x-www-form-urlencoded`` from ``"in": "formData"`` parameters is not implemented yet (`apiaryio/fury-adapter-swagger#68 `__, `apiaryio/fury-adapter-swagger#67 `__). -### Request Body +Request Body +~~~~~~~~~~~~ -#### API Blueprint +API Blueprint +^^^^^^^^^^^^^ The effective request body is taken from following places (the order goes from the highest priority to the lowest): -1. [`+ Body`][body-section] section with sample JSON payload. -2. [`+ Attributes`][attributes-section] section with data structure description in [MSON][] - API Blueprint parser automatically generates sample JSON payload from MSON. +1. `Body `__ section with sample JSON payload. +2. `Attributes `__ section with data structure description in `MSON `__ - API Blueprint parser automatically generates sample JSON payload from MSON. -This order [exactly follows the API Blueprint specification][body-schema-attributes]. +This order `exactly follows the API Blueprint specification `__. -#### Swagger +Swagger +^^^^^^^ -The effective request body is inferred from [`"in": "body"` and `"in": "formData"` parameters][parameters]. +The effective request body is inferred from ``"in": "body"`` and ``"in": "formData"`` parameters (`docs `__). -If body parameter has [`schema.example`][schema-example], it is used as a raw JSON sample for the request body. If it's not present, Dredd's [Swagger Adapter][] generates sample values from the JSON Schema provided in the [`schema`][schema] property. Following rules apply when the adapter fills values of the properties, ordered by precedence: +If body parameter has ``schema.example`` (`docs `__), it is used as a raw JSON sample for the request body. If it’s not present, Dredd’s `Swagger Adapter `__ generates sample values from the JSON Schema provided in the ``schema`` (`docs `__) property. Following rules apply when the adapter fills values of the properties, ordered by precedence: -1. Value of `default`. -2. First value from `enum`. +1. Value of ``default``. +2. First value from ``enum``. 3. Dummy, generated value. -### Empty Response Body +.. _empty-response-body: + +Empty Response Body +~~~~~~~~~~~~~~~~~~~ + +If there is no body example or schema specified for the response in your API description document, Dredd won’t imply any assertions. Any server response will be considered as valid. -If there is no body example or schema specified for the response in your API description document, Dredd won't imply any assertions. Any server response will be considered as valid. +If you want to enforce the incoming body is empty, you can use :ref:`hooks `: -If you want to enforce the incoming body is empty, you can use [hooks](hooks.md): +.. code:: javascript -```javascript -:[hooks example](../test/fixtures/response/empty-body-hooks.js) -``` + :[hooks example](../test/fixtures/response/empty-body-hooks.js) -In case of responses with 204 or 205 status codes Dredd still behaves the same way, but it warns about violating the [RFC7231](https://tools.ietf.org/html/rfc7231) when the responses have non-empty bodies. +In case of responses with 204 or 205 status codes Dredd still behaves the same way, but it warns about violating the `RFC7231 `__ when the responses have non-empty bodies. -## Choosing HTTP Transactions +.. _choosing-http-transactions: -#### API Blueprint +Choosing HTTP Transactions +-------------------------- -While [API Blueprint][] allows specifying multiple requests and responses in any -combination (see specification for the [action section][action-section]), Dredd -currently supports just separated HTTP transaction pairs like this: +API Blueprint +~~~~~~~~~~~~~ -``` -+ Request -+ Response +While `API Blueprint `__ allows specifying multiple requests and responses in any combination (see specification for the `action section `__), Dredd currently supports just separated HTTP transaction pairs like this: -+ Request -+ Response -``` +:: + + + Request + + Response + + + Request + + Response In other words, Dredd always selects just the first response for each request. -> **Note:** Improving the support for multiple requests and responses is under development. Refer to issues [#25](https://github.com/apiaryio/dredd/issues/25) and [#78](https://github.com/apiaryio/dredd/issues/78) for details. Support for URI parameters specific to a single request within one action is also limited. Solving [#227](https://github.com/apiaryio/dredd/issues/227) should unblock many related problems. Also see [Multiple Requests and Responses](how-to-guides.md#multiple-requests-and-responses) guide for workarounds. + **Note:** Improving the support for multiple requests and responses is under development. Refer to issues `#25 `__ and `#78 `__ for details. Support for URI parameters specific to a single request within one action is also limited. Solving `#227 `__ should unblock many related problems. Also see `Multiple Requests and Responses `__ guide for workarounds. + +Swagger +~~~~~~~ -#### Swagger +The `Swagger `__ format allows to specify multiple responses for a single operation. By default Dredd tests only responses with ``2xx`` status codes. Responses with other codes are marked as *skipped* and can be activated in `hooks `__ - see the `Multiple Requests and Responses `__ how-to guide. -The [Swagger][] format allows to specify multiple responses for a single operation. -By default Dredd tests only responses with `2xx` status codes. Responses with other -codes are marked as _skipped_ and can be activated in [hooks](hooks.md) - see the [Multiple Requests and Responses](how-to-guides.md#multiple-requests-and-responses) how-to guide. +In ``produces`` (`docs `__) and ``consumes`` (`docs `__), only JSON media types are supported. Only the first JSON media type in ``produces`` is effective, others are skipped. Other media types are respected only when provided with `explicit examples `__. -In [`produces`][produces] and [`consumes`][consumes], only JSON media types are supported. Only the first JSON media type in `produces` is effective, others are skipped. Other media types are respected only when provided with [explicit examples][response-examples]. +`Default response `__ is ignored by Dredd unless it is the only available response. In that case, the default response is assumed to have HTTP 200 status code. -[Default response][default-responses] is ignored by Dredd unless it is the only available response. In that case, the default response is assumed to have HTTP 200 status code. +.. _security: -## Security +Security +-------- Depending on what you test and how, output of Dredd may contain sensitive data. -Mind that if you run Dredd in a CI server provided as a service (such as [CircleCI][], [Travis CI][], etc.), you are disclosing the CLI output of Dredd to third parties. +Mind that if you run Dredd in a CI server provided as a service (such as `CircleCI `__, `Travis CI `__, etc.), you are disclosing the CLI output of Dredd to third parties. -When using [Apiary Reporter and Apiary Tests](how-to-guides.md#using-apiary-reporter-and-apiary-tests), you are sending your testing data to [Apiary][] (Dredd creators and maintainers). See their [Terms of Service][] and [Privacy Policy][]. Which data exactly is being sent to Apiary? +When using :ref:`Apiary Reporter and Apiary Tests `, you are sending your testing data to `Apiary `__ (Dredd creators and maintainers). See their `Terms of Service `__ and `Privacy Policy `__. Which data exactly is being sent to Apiary? -- **Complete API description under test.** This means your API Blueprint or Swagger files. The API description is stored encrypted in Apiary. -- **Complete testing results.** Those can contain details of all requests made to the server under test and their responses. Apiary stores this data unencrypted, even if the original communication between Dredd and the API server under test happens to be over HTTPS. See [Apiary Reporter Test Data](data-structures.md#apiary-reporter-test-data) for detailed description of what is sent. You can [sanitize it before it gets sent](how-to-guides.md#removing-sensitive-data-from-test-reports). -- **Little meta data about your environment.** Contents of environment variables `TRAVIS`, `CIRCLE`, `CI`, `DRONE`, `BUILD_ID`, `DREDD_AGENT`, `USER`, and `DREDD_HOSTNAME` can be sent to Apiary. Your [hostname][], version of your Dredd installation, and [type][os-type], [release][os-release] and [architecture][os-arch] of your OS can be sent as well. Apiary stores this data unencrypted. +- **Complete API description under test.** This means your API Blueprint or Swagger files. The API description is stored encrypted in Apiary. +- **Complete testing results.** Those can contain details of all requests made to the server under test and their responses. Apiary stores this data unencrypted, even if the original communication between Dredd and the API server under test happens to be over HTTPS. See :ref:`Apiary Reporter Test Data ` for detailed description of what is sent. You can :ref:`sanitize it before it gets sent `. +- **Little meta data about your environment.** Contents of environment variables ``TRAVIS``, ``CIRCLE``, ``CI``, ``DRONE``, ``BUILD_ID``, ``DREDD_AGENT``, ``USER``, and ``DREDD_HOSTNAME`` can be sent to Apiary. Your `hostname `__, version of your Dredd installation, and `type `__, `release `__ and `architecture `__ of your OS can be sent as well. Apiary stores this data unencrypted. -See also [guidelines on how to develop Apiary Reporter](contributing.md#hacking-apiary-reporter). +See also :ref:`guidelines on how to develop Apiary Reporter `. - +.. _using-https-proxy: -## Using HTTP(S) Proxy +Using HTTP(S) Proxy +------------------- You can tell Dredd to use HTTP(S) proxy for: -- downloading API description documents
- ([the positional argument][path-argument] or the [`--path` option][path-option] accepts also URL) -- [reporting to Apiary][apiary-reporter] +- downloading API description documents (:ref:`the positional argument ` or the ``--path`` option (docs :ref:`path-p`) accepts also URL) +- :ref:`reporting to Apiary ` -Dredd respects `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, `http_proxy`, `https_proxy`, and `no_proxy` environment variables. For more information on how those work see [relevant section][request-proxies] of the underlying library's documentation. +Dredd respects ``HTTP_PROXY``, ``HTTPS_PROXY``, ``NO_PROXY``, ``http_proxy``, ``https_proxy``, and ``no_proxy`` environment variables. For more information on how those work see `relevant section `__ of the underlying library’s documentation. Dredd intentionally **does not support HTTP(S) proxies for testing**. Proxy can deliberately modify requests and responses or to behave in a very different way then the server under test. Testing over a proxy is, in the first place, testing of the proxy itself. That makes the test results irrelevant (and hard to debug). - - -[path-argument]: usage-cli.md#api-description-document-string -[path-option]: usage-cli.md#path-p -[apiary-reporter]: how-to-guides.md#using-apiary-reporter-and-apiary-tests -[request-proxies]: https://github.com/request/request#user-content-proxies - -[Apiary]: https://apiary.io/ -[Semantic Versioning]: https://semver.org/ -[API Blueprint]: https://apiblueprint.org/ -[Swagger]: https://swagger.io/ -[Gavel.js]: https://github.com/apiaryio/gavel.js -[Gavel]: https://relishapp.com/apiary/gavel/docs -[MSON]: https://github.com/apiaryio/mson -[JSON Schema]: http://json-schema.org/ -[Swagger Adapter]: https://github.com/apiaryio/fury-adapter-swagger/ -[RFC6570]: https://tools.ietf.org/html/rfc6570 -[Draft v4]: https://tools.ietf.org/html/draft-zyp-json-schema-04 -[Draft v3]: https://tools.ietf.org/html/draft-zyp-json-schema-03 - -[CircleCI]: https://circleci.com/ -[Travis CI]: https://travis-ci.org/ -[Terms of Service]: https://apiary.io/tos -[Privacy Policy]: https://apiary.io/privacy -[hostname]: https://en.wikipedia.org/wiki/Hostname -[os-type]: https://nodejs.org/api/os.html#os_os_type -[os-release]: https://nodejs.org/api/os.html#os_os_release -[os-arch]: https://nodejs.org/api/os.html#os_os_arch - -[schema-section]: https://apiblueprint.org/documentation/specification.html#def-schema-section -[parameters-section]: https://apiblueprint.org/documentation/specification.html#def-uriparameters-section -[attributes-section]: https://apiblueprint.org/documentation/specification.html#def-attributes-section -[body-section]: https://apiblueprint.org/documentation/specification.html#def-body-section -[request-section]: https://apiblueprint.org/documentation/specification.html#def-action-section -[action-section]: https://apiblueprint.org/documentation/specification.html#def-action-section -[body-schema-attributes]: https://apiblueprint.org/documentation/specification.html#relation-of-body-schema-and-attributes-sections - -[produces]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-swaggerProduces -[consumes]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-swaggerConsumes -[response-headers]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-responseHeaders -[schema]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-parameterSchema -[response-schema]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-responseSchema -[response-examples]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-responseExamples -[parameters]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-parameterObject -[operation-parameters]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-operationParameters -[paths-parameters]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-pathItemParameters -[swagger-parameters]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-swaggerParameters -[default-responses]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-responsesDefault -[schema-example]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-schemaExample diff --git a/docs/how-to-guides.rst b/docs/how-to-guides.rst index d5965b38a..0ff791cf0 100644 --- a/docs/how-to-guides.rst +++ b/docs/how-to-guides.rst @@ -1,826 +1,868 @@ -# How-To Guides +.. _how-to-guides: -In the following guides you can find tips and best practices how to cope with some common tasks. While searching this page for particular keywords can give you quick results, reading the whole section should help you to learn some of the Dredd's core concepts and usual ways how to approach problems when testing with Dredd. +How-To Guides +============= -## Isolation of HTTP Transactions +In the following guides you can find tips and best practices how to cope with some common tasks. While searching this page for particular keywords can give you quick results, reading the whole section should help you to learn some of the Dredd’s core concepts and usual ways how to approach problems when testing with Dredd. -Requests in the API description usually aren't sorted in order to comply with logical workflow of the tested application. To get the best results from testing with Dredd, you should ensure each resource action ([API Blueprint][]) or operation ([Swagger][]) is executed in isolated context. This can be easily achieved using [hooks](hooks.md), where you can provide your own setup and teardown code for each HTTP transaction. +Isolation of HTTP Transactions +------------------------------ + +Requests in the API description usually aren’t sorted in order to comply with logical workflow of the tested application. To get the best results from testing with Dredd, you should ensure each resource action (`API Blueprint `__) or operation (`Swagger `__) is executed in isolated context. This can be easily achieved using :ref:`hooks `, where you can provide your own setup and teardown code for each HTTP transaction. You should understand that testing with Dredd is an analogy to **unit tests** of your application code. In unit tests, each unit should be testable without any dependency on other units or previous tests. -### Example +Example +~~~~~~~ Common case is to solve a situation where we want to test deleting of a resource. Obviously, to test deleting of a resource, we first need to create one. However, the order of HTTP transactions can be pretty much random in the API description. -To solve the situation, it's recommended to isolate the deletion test by [hooks](hooks.md). Providing `before` hook, we can ensure the database fixture will be present every time Dredd will try to send the request to delete a category item. +To solve the situation, it’s recommended to isolate the deletion test by :ref:`hooks `. Providing ``before`` hook, we can ensure the database fixture will be present every time Dredd will try to send the request to delete a category item. + +API Blueprint +^^^^^^^^^^^^^ -#### API Blueprint +.. code:: apiblueprint -```apiblueprint -FORMAT: 1A + FORMAT: 1A -# Categories API + # Categories API -## Categories [/categories] + ## Categories [/categories] -### Create a Category [POST] -+ Response 201 + ### Create a Category [POST] + + Response 201 -## Category [/category/{id}] -+ Parameters - + id: 42 (required) + ## Category [/category/{id}] + + Parameters + + id: 42 (required) -### Delete a Category [DELETE] -+ Response 204 + ### Delete a Category [DELETE] + + Response 204 -## Category Items [/category/{id}/items] -+ Parameters - + id: 42 (required) + ## Category Items [/category/{id}/items] + + Parameters + + id: 42 (required) -## Create an Item [POST] -+ Response 201 -``` + ## Create an Item [POST] + + Response 201 To have an idea where we can hook our arbitrary code, we should first ask Dredd to list all available transaction names: -``` -$ dredd api-description.apib http://127.0.0.1:3000 --names -info: Categories > Create a category -info: Category > Delete a category -info: Category Items > Create an item -``` - -Now we can create a `hooks.js` file. The file will contain setup and teardown of the database fixture: - -```javascript -hooks = require('hooks'); -db = require('./src/db'); - -beforeAll(function() { - db.cleanUp(); -}); - -afterEach(function(transaction) { - db.cleanUp(); -}); - -before('Category > Delete a Category', function() { - db.createCategory({id: 42}); -}); - -before('Category Items > Create an Item', function() { - db.createCategory({id: 42}); -}); -``` - -#### Swagger - -```yaml -swagger: "2.0" -info: - version: "0.0.0" - title: Categories API - license: - name: MIT -host: www.example.com -basePath: / -schemes: - - http -consumes: - - application/json -produces: - - application/json -paths: - /categories: - post: - responses: - 200: - description: "" - /category/{id}: - delete: - parameters: - - name: id - in: path - required: true - type: string - enum: - - "42" - responses: - 200: - description: "" - /category/{id}/items: - post: - parameters: - - name: id - in: path - required: true - type: string - enum: - - "42" - responses: - 200: - description: "" -``` +:: + + $ dredd api-description.apib http://127.0.0.1:3000 --names + info: Categories > Create a category + info: Category > Delete a category + info: Category Items > Create an item + +Now we can create a ``hooks.js`` file. The file will contain setup and teardown of the database fixture: + +.. code:: javascript + + hooks = require('hooks'); + db = require('./src/db'); + + beforeAll(function() { + db.cleanUp(); + }); + + afterEach(function(transaction) { + db.cleanUp(); + }); + + before('Category > Delete a Category', function() { + db.createCategory({id: 42}); + }); + + before('Category Items > Create an Item', function() { + db.createCategory({id: 42}); + }); + +Swagger +^^^^^^^ + +.. code:: yaml + + swagger: "2.0" + info: + version: "0.0.0" + title: Categories API + license: + name: MIT + host: www.example.com + basePath: / + schemes: + - http + consumes: + - application/json + produces: + - application/json + paths: + /categories: + post: + responses: + 200: + description: "" + /category/{id}: + delete: + parameters: + - name: id + in: path + required: true + type: string + enum: + - "42" + responses: + 200: + description: "" + /category/{id}/items: + post: + parameters: + - name: id + in: path + required: true + type: string + enum: + - "42" + responses: + 200: + description: "" To have an idea where we can hook our arbitrary code, we should first ask Dredd to list all available transaction names: -``` -$ dredd api-description.yml http://127.0.0.1:3000 --names -info: /categories > POST > 200 > application/json -info: /category/{id} > DELETE > 200 > application/json -info: /category/{id}/items > POST > 200 > application/json -``` +:: + + $ dredd api-description.yml http://127.0.0.1:3000 --names + info: /categories > POST > 200 > application/json + info: /category/{id} > DELETE > 200 > application/json + info: /category/{id}/items > POST > 200 > application/json -Now we can create a `hooks.js` file. The file will contain setup and teardown of the database fixture: +Now we can create a ``hooks.js`` file. The file will contain setup and teardown of the database fixture: -```javascript -hooks = require('hooks'); -db = require('./src/db'); +.. code:: javascript -beforeAll(function() { - db.cleanUp(); -}); + hooks = require('hooks'); + db = require('./src/db'); -afterEach(function(transaction) { - db.cleanUp(); -}); + beforeAll(function() { + db.cleanUp(); + }); -before('/category/{id}', function() { - db.createCategory({id: 42}); -}); + afterEach(function(transaction) { + db.cleanUp(); + }); -before('/category/{id}/items', function() { - db.createCategory({id: 42}); -}); -``` + before('/category/{id}', function() { + db.createCategory({id: 42}); + }); -## Testing API Workflows + before('/category/{id}/items', function() { + db.createCategory({id: 42}); + }); -Often you want to test a sequence of steps, a scenario, rather than just one request-response pair in isolation. Since the API description formats are quite limited in their support of documenting scenarios, Dredd probably isn't the best tool to provide you with this kind of testing. There are some tricks though, which can help you to work around some of the limitations. +Testing API Workflows +--------------------- -> **Note:** [API Blueprint][] prepares direct support for testing and scenarios. Interested? - Check out [apiaryio/api-blueprint#21](https://github.com/apiaryio/api-blueprint/issues/21)! +Often you want to test a sequence of steps, a scenario, rather than just one request-response pair in isolation. Since the API description formats are quite limited in their support of documenting scenarios, Dredd probably isn’t the best tool to provide you with this kind of testing. There are some tricks though, which can help you to work around some of the limitations. -To test various scenarios, you will want to write each of them into a separate API description document. To load them during a single test run, use the `--path` option ([docs](usage-cli.md#path-p)). + **Note:** `API Blueprint `__ prepares direct support for testing and scenarios. Interested? Check out `apiaryio/api-blueprint#21 `__! -For workflows to work properly, you'll also need to keep **shared context** between individual HTTP transactions. You can use [hooks](hooks.md) in order to achieve that. See tips on how to [pass data between transactions](hooks-nodejs.md#sharing-data-between-steps-in-request-stash). +To test various scenarios, you will want to write each of them into a separate API description document. To load them during a single test run, use the ``--path`` option (:ref:`docs `). -### API Blueprint Example +For workflows to work properly, you’ll also need to keep **shared context** between individual HTTP transactions. You can use :ref:`hooks ` in order to achieve that. See tips on how to :ref:`pass data between transactions `. + +API Blueprint Example +~~~~~~~~~~~~~~~~~~~~~ Imagine we have a simple workflow described: -```apiblueprint -FORMAT: 1A +.. code:: apiblueprint -# My Scenario + FORMAT: 1A -## POST /login + # My Scenario -+ Request (application/json) + ## POST /login - {"username": "john", "password": "d0e"} + + Request (application/json) + {"username": "john", "password": "d0e"} -+ Response 200 (application/json) - {"token": "s3cr3t"} + + Response 200 (application/json) -## GET /cars + {"token": "s3cr3t"} -+ Response 200 (application/json) + ## GET /cars - [ - {"id": "42", "color": "red"} - ] + + Response 200 (application/json) -## PATCH /cars/{id} -+ Parameters - + id: 42 (string, required) + [ + {"id": "42", "color": "red"} + ] -+ Request (application/json) + ## PATCH /cars/{id} + + Parameters + + id: 42 (string, required) - {"color": "yellow"} + + Request (application/json) -+ Response 200 (application/json) + {"color": "yellow"} - {"id": 42, "color": "yellow"} + + Response 200 (application/json) -``` + {"id": 42, "color": "yellow"} -#### Writing Hooks +Writing Hooks +^^^^^^^^^^^^^ To have an idea where we can hook our arbitrary code, we should first ask Dredd to list all available transaction names: -``` -$ dredd api-description.apib http://127.0.0.1:3000 --names -info: /login > POST -info: /cars > GET -info: /cars/{id} > PATCH -``` +:: + + $ dredd api-description.apib http://127.0.0.1:3000 --names + info: /login > POST + info: /cars > GET + info: /cars/{id} > PATCH -Now we can create a `hooks.js` file. The code of the file will use global `stash` variable to share data between requests: +Now we can create a ``hooks.js`` file. The code of the file will use global ``stash`` variable to share data between requests: -```javascript -hooks = require('hooks'); -db = require('./src/db'); +.. code:: javascript -stash = {} + hooks = require('hooks'); + db = require('./src/db'); -// Stash the token we've got -after('/login > POST', function (transaction) { - stash.token = JSON.parse(transaction.real.body).token; -}); + stash = {} -// Add the token to all HTTP transactions -beforeEach(function (transaction) { - if (stash.token) { - transaction.request.headers['X-Api-Key'] = stash.token - }; -}); + // Stash the token we've got + after('/login > POST', function (transaction) { + stash.token = JSON.parse(transaction.real.body).token; + }); -// Stash the car ID we've got -after('/cars > GET', function (transaction) { - stash.carId = JSON.parse(transaction.real.body).id; -}); + // Add the token to all HTTP transactions + beforeEach(function (transaction) { + if (stash.token) { + transaction.request.headers['X-Api-Key'] = stash.token + }; + }); -// Replace car ID in request with the one we've stashed -before('/cars/{id} > PATCH', function (transaction) { - transaction.fullPath = transaction.fullPath.replace('42', stash.carId) - transaction.request.uri = transaction.fullPath -}) -``` + // Stash the car ID we've got + after('/cars > GET', function (transaction) { + stash.carId = JSON.parse(transaction.real.body).id; + }); -### Swagger Example + // Replace car ID in request with the one we've stashed + before('/cars/{id} > PATCH', function (transaction) { + transaction.fullPath = transaction.fullPath.replace('42', stash.carId) + transaction.request.uri = transaction.fullPath + }) + +Swagger Example +~~~~~~~~~~~~~~~ Imagine we have a simple workflow described: -```yaml -swagger: "2.0" -info: - version: "0.0.0" - title: Categories API - license: - name: MIT -host: www.example.com -basePath: / -schemes: - - http -consumes: - - application/json -produces: - - application/json -paths: - /login: - post: - parameters: - - name: body - in: body - required: true - schema: - type: object - properties: - username: - type: string - password: - type: string - responses: - 200: - description: "" - schema: - type: object - properties: - token: - type: string - /cars: - get: - responses: - 200: - description: "" - schema: - type: array - items: - type: object - properties: - id: - type: string - color: - type: string - /cars/{id}: - patch: - parameters: - - name: id - in: path - required: true - type: string - enum: - - "42" - - name: body - in: body - required: true - schema: - type: object - properties: - color: - type: string - responses: - 200: - description: "" - schema: - type: object - properties: - id: - type: string - color: - type: string -``` - -#### Writing Hooks +.. code:: yaml + + swagger: "2.0" + info: + version: "0.0.0" + title: Categories API + license: + name: MIT + host: www.example.com + basePath: / + schemes: + - http + consumes: + - application/json + produces: + - application/json + paths: + /login: + post: + parameters: + - name: body + in: body + required: true + schema: + type: object + properties: + username: + type: string + password: + type: string + responses: + 200: + description: "" + schema: + type: object + properties: + token: + type: string + /cars: + get: + responses: + 200: + description: "" + schema: + type: array + items: + type: object + properties: + id: + type: string + color: + type: string + /cars/{id}: + patch: + parameters: + - name: id + in: path + required: true + type: string + enum: + - "42" + - name: body + in: body + required: true + schema: + type: object + properties: + color: + type: string + responses: + 200: + description: "" + schema: + type: object + properties: + id: + type: string + color: + type: string + +Writing Hooks +^^^^^^^^^^^^^ To have an idea where we can hook our arbitrary code, we should first ask Dredd to list all available transaction names: -``` -$ dredd api-description.yml http://127.0.0.1:3000 --names -info: /login > POST > 200 > application/json -info: /cars > GET > 200 > application/json -info: /cars/{id} > PATCH > 200 > application/json -``` +:: + + $ dredd api-description.yml http://127.0.0.1:3000 --names + info: /login > POST > 200 > application/json + info: /cars > GET > 200 > application/json + info: /cars/{id} > PATCH > 200 > application/json -Now we can create a `hooks.js` file. The code of the file will use global `stash` variable to share data between requests: +Now we can create a ``hooks.js`` file. The code of the file will use global ``stash`` variable to share data between requests: -```javascript -hooks = require('hooks'); -db = require('./src/db'); +.. code:: javascript -stash = {} + hooks = require('hooks'); + db = require('./src/db'); -// Stash the token we've got -after('/login > POST > 200 > application/json', function (transaction) { - stash.token = JSON.parse(transaction.real.body).token; -}); + stash = {} -// Add the token to all HTTP transactions -beforeEach(function (transaction) { - if (stash.token) { - transaction.request.headers['X-Api-Key'] = stash.token - }; -}); + // Stash the token we've got + after('/login > POST > 200 > application/json', function (transaction) { + stash.token = JSON.parse(transaction.real.body).token; + }); -// Stash the car ID we've got -after('/cars > GET > 200 > application/json', function (transaction) { - stash.carId = JSON.parse(transaction.real.body).id; -}); + // Add the token to all HTTP transactions + beforeEach(function (transaction) { + if (stash.token) { + transaction.request.headers['X-Api-Key'] = stash.token + }; + }); -// Replace car ID in request with the one we've stashed -before('/cars/{id} > PATCH > 200 > application/json', function (transaction) { - transaction.fullPath = transaction.fullPath.replace('42', stash.carId) - transaction.request.uri = transaction.fullPath -}) -``` + // Stash the car ID we've got + after('/cars > GET > 200 > application/json', function (transaction) { + stash.carId = JSON.parse(transaction.real.body).id; + }); -## Making Dredd Validation Stricter + // Replace car ID in request with the one we've stashed + before('/cars/{id} > PATCH > 200 > application/json', function (transaction) { + transaction.fullPath = transaction.fullPath.replace('42', stash.carId) + transaction.request.uri = transaction.fullPath + }) -API Blueprint or Swagger files are usually created primarily with _documentation_ in mind. But what's enough for documentation doesn't need to be enough for _testing_. +Making Dredd Validation Stricter +-------------------------------- -That applies to both [MSON][] (a language powering API Blueprint's [`+ Attributes`][apib-attributes-section] sections) and [JSON Schema][] (a language powering the Swagger format and API Blueprint's [`+ Schema`][apib-schema-section] sections). +API Blueprint or Swagger files are usually created primarily with *documentation* in mind. But what’s enough for documentation doesn’t need to be enough for *testing*. + +That applies to both `MSON `__ (a language powering API Blueprint’s `Attributes `__ sections) and `JSON Schema `__ (a language powering the Swagger format and API Blueprint’s `Schema `__ sections). In following sections you can learn about how to deal with common scenarios. -### Avoiding Additional Properties +Avoiding Additional Properties +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you describe a JSON body which has attributes ``name`` and ``size``, the following payload will be considered as correct: -If you describe a JSON body which has attributes `name` and `size`, the following payload will be considered as correct: +.. code:: json -```json -{"name": "Sparta", "size": 300, "luck": false} -``` + {"name": "Sparta", "size": 300, "luck": false} -It's because in both [MSON][] and [JSON Schema][] additional properties are not forbidden by default. +It’s because in both `MSON `__ and `JSON Schema `__ additional properties are not forbidden by default. -- In API Blueprint's [`+ Attributes`][apib-attributes-section] sections you can mark your object with [`fixed-type`][apib-fixed-type], which doesn't allow additional properties. -- In API Blueprint's [`+ Schema`][apib-schema-section] sections and in Swagger you can use [`additionalProperties: false`][json-schema-additional-properties] on the objects. +- In API Blueprint’s `Attributes `__ sections you can mark your object with ```fixed-type`` `__, which doesn’t allow additional properties. +- In API Blueprint’s `Schema `__ sections and in Swagger you can use ``additionalProperties: false`` (`docs `__) on the objects. -### Requiring Properties +Requiring Properties +~~~~~~~~~~~~~~~~~~~~ -If you describe a JSON body which has attributes `name` and `size`, the following payload will be considered as correct: +If you describe a JSON body which has attributes ``name`` and ``size``, the following payload will be considered as correct: -```json -{"name": "Sparta"} -``` +.. code:: json -It's because properties are optional by default in both [MSON][] and [JSON Schema][] and you need to explicitly specify them as required. + {"name": "Sparta"} -- In API Blueprint's [`+ Attributes`][apib-attributes-section] section, you can use [`required`][apib-required]. -- In API Blueprint's [`+ Schema`][apib-schema-section] sections and in Swagger you can use [`required`][json-schema-required], where you list the required properties. (Note this is true only for the [Draft v4][] JSON Schema, in older versions the `required` functionality was done differently.) +It’s because properties are optional by default in both `MSON `__ and `JSON Schema `__ and you need to explicitly specify them as required. -### Validating Structure of Array Items +- In API Blueprint’s `Attributes `__ section, you can use ```required`` `__. +- In API Blueprint’s `Schema `__ sections and in Swagger you can use ``required`` (`docs `__), where you list the required properties. (Note this is true only for the `Draft v4 `__ JSON Schema, in older versions the ``required`` functionality was done differently.) -If you describe an array of items, where each of the items should have a `name` property, the following payload will be considered as correct: +Validating Structure of Array Items +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -```json -[{"name": "Sparta"}, {"title": "Athens"}, "Thebes"] -``` +If you describe an array of items, where each of the items should have a ``name`` property, the following payload will be considered as correct: -That's because in [MSON][], the default behavior is that you are specifying what _may_ appear in the array. +.. code:: json -- In API Blueprint's [`+ Attributes`][apib-attributes-section] sections you can mark your array with [`fixed-type`][apib-fixed-type], which doesn't allow array items of a different structure then specified. -- In API Blueprint's [`+ Schema`][apib-schema-section] sections and in Swagger make sure to learn about how [validation of arrays][json-schema-arrays] exactly works. + [{"name": "Sparta"}, {"title": "Athens"}, "Thebes"] -### Validating Specific Values +That’s because in `MSON `__, the default behavior is that you are specifying what *may* appear in the array. -If you describe a JSON body which has attributes `name` and `size`, the following payload will be considered as correct: +- In API Blueprint’s `Attributes `__ sections you can mark your array with ``fixed-type`` (`docs `__), which doesn’t allow array items of a different structure then specified. +- In API Blueprint’s `Schema `__ sections and in Swagger make sure to learn about how `validation of arrays `__ exactly works. -```json -{"name": "Sparta", "size": 42} -``` +Validating Specific Values +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you describe a JSON body which has attributes ``name`` and ``size``, the following payload will be considered as correct: + +.. code:: json + + {"name": "Sparta", "size": 42} If the size should be always equal to 300, you need to specify the fact in your API description. -- In API Blueprint's [`+ Attributes`][apib-attributes-section] sections you can mark your property with [`fixed`][apib-fixed], which turns the sample value into a required value. You can also use [`enum`][apib-enum] to provide a set of possible values. -- In API Blueprint's [`+ Schema`][apib-schema-section] sections and in Swagger you can use [`enum`][json-schema-enum] with one or more possible values. +- In API Blueprint’s `Attributes `__ sections you can mark your property with ``fixed`` (`docs `__), which turns the sample value into a required value. You can also use ``enum`` (`docs `__) to provide a set of possible values. +- In API Blueprint’s `Schema `__ sections and in Swagger you can use ``enum`` (`docs `__) with one or more possible values. -## Integrating Dredd with Your Test Suite +Integrating Dredd with Your Test Suite +-------------------------------------- -Generally, if you want to add Dredd to your existing test suite, you can just save Dredd configuration in the `dredd.yml` file and add call for `dredd` command to your task runner. +Generally, if you want to add Dredd to your existing test suite, you can just save Dredd configuration in the ``dredd.yml`` file and add call for ``dredd`` command to your task runner. There are also some packages which make the integration a piece of cake: -- [grunt-dredd](https://github.com/mfgea/grunt-dredd) -- [dredd-rack](https://github.com/gonzalo-bulnes/dredd-rack) -- [meteor-dredd](https://github.com/storeness/meteor-dredd) +- `grunt-dredd `__ +- `dredd-rack `__ +- `meteor-dredd `__ -To find more, search for `dredd` in your favorite language's package index. +To find more, search for ``dredd`` in your favorite language’s package index. -## Continuous Integration +Continuous Integration +---------------------- -It's a good practice to make Dredd part of your continuous integration workflow. Only that way you can ensure that application code you'll produce won't break the contract you provide in your API documentation. +It’s a good practice to make Dredd part of your continuous integration workflow. Only that way you can ensure that application code you’ll produce won’t break the contract you provide in your API documentation. -Dredd's interactive configuration wizard, `dredd init`, can help you with setting up `dredd.yml` configuration file and with modifying or generating CI configuration files for [Travis CI][] or [CircleCI][]. +Dredd’s interactive configuration wizard, ``dredd init``, can help you with setting up ``dredd.yml`` configuration file and with modifying or generating CI configuration files for `Travis CI `__ or `CircleCI `__. If you prefer to add Dredd yourself or you look for inspiration on how to add Dredd to other continuous integration services, see examples below. When testing in CI, always pin your Dredd version to a specific number and upgrade to newer releases manually. - +.. _circleyml-configuration-file-for-circleci: + +``.circleci/config.yml`` Configuration File for `CircleCI `__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: -### `.circleci/config.yml` Configuration File for [CircleCI][] + version: 2 + jobs: + build: + docker: + - image: circleci/node:latest + steps: + - checkout + - run: npm install dredd@x.x.x --no-optional --global + - run: dredd apiary.apib http://127.0.0.1:3000 -``` -version: 2 -jobs: - build: - docker: - - image: circleci/node:latest - steps: - - checkout - - run: npm install dredd@x.x.x --no-optional --global - - run: dredd apiary.apib http://127.0.0.1:3000 -``` +.. _travisyml-configuration-file-for-travis-ci: - +``.travis.yml`` Configuration File for `Travis CI `__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -### `.travis.yml` Configuration File for [Travis CI][] +:: -``` -before_install: - - npm install dredd@x.x.x --no-optional --global -before_script: - - dredd apiary.apib http://127.0.0.1:3000 -``` + before_install: + - npm install dredd@x.x.x --no-optional --global + before_script: + - dredd apiary.apib http://127.0.0.1:3000 -## Authenticated APIs +Authenticated APIs +------------------ Dredd supports all common authentication schemes: -- Basic access authentication -- Digest access authentication -- OAuth (any version) -- CSRF tokens -- ... +- Basic access authentication +- Digest access authentication +- OAuth (any version) +- CSRF tokens +- … + +Use ``user`` setting in your configuration file or ``--user`` argument to provide HTTP basic authentication: + +:: + + --user=user:password + +Most of the authentication schemes use HTTP header for carrying the authentication data. If you don’t want to add authentication HTTP header to every request in the API description, you can instruct Dredd to do it for you: -Use `user` setting in your configuration file or `--user` argument to provide HTTP basic authentication: +:: -``` ---user=user:password -``` + --header="Authorization: Basic YmVuOnBhc3M=" -Most of the authentication schemes use HTTP header for carrying the authentication data. If you don't want to add authentication HTTP header to every request in the API description, you can instruct Dredd to do it for you: +Sending Multipart Requests +-------------------------- -``` ---header="Authorization: Basic YmVuOnBhc3M=" -``` +.. code:: apiblueprint -## Sending Multipart Requests + :[API Blueprint example](../test/fixtures/request/multipart-form-data.apib) -```apiblueprint -:[API Blueprint example](../test/fixtures/request/multipart-form-data.apib) -``` +.. code:: yaml -```yaml -:[Swagger example](../test/fixtures/request/multipart-form-data.yaml) -``` + :[Swagger example](../test/fixtures/request/multipart-form-data.yaml) -## Sending Form Data +Sending Form Data +----------------- -```apiblueprint -:[API Blueprint example](../test/fixtures/request/application-x-www-form-urlencoded.apib) -``` +.. code:: apiblueprint -```yaml -:[Swagger example](../test/fixtures/request/application-x-www-form-urlencoded.yaml) -``` + :[API Blueprint example](../test/fixtures/request/application-x-www-form-urlencoded.apib) -## Working with Images and other Binary Bodies +.. code:: yaml -The API description formats generally do not provide a way to describe binary content. The easiest solution is to describe only the media type, to [leave out the body](how-it-works.md#empty-response-body), and to handle the rest using [hooks](hooks.md). + :[Swagger example](../test/fixtures/request/application-x-www-form-urlencoded.yaml) -### Binary Request Body +Working with Images and other Binary Bodies +------------------------------------------- -#### API Blueprint +The API description formats generally do not provide a way to describe binary content. The easiest solution is to describe only the media type, to :ref:`leave out the body `, and to handle the rest using :ref:`hooks`. -```apiblueprint -:[API Blueprint example](../test/fixtures/request/image-png.apib) -``` +Binary Request Body +~~~~~~~~~~~~~~~~~~~ -#### Swagger +API Blueprint +^^^^^^^^^^^^^ -```yaml -:[Swagger example](../test/fixtures/request/image-png.yaml) -``` +.. code:: apiblueprint -#### Hooks + :[API Blueprint example](../test/fixtures/request/image-png.apib) -In hooks, you can populate the request body with real binary data. The data must be in a form of a [Base64-encoded](https://en.wikipedia.org/wiki/Base64) string. +Swagger +^^^^^^^ -```javascript -:[Hooks example](../test/fixtures/request/image-png-hooks.js) -``` +.. code:: yaml -### Binary Response Body + :[Swagger example](../test/fixtures/request/image-png.yaml) -#### API Blueprint +Hooks +^^^^^ -```apiblueprint -:[API Blueprint example](../test/fixtures/response/binary.apib) -``` +In hooks, you can populate the request body with real binary data. The data must be in a form of a `Base64-encoded `__ string. -#### Swagger +.. code:: javascript -```yaml -:[Swagger example](../test/fixtures/response/binary.yaml) -``` + :[Hooks example](../test/fixtures/request/image-png-hooks.js) -> **Note:** Do not use the explicit `binary` or `bytes` formats with response bodies, as Dredd is not able to properly work with those ([fury-adapter-swagger#193](https://github.com/apiaryio/fury-adapter-swagger/issues/193)). +Binary Response Body +~~~~~~~~~~~~~~~~~~~~ -### Hooks +API Blueprint +^^^^^^^^^^^^^ + +.. code:: apiblueprint + + :[API Blueprint example](../test/fixtures/response/binary.apib) + +Swagger +^^^^^^^ + +.. code:: yaml + + :[Swagger example](../test/fixtures/response/binary.yaml) + +.. + + **Note:** Do not use the explicit ``binary`` or ``bytes`` formats with response bodies, as Dredd is not able to properly work with those (`fury-adapter-swagger#193 `__). + +Hooks +~~~~~ In hooks, you can either assert the body: -```javascript -:[Hooks example](../test/fixtures/response/binary-assert-body-hooks.js) -``` +.. code:: javascript + + :[Hooks example](../test/fixtures/response/binary-assert-body-hooks.js) Or you can ignore it: -```javascript -:[Hooks example](../test/fixtures/response/binary-ignore-body-hooks.js) -``` +.. code:: javascript -## Multiple Requests and Responses + :[Hooks example](../test/fixtures/response/binary-ignore-body-hooks.js) -> **Note:** For details on this topic see also [How Dredd Works With HTTP Transactions](how-it-works.md#choosing-http-transactions). +Multiple Requests and Responses +------------------------------- -### API Blueprint + **Note:** For details on this topic see also :ref:`How Dredd Works With HTTP Transactions `. + +API Blueprint +~~~~~~~~~~~~~ To test multiple requests and responses within one action in Dredd, you need to cluster them into pairs: -```apiblueprint -FORMAT: 1A +.. code:: apiblueprint -# My API + FORMAT: 1A -## Resource [/resource/{id}] + # My API -+ Parameters - + id: 42 (required) + ## Resource [/resource/{id}] -### Update Resource [PATCH] + + Parameters + + id: 42 (required) -+ Request (application/json) + ### Update Resource [PATCH] - {"color": "yellow"} + + Request (application/json) + {"color": "yellow"} -+ Response 200 (application/json) - {"color": "yellow", "id": 1} + + Response 200 (application/json) + {"color": "yellow", "id": 1} -+ Request Edge Case (application/json) - {"weight": 1} + + Request Edge Case (application/json) -+ Response 400 (application/vnd.error+json) + {"weight": 1} - {"message": "Validation failed"} + + Response 400 (application/vnd.error+json) -``` + {"message": "Validation failed"} Dredd will detect two HTTP transaction examples and will compile following transaction names: -``` -$ dredd api-description.apib http://127.0.0.1 --names -info: Beginning Dredd testing... -info: Resource > Update Resource > Example 1 -info: Resource > Update Resource > Example 2 -``` +:: + + $ dredd api-description.apib http://127.0.0.1 --names + info: Beginning Dredd testing... + info: Resource > Update Resource > Example 1 + info: Resource > Update Resource > Example 2 + +In case you need to perform particular request with different URI parameters and standard inheritance of URI parameters isn’t working for you, try :ref:`modifying transaction before its execution ` in hooks. + +Swagger +~~~~~~~ + +When using `Swagger `__ format, by default Dredd tests only responses with ``2xx`` status codes. Responses with other codes are marked as *skipped* and can be activated in :ref:`hooks `: -In case you need to perform particular request with different URI parameters and standard inheritance of URI parameters isn't working for you, try [modifying transaction before its execution](hooks-nodejs.md#modifying-transaction-request-body-prior-to-execution) in hooks. +.. code:: javascript -### Swagger + var hooks = require('hooks'); -When using [Swagger][] format, by default Dredd tests only responses with `2xx` status codes. Responses with other codes are marked as _skipped_ and can be activated in [hooks](hooks.md): + hooks.before('/resource > GET > 500 > application/json', function (transaction, done) { + transaction.skip = false; + done(); + }); -```javascript -var hooks = require('hooks'); +.. _using-apiary-reporter-and-apiary-tests: -hooks.before('/resource > GET > 500 > application/json', function (transaction, done) { - transaction.skip = false; - done(); -}); -``` +Using Apiary Reporter and Apiary Tests +-------------------------------------- -## Using Apiary Reporter and Apiary Tests +Command-line output of complex HTTP responses and expectations can be hard to read. To tackle the problem, you can use Dredd to send test reports to `Apiary `__. Apiary provides a comfortable interface for browsing complex test reports: -Command-line output of complex HTTP responses and expectations can be hard to read. To tackle the problem, you can use Dredd to send test reports to [Apiary][]. Apiary provides a comfortable interface for browsing complex test reports: +:: -``` -$ dredd apiary.apib http://127.0.0.1 --reporter=apiary -warn: Apiary API Key or API Project Subdomain were not provided. Configure Dredd to be able to save test reports alongside your Apiary API project: http://dredd.readthedocs.io/en/latest/how-to-guides/#using-apiary-reporter-and-apiary-tests -info: Beginning Dredd testing... -pass: DELETE /honey duration: 884ms -complete: 1 passing, 0 failing, 0 errors, 0 skipped, 1 total -complete: Tests took 1631ms -complete: See results in Apiary at: https://app.apiary.io/public/tests/run/74d20a82-55c5-49bb-aac9-a3a5a7450f06 -``` + $ dredd apiary.apib http://127.0.0.1 --reporter=apiary + warn: Apiary API Key or API Project Subdomain were not provided. Configure Dredd to be able to save test reports alongside your Apiary API project: http://dredd.readthedocs.io/en/latest/how-to-guides/#using-apiary-reporter-and-apiary-tests + info: Beginning Dredd testing... + pass: DELETE /honey duration: 884ms + complete: 1 passing, 0 failing, 0 errors, 0 skipped, 1 total + complete: Tests took 1631ms + complete: See results in Apiary at: https://app.apiary.io/public/tests/run/74d20a82-55c5-49bb-aac9-a3a5a7450f06 -![Apiary Tests](_images/apiary-tests.png) +.. figure:: _images/apiary-tests.png + :alt: Apiary Tests -### Saving Test Reports under Your Account in Apiary + Apiary Tests -As you can see on the screenshot, the test reports are anonymous by default and will expire after some time. However, if you provide Apiary credentials, your test reports will appear on the _Tests_ page of your API Project. This is great especially for introspection of test reports from Continuous Integration. +Saving Test Reports under Your Account in Apiary +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As you can see on the screenshot, the test reports are anonymous by default and will expire after some time. However, if you provide Apiary credentials, your test reports will appear on the *Tests* page of your API Project. This is great especially for introspection of test reports from Continuous Integration. To get and setup credentials, just follow the tutorial in Apiary: -![Apiary Tests Tutorial](_images/apiary-tests-tutorial.png) +.. figure:: _images/apiary-tests-tutorial.png + :alt: Apiary Tests Tutorial + + Apiary Tests Tutorial As you can see, the parameters go like this: -``` -$ dredd -c apiaryApiKey: -c apiaryApiName: -``` +:: + + $ dredd -c apiaryApiKey: -c apiaryApiName: + +In addition to using parameters and ``dredd.yml``, you can also use environment variables: -In addition to using parameters and `dredd.yml`, you can also use environment variables: +- ``APIARY_API_KEY=`` - Alternative way to pass credentials to Apiary Reporter. +- ``APIARY_API_NAME=`` - Alternative way to pass credentials to Apiary Reporter. -- `APIARY_API_KEY=` - Alternative way to pass credentials to Apiary Reporter. -- `APIARY_API_NAME=` - Alternative way to pass credentials to Apiary Reporter. +When sending test reports to Apiary, Dredd inspects the environment where it was executed and sends some information about it alongside test results. Those are used mainly for detection whether the environment is Continuous Integration and also, they help you to identify individual test reports on the *Tests* page. You can use the following variables to tell Dredd what to send: -When sending test reports to Apiary, Dredd inspects the environment where it was executed and sends some information about it alongside test results. Those are used mainly for detection whether the environment is Continuous Integration and also, they help you to identify individual test reports on the _Tests_ page. You can use the following variables to tell Dredd what to send: +- agent (string) - ``DREDD_AGENT`` or current user in the OS +- hostname (string) - ``DREDD_HOSTNAME`` or hostname of the OS +- CI (boolean) - looks for ``TRAVIS``, ``CIRCLE``, ``CI``, ``DRONE``, ``BUILD_ID``, … -- agent (string) - `DREDD_AGENT` or current user in the OS -- hostname (string) - `DREDD_HOSTNAME` or hostname of the OS -- CI (boolean) - looks for `TRAVIS`, `CIRCLE`, `CI`, `DRONE`, `BUILD_ID`, ... +.. _example-values-for-request-parameters: -## Example Values for Request Parameters +Example Values for Request Parameters +------------------------------------- -While example values are natural part of the API Blueprint format, the Swagger -specification allows them only for `body` request parameters (`schema.example`). +While example values are natural part of the API Blueprint format, the Swagger specification allows them only for ``body`` request parameters (``schema.example``). -However, Dredd needs to know what values to use when testing described API, so -it supports `x-example` [vendor extension property][] to overcome the Swagger limitation: +However, Dredd needs to know what values to use when testing described API, so it supports ``x-example`` `vendor extension property `__ to overcome the Swagger limitation: -```yaml -... -paths: - /cars: - get: - parameters: - - name: limit - in: query - type: number - x-example: 42 -``` +.. code:: yaml -The `x-example` property is respected for all kinds of request parameters except -of `body` parameters, where native `schema.example` should be used. + ... + paths: + /cars: + get: + parameters: + - name: limit + in: query + type: number + x-example: 42 -## Removing Sensitive Data from Test Reports +The ``x-example`` property is respected for all kinds of request parameters except of ``body`` parameters, where native ``schema.example`` should be used. -Sometimes your API sends back sensitive information you don't want to get disclosed in [Apiary Tests](how-to-guides.md#using-apiary-reporter-and-apiary-tests) or in your CI log. In that case you can use [Hooks](hooks.md) to do sanitation. Before diving into examples below, do not forget to consider following: +.. _removing-sensitive-data-from-test-reports: -- Be sure to read [section about security](how-it-works.md#security) first. -- Only the [`transaction.test`](data-structures.md#transaction-test) object will make it to reporters. You don't have to care about sanitation of the rest of the [`transaction`](data-structures.md#transaction) object. -- The `transaction.test.message` and all the `transaction.test.results.body.results.rawData.*.message` properties contain validation error messages. While they're very useful for learning about what's wrong on command line, they can contain direct mentions of header names, header values, body properties, body structure, body values, etc., thus it's recommended their contents are completely removed to prevent unintended leaks of sensitive information. -- Without the `transaction.test.results.body.results.rawData` property [Apiary reporter](how-to-guides.md#using-apiary-reporter-and-apiary-tests) won't be able to render green/red difference between payloads. -- You can use [Ultimate 'afterEach' Guard](#sanitation-ultimate-guard) to make sure you won't leak any sensitive data by mistake. -- If your hooks crash, Dredd will send an error to reporters, alongside with current contents of the [`transaction.test`](data-structures.md#transaction-test) object. See the [Sanitation of Test Data of Transaction With Secured Erroring Hooks](#sanitation-secured-erroring-hooks) example to learn how to prevent this. +Removing Sensitive Data from Test Reports +----------------------------------------- -### Sanitation of the Entire Request Body +Sometimes your API sends back sensitive information you don’t want to get disclosed in :ref:`Apiary Tests ` or in your CI log. In that case you can use :ref:`Hooks ` to do sanitation. Before diving into examples below, do not forget to consider following: -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/entire-request-body.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/entire-request-body.js) +- Be sure to read :ref:`section about security ` first. +- Only the ``transaction.test`` (:ref:`docs `) object will make it to reporters. You don’t have to care about sanitation of the rest of the ``transaction`` (:ref:`docs `) object. +- The ``transaction.test.message`` and all the ``transaction.test.results.body.results.rawData.*.message`` properties contain validation error messages. While they’re very useful for learning about what’s wrong on command line, they can contain direct mentions of header names, header values, body properties, body structure, body values, etc., thus it’s recommended their contents are completely removed to prevent unintended leaks of sensitive information. +- Without the ``transaction.test.results.body.results.rawData`` property :ref:`Apiary reporter ` won’t be able to render green/red difference between payloads. +- You can use :ref:`Ultimate ‘afterEach’ Guard ` to make sure you won’t leak any sensitive data by mistake. +- If your hooks crash, Dredd will send an error to reporters, alongside with current contents of the ``transaction.test`` (:ref:`docs `) object. See the :ref:`Sanitation of Test Data of Transaction With Secured Erroring Hooks ` example to learn how to prevent this. -### Sanitation of the Entire Response Body +Sanitation of the Entire Request Body +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/entire-response-body.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/entire-response-body.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of a Request Body Attribute +Sanitation of the Entire Response Body +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/request-body-attribute.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/request-body-attribute.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of a Response Body Attribute +Sanitation of a Request Body Attribute +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/response-body-attribute.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/response-body-attribute.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of Plain Text Response Body by Pattern Matching +Sanitation of a Response Body Attribute +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/plain-text-response-body.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/plain-text-response-body.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of Request Headers +Sanitation of Plain Text Response Body by Pattern Matching +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/request-headers.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/request-headers.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of Response Headers +Sanitation of Request Headers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/response-headers.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/response-headers.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of URI Parameters by Pattern Matching +Sanitation of Response Headers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/uri-parameters.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/uri-parameters.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of Any Content by Pattern Matching +Sanitation of URI Parameters by Pattern Matching +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/any-content-pattern-matching.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/any-content-pattern-matching.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of Test Data of Passing Transaction +Sanitation of Any Content by Pattern Matching +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/transaction-passing.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/transaction-passing.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of Test Data When Transaction Is Marked as Failed in \'before\' Hook +Sanitation of Test Data of Passing Transaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/transaction-marked-failed-before.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/transaction-marked-failed-before.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of Test Data When Transaction Is Marked as Failed in \'after\' Hook +Sanitation of Test Data When Transaction Is Marked as Failed in 'before' Hook +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/transaction-marked-failed-after.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/transaction-marked-failed-after.js) +- `API Blueprint `__ +- `Hooks `__ -### Sanitation of Test Data When Transaction Is Marked as Skipped +Sanitation of Test Data When Transaction Is Marked as Failed in 'after' Hook +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/transaction-marked-skipped.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/transaction-marked-skipped.js) +- `API Blueprint `__ +- `Hooks `__ - -### Ultimate 'afterEach' Guard Using Pattern Matching +Sanitation of Test Data When Transaction Is Marked as Skipped +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can use this guard to make sure you won't leak any sensitive data by mistake. +- `API Blueprint `__ +- `Hooks `__ -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/any-content-guard-pattern-matching.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/any-content-guard-pattern-matching.js) +.. _sanitation-ultimate-guard: - -### Sanitation of Test Data of Transaction With Secured Erroring Hooks +Ultimate ‘afterEach’ Guard Using Pattern Matching +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If your hooks crash, Dredd will send an error to reporters, alongside with current contents of the [`transaction.test`](data-structures.md#transaction-test) object. If you want to prevent this, you need to add `try/catch` to your hooks, sanitize the test object, and gracefully fail the transaction. +You can use this guard to make sure you won’t leak any sensitive data by mistake. -- [API Blueprint](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/transaction-secured-erroring-hooks.apib) -- [Hooks](https://github.com/apiaryio/dredd/blob/master/test/fixtures/sanitation/transaction-secured-erroring-hooks.js) +- `API Blueprint `__ +- `Hooks `__ +.. _sanitation-secured-erroring-hooks: -[Apiary]: https://apiary.io/ -[API Blueprint]: https://apiblueprint.org/ -[Swagger]: https://swagger.io/ -[Travis CI]: https://travis-ci.org/ -[CircleCI]: https://circleci.com/ -[vendor extension property]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-vendorExtensions +Sanitation of Test Data of Transaction With Secured Erroring Hooks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -[MSON]: https://apiblueprint.org/documentation/mson/specification.html -[JSON Schema]: http://json-schema.org/ -[Draft v4]: https://tools.ietf.org/html/draft-zyp-json-schema-04 +If your hooks crash, Dredd will send an error to reporters, alongside with current contents of the ``transaction.test`` (:ref:`docs `) object. If you want to prevent this, you need to add ``try/catch`` to your hooks, sanitize the test object, and gracefully fail the transaction. -[apib-attributes-section]: https://apiblueprint.org/documentation/specification.html#def-attributes-section -[apib-schema-section]: https://apiblueprint.org/documentation/specification.html#def-schema-section -[apib-fixed-type]: https://apiblueprint.org/documentation/mson/specification.html#353-type-attribute -[apib-required]: https://apiblueprint.org/documentation/mson/specification.html#353-type-attribute -[apib-fixed]: https://apiblueprint.org/documentation/mson/specification.html#353-type-attribute -[apib-enum]: https://apiblueprint.org/documentation/mson/specification.html#212-structure-types -[json-schema-enum]: https://json-schema.org/understanding-json-schema/reference/generic.html#enumerated-values -[json-schema-additional-properties]: https://json-schema.org/understanding-json-schema/reference/object.html#properties -[json-schema-required]: https://json-schema.org/understanding-json-schema/reference/object.html#required-properties -[json-schema-arrays]: https://json-schema.org/understanding-json-schema/reference/array.html +- `API Blueprint `__ +- `Hooks `__ diff --git a/docs/index.rst b/docs/index.rst index 7e8d56964..615d8a94c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,89 +1,99 @@ -# Dredd — HTTP API Testing Framework - -[![npm version](https://badge.fury.io/js/dredd.svg)](https://www.npmjs.com/package/dredd) -[![Build Status](https://travis-ci.org/apiaryio/dredd.svg?branch=master)](https://travis-ci.org/apiaryio/dredd) -[![Build Status](https://ci.appveyor.com/api/projects/status/n3ixfxh72qushyr4/branch/master?svg=true)](https://ci.appveyor.com/project/Apiary/dredd/branch/master) -[![Dependency Status](https://david-dm.org/apiaryio/dredd.svg)](https://david-dm.org/apiaryio/dredd) -[![devDependency Status](https://david-dm.org/apiaryio/dredd/dev-status.svg)](https://david-dm.org/apiaryio/dredd?type=dev) -[![Documentation Status](https://readthedocs.org/projects/dredd/badge/?version=latest)](https://dredd.readthedocs.io/en/latest/) -[![Coverage Status](https://coveralls.io/repos/apiaryio/dredd/badge.svg?branch=master)](https://coveralls.io/github/apiaryio/dredd) -[![Known Vulnerabilities](https://snyk.io/test/npm/dredd/badge.svg)](https://snyk.io/test/npm/dredd) - -![Dredd - HTTP API Testing Framework](_images/dredd.png) - -> **Dredd is a language-agnostic command-line tool for validating -API description document against backend implementation of the API.** - -Dredd reads your API description and step by step validates whether your API -implementation replies with responses as they are described in the -documentation. - -## Features - -### Supported API Description Formats - -- [API Blueprint][] -- [Swagger][] - -### Supported Hooks Languages - -Dredd supports writing [hooks](hooks.md) — a glue code for each test setup and teardown. Following languages are supported: - -- [Go](hooks-go.md) -- [Node.js (JavaScript)](hooks-nodejs.md) -- [Perl](hooks-perl.md) -- [PHP](hooks-php.md) -- [Python](hooks-python.md) -- [Ruby](hooks-ruby.md) -- [Rust](hooks-rust.md) -- Didn't find your favorite language? _[Add a new one!](hooks-new-language.md)_ - -### Supported Systems - -- Linux, macOS, Windows, ... -- [Travis CI][], [CircleCI][], [Jenkins][], [AppVeyor][], ... - -## Contents - -- [Installation](installation.md) -- [Quickstart](quickstart.md) -- [How It Works](how-it-works.md) -- [How-To Guides](how-to-guides.md) -- [Usage: CLI](usage-cli.md) -- [Usage: JavaScript](usage-js.md) -- [About Hooks](hooks.md) -- [Hooks: Go](hooks-go.md) -- [Hooks: JavaScript (Sandboxed)](hooks-js-sandbox.md) -- [Hooks: Node.js](hooks-nodejs.md) -- [Hooks: Perl](hooks-perl.md) -- [Hooks: PHP](hooks-php.md) -- [Hooks: Python](hooks-python.md) -- [Hooks: Ruby](hooks-ruby.md) -- [Hooks: Rust](hooks-rust.md) -- [Hooks: Other Languages](hooks-new-language.md) -- [Data Structures](data-structures.md) -- [Contributing](contributing.md) - -## Useful Links - -- [GitHub Repository][] -- [Bug Tracker][] -- [Changelog][] - -## Example Applications - -- [Express.js](https://github.com/apiaryio/dredd-example) -- [Ruby on Rails](https://gitlab.com/theodorton/dredd-test-rails/) - - -[API Blueprint]: https://apiblueprint.org/ -[Swagger]: https://swagger.io/ - -[GitHub Repository]: https://github.com/apiaryio/dredd -[Bug Tracker]: https://github.com/apiaryio/dredd/issues?q=is%3Aopen -[Changelog]: https://github.com/apiaryio/dredd/releases - -[Travis CI]: https://travis-ci.org/ -[CircleCI]: https://circleci.com/ -[Jenkins]: https://jenkins.io/ -[AppVeyor]: https://www.appveyor.com/ +.. _index: + +Dredd — HTTP API Testing Framework +================================== + +|npm version| |Build Status| |Windows Build Status| |Dependency Status| |devDependency Status| |Documentation Status| |Coverage Status| |Known Vulnerabilities| + +.. figure:: _images/dredd.png + :alt: Dredd - HTTP API Testing Framework + +.. + + **Dredd is a language-agnostic command-line tool for validating API description document against backend implementation of the API.** + +Dredd reads your API description and step by step validates whether your API implementation replies with responses as they are described in the documentation. + +Features +-------- + +Supported API Description Formats +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- `API Blueprint `__ +- `Swagger `__ + +Supported Hooks Languages +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dredd supports writing :ref:`hooks ` — a glue code for each test setup and teardown. Following languages are supported: + +- :ref:`Go ` +- :ref:`Node.js (JavaScript) ` +- :ref:`Perl ` +- :ref:`PHP ` +- :ref:`Python ` +- :ref:`Ruby ` +- :ref:`Rust ` +- Didn’t find your favorite language? :ref:`Add a new one! ` + +Supported Systems +~~~~~~~~~~~~~~~~~ + +- Linux, macOS, Windows, … +- `Travis CI `__, `CircleCI `__, `Jenkins `__, `AppVeyor `__, … + +Contents +-------- + +.. toctree:: + :maxdepth: 1 + + installation + quickstart + how-it-works + how-to-guides + Usage: CLI + Usage: JavaScript + About Hooks + Hooks: Go + Hooks: JavaScript (Sandboxed) + Hooks: Node.js + Hooks: Perl + Hooks: PHP + Hooks: Python + Hooks: Ruby + Hooks: Rust + Hooks: Other languages + data-structures + contributing + +Useful Links +------------ + +- `GitHub Repository `__ +- `Bug Tracker `__ +- `Changelog `__ + +Example Applications +-------------------- + +- `Express.js `__ +- `Ruby on Rails `__ + +.. |npm version| image:: https://badge.fury.io/js/dredd.svg + :target: https://www.npmjs.com/package/dredd +.. |Build Status| image:: https://travis-ci.org/apiaryio/dredd.svg?branch=master + :target: https://travis-ci.org/apiaryio/dredd +.. |Windows Build Status| image:: https://ci.appveyor.com/api/projects/status/n3ixfxh72qushyr4/branch/master?svg=true + :target: https://ci.appveyor.com/project/Apiary/dredd/branch/master +.. |Dependency Status| image:: https://david-dm.org/apiaryio/dredd.svg + :target: https://david-dm.org/apiaryio/dredd +.. |devDependency Status| image:: https://david-dm.org/apiaryio/dredd/dev-status.svg + :target: https://david-dm.org/apiaryio/dredd?type=dev +.. |Documentation Status| image:: https://readthedocs.org/projects/dredd/badge/?version=latest + :target: https://dredd.readthedocs.io/en/latest/ +.. |Coverage Status| image:: https://coveralls.io/repos/apiaryio/dredd/badge.svg?branch=master + :target: https://coveralls.io/github/apiaryio/dredd +.. |Known Vulnerabilities| image:: https://snyk.io/test/npm/dredd/badge.svg + :target: https://snyk.io/test/npm/dredd diff --git a/docs/installation.rst b/docs/installation.rst index 1d5b6acd1..be2610bd7 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -1,110 +1,107 @@ -# Installation +.. _installation: -Dredd is a command-line application written in JavaScript. To run it on your machine or in your [Continuous Integration server][CI], you first need to have [Node.js][] installed. +Installation +============ - +Dredd is a command-line application written in JavaScript. To run it on your machine or in your :ref:`Continuous Integration server `, you first need to have `Node.js `__ installed. -## Install Node.js +.. _install-nodejs: -### macOS +Install Node.js +--------------- + +macOS +~~~~~ 1. Install Node.js. - - If you're using [Homebrew][], run `brew install node`. - - Otherwise [download Node.js][Download Node.js] from the official website and install Node.js using the downloaded installer. -2. Make sure both `node --version` and `npm --version` work in your Terminal. -### Windows + - If you’re using `Homebrew `__, run ``brew install node``. + - Otherwise `download Node.js `__ from the official website and install Node.js using the downloaded installer. -1. [Download Node.js][] from the official website and install Node.js using the downloaded installer. -2. Make sure both `node --version` and `npm --version` work in your Command Prompt. +2. Make sure both ``node --version`` and ``npm --version`` work in your Terminal. -### Linux +Windows +~~~~~~~ -1. [Install Node.js as system package][]. -2. Make sure both `node --version` and `npm --version` work in your Terminal. +1. `Download Node.js `__ from the official website and install Node.js using the downloaded installer. +2. Make sure both ``node --version`` and ``npm --version`` work in your Command Prompt. -### Pro Tips +Linux +~~~~~ -- [Continuous Integration section in the How-To Guides](how-to-guides.md#continuous-integration) can help you to install Dredd on CI server. -- To maintain multiple Node.js versions on your computer, check out [nvm][]. +1. `Install Node.js as system package `__. +2. Make sure both ``node --version`` and ``npm --version`` work in your Terminal. -## Install Dredd +Pro Tips +~~~~~~~~ -1. `npm install -g dredd` -2. `dredd --version` +- :ref:`Continuous Integration section in the How-To Guides ` can help you to install Dredd on CI server. +- To maintain multiple Node.js versions on your computer, check out `nvm `__. -If the second command works, you're done! +Install Dredd +------------- -### Globally vs locally +1. ``npm install -g dredd`` +2. ``dredd --version`` -The `-g` ensures Dredd will be installed "globally". That means you'll be able to access it from any directory just by typing `dredd`. +If the second command works, you’re done! -If you work on projects installable by `npm`, i.e. projects containing `package.json`, you might want to have Dredd installed as a development dependency instead. Just install Dredd by `npm install dredd --save-dev`. See `package.json` of the [Dredd Example][] repository for inspiration. +Globally vs locally +~~~~~~~~~~~~~~~~~~~ -### Which Version? +The ``-g`` ensures Dredd will be installed “globally”. That means you’ll be able to access it from any directory just by typing ``dredd``. -- **For development**, always go with the latest version. -- **For testing in [CI][]**, always pin your Dredd version to a specific number and upgrade to newer releases manually (but often!). +If you work on projects installable by ``npm``, i.e. projects containing ``package.json``, you might want to have Dredd installed as a development dependency instead. Just install Dredd by ``npm install dredd --save-dev``. See ``package.json`` of the `Dredd Example `__ repository for inspiration. -### Why Am I Seeing Network Errors? +Which Version? +~~~~~~~~~~~~~~ -In a restricted network (VPN, firewall, proxy) you can see errors similar to the following ones: +- **For development**, always go with the latest version. +- **For testing in CI** (:ref:`what’s CI? `), always pin your Dredd version to a specific number and upgrade to newer releases manually (but often!). -```text -npmERR! Cannot read property 'path' of null -npmERR!code ECONNRESET -npmERR!network socket hang up -``` +Why Am I Seeing Network Errors? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -```text -Error: Command failed: git config --get remote.origin.url -ssh: connect to host github.com port 22: Operation timed out -fatal: Could not read from remote repository. -``` +In a restricted network (VPN, firewall, proxy) you can see errors similar to the following ones: -To solve these issues, you need to set your proxy settings for both `npm` and `git`: +.. code:: text -```sh -$ npm config set proxy "http://proxy.company.com:8080" -$ npm config set https-proxy "https://proxy.company.com:8080" + npmERR! Cannot read property 'path' of null + npmERR!code ECONNRESET + npmERR!network socket hang up -$ git config --global http.proxy "http://proxy.company.com:8080" -$ git config --global https.proxy "https://proxy.company.com:8080" -``` +.. code:: text -When using `git config`, make sure you have the port specified even -when it's the standard `:80`. Also check out -[how to set up Dredd to correctly work with proxies][Dredd Proxy]. + Error: Command failed: git config --get remote.origin.url + ssh: connect to host github.com port 22: Operation timed out + fatal: Could not read from remote repository. -### Why I'm Seeing `node-gyp` or `python` Errors? +To solve these issues, you need to set your proxy settings for both ``npm`` and ``git``: -The installation process features compilation of some C++ components, which may not be successful. In that case, errors related to `node-gyp` or `python` are printed. However, if `dredd --version` works for you when the installation is done, feel free to ignore the errors. +.. code:: sh -In case of compilation errors, Dredd automatically uses a less performant solution written in pure JavaScript. Next time when installing Dredd, you can use `npm install -g dredd --no-optional` to skip the compilation step ([learn more about this][C++11 vs JS]). + $ npm config set proxy "http://proxy.company.com:8080" + $ npm config set https-proxy "https://proxy.company.com:8080" -### Why Is the Installation So Slow? + $ git config --global http.proxy "http://proxy.company.com:8080" + $ git config --global https.proxy "https://proxy.company.com:8080" -The installation process features compilation of some C++ components, which may take some time ([learn more about this][C++11 vs JS]). You can simplify and speed up the process using `npm install -g dredd --no-optional` if you are: +When using ``git config``, make sure you have the port specified even when it’s the standard ``:80``. Also check out :ref:`how to set up Dredd to correctly work with proxies `. -- using Dredd exclusively with [Swagger][], -- using Dredd with small [API Blueprint][] files, -- using Dredd on Windows or other environments with complicated C++11 compiler setup. +Why I’m Seeing ``node-gyp`` or ``python`` Errors? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The `--no-optional` option avoids any compilation attempts when installing Dredd, but causes slower reading of the API Blueprint files, especially the large ones. +The installation process features compilation of some C++ components, which may not be successful. In that case, errors related to ``node-gyp`` or ``python`` are printed. However, if ``dredd --version`` works for you when the installation is done, feel free to ignore the errors. +In case of compilation errors, Dredd automatically uses a less performant solution written in pure JavaScript. Next time when installing Dredd, you can use ``npm install -g dredd --no-optional`` to skip the compilation step (:ref:`learn more about this `). -[API Blueprint]: https://apiblueprint.org/ -[Swagger]: https://swagger.io/ +Why Is the Installation So Slow? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -[CoffeeScript]: https://coffeescript.org/ -[CI]: how-to-guides.md#continuous-integration +The installation process features compilation of some C++ components, which may take some time (:ref:`learn more about this `). You can simplify and speed up the process using ``npm install -g dredd --no-optional`` if you are: -[Homebrew]: https://brew.sh/ -[Node.js]: https://nodejs.org/en/ -[nvm]: https://github.com/creationix/nvm -[Download Node.js]: https://nodejs.org/en/download/ -[Install Node.js as system package]: https://nodejs.org/en/download/package-manager/ +- using Dredd exclusively with `Swagger `__, +- using Dredd with small `API Blueprint `__ files, +- using Dredd on Windows or other environments with complicated C++11 compiler setup. -[C++11 vs JS]: contributing.md#compiled-vs-pure-javascript -[Dredd Proxy]: how-it-works.md#using-http-s-proxy -[Dredd Example]: https://github.com/apiaryio/dredd-example/ +The ``--no-optional`` option avoids any compilation attempts when installing Dredd, but causes slower reading of the API Blueprint files, especially the large ones. diff --git a/docs/quickstart.rst b/docs/quickstart.rst index a87f1a095..b8dc5df95 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -1,135 +1,140 @@ -# Quickstart +.. _quickstart: -In following tutorial you can quickly learn how to test a simple HTTP API application with Dredd. The tested application will be very simple backend written in [Express.js][]. +Quickstart +========== -## Install Dredd +In following tutorial you can quickly learn how to test a simple HTTP API application with Dredd. The tested application will be very simple backend written in `Express.js `__. -``` -$ npm install -g dredd -``` +Install Dredd +------------- -If you're not familiar with the Node.js ecosystem or you bump into any issues, follow the [installation guide](installation.md). +:: -## Document Your API + $ npm install -g dredd -First, let's design the API we are about to build and test. That means you will need to create an API description file, which will document how your API should look like. Dredd supports two formats of API description documents: +If you’re not familiar with the Node.js ecosystem or you bump into any issues, follow the :ref:`installation guide `. -- [API Blueprint][] -- [Swagger][] +Document Your API +----------------- -If you choose API Blueprint, create a file called `api-description.apib` in the root of your project and save it with following content: +First, let’s design the API we are about to build and test. That means you will need to create an API description file, which will document how your API should look like. Dredd supports two formats of API description documents: -```apiblueprint -FORMAT: 1A +- `API Blueprint `__ +- `Swagger `__ -# GET / -+ Response 200 (application/json; charset=utf-8) +If you choose API Blueprint, create a file called ``api-description.apib`` in the root of your project and save it with following content: - {"message": "Hello World!"} -``` +.. code:: apiblueprint -If you choose Swagger, create a file called `api-description.yml`: + FORMAT: 1A -```yaml -swagger: "2.0" -info: - version: "1.0" - title: Example API - license: - name: MIT -host: www.example.com -basePath: / -schemes: - - http -paths: - /: - get: - produces: - - application/json; charset=utf-8 - responses: - 200: - description: "" - schema: - type: object - properties: - message: - type: string - required: - - message -``` + # GET / + + Response 200 (application/json; charset=utf-8) -## Implement Your API + {"message": "Hello World!"} -As we mentioned in the beginning, we'll use [Express.js][] to implement the API. Install the framework by `npm`: +If you choose Swagger, create a file called ``api-description.yml``: -```sh -$ npm init -$ npm install express --save -``` +.. code:: yaml -Now let's code the thing! Create a file called `app.js` with following contents: + swagger: "2.0" + info: + version: "1.0" + title: Example API + license: + name: MIT + host: www.example.com + basePath: / + schemes: + - http + paths: + /: + get: + produces: + - application/json; charset=utf-8 + responses: + 200: + description: "" + schema: + type: object + properties: + message: + type: string + required: + - message -```javascript -var app = require('express')(); +Implement Your API +------------------ -app.get('/', function(req, res) { - res.json({message: 'Hello World!'}); -}) +As we mentioned in the beginning, we’ll use `Express.js `__ to implement the API. Install the framework by ``npm``: -app.listen(3000); -``` +.. code:: sh -## Test Your API + $ npm init + $ npm install express --save -At this moment, the implementation is ready to be tested. Let's run the server as a background process and let's test it: +Now let’s code the thing! Create a file called ``app.js`` with following contents: -```sh -$ node app.js & -``` +.. code:: javascript + + var app = require('express')(); + + app.get('/', function(req, res) { + res.json({message: 'Hello World!'}); + }) + + app.listen(3000); + +Test Your API +------------- + +At this moment, the implementation is ready to be tested. Let’s run the server as a background process and let’s test it: + +.. code:: sh + + $ node app.js & Finally, let Dredd validate whether your freshly implemented API complies with the description you have: -```sh -$ dredd api-description.apib http://127.0.0.1:3000 # API Blueprint -$ dredd api-description.yml http://127.0.0.1:3000 # Swagger -``` +.. code:: sh -## Configure Dredd + $ dredd api-description.apib http://127.0.0.1:3000 # API Blueprint + $ dredd api-description.yml http://127.0.0.1:3000 # Swagger -Dredd can be configured by [many CLI options](usage-cli.md). It's recommended to save your Dredd configuration alongside your project, so it's easier to repeatedly execute always the same test run. Use interactive configuration wizard to create `dredd.yml` file in the root of your project: +Configure Dredd +--------------- -``` -$ dredd init -? Location of the API description document: api-description.apib -? Command to start API backend server e.g. (bundle exec rails server) -? URL of tested API endpoint: http://127.0.0.1:3000 -? Programming language of hooks: -❯ nodejs - python - ruby - ... -? Dredd is best served with Continuous Integration. Create CircleCI config for Dredd? Yes -``` +Dredd can be configured by :ref:`many CLI options `. It’s recommended to save your Dredd configuration alongside your project, so it’s easier to repeatedly execute always the same test run. Use interactive configuration wizard to create ``dredd.yml`` file in the root of your project: -Now you can start test run just by typing `dredd`! +:: -``` -$ dredd -``` + $ dredd init + ? Location of the API description document: api-description.apib + ? Command to start API backend server e.g. (bundle exec rails server) + ? URL of tested API endpoint: http://127.0.0.1:3000 + ? Programming language of hooks: + ❯ nodejs + python + ruby + ... + ? Dredd is best served with Continuous Integration. Create CircleCI config for Dredd? Yes -## Use Hooks +Now you can start test run just by typing ``dredd``! -Dredd's [hooks](hooks.md) enable you to write some glue code in your favorite language to support enhanced scenarios in your API tests. Read the documentation about hooks to learn more on how to write them. Choose your language and install corresponding hook handler library. +:: -## Advanced Examples + $ dredd -For more complex example applications, please refer to: +Use Hooks +--------- -- [Express.js example application](https://github.com/apiaryio/dredd-example) -- [Ruby on Rails example application](https://github.com/theodorton/dredd-test-rails) -- [Laravel example application](https://github.com/ddelnano/dredd-hooks-php/wiki/Laravel-Example) +Dredd’s :ref:`hooks ` enable you to write some glue code in your favorite language to support enhanced scenarios in your API tests. Read the documentation about hooks to learn more on how to write them. Choose your language and install corresponding hook handler library. +Advanced Examples +----------------- + +For more complex example applications, please refer to: -[API Blueprint]: https://apiblueprint.org/ -[Swagger]: https://swagger.io/ -[Express.js]: http://expressjs.com/starter/hello-world.html +- `Express.js example application `__ +- `Ruby on Rails example application `__ +- `Laravel example application `__ diff --git a/docs/usage-cli.rst b/docs/usage-cli.rst new file mode 100644 index 000000000..695ad1b6e --- /dev/null +++ b/docs/usage-cli.rst @@ -0,0 +1,109 @@ +.. _usage-cli: + +Command-line Interface +====================== + +.. _api-description-document-string: +.. _path-p: +.. _hooks-worker-timeout: +.. _hooks-worker-connect-timeout: +.. _hooks-worker-connect-retry: +.. _hooks-worker-after-connect-wait: +.. _hooks-worker-term-timeout: +.. _hooks-worker-term-retry: +.. _hooks-worker-handler-host: +.. _hooks-worker-handler-port: + +Foo bar +------- + +.. + # Command-line Interface + + ## Usage + + ``` + $ dredd '' '' [OPTIONS] + ``` + + Example: + + ``` + $ dredd ./apiary.md http://127.0.0.1:3000 + ``` + + ## Arguments + + ### API Description Document (string) + + URL or path to the API description document (API Blueprint, Swagger).
+ **Sample values:** `./api-blueprint.apib`, `./swagger.yml`, `./swagger.json`, `http://example.com/api-blueprint.apib` + + ### API Location (string) + + URL, the root address of your API.
+ **Sample values:** `http://127.0.0.1:3000`, `http://api.example.com` + + ## Configuration File + + If you use Dredd repeatedly within a single project, the preferred way to run it is to first persist your configuration in a `dredd.yml` file. With the file in place you can then run Dredd every time simply just by: + + ``` + $ dredd + ``` + + Dredd offers interactive wizard to setup your `dredd.yml` file: + + ``` + $ dredd init + ``` + + See below how sample configuration file could look like. The structure is + the same as of the [Dredd Class configuration object](usage-js.md#configuration-object-for-dredd-class). + + ```yaml + reporter: apiary + custom: + - "apiaryApiKey:yourSecretApiaryAPiKey" + - "apiaryApiName:apiName" + dry-run: null + hookfiles: "dreddhooks.js" + sandbox: false + server: rails server + server-wait: 3 + init: false + custom: {} + names: false + only: [] + output: [] + header: [] + sorted: false + user: null + inline-errors: false + details: false + method: [] + level: info + timestamp: false + silent: false + path: [] + blueprint: api-description.apib + endpoint: "http://127.0.0.1:3000" + ``` + + > **Note:** Do not get confused by Dredd using a keyword `blueprint` also for paths to Swagger documents. This is for historical reasons and will be changed in the future. + + ## CLI Options Reference + + Remember you can always list all available arguments by `dredd --help`. + + <% for option in @options: %> + + + ### \-\-<%= option.name %><% if option.alias: %>, -<%= option.alias %><% end %> + + <%= option.description %>
+ <% if option.default: %> + **Default value:** `<%- JSON.stringify(option.default) %>` + <% end %> + + <% end %> diff --git a/docs/usage-js.rst b/docs/usage-js.rst index 89f3c3e8f..b73de1d1b 100644 --- a/docs/usage-js.rst +++ b/docs/usage-js.rst @@ -1,109 +1,112 @@ -## Using Dredd as a JavaScript Library +.. _usage-js: -Dredd can be used directly from your JavaScript code. First, import -and configure Dredd: +Using Dredd as a JavaScript Library +=================================== -```javascript -var Dredd = require('dredd'); -var dredd = new Dredd(configuration); -``` +Dredd can be used directly from your JavaScript code. First, import and configure Dredd: + +.. code:: javascript + + var Dredd = require('dredd'); + var dredd = new Dredd(configuration); Then you need to run the Dredd testing: -```javascript -dredd.run(function (err, stats) { - // err is present if anything went wrong - // otherwise stats is an object with useful statistics -}); -``` +.. code:: javascript -As you can see, `dredd.run` is a function receiving another function as a callback. -Received arguments are `err` (error if any) and `stats` (testing statistics) with -numbers accumulated throughout the Dredd run. + dredd.run(function (err, stats) { + // err is present if anything went wrong + // otherwise stats is an object with useful statistics + }); +As you can see, ``dredd.run`` is a function receiving another function as a callback. Received arguments are ``err`` (error if any) and ``stats`` (testing statistics) with numbers accumulated throughout the Dredd run. -### Configuration Object for Dredd Class +.. _configuration-object-for-dredd-class: -Let's have a look at an example configuration first. (Please also see [options source](https://github.com/apiaryio/dredd/blob/master/src/options.js) to read detailed information about the `options` attributes). +Configuration Object for Dredd Class +------------------------------------ -```javascript -{ - server: 'http://127.0.0.1:3000/api', // your URL to API endpoint the tests will run against - options: { +Let’s have a look at an example configuration first. (Please also see the `options source `__ to read detailed information about the ``options`` attributes). - 'path': [], // Required Array if Strings; filepaths to API description documents, can use glob wildcards +.. code:: javascript - 'dry-run': false, // Boolean, do not run any real HTTP transaction - 'names': false, // Boolean, Print Transaction names and finish, similar to dry-run + { + server: 'http://127.0.0.1:3000/api', // your URL to API endpoint the tests will run against + options: { - 'level': 'info', // String, log-level (info, silly, debug, verbose, ...) - 'silent': false, // Boolean, Silences all logging output + 'path': [], // Required Array if Strings; filepaths to API description documents, can use glob wildcards - 'only': [], // Array of Strings, run only transaction that match these names + 'dry-run': false, // Boolean, do not run any real HTTP transaction + 'names': false, // Boolean, Print Transaction names and finish, similar to dry-run - 'header': [], // Array of Strings, these strings are then added as headers (key:value) to every transaction - 'user': null, // String, Basic Auth credentials in the form username:password + 'level': 'info', // String, log-level (info, silly, debug, verbose, ...) + 'silent': false, // Boolean, Silences all logging output - 'hookfiles': [], // Array of Strings, filepaths to files containing hooks (can use glob wildcards) + 'only': [], // Array of Strings, run only transaction that match these names - 'reporter': ['dot', 'html'], // Array of possible reporters, see folder src/reporters + 'header': [], // Array of Strings, these strings are then added as headers (key:value) to every transaction + 'user': null, // String, Basic Auth credentials in the form username:password - 'output': [], // Array of Strings, filepaths to files used for output of file-based reporters + 'hookfiles': [], // Array of Strings, filepaths to files containing hooks (can use glob wildcards) - 'inline-errors': false, // Boolean, If failures/errors are display immediately in Dredd run + 'reporter': ['dot', 'html'], // Array of possible reporters, see folder src/reporters - 'color': true, - 'timestamp': false - }, + 'output': [], // Array of Strings, filepaths to files used for output of file-based reporters - 'emitter': EventEmitterInstance, // optional - listen to test progress, your own instance of EventEmitter + 'inline-errors': false, // Boolean, If failures/errors are display immediately in Dredd run - 'hooksData': { - 'pathToHook' : '...' - } + 'color': true, + 'timestamp': false + }, - 'data': { - 'path/to/file': '...' - } -} -``` + 'emitter': EventEmitterInstance, // optional - listen to test progress, your own instance of EventEmitter -### Properties + 'hooksData': { + 'pathToHook' : '...' + } -#### server (string) + 'data': { + 'path/to/file': '...' + } + } -Your choice of the API endpoint to test the API description against. -It must be a valid URL (you can specify `port`, `path` and http or https `protocol`). +Properties +---------- -#### options (object) +server (string) +~~~~~~~~~~~~~~~ -Because `options.path` array is required, you must specify options. You'll end -with errors otherwise. +Your choice of the API endpoint to test the API description against. It must be a valid URL (you can specify ``port``, ``path`` and http or https ``protocol``). - +options (object) +~~~~~~~~~~~~~~~~ -##### options.path (object) +Because ``options.path`` array is required, you must specify options. You’ll end with errors otherwise. + +options.path (object) +^^^^^^^^^^^^^^^^^^^^^ **Required** Array of filepaths to API description documents. Or it can also be an URL to download the API description from internet via http(s) protocol. -##### data (object) +data (object) +^^^^^^^^^^^^^ -**Optional** Object with keys as `filename` and value as `blueprint`-code. +**Optional** Object with keys as ``filename`` and value as ``blueprint``-code. -Useful when you don't want to operate on top of filesystem and want to pass -code of your API description as a string. You get the point. +Useful when you don’t want to operate on top of filesystem and want to pass code of your API description as a string. You get the point. -##### hooksData (object) +hooksData (object) +^^^^^^^^^^^^^^^^^^ -**Optional** Object with keys as `filename` and strings with JavaScript hooks code. +**Optional** Object with keys as ``filename`` and strings with JavaScript hooks code. Load hooks file code from string. Must be used together with sandboxed mode. -```javascript -{ - 'data': { - './api-description.apib': 'FORMAT: 1A\n\n# My String API\n\nGET /url\n+ Response 200\n\n Some content', - './directory/another-api-description.apib': '# Another API\n\n## Group Machines\n\n### Machine [/machine]\n\n#### Read machine [GET]\n\n...' - } -} -``` +.. code:: javascript + + { + 'data': { + './api-description.apib': 'FORMAT: 1A\n\n# My String API\n\nGET /url\n+ Response 200\n\n Some content', + './directory/another-api-description.apib': '# Another API\n\n## Group Machines\n\n### Machine [/machine]\n\n#### Read machine [GET]\n\n...' + } + } From 4253dd8a2d2321a6d32b9a685b4f99c20f2c1b4b Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Tue, 16 Oct 2018 19:30:21 +0200 Subject: [PATCH 07/22] docs: use code-block --- .github/CONTRIBUTING.rst | 4 +-- docs/hooks-go.rst | 10 ++++---- docs/hooks-js-sandbox.rst | 6 ++--- docs/hooks-nodejs.rst | 22 ++++++++--------- docs/hooks-perl.rst | 16 ++++++------ docs/hooks-php.rst | 12 ++++----- docs/hooks-python.rst | 16 ++++++------ docs/hooks-ruby.rst | 16 ++++++------ docs/hooks-rust.rst | 10 ++++---- docs/hooks.rst | 6 ++--- docs/how-it-works.rst | 2 +- docs/how-to-guides.rst | 52 +++++++++++++++++++-------------------- docs/installation.rst | 6 ++--- docs/quickstart.rst | 12 ++++----- docs/usage-js.rst | 8 +++--- 15 files changed, 99 insertions(+), 99 deletions(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 7d326f1d3..8bb1a7904 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -99,7 +99,7 @@ Forcing the JavaScript version The ``--no-optional`` option forces the JavaScript version of Drafter and avoids any compilation attempts when installing Dredd: -.. code:: sh +.. code-block:: shell $ npm install -g dredd --no-optional @@ -184,7 +184,7 @@ Installation and Development 2. `Get Python 3 `__. On macOS, run ``brew install python3``. `ReadTheDocs `__ build the docs with Python 3.5, so make sure you have that or higher. 3. Create a `virtual environment `__ and activate it: - .. code:: sh + .. code-block:: shell python3 -m venv ./venv . ./env/bin/activate diff --git a/docs/hooks-go.rst b/docs/hooks-go.rst index da7b3b001..f9e001921 100644 --- a/docs/hooks-go.rst +++ b/docs/hooks-go.rst @@ -36,7 +36,7 @@ You’ll need to know a few things about the ``Server`` type in the hooks packag 2. To get a ``hooks.Server`` struct you must do the following -.. code:: go +.. code-block:: go package main @@ -87,7 +87,7 @@ Using the Go API Example usage of all methods. -.. code:: go +.. code-block:: go package main @@ -137,7 +137,7 @@ How to Skip Tests Any test step can be skipped by setting the ``Skip`` property of the ``Transaction`` instance to ``true``. -.. code:: go +.. code-block:: go package main @@ -163,7 +163,7 @@ Failing Tests Programmatically You can fail any step by setting the ``Fail`` field of the ``Transaction`` instance to ``true`` or any string with a descriptive message. -.. code:: go +.. code-block:: go package main @@ -190,7 +190,7 @@ You can fail any step by setting the ``Fail`` field of the ``Transaction`` insta Modifying the Request Body Prior to Execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: go +.. code-block:: go package main diff --git a/docs/hooks-js-sandbox.rst b/docs/hooks-js-sandbox.rst index fe57fd742..e40198e6a 100644 --- a/docs/hooks-js-sandbox.rst +++ b/docs/hooks-js-sandbox.rst @@ -15,7 +15,7 @@ Dredd JS API Option Sandbox mode can be enabled in Dredd JavaScript API -.. code:: javascript +.. code-block:: javascript var Dredd = require('dredd'); var configuration = { @@ -68,7 +68,7 @@ The Sandbox mode can be used for running untrusted hook code. It can be activate Request Stash in Sandbox Mode ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: javascript +.. code-block:: javascript after('First action', function (transaction) { stash['id'] = JSON.parse(transaction.real.response); @@ -87,7 +87,7 @@ When **sandboxed**, hook function **context is not shared** between even the sam Note: **This is wrong**. It throws an exception. -.. code:: javascript +.. code-block:: javascript var myObject = {}; diff --git a/docs/hooks-nodejs.rst b/docs/hooks-nodejs.rst index bee4755a4..5f606faf5 100644 --- a/docs/hooks-nodejs.rst +++ b/docs/hooks-nodejs.rst @@ -24,7 +24,7 @@ API Reference Sync API ~~~~~~~~ -.. code:: javascript +.. code-block:: javascript var hooks = require('hooks'); @@ -65,7 +65,7 @@ Async API When the callback is used in the hook function, callbacks can handle asynchronous function calls. -.. code:: javascript +.. code-block:: javascript var hooks = require('hooks'); @@ -117,7 +117,7 @@ How to Skip Tests Any test step can be skipped by setting ``skip`` property of the ``transaction`` object to ``true``. -.. code:: javascript +.. code-block:: javascript var before = require('hooks').before; @@ -132,7 +132,7 @@ Sharing Data Between Steps in Request Stash You may pass data between test steps using the response stash. -.. code:: javascript +.. code-block:: javascript var hooks = require('hooks'); var before = hooks.before; @@ -161,7 +161,7 @@ Failing Tests Programmatically You can fail any step by setting ``fail`` property on ``transaction`` object to ``true`` or any string with descriptive message. -.. code:: javascript +.. code-block:: javascript var before = require('hooks').before; @@ -176,7 +176,7 @@ Using Chai Assertions Inside hook files, you can require `Chai `__ and use its ``assert``, ``should`` or ``expect`` interface in hooks and write your custom expectations. Dredd catches Chai’s expectation error in hooks and makes transaction to fail. -.. code:: javascript +.. code-block:: javascript var hooks = require('hooks'); var before = hooks.before; @@ -191,7 +191,7 @@ Inside hook files, you can require `Chai `__ and use its Modifying Transaction Request Body Prior to Execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: javascript +.. code-block:: javascript var hooks = require('hooks'); var before = hooks.before; @@ -212,7 +212,7 @@ Modifying Multipart Transaction Request Body Prior to Execution Dependencies: - `multi-part `__ - `stream-to-string `__ -.. code:: javascript +.. code-block:: javascript const hooks = require('hooks'); const fs = require('fs'); @@ -233,7 +233,7 @@ Dependencies: - `multi-part `__ - `str Adding or Changing URI Query Parameters to All Requests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: javascript +.. code-block:: javascript var hooks = require('hooks'); @@ -250,7 +250,7 @@ Adding or Changing URI Query Parameters to All Requests Handling sessions ~~~~~~~~~~~~~~~~~ -.. code:: javascript +.. code-block:: javascript var hooks = require('hooks'); var stash = {}; @@ -270,7 +270,7 @@ Handling sessions Remove trailing newline character in expected *plain text* bodies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: javascript +.. code-block:: javascript var hooks = require('hooks'); diff --git a/docs/hooks-perl.rst b/docs/hooks-perl.rst index 8e21e609c..6b83ec3a8 100644 --- a/docs/hooks-perl.rst +++ b/docs/hooks-perl.rst @@ -48,7 +48,7 @@ Using Perl API Example usage of all methods in -.. code:: perl +.. code-block:: perl use Dredd::Hooks::Methods; @@ -92,7 +92,7 @@ How to Skip Tests Any test step can be skipped by setting ``skip`` property of the ``transaction`` object to ``true``. -.. code:: perl +.. code-block:: perl use Dredd::Hooks::Methods; use Types::Serialiser; @@ -108,7 +108,7 @@ Sharing Data Between Steps in Request Stash If you want to test some API workflow, you may pass data between test steps using the response stash. -.. code:: perl +.. code-block:: perl use JSON; use Dredd::Hooks::Methods; @@ -138,7 +138,7 @@ Failing Tests Programmatically You can fail any step by setting ``fail`` property on ``transaction`` object to ``true`` or any string with descriptive message. -.. code:: perl +.. code-block:: perl use Dredd::Hooks::Methods; @@ -150,7 +150,7 @@ You can fail any step by setting ``fail`` property on ``transaction`` object to Modifying Transaction Request Body Prior to Execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: perl +.. code-block:: perl use JSON; use Dredd::Hooks::Methods; @@ -171,7 +171,7 @@ Modifying Transaction Request Body Prior to Execution Adding or Changing URI Query Parameters to All Requests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: perl +.. code-block:: perl use Dredd::Hooks::Methods; @@ -190,7 +190,7 @@ Adding or Changing URI Query Parameters to All Requests Handling sessions ~~~~~~~~~~~~~~~~~ -.. code:: perl +.. code-block:: perl use JSON; use Dredd::Hooks::Methods; @@ -217,7 +217,7 @@ Handling sessions Remove trailing newline character in expected *plain text* bodies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: perl +.. code-block:: perl use Dredd::Hooks::Methods; diff --git a/docs/hooks-php.rst b/docs/hooks-php.rst index bbe10cb69..bdf00dd9a 100644 --- a/docs/hooks-php.rst +++ b/docs/hooks-php.rst @@ -55,7 +55,7 @@ Using PHP API Example usage of all methods. **Very Important** The ``$transaction`` variable passed to the closure **MUST** be a reference. Otherwise the ``$transaction`` variable will be passed by value when the closure is executed and the changes will not be reflected. -.. code:: php +.. code-block:: php Machines collection > Get Machines diff --git a/docs/how-it-works.rst b/docs/how-it-works.rst index bd945809b..d5a2b1268 100644 --- a/docs/how-it-works.rst +++ b/docs/how-it-works.rst @@ -191,7 +191,7 @@ If there is no body example or schema specified for the response in your API des If you want to enforce the incoming body is empty, you can use :ref:`hooks `: -.. code:: javascript +.. code-block:: javascript :[hooks example](../test/fixtures/response/empty-body-hooks.js) diff --git a/docs/how-to-guides.rst b/docs/how-to-guides.rst index 0ff791cf0..ab7f9c208 100644 --- a/docs/how-to-guides.rst +++ b/docs/how-to-guides.rst @@ -22,7 +22,7 @@ To solve the situation, it’s recommended to isolate the deletion test by :ref: API Blueprint ^^^^^^^^^^^^^ -.. code:: apiblueprint +.. code-block:: apiblueprint FORMAT: 1A @@ -58,7 +58,7 @@ To have an idea where we can hook our arbitrary code, we should first ask Dredd Now we can create a ``hooks.js`` file. The file will contain setup and teardown of the database fixture: -.. code:: javascript +.. code-block:: javascript hooks = require('hooks'); db = require('./src/db'); @@ -82,7 +82,7 @@ Now we can create a ``hooks.js`` file. The file will contain setup and teardown Swagger ^^^^^^^ -.. code:: yaml +.. code-block:: yaml swagger: "2.0" info: @@ -140,7 +140,7 @@ To have an idea where we can hook our arbitrary code, we should first ask Dredd Now we can create a ``hooks.js`` file. The file will contain setup and teardown of the database fixture: -.. code:: javascript +.. code-block:: javascript hooks = require('hooks'); db = require('./src/db'); @@ -177,7 +177,7 @@ API Blueprint Example Imagine we have a simple workflow described: -.. code:: apiblueprint +.. code-block:: apiblueprint FORMAT: 1A @@ -228,7 +228,7 @@ To have an idea where we can hook our arbitrary code, we should first ask Dredd Now we can create a ``hooks.js`` file. The code of the file will use global ``stash`` variable to share data between requests: -.. code:: javascript +.. code-block:: javascript hooks = require('hooks'); db = require('./src/db'); @@ -263,7 +263,7 @@ Swagger Example Imagine we have a simple workflow described: -.. code:: yaml +.. code-block:: yaml swagger: "2.0" info: @@ -357,7 +357,7 @@ To have an idea where we can hook our arbitrary code, we should first ask Dredd Now we can create a ``hooks.js`` file. The code of the file will use global ``stash`` variable to share data between requests: -.. code:: javascript +.. code-block:: javascript hooks = require('hooks'); db = require('./src/db'); @@ -401,7 +401,7 @@ Avoiding Additional Properties If you describe a JSON body which has attributes ``name`` and ``size``, the following payload will be considered as correct: -.. code:: json +.. code-block:: json {"name": "Sparta", "size": 300, "luck": false} @@ -415,7 +415,7 @@ Requiring Properties If you describe a JSON body which has attributes ``name`` and ``size``, the following payload will be considered as correct: -.. code:: json +.. code-block:: json {"name": "Sparta"} @@ -429,7 +429,7 @@ Validating Structure of Array Items If you describe an array of items, where each of the items should have a ``name`` property, the following payload will be considered as correct: -.. code:: json +.. code-block:: json [{"name": "Sparta"}, {"title": "Athens"}, "Thebes"] @@ -443,7 +443,7 @@ Validating Specific Values If you describe a JSON body which has attributes ``name`` and ``size``, the following payload will be considered as correct: -.. code:: json +.. code-block:: json {"name": "Sparta", "size": 42} @@ -529,22 +529,22 @@ Most of the authentication schemes use HTTP header for carrying the authenticati Sending Multipart Requests -------------------------- -.. code:: apiblueprint +.. code-block:: apiblueprint :[API Blueprint example](../test/fixtures/request/multipart-form-data.apib) -.. code:: yaml +.. code-block:: yaml :[Swagger example](../test/fixtures/request/multipart-form-data.yaml) Sending Form Data ----------------- -.. code:: apiblueprint +.. code-block:: apiblueprint :[API Blueprint example](../test/fixtures/request/application-x-www-form-urlencoded.apib) -.. code:: yaml +.. code-block:: yaml :[Swagger example](../test/fixtures/request/application-x-www-form-urlencoded.yaml) @@ -559,14 +559,14 @@ Binary Request Body API Blueprint ^^^^^^^^^^^^^ -.. code:: apiblueprint +.. code-block:: apiblueprint :[API Blueprint example](../test/fixtures/request/image-png.apib) Swagger ^^^^^^^ -.. code:: yaml +.. code-block:: yaml :[Swagger example](../test/fixtures/request/image-png.yaml) @@ -575,7 +575,7 @@ Hooks In hooks, you can populate the request body with real binary data. The data must be in a form of a `Base64-encoded `__ string. -.. code:: javascript +.. code-block:: javascript :[Hooks example](../test/fixtures/request/image-png-hooks.js) @@ -585,14 +585,14 @@ Binary Response Body API Blueprint ^^^^^^^^^^^^^ -.. code:: apiblueprint +.. code-block:: apiblueprint :[API Blueprint example](../test/fixtures/response/binary.apib) Swagger ^^^^^^^ -.. code:: yaml +.. code-block:: yaml :[Swagger example](../test/fixtures/response/binary.yaml) @@ -605,13 +605,13 @@ Hooks In hooks, you can either assert the body: -.. code:: javascript +.. code-block:: javascript :[Hooks example](../test/fixtures/response/binary-assert-body-hooks.js) Or you can ignore it: -.. code:: javascript +.. code-block:: javascript :[Hooks example](../test/fixtures/response/binary-ignore-body-hooks.js) @@ -625,7 +625,7 @@ API Blueprint To test multiple requests and responses within one action in Dredd, you need to cluster them into pairs: -.. code:: apiblueprint +.. code-block:: apiblueprint FORMAT: 1A @@ -672,7 +672,7 @@ Swagger When using `Swagger `__ format, by default Dredd tests only responses with ``2xx`` status codes. Responses with other codes are marked as *skipped* and can be activated in :ref:`hooks `: -.. code:: javascript +.. code-block:: javascript var hooks = require('hooks'); @@ -741,7 +741,7 @@ While example values are natural part of the API Blueprint format, the Swagger s However, Dredd needs to know what values to use when testing described API, so it supports ``x-example`` `vendor extension property `__ to overcome the Swagger limitation: -.. code:: yaml +.. code-block:: yaml ... paths: diff --git a/docs/installation.rst b/docs/installation.rst index be2610bd7..458a66d39 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -64,13 +64,13 @@ Why Am I Seeing Network Errors? In a restricted network (VPN, firewall, proxy) you can see errors similar to the following ones: -.. code:: text +.. code-block:: text npmERR! Cannot read property 'path' of null npmERR!code ECONNRESET npmERR!network socket hang up -.. code:: text +.. code-block:: text Error: Command failed: git config --get remote.origin.url ssh: connect to host github.com port 22: Operation timed out @@ -78,7 +78,7 @@ In a restricted network (VPN, firewall, proxy) you can see errors similar to the To solve these issues, you need to set your proxy settings for both ``npm`` and ``git``: -.. code:: sh +.. code-block:: shell $ npm config set proxy "http://proxy.company.com:8080" $ npm config set https-proxy "https://proxy.company.com:8080" diff --git a/docs/quickstart.rst b/docs/quickstart.rst index b8dc5df95..45456b8cb 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -24,7 +24,7 @@ First, let’s design the API we are about to build and test. That means you wil If you choose API Blueprint, create a file called ``api-description.apib`` in the root of your project and save it with following content: -.. code:: apiblueprint +.. code-block:: apiblueprint FORMAT: 1A @@ -35,7 +35,7 @@ If you choose API Blueprint, create a file called ``api-description.apib`` in th If you choose Swagger, create a file called ``api-description.yml``: -.. code:: yaml +.. code-block:: yaml swagger: "2.0" info: @@ -68,14 +68,14 @@ Implement Your API As we mentioned in the beginning, we’ll use `Express.js `__ to implement the API. Install the framework by ``npm``: -.. code:: sh +.. code-block:: shell $ npm init $ npm install express --save Now let’s code the thing! Create a file called ``app.js`` with following contents: -.. code:: javascript +.. code-block:: javascript var app = require('express')(); @@ -90,13 +90,13 @@ Test Your API At this moment, the implementation is ready to be tested. Let’s run the server as a background process and let’s test it: -.. code:: sh +.. code-block:: shell $ node app.js & Finally, let Dredd validate whether your freshly implemented API complies with the description you have: -.. code:: sh +.. code-block:: shell $ dredd api-description.apib http://127.0.0.1:3000 # API Blueprint $ dredd api-description.yml http://127.0.0.1:3000 # Swagger diff --git a/docs/usage-js.rst b/docs/usage-js.rst index b73de1d1b..cf0e36094 100644 --- a/docs/usage-js.rst +++ b/docs/usage-js.rst @@ -5,14 +5,14 @@ Using Dredd as a JavaScript Library Dredd can be used directly from your JavaScript code. First, import and configure Dredd: -.. code:: javascript +.. code-block:: javascript var Dredd = require('dredd'); var dredd = new Dredd(configuration); Then you need to run the Dredd testing: -.. code:: javascript +.. code-block:: javascript dredd.run(function (err, stats) { // err is present if anything went wrong @@ -28,7 +28,7 @@ Configuration Object for Dredd Class Let’s have a look at an example configuration first. (Please also see the `options source `__ to read detailed information about the ``options`` attributes). -.. code:: javascript +.. code-block:: javascript { server: 'http://127.0.0.1:3000/api', // your URL to API endpoint the tests will run against @@ -102,7 +102,7 @@ hooksData (object) Load hooks file code from string. Must be used together with sandboxed mode. -.. code:: javascript +.. code-block:: javascript { 'data': { From d42e3f06bc0022d672e537ca023297281277ace7 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Wed, 17 Oct 2018 12:19:17 +0200 Subject: [PATCH 08/22] docs: backport one missing legacy anchor --- docs/usage-js.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/usage-js.rst b/docs/usage-js.rst index cf0e36094..a6819e1f0 100644 --- a/docs/usage-js.rst +++ b/docs/usage-js.rst @@ -83,6 +83,8 @@ options (object) Because ``options.path`` array is required, you must specify options. You’ll end with errors otherwise. +.. _optionspath-object: + options.path (object) ^^^^^^^^^^^^^^^^^^^^^ From 7730ee33fccac12b3394ba0f4fd78ac0737332b7 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Wed, 17 Oct 2018 12:19:50 +0200 Subject: [PATCH 09/22] docs: replace Hercule syntax with Sphinx syntax --- docs/how-it-works.rst | 5 ++-- docs/how-to-guides.rst | 55 +++++++++++++++++------------------------- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/docs/how-it-works.rst b/docs/how-it-works.rst index d5a2b1268..8fd9dfd6c 100644 --- a/docs/how-it-works.rst +++ b/docs/how-it-works.rst @@ -191,9 +191,8 @@ If there is no body example or schema specified for the response in your API des If you want to enforce the incoming body is empty, you can use :ref:`hooks `: -.. code-block:: javascript - - :[hooks example](../test/fixtures/response/empty-body-hooks.js) +.. literalinclude:: ../test/fixtures/response/empty-body-hooks.js + :language: javascript In case of responses with 204 or 205 status codes Dredd still behaves the same way, but it warns about violating the `RFC7231 `__ when the responses have non-empty bodies. diff --git a/docs/how-to-guides.rst b/docs/how-to-guides.rst index ab7f9c208..ec9bb798b 100644 --- a/docs/how-to-guides.rst +++ b/docs/how-to-guides.rst @@ -529,24 +529,20 @@ Most of the authentication schemes use HTTP header for carrying the authenticati Sending Multipart Requests -------------------------- -.. code-block:: apiblueprint - - :[API Blueprint example](../test/fixtures/request/multipart-form-data.apib) - -.. code-block:: yaml +.. literalinclude:: ../test/fixtures/request/multipart-form-data.apib + :language: apiblueprint - :[Swagger example](../test/fixtures/request/multipart-form-data.yaml) +.. literalinclude:: ../test/fixtures/request/multipart-form-data.yaml + :language: yaml Sending Form Data ----------------- -.. code-block:: apiblueprint +.. literalinclude:: ../test/fixtures/request/application-x-www-form-urlencoded.apib + :language: apiblueprint - :[API Blueprint example](../test/fixtures/request/application-x-www-form-urlencoded.apib) - -.. code-block:: yaml - - :[Swagger example](../test/fixtures/request/application-x-www-form-urlencoded.yaml) +.. literalinclude:: ../test/fixtures/request/application-x-www-form-urlencoded.yaml + :language: yaml Working with Images and other Binary Bodies ------------------------------------------- @@ -559,25 +555,22 @@ Binary Request Body API Blueprint ^^^^^^^^^^^^^ -.. code-block:: apiblueprint - - :[API Blueprint example](../test/fixtures/request/image-png.apib) +.. literalinclude:: ../test/fixtures/request/image-png.apib + :language: apiblueprint Swagger ^^^^^^^ -.. code-block:: yaml - - :[Swagger example](../test/fixtures/request/image-png.yaml) +.. literalinclude:: ../test/fixtures/request/image-png.yaml + :language: yaml Hooks ^^^^^ In hooks, you can populate the request body with real binary data. The data must be in a form of a `Base64-encoded `__ string. -.. code-block:: javascript - - :[Hooks example](../test/fixtures/request/image-png-hooks.js) +.. literalinclude:: ../test/fixtures/request/image-png-hooks.js + :language: javascript Binary Response Body ~~~~~~~~~~~~~~~~~~~~ @@ -585,16 +578,14 @@ Binary Response Body API Blueprint ^^^^^^^^^^^^^ -.. code-block:: apiblueprint - - :[API Blueprint example](../test/fixtures/response/binary.apib) +.. literalinclude:: ../test/fixtures/response/binary.apib + :language: apiblueprint Swagger ^^^^^^^ -.. code-block:: yaml - - :[Swagger example](../test/fixtures/response/binary.yaml) +.. literalinclude:: ../test/fixtures/response/binary.yaml + :language: yaml .. @@ -605,15 +596,13 @@ Hooks In hooks, you can either assert the body: -.. code-block:: javascript - - :[Hooks example](../test/fixtures/response/binary-assert-body-hooks.js) +.. literalinclude:: ../test/fixtures/response/binary-assert-body-hooks.js + :language: javascript Or you can ignore it: -.. code-block:: javascript - - :[Hooks example](../test/fixtures/response/binary-ignore-body-hooks.js) +.. literalinclude:: ../test/fixtures/response/binary-ignore-body-hooks.js + :language: javascript Multiple Requests and Responses ------------------------------- From 8af6dcfe24dccb348574212f2f93a250ff269ee7 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Wed, 17 Oct 2018 12:23:14 +0200 Subject: [PATCH 10/22] docs: use semantic reStructuredText notes --- docs/hooks-js-sandbox.rst | 3 ++- docs/how-it-works.rst | 11 ++++++----- docs/how-to-guides.rst | 11 ++++++----- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/docs/hooks-js-sandbox.rst b/docs/hooks-js-sandbox.rst index e40198e6a..b48efa11b 100644 --- a/docs/hooks-js-sandbox.rst +++ b/docs/hooks-js-sandbox.rst @@ -85,7 +85,8 @@ Hook function context is not shared When **sandboxed**, hook function **context is not shared** between even the same step hook functions. -Note: **This is wrong**. It throws an exception. +.. note:: + **This is wrong**. It throws an exception. .. code-block:: javascript diff --git a/docs/how-it-works.rst b/docs/how-it-works.rst index 8fd9dfd6c..3e09f01c4 100644 --- a/docs/how-it-works.rst +++ b/docs/how-it-works.rst @@ -143,7 +143,8 @@ Both `API Blueprint `__ and `Swagger `__ documents, HTTP headers are inferred from ` - ``produces`` (`docs `__) is propagated as request’s ``Accept`` header. - If request body parameters are specified as ``"in": "formData"``, request’s ``Content-Type`` header is set to ``application/x-www-form-urlencoded``. -.. - - **Note:** Processing ``"in": "header"`` parameters and inferring ``application/x-www-form-urlencoded`` from ``"in": "formData"`` parameters is not implemented yet (`apiaryio/fury-adapter-swagger#68 `__, `apiaryio/fury-adapter-swagger#67 `__). +.. note:: + Processing ``"in": "header"`` parameters and inferring ``application/x-www-form-urlencoded`` from ``"in": "formData"`` parameters is not implemented yet (`apiaryio/fury-adapter-swagger#68 `__, `apiaryio/fury-adapter-swagger#67 `__). Request Body ~~~~~~~~~~~~ @@ -216,7 +216,8 @@ While `API Blueprint `__ allows specifying multiple r In other words, Dredd always selects just the first response for each request. - **Note:** Improving the support for multiple requests and responses is under development. Refer to issues `#25 `__ and `#78 `__ for details. Support for URI parameters specific to a single request within one action is also limited. Solving `#227 `__ should unblock many related problems. Also see `Multiple Requests and Responses `__ guide for workarounds. +.. note:: + Improving the support for multiple requests and responses is under development. Refer to issues `#25 `__ and `#78 `__ for details. Support for URI parameters specific to a single request within one action is also limited. Solving `#227 `__ should unblock many related problems. Also see `Multiple Requests and Responses `__ guide for workarounds. Swagger ~~~~~~~ diff --git a/docs/how-to-guides.rst b/docs/how-to-guides.rst index ec9bb798b..32c072ee1 100644 --- a/docs/how-to-guides.rst +++ b/docs/how-to-guides.rst @@ -166,7 +166,8 @@ Testing API Workflows Often you want to test a sequence of steps, a scenario, rather than just one request-response pair in isolation. Since the API description formats are quite limited in their support of documenting scenarios, Dredd probably isn’t the best tool to provide you with this kind of testing. There are some tricks though, which can help you to work around some of the limitations. - **Note:** `API Blueprint `__ prepares direct support for testing and scenarios. Interested? Check out `apiaryio/api-blueprint#21 `__! +.. note:: + `API Blueprint `__ prepares direct support for testing and scenarios. Interested? Check out `apiaryio/api-blueprint#21 `__! To test various scenarios, you will want to write each of them into a separate API description document. To load them during a single test run, use the ``--path`` option (:ref:`docs `). @@ -587,9 +588,8 @@ Swagger .. literalinclude:: ../test/fixtures/response/binary.yaml :language: yaml -.. - - **Note:** Do not use the explicit ``binary`` or ``bytes`` formats with response bodies, as Dredd is not able to properly work with those (`fury-adapter-swagger#193 `__). +.. note:: + Do not use the explicit ``binary`` or ``bytes`` formats with response bodies, as Dredd is not able to properly work with those (`fury-adapter-swagger#193 `__). Hooks ~~~~~ @@ -607,7 +607,8 @@ Or you can ignore it: Multiple Requests and Responses ------------------------------- - **Note:** For details on this topic see also :ref:`How Dredd Works With HTTP Transactions `. +.. note:: + For details on this topic see also :ref:`How Dredd Works With HTTP Transactions `. API Blueprint ~~~~~~~~~~~~~ From 2f92d45515bd88758dcd0bf9d1cba953258e7d60 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Wed, 17 Oct 2018 12:45:38 +0200 Subject: [PATCH 11/22] docs: fix minor bugs in markup --- docs/hooks-js-sandbox.rst | 26 +++++++++----------------- docs/hooks-nodejs.rst | 5 ++++- docs/how-it-works.rst | 4 ++-- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/docs/hooks-js-sandbox.rst b/docs/hooks-js-sandbox.rst index b48efa11b..47b6e41fa 100644 --- a/docs/hooks-js-sandbox.rst +++ b/docs/hooks-js-sandbox.rst @@ -37,23 +37,15 @@ Sandboxed JavaScript Hooks API reference The Sandbox mode can be used for running untrusted hook code. It can be activated with a CLI switch or with the JS API. In each hook file you can use following functions: -``beforeAll(function)`` - -``beforeEach(function)`` - -``before(transactionName, function)`` - -``beforeEachValidation(function)`` - -``beforeValidation(transactionName, function)`` - -``after(transactionName, function)`` - -``afterEach(function)`` - -``afterAll(function)`` - -``log(string)`` +.. js:function:: beforeAll(function) +.. js:function:: beforeEach(function) +.. js:function:: before(transactionName, function) +.. js:function:: beforeEachValidation(function) +.. js:function:: beforeValidation(transactionName, function) +.. js:function:: after(transactionName, function) +.. js:function:: afterEach(function) +.. js:function:: afterAll(function) +.. js:function:: log(string) - A :ref:`Transaction Object ` is passed as a first argument to the hook function for ``before``, ``after``, ``beforeEach``, ``afterEach``, ``beforeValidation`` and ``beforeEachValidation``. - An array of Transaction Objects is passed to ``beforeAll`` and ``afterAll``. diff --git a/docs/hooks-nodejs.rst b/docs/hooks-nodejs.rst index 5f606faf5..f8cb56570 100644 --- a/docs/hooks-nodejs.rst +++ b/docs/hooks-nodejs.rst @@ -210,7 +210,10 @@ Modifying Transaction Request Body Prior to Execution Modifying Multipart Transaction Request Body Prior to Execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Dependencies: - `multi-part `__ - `stream-to-string `__ +Dependencies: + +- `multi-part `__ +- `stream-to-string `__ .. code-block:: javascript diff --git a/docs/how-it-works.rst b/docs/how-it-works.rst index 3e09f01c4..ee50d3b35 100644 --- a/docs/how-it-works.rst +++ b/docs/how-it-works.rst @@ -84,9 +84,9 @@ Response Headers Expectations - Only values of headers significant for content negotiation are validated. - All other headers values can differ. -When using `Swagger `__, headers are taken from ```response.headers`` `__. HTTP headers significant for content negotiation are inferred according to following rules: +When using `Swagger `__, headers are taken from ``response.headers`` (`docs `__). HTTP headers significant for content negotiation are inferred according to following rules: -- ```produces`` `__ is propagated as response’s ``Content-Type`` header. +- ``produces`` (`docs `__) is propagated as response’s ``Content-Type`` header. - Response’s ``Content-Type`` header overrides any ``produces``. Response Body Expectations From 2a9c16b16ff302a98840f5d0266af5c422ab0fee Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Wed, 17 Oct 2018 13:02:47 +0200 Subject: [PATCH 12/22] docs: fix linters and broken links --- .github/CONTRIBUTING.rst | 2 +- doc8.ini | 2 ++ docs/hooks-nodejs.rst | 2 +- docs/how-it-works.rst | 5 +++-- docs/how-to-guides.rst | 4 ++++ docs/installation.rst | 2 +- docs/usage-js.rst | 2 +- package.json | 2 +- 8 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 8bb1a7904..6f7c4765d 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -276,7 +276,7 @@ it uses a public API described in following documents: Following data are sent over the wire to Apiary: -- `Apiary Reporter Test Data `__ +- :ref:`Apiary Reporter Test Data ` There is also one environment variable you could find useful: diff --git a/doc8.ini b/doc8.ini index 06d3cb304..02b48beed 100644 --- a/doc8.ini +++ b/doc8.ini @@ -1,4 +1,6 @@ [doc8] +ignore-path=docs/_build + # Do not check line length. This project relies on writing in an editor with # word wrap turned on. No explicit newlines, please. ignore=D001 diff --git a/docs/hooks-nodejs.rst b/docs/hooks-nodejs.rst index f8cb56570..413458312 100644 --- a/docs/hooks-nodejs.rst +++ b/docs/hooks-nodejs.rst @@ -174,7 +174,7 @@ You can fail any step by setting ``fail`` property on ``transaction`` object to Using Chai Assertions ~~~~~~~~~~~~~~~~~~~~~ -Inside hook files, you can require `Chai `__ and use its ``assert``, ``should`` or ``expect`` interface in hooks and write your custom expectations. Dredd catches Chai’s expectation error in hooks and makes transaction to fail. +Inside hook files, you can require `Chai `__ and use its ``assert``, ``should`` or ``expect`` interface in hooks and write your custom expectations. Dredd catches Chai’s expectation error in hooks and makes transaction to fail. .. code-block:: javascript diff --git a/docs/how-it-works.rst b/docs/how-it-works.rst index ee50d3b35..af7f71fd5 100644 --- a/docs/how-it-works.rst +++ b/docs/how-it-works.rst @@ -217,12 +217,12 @@ While `API Blueprint `__ allows specifying multiple r In other words, Dredd always selects just the first response for each request. .. note:: - Improving the support for multiple requests and responses is under development. Refer to issues `#25 `__ and `#78 `__ for details. Support for URI parameters specific to a single request within one action is also limited. Solving `#227 `__ should unblock many related problems. Also see `Multiple Requests and Responses `__ guide for workarounds. + Improving the support for multiple requests and responses is under development. Refer to issues `#25 `__ and `#78 `__ for details. Support for URI parameters specific to a single request within one action is also limited. Solving `#227 `__ should unblock many related problems. Also see :ref:`multiple-requests-and-responses` guide for workarounds. Swagger ~~~~~~~ -The `Swagger `__ format allows to specify multiple responses for a single operation. By default Dredd tests only responses with ``2xx`` status codes. Responses with other codes are marked as *skipped* and can be activated in `hooks `__ - see the `Multiple Requests and Responses `__ how-to guide. +The `Swagger `__ format allows to specify multiple responses for a single operation. By default Dredd tests only responses with ``2xx`` status codes. Responses with other codes are marked as *skipped* and can be activated in :ref:`hooks ` - see the :ref:`multiple-requests-and-responses` how-to guide. In ``produces`` (`docs `__) and ``consumes`` (`docs `__), only JSON media types are supported. Only the first JSON media type in ``produces`` is effective, others are skipped. Other media types are respected only when provided with `explicit examples `__. @@ -245,6 +245,7 @@ When using :ref:`Apiary Reporter and Apiary Tests `. +.. _using-http-s-proxy: .. _using-https-proxy: Using HTTP(S) Proxy diff --git a/docs/how-to-guides.rst b/docs/how-to-guides.rst index 32c072ee1..797ab1e87 100644 --- a/docs/how-to-guides.rst +++ b/docs/how-to-guides.rst @@ -466,6 +466,8 @@ There are also some packages which make the integration a piece of cake: To find more, search for ``dredd`` in your favorite language’s package index. +.. _continuous-integration: + Continuous Integration ---------------------- @@ -604,6 +606,8 @@ Or you can ignore it: .. literalinclude:: ../test/fixtures/response/binary-ignore-body-hooks.js :language: javascript +.. _multiple-requests-and-responses: + Multiple Requests and Responses ------------------------------- diff --git a/docs/installation.rst b/docs/installation.rst index 458a66d39..3ac42dc3f 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -86,7 +86,7 @@ To solve these issues, you need to set your proxy settings for both ``npm`` and $ git config --global http.proxy "http://proxy.company.com:8080" $ git config --global https.proxy "https://proxy.company.com:8080" -When using ``git config``, make sure you have the port specified even when it’s the standard ``:80``. Also check out :ref:`how to set up Dredd to correctly work with proxies `. +When using ``git config``, make sure you have the port specified even when it’s the standard ``:80``. Also check out :ref:`how to set up Dredd to correctly work with proxies `. Why I’m Seeing ``node-gyp`` or ``python`` Errors? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/usage-js.rst b/docs/usage-js.rst index a6819e1f0..6bbd230fe 100644 --- a/docs/usage-js.rst +++ b/docs/usage-js.rst @@ -26,7 +26,7 @@ As you can see, ``dredd.run`` is a function receiving another function as a call Configuration Object for Dredd Class ------------------------------------ -Let’s have a look at an example configuration first. (Please also see the `options source `__ to read detailed information about the ``options`` attributes). +Let’s have a look at an example configuration first. (Please also see the :ref:`CLI options ` to read detailed information about the ``options`` attributes). .. code-block:: javascript diff --git a/package.json b/package.json index a60d76ee4..de56da836 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "build": "babel ./src --out-dir ./lib/", "build:watch": "babel ./src --out-dir ./lib/ --watch", "coveralls": "scripts/coveralls.sh", - "docs:lint": "doc8 && sphinx-build -nW -b linkcheck docs docs/_build/", + "docs:lint": "doc8 docs && sphinx-build -nW -b linkcheck docs docs/_build/", "docs:build": "sphinx-build -nW -b html docs docs/_build/", "docs:serve": "sphinx-autobuild docs docs/_build/", "lint": "conventional-changelog-lint --from=master && eslint .", From 7ec1a8d9629cddf0f87514d4d03b0ec424f5440d Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Wed, 17 Oct 2018 17:37:14 +0200 Subject: [PATCH 13/22] docs: use Sphinx extension to generate CLI options --- docs/_extensions/generate-cli-docs.coffee | 45 ----------- docs/conf.py | 22 ++--- docs/extensions/cli_options.py | 49 ++++++++++++ docs/usage-cli.md | 89 --------------------- docs/usage-cli.rst | 97 ++++++++++------------- 5 files changed, 103 insertions(+), 199 deletions(-) delete mode 100644 docs/_extensions/generate-cli-docs.coffee create mode 100644 docs/extensions/cli_options.py delete mode 100644 docs/usage-cli.md diff --git a/docs/_extensions/generate-cli-docs.coffee b/docs/_extensions/generate-cli-docs.coffee deleted file mode 100644 index 2d1cc0967..000000000 --- a/docs/_extensions/generate-cli-docs.coffee +++ /dev/null @@ -1,45 +0,0 @@ -# Generates CLI docs for Dredd. -# -# Purpose: -# Thanks to this we can be sure the CLI docs are always up-to-date. -# -# Usage: -# -# $ cat document-template.md | coffee generate-cli-docs.coffee > document.md - - -fs = require('fs') -path = require('path') -ect = require('ect') -clone = require('clone') - -options = require('../../src/options') - - -# Turn options into a sorted array -data = {options: []} - -for own name, attributes of options - option = clone(attributes) - option.description = option.description.trim() - option.name = name - data.options.push(option) - -data.options.sort((o1, o2) -> - switch - when o1.name < o2.name then -1 - when o1.name > o2.name then 1 - else 0 -) - - -# Process stdin -source = '' -process.stdin.on('data', (buffer) -> - source += buffer.toString() -) -process.stdin.on('end', -> - renderer = ect({root: {source}}) - rendered = renderer.render('source', data) - process.stdout.write(rendered) -) diff --git a/docs/conf.py b/docs/conf.py index 04e2d2d8a..ac2eeee19 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,14 +1,11 @@ import os +import sys import re import json import subprocess import urllib.request -from docutils import nodes -from sphinx.util import console from sphinx.errors import SphinxError -from recommonmark.parser import CommonMarkParser -from recommonmark.transform import AutoStructify ########################################################################### @@ -20,15 +17,25 @@ # -- Environment ---------------------------------------------------------- +# Explicitly put the extensions directory to Python path +sys.path.append(os.path.abspath('extensions')) + +# Detect whether the build happens on ReadTheDocs IS_READTHEDOCS = os.environ.get('READTHEDOCS') == 'True' +# Install all npm dependencies if on ReadTheDocs. This requires the latest +# ReadTheDocs build image, which supports Node.js out of the box. This is +# specified in the readthedocs.yml in the root of the project. if IS_READTHEDOCS: subprocess.check_call('npm install', cwd=project_dir, shell=True) +# Specify paths docs_dir = os.path.dirname(__file__) project_dir = os.path.join(docs_dir, '..') +extensions_dir = os.path.join(docs_dir, 'extensions') node_modules_bin_dir = os.path.join(project_dir, 'node_modules', '.bin') +# Load package.json data with open(os.path.join(project_dir, 'package.json')) as f: package_json = json.load(f) @@ -39,6 +46,7 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + 'cli_options', 'pygments_markdown_lexer', ] @@ -159,12 +167,6 @@ def get_release(): ] -# -- Custom Extensions ---------------------------------------------------- - -def setup(app): - pass - - # -- Hacks ---------------------------------------------------------------- import sphinx.application diff --git a/docs/extensions/cli_options.py b/docs/extensions/cli_options.py new file mode 100644 index 000000000..4107a5fac --- /dev/null +++ b/docs/extensions/cli_options.py @@ -0,0 +1,49 @@ +import os +import json + +from docutils import nodes +from docutils.statemachine import ViewList + +from sphinx.util.compat import Directive +from sphinx.util.nodes import nested_parse_with_titles + + +class CLIOptionsDirective(Directive): + required_arguments = 1 + + def run(self): + # Load options from given JSON file + options_path = os.path.join( + os.path.dirname(self.state.document['source']), + self.arguments[0], + ) + with open(options_path) as f: + options = json.load(f) + + # Generate reStructuredText lines + lines = [] + for name, attrs in sorted(options.items()): + ref = name + heading = f'.. option:: --{name}' + if 'alias' in attrs: + ref += f"-{attrs['alias']}" + heading += f", -{attrs['alias']}" + desc = f" {attrs['description']}" + if 'default' in attrs: + value = attrs['default'] + value = 'null' if value is None else str(value).lower() + desc += f' **Default value:** ``{value}``' + lines += ['', f'.. _{ref}:', '', heading, '', desc, ''] + + # Generate docutils nodes + result = ViewList() + for line in lines: + result.append(line, f'') + node = nodes.section(document=self.state.document) + nested_parse_with_titles(self.state, result, node) + return node.children + + +def setup(app): + app.add_directive('cli-options', CLIOptionsDirective) + return {'version': '1.0', 'parallel_read_safe': True} diff --git a/docs/usage-cli.md b/docs/usage-cli.md deleted file mode 100644 index 79cd2aedf..000000000 --- a/docs/usage-cli.md +++ /dev/null @@ -1,89 +0,0 @@ -# Command-line Interface - -## Usage - -``` -$ dredd '' '' [OPTIONS] -``` - -Example: - -``` -$ dredd ./apiary.md http://127.0.0.1:3000 -``` - -## Arguments - -### API Description Document (string) - -URL or path to the API description document (API Blueprint, Swagger).
-**Sample values:** `./api-blueprint.apib`, `./swagger.yml`, `./swagger.json`, `http://example.com/api-blueprint.apib` - -### API Location (string) - -URL, the root address of your API.
-**Sample values:** `http://127.0.0.1:3000`, `http://api.example.com` - -## Configuration File - -If you use Dredd repeatedly within a single project, the preferred way to run it is to first persist your configuration in a `dredd.yml` file. With the file in place you can then run Dredd every time simply just by: - -``` -$ dredd -``` - -Dredd offers interactive wizard to setup your `dredd.yml` file: - -``` -$ dredd init -``` - -See below how sample configuration file could look like. The structure is -the same as of the [Dredd Class configuration object](usage-js.md#configuration-object-for-dredd-class). - -```yaml -reporter: apiary -custom: - - "apiaryApiKey:yourSecretApiaryAPiKey" - - "apiaryApiName:apiName" -dry-run: null -hookfiles: "dreddhooks.js" -sandbox: false -server: rails server -server-wait: 3 -init: false -custom: {} -names: false -only: [] -output: [] -header: [] -sorted: false -user: null -inline-errors: false -details: false -method: [] -level: info -timestamp: false -silent: false -path: [] -blueprint: api-description.apib -endpoint: "http://127.0.0.1:3000" -``` - -> **Note:** Do not get confused by Dredd using a keyword `blueprint` also for paths to Swagger documents. This is for historical reasons and will be changed in the future. - -## CLI Options Reference - -Remember you can always list all available arguments by `dredd --help`. - -<% for option in @options: %> - - -### \-\-<%= option.name %><% if option.alias: %>, -<%= option.alias %><% end %> - -<%= option.description %>
-<% if option.default: %> -**Default value:** `<%- JSON.stringify(option.default) %>` -<% end %> - -<% end %> diff --git a/docs/usage-cli.rst b/docs/usage-cli.rst index 695ad1b6e..ee104865b 100644 --- a/docs/usage-cli.rst +++ b/docs/usage-cli.rst @@ -3,69 +3,63 @@ Command-line Interface ====================== -.. _api-description-document-string: -.. _path-p: -.. _hooks-worker-timeout: -.. _hooks-worker-connect-timeout: -.. _hooks-worker-connect-retry: -.. _hooks-worker-after-connect-wait: -.. _hooks-worker-term-timeout: -.. _hooks-worker-term-retry: -.. _hooks-worker-handler-host: -.. _hooks-worker-handler-port: - -Foo bar -------- +Usage +----- -.. - # Command-line Interface +:: - ## Usage - - ``` $ dredd '' '' [OPTIONS] - ``` - Example: +Example: + +:: - ``` $ dredd ./apiary.md http://127.0.0.1:3000 - ``` - ## Arguments +Arguments +--------- + +.. _api-description-document-string: + +API Description Document (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ### API Description Document (string) +URL or path to the API description document (API Blueprint, Swagger). - URL or path to the API description document (API Blueprint, Swagger).
- **Sample values:** `./api-blueprint.apib`, `./swagger.yml`, `./swagger.json`, `http://example.com/api-blueprint.apib` +**Sample values:** ``./api-blueprint.apib``, ``./swagger.yml``, ``./swagger.json``, ``http://example.com/api-blueprint.apib`` - ### API Location (string) +.. _api-location-string: - URL, the root address of your API.
- **Sample values:** `http://127.0.0.1:3000`, `http://api.example.com` +API Location (string) +~~~~~~~~~~~~~~~~~~~~~ - ## Configuration File +URL, the root address of your API. - If you use Dredd repeatedly within a single project, the preferred way to run it is to first persist your configuration in a `dredd.yml` file. With the file in place you can then run Dredd every time simply just by: +**Sample values:** ``http://127.0.0.1:3000``, ``http://api.example.com`` + +Configuration File +------------------ + +If you use Dredd repeatedly within a single project, the preferred way to run it is to first persist your configuration in a ``dredd.yml`` file. With the file in place you can then run Dredd every time simply just by: + +:: - ``` $ dredd - ``` - Dredd offers interactive wizard to setup your `dredd.yml` file: +Dredd offers interactive wizard to setup your ``dredd.yml`` file: + +:: - ``` $ dredd init - ``` - See below how sample configuration file could look like. The structure is - the same as of the [Dredd Class configuration object](usage-js.md#configuration-object-for-dredd-class). +See below how sample configuration file could look like. The structure is the same as of the :ref:`Dredd Class configuration object `. + +.. code-block:: yaml - ```yaml reporter: apiary custom: - - "apiaryApiKey:yourSecretApiaryAPiKey" - - "apiaryApiName:apiName" + - "apiaryApiKey:yourSecretApiaryAPiKey" + - "apiaryApiName:apiName" dry-run: null hookfiles: "dreddhooks.js" sandbox: false @@ -88,22 +82,15 @@ Foo bar path: [] blueprint: api-description.apib endpoint: "http://127.0.0.1:3000" - ``` - - > **Note:** Do not get confused by Dredd using a keyword `blueprint` also for paths to Swagger documents. This is for historical reasons and will be changed in the future. - - ## CLI Options Reference - Remember you can always list all available arguments by `dredd --help`. +.. note:: + Do not get confused by Dredd using a keyword ``blueprint`` also for paths to Swagger documents. This is for historical reasons and will be changed in the future. - <% for option in @options: %> - +CLI Options Reference +--------------------- - ### \-\-<%= option.name %><% if option.alias: %>, -<%= option.alias %><% end %> +Remember you can always list all available arguments by ``dredd --help``. - <%= option.description %>
- <% if option.default: %> - **Default value:** `<%- JSON.stringify(option.default) %>` - <% end %> +.. program:: dredd - <% end %> +.. cli-options:: ../src/options.json From 3b365b858263d5d236c27baee21dfa86ce321d92 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Wed, 17 Oct 2018 17:58:05 +0200 Subject: [PATCH 14/22] docs: use jinja2 to generate reStructuredText --- docs/extensions/cli_options.py | 36 ++++++++++++++++++++-------------- docs/requirements.txt | 1 + 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/docs/extensions/cli_options.py b/docs/extensions/cli_options.py index 4107a5fac..2307c901e 100644 --- a/docs/extensions/cli_options.py +++ b/docs/extensions/cli_options.py @@ -1,9 +1,10 @@ import os import json - +from textwrap import dedent from docutils import nodes from docutils.statemachine import ViewList +from jinja2 import Template from sphinx.util.compat import Directive from sphinx.util.nodes import nested_parse_with_titles @@ -20,24 +21,29 @@ def run(self): with open(options_path) as f: options = json.load(f) - # Generate reStructuredText lines - lines = [] + # Generate reStructuredText markup + rst = '' for name, attrs in sorted(options.items()): - ref = name - heading = f'.. option:: --{name}' - if 'alias' in attrs: - ref += f"-{attrs['alias']}" - heading += f", -{attrs['alias']}" - desc = f" {attrs['description']}" - if 'default' in attrs: - value = attrs['default'] - value = 'null' if value is None else str(value).lower() - desc += f' **Default value:** ``{value}``' - lines += ['', f'.. _{ref}:', '', heading, '', desc, ''] + data = { + 'name': name, + 'alias': attrs.get('alias'), + 'default': json.dumps(attrs['default']) if 'default' in attrs else None, + 'description': attrs['description'], + } + template = Template(dedent(''' + .. _{{ name }}{% if alias %}-{{ alias }}{% endif %}: + + .. option:: --{{ name }}{% if alias %}, -{{ alias }}{% endif %} + + {{ description }} + {% if default %}**Default value:** ``{{ default }}``{% endif %} + + ''')) + rst += template.render(**data) # Generate docutils nodes result = ViewList() - for line in lines: + for line in rst.splitlines(): result.append(line, f'') node = nodes.section(document=self.state.document) nested_parse_with_titles(self.state, result, node) diff --git a/docs/requirements.txt b/docs/requirements.txt index 86c63efb4..ba54b2c32 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,3 +4,4 @@ sphinx-rtd-theme==0.2.4 pygments-markdown-lexer==0.1.0.dev39 pygments-apiblueprint==0.1.0 doc8==0.8.0 +jinja2==2.10 From 2c6447a04508e603bf6d6ca6d972e5cd8cd3011e Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Wed, 17 Oct 2018 18:18:03 +0200 Subject: [PATCH 15/22] docs: use :option: wherever possible --- docs/hooks-js-sandbox.rst | 2 +- docs/hooks-new-language.rst | 22 +++++++++++----------- docs/hooks.rst | 4 ++-- docs/how-it-works.rst | 2 +- docs/how-to-guides.rst | 6 +++--- docs/usage-cli.rst | 20 +++++++------------- 6 files changed, 25 insertions(+), 31 deletions(-) diff --git a/docs/hooks-js-sandbox.rst b/docs/hooks-js-sandbox.rst index 47b6e41fa..2081d2efa 100644 --- a/docs/hooks-js-sandbox.rst +++ b/docs/hooks-js-sandbox.rst @@ -55,7 +55,7 @@ The Sandbox mode can be used for running untrusted hook code. It can be activate - You can access global ``stash`` object variables in each separate hook file. ``stash`` is passed between contexts of each hook function execution. This ``stash`` object purpose is to allow *transportation* of user defined values of type ``String``, ``Number``, ``Boolean``, ``null`` or ``Object`` and ``Array`` (no ``Functions`` or callbacks). - Hook code is evaluated with ``"use strict"`` directive - `details at MDN `__ - Sandboxed mode does not support hooks written in CoffeScript language -- You can print to console (via Dredd’s logger) with ``log`` function, taking into account the used logging level ``--level`` option (levels: ``error > warn > hook > info``) +- You can print to console (via Dredd’s logger) with ``log`` function, taking into account the used logging level :option:`--level` option (levels: ``error > warn > hook > info``) Request Stash in Sandbox Mode ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/hooks-new-language.rst b/docs/hooks-new-language.rst index 0ab564ba8..5a2d76dac 100644 --- a/docs/hooks-new-language.rst +++ b/docs/hooks-new-language.rst @@ -8,7 +8,7 @@ Dredd hooks handler client Dredd comes with concept of hooks language abstraction bridge via simple TCP socket. -When you run Dredd with ``--language`` argument, it runs the command in argument and tries to connect to ``http://127.0.0.1:61321``. If connection to the hook handling server wasn’t successful, it exits with exit code ``3``. +When you run Dredd with :option:`--language` option, it runs the given command and tries to connect to ``http://127.0.0.1:61321``. If connection to the hook handling server wasn’t successful, it exits with exit code ``3``. Dredd internally registers a function for each :ref:`type of hooks ` and when this function is executed it assigns execution ``uuid`` to that event, serializes received function parameters (a :ref:`Transaction object ` or an Array of it), sends it to the TCP socket to be handled (executed) in other language and waits until message with same ``uuid`` is received. After data reception it assigns received ``data`` back to the transaction, so other language can interact with transactions same way like :ref:`native Node.js hooks `. @@ -70,8 +70,8 @@ Termination When the testing is done, Dredd signals the hook handler process to terminate. This is done repeatedly with delays. When termination timeout is over, Dredd loses its patience and kills the process forcefully. -- **retry delays** can be configured by ``--hooks-worker-term-retry`` (:ref:`docs `) -- **timeout** can be configured by ``--hooks-worker-term-timeout`` (:ref:`docs `) +- **retry delays** can be configured by :option:`--hooks-worker-term-retry` +- **timeout** can be configured by :option:`--hooks-worker-term-timeout` On Linux or macOS, Dredd uses the ``SIGTERM`` signal to tell the hook handler process it should terminate. On Windows, where signals do not exist, Dredd sends the ``END OF TEXT`` character (``\u0003``, which is ASCII representation of Ctrl+C) to standard input of the process. @@ -101,14 +101,14 @@ Configuration Options There are several configuration options, which can help you during development: -- ``--hooks-worker-timeout`` - :ref:`docs ` -- ``--hooks-worker-connect-timeout`` - :ref:`docs ` -- ``--hooks-worker-connect-retry`` - :ref:`docs ` -- ``--hooks-worker-after-connect-wait`` - :ref:`docs ` -- ``--hooks-worker-term-timeout`` - :ref:`docs ` -- ``--hooks-worker-term-retry`` - :ref:`docs ` -- ``--hooks-worker-handler-host`` - :ref:`docs ` -- ``--hooks-worker-handler-port`` - :ref:`docs ` +- :option:`--hooks-worker-timeout` +- :option:`--hooks-worker-connect-timeout` +- :option:`--hooks-worker-connect-retry` +- :option:`--hooks-worker-after-connect-wait` +- :option:`--hooks-worker-term-timeout` +- :option:`--hooks-worker-term-retry` +- :option:`--hooks-worker-handler-host` +- :option:`--hooks-worker-handler-port` Need help? No problem! ---------------------- diff --git a/docs/hooks.rst b/docs/hooks.rst index f5ae1ce17..7e4070f91 100644 --- a/docs/hooks.rst +++ b/docs/hooks.rst @@ -35,7 +35,7 @@ Dredd doesn’t speak your language? :ref:`It’s very easy to write support for Using Hook Files ---------------- -To use a hook file with Dredd, use the ``--hookfiles`` flag in the command line. You can use this flag multiple times or use a `glob `__ expression for loading multiple hook files. Dredd executes hook files in alphabetical order. +To use a hook file with Dredd, use the :option:`--hookfiles` flag in the command line. You can use this flag multiple times or use a `glob `__ expression for loading multiple hook files. Dredd executes hook files in alphabetical order. Example: @@ -50,7 +50,7 @@ Getting Transaction Names For addressing specific test steps is used the **transaction names** of the compiled HTTP transactions (*actions*) from the API description. -In order to retrieve transaction names please run Dredd with the ``--names`` argument last and it will print all available names of transactions. +In order to retrieve transaction names please run Dredd with the :option:`--names` option last and it will print all available names of transactions. For example, given an API Blueprint file ``api-description.apib`` as following: diff --git a/docs/how-it-works.rst b/docs/how-it-works.rst index af7f71fd5..ec5c3e388 100644 --- a/docs/how-it-works.rst +++ b/docs/how-it-works.rst @@ -253,7 +253,7 @@ Using HTTP(S) Proxy You can tell Dredd to use HTTP(S) proxy for: -- downloading API description documents (:ref:`the positional argument ` or the ``--path`` option (docs :ref:`path-p`) accepts also URL) +- downloading API description documents (the positional argument :option:`api-description-document` or the :option:`--path` option accepts also URL) - :ref:`reporting to Apiary ` Dredd respects ``HTTP_PROXY``, ``HTTPS_PROXY``, ``NO_PROXY``, ``http_proxy``, ``https_proxy``, and ``no_proxy`` environment variables. For more information on how those work see `relevant section `__ of the underlying library’s documentation. diff --git a/docs/how-to-guides.rst b/docs/how-to-guides.rst index 797ab1e87..999b8eeaf 100644 --- a/docs/how-to-guides.rst +++ b/docs/how-to-guides.rst @@ -169,7 +169,7 @@ Often you want to test a sequence of steps, a scenario, rather than just one req .. note:: `API Blueprint `__ prepares direct support for testing and scenarios. Interested? Check out `apiaryio/api-blueprint#21 `__! -To test various scenarios, you will want to write each of them into a separate API description document. To load them during a single test run, use the ``--path`` option (:ref:`docs `). +To test various scenarios, you will want to write each of them into a separate API description document. To load them during a single test run, use the :option:`--path` option. For workflows to work properly, you’ll also need to keep **shared context** between individual HTTP transactions. You can use :ref:`hooks ` in order to achieve that. See tips on how to :ref:`pass data between transactions `. @@ -517,13 +517,13 @@ Dredd supports all common authentication schemes: - CSRF tokens - … -Use ``user`` setting in your configuration file or ``--user`` argument to provide HTTP basic authentication: +Use ``user`` setting in your configuration file or the :option:`--user` option to provide HTTP basic authentication: :: --user=user:password -Most of the authentication schemes use HTTP header for carrying the authentication data. If you don’t want to add authentication HTTP header to every request in the API description, you can instruct Dredd to do it for you: +Most of the authentication schemes use HTTP header for carrying the authentication data. If you don’t want to add authentication HTTP header to every request in the API description, you can instruct Dredd to do it for you by the :option:`--header` option: :: diff --git a/docs/usage-cli.rst b/docs/usage-cli.rst index ee104865b..77a2fd5df 100644 --- a/docs/usage-cli.rst +++ b/docs/usage-cli.rst @@ -8,7 +8,7 @@ Usage :: - $ dredd '' '' [OPTIONS] + $ dredd '' '' [OPTIONS] Example: @@ -21,21 +21,17 @@ Arguments .. _api-description-document-string: -API Description Document (string) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. option:: api-description-document -URL or path to the API description document (API Blueprint, Swagger). - -**Sample values:** ``./api-blueprint.apib``, ``./swagger.yml``, ``./swagger.json``, ``http://example.com/api-blueprint.apib`` + URL or path to the API description document (API Blueprint, Swagger). + **Sample values:** ``./api-blueprint.apib``, ``./swagger.yml``, ``./swagger.json``, ``http://example.com/api-blueprint.apib`` .. _api-location-string: -API Location (string) -~~~~~~~~~~~~~~~~~~~~~ - -URL, the root address of your API. +.. option:: api-location -**Sample values:** ``http://127.0.0.1:3000``, ``http://api.example.com`` + URL, the root address of your API. + **Sample values:** ``http://127.0.0.1:3000``, ``http://api.example.com`` Configuration File ------------------ @@ -91,6 +87,4 @@ CLI Options Reference Remember you can always list all available arguments by ``dredd --help``. -.. program:: dredd - .. cli-options:: ../src/options.json From 8806adb4c0821c5883002d854c376910cc0e47d9 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Thu, 18 Oct 2018 13:19:04 +0200 Subject: [PATCH 16/22] chore: remove ect and Hercule These were used only as extensions to building the docs. ect is now replaced with Jinja2 and Hercule is replaced by Sphinx' very own literalinclude directive. Closes https://github.com/apiaryio/dredd/issues/1048 Closes https://github.com/apiaryio/dredd/issues/1044 --- package-lock.json | 218 ---------------------------------------------- package.json | 2 - 2 files changed, 220 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0c6c91a27..080e684e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1375,12 +1375,6 @@ "integrity": "sha512-e9DBeH0Oby7EbUQN3DRWKxgbpEJO3KAZUhP0xDmPA23Qr6PmvXI7Ojy8ZthsOsz+1iSoaV9G7eWJXUOyryJ6NA==", "dev": true }, - "capture-stack-trace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", - "dev": true - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -1498,16 +1492,6 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=" }, - "clone-regexp": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.1.tgz", - "integrity": "sha512-Fcij9IwRW27XedRIJnSOEupS7RVcXtObJXbcUOX93UCLqqOdRpkvzKywOOSizmEK/Is3S/RHX9dLdfo6R1Q1mw==", - "dev": true, - "requires": { - "is-regexp": "^1.0.0", - "is-supported-regexp-flag": "^1.0.0" - } - }, "clone-stats": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", @@ -2349,15 +2333,6 @@ } } }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -2648,12 +2623,6 @@ "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, "duplexify": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", @@ -2680,39 +2649,6 @@ "jsbn": "~0.1.0" } }, - "ect": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/ect/-/ect-0.5.9.tgz", - "integrity": "sha1-ewTsGC67f7ORO2KeFpANsz4PTeA=", - "dev": true, - "requires": { - "coffee-script": ">= 1.5.0", - "optimist": "0.4.0" - }, - "dependencies": { - "coffee-script": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", - "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", - "dev": true - }, - "optimist": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.4.0.tgz", - "integrity": "sha1-y47Dfy/jqphky2eidSUOfhliCiU=", - "dev": true, - "requires": { - "wordwrap": "~0.0.2" - } - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - } - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4373,12 +4309,6 @@ "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", "dev": true }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -4787,25 +4717,6 @@ "resolved": "https://registry.npmjs.org/googlediff/-/googlediff-0.1.0.tgz", "integrity": "sha1-mazwXMBiI+tmwpAI2B+bLRjCRT0=" }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "dev": true, - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - } - }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -4916,34 +4827,6 @@ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, - "hercule": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/hercule/-/hercule-4.0.1.tgz", - "integrity": "sha1-fxfpPdxoOVqH3HlP2cAxsur7EzE=", - "dev": true, - "requires": { - "async": "^2.1.4", - "clone-regexp": "^1.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "got": "^6.5.0", - "isstream": "^0.1.2", - "left-split": "^1.0.0", - "lodash": "^4.0.0", - "meow": "^3.7.0", - "source-map": "^0.5.3", - "through2": "^2.0.0", - "through2-get": "^0.0.2" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -5279,30 +5162,12 @@ "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", "dev": true }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true - }, "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, - "is-retry-allowed": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", - "dev": true - }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -5315,12 +5180,6 @@ "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", "dev": true }, - "is-supported-regexp-flag": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.1.tgz", - "integrity": "sha512-3vcJecUUrpgCqc/ca0aWeNu64UGgxcvO60K/Fkr1N6RSvfGCTU60UKN68JDmKokgba0rFFJs12EnzOQa14ubKQ==", - "dev": true - }, "is-text-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", @@ -5719,12 +5578,6 @@ "vinyl-fs": "^2.4.3" } }, - "left-split": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/left-split/-/left-split-1.0.0.tgz", - "integrity": "sha1-vsUUwjz7TJV6mXTt/aOFvFlyiAY=", - "dev": true - }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -5799,12 +5652,6 @@ "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", "dev": true }, - "lodash._baseget": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/lodash._baseget/-/lodash._baseget-3.7.2.tgz", - "integrity": "sha1-G2rh1frPPCVTI1ChPBGXy4u2dPQ=", - "dev": true - }, "lodash._bindcallback": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", @@ -5840,15 +5687,6 @@ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "dev": true }, - "lodash._topath": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/lodash._topath/-/lodash._topath-3.8.1.tgz", - "integrity": "sha1-PsXiYGAU9MuX91X+aRTt2L/ADqw=", - "dev": true, - "requires": { - "lodash.isarray": "^3.0.0" - } - }, "lodash.assign": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz", @@ -5979,12 +5817,6 @@ "signal-exit": "^3.0.0" } }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, "lru-cache": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", @@ -6830,12 +6662,6 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", @@ -7945,35 +7771,6 @@ "xtend": "~4.0.0" } }, - "through2-get": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/through2-get/-/through2-get-0.0.2.tgz", - "integrity": "sha1-uj+J47zv1ATVb0zdYmqi1vqRXcc=", - "dev": true, - "requires": { - "lodash.get": "^3.7.0", - "through2": "^2.0.0", - "xtend": "4.0.1" - }, - "dependencies": { - "lodash.get": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-3.7.0.tgz", - "integrity": "sha1-POaK4skWg7KBzFOUEoMDy/deaR8=", - "dev": true, - "requires": { - "lodash._baseget": "^3.0.0", - "lodash._topath": "^3.0.0" - } - } - } - }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -8378,12 +8175,6 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true - }, "uptown": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/uptown/-/uptown-1.0.1.tgz", @@ -8417,15 +8208,6 @@ "pct-encode": "~1.0.0" } }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - }, "user-home": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", diff --git a/package.json b/package.json index de56da836..ab0952c8c 100644 --- a/package.json +++ b/package.json @@ -74,12 +74,10 @@ "conventional-changelog-lint": "1.1.9", "coveralls": "2.13.0", "drafter": "1.2.0", - "ect": "0.5.9", "eslint": "4.4.1", "eslint-config-airbnb": "15.1.0", "eslint-plugin-import": "2.7.0", "express": "4.16.3", - "hercule": "4.0.1", "istanbul": "0.4.5", "lcov-result-merger": "1.2.0", "mocha": "5.2.0", From 706599c7a8be6a8d4f6160c10359dc9870c9a981 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Thu, 18 Oct 2018 14:22:54 +0200 Subject: [PATCH 17/22] chore: document Python requirements --- docs/requirements.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index ba54b2c32..2bef51885 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,7 +1,14 @@ +# Not using pipenv on purpose as ReadTheDocs do not support it yet +# https://github.com/rtfd/readthedocs.org/issues/3181 + + +# dependencies sphinx==1.5.6 -sphinx-autobuild==0.7.1 -sphinx-rtd-theme==0.2.4 +jinja2==2.10 pygments-markdown-lexer==0.1.0.dev39 pygments-apiblueprint==0.1.0 + +# dev dependencies doc8==0.8.0 -jinja2==2.10 +sphinx-autobuild==0.7.1 +sphinx-rtd-theme==0.2.4 From 5d41df790d50c0efd36c88888f257c06e1ad28d8 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Thu, 18 Oct 2018 14:23:32 +0200 Subject: [PATCH 18/22] chore: make sure we're using Python 3.6 (aligned with ReadTheDocs) --- .travis.yml | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index 900e85235..0dc34d2a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,11 +3,8 @@ sudo: false dist: "trusty" language: "node_js" -addons: - apt: - packages: - - "python3" - - "python3-pip" +node_js: + - "10" cache: directories: - "node_modules" @@ -16,30 +13,28 @@ before_install: # so 'conventional-changelog-lint' could compare commits and lint them: marionebl/conventional-changelog-lint#7 - "git remote set-branches origin master && git fetch && git checkout master && git checkout -" - "npm -g install npm@6" - - "pip3 install --user -r docs/requirements.txt" -install: "npm install --no-optional" + - "pyenv global 3.6" +install: + - "npm install --no-optional" + - "pip install --user -r docs/requirements.txt" jobs: include: # stage 1, all following runs in parallel: - stage: "quality checks & tests" env: "JOB=quality_checks" - node_js: "10" script: "npm run lint && npm run docs:lint" - - node_js: "10" - env: "JOB=docs_build_dry_run" # why dry run? because production build happens directly on ReadTheDocs infrastructure + - env: "JOB=docs_build_dry_run" # why dry run? because production build happens directly on ReadTheDocs infrastructure script: "npm run docs:build" - - node_js: "6" - env: "JOB=node6" + - env: "JOB=node6" + node_js: "6" script: "npm run test:coverage && npm run coveralls" - - node_js: "8" - env: "JOB=node8" + - env: "JOB=node8" + node_js: "8" script: "npm run test:coverage && npm run coveralls" - - node_js: "10" - env: "JOB=node10" + - env: "JOB=node10" script: "npm run test:coverage && npm run coveralls" # stage 2 - stage: "semantic release" - node_js: "10" script: "npm run semantic-release || true" if: fork = false AND branch = master AND type = push From 680d32467addf66dfb0d5799811e40a70ea351d3 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Thu, 18 Oct 2018 15:04:16 +0200 Subject: [PATCH 19/22] style: fix lint error --- src/cli.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cli.js b/src/cli.js index 6d909a44e..52aac15cb 100644 --- a/src/cli.js +++ b/src/cli.js @@ -2,7 +2,6 @@ const console = require('console'); // Stubbed in tests by proxyquire const fs = require('fs'); const optimist = require('optimist'); const os = require('os'); -const clone = require('clone'); const spawnArgs = require('spawn-args'); const spawnSync = require('cross-spawn').sync; From 710460399d481995e968bac77986e461cc92d662 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Thu, 18 Oct 2018 15:12:26 +0200 Subject: [PATCH 20/22] chore: update docs dependencies Uses pygments-markdown-lexer from git as https://github.com/jhermann/pygments-markdown-lexer/issues/6 still isn't released :( --- docs/extensions/cli_options.py | 2 +- docs/requirements.txt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/extensions/cli_options.py b/docs/extensions/cli_options.py index 2307c901e..9820bd4fe 100644 --- a/docs/extensions/cli_options.py +++ b/docs/extensions/cli_options.py @@ -3,9 +3,9 @@ from textwrap import dedent from docutils import nodes from docutils.statemachine import ViewList +from docutils.parsers.rst import Directive from jinja2 import Template -from sphinx.util.compat import Directive from sphinx.util.nodes import nested_parse_with_titles diff --git a/docs/requirements.txt b/docs/requirements.txt index 2bef51885..520ec5d07 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,12 +3,12 @@ # dependencies -sphinx==1.5.6 +sphinx==1.8.1 jinja2==2.10 -pygments-markdown-lexer==0.1.0.dev39 +-e git://github.com/jhermann/pygments-markdown-lexer.git@e651a9a3f664285b01451eb39232b1ad9af65956#egg=pygments-markdown-lexer pygments-apiblueprint==0.1.0 # dev dependencies doc8==0.8.0 sphinx-autobuild==0.7.1 -sphinx-rtd-theme==0.2.4 +sphinx-rtd-theme==0.4.2 From 804abeab4b9ee250697c4a9ce3e25d9e47227f45 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Thu, 18 Oct 2018 20:58:48 +0200 Subject: [PATCH 21/22] docs: fix a bug in precedence of variables --- docs/conf.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index ac2eeee19..2b53462a0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -23,18 +23,17 @@ # Detect whether the build happens on ReadTheDocs IS_READTHEDOCS = os.environ.get('READTHEDOCS') == 'True' +# Specify paths +docs_dir = os.path.dirname(__file__) +project_dir = os.path.join(docs_dir, '..') +node_modules_bin_dir = os.path.join(project_dir, 'node_modules', '.bin') + # Install all npm dependencies if on ReadTheDocs. This requires the latest # ReadTheDocs build image, which supports Node.js out of the box. This is # specified in the readthedocs.yml in the root of the project. if IS_READTHEDOCS: subprocess.check_call('npm install', cwd=project_dir, shell=True) -# Specify paths -docs_dir = os.path.dirname(__file__) -project_dir = os.path.join(docs_dir, '..') -extensions_dir = os.path.join(docs_dir, 'extensions') -node_modules_bin_dir = os.path.join(project_dir, 'node_modules', '.bin') - # Load package.json data with open(os.path.join(project_dir, 'package.json')) as f: package_json = json.load(f) From 8a33d0ad6c2341c6a47087cedda45499a7e6b761 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Thu, 18 Oct 2018 21:22:40 +0200 Subject: [PATCH 22/22] refactor: fix babel and imports to include options.json --- package.json | 18 +++++++++--------- src/dredd.js | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index ab0952c8c..01ae5d9ae 100644 --- a/package.json +++ b/package.json @@ -10,19 +10,19 @@ "node": ">= 6" }, "scripts": { - "build": "babel ./src --out-dir ./lib/", - "build:watch": "babel ./src --out-dir ./lib/ --watch", - "coveralls": "scripts/coveralls.sh", - "docs:lint": "doc8 docs && sphinx-build -nW -b linkcheck docs docs/_build/", - "docs:build": "sphinx-build -nW -b html docs docs/_build/", - "docs:serve": "sphinx-autobuild docs docs/_build/", + "build": "babel ./src --out-dir ./lib --copy-files", + "build:watch": "babel ./src --out-dir ./lib --copy-files --watch", + "coveralls": "./scripts/coveralls.sh", + "docs:lint": "doc8 ./docs && sphinx-build -nW -b linkcheck ./docs ./docs/_build/", + "docs:build": "sphinx-build -nW -b html ./docs ./docs/_build/", + "docs:serve": "sphinx-autobuild docs ./docs/_build/", "lint": "conventional-changelog-lint --from=master && eslint .", "prepare": "npm run build", "pretest": "npm run build", "semantic-release": "scripts/semantic-release.sh", - "test": "mocha \"test/**/*-test.js\"", - "test:coverage": "scripts/coverage.sh", - "test:debug": "mocha --debug-brk \"test/**/*-test.js\"" + "test": "mocha \"./test/**/*-test.js\"", + "test:coverage": "./scripts/coverage.sh", + "test:debug": "mocha --debug-brk \"./test/**/*-test.js\"" }, "repository": { "type": "git", diff --git a/src/dredd.js b/src/dredd.js index 1777a837b..f7ec92a07 100644 --- a/src/dredd.js +++ b/src/dredd.js @@ -12,7 +12,7 @@ const logger = require('./logger'); const Runner = require('./transaction-runner'); const { applyConfiguration } = require('./configuration'); -const options = require('./options'); +const options = require('./options.json'); const PROXY_ENV_VARIABLES = ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY']; const FILE_DOWNLOAD_TIMEOUT = 5000;