├── .babelrc ├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── bin └── just-api ├── docs ├── cinder │ ├── __init__.py │ ├── css │ │ ├── base.css │ │ ├── bootstrap-custom.css │ │ ├── bootstrap-custom.min.css │ │ ├── cinder.css │ │ ├── font-awesome-4.0.3.css │ │ └── highlight.css │ ├── fonts │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ ├── img │ │ ├── favicon.ico │ │ ├── grid1.png │ │ ├── grid10.png │ │ ├── grid11.png │ │ ├── grid12.png │ │ ├── grid13.png │ │ ├── grid14.png │ │ ├── grid15.png │ │ ├── grid16.png │ │ ├── grid17.png │ │ ├── grid18.png │ │ ├── grid19.png │ │ ├── grid2.png │ │ ├── grid20.png │ │ ├── grid3.png │ │ ├── grid4.png │ │ ├── grid5.png │ │ ├── grid6.png │ │ ├── grid7.png │ │ ├── grid8.png │ │ └── grid9.png │ └── js │ │ ├── base.js │ │ ├── bootstrap-3.0.3.min.js │ │ ├── highlight.pack.js │ │ └── jquery-1.10.2.min.js ├── docs │ ├── CLI.md │ ├── basic-concepts.md │ ├── examples.md │ ├── features.md │ ├── getting-started.md │ ├── img │ │ └── html-report.png │ ├── index.md │ ├── js │ │ └── extra.js │ ├── reporters.md │ └── running-suites-in-parallel.md └── mkdocs.yml ├── gulpfile.js ├── justapi_diagram.png ├── lib ├── errors.js ├── just-api.js ├── launcher.js ├── main.js ├── reporters │ ├── base.js │ ├── html-src │ │ ├── assets │ │ │ ├── html-report.css │ │ │ └── html-report.js │ │ └── template.js │ ├── html.js │ ├── json.js │ └── specs.js ├── request.js ├── response.js ├── schema │ ├── validator.js │ └── yaml │ │ ├── custom-types.js │ │ ├── loader.js │ │ ├── suite-config.json │ │ └── suite.json ├── spec.js ├── suite-dependency.js ├── suite.js └── utils.js ├── npm-shrinkwrap.json ├── package.json └── test ├── api ├── db_original.json ├── package.json └── server.js └── cli ├── additionalopts.spec.js ├── afterall.spec.js ├── aftereach.spec.js ├── aftertest.spec.js ├── beforeall.spec.js ├── beforeeach.spec.js ├── beforetest.spec.js ├── cookies.spec.js ├── customvalidator.spec.js ├── disabledspecs.spec.js ├── disabledsuite.spec.js ├── grep.spec.js ├── headers.spec.js ├── helpers.js ├── https.spec.js ├── interdep.spec.js ├── interdep.suite.relative.paths.spec.js ├── intradep.spec.js ├── invalidsuiteschema.spec.js ├── jsondata.spec.js ├── jsonschema.spec.js ├── loop.spec.js ├── multipartformbody.spec.js ├── otherverbs.spec.js ├── params.spec.js ├── postrawbody.spec.js ├── retry.spec.js ├── smoke.spec.js ├── src ├── modules │ ├── after_each.js │ ├── after_test.js │ ├── before_each.js │ ├── before_test.js │ ├── custom_validator.js │ ├── loop.js │ └── suite_configuration.js ├── static │ ├── assets │ │ ├── chow.jpg │ │ └── logo.png │ └── schema │ │ ├── junk_simple_valid.json │ │ ├── simple_invalid.json │ │ └── simple_valid.json └── suites │ ├── additional.opts.suite.yml │ ├── cookies.suite.yml │ ├── customvalidator.suite.yml │ ├── disabledspecs.suite.yml │ ├── disabledsuite.suite.yml │ ├── grep.suite.yml │ ├── headers.suite.yaml │ ├── hooks │ ├── afterall │ │ ├── afterall.inline.async.failure.suite.yml │ │ ├── afterall.inline.async.success.suite.yml │ │ ├── afterall.inline.failure.suite.yml │ │ └── afterall.inline.success.suite.yml │ ├── aftereach │ │ ├── aftereach.inline.async.failure.suite.yml │ │ ├── aftereach.inline.async.success.suite.yml │ │ ├── aftereach.inline.failure.suite.yml │ │ ├── aftereach.inline.success.suite.yml │ │ ├── aftereach.module.async.failure.suite.yml │ │ ├── aftereach.module.async.success.suite.yml │ │ ├── aftereach.module.failure.suite.yml │ │ └── aftereach.module.success.suite.yml │ ├── aftertest.suite.yml │ ├── beforeall │ │ ├── beforeall.inline.async.failure.suite.yml │ │ ├── beforeall.inline.async.success.suite.yml │ │ ├── beforeall.inline.failure.suite.yml │ │ └── beforeall.inline.success.suite.yml │ ├── beforeeach │ │ ├── beforeeach.inline.async.failure.suite.yml │ │ ├── beforeeach.inline.async.success.suite.yml │ │ ├── beforeeach.inline.failure.suite.yml │ │ ├── beforeeach.inline.success.suite.yml │ │ ├── beforeeach.module.async.failure.suite.yml │ │ ├── beforeeach.module.async.success.suite.yml │ │ ├── beforeeach.module.failure.suite.yml │ │ └── beforeeach.module.success.suite.yml │ └── beforetest.suite.yml │ ├── https.suite.yml │ ├── jsondata.suite.yml │ ├── jsonschema.suite.yml │ ├── loop.suite.yml │ ├── multipartformpost.suite.yml │ ├── otherverbs.suite.yml │ ├── params.suite.yml │ ├── postrawbody.suite.yml │ ├── retry.suite.yml │ ├── smoke.suite.yml │ ├── smoke2.suite.yml │ ├── statuscode.suite.yml │ ├── suite.relative.paths.suite.yml │ ├── suiteconfig │ ├── inline.async.error.suite.yml │ ├── inline.async.invalidconfig.suite.yml │ ├── inline.async.rejectedpromise.suite.yml │ ├── inline.async.valid.suite.yml │ ├── inline.sync.error.suite.yml │ ├── inline.sync.invalidconfig.suite.yml │ └── inline.sync.valid.suite.yml │ ├── suitedependencies │ ├── dep.suite.yml │ ├── intersuitedeps.suite.yml │ ├── intradependencies.suite.yml │ └── relative.intersuite.dep.suite.yml │ ├── suiteschema │ └── invalidspecschema.suite.yml │ └── urlencodeformpost.suite.yml ├── statuscode.spec.js ├── suite.relative.paths.spec.js ├── suiteconfig.spec.js └── urlencodedformpost.spec.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | plugins: [ 3 | "array-includes", 4 | "add-module-exports", 5 | "transform-es2015-modules-commonjs", 6 | "transform-es2015-spread", 7 | "transform-es2015-parameters", 8 | "transform-es2015-destructuring", 9 | "transform-object-rest-spread" ] 10 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [kiranz] 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | *.DS_Store 4 | 5 | src/ 6 | local/ 7 | test/api/node_modules 8 | test/api/db.json 9 | !test/cli/src 10 | test/cli/src/logs/ 11 | test/cli/src/*.html 12 | test/cli/src/*.json 13 | node_modules/ 14 | docs/site/ 15 | logs/ 16 | *.txt 17 | *.html 18 | *.log 19 | report.json -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | *.DS_Store 4 | .github/ 5 | docs/ 6 | lib/ 7 | local/ 8 | test/ 9 | scripts/ 10 | logs/ 11 | test/cli/src/logs 12 | test/cli/src/*.html 13 | test/cli/src/*.json 14 | 15 | *.html 16 | *.txt 17 | *.log 18 | report.json 19 | 20 | .travis.yml 21 | circle.yml 22 | .gitignore -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kiran 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /bin/just-api: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var semver = require('semver'); 4 | var package = require('./../package'); 5 | var version = package.engines.node; 6 | 7 | if (!semver.satisfies(process.version, version)) { 8 | console.log('Required node version:' + version + ', current version:' + process.version + '. Please upgrade.'); 9 | process.exit(1); 10 | } 11 | 12 | require('../src/main.js'); -------------------------------------------------------------------------------- /docs/cinder/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/__init__.py -------------------------------------------------------------------------------- /docs/cinder/css/base.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 70px; 3 | } 4 | 5 | h1[id]:before, h2[id]:before, h3[id]:before, h4[id]:before, h5[id]:before, h6[id]:before { 6 | content: ""; 7 | display: block; 8 | margin-top: -75px; 9 | height: 75px; 10 | } 11 | 12 | p > img { 13 | max-width: 100%; 14 | height: auto; 15 | } 16 | 17 | ul.nav li.first-level { 18 | font-weight: bold; 19 | } 20 | 21 | ul.nav li.third-level { 22 | padding-left: 12px; 23 | } 24 | 25 | div.col-md-3 { 26 | padding-left: 0; 27 | } 28 | 29 | div.col-md-9 { 30 | padding-bottom: 100px; 31 | } 32 | 33 | div.source-links { 34 | float: right; 35 | } 36 | 37 | /* 38 | * Side navigation 39 | * 40 | * Scrollspy and affixed enhanced navigation to highlight sections and secondary 41 | * sections of docs content. 42 | */ 43 | 44 | /* By default it's not affixed in mobile views, so undo that */ 45 | .bs-sidebar.affix { 46 | position: static; 47 | } 48 | 49 | .bs-sidebar.well { 50 | padding: 0; 51 | } 52 | 53 | /* First level of nav */ 54 | .bs-sidenav { 55 | margin-top: 30px; 56 | margin-bottom: 30px; 57 | padding-top: 10px; 58 | padding-bottom: 10px; 59 | border-radius: 5px; 60 | } 61 | 62 | /* All levels of nav */ 63 | .bs-sidebar .nav > li > a { 64 | display: block; 65 | padding: 5px 20px; 66 | z-index: 1; 67 | } 68 | .bs-sidebar .nav > li > a:hover, 69 | .bs-sidebar .nav > li > a:focus { 70 | text-decoration: none; 71 | border-right: 1px solid; 72 | } 73 | .bs-sidebar .nav > .active > a, 74 | .bs-sidebar .nav > .active:hover > a, 75 | .bs-sidebar .nav > .active:focus > a { 76 | font-weight: bold; 77 | background-color: transparent; 78 | border-right: 1px solid; 79 | } 80 | 81 | /* Nav: second level (shown on .active) */ 82 | .bs-sidebar .nav .nav { 83 | display: none; /* Hide by default, but at >768px, show it */ 84 | margin-bottom: 8px; 85 | } 86 | .bs-sidebar .nav .nav > li > a { 87 | padding-top: 3px; 88 | padding-bottom: 3px; 89 | padding-left: 30px; 90 | font-size: 90%; 91 | } 92 | 93 | /* Show and affix the side nav when space allows it */ 94 | @media (min-width: 992px) { 95 | .bs-sidebar .nav > .active > ul { 96 | display: block; 97 | } 98 | /* Widen the fixed sidebar */ 99 | .bs-sidebar.affix, 100 | .bs-sidebar.affix-bottom { 101 | width: 213px; 102 | } 103 | .bs-sidebar.affix { 104 | position: fixed; /* Undo the static from mobile first approach */ 105 | top: 80px; 106 | } 107 | .bs-sidebar.affix-bottom { 108 | position: absolute; /* Undo the static from mobile first approach */ 109 | } 110 | .bs-sidebar.affix-bottom .bs-sidenav, 111 | .bs-sidebar.affix .bs-sidenav { 112 | margin-top: 0; 113 | margin-bottom: 0; 114 | } 115 | } 116 | @media (min-width: 1200px) { 117 | /* Widen the fixed sidebar again */ 118 | .bs-sidebar.affix-bottom, 119 | .bs-sidebar.affix { 120 | width: 263px; 121 | } 122 | } 123 | 124 | 125 | /* Added to support >2 level nav in drop down */ 126 | 127 | .dropdown-submenu { 128 | position: relative; 129 | } 130 | 131 | .dropdown-submenu>.dropdown-menu { 132 | top: 0; 133 | left: 100%; 134 | margin-top: 0px; 135 | margin-left: 0px; 136 | -webkit-border-radius: 0 6px 6px 6px; 137 | -moz-border-radius: 0 6px 6px; 138 | border-radius: 0 6px 6px 6px; 139 | } 140 | 141 | .dropdown-submenu:hover>.dropdown-menu { 142 | display: block; 143 | } 144 | 145 | .dropdown-submenu>a:after { 146 | display: block; 147 | content: " "; 148 | float: right; 149 | width: 0; 150 | height: 0; 151 | border-color: transparent; 152 | border-style: solid; 153 | border-width: 5px 0 5px 5px; 154 | border-left-color: #ccc; 155 | margin-top: 5px; 156 | margin-right: -10px; 157 | } 158 | 159 | .dropdown-submenu:hover>a:after { 160 | border-left-color: #fff; 161 | } 162 | 163 | .dropdown-submenu.pull-left { 164 | float: none; 165 | } 166 | 167 | .dropdown-submenu.pull-left>.dropdown-menu { 168 | left: -100%; 169 | margin-left: 00px; 170 | -webkit-border-radius: 6px 0 6px 6px; 171 | -moz-border-radius: 6px 0 6px 6px; 172 | border-radius: 6px 0 6px 6px; 173 | } 174 | -------------------------------------------------------------------------------- /docs/cinder/css/cinder.css: -------------------------------------------------------------------------------- 1 | /* 2 | Cinder Theme for MkDocs | Copyright 2015 Christopher Simpkins | MIT License 3 | */ 4 | 5 | body { 6 | font-family:"Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 7 | font-size: 16px; 8 | line-height: 1.7; 9 | background-color: #FFF; 10 | color: #343838; 11 | } 12 | h1, h2, h3, h4, h5, h6 { 13 | font-family:'PT Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 14 | color: #222; 15 | } 16 | h1 small, h2 small, h3 small, h4 small, h5 small, h6 small, .h1 small, .h2 small, .h3 small, .h4 small, .h5 small, .h6 small, h1 .small, h2 .small, h3 .small, h4 .small, h5 .small, h6 .small, .h1 .small, .h2 .small, .h3 .small, .h4 .small, .h5 .small, .h6 .small { 17 | color: #B1B7B9; 18 | } 19 | h1, h2 { 20 | font-weight: 700; 21 | } 22 | h4 { 23 | font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 24 | font-weight: 300; 25 | margin-top: 20px; 26 | font-style: italic; 27 | } 28 | h5 { 29 | font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 30 | font-weight: 300; 31 | font-variant: small-caps; 32 | } 33 | pre, code { 34 | background-color: #FCFDFF; 35 | } 36 | pre>code { 37 | font-size: 13px; 38 | } 39 | pre { 40 | margin-top: 25px; 41 | margin-bottom: 25px; 42 | } 43 | .lead { 44 | font-family:"Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 45 | font-weight: 400; 46 | line-height: 1.4; 47 | letter-spacing: 0.0312em; 48 | color: #B1B7B9; 49 | } 50 | .navbar-default { 51 | background-color: #343838; 52 | border-bottom: 8px #EBF2F2 solid; 53 | } 54 | .bs-sidenav { 55 | background-image: url("../img/grid11.png"); 56 | background-repeat: repeat; 57 | font-size: 12px; 58 | } 59 | .well { 60 | background-color: #FCFDFF; 61 | } 62 | .btn-default { 63 | background-color:#FCFDFF; 64 | } 65 | .table-striped > tbody > tr:nth-child(2n+1) > td, .table-striped > tbody > tr:nth-child(2n+1) > th { 66 | background-color: #FCFDFF; 67 | } 68 | #mkdocs-search-query:focus { 69 | outline: none; 70 | -webkit-box-shadow: none; 71 | box-shadow: none; 72 | } 73 | #mkdocs-search-query { 74 | font-family:"Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 75 | font-size: 20px; 76 | font-weight: 700; 77 | color: #343838; 78 | height: 45px; 79 | } 80 | footer > hr { 81 | width: 35%; 82 | } 83 | -------------------------------------------------------------------------------- /docs/cinder/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | This is the GitHub theme for highlight.js 3 | 4 | github.com style (c) Vasily Polovnyov 5 | 6 | */ 7 | 8 | .hljs { 9 | display: block; 10 | overflow-x: auto; 11 | padding: 0.5em; 12 | color: #333; 13 | -webkit-text-size-adjust: none; 14 | } 15 | 16 | .hljs-comment, 17 | .diff .hljs-header, 18 | .hljs-javadoc { 19 | color: #998; 20 | font-style: italic; 21 | } 22 | 23 | .hljs-keyword, 24 | .css .rule .hljs-keyword, 25 | .hljs-winutils, 26 | .nginx .hljs-title, 27 | .hljs-subst, 28 | .hljs-request, 29 | .hljs-status { 30 | color: #333; 31 | font-weight: bold; 32 | } 33 | 34 | .hljs-number, 35 | .hljs-hexcolor, 36 | .ruby .hljs-constant { 37 | color: #008080; 38 | } 39 | 40 | .hljs-string, 41 | .hljs-tag .hljs-value, 42 | .hljs-phpdoc, 43 | .hljs-dartdoc, 44 | .tex .hljs-formula { 45 | color: #d14; 46 | } 47 | 48 | .hljs-title, 49 | .hljs-id, 50 | .scss .hljs-preprocessor { 51 | color: #900; 52 | font-weight: bold; 53 | } 54 | 55 | .hljs-list .hljs-keyword, 56 | .hljs-subst { 57 | font-weight: normal; 58 | } 59 | 60 | .hljs-class .hljs-title, 61 | .hljs-type, 62 | .vhdl .hljs-literal, 63 | .tex .hljs-command { 64 | color: #458; 65 | font-weight: bold; 66 | } 67 | 68 | .hljs-tag, 69 | .hljs-tag .hljs-title, 70 | .hljs-rule .hljs-property, 71 | .django .hljs-tag .hljs-keyword { 72 | color: #000080; 73 | font-weight: normal; 74 | } 75 | 76 | .hljs-attribute, 77 | .hljs-variable, 78 | .lisp .hljs-body, 79 | .hljs-name { 80 | color: #008080; 81 | } 82 | 83 | .hljs-regexp { 84 | color: #009926; 85 | } 86 | 87 | .hljs-symbol, 88 | .ruby .hljs-symbol .hljs-string, 89 | .lisp .hljs-keyword, 90 | .clojure .hljs-keyword, 91 | .scheme .hljs-keyword, 92 | .tex .hljs-special, 93 | .hljs-prompt { 94 | color: #990073; 95 | } 96 | 97 | .hljs-built_in { 98 | color: #0086b3; 99 | } 100 | 101 | .hljs-preprocessor, 102 | .hljs-pragma, 103 | .hljs-pi, 104 | .hljs-doctype, 105 | .hljs-shebang, 106 | .hljs-cdata { 107 | color: #999; 108 | font-weight: bold; 109 | } 110 | 111 | .hljs-deletion { 112 | background: #fdd; 113 | } 114 | 115 | .hljs-addition { 116 | background: #dfd; 117 | } 118 | 119 | .diff .hljs-change { 120 | background: #0086b3; 121 | } 122 | 123 | .hljs-chunk { 124 | color: #aaa; 125 | } 126 | -------------------------------------------------------------------------------- /docs/cinder/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/cinder/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/cinder/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/cinder/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/favicon.ico -------------------------------------------------------------------------------- /docs/cinder/img/grid1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid1.png -------------------------------------------------------------------------------- /docs/cinder/img/grid10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid10.png -------------------------------------------------------------------------------- /docs/cinder/img/grid11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid11.png -------------------------------------------------------------------------------- /docs/cinder/img/grid12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid12.png -------------------------------------------------------------------------------- /docs/cinder/img/grid13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid13.png -------------------------------------------------------------------------------- /docs/cinder/img/grid14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid14.png -------------------------------------------------------------------------------- /docs/cinder/img/grid15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid15.png -------------------------------------------------------------------------------- /docs/cinder/img/grid16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid16.png -------------------------------------------------------------------------------- /docs/cinder/img/grid17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid17.png -------------------------------------------------------------------------------- /docs/cinder/img/grid18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid18.png -------------------------------------------------------------------------------- /docs/cinder/img/grid19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid19.png -------------------------------------------------------------------------------- /docs/cinder/img/grid2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid2.png -------------------------------------------------------------------------------- /docs/cinder/img/grid20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid20.png -------------------------------------------------------------------------------- /docs/cinder/img/grid3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid3.png -------------------------------------------------------------------------------- /docs/cinder/img/grid4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid4.png -------------------------------------------------------------------------------- /docs/cinder/img/grid5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid5.png -------------------------------------------------------------------------------- /docs/cinder/img/grid6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid6.png -------------------------------------------------------------------------------- /docs/cinder/img/grid7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid7.png -------------------------------------------------------------------------------- /docs/cinder/img/grid8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid8.png -------------------------------------------------------------------------------- /docs/cinder/img/grid9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/cinder/img/grid9.png -------------------------------------------------------------------------------- /docs/cinder/js/base.js: -------------------------------------------------------------------------------- 1 | 2 | /* Highlight */ 3 | $( document ).ready(function() { 4 | hljs.initHighlightingOnLoad(); 5 | $('table').addClass('table table-striped table-hover'); 6 | }); 7 | 8 | 9 | $('body').scrollspy({ 10 | target: '.bs-sidebar', 11 | }); 12 | 13 | 14 | /* Prevent disabled links from causing a page reload */ 15 | $("li.disabled a").click(function() { 16 | event.preventDefault(); 17 | }); 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/docs/CLI.md: -------------------------------------------------------------------------------- 1 | # CLI Reference 2 | 3 | Invoke `just-api` from command-line 4 | 5 | ```text 6 | Usage: just-api [options] [files] 7 | 8 | Options: 9 | 10 | -V, --version outputs the version number 11 | --parallel specify the number of suites to be run in parallel 12 | --reporter specify the reporters to use, comma separated list e.g json,html 13 | --reporter-options reporter-specific options 14 | --grep only run tests matching 15 | --recursive include sub directories when searching for suites 16 | --reporters display available reporters 17 | -h, --help outputs usage information 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/docs/basic-concepts.md: -------------------------------------------------------------------------------- 1 | # Basic Concepts 2 | 3 | This section covers some high level basic concepts that are important to understand for day to day Just-API usage. We highly recommend that you read this page before proceeding to use Just-API. 4 | 5 | ## The High-level View 6 | 7 | Just-API's main purpose is to test HTTP-based APIs without code, and make API testing easy, free and fast for everyone. 8 | 9 | Write your API test specification and tell Just-API to run them. API test specification is written in YAML and we call each YAML file a test suite, with the option to write Javascript (using any `npm` module if needed) to implement custom logic. 10 | 11 | Just-API is written with parallelism as high priority when running test suites, so your test execution takes as less time as possible. 12 | 13 | ## Putting a test suite together ## 14 | 15 | A test suite has three required sections - `meta`, `configuration` and `specs`. 16 | 17 | And optional sections `hooks` and `spec_dependencies` (you can find more about these optional parts in later sections of the documentation). 18 | 19 | ### The `meta` Section ### 20 | 21 | Specify following suite attributes in this section 22 | 23 | - `name` (_required attribute_) 24 | - `locate_files_relative` (_optional attribute_) 25 | 26 | *name*[String]: Give a name that describes the suite (e.g: like a microservice name) 27 | 28 | *locate_files_relative*[Boolean]: Tells Just-API if file paths provided in the suite are relative to suite path or not. If false, Just-API will try to find files relative to Node process's current working directory. 29 | If true, Just-API will try to find files relative to the suite's path. 30 | Default value is false. 31 | 32 | Note: This attribute value applies to every file path you provide in a suite. 33 | 34 | ### The `configuration` Section ### 35 | 36 | You can use `configuration` section to specify API's host, protocol, port etc. You can also provide a custom Javascript function to `custom_configuration` attribute, so it's easy to 37 | dynamically configure your suite at runtime. 38 | 39 | ### The `specs` Section ### 40 | 41 | `specs` section is a list of tests. Each test contains name, request, response validation specification, and a few other additional attributes. 42 | 43 | ### An Example Suite ### 44 | 45 | A sample suite for Star Wars API service would look like this: 46 | 47 | ```yaml 48 | meta: 49 | name: Star Wars service 50 | configuration: 51 | scheme: https 52 | base_path: /api 53 | custom_configuration: 54 | run_type: inline 55 | inline: 56 | function: !!js/function > 57 | function() { 58 | this.host = 'swapi.co'; 59 | } 60 | specs: 61 | - name: get Luke Skywalker info 62 | request: 63 | path: /people/1/ 64 | method: get 65 | response: 66 | status_code: 200 67 | json_data: 68 | - path: $.name 69 | value: Luke Skywalker 70 | - name: get all Star Wars Films 71 | request: 72 | path: /films/ 73 | method: get 74 | response: 75 | status_code: 200 76 | ``` 77 | 78 | **Next:** 79 | 80 | - See the full set of features available in [Features](features). 81 | - Learn about **reporters** in [Reporters](reporters). 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /docs/docs/examples.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | You can find some examples on how to write test suites and tests in Just-API's test directory. 4 | 5 | Just-API itself is filled with lots of tests covering all supported features. 6 | 7 | Please checkout test suites available [here](https://github.com/kiranz/just-api/tree/master/test/cli/src/suites) 8 | 9 | Test suites available there should be able to help you write tests for your APIs. -------------------------------------------------------------------------------- /docs/docs/getting-started.md: -------------------------------------------------------------------------------- 1 | ## Installation 2 | 3 | Install with [npm](https://npmjs.org): 4 | 5 | ``` bash 6 | npm install just-api 7 | ``` 8 | 9 | !!! note 10 | To run just-api, you will need Node.js v7.10.0 or newer. 11 | 12 | ## Getting Started 13 | 14 | ``` bash 15 | mkdir specs 16 | ``` 17 | 18 | ``` bash 19 | vim specs/starwars_service.yml 20 | ``` 21 | 22 | Enter below specification in YAML file 23 | 24 | ``` yaml 25 | meta: 26 | name: "Star Wars suite" 27 | configuration: 28 | scheme: "https" 29 | host: "swapi.co" 30 | base_path: "/api" 31 | specs: 32 | - name: "get Luke Skywalker info" 33 | request: 34 | path: "/people/1/" 35 | method: "get" 36 | response: 37 | status_code: 200 38 | headers: 39 | - name: "content-type" 40 | value: !!js/regexp application/json 41 | json_data: 42 | - path: "$.name" 43 | value: "Luke Skywalker" 44 | ``` 45 | 46 | Back in the terminal 47 | 48 | ``` text 49 | $ ./node_modules/.bin/just-api 50 | 51 | ✓ get Luke Skywalker info (1216ms) 52 | 53 | Done: specs/starwars_service.yml (Passed) 54 | 55 | 0 skipped, 0 failed, 1 passed (1 tests) 56 | 0 skipped, 0 failed, 1 passed (1 suites) 57 | Duration: 1.3s 58 | ``` 59 | 60 | ### Testing GraphQL APIs 61 | 62 | Following example tests a GraphQL API that returns location for a given ip address. 63 | 64 | Create a YAML suite and run just-api. 65 | 66 | ```yaml 67 | meta: 68 | name: GraphQL location service 69 | configuration: 70 | host: api.graphloc.com 71 | scheme: https 72 | specs: 73 | - name: Get Location of a given ip address 74 | request: 75 | method: post 76 | path: /graphql 77 | headers: 78 | - name: content-type 79 | value: application/json 80 | payload: 81 | body: 82 | type: json 83 | content: 84 | query: > 85 | { 86 | getLocation(ip: "8.8.8.8") { 87 | country { 88 | iso_code 89 | } 90 | } 91 | } 92 | variables: null 93 | operationName: null 94 | response: 95 | status_code: 200 96 | json_data: 97 | - path: $.data.getLocation.country.iso_code 98 | value: US 99 | ``` 100 | 101 | ### A chained request flow with hook and custom validation 102 | 103 | When you need to test complex chained API flows, run dependencies in hooks to fetch pre-requisite data 104 | and pass it to actual test. 105 | 106 | Following example shows how to run dependencies using a hook, get data and validating response with a custom validator function. 107 | 108 | ```yaml 109 | meta: 110 | name: Starwars suite 111 | configuration: 112 | scheme: https 113 | host: swapi.co 114 | base_path: /api 115 | specs: 116 | - name: get R2-D2 info 117 | request: 118 | path: /people/3/ 119 | method: get 120 | response: 121 | status_code: 200 122 | json_data: 123 | - path: $.name 124 | value: R2-D2 125 | 126 | - name: search R2-D2 info 127 | before_test: 128 | run_type: inline 129 | inline: 130 | function: !js/asyncFunction > 131 | async function() { 132 | var response = await this.runSpec('get R2-D2 info'); 133 | var jsonData = JSON.parse(response.body); 134 | this.test.query_params = { name: jsonData.name }; 135 | } 136 | request: 137 | path: /people 138 | method: get 139 | response: 140 | status_code: 200 141 | custom_validator: 142 | run_type: inline 143 | inline: 144 | function: !!js/function > 145 | function() { 146 | var jsonData = JSON.parse(this.response.body); 147 | var r2d2 = jsonData.results.find(result => result.name === 'R2-D2'); 148 | 149 | if (!r2d2) throw new Error('R2-D2 not returned in search results'); 150 | } 151 | ``` 152 | 153 | 154 | !!! note 155 | You can also place custom JS functions in a module and specify the function name and path to module in YAML. 156 | 157 | ### Using docker to run Just-API tests 158 | If you are looking to use Docker to run Just-API, you might want to checkout 159 | Just-API docker boilerplate [here](https://github.com/kiranz/docker-just-api-sample) -------------------------------------------------------------------------------- /docs/docs/img/html-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/docs/docs/img/html-report.png -------------------------------------------------------------------------------- /docs/docs/index.md: -------------------------------------------------------------------------------- 1 | # Just-API 2 | Just-API is a declarative, specification based test framework for `REST`, `GraphQL` (or any HTTP-based) APIs. Users can test APIs without writing code, but they can also tap into code when they want to. It reads API test specification from YAML files and runs them in serial/parallel mode. Test reports can be generated in several formats including HTML and JSON. 3 |
4 | 5 | In simple terms, users build a test suite by providing a set of request and response validation specification in a YAML file. Each suite can have one or more specs. Just-API builds the request, sends it to server and validates response as per the specification. 6 | One can choose to validate any or all of following 7 | 8 | - Status code 9 | - Headers 10 | - Cookies 11 | - Response JSON body 12 | - Response JSON schema 13 | 14 | _or Provide a custom Javascript function to validate the response_ 15 | 16 | ## Contents 17 | 18 | ### Documentation 19 | 20 | - [Getting Started](getting-started) 21 | - [Basic Concepts](basic-concepts) 22 | - [CLI](CLI) 23 | - [Features](features) 24 | - [Reporters](reporters) 25 | - [Examples](examples) 26 | 27 | ## Find it on npm 28 | [![npm package](https://nodei.co/npm/just-api.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/just-api) 29 | ## Stay In Touch 30 | 31 | [![Twitter](https://img.shields.io/twitter/follow/just_api_.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=just_api_) [![GitHub stars](https://img.shields.io/github/stars/kiranz/just-api.svg?style=social&label=Star)](https://github.com/kiranz/just-api) 32 | 33 | If you are having problems with Just-API, or have a question, chat with the community on gitter. 34 | 35 | [![Join the chat at https://gitter.im/just-api/Lobby](https://badges.gitter.im/just-api/Lobby.svg)](https://gitter.im/just-api/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 36 | 37 | 38 | [Just-API Google group](https://groups.google.com/forum/#!forum/just-api) -------------------------------------------------------------------------------- /docs/docs/js/extra.js: -------------------------------------------------------------------------------- 1 | document.getElementsByClassName('md-footer-copyright')[0].innerHTML = '©2018 Created by  Kiran Mandadi'; -------------------------------------------------------------------------------- /docs/docs/reporters.md: -------------------------------------------------------------------------------- 1 | # Reporters 2 | 3 | 4 | ### Generating a report ### 5 | Just-API has several built-in reporters, `json`, `specs`, `html` etc. 6 | 7 | When you need a HTML report, you can invoke just-api with the `--reporter` option 8 | 9 | ```sh 10 | ./node_modules/.bin/just-api --reporter html 11 | ``` 12 | 13 | #### A sample html report: 14 | 15 | ![Report](./img/html-report.png) 16 | 17 | _Notice that report has request, response details for the failed test_ 18 | 19 | ### Generating reports in multiple formats ### 20 | 21 | Just-API can generate reports in multiple formats. 22 | 23 | When you need a HTML report and a JSON report too, you could do something like this 24 | 25 | ```sh 26 | ./node_modules/.bin/just-api --reporter html,json 27 | ``` 28 | 29 | This way you can generate reports in multiple formats for the same run. 30 | 31 | ### Custom Reporters ### 32 | 33 | When built-in reporters do not provide the information you need, you can write a custom reporter and use it: 34 | 35 | ```sh 36 | ./node_modules/.bin/just-api --reporter html,custom-reporter-module-name 37 | ``` 38 | or if the reporter is local js file 39 | 40 | ```sh 41 | ./node_modules/.bin/just-api --reporter html,/absolute/path/to/js/file 42 | ``` 43 | 44 | Reporters in Just-API are JavaScript constructors. When instantiated, a reporter receives the test launcher object along with program options. 45 | 46 | 47 | Just-API emits events on launcher object and suite object, So a custom reporter should listen to these events and implement reporting. 48 | 49 | Following events are emitted on the launcher object 50 | 51 | - start 52 | - end 53 | - new suite (Indicates the start of a new suite) 54 | 55 | And below events are emitted on each suite object 56 | 57 | - test pass 58 | - test fail 59 | - test skip 60 | - end (Indicates the end of a suite) 61 | 62 | If you are looking to write a custom reporter, take a look at Just-API's [JSON Reporter](https://github.com/kiranz/just-api/blob/master/lib/reporters/json.js) 63 | 64 | ### Reporter options ### 65 | 66 | Just-API accepts an additonal command line option `--reporter-options` that you can use to customize how and where reports are generated and saved. 67 | 68 | You must pass a comma separated list of key and value pairs to this option as `k=v,k2=v2,...` 69 | 70 | Following keys are supported currently. 71 | 72 | - jsonReportDir 73 | - jsonReportName 74 | - htmlReportDir 75 | - htmlReportName 76 | - logRequests 77 | 78 | `jsonReportDir`: Provide an existing directory path that is relative to Just-API node process's cwd. JSON report will be saved to this directory. 79 | 80 | `htmlReportDir`: Provide an existing directory path that is relative to Just-API node process's cwd. HTML report will be saved to this directory. 81 | 82 | `jsonReportName`: Provide a name for the JSON report file. JSON report will be saved with this name. 83 | 84 | `htmlReportName`: Provide a name for the HTML report file. HTML report will be saved with this name. 85 | 86 | `logRequests`: Tells Just-API to log HTTP request & response details in reports for failed tests. Omit this if you don't want to log details. 87 | 88 | 89 | A sample Just-API invocation would look like: 90 | 91 | 92 | ```sh 93 | ./node_modules/.bin/just-api --reporter html,json --reporter-options jsonReportDir=reports,jsonReportName=json-report,htmlReportDir=reports,htmlReportName=html-report,logRequests 94 | ``` 95 | -------------------------------------------------------------------------------- /docs/docs/running-suites-in-parallel.md: -------------------------------------------------------------------------------- 1 | # Executing suites in parallel 2 | 3 | When you have lots of test suites, it might take a while to execute all of them serially. 4 | 5 | To reduce the test execution time, Just-API is built with parallelism. You can invoke just-api with `--parallel` option to trigger parallel execution mode. 6 | All reporters respect parallel mode and generate correct reports with properly mapped errors if any. 7 | 8 | This is how you can execute suites in parallel with just-api 9 | 10 | ```sh 11 | ./node_modules/.bin/just-api --parallel 8 12 | ``` 13 | 14 | Above command will start test execution in parallel mode with 8 suites at a time. 15 | 16 | **Note**: Maximum number of suites you can run in parallel is 24. -------------------------------------------------------------------------------- /docs/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Just-API 2 | theme: 3 | name: material 4 | palette: 5 | accent: blue 6 | extra_javascript: 7 | - js/extra.js 8 | pages: 9 | - Home: index.md 10 | - Getting Started: getting-started.md 11 | - Basic Concepts: basic-concepts.md 12 | - CLI Reference: CLI.md 13 | - Features: features.md 14 | - Parallel exectuion: running-suites-in-parallel.md 15 | - Reporters: reporters.md 16 | - Examples: examples.md 17 | markdown_extensions: 18 | - codehilite 19 | - admonition 20 | google_analytics: 21 | - UA-120233669-1 22 | - auto 23 | repo_name: Just-API 24 | repo_url: https://github.com/kiranz/just-api 25 | edit_uri: "" 26 | extra: 27 | social: 28 | - type: 'github' 29 | link: 'https://github.com/kiranz/just-api' 30 | - type: 'twitter' 31 | link: 'https://twitter.com/just_api_' 32 | 33 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const babel = require('gulp-babel'); 3 | const del = require('del'); 4 | 5 | gulp.task('clean_dist', function () { 6 | return del.sync('./src'); 7 | }); 8 | 9 | gulp.task('transpile', function() { 10 | return gulp.src('lib/**/*.js') 11 | .pipe(babel()) 12 | .pipe(gulp.dest('src')); 13 | }); 14 | 15 | gulp.task('copy_files',function(){ 16 | return gulp.src([ 17 | './lib/schema/yaml/*.json', 18 | './lib/reporters/html-src/assets/*.css' 19 | ], { base: './lib/' }) 20 | .pipe(gulp.dest('src')); 21 | }); 22 | 23 | gulp.task('default', ['clean_dist', 'transpile', 'copy_files']); -------------------------------------------------------------------------------- /justapi_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/justapi_diagram.png -------------------------------------------------------------------------------- /lib/errors.js: -------------------------------------------------------------------------------- 1 | const errorEx = require('error-ex'); 2 | 3 | export function customError(name, opts) { 4 | return errorEx(name, opts); 5 | } 6 | 7 | export const errorTypes = [ 8 | 'FileDoesNotExistError', 9 | 'NotAValidYAMLCustomTypeError', 10 | 'InvalidYAMLSuiteSchemaError', 11 | 'InvalidSuiteConfigurationError', 12 | 'DisabledSuiteError', 13 | 'NoSpecsFoundError', 14 | 'NoSpecFoundMatchingNameError', 15 | 'RequestBodyNotFoundError', 16 | 'ResponseStatusCodeDidNotMatchError', 17 | 'ResponseHeaderValueDidNotMatchError', 18 | 'YAMLSuiteLoadingError', 19 | 'SuiteConfigurationFailedError', 20 | 'BeforeAllHookError', 21 | 'AfterAllHookError', 22 | 'InvalidSpecificationSchemaError', 23 | 'BeforeEachHookError', 24 | 'AfterEachHookError', 25 | 'BeforeTestHookError', 26 | 'AfterTestHookError', 27 | 'InvalidRequestSpecificationError', 28 | 'InvalidRequestHeaderError', 29 | 'RequestBuilderError', 30 | 'RequestBodyBuilderError', 31 | 'JSONBodyParseError', 32 | 'LoadingSpecDependencySuiteError', 33 | 'ResponseJSONDataMismatchError', 34 | 'ResponseJSONSchemaValidationError', 35 | 'CustomResponseValidationError', 36 | 'LoopItemsBuilderError', 37 | 'SuiteCustomConfigurationError', 38 | 'CustomFunctionNotFoundInModuleError', 39 | 'ResponseCookieValueDidNotMatchError' 40 | ]; 41 | -------------------------------------------------------------------------------- /lib/launcher.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import EventEmitter from 'events'; 4 | import fs from 'fs'; 5 | import * as childProcess from 'child_process'; 6 | 7 | import Suite from './suite'; 8 | import { convertMillisToHumanReadableFormat, isNumber } from './utils'; 9 | 10 | export default class Launcher extends EventEmitter { 11 | 12 | constructor(specFiles, options) { 13 | super(); 14 | 15 | this.specs = specFiles.slice(0); 16 | this.options = options; 17 | this.pendingFiles = specFiles.slice(0); 18 | this.runningFiles = []; 19 | this.suiteOptions = {}; 20 | this.parallel = options.parallel; 21 | this.max_parallel = options.max_parallel; 22 | this.max_parallel_limit = options.max_parallel_limit; 23 | this.suiteOptions.grep = options.grep; 24 | this.reporterOptions = options.reporterOptions; 25 | this.results = []; 26 | 27 | this.setupReporters(options.reporters); 28 | } 29 | 30 | setupReporters(reporters) { 31 | if (!reporters) { 32 | console.error(`Reporters not set`); 33 | process.exit(1); 34 | } 35 | 36 | this.reporters = []; 37 | 38 | for (let Reporter of reporters) { 39 | try { 40 | let reporter = new Reporter(this, { 41 | parallel: this.parallel, 42 | reporterOptions: {...this.reporterOptions} 43 | }); 44 | 45 | this.reporters.push(reporter); 46 | } catch (err) { 47 | console.error(`Error occurred while initializing reporter: ${Reporter.name} \n ${err.stack}`); 48 | process.exit(1); 49 | } 50 | 51 | } 52 | } 53 | 54 | async go() { 55 | const self = this; 56 | 57 | this.emit('start', this.pendingFiles.slice(0)); 58 | 59 | if (self.parallel) { 60 | let parallelRuns; 61 | 62 | if (self.max_parallel >= self.pendingFiles.length) { 63 | parallelRuns = self.pendingFiles.length; 64 | } else { 65 | parallelRuns = self.max_parallel; 66 | } 67 | 68 | for (let run = 1; run <= parallelRuns; run++) { 69 | self.runNextSuite(self); 70 | } 71 | 72 | 73 | } else { 74 | for (let file of self.pendingFiles) { 75 | const suite = new Suite(file, this.suiteOptions); 76 | this.emit('new suite', suite); 77 | await suite.launch(); 78 | let result = suite.result; 79 | result.status = suite.status; 80 | self.results.push(result); 81 | } 82 | 83 | this.exit(); 84 | } 85 | } 86 | 87 | runNextSuite(context) { 88 | let self = context; 89 | 90 | if (self.runningFiles.length === 0 && self.pendingFiles.length === 0) { 91 | self.exit(); 92 | } 93 | 94 | let file = self.pendingFiles.shift(); 95 | 96 | if (file) { 97 | let suite = new Suite(file, self.suiteOptions); 98 | self.runningFiles.push(file); 99 | this.emit('new suite', suite); 100 | 101 | suite.on('end', function (suiteObject, error) { 102 | self.runningFiles.splice(self.runningFiles.indexOf(suiteObject.file), 1); 103 | let result = suiteObject.result; 104 | result.status = suiteObject.status; 105 | self.results.push(result); 106 | self.runNextSuite(self); 107 | }); 108 | 109 | suite.launch(); 110 | } else if (!file && self.runningFiles.length > 0) { 111 | console.log(`\n ${self.runningFiles.length} suite(s) are still running...`); 112 | } 113 | } 114 | 115 | exit() { 116 | this.emit('end'); 117 | console.log(); 118 | 119 | try { 120 | let failedSuites = this.results.filter(suiteResult => (suiteResult.status !== 'pass' && suiteResult.status !== 'skip')); 121 | process.exitCode = failedSuites.length; 122 | } catch (error) { 123 | process.exitCode = 1; 124 | } 125 | 126 | } 127 | 128 | } -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | process._api = {}; 4 | process._api.startTime = new Date(); 5 | 6 | process 7 | .on('unhandledRejection', (reason, p) => { 8 | console.error(reason, 'Unhandled Rejection at Promise', p); 9 | process.exit(1); 10 | }) 11 | .on('uncaughtException', err => { 12 | console.error(err, 'Uncaught Exception thrown'); 13 | process.exit(1); 14 | }); 15 | 16 | const program = require('commander'); 17 | import fs from 'fs'; 18 | import path from 'path'; 19 | import JustAPI from './just-api'; 20 | import { findSuiteFiles, doesDirectoryExist } from './utils'; 21 | 22 | program 23 | .version(JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')).version) 24 | .usage(' ') 25 | .option('--parallel ', 'specify the number of suites to be run in parallel') 26 | .option('--reporter ', 'specify the reporters to use, comma separated list e.g json,html') 27 | .option('--reporter-options ', 'reporter-specific options') 28 | .option('--grep ', 'only run tests matching ') 29 | .option('--recursive', 'include sub directories when searching for suites') 30 | .option('--reporters', 'display available reporters'); 31 | 32 | program.on('option:reporters', () => { 33 | console.log(); 34 | console.log(' spec - hierarchical spec list'); 35 | console.log(' html - html file'); 36 | console.log(); 37 | process.exit(); 38 | }); 39 | 40 | program._name = 'just-api'; 41 | 42 | program.parse(process.argv); 43 | 44 | const args = program.args; 45 | let suiteFiles = []; 46 | 47 | if (!args.length) { 48 | console.warn('Test Suite path/pattern/directory is not specified, Looking for suites in specs directory'); 49 | 50 | if (doesDirectoryExist('specs')) { 51 | args.push('specs'); 52 | } else { 53 | console.error("'specs' directory does not exist. You can specify a path as 'just-api /path/to/yamlfile'"); 54 | process.exit(1); 55 | } 56 | } 57 | 58 | args.forEach(arg => { 59 | let files; 60 | 61 | try { 62 | files = findSuiteFiles(arg, program.recursive); 63 | } catch (err) { 64 | if (err.message.indexOf('No suites found using path/pattern') === 0) { 65 | console.error(`Warning: Could not find any suite files matching pattern: ${arg}`); 66 | return; 67 | } 68 | 69 | throw err; 70 | } 71 | 72 | if (typeof files === 'string' || typeof files === 'object') 73 | suiteFiles = suiteFiles.concat(files); 74 | }); 75 | 76 | let additionalOptions = { 77 | parallel: program.parallel, 78 | reporter: program.reporter, 79 | grep: program.grep, 80 | reporterOptions: program.reporterOptions 81 | }; 82 | 83 | const justAPI = new JustAPI(suiteFiles, additionalOptions); 84 | justAPI.init(); 85 | -------------------------------------------------------------------------------- /lib/reporters/html-src/assets/html-report.js: -------------------------------------------------------------------------------- 1 | function addSuiteNames() { 2 | var suites = document.getElementsByClassName('suite'); 3 | 4 | for (var idx = 0; idx < suites.length; idx++) { 5 | var suite = suites[idx]; 6 | var headers = suite.getElementsByTagName('h1'); 7 | if (headers.length > 0) { 8 | var file = headers[0].innerText; 9 | var suiteName = suite.getElementsByClassName('suite-name-hidden'); 10 | if (suiteName.length > 0) { 11 | headers[0].innerHTML = suiteName[0].innerText + ' ( ' + file + ' )'; 12 | } 13 | } 14 | } 15 | } 16 | 17 | addSuiteNames(); 18 | 19 | function toggleTestDetailedView(elem) { 20 | var allPreElements = elem.parentNode.getElementsByTagName('pre'); 21 | 22 | for (var idx = 0; idx < allPreElements.length; idx++) { 23 | var preElem = allPreElements[idx]; 24 | preElem.classList.toggle("show"); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /lib/reporters/html-src/template.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export function buildHTML(data) { 4 | return ` 5 | 6 | Just-API Report 7 | 8 | 11 | 12 | 13 |
14 |
15 |
Just-API Report
16 |
17 | ${ data.stats.skippedTests } Skipped, ${ data.stats.failedTests } Failed, ${ data.stats.passedTests } Passed ( ${ data.stats.tests } Tests ) 18 |
19 | ${ data.stats.skippedSuites } Skipped, ${ data.stats.failedSuites } Failed, ${ data.stats.passedSuites} Passed ( ${ data.stats.suites } Suites ) 20 |
21 | Duration: ${ data.stats.duration } 22 |
23 | ${ new Date().toUTCString() } 24 |
25 |
26 |
    ${ data.report }
27 |
28 | 31 | 32 | 37 | 38 | `; 39 | } 40 | -------------------------------------------------------------------------------- /lib/reporters/specs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const chalk = require('chalk'); 4 | import BaseReporter from './base'; 5 | import { INDICATORS } from './base'; 6 | const testIndent = ' '; 7 | const suiteIndent = ' '; 8 | 9 | export default class SpecsReporter extends BaseReporter { 10 | 11 | constructor(launcher, opts = {}) { 12 | super(launcher, opts); 13 | 14 | this.launcher = launcher; 15 | this.isParallelRun = opts.parallel; 16 | let self = this; 17 | 18 | launcher.on('start', function (suiteFiles) { 19 | console.log(); 20 | console.log(`Launcher will run suites: ${suiteFiles}`); 21 | }); 22 | 23 | launcher.on('end', function () { 24 | console.log(); 25 | }); 26 | 27 | launcher.on('new suite', function (suite) { 28 | self.addSuite(suite) 29 | }); 30 | } 31 | 32 | addSuite(suite) { 33 | super.addSuite(suite); 34 | 35 | suite.on('test pass', function (test) { 36 | console.log(); 37 | console.log(chalk.green(`${testIndent} ${INDICATORS.ok} ${test.name} (${test.duration}ms)`)); 38 | }); 39 | 40 | suite.on('test fail', function (test, error) { 41 | console.log(); 42 | console.log(chalk.red(`${testIndent} ${INDICATORS.err} ${test.name} (${test.duration}ms)`)); 43 | }); 44 | 45 | suite.on('test skip', function (test) { 46 | console.log(); 47 | console.log(chalk.cyan(`${testIndent} - ${test.name} (${test.duration}ms)`)); 48 | }); 49 | 50 | suite.on('end', function (suite, error) { 51 | console.log(); 52 | 53 | if (suite.status === 'pass') { 54 | console.log(chalk.green(`${suiteIndent} Done: ${suite.file} (Passed)`)); 55 | } else if (suite.status === 'skip') { 56 | console.log(chalk.cyan(`${suiteIndent} Done: ${suite.file} (Skipped)`)); 57 | } else { 58 | console.log(chalk.red(`${suiteIndent} Done: ${suite.file} (Failed)`)); 59 | } 60 | }); 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /lib/request.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const request = require('request'); 4 | import JustAPIResponse from './response'; 5 | 6 | export default class JustAPIRequest { 7 | constructor(options, test) { 8 | this.options = options; 9 | this.test = test; 10 | } 11 | 12 | buildCookieJar() { 13 | if (this.options.cookiesData && Object.keys(this.options.cookiesData).length > 0) { 14 | 15 | let cookieJar = request.jar(); 16 | 17 | for (let [ key, value ] of Object.entries(this.options.cookiesData)) { 18 | cookieJar.setCookie(request.cookie(`${key}=${value}`), this.options.baseUrl || this.options.url); 19 | } 20 | 21 | this.options.jar = cookieJar; 22 | } 23 | } 24 | 25 | async send() { 26 | const self = this; 27 | self.options.time = true; 28 | self.buildCookieJar(); 29 | 30 | try { 31 | let response = await new Promise(function (resolve, reject) { 32 | request(self.options, function (err, response, body) { 33 | let log = {}; 34 | 35 | log.request = { 36 | uri: this.uri.href, 37 | method: this.method, 38 | headers: {...this.headers} 39 | }; 40 | 41 | if (this.body) { 42 | log.request.body = this.body.toString('utf8'); 43 | } else if (this.formData) { 44 | log.request.formRequest = true; 45 | log.request.body = {...this.formData}; 46 | } 47 | 48 | if (err !== null) { 49 | log.error = err; 50 | self.test.suite.requests.push(log); 51 | return reject(err); 52 | } 53 | 54 | log.response = { 55 | headers: {...response.headers}, 56 | statusCode: response.statusCode, 57 | body: body, 58 | timings: {...response.timingPhases } 59 | }; 60 | 61 | self.test.suite.requests.push(log); 62 | 63 | let justAPIResponse = new JustAPIResponse(this, err, response, body); 64 | return resolve(justAPIResponse); 65 | }); 66 | }); 67 | 68 | return response; 69 | } catch (error) { 70 | throw error; 71 | } 72 | 73 | } 74 | 75 | } -------------------------------------------------------------------------------- /lib/response.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export default class JustAPIResponse { 4 | 5 | constructor(req, err, response, body) { 6 | this._req = req; 7 | this._err = err; 8 | this._response = response; 9 | this._body = body; 10 | 11 | if (response.timingPhases && response.timingPhases.total) { 12 | this._response.duration = response.timingPhases.total; 13 | } 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /lib/schema/validator.js: -------------------------------------------------------------------------------- 1 | import { validate as validateSchema } from 'jsonschema'; 2 | import fs from 'fs'; 3 | 4 | export function validateJSONSchema(dataObject, schemaFilePath) { 5 | const expectedSchema = JSON.parse(fs.readFileSync(schemaFilePath, 'utf8')); 6 | 7 | return validateSchema(dataObject, expectedSchema); 8 | } -------------------------------------------------------------------------------- /lib/schema/yaml/custom-types.js: -------------------------------------------------------------------------------- 1 | const esprima = require('esprima'); 2 | import yaml from 'js-yaml'; 3 | 4 | const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor; 5 | 6 | export function asyncFunction() { 7 | return new yaml.Type('!js/asyncFunction', { 8 | kind: 'scalar', 9 | construct: function (data) { 10 | let functionBody = data || ''; 11 | return constructJavascriptFunction(functionBody); 12 | }, 13 | instanceOf: AsyncFunction 14 | }); 15 | } 16 | 17 | function constructJavascriptFunction(data) { 18 | let source = '(' + data + ')', 19 | ast = esprima.parse(source, {range: true}), 20 | params = [], 21 | body; 22 | 23 | if (ast.type !== 'Program' || 24 | ast.body.length !== 1 || 25 | ast.body[0].type !== 'ExpressionStatement' || 26 | (ast.body[0].expression.type !== 'ArrowFunctionExpression' && 27 | ast.body[0].expression.type !== 'FunctionExpression')) { 28 | throw new Error(`Failed to resolve async function with body ${data}`); 29 | } 30 | 31 | ast.body[0].expression.params.forEach(function (param) { 32 | params.push(param.name); 33 | }); 34 | 35 | body = ast.body[0].expression.body.range; 36 | 37 | return new AsyncFunction(params, source.slice(body[0] + 1, body[1] - 1)); 38 | } -------------------------------------------------------------------------------- /lib/schema/yaml/loader.js: -------------------------------------------------------------------------------- 1 | import yaml from 'js-yaml'; 2 | import fs from 'fs'; 3 | 4 | import {asyncFunction} from './custom-types'; 5 | import { NotAValidYAMLCustomType } from './../../errors'; 6 | 7 | export function loadYAML(filePath, options) { 8 | let customSchema; 9 | 10 | if (options.customTypes) { 11 | let typeDefinitions = []; 12 | 13 | for (let type of options.customTypes) { 14 | typeDefinitions.push(getCustomYAMLSchema(type)); 15 | } 16 | 17 | customSchema = yaml.Schema.create(typeDefinitions); 18 | } 19 | 20 | try { 21 | return yaml.load(fs.readFileSync(filePath, {encoding: options.encoding}), {schema: customSchema}) 22 | } catch (err) { 23 | throw err; 24 | } 25 | } 26 | 27 | function getCustomYAMLSchema(customType) { 28 | let yamlType; 29 | 30 | switch (customType) { 31 | case 'asyncFunction': 32 | yamlType = asyncFunction(); 33 | break; 34 | default: 35 | throw new NotAValidYAMLCustomType(`${customType} is not a valid custom YAML type`); 36 | } 37 | 38 | return yamlType; 39 | } -------------------------------------------------------------------------------- /lib/schema/yaml/suite-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "http://example.com/example.json", 3 | "type": "object", 4 | "definitions": {}, 5 | "$schema": "http://json-schema.org/draft-06/schema#", 6 | "properties": { 7 | "host": { 8 | "$id": "/properties/host", 9 | "type": "string", 10 | "minLength": 1 11 | }, 12 | "scheme": { 13 | "$id": "/properties/scheme", 14 | "type": "string", 15 | "enum": ["http", "https"], 16 | "minLength": 4 17 | }, 18 | "base_path": { 19 | "$id": "/properties/base_path", 20 | "type": "string" 21 | }, 22 | "read_timeout": { 23 | "$id": "/properties/read_timeout", 24 | "type": "integer" 25 | }, 26 | "port": { 27 | "$id": "/properties/port", 28 | "type": "integer" 29 | } 30 | }, 31 | "required": [ 32 | "host", 33 | "scheme", 34 | "base_path", 35 | "read_timeout" 36 | ] 37 | } -------------------------------------------------------------------------------- /lib/suite-dependency.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import { loadYAML } from './schema/yaml/loader'; 4 | import { customError } from './errors'; 5 | 6 | export default class SuiteDependency { 7 | 8 | constructor(filePath, parent) { 9 | this.file = filePath; 10 | this.parent = parent; 11 | this.targetConfiguration = {}; 12 | this.commonHeaders = {}; 13 | } 14 | 15 | loadFileAndValidateSchema() { 16 | this.parent.loadFileAndValidateSchema.call(this); 17 | } 18 | 19 | loadFile(file) { 20 | if (!fs.existsSync(file)) { 21 | let FileDoesNotExistError = customError('FileDoesNotExist'); 22 | throw new FileDoesNotExistError(`Test suite file doesn't exist at '${file}'`); 23 | } 24 | 25 | try { 26 | return loadYAML(file, {encoding: 'UTF-8', customTypes: ['asyncFunction']}); 27 | } catch (err) { 28 | let YAMLSuiteLoadingError = customError('YAMLSuiteLoadingError'); 29 | throw new YAMLSuiteLoadingError(`(${file}) \n ${err.message}`); 30 | } 31 | } 32 | 33 | resolveFile(filePath) { 34 | return this.parent.resolveFile.call(this, filePath); 35 | } 36 | 37 | async configure() { 38 | await this.parent.configure.call(this); 39 | } 40 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "just-api", 3 | "version": "1.2.5", 4 | "description": "Specification based API test framework for HTTP APIs (REST, GraphQL)", 5 | "homepage": "https://kiranz.github.io/just-api/", 6 | "keywords": [ 7 | "API", 8 | "mocha", 9 | "REST", 10 | "GraphQL", 11 | "testing", 12 | "test", 13 | "restful", 14 | "rest", 15 | "http", 16 | "webservice", 17 | "microservice", 18 | "yaml", 19 | "testrunner", 20 | "QA", 21 | "api", 22 | "automation", 23 | "testreporter" 24 | ], 25 | "author": "Kiran Mandadi ", 26 | "contributors": [ 27 | "Kiran Mandadi (https://github.com/kiranz)" 28 | ], 29 | "license": "MIT", 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/kiranz/just-api.git" 33 | }, 34 | "engines": { 35 | "node": ">=7.10.0", 36 | "npm": ">=4.5.0" 37 | }, 38 | "publishConfig": { 39 | "registry": "https://registry.npmjs.org/" 40 | }, 41 | "scripts": { 42 | "clean": "rm -rf ./node_modules", 43 | "install_testapi": "cd test/api && npm install", 44 | "start_testapi": "npm run install_testapi && cd test/api && node server.js", 45 | "clean_testlogs": "rm -rf test/cli/src/logs && mkdir test/cli/src/logs", 46 | "test": "npm run clean_testlogs && ./node_modules/.bin/mocha --timeout 10000 test/cli/*.spec.js" 47 | }, 48 | "dependencies": { 49 | "commander": "2.11.0", 50 | "debug": "3.1.0", 51 | "glob": "7.1.2", 52 | "mkdirp": "0.5.1", 53 | "js-yaml": "3.11.0", 54 | "jsonschema": "1.2.2", 55 | "request": "2.85.0", 56 | "url-parse": "1.4.3", 57 | "chai": "4.1.2", 58 | "string-template": "1.0.0", 59 | "esprima": "4.0.0", 60 | "jsonpath": "1.0.0", 61 | "pretty-ms": "3.1.0", 62 | "error-ex": "1.3.1", 63 | "chalk": "2.4.1", 64 | "lodash": "4.17.10", 65 | "serialize-error": "2.1.0", 66 | "semver": "5.5.0", 67 | "he": "1.1.1", 68 | "request-cookies": "1.1.0" 69 | }, 70 | "devDependencies": { 71 | "babel-cli": "^6.24.1", 72 | "babel-plugin-add-module-exports": "^0.2.1", 73 | "babel-plugin-array-includes": "^2.0.3", 74 | "babel-plugin-transform-es2015-destructuring": "^6.23.0", 75 | "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", 76 | "babel-plugin-transform-es2015-parameters": "^6.24.1", 77 | "babel-plugin-transform-es2015-spread": "^6.22.0", 78 | "babel-plugin-transform-object-rest-spread": "^6.23.0", 79 | "babel-plugin-transform-react-jsx": "^6.24.1", 80 | "babel-register": "^6.24.1", 81 | "gulp": "3.9.1", 82 | "gulp-babel": "7.0.1", 83 | "del": "3.0.0", 84 | "mocha": "5.2.0", 85 | "cross-spawn": "6.0.5", 86 | "chai": "4.1.2" 87 | }, 88 | "bin": { 89 | "just-api": "./bin/just-api" 90 | }, 91 | "files": [ 92 | "bin", 93 | "src" 94 | ] 95 | } 96 | -------------------------------------------------------------------------------- /test/api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "just-api-test-api", 3 | "version": "0.0.1", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "json-server": "0.12.2", 7 | "multer": "1.3.0", 8 | "cookie-parser": "1.4.3" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/cli/additionalopts.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('additional request options', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('additional.opts.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(1); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(1); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('post redirect is followed by default', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('pass'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | it('redirect is not followed - should fail', function () { 38 | let result = suiteContext.result; 39 | let test = result.tests.find(t => t.name === this.test.title); 40 | expect(test.status).to.equal('fail'); 41 | expect(test.error.name).to.equal('ResponseStatusCodeDidNotMatchError'); 42 | expect(test.error.message).to.contain('Expected status code: 200, Actual status code: 302'); 43 | }); 44 | 45 | }); -------------------------------------------------------------------------------- /test/cli/afterall.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('after all hook', function () { 8 | let suiteContext = this; 9 | 10 | function runConfigSuite(path) { 11 | let result = runJustAPIJSON(path); 12 | if (result.error) throw result.error; 13 | return result; 14 | } 15 | 16 | it('inline async error', function () { 17 | let result = runConfigSuite('hooks/afterall/afterall.inline.async.failure.suite.yml'); 18 | expect(result.exitCode).to.equal(1); 19 | expect(result.terminationSignal).to.be.a('null'); 20 | const report = fs.readFileSync(result.jsonReport); 21 | let reportData = JSON.parse(report); 22 | 23 | expect(reportData.passedSuitesCount).to.equal(0); 24 | expect(reportData.skippedSuitesCount).to.equal(0); 25 | expect(reportData.failedSuitesCount).to.equal(1); 26 | expect(reportData.passedTestsCount).to.equal(1); 27 | expect(reportData.skippedTestsCount).to.equal(0); 28 | expect(reportData.failedTestsCount).to.equal(0); 29 | expect(reportData.suites.length).to.equal(1); 30 | expect(reportData.suites[0].status).to.equal('fail'); 31 | expect(reportData.suites[0].tests.length).to.equal(1); 32 | expect(reportData.suites[0].error.name).to.equal('AfterAllHookError'); 33 | }); 34 | 35 | it('inline async success', function () { 36 | let result = runConfigSuite('hooks/afterall/afterall.inline.async.success.suite.yml'); 37 | expect(result.exitCode).to.equal(0); 38 | expect(result.terminationSignal).to.be.a('null'); 39 | const report = fs.readFileSync(result.jsonReport); 40 | let reportData = JSON.parse(report); 41 | 42 | expect(reportData.passedSuitesCount).to.equal(1); 43 | expect(reportData.skippedSuitesCount).to.equal(0); 44 | expect(reportData.failedSuitesCount).to.equal(0); 45 | expect(reportData.passedTestsCount).to.equal(1); 46 | expect(reportData.skippedTestsCount).to.equal(0); 47 | expect(reportData.failedTestsCount).to.equal(0); 48 | expect(reportData.suites.length).to.equal(1); 49 | expect(reportData.suites[0].status).to.equal('pass'); 50 | expect(reportData.suites[0].tests.length).to.equal(1); 51 | expect(reportData.suites[0].error).to.be.a('null'); 52 | }); 53 | 54 | 55 | it('inline sync error', function () { 56 | let result = runConfigSuite('hooks/afterall/afterall.inline.failure.suite.yml'); 57 | expect(result.exitCode).to.equal(1); 58 | expect(result.terminationSignal).to.be.a('null'); 59 | const report = fs.readFileSync(result.jsonReport); 60 | let reportData = JSON.parse(report); 61 | 62 | expect(reportData.passedSuitesCount).to.equal(0); 63 | expect(reportData.skippedSuitesCount).to.equal(0); 64 | expect(reportData.failedSuitesCount).to.equal(1); 65 | expect(reportData.passedTestsCount).to.equal(1); 66 | expect(reportData.skippedTestsCount).to.equal(0); 67 | expect(reportData.failedTestsCount).to.equal(0); 68 | expect(reportData.suites.length).to.equal(1); 69 | expect(reportData.suites[0].status).to.equal('fail'); 70 | expect(reportData.suites[0].tests.length).to.equal(1); 71 | expect(reportData.suites[0].error.name).to.equal('AfterAllHookError'); 72 | }); 73 | 74 | it('inline sync valid', function () { 75 | let result = runConfigSuite('hooks/afterall/afterall.inline.success.suite.yml'); 76 | expect(result.exitCode).to.equal(0); 77 | expect(result.terminationSignal).to.be.a('null'); 78 | const report = fs.readFileSync(result.jsonReport); 79 | let reportData = JSON.parse(report); 80 | 81 | expect(reportData.passedSuitesCount).to.equal(1); 82 | expect(reportData.skippedSuitesCount).to.equal(0); 83 | expect(reportData.failedSuitesCount).to.equal(0); 84 | expect(reportData.passedTestsCount).to.equal(1); 85 | expect(reportData.skippedTestsCount).to.equal(0); 86 | expect(reportData.failedTestsCount).to.equal(0); 87 | expect(reportData.suites.length).to.equal(1); 88 | expect(reportData.suites[0].status).to.equal('pass'); 89 | expect(reportData.suites[0].tests.length).to.equal(1); 90 | expect(reportData.suites[0].error).to.be.a('null'); 91 | }); 92 | 93 | }); -------------------------------------------------------------------------------- /test/cli/beforeall.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('before all hook', function () { 8 | let suiteContext = this; 9 | 10 | function runConfigSuite(path) { 11 | let result = runJustAPIJSON(path); 12 | if (result.error) throw result.error; 13 | return result; 14 | } 15 | 16 | it('inline async error', function () { 17 | let result = runConfigSuite('hooks/beforeall/beforeall.inline.async.failure.suite.yml'); 18 | expect(result.exitCode).to.equal(1); 19 | expect(result.terminationSignal).to.be.a('null'); 20 | const report = fs.readFileSync(result.jsonReport); 21 | let reportData = JSON.parse(report); 22 | 23 | expect(reportData.passedSuitesCount).to.equal(0); 24 | expect(reportData.skippedSuitesCount).to.equal(0); 25 | expect(reportData.failedSuitesCount).to.equal(1); 26 | expect(reportData.passedTestsCount).to.equal(0); 27 | expect(reportData.skippedTestsCount).to.equal(0); 28 | expect(reportData.failedTestsCount).to.equal(0); 29 | expect(reportData.suites.length).to.equal(1); 30 | expect(reportData.suites[0].status).to.equal('fail'); 31 | expect(reportData.suites[0].tests.length).to.equal(0); 32 | expect(reportData.suites[0].error.name).to.equal('BeforeAllHookError'); 33 | }); 34 | 35 | it('inline async success', function () { 36 | let result = runConfigSuite('hooks/beforeall/beforeall.inline.async.success.suite.yml'); 37 | expect(result.exitCode).to.equal(0); 38 | expect(result.terminationSignal).to.be.a('null'); 39 | const report = fs.readFileSync(result.jsonReport); 40 | let reportData = JSON.parse(report); 41 | 42 | expect(reportData.passedSuitesCount).to.equal(1); 43 | expect(reportData.skippedSuitesCount).to.equal(0); 44 | expect(reportData.failedSuitesCount).to.equal(0); 45 | expect(reportData.passedTestsCount).to.equal(1); 46 | expect(reportData.skippedTestsCount).to.equal(0); 47 | expect(reportData.failedTestsCount).to.equal(0); 48 | expect(reportData.suites.length).to.equal(1); 49 | expect(reportData.suites[0].status).to.equal('pass'); 50 | expect(reportData.suites[0].tests.length).to.equal(1); 51 | expect(reportData.suites[0].error).to.be.a('null'); 52 | }); 53 | 54 | 55 | it('inline sync error', function () { 56 | let result = runConfigSuite('hooks/beforeall/beforeall.inline.failure.suite.yml'); 57 | expect(result.exitCode).to.equal(1); 58 | expect(result.terminationSignal).to.be.a('null'); 59 | const report = fs.readFileSync(result.jsonReport); 60 | let reportData = JSON.parse(report); 61 | 62 | expect(reportData.passedSuitesCount).to.equal(0); 63 | expect(reportData.skippedSuitesCount).to.equal(0); 64 | expect(reportData.failedSuitesCount).to.equal(1); 65 | expect(reportData.passedTestsCount).to.equal(0); 66 | expect(reportData.skippedTestsCount).to.equal(0); 67 | expect(reportData.failedTestsCount).to.equal(0); 68 | expect(reportData.suites.length).to.equal(1); 69 | expect(reportData.suites[0].status).to.equal('fail'); 70 | expect(reportData.suites[0].tests.length).to.equal(0); 71 | expect(reportData.suites[0].error.name).to.equal('BeforeAllHookError'); 72 | }); 73 | 74 | it('inline sync valid', function () { 75 | let result = runConfigSuite('hooks/beforeall/beforeall.inline.success.suite.yml'); 76 | expect(result.exitCode).to.equal(0); 77 | expect(result.terminationSignal).to.be.a('null'); 78 | const report = fs.readFileSync(result.jsonReport); 79 | let reportData = JSON.parse(report); 80 | 81 | expect(reportData.passedSuitesCount).to.equal(1); 82 | expect(reportData.skippedSuitesCount).to.equal(0); 83 | expect(reportData.failedSuitesCount).to.equal(0); 84 | expect(reportData.passedTestsCount).to.equal(1); 85 | expect(reportData.skippedTestsCount).to.equal(0); 86 | expect(reportData.failedTestsCount).to.equal(0); 87 | expect(reportData.suites.length).to.equal(1); 88 | expect(reportData.suites[0].status).to.equal('pass'); 89 | expect(reportData.suites[0].tests.length).to.equal(1); 90 | expect(reportData.suites[0].error).to.be.a('null'); 91 | }); 92 | 93 | }); -------------------------------------------------------------------------------- /test/cli/cookies.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Cookies', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('cookies.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(4); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(1); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('Add static cookies with request specification', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('pass'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | it('add static cookies in hooks', function () { 38 | let result = suiteContext.result; 39 | let test = result.tests.find(t => t.name === this.test.title); 40 | expect(test.status).to.equal('pass'); 41 | expect(test.error).to.be.a('null'); 42 | }); 43 | 44 | it('run dependency with cookies', function () { 45 | let result = suiteContext.result; 46 | let test = result.tests.find(t => t.name === this.test.title); 47 | expect(test.status).to.equal('pass'); 48 | expect(test.error).to.be.a('null'); 49 | }); 50 | 51 | it('Validate cookies in response - should fail', function () { 52 | let result = suiteContext.result; 53 | let test = result.tests.find(t => t.name === this.test.title); 54 | expect(test.status).to.equal('fail'); 55 | expect(test.error.name).to.equal('ResponseCookieValueDidNotMatchError'); 56 | }); 57 | 58 | it('Validate cookies in response', function () { 59 | let result = suiteContext.result; 60 | let test = result.tests.find(t => t.name === this.test.title); 61 | expect(test.status).to.equal('pass'); 62 | expect(test.error).to.be.a('null'); 63 | }); 64 | 65 | }); -------------------------------------------------------------------------------- /test/cli/disabledspecs.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Disabled specs', function () { 8 | let suiteContext = this; 9 | let tests = ['disabled', 'enabled default', 'enabled with spec']; 10 | 11 | before(async function () { 12 | let result = runJustAPIJSON('disabledspecs.suite.yml'); 13 | if (result.error) throw result.error; 14 | expect(result.exitCode).to.equal(0); 15 | expect(result.terminationSignal).to.be.a('null'); 16 | const report = fs.readFileSync(result.jsonReport); 17 | let reportData = JSON.parse(report); 18 | 19 | expect(reportData.passedSuitesCount).to.equal(1); 20 | expect(reportData.skippedSuitesCount).to.equal(0); 21 | expect(reportData.failedSuitesCount).to.equal(0); 22 | expect(reportData.passedTestsCount).to.equal(2); 23 | expect(reportData.skippedTestsCount).to.equal(1); 24 | expect(reportData.failedTestsCount).to.equal(0); 25 | expect(reportData.suites.length).to.equal(1); 26 | expect(reportData.suites[0].status).to.equal('pass'); 27 | 28 | suiteContext.result = reportData.suites[0]; 29 | }); 30 | 31 | tests.forEach(function (testTitle) { 32 | it(testTitle, function () { 33 | let result = suiteContext.result; 34 | let test = result.tests.find(t => t.name === this.test.title); 35 | if (this.test.title.includes('disabled')) { 36 | expect(test.status).to.equal('skip'); 37 | expect(test.error).to.be.a('null'); 38 | } else { 39 | expect(test.status).to.equal('pass'); 40 | expect(test.error).to.be.a('null'); 41 | } 42 | 43 | }); 44 | }); 45 | 46 | 47 | }); -------------------------------------------------------------------------------- /test/cli/disabledsuite.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Disabled suite', function () { 8 | 9 | it('correct response code', async function () { 10 | let result = runJustAPIJSON('disabledsuite.suite.yml'); 11 | if (result.error) throw result.error; 12 | expect(result.exitCode).to.equal(0); 13 | expect(result.terminationSignal).to.be.a('null'); 14 | const report = fs.readFileSync(result.jsonReport); 15 | let reportData = JSON.parse(report); 16 | 17 | expect(reportData.passedSuitesCount).to.equal(0); 18 | expect(reportData.skippedSuitesCount).to.equal(1); 19 | expect(reportData.failedSuitesCount).to.equal(0); 20 | expect(reportData.passedTestsCount).to.equal(0); 21 | expect(reportData.skippedTestsCount).to.equal(0); 22 | expect(reportData.failedTestsCount).to.equal(0); 23 | expect(reportData.suites.length).to.equal(1); 24 | expect(reportData.suites[0].status).to.equal('skip'); 25 | }); 26 | 27 | 28 | }); -------------------------------------------------------------------------------- /test/cli/grep.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('grep', function () { 8 | let suiteContext = this; 9 | 10 | it('grep using string', async function () { 11 | let result = runJustAPIJSON('grep.suite.yml', ['--grep', 'matches']); 12 | if (result.error) throw result.error; 13 | 14 | expect(result.exitCode).to.equal(0); 15 | expect(result.terminationSignal).to.be.a('null'); 16 | const report = fs.readFileSync(result.jsonReport); 17 | let reportData = JSON.parse(report); 18 | 19 | expect(reportData.passedSuitesCount).to.equal(1); 20 | expect(reportData.skippedSuitesCount).to.equal(0); 21 | expect(reportData.failedSuitesCount).to.equal(0); 22 | expect(reportData.passedTestsCount).to.equal(2); 23 | expect(reportData.skippedTestsCount).to.equal(2); 24 | expect(reportData.failedTestsCount).to.equal(0); 25 | expect(reportData.suites.length).to.equal(1); 26 | expect(reportData.suites[0].status).to.equal('pass'); 27 | 28 | suiteContext.result = reportData.suites[0]; 29 | 30 | suiteContext.result.tests.forEach(function (test) { 31 | if (test.name.includes('matches')) { 32 | expect(test.status).to.equal('pass'); 33 | expect(test.error).to.be.a('null'); 34 | } else { 35 | expect(test.status).to.equal('skip'); 36 | expect(test.error).to.be.a('null'); 37 | } 38 | }) 39 | }); 40 | 41 | it('grep using regex', async function () { 42 | let result = runJustAPIJSON('grep.suite.yml', ['--grep', /(\d)/]); 43 | if (result.error) throw result.error; 44 | 45 | expect(result.exitCode).to.equal(0); 46 | expect(result.terminationSignal).to.be.a('null'); 47 | const report = fs.readFileSync(result.jsonReport); 48 | let reportData = JSON.parse(report); 49 | 50 | expect(reportData.passedSuitesCount).to.equal(1); 51 | expect(reportData.skippedSuitesCount).to.equal(0); 52 | expect(reportData.failedSuitesCount).to.equal(0); 53 | expect(reportData.passedTestsCount).to.equal(2); 54 | expect(reportData.skippedTestsCount).to.equal(2); 55 | expect(reportData.failedTestsCount).to.equal(0); 56 | expect(reportData.suites.length).to.equal(1); 57 | expect(reportData.suites[0].status).to.equal('pass'); 58 | 59 | suiteContext.result = reportData.suites[0]; 60 | let regex = new RegExp(/(\d)/); 61 | 62 | suiteContext.result.tests.forEach(function (test) { 63 | if (regex.test(test.name)) { 64 | expect(test.status).to.equal('pass'); 65 | expect(test.error).to.be.a('null'); 66 | } else { 67 | expect(test.status).to.equal('skip'); 68 | expect(test.error).to.be.a('null'); 69 | } 70 | }) 71 | }); 72 | 73 | }); -------------------------------------------------------------------------------- /test/cli/headers.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('headers', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('headers.suite.yaml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(7); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(2); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('add suite headers to request headers', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('pass'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | it('ignore suite headers', function () { 38 | let result = suiteContext.result; 39 | let test = result.tests.find(t => t.name === this.test.title); 40 | expect(test.status).to.equal('pass'); 41 | expect(test.error).to.be.a('null'); 42 | }); 43 | 44 | it('validate response json header with value', function () { 45 | let result = suiteContext.result; 46 | let test = result.tests.find(t => t.name === this.test.title); 47 | expect(test.status).to.equal('pass'); 48 | expect(test.error).to.be.a('null'); 49 | }); 50 | 51 | it('validate response headers - should fail', function () { 52 | let result = suiteContext.result; 53 | let test = result.tests.find(t => t.name === this.test.title); 54 | expect(test.status).to.equal('fail'); 55 | expect(test.error.name).to.equal('ResponseHeaderValueDidNotMatchError'); 56 | expect(test.error.message).to.contain('Expected value for header: content-type is application/xml, Actual value: application/json'); 57 | }); 58 | 59 | it('validate response headers - with regex', function () { 60 | let result = suiteContext.result; 61 | let test = result.tests.find(t => t.name === this.test.title); 62 | expect(test.status).to.equal('pass'); 63 | expect(test.error).to.be.a('null'); 64 | }); 65 | 66 | it('validate response headers - with regex should fail', function () { 67 | let result = suiteContext.result; 68 | let test = result.tests.find(t => t.name === this.test.title); 69 | expect(test.status).to.equal('fail'); 70 | expect(test.error.name).to.equal('ResponseHeaderValueDidNotMatchError'); 71 | expect(test.error.message).to.contain('Header value did not match with expected Regex. Expected value for header: content-type is to match RegExp /application\\/xml/, Actual value: application/json;'); 72 | }); 73 | 74 | it('send headers specified in request', function () { 75 | let result = suiteContext.result; 76 | let test = result.tests.find(t => t.name === this.test.title); 77 | expect(test.status).to.equal('pass'); 78 | expect(test.error).to.be.a('null'); 79 | }); 80 | 81 | it('send headers specified in before test hook', function () { 82 | let result = suiteContext.result; 83 | let test = result.tests.find(t => t.name === this.test.title); 84 | expect(test.status).to.equal('pass'); 85 | expect(test.error).to.be.a('null'); 86 | }); 87 | 88 | it('override headers specified in before test hook', function () { 89 | let result = suiteContext.result; 90 | let test = result.tests.find(t => t.name === this.test.title); 91 | expect(test.status).to.equal('pass'); 92 | expect(test.error).to.be.a('null'); 93 | }); 94 | 95 | }); -------------------------------------------------------------------------------- /test/cli/helpers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const spawn = require('cross-spawn').spawn; 4 | const path = require('path'); 5 | 6 | function runJustAPIJSON(suiteName, args) { 7 | let suite = resolveSuitePath(suiteName); 8 | 9 | let jsonFile = (new Date()).getTime().toString(); 10 | let jsonReportOpts = `jsonReportDir=logs,jsonReportName=${jsonFile}`; 11 | const jsonReport = path.resolve(path.resolve('./test/cli/src/logs'), `${jsonFile}.json`); 12 | args = args || []; 13 | args = args.concat(['--reporter', 'json', '--reporter-options', jsonReportOpts, suite]); 14 | 15 | let justAPIProcess = invokeJustAPI(args); 16 | 17 | return { 18 | error: justAPIProcess.error, 19 | output: justAPIProcess.output, 20 | exitCode: justAPIProcess.status, 21 | terminationSignal: justAPIProcess.signal, 22 | jsonReport: jsonReport 23 | } 24 | } 25 | 26 | function invokeJustAPI (args) { 27 | args = [path.join(__dirname, '..', '..', 'bin', 'just-api')].concat(args); 28 | 29 | return spawn.sync(process.execPath, args, { cwd: path.resolve('./test/cli/src') }); 30 | } 31 | 32 | function resolveSuitePath (suiteFile) { 33 | return path.resolve(process.cwd(), 'test/cli/src/suites', suiteFile); 34 | } 35 | 36 | module.exports = { 37 | runJustAPIJSON: runJustAPIJSON 38 | }; 39 | -------------------------------------------------------------------------------- /test/cli/https.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('https', function () { 8 | let suiteContext = this; 9 | 10 | before(function () { 11 | let result = runJustAPIJSON('https.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(0); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(1); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(0); 21 | expect(reportData.passedTestsCount).to.equal(1); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(0); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('pass'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('get google https', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('pass'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | }); -------------------------------------------------------------------------------- /test/cli/interdep.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Inter suite spec dependencies', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('suitedependencies/intersuitedeps.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(2); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(3); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('beforetest hook inter-dependent', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('pass'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | it('beforetest hook inter-dependent enabled', function () { 38 | let result = suiteContext.result; 39 | let test = result.tests.find(t => t.name === this.test.title); 40 | expect(test.status).to.equal('pass'); 41 | expect(test.error).to.be.a('null'); 42 | }); 43 | 44 | it('beforetest hook inter-dependent validate response - should fail', function () { 45 | let result = suiteContext.result; 46 | let test = result.tests.find(t => t.name === this.test.title); 47 | expect(test.status).to.equal('fail'); 48 | expect(test.error.name).to.equal('BeforeTestHookError'); 49 | expect(test.error.message).to.contain('ResponseStatusCodeDidNotMatchError - Expected status code: 400, Actual status code: 200'); 50 | }); 51 | 52 | it('beforetest hook inter-dependent error in hook - should fail', function () { 53 | let result = suiteContext.result; 54 | let test = result.tests.find(t => t.name === this.test.title); 55 | expect(test.status).to.equal('fail'); 56 | expect(test.error.name).to.equal('BeforeTestHookError'); 57 | expect(test.error.message).to.contain('SyntaxError - Unexpected token u in JSON at position'); 58 | }); 59 | 60 | it('beforetest hook inter-dependent no matching spec - should fail', function () { 61 | let result = suiteContext.result; 62 | let test = result.tests.find(t => t.name === this.test.title); 63 | expect(test.status).to.equal('fail'); 64 | expect(test.error.name).to.equal('BeforeTestHookError'); 65 | expect(test.error.message).to.contain('NoSpecFoundMatchingNameError - No matching spec found with name'); 66 | }); 67 | 68 | }); -------------------------------------------------------------------------------- /test/cli/interdep.suite.relative.paths.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Inter suite spec dependencies with relative path', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('suitedependencies/relative.intersuite.dep.suite.yml'); 12 | 13 | if (result.error) throw result.error; 14 | expect(result.exitCode).to.equal(0); 15 | expect(result.terminationSignal).to.be.a('null'); 16 | const report = fs.readFileSync(result.jsonReport); 17 | let reportData = JSON.parse(report); 18 | 19 | expect(reportData.passedSuitesCount).to.equal(1); 20 | expect(reportData.skippedSuitesCount).to.equal(0); 21 | expect(reportData.failedSuitesCount).to.equal(0); 22 | expect(reportData.passedTestsCount).to.equal(2); 23 | expect(reportData.skippedTestsCount).to.equal(0); 24 | expect(reportData.failedTestsCount).to.equal(0); 25 | expect(reportData.suites.length).to.equal(1); 26 | expect(reportData.suites[0].status).to.equal('pass'); 27 | 28 | suiteContext.result = reportData.suites[0]; 29 | }); 30 | 31 | it('inter dependency relative path', function () { 32 | let result = suiteContext.result; 33 | let test = result.tests.find(t => t.name === this.test.title); 34 | expect(test.status).to.equal('pass'); 35 | expect(test.error).to.be.a('null'); 36 | }); 37 | 38 | it('inter dependency relative path file upload', function () { 39 | let result = suiteContext.result; 40 | let test = result.tests.find(t => t.name === this.test.title); 41 | expect(test.status).to.equal('pass'); 42 | expect(test.error).to.be.a('null'); 43 | }); 44 | 45 | }); -------------------------------------------------------------------------------- /test/cli/intradep.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Intra suite spec dependencies', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('suitedependencies/intradependencies.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(3); 22 | expect(reportData.skippedTestsCount).to.equal(1); 23 | expect(reportData.failedTestsCount).to.equal(3); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('dep disabled', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('skip'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | it('beforetest hook intra-dependent', function () { 38 | let result = suiteContext.result; 39 | let test = result.tests.find(t => t.name === this.test.title); 40 | expect(test.status).to.equal('pass'); 41 | expect(test.error).to.be.a('null'); 42 | }); 43 | 44 | it('dep enabled', function () { 45 | let result = suiteContext.result; 46 | let test = result.tests.find(t => t.name === this.test.title); 47 | expect(test.status).to.equal('pass'); 48 | expect(test.error).to.be.a('null'); 49 | }); 50 | 51 | it('beforetest hook intra-dependent enabled', function () { 52 | let result = suiteContext.result; 53 | let test = result.tests.find(t => t.name === this.test.title); 54 | expect(test.status).to.equal('pass'); 55 | expect(test.error).to.be.a('null'); 56 | }); 57 | 58 | it('beforetest hook intra-dependent validate response - should fail', function () { 59 | let result = suiteContext.result; 60 | let test = result.tests.find(t => t.name === this.test.title); 61 | expect(test.status).to.equal('fail'); 62 | expect(test.error.name).to.equal('BeforeTestHookError'); 63 | expect(test.error.message).to.contain('ResponseStatusCodeDidNotMatchError - Expected status code: 400, Actual status code: 200'); 64 | }); 65 | 66 | it('beforetest hook intra-dependent error in hook - should fail', function () { 67 | let result = suiteContext.result; 68 | let test = result.tests.find(t => t.name === this.test.title); 69 | expect(test.status).to.equal('fail'); 70 | expect(test.error.name).to.equal('BeforeTestHookError'); 71 | expect(test.error.message).to.contain('SyntaxError - Unexpected token u in JSON at position'); 72 | }); 73 | 74 | it('beforetest hook intra-dependent no matching spec - should fail', function () { 75 | let result = suiteContext.result; 76 | let test = result.tests.find(t => t.name === this.test.title); 77 | expect(test.status).to.equal('fail'); 78 | expect(test.error.name).to.equal('BeforeTestHookError'); 79 | expect(test.error.message).to.contain('NoSpecFoundMatchingNameError - No matching spec found with name'); 80 | }); 81 | 82 | }); -------------------------------------------------------------------------------- /test/cli/invalidsuiteschema.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Invalid suite schema', function () { 8 | 9 | it('invalid suite schema - request key missing in spec', function () { 10 | let result = runJustAPIJSON('suiteschema/invalidspecschema.suite.yml'); 11 | expect(result.exitCode).to.equal(1); 12 | expect(result.terminationSignal).to.be.a('null'); 13 | const report = fs.readFileSync(result.jsonReport); 14 | let reportData = JSON.parse(report); 15 | 16 | expect(reportData.passedSuitesCount).to.equal(0); 17 | expect(reportData.skippedSuitesCount).to.equal(0); 18 | expect(reportData.failedSuitesCount).to.equal(1); 19 | expect(reportData.passedTestsCount).to.equal(0); 20 | expect(reportData.skippedTestsCount).to.equal(0); 21 | expect(reportData.failedTestsCount).to.equal(0); 22 | expect(reportData.suites.length).to.equal(1); 23 | expect(reportData.suites[0].status).to.equal('fail'); 24 | expect(reportData.suites[0].tests.length).to.equal(0); 25 | expect(reportData.suites[0].error.name).to.equal('InvalidSuiteSchemaError'); 26 | }); 27 | 28 | }); -------------------------------------------------------------------------------- /test/cli/jsonschema.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Response JSON schema', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('jsonschema.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(2); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(5); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('read json schema from file and validate response', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('pass'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | it('read inline json schema and validate response', function () { 38 | let result = suiteContext.result; 39 | let test = result.tests.find(t => t.name === this.test.title); 40 | expect(test.status).to.equal('pass'); 41 | expect(test.error).to.be.a('null'); 42 | }); 43 | 44 | it('read json schema from file and validate response - should fail', function () { 45 | let result = suiteContext.result; 46 | let test = result.tests.find(t => t.name === this.test.title); 47 | expect(test.status).to.equal('fail'); 48 | expect(test.error.name).to.equal('ResponseJSONSchemaValidationError'); 49 | expect(test.error.message).to.contain('Response json schema validation failed for property - instance.key, message: is not of a type(s) number'); 50 | }); 51 | 52 | it('read json schema from non existant file and validate response - should fail', function () { 53 | let result = suiteContext.result; 54 | let test = result.tests.find(t => t.name === this.test.title); 55 | expect(test.status).to.equal('fail'); 56 | expect(test.error.name).to.equal('ResponseJSONSchemaValidationError'); 57 | expect(test.error.message).to.contain('Error occurred during response json schema validation'); 58 | }); 59 | 60 | it('read inline invalid json schema and validate response - should fail', function () { 61 | let result = suiteContext.result; 62 | let test = result.tests.find(t => t.name === this.test.title); 63 | expect(test.status).to.equal('fail'); 64 | expect(test.error.name).to.equal('ResponseJSONSchemaValidationError'); 65 | expect(test.error.message).to.contain('Response json schema validation failed for property - instance.key, message: is not of a type(s) number'); 66 | }); 67 | 68 | it('read junk json schema from file and validate response - should fail', function () { 69 | let result = suiteContext.result; 70 | let test = result.tests.find(t => t.name === this.test.title); 71 | expect(test.status).to.equal('fail'); 72 | expect(test.error.name).to.equal('ResponseJSONSchemaValidationError'); 73 | expect(test.error.message).to.contain('SyntaxError occurred while parsing the input schema'); 74 | }); 75 | 76 | it('invalid input schema - should fail', function () { 77 | let result = suiteContext.result; 78 | let test = result.tests.find(t => t.name === this.test.title); 79 | expect(test.status).to.equal('fail'); 80 | expect(test.error.name).to.equal('ResponseJSONSchemaValidationError'); 81 | expect(test.error.message).to.contain('SyntaxError occurred while parsing the inline input schema'); 82 | }); 83 | 84 | }); -------------------------------------------------------------------------------- /test/cli/loop.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('loop', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('loop.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(11); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(2); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('test status', function () { 31 | let result = suiteContext.result; 32 | result.tests.forEach(function (test) { 33 | if (test.name === 'loop continues despite iteration failure - should fail one in loop - loop iteration 1') { 34 | expect(test.status).to.equal('fail'); 35 | expect(test.error.name).to.equal('CustomResponseValidationError'); 36 | expect(test.error.message).to.contain('failing loop spec on an iteration'); 37 | } else if (test.name === 'loop function failure - should fail') { 38 | expect(test.status).to.equal('fail'); 39 | expect(test.error.name).to.equal('LoopItemsBuilderError'); 40 | expect(test.error.message).to.contain('error thrown from loop items builder function'); 41 | } else { 42 | expect(test.status).to.equal('pass'); 43 | expect(test.error).to.be.a('null'); 44 | } 45 | }); 46 | 47 | }); 48 | 49 | 50 | }); -------------------------------------------------------------------------------- /test/cli/multipartformbody.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Multipart form post', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('multipartformpost.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(3); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(3); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('post multipart form data single file and field', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('pass'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | it('post multipart form data multiple files and fields', function () { 38 | let result = suiteContext.result; 39 | let test = result.tests.find(t => t.name === this.test.title); 40 | expect(test.status).to.equal('pass'); 41 | expect(test.error).to.be.a('null'); 42 | }); 43 | 44 | it('post multipart form data single file and json text as field with options', function () { 45 | let result = suiteContext.result; 46 | let test = result.tests.find(t => t.name === this.test.title); 47 | expect(test.status).to.equal('pass'); 48 | expect(test.error).to.be.a('null'); 49 | }); 50 | 51 | it('post multipart form data single file and field without header - should fail', function () { 52 | let result = suiteContext.result; 53 | let test = result.tests.find(t => t.name === this.test.title); 54 | expect(test.status).to.equal('fail'); 55 | expect(test.error.name).to.equal('InvalidRequestHeaderError'); 56 | expect(test.error.message).to.contain('Request method is post,request body is provided but Content-Type header is not provided'); 57 | }); 58 | 59 | it('post multipart form data single non existant file and field - should fail', function () { 60 | let result = suiteContext.result; 61 | let test = result.tests.find(t => t.name === this.test.title); 62 | expect(test.status).to.equal('fail'); 63 | expect(test.error.name).to.equal('RequestBodyBuilderError'); 64 | expect(test.error.message).to.contain("Provide a valid path for content of form body"); 65 | }); 66 | 67 | it('post multipart form data single directory as file and field - should fail', function () { 68 | let result = suiteContext.result; 69 | let test = result.tests.find(t => t.name === this.test.title); 70 | expect(test.status).to.equal('fail'); 71 | expect(test.error.name).to.equal('RequestBodyBuilderError'); 72 | expect(test.error.message).to.contain("Provide a valid path for content of form body"); 73 | }); 74 | 75 | 76 | }); -------------------------------------------------------------------------------- /test/cli/otherverbs.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Other verbs', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('otherverbs.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(0); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(1); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(0); 21 | expect(reportData.passedTestsCount).to.equal(5); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(0); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('pass'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | let tests = ['put json data as body', 'patch json data as body', 'delete item', 'HEAD method', 'options method']; 31 | 32 | tests.forEach(function (testTitle) { 33 | it(testTitle, function () { 34 | let result = suiteContext.result; 35 | let test = result.tests.find(t => t.name === this.test.title); 36 | expect(test.status).to.equal('pass'); 37 | expect(test.error).to.be.a('null'); 38 | }); 39 | }) 40 | 41 | }); -------------------------------------------------------------------------------- /test/cli/params.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Params', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('params.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(0); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(1); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(0); 21 | expect(reportData.passedTestsCount).to.equal(8); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(0); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('pass'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | let tests = ['static query params in request', 'multiple static query params in request', 'query params added to test context', 'query params overidden in test context', 'static path params in request', 31 | 'multiple static path params in request', 'query params added to test context', 'query params overidden in test context']; 32 | 33 | tests.forEach(function (testTitle) { 34 | it(testTitle, function () { 35 | let result = suiteContext.result; 36 | let test = result.tests.find(t => t.name === this.test.title); 37 | expect(test.status).to.equal('pass'); 38 | expect(test.error).to.be.a('null'); 39 | }); 40 | }) 41 | 42 | }); -------------------------------------------------------------------------------- /test/cli/postrawbody.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Post raw body request', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('postrawbody.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(4); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(4); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | suiteContext.result = reportData.suites[0]; 27 | }); 28 | 29 | it('post json data as body', function () { 30 | let result = suiteContext.result; 31 | let test = result.tests.find(t => t.name === this.test.title); 32 | expect(test.status).to.equal('pass'); 33 | expect(test.error).to.be.a('null'); 34 | }); 35 | 36 | it('post text data as json body', function () { 37 | let result = suiteContext.result; 38 | let test = result.tests.find(t => t.name === this.test.title); 39 | expect(test.status).to.equal('pass'); 40 | expect(test.error).to.be.a('null'); 41 | }); 42 | 43 | it('post text data as body', function () { 44 | let result = suiteContext.result; 45 | let test = result.tests.find(t => t.name === this.test.title); 46 | expect(test.status).to.equal('pass'); 47 | expect(test.error).to.be.a('null'); 48 | }); 49 | 50 | it('post binary data (file) as body', function () { 51 | let result = suiteContext.result; 52 | let test = result.tests.find(t => t.name === this.test.title); 53 | expect(test.status).to.equal('pass'); 54 | expect(test.error).to.be.a('null'); 55 | }); 56 | 57 | it('post json data as body without header - should fail', function () { 58 | let result = suiteContext.result; 59 | let test = result.tests.find(t => t.name === this.test.title); 60 | expect(test.status).to.equal('fail'); 61 | expect(test.error.name).to.equal('InvalidRequestHeaderError'); 62 | expect(test.error.message).to.contain('Request method is post,request body is provided but Content-Type header is not provided'); 63 | }); 64 | 65 | it('post text data as body with wrong content - should fail', function () { 66 | let result = suiteContext.result; 67 | let test = result.tests.find(t => t.name === this.test.title); 68 | expect(test.status).to.equal('fail'); 69 | expect(test.error.name).to.equal('InvalidRequestSpecificationError'); 70 | expect(test.error.message).to.contain('Payload type is given as text, but content provided is not a string or number'); 71 | }); 72 | 73 | it('post binary data (non existant file) as body - should fail', function () { 74 | let result = suiteContext.result; 75 | let test = result.tests.find(t => t.name === this.test.title); 76 | expect(test.status).to.equal('fail'); 77 | expect(test.error.name).to.equal('RequestBodyBuilderError'); 78 | expect(test.error.message).to.contain('does not exist, Provide a valid file path to be sent as body content'); 79 | }); 80 | 81 | it('post binary data (directory path) as body - should fail', function () { 82 | let result = suiteContext.result; 83 | let test = result.tests.find(t => t.name === this.test.title); 84 | expect(test.status).to.equal('fail'); 85 | expect(test.error.name).to.equal('RequestBodyBuilderError'); 86 | expect(test.error.message).to.contain('is not a file, Provide a valid file path to be sent as body content'); 87 | }); 88 | 89 | }); -------------------------------------------------------------------------------- /test/cli/retry.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('retries', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('retry.suite.yml', ['--reporter-options', 'logRequests']); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(1); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(1); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('retry returns success after 2 attempts', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('pass'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | it('retry fails - should fail', function () { 38 | let result = suiteContext.result; 39 | let test = result.tests.find( t => t.name === this.test.title ); 40 | expect(test.status).to.equal('fail'); 41 | expect(test.error.name).to.equal('ResponseStatusCodeDidNotMatchError'); 42 | expect(test.error.message).to.contain('Expected status code: 200, Actual status code: 404'); 43 | }); 44 | 45 | }); -------------------------------------------------------------------------------- /test/cli/smoke.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('smoke test', async function () { 8 | it('can invoke and run just-api with serial execution mode', async function () { 9 | let result = runJustAPIJSON('smoke*.suite.yml'); 10 | if (result.error) throw result.error; 11 | 12 | expect(result.exitCode).to.equal(0); 13 | expect(result.terminationSignal).to.be.a('null'); 14 | 15 | const report = fs.readFileSync(result.jsonReport); 16 | const reportData = JSON.parse(report); 17 | expect(reportData.passedSuitesCount).to.equal(2); 18 | expect(reportData.skippedSuitesCount).to.equal(0); 19 | expect(reportData.failedSuitesCount).to.equal(0); 20 | expect(reportData.passedTestsCount).to.equal(2); 21 | expect(reportData.skippedTestsCount).to.equal(0); 22 | expect(reportData.failedTestsCount).to.equal(0); 23 | 24 | reportData.suites.forEach(suite => { 25 | expect(suite.error).to.be.a('null'); 26 | }) 27 | }); 28 | 29 | it('can invoke and run just-api with parallel execution mode', async function () { 30 | let args = ['--parallel', '4']; 31 | let result = runJustAPIJSON('smoke*.suite.yml', args); 32 | if (result.error) throw result.error; 33 | 34 | expect(result.exitCode).to.equal(0); 35 | expect(result.terminationSignal).to.be.a('null'); 36 | 37 | const report = fs.readFileSync(result.jsonReport); 38 | const reportData = JSON.parse(report); 39 | expect(reportData.passedSuitesCount).to.equal(2); 40 | expect(reportData.skippedSuitesCount).to.equal(0); 41 | expect(reportData.failedSuitesCount).to.equal(0); 42 | expect(reportData.passedTestsCount).to.equal(2); 43 | expect(reportData.skippedTestsCount).to.equal(0); 44 | expect(reportData.failedTestsCount).to.equal(0); 45 | 46 | reportData.suites.forEach(suite => { 47 | expect(suite.error).to.be.a('null'); 48 | }) 49 | }); 50 | 51 | }); -------------------------------------------------------------------------------- /test/cli/src/modules/after_each.js: -------------------------------------------------------------------------------- 1 | function afterEachSyncSuccess() { 2 | var keys = Object.keys(this); 3 | if (keys.length !== 5) 4 | throw new Error("after each context doesn't have expected keys"); 5 | 6 | var body = JSON.parse(this.response.body); 7 | if (body.param1 !== 'value2') 8 | throw new Error('unexpected response'); 9 | } 10 | 11 | async function afterEachAsyncSuccess() { 12 | var keys = Object.keys(this); 13 | if (keys.length !== 5) 14 | throw new Error("after each context doesn't have expected keys"); 15 | 16 | var body = JSON.parse(this.response.body); 17 | if (body.param1 !== 'value2') 18 | throw new Error('unexpected response'); 19 | } 20 | 21 | function afterEachSyncError() { 22 | var keys = Object.keys(this); 23 | if (keys.length !== 5) 24 | throw new Error("after each context doesn't have expected keys"); 25 | 26 | var body = JSON.parse(this.response.body); 27 | if (body.param1 !== 'value2') 28 | throw new Error('unexpected response'); 29 | throw new Error('error thrown in after each hook'); 30 | } 31 | 32 | async function afterEachAsyncError() { 33 | var keys = Object.keys(this); 34 | if (keys.length !== 5) 35 | throw new Error("after each context doesn't have expected keys"); 36 | 37 | var body = JSON.parse(this.response.body); 38 | if (body.param1 !== 'value2') 39 | throw new Error('unexpected response'); 40 | throw new Error('error thrown in after each hook'); 41 | } 42 | 43 | module.exports = { 44 | afterEachSyncSuccess: afterEachSyncSuccess, 45 | afterEachAsyncSuccess: afterEachAsyncSuccess, 46 | afterEachSyncError: afterEachSyncError, 47 | afterEachAsyncError: afterEachAsyncError 48 | }; -------------------------------------------------------------------------------- /test/cli/src/modules/after_test.js: -------------------------------------------------------------------------------- 1 | function afterTestSyncSuccess() { 2 | var body = JSON.parse(this.response.body); 3 | if (body.param1 !== 'value2') 4 | throw new Error('unexpected response'); 5 | } 6 | 7 | async function afterTestAsyncSuccess() { 8 | var self = this; 9 | 10 | await new Promise(function (resolve, reject) { 11 | setTimeout(function () { 12 | var body = JSON.parse(self.response.body); 13 | if (body.param1 !== 'value2') 14 | throw new Error('unexpected response'); 15 | resolve(true); 16 | }, 1); 17 | }); 18 | } 19 | 20 | function afterTestSyncError() { 21 | var body = JSON.parse(this.response.body); 22 | if (body.param1 !== 'value2') 23 | throw new Error('unexpected response'); 24 | 25 | throw new Error('error thrown in after test hook'); 26 | } 27 | 28 | async function afterTestAsyncError() { 29 | var self = this; 30 | 31 | await new Promise(function (resolve, reject) { 32 | setTimeout(function () { 33 | var body = JSON.parse(self.response.body); 34 | if (body.param1 !== 'value2') 35 | throw new Error('unexpected response'); 36 | resolve(true); 37 | }, 1); 38 | }); 39 | 40 | throw new Error('error thrown in after test hook'); 41 | } 42 | 43 | async function afterTestAsyncRejectedPromise() { 44 | var self = this; 45 | 46 | await new Promise(function (resolve, reject) { 47 | setTimeout(function () { 48 | var body = JSON.parse(self.response.body); 49 | if (body.param1 !== 'value2') 50 | throw new Error('unexpected response'); 51 | reject('error thrown in after test hook'); 52 | }, 1); 53 | }); 54 | } 55 | 56 | module.exports = { 57 | afterTestSyncSuccess: afterTestSyncSuccess, 58 | afterTestAsyncSuccess: afterTestAsyncSuccess, 59 | afterTestSyncError: afterTestSyncError, 60 | afterTestAsyncError: afterTestAsyncError, 61 | afterTestAsyncRejectedPromise: afterTestAsyncRejectedPromise 62 | }; -------------------------------------------------------------------------------- /test/cli/src/modules/before_each.js: -------------------------------------------------------------------------------- 1 | function beforeEachSyncSuccess() { 2 | var keys = Object.keys(this); 3 | if (keys.length !== 4) 4 | throw new Error("before each context doesn't have expected keys"); 5 | 6 | this.test.query_params = {param1: 'value2'}; 7 | } 8 | 9 | async function beforeEachAsyncSuccess() { 10 | var keys = Object.keys(this); 11 | if (keys.length !== 4) 12 | throw new Error("before each context doesn't have expected keys"); 13 | 14 | this.test.query_params = {param1: 'value2'}; 15 | } 16 | 17 | function beforeEachSyncError() { 18 | var keys = Object.keys(this); 19 | if (keys.length !== 4) 20 | throw new Error("before each context doesn't have expected keys"); 21 | 22 | this.test.query_params = {param1: 'value2'}; 23 | throw new Error('error thrown in before each hook'); 24 | } 25 | 26 | async function beforeEachAsyncError() { 27 | var keys = Object.keys(this); 28 | if (keys.length !== 4) 29 | throw new Error("before each context doesn't have expected keys"); 30 | 31 | this.test.query_params = {param1: 'value2'}; 32 | throw new Error('error thrown in before each hook'); 33 | } 34 | 35 | module.exports = { 36 | beforeEachSyncSuccess: beforeEachSyncSuccess, 37 | beforeEachAsyncSuccess: beforeEachAsyncSuccess, 38 | beforeEachSyncError: beforeEachSyncError, 39 | beforeEachAsyncError: beforeEachAsyncError 40 | }; -------------------------------------------------------------------------------- /test/cli/src/modules/before_test.js: -------------------------------------------------------------------------------- 1 | function beforeTestSyncSuccess() { 2 | this.test.query_params = {param1: 'value2'}; 3 | } 4 | 5 | async function beforeTestAsyncSuccess() { 6 | var self = this; 7 | 8 | await new Promise(function (resolve, reject) { 9 | setTimeout(function () { 10 | self.test.query_params = {param1: 'value2'}; 11 | resolve(true); 12 | }, 1); 13 | }); 14 | } 15 | 16 | function beforeTestSyncError() { 17 | this.test.query_params = {param1: 'value2'}; 18 | throw new Error('error thrown in before test hook'); 19 | } 20 | 21 | async function beforeTestAsyncError() { 22 | var self = this; 23 | 24 | await new Promise(function (resolve, reject) { 25 | setTimeout(function () { 26 | self.test.query_params = {param1: 'value2'}; 27 | resolve(true); 28 | }, 1); 29 | }); 30 | 31 | throw new Error('error thrown in before test hook'); 32 | } 33 | 34 | async function beforeTestAsyncRejectedPromise() { 35 | var self = this; 36 | 37 | await new Promise(function (resolve, reject) { 38 | setTimeout(function () { 39 | self.test.query_params = {param1: 'value2'}; 40 | reject('error thrown in before test hook'); 41 | }, 1); 42 | }); 43 | } 44 | 45 | module.exports = { 46 | beforeTestSyncSuccess: beforeTestSyncSuccess, 47 | beforeTestAsyncSuccess: beforeTestAsyncSuccess, 48 | beforeTestSyncError: beforeTestSyncError, 49 | beforeTestAsyncError: beforeTestAsyncError, 50 | beforeTestAsyncRejectedPromise: beforeTestAsyncRejectedPromise 51 | }; -------------------------------------------------------------------------------- /test/cli/src/modules/custom_validator.js: -------------------------------------------------------------------------------- 1 | function customValidatorSuccessSync() { 2 | var keys = Object.keys(this); 3 | 4 | if (keys.length !== 1 || keys[0] !== 'response') 5 | throw new Error("response context is not available in custom validator module sync function"); 6 | 7 | if (this.response.constructor.name !== 'IncomingMessage') 8 | throw new Error("response is not of type Incoming Message"); 9 | 10 | var body = JSON.parse(this.response.body); 11 | 12 | if (body.key1 !== 'value1') 13 | throw new Error("Value of key1 is not value1"); 14 | } 15 | 16 | function customValidatorErrorSync() { 17 | throw new Error('error thrown from custom validator module sync function'); 18 | } 19 | 20 | async function customValidatorSuccessAsync() { 21 | var keys = Object.keys(this); 22 | if (keys.length !== 1 || keys[0] !== 'response') 23 | throw new Error("response context is not available in custom validator"); 24 | 25 | var startTime = new Date().getTime(); 26 | var result = await new Promise(function (resolve, reject) { 27 | setTimeout(function () { 28 | resolve(1) 29 | }, 7); 30 | }); 31 | var endTime = new Date().getTime(); 32 | 33 | if ((endTime - startTime) < 7) 34 | throw new Error("did not wait until promise is resolved"); 35 | 36 | var body = JSON.parse(this.response.body); 37 | 38 | if (body.key1 !== 'value1') 39 | throw new Error("Value of key1 is not value1"); 40 | } 41 | 42 | async function customValidatorErrorAsync() { 43 | throw new Error('error thrown from custom validator module async function'); 44 | } 45 | 46 | async function customValidatorErrorAsyncRejectedPromise() { 47 | var result = await new Promise(function (resolve, reject) { 48 | reject('rejected promise'); 49 | }); 50 | 51 | var endTime = new Date().getTime(); 52 | } 53 | 54 | async function customValidatorErrorAsyncReturnRejectedPromise() { 55 | return new Promise(function (resolve, reject) { 56 | setTimeout(function () { 57 | reject('rejected promise') 58 | }, 3); 59 | }); 60 | } 61 | 62 | module.exports = { 63 | customValidatorSuccessSync: customValidatorSuccessSync, 64 | customValidatorErrorSync: customValidatorErrorSync, 65 | customValidatorSuccessAsync: customValidatorSuccessAsync, 66 | customValidatorErrorAsync: customValidatorErrorAsync, 67 | customValidatorErrorAsyncRejectedPromise: customValidatorErrorAsyncRejectedPromise, 68 | customValidatorErrorAsyncReturnRejectedPromise: customValidatorErrorAsyncReturnRejectedPromise 69 | }; -------------------------------------------------------------------------------- /test/cli/src/modules/loop.js: -------------------------------------------------------------------------------- 1 | function loopSyncSuccess() { 2 | return ['a', 'b']; 3 | } 4 | 5 | async function loopAsyncSuccess() { 6 | var promise = await new Promise(function (resolve, reject) { 7 | setTimeout(function () { 8 | resolve(['a', 'b']) 9 | }, 3) 10 | }); 11 | 12 | return promise; 13 | } 14 | 15 | module.exports = { 16 | loopSyncSuccess: loopSyncSuccess, 17 | loopAsyncSuccess: loopAsyncSuccess 18 | }; -------------------------------------------------------------------------------- /test/cli/src/modules/suite_configuration.js: -------------------------------------------------------------------------------- 1 | function syncSuiteConfig() { 2 | this.scheme = 'http'; 3 | this.port = 3027; 4 | } 5 | 6 | module.exports = { 7 | syncSuiteConfig: syncSuiteConfig 8 | }; -------------------------------------------------------------------------------- /test/cli/src/static/assets/chow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/test/cli/src/static/assets/chow.jpg -------------------------------------------------------------------------------- /test/cli/src/static/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiranz/just-api/d076362e366ac6d44404302c3df0640f30da9b02/test/cli/src/static/assets/logo.png -------------------------------------------------------------------------------- /test/cli/src/static/schema/junk_simple_valid.json: -------------------------------------------------------------------------------- 1 | { 2 | junk"$id": "http://example.com/example.json", 3 | "type": "object", 4 | "$schema": "http://json-schema.org/draft-06/schema#", 5 | "properties": { 6 | "key": { 7 | "$id": "/properties/key", 8 | "type": "string" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/cli/src/static/schema/simple_invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "http://example.com/example.json", 3 | "type": "object", 4 | "$schema": "http://json-schema.org/draft-06/schema#", 5 | "properties": { 6 | "key": { 7 | "$id": "/properties/key", 8 | "type": "number" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/cli/src/static/schema/simple_valid.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "http://example.com/example.json", 3 | "type": "object", 4 | "$schema": "http://json-schema.org/draft-06/schema#", 5 | "properties": { 6 | "key": { 7 | "$id": "/properties/key", 8 | "type": "string" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/cli/src/suites/additional.opts.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Additional request options 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: post redirect is followed by default 9 | request: &default_request 10 | path: /redirect302 11 | method: get 12 | response: 13 | status_code: 200 14 | 15 | - name: redirect is not followed - should fail 16 | request: &default_request 17 | path: /redirect302 18 | method: get 19 | additional_options: 20 | followRedirect: false 21 | response: 22 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/cookies.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Cookies Suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: Add static cookies with request specification 9 | request: 10 | path: /echoCookies 11 | method: get 12 | cookies: 13 | - name: cookie1 14 | value: cookie1-value 15 | - name: cookie2 16 | value: cookie2-value 17 | response: 18 | status_code: 200 19 | json_data: 20 | - path: $.cookie1 21 | value: cookie1-value 22 | - path: $.cookie2 23 | value: cookie2-value 24 | 25 | - name: add static cookies in hooks 26 | before_test: 27 | run_type: inline 28 | inline: 29 | function: !!js/function > 30 | function() { 31 | this.test.cookies = {cookie1: 'cookie1-value'} 32 | } 33 | request: 34 | path: /echoCookies 35 | method: get 36 | response: 37 | status_code: 200 38 | json_data: 39 | - path: $.cookie1 40 | value: cookie1-value 41 | 42 | - name: run dependency with cookies 43 | before_test: 44 | run_type: inline 45 | inline: 46 | function: !js/asyncFunction > 47 | async function() { 48 | var response = await this.runSpec('Add static cookies with request specification', {cookies: {z: 'k'}}); 49 | var responseData = JSON.parse(response.body); 50 | this.test.cookies = responseData; 51 | } 52 | request: 53 | path: /echoCookies 54 | method: get 55 | response: 56 | status_code: 200 57 | json_data: 58 | - path: $.z 59 | value: k 60 | 61 | - name: Validate cookies in response 62 | request: 63 | path: /setCookies 64 | method: post 65 | headers: 66 | - name: content-type 67 | value: application/json 68 | payload: 69 | body: 70 | type: json 71 | content: 72 | cookie1: value1 73 | cookie2: value2 74 | response: 75 | status_code: 200 76 | cookies: 77 | - name: cookie1 78 | value: value1 79 | - name: cookie2 80 | value: !!js/regexp /[0-9]/ 81 | 82 | - name: Validate cookies in response - should fail 83 | request: 84 | path: /setCookies 85 | method: post 86 | headers: 87 | - name: content-type 88 | value: application/json 89 | payload: 90 | body: 91 | type: json 92 | content: 93 | cookie1: value1 94 | cookie2: value2 95 | response: 96 | status_code: 200 97 | cookies: 98 | - name: cookie1 99 | value: wrongvalue -------------------------------------------------------------------------------- /test/cli/src/suites/disabledspecs.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: grep suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: disabled 9 | enabled: false 10 | request: &default_request 11 | path: / 12 | method: get 13 | response: &default_response 14 | status_code: 200 15 | 16 | - name: enabled default 17 | request: *default_request 18 | response: *default_response 19 | 20 | - name: enabled with spec 21 | enabled: true 22 | request: *default_request 23 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/disabledsuite.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: dependency suite 3 | enabled: false 4 | configuration: 5 | scheme: http 6 | host: 127.0.0.1 7 | port: 3027 8 | specs: 9 | - name: get query params 10 | request: 11 | path: /echoQueryParams 12 | method: get 13 | query_params: 14 | - name: q 15 | value: v 16 | response: 17 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/grep.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: grep suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: grep matches get index html 9 | request: &default_request 10 | path: / 11 | method: get 12 | response: &default_response 13 | status_code: 200 14 | 15 | - name: grep doesnotmatch get index html 16 | request: *default_request 17 | response: *default_response 18 | 19 | - name: grep matches get index html 1 20 | request: *default_request 21 | response: *default_response 22 | 23 | - name: grep doesnotmatch get index html 1 24 | request: *default_request 25 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/headers.suite.yaml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Testing headers 3 | enabled: true 4 | version: "1.0" 5 | configuration: 6 | scheme: http 7 | host: 127.0.0.1 8 | port: 3027 9 | common_headers: 10 | - name: customsuiteheader 11 | value: custom-suite-header-value 12 | specs: 13 | - name: add suite headers to request headers 14 | request: 15 | path: /echoHeaders 16 | method: get 17 | response: 18 | json_data: 19 | - path: "$.customsuiteheader" 20 | value: "custom-suite-header-value" 21 | - name: ignore suite headers 22 | ignore_suite_headers: true 23 | request: 24 | path: /echoHeaders 25 | method: get 26 | response: 27 | custom_validator: 28 | run_type: inline 29 | inline: 30 | function: !!js/function > 31 | function() { 32 | let body = JSON.parse(this.response.body); 33 | 34 | if (body.customsuiteheader) 35 | throw new Error('common suite header is received in response'); 36 | } 37 | - name: validate response json header with value 38 | request: 39 | path: /echoHeaders 40 | method: get 41 | response: 42 | headers: 43 | - name: content-type 44 | value: application/json; charset=utf-8 45 | - name: validate response headers - should fail 46 | request: 47 | path: /echoHeaders 48 | method: get 49 | response: 50 | headers: 51 | - name: content-type 52 | value: application/xml 53 | - name: validate response headers - with regex 54 | request: 55 | path: /echoHeaders 56 | method: get 57 | response: 58 | headers: 59 | - name: content-type 60 | value: !!js/regexp application/json 61 | - name: validate response headers - with regex should fail 62 | request: 63 | path: /echoHeaders 64 | method: get 65 | response: 66 | headers: 67 | - name: content-type 68 | value: !!js/regexp application/xml 69 | - name: send headers specified in request 70 | request: 71 | path: /echoHeaders 72 | method: get 73 | headers: 74 | - name: header1 75 | value: header1-value 76 | response: 77 | json_data: 78 | - path: "$.header1" 79 | value: "header1-value" 80 | - name: send headers specified in before test hook 81 | before_test: 82 | run_type: inline 83 | inline: 84 | function: !!js/function > 85 | function() { 86 | this.test.headers = { header2: 'header2-value' }; 87 | } 88 | request: 89 | path: /echoHeaders 90 | method: get 91 | headers: 92 | - name: header1 93 | value: header1-value 94 | response: 95 | json_data: 96 | - path: "$.header2" 97 | value: "header2-value" 98 | - path: "$.header1" 99 | value: "header1-value" 100 | - name: override headers specified in before test hook 101 | before_test: 102 | run_type: inline 103 | inline: 104 | function: !!js/function > 105 | function() { 106 | this.test.headers = { header1: 'header2-value' }; 107 | } 108 | request: 109 | path: /echoHeaders 110 | method: get 111 | headers: 112 | - name: header1 113 | value: header1-value 114 | response: 115 | json_data: 116 | - path: "$.header1" 117 | value: "header2-value" -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/afterall/afterall.inline.async.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After all inline async failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_all: 9 | run_type: inline 10 | inline: 11 | function: !js/asyncFunction > 12 | async function() { 13 | throw new Error("error from after all"); 14 | } 15 | specs: 16 | - name: get home 17 | request: &default_request 18 | path: / 19 | method: get 20 | response: &default_response 21 | status_code: 200 22 | -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/afterall/afterall.inline.async.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After all inline async success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_all: 9 | run_type: inline 10 | inline: 11 | function: !js/asyncFunction > 12 | async function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 3) 15 | throw new Error("after all context doesn't have expected keys"); 16 | } 17 | specs: 18 | - name: get home 19 | request: &default_request 20 | path: / 21 | method: get 22 | response: &default_response 23 | status_code: 200 24 | -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/afterall/afterall.inline.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After all inline failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_all: 9 | run_type: inline 10 | inline: 11 | function: !!js/function > 12 | function() { 13 | throw new Error('error from after all'); 14 | } 15 | specs: 16 | - name: get home 17 | request: &default_request 18 | path: / 19 | method: get 20 | response: &default_response 21 | status_code: 200 22 | -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/afterall/afterall.inline.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After all inline success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_all: 9 | run_type: inline 10 | inline: 11 | function: !!js/function > 12 | function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 3) 15 | throw new Error("after all context doesn't have expected keys"); 16 | } 17 | specs: 18 | - name: get home 19 | request: &default_request 20 | path: / 21 | method: get 22 | response: &default_response 23 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/aftereach/aftereach.inline.async.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After each inline async failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_each: 9 | run_type: inline 10 | inline: 11 | function: !js/asyncFunction > 12 | async function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 5) 15 | throw new Error("after each context doesn't have expected keys"); 16 | 17 | var body = JSON.parse(this.response.body); 18 | if (body.param1 !== 'value2') 19 | throw new Error('unexpected response'); 20 | throw new Error('error thrown in after each hook'); 21 | } 22 | specs: 23 | - name: get query params 24 | request: &default_request 25 | path: /echoQueryParams 26 | method: get 27 | query_params: 28 | - name: param1 29 | value: value2 30 | response: &default_response 31 | json_data: 32 | - path: $ 33 | value: 34 | param1: value2 35 | 36 | - name: get query params again 37 | request: *default_request 38 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/aftereach/aftereach.inline.async.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After each inline async success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_each: 9 | run_type: inline 10 | inline: 11 | function: !js/asyncFunction > 12 | async function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 5) 15 | throw new Error("after each context doesn't have expected keys"); 16 | 17 | var body = JSON.parse(this.response.body); 18 | if (body.param1 !== 'value2') 19 | throw new Error('unexpected response'); 20 | } 21 | specs: 22 | - name: get query params 23 | request: &default_request 24 | path: /echoQueryParams 25 | method: get 26 | query_params: 27 | - name: param1 28 | value: value2 29 | response: &default_response 30 | json_data: 31 | - path: $ 32 | value: 33 | param1: value2 34 | 35 | - name: get query params again 36 | request: *default_request 37 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/aftereach/aftereach.inline.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After each inline sync failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_each: 9 | run_type: inline 10 | inline: 11 | function: !!js/function > 12 | function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 5) 15 | throw new Error("after each context doesn't have expected keys"); 16 | 17 | var body = JSON.parse(this.response.body); 18 | if (body.param1 !== 'value2') 19 | throw new Error('unexpected response'); 20 | throw new Error('error thrown in after each hook'); 21 | } 22 | specs: 23 | - name: get query params 24 | request: &default_request 25 | path: /echoQueryParams 26 | method: get 27 | query_params: 28 | - name: param1 29 | value: value2 30 | response: &default_response 31 | json_data: 32 | - path: $ 33 | value: 34 | param1: value2 35 | 36 | - name: get query params again 37 | request: *default_request 38 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/aftereach/aftereach.inline.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After each inline sync success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_each: 9 | run_type: inline 10 | inline: 11 | function: !!js/function > 12 | function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 5) 15 | throw new Error("after each context doesn't have expected keys"); 16 | 17 | var body = JSON.parse(this.response.body); 18 | if (body.param1 !== 'value2') 19 | throw new Error('unexpected response'); 20 | } 21 | specs: 22 | - name: get query params 23 | request: &default_request 24 | path: /echoQueryParams 25 | method: get 26 | query_params: 27 | - name: param1 28 | value: value2 29 | response: &default_response 30 | json_data: 31 | - path: $ 32 | value: 33 | param1: value2 34 | 35 | - name: get query params again 36 | request: *default_request 37 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/aftereach/aftereach.module.async.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After each module async failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_each: 9 | run_type: module 10 | module: 11 | function_name: afterEachAsyncError 12 | module_path: modules/after_each.js 13 | specs: 14 | - name: get query params 15 | request: &default_request 16 | path: /echoQueryParams 17 | method: get 18 | query_params: 19 | - name: param1 20 | value: value2 21 | response: &default_response 22 | json_data: 23 | - path: $ 24 | value: 25 | param1: value2 26 | 27 | - name: get query params again 28 | request: *default_request 29 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/aftereach/aftereach.module.async.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After each module async success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_each: 9 | run_type: module 10 | module: 11 | function_name: afterEachAsyncSuccess 12 | module_path: modules/after_each.js 13 | specs: 14 | - name: get query params 15 | request: &default_request 16 | path: /echoQueryParams 17 | method: get 18 | query_params: 19 | - name: param1 20 | value: value2 21 | response: &default_response 22 | json_data: 23 | - path: $ 24 | value: 25 | param1: value2 26 | 27 | - name: get query params again 28 | request: *default_request 29 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/aftereach/aftereach.module.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After each module sync failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_each: 9 | run_type: module 10 | module: 11 | function_name: afterEachAsyncError 12 | module_path: modules/after_each.js 13 | specs: 14 | - name: get query params 15 | request: &default_request 16 | path: /echoQueryParams 17 | method: get 18 | query_params: 19 | - name: param1 20 | value: value2 21 | response: &default_response 22 | json_data: 23 | - path: $ 24 | value: 25 | param1: value2 26 | 27 | - name: get query params again 28 | request: *default_request 29 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/aftereach/aftereach.module.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After each inline sync success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | after_each: 9 | run_type: module 10 | module: 11 | function_name: afterEachSyncSuccess 12 | module_path: modules/after_each.js 13 | specs: 14 | - name: get query params 15 | request: &default_request 16 | path: /echoQueryParams 17 | method: get 18 | query_params: 19 | - name: param1 20 | value: value2 21 | response: &default_response 22 | json_data: 23 | - path: $ 24 | value: 25 | param1: value2 26 | 27 | - name: get query params again 28 | request: *default_request 29 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/aftertest.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: After test suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: after test hook inline sync funtion 9 | after_test: 10 | run_type: inline 11 | inline: 12 | function: !!js/function > 13 | function() { 14 | var keys = Object.keys(this); 15 | if (keys.length !== 5) 16 | throw new Error("after test context doesn't have expected keys"); 17 | 18 | var body = JSON.parse(this.response.body); 19 | if (body.param1 !== 'value2') 20 | throw new Error('unexpected response'); 21 | } 22 | request: &default_request 23 | path: /echoQueryParams 24 | method: get 25 | query_params: 26 | - name: param1 27 | value: value2 28 | response: &default_response 29 | json_data: 30 | - path: $ 31 | value: 32 | param1: value2 33 | 34 | - name: after test hook inline async funtion 35 | after_test: 36 | run_type: inline 37 | inline: 38 | function: !js/asyncFunction > 39 | function() { 40 | var body = JSON.parse(this.response.body); 41 | if (body.param1 !== 'value2') 42 | throw new Error('unexpected response'); 43 | } 44 | request: *default_request 45 | response: *default_response 46 | 47 | - name: after test hook module sync funtion 48 | after_test: 49 | run_type: module 50 | module: 51 | module_path: modules/after_test.js 52 | function_name: afterTestSyncSuccess 53 | request: *default_request 54 | response: *default_response 55 | 56 | - name: after test hook module async funtion 57 | after_test: 58 | run_type: module 59 | module: 60 | module_path: modules/after_test.js 61 | function_name: afterTestAsyncSuccess 62 | request: *default_request 63 | response: *default_response 64 | 65 | - name: after test hook inline sync funtion throws error - should fail 66 | after_test: 67 | run_type: inline 68 | inline: 69 | function: !!js/function > 70 | function() { 71 | var body = JSON.parse(this.response.body); 72 | if (body.param1 !== 'value2') 73 | throw new Error('unexpected response'); 74 | throw new Error('error thrown in after test hook'); 75 | } 76 | request: *default_request 77 | response: *default_response 78 | 79 | - name: after test hook inline async funtion throws error - should fail 80 | after_test: 81 | run_type: inline 82 | inline: 83 | function: !js/asyncFunction > 84 | function() { 85 | var body = JSON.parse(this.response.body); 86 | if (body.param1 !== 'value2') 87 | throw new Error('unexpected response'); 88 | throw new Error('error thrown in after test hook'); 89 | } 90 | request: *default_request 91 | response: *default_response 92 | 93 | - name: after test hook module sync funtion throws error - should fail 94 | after_test: 95 | run_type: module 96 | module: 97 | module_path: modules/after_test.js 98 | function_name: afterTestSyncError 99 | request: *default_request 100 | response: *default_response 101 | 102 | - name: after test hook module async funtion throws error - should fail 103 | after_test: 104 | run_type: module 105 | module: 106 | module_path: modules/after_test.js 107 | function_name: afterTestAsyncError 108 | request: *default_request 109 | response: *default_response 110 | 111 | - name: after test hook module async funtion rejected promise - should fail 112 | after_test: 113 | run_type: module 114 | module: 115 | module_path: modules/after_test.js 116 | function_name: afterTestAsyncRejectedPromise 117 | request: *default_request 118 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeall/beforeall.inline.async.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before all inline async failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_all: 9 | run_type: inline 10 | inline: 11 | function: !js/asyncFunction > 12 | async function() { 13 | throw new Error("error from before all"); 14 | } 15 | specs: 16 | - name: get home 17 | request: &default_request 18 | path: / 19 | method: get 20 | response: &default_response 21 | status_code: 200 22 | -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeall/beforeall.inline.async.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before all inline async success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_all: 9 | run_type: inline 10 | inline: 11 | function: !js/asyncFunction > 12 | async function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 3) 15 | throw new Error("before all context doesn't have expected keys"); 16 | } 17 | specs: 18 | - name: get home 19 | request: &default_request 20 | path: / 21 | method: get 22 | response: &default_response 23 | status_code: 200 24 | -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeall/beforeall.inline.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before all inline failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_all: 9 | run_type: inline 10 | inline: 11 | function: !!js/function > 12 | function() { 13 | throw new Error('error from before all'); 14 | } 15 | specs: 16 | - name: get home 17 | request: &default_request 18 | path: / 19 | method: get 20 | response: &default_response 21 | status_code: 200 22 | -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeall/beforeall.inline.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before all inline success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_all: 9 | run_type: inline 10 | inline: 11 | function: !!js/function > 12 | function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 3) 15 | throw new Error("before all context doesn't have expected keys"); 16 | } 17 | specs: 18 | - name: get home 19 | request: &default_request 20 | path: / 21 | method: get 22 | response: &default_response 23 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeeach/beforeeach.inline.async.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before each inline async failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_each: 9 | run_type: inline 10 | inline: 11 | function: !js/asyncFunction > 12 | async function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 4) 15 | throw new Error("before each context doesn't have expected keys"); 16 | 17 | this.test.query_params = { param1: 'value2' }; 18 | throw new Error('error thrown in before each hook'); 19 | } 20 | specs: 21 | - name: get query params 22 | request: &default_request 23 | path: /echoQueryParams 24 | method: get 25 | response: &default_response 26 | json_data: 27 | - path: $ 28 | value: 29 | param1: value2 30 | 31 | - name: get query params again 32 | request: *default_request 33 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeeach/beforeeach.inline.async.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before each inline async success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_each: 9 | run_type: inline 10 | inline: 11 | function: !js/asyncFunction > 12 | async function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 4) 15 | throw new Error("before each context doesn't have expected keys"); 16 | 17 | this.test.query_params = { param1: 'value2' }; 18 | } 19 | specs: 20 | - name: get query params 21 | request: &default_request 22 | path: /echoQueryParams 23 | method: get 24 | response: &default_response 25 | json_data: 26 | - path: $ 27 | value: 28 | param1: value2 29 | 30 | - name: get query params again 31 | request: *default_request 32 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeeach/beforeeach.inline.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before each inline failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_each: 9 | run_type: inline 10 | inline: 11 | function: !!js/function > 12 | function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 4) 15 | throw new Error("before each context doesn't have expected keys"); 16 | 17 | this.test.query_params = { param1: 'value2' }; 18 | throw new Error('error thrown in before each hook'); 19 | } 20 | specs: 21 | - name: get query params 22 | request: &default_request 23 | path: /echoQueryParams 24 | method: get 25 | response: &default_response 26 | json_data: 27 | - path: $ 28 | value: 29 | param1: value2 30 | 31 | - name: get query params again 32 | request: *default_request 33 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeeach/beforeeach.inline.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before each inline success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_each: 9 | run_type: inline 10 | inline: 11 | function: !!js/function > 12 | function() { 13 | var keys = Object.keys(this); 14 | if (keys.length !== 4) 15 | throw new Error("before each context doesn't have expected keys"); 16 | 17 | this.test.query_params = { param1: 'value2' }; 18 | } 19 | specs: 20 | - name: get query params 21 | request: &default_request 22 | path: /echoQueryParams 23 | method: get 24 | response: &default_response 25 | json_data: 26 | - path: $ 27 | value: 28 | param1: value2 29 | 30 | - name: get query params again 31 | request: *default_request 32 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeeach/beforeeach.module.async.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before each inline async failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_each: 9 | run_type: module 10 | module: 11 | function_name: beforeEachAsyncError 12 | module_path: modules/before_each.js 13 | specs: 14 | - name: get query params 15 | request: &default_request 16 | path: /echoQueryParams 17 | method: get 18 | response: &default_response 19 | json_data: 20 | - path: $ 21 | value: 22 | param1: value2 23 | 24 | - name: get query params again 25 | request: *default_request 26 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeeach/beforeeach.module.async.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before each inline async success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_each: 9 | run_type: module 10 | module: 11 | function_name: beforeEachAsyncSuccess 12 | module_path: modules/before_each.js 13 | specs: 14 | - name: get query params 15 | request: &default_request 16 | path: /echoQueryParams 17 | method: get 18 | response: &default_response 19 | json_data: 20 | - path: $ 21 | value: 22 | param1: value2 23 | 24 | - name: get query params again 25 | request: *default_request 26 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeeach/beforeeach.module.failure.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before each inline failure suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_each: 9 | run_type: module 10 | module: 11 | function_name: beforeEachSyncError 12 | module_path: modules/before_each.js 13 | specs: 14 | - name: get query params 15 | request: &default_request 16 | path: /echoQueryParams 17 | method: get 18 | response: &default_response 19 | json_data: 20 | - path: $ 21 | value: 22 | param1: value2 23 | 24 | - name: get query params again 25 | request: *default_request 26 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforeeach/beforeeach.module.success.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before each inline success suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | hooks: 8 | before_each: 9 | run_type: module 10 | module: 11 | function_name: beforeEachSyncSuccess 12 | module_path: modules/before_each.js 13 | specs: 14 | - name: get query params 15 | request: &default_request 16 | path: /echoQueryParams 17 | method: get 18 | response: &default_response 19 | json_data: 20 | - path: $ 21 | value: 22 | param1: value2 23 | 24 | - name: get query params again 25 | request: *default_request 26 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/hooks/beforetest.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Before test suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: before test hook inline sync funtion 9 | before_test: 10 | run_type: inline 11 | inline: 12 | function: !!js/function > 13 | function() { 14 | var keys = Object.keys(this); 15 | if (keys.length !== 4) 16 | throw new Error("before test context doesn't have expected keys"); 17 | 18 | this.test.query_params = { param1: 'value2' }; 19 | } 20 | request: &default_request 21 | path: /echoQueryParams 22 | method: get 23 | response: &default_response 24 | json_data: 25 | - path: $ 26 | value: 27 | param1: value2 28 | 29 | - name: before test hook inline async funtion 30 | before_test: 31 | run_type: inline 32 | inline: 33 | function: !js/asyncFunction > 34 | function() { 35 | this.test.query_params = { param1: 'value2' }; 36 | } 37 | request: *default_request 38 | response: *default_response 39 | 40 | - name: before test hook module sync funtion 41 | before_test: 42 | run_type: module 43 | module: 44 | module_path: modules/before_test.js 45 | function_name: beforeTestSyncSuccess 46 | request: *default_request 47 | response: *default_response 48 | 49 | - name: before test hook module async funtion 50 | before_test: 51 | run_type: module 52 | module: 53 | module_path: modules/before_test.js 54 | function_name: beforeTestAsyncSuccess 55 | request: *default_request 56 | response: *default_response 57 | 58 | - name: before test hook inline sync funtion throws error - should fail 59 | before_test: 60 | run_type: inline 61 | inline: 62 | function: !!js/function > 63 | function() { 64 | this.test.query_params = { param1: 'value2' }; 65 | throw new Error('error thrown in before test hook'); 66 | } 67 | request: *default_request 68 | response: *default_response 69 | 70 | - name: before test hook inline async funtion throws error - should fail 71 | before_test: 72 | run_type: inline 73 | inline: 74 | function: !js/asyncFunction > 75 | function() { 76 | this.test.query_params = { param1: 'value2' }; 77 | throw new Error('error thrown in before test hook'); 78 | } 79 | request: *default_request 80 | response: *default_response 81 | 82 | - name: before test hook module sync funtion throws error - should fail 83 | before_test: 84 | run_type: module 85 | module: 86 | module_path: modules/before_test.js 87 | function_name: beforeTestSyncError 88 | request: *default_request 89 | response: *default_response 90 | 91 | - name: before test hook module async funtion throws error - should fail 92 | before_test: 93 | run_type: module 94 | module: 95 | module_path: modules/before_test.js 96 | function_name: beforeTestAsyncError 97 | request: *default_request 98 | response: *default_response 99 | 100 | - name: before test hook module async funtion rejected promise - should fail 101 | before_test: 102 | run_type: module 103 | module: 104 | module_path: modules/before_test.js 105 | function_name: beforeTestAsyncRejectedPromise 106 | request: *default_request 107 | response: *default_response -------------------------------------------------------------------------------- /test/cli/src/suites/https.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: HTTPS suite 3 | configuration: 4 | scheme: https 5 | host: google.com 6 | specs: 7 | - name: get google https 8 | request: 9 | path: / 10 | method: get 11 | response: 12 | status_code: 200 13 | -------------------------------------------------------------------------------- /test/cli/src/suites/jsondata.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: verifying JSON data suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: validate json response with json data functionality 9 | request: &default_request 10 | path: /echoJSONBodyResponse 11 | method: post 12 | headers: 13 | - name: content-type 14 | value: application/json 15 | payload: 16 | body: 17 | type: json 18 | content: &default_json_content 19 | key1: value1 20 | key2: value2 21 | keyn: 4 22 | keyBoolean: false 23 | keyNull: null 24 | response: 25 | json_data: 26 | - path: $.key2 27 | value: value2 28 | - path: $.keyBoolean 29 | value: false 30 | - path: $.keyNull 31 | value: null 32 | 33 | - name: validate json response with json data functionality - should fail 34 | request: *default_request 35 | response: 36 | json_data: 37 | - path: $.key2 38 | value: wrongvalue 39 | 40 | - name: validate json response with json data functionality regex 41 | request: *default_request 42 | response: 43 | json_data: 44 | - path: $.key2 45 | value: !!js/regexp /value(\d)/ 46 | 47 | - name: should fail when json data regex does not match the value 48 | request: *default_request 49 | response: 50 | json_data: 51 | - path: $.key2 52 | value: !!js/regexp /valuex(\d)/ 53 | 54 | - name: validate json response with multiple json data expectations 55 | request: *default_request 56 | response: 57 | json_data: 58 | - path: $.key2 59 | value: !!js/regexp /value(\d)/ 60 | - path: $.key1 61 | value: value1 62 | - path: $.keyn 63 | value: 4 64 | 65 | - name: validate json response with json data value as object 66 | request: *default_request 67 | response: 68 | json_data: 69 | - path: $ 70 | value: *default_json_content 71 | 72 | - name: validate json response with json data value as non matching object - should fail 73 | request: *default_request 74 | response: 75 | json_data: 76 | - path: $ 77 | value: 78 | <<: *default_json_content 79 | key2: value3 80 | 81 | - name: validate json response with json data value as Array 82 | request: &array_json_request 83 | path: /echoJSONBodyResponse 84 | method: post 85 | headers: 86 | - name: content-type 87 | value: application/json 88 | payload: 89 | body: 90 | type: json 91 | content: &array_json_content 92 | - item1 93 | - item2 94 | response: 95 | json_data: 96 | - path: $ 97 | value: *array_json_content 98 | 99 | - name: validate json response with json data value as non matching Array - should fail 100 | request: *array_json_request 101 | response: 102 | json_data: 103 | - path: $ 104 | value: 105 | - item1 106 | - item2 107 | - item3 108 | -------------------------------------------------------------------------------- /test/cli/src/suites/jsonschema.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Response JSON schema validation suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: read json schema from file and validate response 9 | request: &default_request 10 | path: /echoJSONBodyResponse 11 | method: post 12 | headers: 13 | - name: content-type 14 | value: application/json 15 | payload: 16 | body: 17 | type: json 18 | content: &default_json_content 19 | key: value 20 | response: 21 | json_schema: 22 | type: file 23 | $ref: static/schema/simple_valid.json 24 | 25 | - name: read json schema from file and validate response - should fail 26 | request: *default_request 27 | response: 28 | json_schema: 29 | type: file 30 | $ref: static/schema/simple_invalid.json 31 | 32 | - name: read json schema from non existant file and validate response - should fail 33 | request: *default_request 34 | response: 35 | json_schema: 36 | type: file 37 | $ref: static/schema/doesnotexist.json 38 | 39 | - name: read inline json schema and validate response 40 | request: *default_request 41 | response: 42 | json_schema: 43 | type: inline 44 | $ref: > 45 | { 46 | "$id": "http://example.com/example.json", 47 | "type": "object", 48 | "$schema": "http://json-schema.org/draft-06/schema#", 49 | "properties": { 50 | "key": { 51 | "$id": "/properties/key", 52 | "type": "string" 53 | } 54 | } 55 | } 56 | 57 | - name: read inline invalid json schema and validate response - should fail 58 | request: *default_request 59 | response: 60 | json_schema: 61 | type: inline 62 | $ref: > 63 | { 64 | "$id": "http://example.com/example.json", 65 | "type": "object", 66 | "$schema": "http://json-schema.org/draft-06/schema#", 67 | "properties": { 68 | "key": { 69 | "$id": "/properties/key", 70 | "type": "number" 71 | } 72 | } 73 | } 74 | 75 | - name: read junk json schema from file and validate response - should fail 76 | request: *default_request 77 | response: 78 | json_schema: 79 | type: file 80 | $ref: static/schema/junk_simple_valid.json 81 | 82 | - name: invalid input schema - should fail 83 | request: *default_request 84 | response: 85 | json_schema: 86 | type: inline 87 | $ref: > 88 | { 89 | ladjfj"$id": "http://example.com/example.json", 90 | "type": "object", 91 | "$schema": "http://json-schema.org/draft-06/schema#", 92 | "properties": { 93 | "key": { 94 | "$id": "/properties/key", 95 | "type": "string" 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /test/cli/src/suites/loop.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: loop suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: static loop test 9 | loop: 10 | type: static 11 | static: 12 | - a 13 | - b 14 | before_test: &beforeTestHook 15 | run_type: inline 16 | inline: 17 | function: !!js/function > 18 | function() { 19 | this.test.query_params = { param : this.loopItem }; 20 | } 21 | request: &request 22 | path: /echoQueryParams 23 | method: get 24 | response: &response 25 | status_code: 200 26 | custom_validator: 27 | run_type: inline 28 | inline: 29 | function: !!js/function > 30 | function() { 31 | var body = JSON.parse(this.response.body); 32 | 33 | if (body.param !== this.loopItem) 34 | throw new Error('body does not have the expected param value'); 35 | } 36 | 37 | - name: loop continues despite iteration failure - should fail one in loop 38 | loop: 39 | type: static 40 | static: 41 | - a 42 | - b 43 | before_test: *beforeTestHook 44 | request: *request 45 | response: 46 | status_code: 200 47 | custom_validator: 48 | run_type: inline 49 | inline: 50 | function: !!js/function > 51 | function() { 52 | var body = JSON.parse(this.response.body); 53 | 54 | if (body.param === 'a') 55 | throw new Error('failing loop spec on an iteration'); 56 | } 57 | 58 | - name: dynamic inline sync loop test 59 | loop: 60 | type: dynamic 61 | dynamic: 62 | run_type: inline 63 | inline: 64 | function: !!js/function > 65 | function() { 66 | return ['a', 'b']; 67 | } 68 | before_test: *beforeTestHook 69 | request: *request 70 | response: *response 71 | 72 | - name: dynamic inline async loop test 73 | loop: 74 | type: dynamic 75 | dynamic: 76 | run_type: inline 77 | inline: 78 | function: !js/asyncFunction > 79 | async function() { 80 | var promise = await new Promise(function(resolve, reject) { setTimeout(function(){ resolve(['a', 'b']) }, 3)}) 81 | return promise; 82 | } 83 | before_test: *beforeTestHook 84 | request: *request 85 | response: *response 86 | 87 | - name: dynamic module sync loop test 88 | loop: 89 | type: dynamic 90 | dynamic: 91 | run_type: module 92 | module: 93 | module_path: modules/loop.js 94 | function_name: loopSyncSuccess 95 | before_test: *beforeTestHook 96 | request: *request 97 | response: *response 98 | 99 | - name: dynamic module async loop test 100 | loop: 101 | type: dynamic 102 | dynamic: 103 | run_type: module 104 | module: 105 | module_path: modules/loop.js 106 | function_name: loopAsyncSuccess 107 | before_test: *beforeTestHook 108 | request: *request 109 | response: *response 110 | 111 | - name: loop function failure - should fail 112 | loop: 113 | type: dynamic 114 | dynamic: 115 | run_type: inline 116 | inline: 117 | function: !!js/function > 118 | function() { 119 | throw new Error('error thrown from loop items builder function'); 120 | } 121 | before_test: *beforeTestHook 122 | request: *request 123 | response: *response -------------------------------------------------------------------------------- /test/cli/src/suites/otherverbs.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: POST raw body requests (json , text, binary ) 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: put json data as body 9 | request: &default_request 10 | path: /echoJSONBodyResponsePut 11 | method: put 12 | headers: 13 | - name: content-type 14 | value: application/json 15 | payload: 16 | body: 17 | type: json 18 | content: &default_json_content 19 | key1: value1 20 | key2: value2 21 | response: 22 | status_code: 200 23 | json_data: 24 | - path: $ 25 | value: *default_json_content 26 | 27 | - name: patch json data as body 28 | request: 29 | path: /echoJSONBodyResponsePatch 30 | method: patch 31 | headers: 32 | - name: content-type 33 | value: application/json 34 | payload: 35 | body: 36 | type: json 37 | content: *default_json_content 38 | response: 39 | status_code: 200 40 | json_data: 41 | - path: $ 42 | value: *default_json_content 43 | 44 | - name: delete item 45 | request: 46 | path: /echoDeleteQueryParams 47 | method: delete 48 | query_params: &query_params 49 | - name: p1 50 | value: v1 51 | response: 52 | status_code: 200 53 | json_data: 54 | - path: $ 55 | value: 56 | p1: v1 57 | 58 | - name: HEAD method 59 | request: 60 | path: /posts 61 | method: head 62 | response: 63 | status_code: 200 64 | headers: 65 | - name: content-type 66 | value: !!js/regexp application/json 67 | 68 | - name: options method 69 | request: 70 | path: /posts 71 | method: options 72 | response: 73 | status_code: 204 74 | headers: 75 | - name: Access-Control-Allow-Methods 76 | value: "GET,HEAD,PUT,PATCH,POST,DELETE" -------------------------------------------------------------------------------- /test/cli/src/suites/params.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Params suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: static query params in request 9 | request: 10 | path: /echoQueryParams 11 | method: get 12 | query_params: 13 | - name: param1 14 | value: value1 15 | response: &default_response 16 | status_code: 200 17 | json_data: 18 | - path: $ 19 | value: 20 | param1: value1 21 | 22 | - name: multiple static query params in request 23 | request: 24 | path: /echoQueryParams 25 | method: get 26 | query_params: 27 | - name: param1 28 | value: value1 29 | - name: param2 30 | value: value2 31 | response: 32 | status_code: 200 33 | json_data: 34 | - path: $ 35 | value: 36 | param1: value1 37 | param2: value2 38 | 39 | - name: query params added to test context 40 | before_test: 41 | run_type: inline 42 | inline: 43 | function: !!js/function > 44 | function() { 45 | this.test.query_params = { param2: 'value2' }; 46 | } 47 | request: 48 | path: /echoQueryParams 49 | method: get 50 | response: 51 | status_code: 200 52 | json_data: 53 | - path: $ 54 | value: 55 | param2: value2 56 | 57 | - name: query params overidden in test context 58 | before_test: 59 | run_type: inline 60 | inline: 61 | function: !!js/function > 62 | function() { 63 | this.test.query_params = { param1: 'value2' }; 64 | } 65 | request: 66 | path: /echoQueryParams 67 | method: get 68 | query_params: 69 | - name: param1 70 | value: value1 71 | response: &default_response 72 | status_code: 200 73 | json_data: 74 | - path: $ 75 | value: 76 | param1: value2 77 | 78 | - name: static path params in request 79 | request: 80 | path: /echoPathParams/{id1} 81 | method: get 82 | path_params: 83 | - name: id1 84 | value: value1 85 | response: 86 | status_code: 200 87 | json_data: 88 | - path: $ 89 | value: 90 | - value1 91 | 92 | - name: multiple static path params in request 93 | request: 94 | path: /echoPathParams/{id1}/{id2} 95 | method: get 96 | path_params: 97 | - name: id1 98 | value: value1 99 | - name: id2 100 | value: value2 101 | response: 102 | status_code: 200 103 | json_data: 104 | - path: $ 105 | value: 106 | - value1 107 | - value2 108 | 109 | - name: path params added to test context 110 | before_test: 111 | run_type: inline 112 | inline: 113 | function: !!js/function > 114 | function() { 115 | this.test.path_params = { id1: 'value2' }; 116 | } 117 | request: 118 | path: /echoPathParams/{id1} 119 | method: get 120 | response: 121 | status_code: 200 122 | json_data: 123 | - path: $ 124 | value: 125 | - value2 126 | 127 | - name: path params overidden in test context 128 | before_test: 129 | run_type: inline 130 | inline: 131 | function: !!js/function > 132 | function() { 133 | this.test.path_params = { id1: 'value2' }; 134 | } 135 | request: 136 | path: /echoPathParams/{id1} 137 | method: get 138 | path_params: 139 | - name: id1 140 | value: value1 141 | response: &default_response 142 | status_code: 200 143 | json_data: 144 | - path: $ 145 | value: 146 | - value2 -------------------------------------------------------------------------------- /test/cli/src/suites/postrawbody.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: POST raw body requests (json , text, binary ) 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: post json data as body 9 | request: &default_request 10 | path: /echoJSONBodyResponse 11 | method: post 12 | headers: 13 | - name: content-type 14 | value: application/json 15 | payload: 16 | body: 17 | type: json 18 | content: &default_json_content 19 | key1: value1 20 | key2: value2 21 | keyn: 4 22 | response: 23 | status_code: 200 24 | json_data: 25 | - path: $ 26 | value: *default_json_content 27 | 28 | - name: post text data as json body 29 | request: &default_request 30 | path: /echoJSONBodyResponse 31 | method: post 32 | headers: 33 | - name: content-type 34 | value: application/json 35 | payload: 36 | body: 37 | type: json 38 | content: {"a": "b"} 39 | response: 40 | status_code: 200 41 | json_data: 42 | - path: $ 43 | value: 44 | a: b 45 | 46 | - name: post json data as body without header - should fail 47 | request: 48 | path: /echoJSONBodyResponse 49 | method: post 50 | payload: 51 | body: 52 | type: json 53 | content: 54 | key1: value1 55 | response: 56 | status_code: 200 57 | json_data: 58 | - path: $ 59 | value: 60 | key1: value1 61 | 62 | - name: post text data as body 63 | request: 64 | path: /echoNonFormBodyTextResponse 65 | method: post 66 | headers: 67 | - name: content-type 68 | value: text/plain 69 | payload: 70 | body: 71 | type: text 72 | content: textbody 73 | response: 74 | status_code: 200 75 | custom_validator: 76 | run_type: inline 77 | inline: 78 | function: !!js/function > 79 | function() { 80 | if (this.response.body !== 'textbody') { 81 | throw new Error("Response body not equals 'textbody'"); 82 | } 83 | } 84 | 85 | - name: post text data as body with wrong content - should fail 86 | request: 87 | path: /echoNonFormBodyTextResponse 88 | method: post 89 | headers: 90 | - name: content-type 91 | value: application/json 92 | payload: 93 | body: 94 | type: text 95 | content: 96 | - item1 97 | response: 98 | status_code: 200 99 | 100 | - name: post binary data (file) as body 101 | request: 102 | path: /echoBinaryBodyResponseStats 103 | method: post 104 | headers: 105 | - name: content-type 106 | value: image/png 107 | payload: 108 | body: 109 | type: binary 110 | content: static/assets/logo.png 111 | response: 112 | status_code: 200 113 | json_data: 114 | - path: $.request_content_size 115 | value: 12371 116 | 117 | - name: post binary data (non existant file) as body - should fail 118 | request: 119 | path: /echoBinaryBodyResponseStats 120 | method: post 121 | headers: 122 | - name: content-type 123 | value: image/png 124 | payload: 125 | body: 126 | type: binary 127 | content: static/assets/doesnotexist.png 128 | response: 129 | status_code: 200 130 | 131 | - name: post binary data (directory path) as body - should fail 132 | request: 133 | path: /echoBinaryBodyResponseStats 134 | method: post 135 | headers: 136 | - name: content-type 137 | value: image/png 138 | payload: 139 | body: 140 | type: binary 141 | content: static/assets 142 | response: 143 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/retry.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Retry Suite 3 | enabled: true 4 | configuration: 5 | scheme: http 6 | host: 127.0.0.1 7 | port: 3027 8 | specs: 9 | - name: retry returns success after 2 attempts 10 | before_test: 11 | run_type: inline 12 | inline: 13 | function: !!js/function > 14 | function() { 15 | this.test.path_params = { id: 'success' + new Date().getTime() }; 16 | } 17 | request: 18 | path: /retry/{id} 19 | method: get 20 | retry: 21 | count: 3 22 | wait_before_each: 10 23 | response: 24 | status_code: 200 25 | 26 | - name: retry fails - should fail 27 | before_test: 28 | run_type: inline 29 | inline: 30 | function: !!js/function > 31 | function() { 32 | this.test.path_params = { id: new Date().getTime() }; 33 | } 34 | request: 35 | path: /retry/{id} 36 | method: get 37 | retry: 38 | count: 3 39 | wait_before_each: 10 40 | response: 41 | status_code: 200 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /test/cli/src/suites/smoke.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Smoke suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: get index html 9 | request: 10 | path: / 11 | method: get 12 | response: 13 | status_code: 200 14 | -------------------------------------------------------------------------------- /test/cli/src/suites/smoke2.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Smoke suite 2 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: get index html 9 | request: 10 | path: / 11 | method: get 12 | response: 13 | status_code: 200 14 | -------------------------------------------------------------------------------- /test/cli/src/suites/statuscode.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Status code suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: correct response code 9 | request: &default_request 10 | path: / 11 | method: get 12 | response: 13 | status_code: 200 14 | 15 | - name: incorrect response code - should fail 16 | request: *default_request 17 | response: 18 | status_code: 400 -------------------------------------------------------------------------------- /test/cli/src/suites/suite.relative.paths.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: File searching with relative paths 3 | locate_files_relative: true 4 | configuration: 5 | host: 127.0.0.1 6 | custom_configuration: 7 | run_type: module 8 | module: 9 | module_path: ./../modules/suite_configuration.js 10 | function_name: syncSuiteConfig 11 | specs: 12 | - name: post multipart form data single file with relative path and field 13 | request: 14 | path: /echoMultipartBodySingleFileStats 15 | method: post 16 | headers: 17 | - name: content-type 18 | value: multipart/form-data 19 | payload: 20 | form_data: 21 | - name: file_name 22 | content: ./../static/assets/logo.png 23 | type: file 24 | - name: field1 25 | content: value1 26 | type: text 27 | response: 28 | status_code: 200 29 | json_data: 30 | - path: $.file.size 31 | value: 12371 32 | - path: $.file.originalname 33 | value: logo.png 34 | - path: $.fields 35 | value: 36 | field1: value1 37 | 38 | - name: post binary data (file) as body 39 | request: 40 | path: /echoBinaryBodyResponseStats 41 | method: post 42 | headers: 43 | - name: content-type 44 | value: image/png 45 | payload: 46 | body: 47 | type: binary 48 | content: ./../static/assets/logo.png 49 | response: 50 | status_code: 200 51 | json_data: 52 | - path: $.request_content_size 53 | value: 12371 54 | 55 | - name: post non existent binary data (file) as body - should fail 56 | request: 57 | path: /echoBinaryBodyResponseStats 58 | method: post 59 | headers: 60 | - name: content-type 61 | value: image/png 62 | payload: 63 | body: 64 | type: binary 65 | content: ./../static/assets/logononexistent.png 66 | response: 67 | status_code: 200 68 | - name: post non existent relative file path binary data (file) as body - should fail 69 | request: 70 | path: /echoBinaryBodyResponseStats 71 | method: post 72 | headers: 73 | - name: content-type 74 | value: image/png 75 | payload: 76 | body: 77 | type: binary 78 | content: static/assets/logo.png 79 | response: 80 | status_code: 200 81 | - name: before test hook module relative path 82 | before_test: 83 | run_type: module 84 | module: 85 | module_path: ./../modules/before_test.js 86 | function_name: beforeTestSyncSuccess 87 | request: 88 | path: /echoQueryParams 89 | method: get 90 | response: 91 | json_data: 92 | - path: $ 93 | value: 94 | param1: value2 95 | - name: read json schema from file and validate response 96 | request: 97 | path: /echoJSONBodyResponse 98 | method: post 99 | headers: 100 | - name: content-type 101 | value: application/json 102 | payload: 103 | body: 104 | type: json 105 | content: 106 | key: value 107 | response: 108 | json_schema: 109 | type: file 110 | $ref: ./../static/schema/simple_valid.json -------------------------------------------------------------------------------- /test/cli/src/suites/suiteconfig/inline.async.error.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: suite config inline async throws error 3 | configuration: 4 | host: 127.0.0.1 5 | custom_configuration: 6 | run_type: inline 7 | inline: 8 | function: !js/asyncFunction > 9 | async function() { 10 | this.scheme = 'http'; 11 | throw new Error('error thrown from suite custom configuration'); 12 | this.port = 3027; 13 | } 14 | specs: 15 | - name: basic request 16 | request: 17 | path: /echoHeaders 18 | method: get 19 | response: 20 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/suiteconfig/inline.async.invalidconfig.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: suite config inline async has invalid config 3 | configuration: 4 | host: 127.0.0.1 5 | custom_configuration: 6 | run_type: inline 7 | inline: 8 | function: !js/asyncFunction > 9 | async function() { 10 | this.port = 3027; 11 | } 12 | specs: 13 | - name: basic request 14 | request: 15 | path: /echoHeaders 16 | method: get 17 | response: 18 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/suiteconfig/inline.async.rejectedpromise.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: suite config inline async rejects promise 3 | configuration: 4 | host: 127.0.0.1 5 | custom_configuration: 6 | run_type: inline 7 | inline: 8 | function: !js/asyncFunction > 9 | async function() { 10 | this.scheme = 'http'; 11 | var result = await new Promise(function(resolve, reject){ 12 | setTimeout(function() { reject('abc') }, 1); 13 | }); 14 | this.port = 3027; 15 | } 16 | specs: 17 | - name: basic request 18 | request: 19 | path: /echoHeaders 20 | method: get 21 | response: 22 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/suiteconfig/inline.async.valid.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: suite config inline async valid 3 | configuration: 4 | host: 127.0.0.1 5 | custom_configuration: 6 | run_type: inline 7 | inline: 8 | function: !js/asyncFunction > 9 | async function() { 10 | this.scheme = 'http'; 11 | this.port = 3027; 12 | } 13 | specs: 14 | - name: basic request 15 | request: 16 | path: /echoHeaders 17 | method: get 18 | response: 19 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/suiteconfig/inline.sync.error.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: suite config inline sync throws error 3 | configuration: 4 | host: 127.0.0.1 5 | custom_configuration: 6 | run_type: inline 7 | inline: 8 | function: !!js/function > 9 | function() { 10 | this.scheme = 'http'; 11 | throw new Error('error thrown from suite custom configuration'); 12 | this.port = 3027; 13 | } 14 | specs: 15 | - name: basic request 16 | request: 17 | path: /echoHeaders 18 | method: get 19 | response: 20 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/suiteconfig/inline.sync.invalidconfig.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: suite config inline sync has invalid config 3 | configuration: 4 | host: 127.0.0.1 5 | custom_configuration: 6 | run_type: inline 7 | inline: 8 | function: !!js/function > 9 | function() { 10 | this.port = 3027; 11 | } 12 | specs: 13 | - name: basic request 14 | request: 15 | path: /echoHeaders 16 | method: get 17 | response: 18 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/suiteconfig/inline.sync.valid.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: suite config inline sync valid 3 | configuration: 4 | host: 127.0.0.1 5 | custom_configuration: 6 | run_type: inline 7 | inline: 8 | function: !!js/function > 9 | function() { 10 | this.scheme = 'http'; 11 | this.port = 3027; 12 | } 13 | specs: 14 | - name: basic request 15 | request: 16 | path: /echoHeaders 17 | method: get 18 | response: 19 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/suitedependencies/dep.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: dependency suite 3 | locate_files_relative: true 4 | configuration: 5 | scheme: http 6 | host: 127.0.0.1 7 | port: 3027 8 | specs: 9 | - name: dep disabled 10 | enabled: false 11 | request: 12 | path: /echoQueryParams 13 | method: get 14 | query_params: 15 | - name: q 16 | value: interdepvalue 17 | response: 18 | status_code: 400 19 | 20 | - name: dep enabled 21 | request: 22 | path: /echoQueryParams 23 | method: get 24 | query_params: 25 | - name: q 26 | value: interdepvalue_from_enabled 27 | response: 28 | status_code: 200 29 | 30 | - name: post binary data file 31 | request: 32 | path: /echoBinaryBodyResponseStats 33 | method: post 34 | headers: 35 | - name: content-type 36 | value: image/png 37 | payload: 38 | body: 39 | type: binary 40 | content: ./../../static/assets/logo.png 41 | response: 42 | status_code: 200 43 | json_data: 44 | - path: $.request_content_size 45 | value: 12371 -------------------------------------------------------------------------------- /test/cli/src/suites/suitedependencies/intersuitedeps.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Status code suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | spec_dependencies: 8 | - suites/suitedependencies/dep.suite.yml 9 | specs: 10 | - name: beforetest hook inter-dependent 11 | before_test: 12 | run_type: inline 13 | inline: 14 | function: !js/asyncFunction > 15 | async function() { 16 | var response = await this.runSpec('dep disabled'); 17 | var prevQueryParams = JSON.parse(response.body); 18 | this.test.query_params = { k: prevQueryParams.q }; 19 | } 20 | request: 21 | path: /echoQueryParams 22 | method: get 23 | response: 24 | status_code: 200 25 | json_data: 26 | - path: $.k 27 | value: interdepvalue 28 | 29 | - name: beforetest hook inter-dependent validate response - should fail 30 | before_test: 31 | run_type: inline 32 | inline: 33 | function: !js/asyncFunction > 34 | async function() { 35 | var response = await this.runSpec('dep disabled', { validateResponse: true }); 36 | var prevQueryParams = JSON.parse(response.body); 37 | this.test.query_params = { k: prevQueryParams.q }; 38 | } 39 | request: 40 | path: /echoQueryParams 41 | method: get 42 | response: 43 | status_code: 200 44 | json_data: 45 | - path: $.k 46 | value: interdepvalue 47 | 48 | - name: beforetest hook inter-dependent enabled 49 | before_test: 50 | run_type: inline 51 | inline: 52 | function: !js/asyncFunction > 53 | async function() { 54 | var response = await this.runSpec('dep enabled'); 55 | var prevQueryParams = JSON.parse(response.body); 56 | this.test.query_params = { k: prevQueryParams.q }; 57 | } 58 | request: 59 | path: /echoQueryParams 60 | method: get 61 | response: 62 | status_code: 200 63 | json_data: 64 | - path: $.k 65 | value: interdepvalue_from_enabled 66 | 67 | - name: beforetest hook inter-dependent error in hook - should fail 68 | before_test: 69 | run_type: inline 70 | inline: 71 | function: !js/asyncFunction > 72 | async function() { 73 | var response = await this.runSpec('dep enabled'); 74 | var prevQueryParams = JSON.parse(response.bodya); 75 | this.test.query_params = { k: prevQueryParams.q }; 76 | } 77 | request: 78 | path: /echoQueryParams 79 | method: get 80 | response: 81 | status_code: 200 82 | json_data: 83 | - path: $.k 84 | value: interdepvalue_from_enabled 85 | 86 | - name: beforetest hook inter-dependent no matching spec - should fail 87 | before_test: 88 | run_type: inline 89 | inline: 90 | function: !js/asyncFunction > 91 | async function() { 92 | var response = await this.runSpec('no spec'); 93 | var prevQueryParams = JSON.parse(response.bodya); 94 | this.test.query_params = { k: prevQueryParams.q }; 95 | } 96 | request: 97 | path: /echoQueryParams 98 | method: get 99 | response: 100 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/suitedependencies/intradependencies.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Status code suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: dep disabled 9 | enabled: false 10 | request: 11 | path: /echoQueryParams 12 | method: get 13 | query_params: 14 | - name: q 15 | value: valuefromdep 16 | response: 17 | status_code: 400 18 | 19 | - name: beforetest hook intra-dependent 20 | before_test: 21 | run_type: inline 22 | inline: 23 | function: !js/asyncFunction > 24 | async function() { 25 | var response = await this.runSpec('dep disabled'); 26 | var prevQueryParams = JSON.parse(response.body); 27 | this.test.query_params = { k: prevQueryParams.q }; 28 | } 29 | request: 30 | path: /echoQueryParams 31 | method: get 32 | response: 33 | status_code: 200 34 | json_data: 35 | - path: $.k 36 | value: valuefromdep 37 | 38 | - name: beforetest hook intra-dependent validate response - should fail 39 | before_test: 40 | run_type: inline 41 | inline: 42 | function: !js/asyncFunction > 43 | async function() { 44 | var response = await this.runSpec('dep disabled', { validateResponse: true }); 45 | var prevQueryParams = JSON.parse(response.body); 46 | this.test.query_params = { k: prevQueryParams.q }; 47 | } 48 | request: 49 | path: /echoQueryParams 50 | method: get 51 | response: 52 | status_code: 200 53 | json_data: 54 | - path: $.k 55 | value: valuefromdep 56 | 57 | - name: dep enabled 58 | request: 59 | path: /echoQueryParams 60 | method: get 61 | query_params: 62 | - name: q 63 | value: valuefromenableddep 64 | response: 65 | status_code: 200 66 | 67 | - name: beforetest hook intra-dependent enabled 68 | before_test: 69 | run_type: inline 70 | inline: 71 | function: !js/asyncFunction > 72 | async function() { 73 | var response = await this.runSpec('dep enabled'); 74 | var prevQueryParams = JSON.parse(response.body); 75 | this.test.query_params = { k: prevQueryParams.q }; 76 | } 77 | request: 78 | path: /echoQueryParams 79 | method: get 80 | response: 81 | status_code: 200 82 | json_data: 83 | - path: $.k 84 | value: valuefromenableddep 85 | 86 | - name: beforetest hook intra-dependent error in hook - should fail 87 | before_test: 88 | run_type: inline 89 | inline: 90 | function: !js/asyncFunction > 91 | async function() { 92 | var response = await this.runSpec('dep enabled'); 93 | var prevQueryParams = JSON.parse(response.bodya); 94 | this.test.query_params = { k: prevQueryParams.q }; 95 | } 96 | request: 97 | path: /echoQueryParams 98 | method: get 99 | response: 100 | status_code: 200 101 | json_data: 102 | - path: $.k 103 | value: valuefromenableddep 104 | 105 | - name: beforetest hook intra-dependent no matching spec - should fail 106 | before_test: 107 | run_type: inline 108 | inline: 109 | function: !js/asyncFunction > 110 | async function() { 111 | var response = await this.runSpec('no spec'); 112 | var prevQueryParams = JSON.parse(response.bodya); 113 | this.test.query_params = { k: prevQueryParams.q }; 114 | } 115 | request: 116 | path: /echoQueryParams 117 | method: get 118 | response: 119 | status_code: 200 -------------------------------------------------------------------------------- /test/cli/src/suites/suitedependencies/relative.intersuite.dep.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Interdep suite with relative path 3 | locate_files_relative: true 4 | configuration: 5 | scheme: http 6 | host: 127.0.0.1 7 | port: 3027 8 | spec_dependencies: 9 | - ./dep.suite.yml 10 | specs: 11 | - name: inter dependency relative path 12 | before_test: 13 | run_type: inline 14 | inline: 15 | function: !js/asyncFunction > 16 | async function() { 17 | var response = await this.runSpec('dep disabled'); 18 | var prevQueryParams = JSON.parse(response.body); 19 | this.test.query_params = { k: prevQueryParams.q }; 20 | } 21 | request: 22 | path: /echoQueryParams 23 | method: get 24 | response: 25 | status_code: 200 26 | json_data: 27 | - path: $.k 28 | value: interdepvalue 29 | - name: inter dependency relative path file upload 30 | before_test: 31 | run_type: inline 32 | inline: 33 | function: !js/asyncFunction > 34 | async function() { 35 | var response = await this.runSpec('post binary data file', { validateResponse: true }); 36 | this.test.query_params = { k: 'interdepvalue' }; 37 | } 38 | request: 39 | path: /echoQueryParams 40 | method: get 41 | response: 42 | status_code: 200 43 | json_data: 44 | - path: $.k 45 | value: interdepvalue -------------------------------------------------------------------------------- /test/cli/src/suites/suiteschema/invalidspecschema.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: Invalid spec schema suite 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: get index html 9 | requestdoesnotexist: 10 | path: / 11 | method: get 12 | response: 13 | status_code: 200 14 | -------------------------------------------------------------------------------- /test/cli/src/suites/urlencodeformpost.suite.yml: -------------------------------------------------------------------------------- 1 | meta: 2 | name: URLEncoded Form POST requests 3 | configuration: 4 | scheme: http 5 | host: 127.0.0.1 6 | port: 3027 7 | specs: 8 | - name: post form data as body 9 | request: &default_request 10 | path: /posts 11 | method: post 12 | headers: 13 | - name: content-type 14 | value: application/x-www-form-urlencoded 15 | payload: 16 | form: 17 | title: post title 18 | body: post body 19 | userId: 1 20 | response: 21 | status_code: 201 22 | json_data: 23 | - path: $.title 24 | value: post title 25 | - path: $.body 26 | value: post body 27 | - path: $.userId 28 | value: "1" 29 | - name: post form data as body without header - should fail 30 | request: 31 | path: /posts 32 | method: post 33 | payload: 34 | form: 35 | title: post title 36 | body: post body 37 | userId: 1 38 | response: 39 | status_code: 201 40 | - name: post form data as body with wrong header - should fail 41 | request: 42 | path: /posts 43 | method: post 44 | headers: 45 | - name: content-type 46 | value: application/wrongheadertype 47 | payload: 48 | form: 49 | title: post title 50 | body: post body 51 | userId: 1 52 | response: 53 | status_code: 201 -------------------------------------------------------------------------------- /test/cli/statuscode.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('status code', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('statuscode.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(1); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(1); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('correct response code', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('pass'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | it('incorrect response code - should fail', function () { 38 | let result = suiteContext.result; 39 | let test = result.tests.find(t => t.name === this.test.title); 40 | expect(test.status).to.equal('fail'); 41 | expect(test.error.name).to.equal('ResponseStatusCodeDidNotMatchError'); 42 | expect(test.error.message).to.contain('Expected status code: 400, Actual status code: 200'); 43 | }); 44 | 45 | }); -------------------------------------------------------------------------------- /test/cli/suite.relative.paths.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('Suite with relative paths', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('suite.relative.paths.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(4); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(2); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | suiteContext.result = reportData.suites[0]; 27 | }); 28 | 29 | it('post multipart form data single file with relative path and field', function () { 30 | let result = suiteContext.result; 31 | let test = result.tests.find(t => t.name === this.test.title); 32 | expect(test.status).to.equal('pass'); 33 | expect(test.error).to.be.a('null'); 34 | }); 35 | 36 | it('post binary data (file) as body', function () { 37 | let result = suiteContext.result; 38 | let test = result.tests.find(t => t.name === this.test.title); 39 | expect(test.status).to.equal('pass'); 40 | expect(test.error).to.be.a('null'); 41 | }); 42 | 43 | it('post non existent binary data (file) as body - should fail', function () { 44 | let result = suiteContext.result; 45 | let test = result.tests.find(t => t.name === this.test.title); 46 | expect(test.status).to.equal('fail'); 47 | expect(test.error.name).to.equal('RequestBodyBuilderError'); 48 | expect(test.error.message).to.contain('does not exist'); 49 | }); 50 | 51 | it('post non existent relative file path binary data (file) as body - should fail', function () { 52 | let result = suiteContext.result; 53 | let test = result.tests.find(t => t.name === this.test.title); 54 | expect(test.status).to.equal('fail'); 55 | expect(test.error.name).to.equal('RequestBodyBuilderError'); 56 | expect(test.error.message).to.contain('does not exist'); 57 | }); 58 | 59 | it('before test hook module relative path', function () { 60 | let result = suiteContext.result; 61 | let test = result.tests.find(t => t.name === this.test.title); 62 | expect(test.status).to.equal('pass'); 63 | expect(test.error).to.be.a('null'); 64 | }); 65 | 66 | it('read json schema from file and validate response', function () { 67 | let result = suiteContext.result; 68 | let test = result.tests.find(t => t.name === this.test.title); 69 | expect(test.status).to.equal('pass'); 70 | expect(test.error).to.be.a('null'); 71 | }); 72 | 73 | }); -------------------------------------------------------------------------------- /test/cli/urlencodedformpost.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const runJustAPIJSON = require('./helpers').runJustAPIJSON; 4 | const expect = require('chai').expect; 5 | const fs = require('fs'); 6 | 7 | describe('url encoded form post', function () { 8 | let suiteContext = this; 9 | 10 | before(async function () { 11 | let result = runJustAPIJSON('urlencodeformpost.suite.yml'); 12 | if (result.error) throw result.error; 13 | expect(result.exitCode).to.equal(1); 14 | expect(result.terminationSignal).to.be.a('null'); 15 | const report = fs.readFileSync(result.jsonReport); 16 | let reportData = JSON.parse(report); 17 | 18 | expect(reportData.passedSuitesCount).to.equal(0); 19 | expect(reportData.skippedSuitesCount).to.equal(0); 20 | expect(reportData.failedSuitesCount).to.equal(1); 21 | expect(reportData.passedTestsCount).to.equal(1); 22 | expect(reportData.skippedTestsCount).to.equal(0); 23 | expect(reportData.failedTestsCount).to.equal(2); 24 | expect(reportData.suites.length).to.equal(1); 25 | expect(reportData.suites[0].status).to.equal('fail'); 26 | 27 | suiteContext.result = reportData.suites[0]; 28 | }); 29 | 30 | it('post form data as body', function () { 31 | let result = suiteContext.result; 32 | let test = result.tests.find(t => t.name === this.test.title); 33 | expect(test.status).to.equal('pass'); 34 | expect(test.error).to.be.a('null'); 35 | }); 36 | 37 | it('post form data as body without header - should fail', function () { 38 | let result = suiteContext.result; 39 | let test = result.tests.find(t => t.name === this.test.title); 40 | expect(test.status).to.equal('fail'); 41 | expect(test.error.name).to.equal('InvalidRequestHeaderError'); 42 | expect(test.error.message).to.contain('Request method is post,request body is provided but Content-Type header is not provided'); 43 | }); 44 | 45 | it('post form data as body with wrong header - should fail', function () { 46 | let result = suiteContext.result; 47 | let test = result.tests.find(t => t.name === this.test.title); 48 | expect(test.status).to.equal('fail'); 49 | expect(test.error.name).to.equal('InvalidRequestHeaderError'); 50 | expect(test.error.message).to.contain('Request body is provided as form but request Content-Type is application/wrongheadertype. It should be application/x-www-form-urlencoded'); 51 | }); 52 | 53 | }); --------------------------------------------------------------------------------