├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json └── tasks.json ├── CNAME ├── LICENSE ├── README.md ├── _config.yml ├── _layouts └── default.html ├── appveyor.yml ├── assets ├── css │ └── style.scss └── img │ ├── mocha-chai │ ├── browser.gif │ ├── cli.gif │ ├── ide.gif │ ├── karma.png │ ├── logo.png │ ├── saucelabs.png │ └── screenshot.gif │ ├── postman │ ├── logo.png │ ├── newman.gif │ ├── request-builder.gif │ ├── runner.gif │ └── screenshot.gif │ ├── restlet │ ├── expression-builder.gif │ ├── logo.png │ ├── maven.gif │ ├── runner.gif │ └── screenshot.gif │ ├── stoplight │ ├── contract-verification.gif │ ├── coverage.gif │ ├── logo.png │ ├── prism.gif │ ├── runner.gif │ └── screenshot.gif │ └── title-banner.png ├── mocha-chai ├── README.md ├── banner.js ├── browser.html ├── karma.conf.js ├── lib │ ├── chai-http.js │ ├── chai-json-schema.js │ ├── chai.js │ ├── jsonpointer.js │ ├── karma-host-environment.js │ ├── mocha.css │ ├── mocha.js │ └── tv4.js ├── package-lock.json ├── package.json └── test │ ├── fixtures │ ├── assertions.js │ ├── before-each.js │ ├── environment.js │ ├── open-api.js │ └── setup-chai.js │ ├── mocha.opts │ └── specs │ ├── create-character.spec.js │ ├── get-all-characters.spec.js │ ├── get-character.spec.js │ ├── search-characters.spec.js │ └── update-character.spec.js ├── postman ├── README.md ├── banner.js ├── postman-collection.json └── postman-environment.json ├── presentation.pdf ├── restlet ├── README.md ├── banner.js ├── pom.xml └── restlet-repository.json └── stoplight ├── README.md ├── banner.js ├── stoplight-collection.json ├── stoplight-environment.json └── stoplight-spec.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Specifies intentionally untracked files to ignore when using Git 2 | # http://git-scm.com/docs/gitignore 3 | 4 | **/*~ 5 | **/._* 6 | **/.DS_Store 7 | npm-debug.log 8 | node_modules 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Travis CI config 2 | # http://docs.travis-ci.com/user/languages/javascript-with-nodejs/ 3 | # https://docs.travis-ci.com/user/customizing-the-build/ 4 | # https://docs.travis-ci.com/user/migrating-from-legacy/ 5 | 6 | dist: trusty 7 | sudo: required # Required for headless Chrome 8 | 9 | addons: 10 | firefox: latest 11 | chrome: stable 12 | 13 | before_script: 14 | # Setup a virtual display for browser testing 15 | - export DISPLAY=:99.0 16 | - sh -e /etc/init.d/xvfb start 17 | 18 | # Install Node 8 (required by Mocha and Postman) 19 | - nvm install 8 20 | - node --version 21 | - npm --version 22 | 23 | # Install Mocha + Chai 24 | - cd mocha-chai 25 | - npm install 26 | - cd .. 27 | 28 | # Install Newman (required by Postman) 29 | - npm install --global newman 30 | 31 | # Install Prism (required by Stoplight) 32 | - sudo curl https://raw.githubusercontent.com/stoplightio/prism/2.x/install.sh | sudo sh 33 | 34 | script: 35 | # Mocha + Chai 36 | - cd mocha-chai && node banner.js 37 | - npm run mocha 38 | - npm run karma 39 | 40 | # Postman 41 | - cd ../postman && node banner.js 42 | - newman run postman-collection.json --environment postman-environment.json 43 | 44 | # Stoplight 45 | - cd ../stoplight && node banner.js 46 | - prism conduct stoplight-collection.json --spec stoplight-spec.json --env stoplight-environment.json 47 | 48 | # Restlet 49 | - cd ../restlet && node banner.js 50 | - mvn test --quiet --define license_key=$LICENSE_KEY 51 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Run tests", 6 | "type": "node", 7 | "request": "launch", 8 | "program": "${workspaceRoot}/Mocha-Chai/node_modules/.bin/_mocha", 9 | "stopOnEntry": false, 10 | "args": ["--timeout=600000"], 11 | "cwd": "${workspaceRoot}/Mocha-Chai", 12 | "preLaunchTask": null, 13 | "runtimeExecutable": null, 14 | "runtimeArgs": [ 15 | "--nolazy" 16 | ], 17 | "env": { 18 | "NODE_ENV": "test", 19 | "API_ROOT": "http://localhost:8080" 20 | }, 21 | "console": "internalConsole", 22 | "internalConsoleOptions": "openOnSessionStart", 23 | "sourceMaps": true 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | { 10 | "version": "0.1.0", 11 | "command": "npm", 12 | "isShellCommand": true, 13 | "suppressTaskName": true, 14 | "tasks": [ 15 | { 16 | "taskName": "start", 17 | "args": ["run", "start", "--silent"], 18 | "showOutput": "always", 19 | "problemMatcher": "$eslint-stylish", 20 | "isBuildCommand": true 21 | }, 22 | { 23 | "taskName": "test", 24 | "args": ["run", "mocha", "--silent"], 25 | "options": { 26 | "cwd": "${workspaceRoot}/Mocha-Chai", 27 | "env": { 28 | "NODE_ENV": "test", 29 | "API_ROOT": "http://localhost:8080" 30 | } 31 | }, 32 | "showOutput": "always", 33 | "isTestCommand": true 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | apitesting.jamesmessinger.com -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Superhero imagery Copyright: malchev / 123RF Stock Photo 2 | 3 | ===================================================== 4 | 5 | Everything else is licensed under the MIT License (MIT) 6 | 7 | Copyright (c) 2016 James Messinger 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Super-Powered API Testing](assets/img/title-banner.png)](https://apitesting.jamesmessinger.com) 2 | 3 | What is this? 4 | -------------------------------------------------------------------------------- 5 | This website accompanies a talk/workshop ([here's the slide deck](https://github.com/JamesMessinger/super-powered-api-testing/blob/master/presentation.pdf)) that discusses and compares various API testing tools and best-practices. I've re-created the same API test suite in several different tools to make it easy to compare and contrast them in terms of features, ease-of-use, syntax, etc. 6 | 7 | 8 | Demo API 9 | -------------------------------------------------------------------------------- 10 | This is the REST API that we're testing. It's a fun list of technology-themed superheroes, sidekicks, and villains. 11 | 12 | - [Demo website](https://heroes.jamesmessinger.com/) 13 | - [The Raw API](https://api.heroes.jamesmessinger.com/) 14 | - [API documentation](https://documenter.getpostman.com/view/220187/super-tech-heroes-api/77cf6KB) 15 | - [OpenAPI 3.0 definition](https://api.heroes.jamesmessinger.com/schema) 16 | - [Swagger 2.0 definition](https://api.heroes.jamesmessinger.com/schema?accept=application/openapi+json;version=2.0) 17 | 18 | 19 | 20 | API Testing Tools 21 | -------------------------------------------------------------------------------- 22 | 23 | [![Mocha & Chai](assets/img/mocha-chai/logo.png)](mocha-chai/) 24 | -------------------------------------------------------------------------------- 25 | Mocha and Chai are JavaScript libraries that make it easy to write complex API tests using an intuitive fluent syntax that's easy to learn. 26 | 27 | [Features](mocha-chai/) | [Demo](mocha-chai/#demo-setup) 28 | 29 | 30 | 31 | [![Restlet](assets/img/restlet/logo.png)](restlet/) 32 | -------------------------------------------------------------------------------- 33 | Restlet is a free Chrome extension that's so easy to use that _anybody_ can build API tests. 34 | 35 | [Features](restlet/) | [Demo](restlet/#demo-setup) 36 | 37 | 38 | 39 | [![Postman](assets/img/postman/logo.png)](postman/) 40 | -------------------------------------------------------------------------------- 41 | Postman is a free app that makes it easy to build, test, and document your APIs. It has powerful API testing features that strike a good balance between power and ease-of-use. 42 | 43 | [Features](postman/) | [Demo](postman/#demo-setup) 44 | 45 | 46 | 47 | [![Stoplight](assets/img/stoplight/logo.png)](stoplight/) 48 | -------------------------------------------------------------------------------- 49 | Stoplight is a powerful API development tool that's based on OpenAPI (fka Swagger). Its tight integration with OpenAPI enables powerful features like automatic contract verification and code-coverage analysis. 50 | 51 | [Features](stoplight/) | [Demo](stoplight/#demo-setup) 52 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Jekyll configuration file 2 | # https://jekyllrb.com/docs/configuration/ 3 | 4 | # https://github.com/pages-themes/primer 5 | theme: jekyll-theme-primer 6 | 7 | # Jekyll SEO Tag plugin 8 | # https://github.com/jekyll/jekyll-seo-tag/blob/master/docs/usage.md 9 | # https://github.com/jekyll/jekyll-seo-tag/blob/master/docs/advanced-usage.md 10 | title: Super-Powered API Testing 11 | logo: /assets/img/title-banner.png 12 | author: 13 | name: James Messinger 14 | twitter: James_Messinger 15 | twitter: 16 | username: James_Messinger 17 | defaults: 18 | - scope: 19 | path: "" # All pages 20 | values: 21 | image: /assets/img/title-banner.png 22 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% seo %} 8 | 9 | 10 | 11 | 12 |
13 | {{ content }} 14 | 15 | {% if site.github.private != true and site.github.license %} 16 | 27 | {% endif %} 28 |
29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # AppVeyor Config 2 | # http://www.appveyor.com/docs/lang/nodejs-iojs 3 | 4 | image: Visual Studio 2017 5 | 6 | # Don't run MSBuild 7 | build: off 8 | 9 | # Don't build tags 10 | skip_tags: true 11 | 12 | environment: 13 | nodejs_version: "8" 14 | 15 | install: 16 | # Install Node 8 (required by Mocha and Postman) 17 | - ps: Install-Product node $env:nodejs_version 18 | - node --version 19 | - npm --version 20 | 21 | # Install Mocha + Chai 22 | - cd mocha-chai 23 | - npm install 24 | - cd .. 25 | 26 | # Install Newman (required by Postman) 27 | - npm install --global newman 28 | 29 | # Install Prism (required by Stoplight) 30 | - curl -L "https://github.com/stoplightio/prism/releases/download/v2.0.0-beta.2/prism_windows_386.exe" > stoplight/prism.exe 31 | 32 | # Install Maven (required by Restlet) 33 | - choco install maven 34 | 35 | test_script: 36 | # Mocha + Chai 37 | - cd mocha-chai && node banner.js 38 | - npm run mocha 39 | - npm run karma 40 | 41 | # Postman 42 | - cd ../postman && node banner.js 43 | - newman run postman-collection.json --environment postman-environment.json 44 | 45 | # Stoplight 46 | - cd ../stoplight && node banner.js 47 | - prism conduct stoplight-collection.json --spec stoplight-spec.json --env stoplight-environment.json 48 | 49 | # Restlet 50 | - cd ../restlet && node banner.js 51 | - mvn test --quiet --define license_key=$LICENSE_KEY 52 | -------------------------------------------------------------------------------- /assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "{{ site.theme }}"; 5 | 6 | body { 7 | // Add a blue gradient at the top of the page, behind the superhero image 8 | background-color: white; 9 | background: white linear-gradient(169deg, #99c7ff, white 500px) no-repeat; 10 | } 11 | 12 | .markdown-body img { 13 | // Remove the white background from that the default theme applies to images 14 | background-color: transparent; 15 | } 16 | -------------------------------------------------------------------------------- /assets/img/mocha-chai/browser.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/mocha-chai/browser.gif -------------------------------------------------------------------------------- /assets/img/mocha-chai/cli.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/mocha-chai/cli.gif -------------------------------------------------------------------------------- /assets/img/mocha-chai/ide.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/mocha-chai/ide.gif -------------------------------------------------------------------------------- /assets/img/mocha-chai/karma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/mocha-chai/karma.png -------------------------------------------------------------------------------- /assets/img/mocha-chai/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/mocha-chai/logo.png -------------------------------------------------------------------------------- /assets/img/mocha-chai/saucelabs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/mocha-chai/saucelabs.png -------------------------------------------------------------------------------- /assets/img/mocha-chai/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/mocha-chai/screenshot.gif -------------------------------------------------------------------------------- /assets/img/postman/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/postman/logo.png -------------------------------------------------------------------------------- /assets/img/postman/newman.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/postman/newman.gif -------------------------------------------------------------------------------- /assets/img/postman/request-builder.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/postman/request-builder.gif -------------------------------------------------------------------------------- /assets/img/postman/runner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/postman/runner.gif -------------------------------------------------------------------------------- /assets/img/postman/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/postman/screenshot.gif -------------------------------------------------------------------------------- /assets/img/restlet/expression-builder.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/restlet/expression-builder.gif -------------------------------------------------------------------------------- /assets/img/restlet/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/restlet/logo.png -------------------------------------------------------------------------------- /assets/img/restlet/maven.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/restlet/maven.gif -------------------------------------------------------------------------------- /assets/img/restlet/runner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/restlet/runner.gif -------------------------------------------------------------------------------- /assets/img/restlet/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/restlet/screenshot.gif -------------------------------------------------------------------------------- /assets/img/stoplight/contract-verification.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/stoplight/contract-verification.gif -------------------------------------------------------------------------------- /assets/img/stoplight/coverage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/stoplight/coverage.gif -------------------------------------------------------------------------------- /assets/img/stoplight/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/stoplight/logo.png -------------------------------------------------------------------------------- /assets/img/stoplight/prism.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/stoplight/prism.gif -------------------------------------------------------------------------------- /assets/img/stoplight/runner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/stoplight/runner.gif -------------------------------------------------------------------------------- /assets/img/stoplight/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/stoplight/screenshot.gif -------------------------------------------------------------------------------- /assets/img/title-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JamesMessinger/super-powered-api-testing/ba34b2bd3708d330bceb43100b97cb74efea8555/assets/img/title-banner.png -------------------------------------------------------------------------------- /mocha-chai/README.md: -------------------------------------------------------------------------------- 1 | [![Super-Powered API Testing](https://apitesting.jamesmessinger.com/assets/img/title-banner.png)](https://apitesting.jamesmessinger.com) 2 | 3 | [![Mocha & Chai](https://apitesting.jamesmessinger.com/assets/img/mocha-chai/logo.png)](http://mochajs.org) 4 | ================================================================================ 5 | 6 | [Mocha](https://mochajs.org/) and [Chai](http://chaijs.com/) are JavaScript libraries that make it easy to write complex API tests using an intuitive fluent syntax that's easy to learn. 7 | 8 | - **[Demo setup instructions](#demo-setup)** 9 | - **[Running tests from the command-line](#cli)** 10 | - **[Running tests in an IDE](#ide)** 11 | - **[Running tests in a web browser](#browser)** 12 | - **[Running automated cross-browser tests](#karma)** 13 | 14 | 15 | 16 | Tests that run everywhere 17 | -------------------------------------------------------------------------------- 18 | Mocha and Chai give you an impressive list of options for running your tests. There's a CLI for running tests on the command line, which also works well for automated testing as well as CI/CD tools. There are also [plugins](https://mochajs.org/#editor-plugins) for many popular IDEs and code editors, including [VSCode](https://marketplace.visualstudio.com/search?term=mocha&target=VSCode&category=All%20categories&sortBy=Relevance), [Atom](https://atom.io/packages/search?q=mocha), [WebStorm](https://www.youtube.com/watch?v=4mKiGkokyx8), [Visual Studio](https://github.com/Microsoft/nodejstools/wiki/Test-Explorer), and even [Emacs](https://github.com/scottaj/mocha.el). You can even run your tests in any web browser or mobile device. (more on that below...) 19 | 20 | ![Mocha + Chai screenshots](https://apitesting.jamesmessinger.com/assets/img/mocha-chai/screenshot.gif) 21 | 22 | 23 | 24 | Browsers & Mobile testing 25 | -------------------------------------------------------------------------------- 26 | This is an important feature that _only_ Mocha and Chai offers. Browsers and mobile devices have many limitations and restrictions in place for security, privacy, and latency reasons, which your API may need to account for. 27 | 28 | Are you sure that your API works with [Same-Origin Policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) and [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)? Have you properly implemented [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)? Does your API require any of [the forbidden headers](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name)? You need to run your API tests on real-world client devices to be sure. 29 | 30 | You can use tools such as [Karma](https://karma-runner.github.io/) or [Nightwatch](http://nightwatchjs.org/) to automate cross-browser testing and integrate it into your CI/CD pipeline. You can also use cloud-hosted device testing services such as [SauceLabs](https://saucelabs.com/) or [BrowserStack](https://www.browserstack.com/) to test on a wider variety of devices. 31 | 32 | [![SauceLabs test matrix](https://apitesting.jamesmessinger.com/assets/img/mocha-chai/saucelabs.png)](https://wiki.saucelabs.com/display/DOCS/Using+Status+Badges+and+the+Browser+Matrix+Widget+to+Monitor+Test+Results) 33 | 34 | 35 | Some coding required 36 | -------------------------------------------------------------------------------- 37 | Whereas many other API testing tools let you build your tests using a graphical interface, Mocha and Chai are 100% JavaScript code. This makes it a great choice for people with coding skills, but perhaps not such a great option for teams with a diverse range of people who need to be able to create API tests. 38 | 39 | There are numerous benefits to being 100% JavaScript though. As mentioned above, your tests can [run anywhere](#run-everywhere), not just in a vendor-specific tool. You also aren't limited or restricted by the functionality of a tool. Many API testing tools don't support complex testing scenarios, such as conditional flows, loops, processing data files, setup/teardown steps, etc. But you can do all that and more in Mocha and Chai because it's just JavaScript. 40 | 41 | You can also leverage numerous [Chai plugins](http://chaijs.com/plugins/) as well as the [vast ecosystem](https://www.npmjs.com/) of JavaScript libraries to help you with complex things like [hasing and encryption](https://code.google.com/archive/p/crypto-js/) or [JSON Schema validation](http://chaijs.com/plugins/chai-json-schema/). 42 | 43 | 44 | 45 | 46 | Demo Setup 47 | -------------------------------------------------------------------------------- 48 | In this demo, you'll run [the API tests](https://github.com/JamesMessinger/super-powered-api-testing/blob/v2/mocha-chai/test/specs) from the command-line, in an IDE, in a web browser, and via automated cross-browser testing. 49 | 50 | ### Step 1. Install Node.js 51 | The Mocha CLI requires [Node.js 4.0 or greater](https://nodejs.org/en/). 52 | 53 | ### Step 2. Download the demo code 54 | Download [this tarball file](https://registry.npmjs.org/super-powered-api-testing/-/super-powered-api-testing-2.1.3.tgz), which contains the sample tests and scripts to run them. 55 | 56 | If you don't have a way to unpack the tarball, then you can use the following [npx](https://www.npmjs.com/package/npx) command: 57 | 58 | ``` 59 | npx decompress-cli super-powered-api-testing-2.1.3.tgz -o . 60 | ``` 61 | 62 | ### Step 3. Install dependencies 63 | Open the demo code directory in a terminal and run the following command to install all dependencies. This will install Mocha and Chai, as well as the [Karma test runner](https://karma-runner.github.io/) to run automated cross-browser tests. 64 | 65 | ``` 66 | cd /path/to/demo/code 67 | npm install 68 | ``` 69 | 70 | 71 | 72 | 73 | Running the tests from the command-line 74 | -------------------------------------------------------------------------------- 75 | Open the demo code directory in a terminal and run the following command: 76 | 77 | ``` 78 | cd /path/to/demo/code 79 | npm run mocha 80 | ``` 81 | 82 | This command runs the Mocha CLI, which will read the [`mocha.opts`](https://github.com/JamesMessinger/super-powered-api-testing/blob/v2/mocha-chai/test/mocha.opts) file. This file configures several Mocha options, such as timeouts and failure behavior. It also tells Mocha which test scripts to run. 83 | 84 | #### The `test/fixtures` folder 85 | This folder contains scripts that perform initialization logic and define helpers that are used by the tests 86 | 87 | |Script file |Purpose 88 | |:-----------------------------|:----------------------------------------------------------- 89 | |[`test/fixtures/assertions.js`](https://github.com/JamesMessinger/super-powered-api-testing/blob/v2/mocha-chai/test/fixtures/assertions.js) |Defines custom Chai.js assertions, which eliminate redundancy and make our tests more readable (e.g. `response.body.should.be.a.character()`) 90 | |[`fixtures/before-each.js`](https://github.com/JamesMessinger/super-powered-api-testing/blob/v2/mocha-chai/test/fixtures/before-each.js) |Defines a Mocha `beforeEach` hook, which will reset the state before each test by deleting any data that were created by the previous test. 91 | |[`test/fixtures/environment.js`](https://github.com/JamesMessinger/super-powered-api-testing/blob/v2/mocha-chai/test/fixtures/environment.js)|Sets environment variables, such as `API_ROOT` and `API_KEY`. These variables allow us to test against different instances of our API (e.g. dev, staging, prod) 92 | |[`test/fixtures/open-api.js`](https://github.com/JamesMessinger/super-powered-api-testing/blob/v2/mocha-chai/test/fixtures/open-api.js) |This script downloads the [OpenAPI definition](https://api.heroes.jamesmessinger.com/schema), so we can use it to test whether our API responses match the JSON Schemas. 93 | |[`test/fixtures/setup-chai.js`](https://github.com/JamesMessinger/super-powered-api-testing/blob/v2/mocha-chai/test/fixtures/setup-chai.js) |This script initializes Chai and loads the [Chai-HTTP](http://chaijs.com/plugins/chai-http/) and [Chai-JSON-Schema](http://chaijs.com/plugins/chai-json-schema/) plugins. 94 | 95 | ![CLI screenshot](https://apitesting.jamesmessinger.com/assets/img/mocha-chai/cli.gif) 96 | 97 | 98 | 99 | 100 | Running the tests in an IDE 101 | -------------------------------------------------------------------------------- 102 | Many popular IDEs and text editors have built-in support for [Mocha](https://mochajs.org/), so you can easily run your tests with the press of a button and see the results right in your IDE. 103 | 104 | - [How to use Mocha in WebStorm](https://www.youtube.com/watch?v=4mKiGkokyx8)) 105 | - [How to use Mocha in Visual Studio](https://github.com/Microsoft/nodejstools/wiki/Test-Explorer) 106 | - [Mocha plug-ins for VSCode](https://marketplace.visualstudio.com/search?term=mocha&target=VSCode&category=All%20categories&sortBy=Relevance) 107 | - [Mocha plug-ins for Atom](https://atom.io/packages/search?q=mocha) 108 | - [Mocha package for Emacs](https://github.com/scottaj/mocha.el) 109 | 110 | ![IDE screenshot](https://apitesting.jamesmessinger.com/assets/img/mocha-chai/ide.gif) 111 | 112 | 113 | 114 | 115 | 116 | Running the tests in a web browser 117 | -------------------------------------------------------------------------------- 118 | Mocha and Chai can run in web browsers too, which is [very important](#browser-testing) for testing your API in real-world conditions. You can even run your tests in mobile browsers, such as iOS and Android, and in [hybrid mobile apps](https://developer.telerik.com/featured/what-is-a-hybrid-mobile-app/) such as PhoneGap, Cordova, and React Native. 119 | 120 | Just open the [`browser.html`](https://github.com/JamesMessinger/super-powered-api-testing/blob/v2/mocha-chai/browser.html) file in a web browser. Or run the following command to open it in your default browser: 121 | 122 | ``` 123 | cd /path/to/demo/code 124 | npm start 125 | ``` 126 | 127 | The Mocha web UI automatically runs all of your tests and checks-off each one as they pass. If any tests fail, you'll see the reason for the failure. You can click on any test to see the source code for that test. You can also click the arrows on the far right side of the page to run a single test, which is great for debugging. 128 | 129 | ![Browser screenshot](https://apitesting.jamesmessinger.com/assets/img/mocha-chai/browser.gif) 130 | 131 | 132 | 133 | 134 | 135 | Running automated cross-browser tests 136 | -------------------------------------------------------------------------------- 137 | Mocha and Chai work great with cross-browser automation tools such as [Karma](https://karma-runner.github.io/) or [Nightwatch](http://nightwatchjs.org/), which can easily be integrated into your CI/CD pipeline. You can also use cloud-hosted device testing services such as [SauceLabs](https://saucelabs.com/) or [BrowserStack](https://www.browserstack.com/) to test on a wider variety of devices. 138 | 139 | For this demo, we'll use [Karma](https://karma-runner.github.io/), which is a Node.js-based CLI. Karma is a powerful with [lots of configuration options](https://karma-runner.github.io/1.0/config/configuration-file.html) and [hundreds of plugins](https://www.npmjs.com/browse/keyword/karma-plugin), which can be daunting at first. For this demo, I've already created a [`karma.conf.js` config file](https://github.com/JamesMessinger/super-powered-api-testing/blob/v2/mocha-chai/karma.conf.js), so all you need to do is run the following command: 140 | 141 | ``` 142 | cd /path/to/demo/code 143 | npm run karma 144 | ``` 145 | 146 | Depending on your operating system, Karma will automatically launch Chrome, Firefox, Safari, and/or Internet Explorer and run the tests in each browser. Once the tests are complete, Karma will close the browsers and show the results in the terminal window. 147 | 148 | Karma can also run in a "watch" mode, where it will keep the browsers running instead of closing them after the tests finish. In this mode, it will monitor your source code for changes and will automatically re-run the tests each time you save. 149 | 150 | Karma can be integrated into [TravisCI](https://karma-runner.github.io/1.0/plus/travis.html), [Jenkins](https://karma-runner.github.io/1.0/plus/jenkins.html), [TeamCity](https://karma-runner.github.io/1.0/plus/teamcity.html), or any other CI/CD tool that can run Node.js scripts. 151 | 152 | ![Karma screenshot](https://apitesting.jamesmessinger.com/assets/img/mocha-chai/karma.png) 153 | -------------------------------------------------------------------------------- /mocha-chai/banner.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | console.log('\n\n\n'); 5 | console.log(' __ __ _______ _______ __ __ _______ _ _______ __ __ _______ ___ '); 6 | console.log('| |_| || || || | | || _ | _| |_ | || | | || _ || |'); 7 | console.log('| || _ || || |_| || |_| | |_ _| | || |_| || |_| || |'); 8 | console.log('| || | | || || || | |_| | || || || |'); 9 | console.log('| || |_| || _|| || | | _|| || || |'); 10 | console.log('| ||_|| || || |_ | _ || _ | | |_ | _ || _ || |'); 11 | console.log('|_| |_||_______||_______||__| |__||__| |__| |_______||__| |__||__| |__||___|'); 12 | console.log('\n'); 13 | -------------------------------------------------------------------------------- /mocha-chai/browser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | SuperPowered API Testing | Mocha+Chai lets you test your API in web browsers! 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /mocha-chai/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma config 2 | // https://karma-runner.github.io/0.12/config/configuration-file.html 3 | 4 | 'use strict'; 5 | 6 | module.exports = function (karma) { 7 | karma.set({ 8 | frameworks: ['mocha', 'chai', 'host-environment'], 9 | 10 | files: [ 11 | // Third-Party Libraries 12 | 'lib/chai-http.js', 13 | 'lib/jsonpointer.js', 14 | 'lib/tv4.js', 15 | 'lib/chai-json-schema.js', 16 | 17 | // Test Fixtures 18 | 'test/fixtures/*.js', 19 | 20 | // Tests 21 | 'test/specs/**/*.spec.js', 22 | ], 23 | 24 | browsers: getBrowsersForCurrentPlatform(), 25 | 26 | // Set liberal tolerances to allow for slow/unreliable networks 27 | captureTimeout: 60000, 28 | browserDisconnectTimeout: 30000, 29 | browserDisconnectTolerance: 5, 30 | browserNoActivityTimeout: 60000, 31 | client: { 32 | mocha: { 33 | timeout: 10000, 34 | } 35 | }, 36 | }); 37 | }; 38 | 39 | 40 | /** 41 | * Configures the browsers for the current platform 42 | */ 43 | function getBrowsersForCurrentPlatform () { 44 | var isCI = process.env.CI; 45 | var isMac = /^darwin/.test(process.platform); 46 | var isWindows = /^win/.test(process.platform); 47 | var isLinux = !isMac && !isWindows; 48 | 49 | if (isCI) { 50 | return ['Firefox', 'ChromeHeadless']; 51 | } 52 | if (isMac) { 53 | return ['Firefox', 'Chrome', 'Safari']; 54 | } 55 | else if (isLinux) { 56 | return ['Firefox', 'Chrome']; 57 | } 58 | else if (isWindows) { 59 | return ['Firefox', 'Chrome', 'IE']; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /mocha-chai/lib/chai-http.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Chai-HTTP 3 | * v3.0.0 (2016-06-10) 4 | * http://chaijs.com/plugins/chai-http/ 5 | * https://cdn.rawgit.com/chaijs/chai-http/80b4efb1/dist/chai-http.min.js 6 | */ 7 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.chaiHttp = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 11 | * MIT Licensed 12 | */ 13 | module.exports=function(e,t){/*! 14 | * Return a header from `Request` or `Response` object. 15 | * 16 | * @param {Request|Response} object 17 | * @param {String} Header 18 | * @returns {String|Undefined} 19 | */ 20 | function o(e,t){return t&&(t=t.toLowerCase()),e.getHeader?e.getHeader(t):e.headers?e.headers[t]:void 0}function s(e){var t=c[e];n.addProperty(e,function(){new n(this._obj).to.have.headers;var e=o(this._obj,"content-type"),s="undefined"===h(e)?"headers":h(e);this.assert(e&&~e.indexOf(t),"expected "+s+" to include '"+t+"'","expected "+s+" to not include '"+t+"'")})}/*! 21 | * Module dependencies. 22 | */ 23 | var r=require("net"),a=require("qs"),i=require("url"),d=require("cookiejar"),n=e.Assertion,h=t.inspect;/*! 24 | * Expose request builder 25 | */ 26 | e.request=require("./request");/*! 27 | * Content types hash. Used to 28 | * define `Assertion` properties. 29 | * 30 | * @type {Object} 31 | */ 32 | var c={json:"application/json",text:"text/plain",html:"text/html"};n.addMethod("status",function(e){new n(this._obj).to.have.property("status");var t=this._obj.status;this.assert(t==e,"expected #{this} to have status code #{exp} but got #{act}","expected #{this} to not have status code #{act}",e,t)}),n.addMethod("header",function(e,t){var s=o(this._obj,e);arguments.length<2?this.assert("undefined"!=typeof s||null===s,"expected header '"+e+"' to exist","expected header '"+e+"' to not exist"):arguments[1]instanceof RegExp?this.assert(t.test(s),"expected header '"+e+"' to match "+t+" but got "+h(s),"expected header '"+e+"' not to match "+t+" but got "+h(s),t,s):this.assert(s==t,"expected header '"+e+"' to have value "+t+" but got "+h(s),"expected header '"+e+"' to not have value "+t,t,s)}),n.addProperty("headers",function(){this.assert(this._obj.headers||this._obj.getHeader,"expected #{this} to have headers or getHeader method","expected #{this} to not have headers or getHeader method")}),n.addProperty("ip",function(){this.assert(r.isIP(this._obj),"expected #{this} to be an ip","expected #{this} to not be an ip")}),Object.keys(c).forEach(s),n.addProperty("redirect",function(){var e=[301,302,303],t=this._obj.status,o=this._obj.redirects;this.assert(e.indexOf(t)>=0||o&&o.length,"expected redirect with 30{1-3} status code but got "+t,"expected not to redirect but got "+t+" status")}),n.addMethod("redirectTo",function(e){var o=this._obj.redirects;if(new n(this._obj).to.redirect,o&&o.length)this.assert(o.indexOf(e)>-1,"expected redirect to "+e+" but got "+o.join(" then "),"expected not to redirect to "+e+" but got "+o.join(" then "));else{var s=new n(this._obj);t.transferFlags(this,s),s["with"].header("location",e)}}),n.addMethod("param",function(e,o){var s=new n;t.transferFlags(this,s),s._obj=a.parse(i.parse(this._obj.url).query),s.property.apply(s,arguments)}),n.addMethod("cookie",function(e,t){var s,r=o(this._obj,"set-cookie");r||(r=(o(this._obj,"cookie")||"").split(";")),s=d.CookieJar(),s.setCookies(r),s=s.getCookie(e,new d.CookieAccessInfo),2===arguments.length?this.assert(s.value==t,"expected cookie '"+e+"' to have value #{exp} but got #{act}","expected cookie '"+e+"' to not have value #{exp}",t,s.value):this.assert("undefined"!=typeof s||null===s,"expected cookie '"+e+"' to exist","expected cookie '"+e+"' to not exist")})}; 33 | 34 | },{"./request":3,"cookiejar":6,"net":2,"qs":13,"url":25}],2:[function(require,module,exports){ 35 | /*! 36 | * chai-http - request helper 37 | * Copyright(c) 2011-2012 Jake Luer 38 | * MIT Licensed 39 | */ 40 | /*! 41 | * net.isIP shim for browsers 42 | */ 43 | var isIP=require("is-ip");exports.isIP=isIP,exports.isIPv4=isIP.v4,exports.isIPv6=isIP.v6; 44 | 45 | },{"is-ip":9}],3:[function(require,module,exports){ 46 | /*! 47 | * chai-http - request helper 48 | * Copyright(c) 2011-2012 Jake Luer 49 | * MIT Licensed 50 | */ 51 | /*! 52 | * Module dependancies 53 | */ 54 | /*! 55 | * Test 56 | * 57 | * An extension of superagent.Request, 58 | * this provides the same chainable api 59 | * as superagent so all things can be modified. 60 | * 61 | * @param {Object|String} server, app, or url 62 | * @param {String} method 63 | * @param {String} path 64 | * @api private 65 | */ 66 | function Test(e,t,s){Request.call(this,t,s),this.app=e,this.url="string"==typeof e?e+s:serverAddress(e,s)}function serverAddress(e,t){if("string"==typeof e)return e+t;var s=e.address();s||(e.listen(0),s=e.address());var r=e instanceof https.Server?"https":"http";return("0.0.0.0"===s.address||"::"===s.address)&&(s.address="127.0.0.1"),r+"://"+s.address+":"+s.port+t}/*! 67 | * agent 68 | * 69 | * Follows the same API as superagent.Request, 70 | * but allows persisting of cookies between requests. 71 | * 72 | * @param {Object|String} server, app, or url 73 | * @param {String} method 74 | * @param {String} path 75 | * @api private 76 | */ 77 | function TestAgent(e){return this instanceof TestAgent?("function"==typeof e&&(e=http.createServer(e)),(Agent||Request).call(this),void(this.app=e)):new TestAgent(e)}var http=require("http"),https=require("https"),methods=require("methods"),superagent=require("superagent"),Agent=superagent.agent,Request=superagent.Request,util=require("util");module.exports=function(e){/*! 78 | * @param {Mixed} function or server 79 | * @returns {Object} API 80 | */ 81 | var t="function"==typeof e?http.createServer(e):e,s={};return methods.forEach(function(e){s[e]=function(s){return new Test(t,e,s)}}),s.del=s["delete"],s},module.exports.Test=Test,module.exports.Request=Test,module.exports.agent=TestAgent,util.inherits(Test,Request),util.inherits(TestAgent,Agent||Request),methods.forEach(function(e){TestAgent.prototype[e]=function(t){var s=new Test(this.app,e,t),r=this;return Agent?(s.on("response",function(e){r._saveCookies(e)}),s.on("redirect",function(e){r._saveCookies(e)}),s.on("redirect",function(){r._attachCookies(s)}),this._attachCookies(s)):s.withCredentials(),s}}),TestAgent.prototype.del=TestAgent.prototype["delete"]; 82 | 83 | },{"http":4,"https":4,"methods":10,"superagent":21,"util":28}],4:[function(require,module,exports){ 84 | 85 | },{}],5:[function(require,module,exports){ 86 | function Emitter(t){return t?mixin(t):void 0}function mixin(t){for(var e in Emitter.prototype)t[e]=Emitter.prototype[e];return t}"undefined"!=typeof module&&(module.exports=Emitter),Emitter.prototype.on=Emitter.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},Emitter.prototype.once=function(t,e){function i(){this.off(t,i),e.apply(this,arguments)}return i.fn=e,this.on(t,i),this},Emitter.prototype.off=Emitter.prototype.removeListener=Emitter.prototype.removeAllListeners=Emitter.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var i=this._callbacks["$"+t];if(!i)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var r,s=0;sr;++r)i[r].apply(this,e)}return this},Emitter.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks["$"+t]||[]},Emitter.prototype.hasListeners=function(t){return!!this.listeners(t).length}; 87 | 88 | },{}],6:[function(require,module,exports){ 89 | !function(){"use strict";function t(i,e,n,s){return this instanceof t?(this.domain=i||void 0,this.path=e||"/",this.secure=!!n,this.script=!!s,this):new t(i,e,n,s)}function i(t,e,n){return t instanceof i?t:this instanceof i?(this.name=null,this.value=null,this.expiration_date=1/0,this.path=String(n||"/"),this.explicit_path=!1,this.domain=e||null,this.explicit_domain=!1,this.secure=!1,this.noscript=!1,t&&this.parse(t,e,n),this):new i(t,e,n)}function e(){var t,n,s;return this instanceof e?(t=Object.create(null),this.setCookie=function(e,r,a){var o,h;if(e=new i(e,r,a),o=e.expiration_date<=Date.now(),void 0!==t[e.name]){for(n=t[e.name],h=0;h1)for(var r=1;r1&&(t=r[0]+"@",e=r[1]),e=e.replace(S,".");var u=e.split("."),i=n(u,o).join(".");return t+i}function t(e){for(var o,n,r=[],t=0,u=e.length;u>t;)o=e.charCodeAt(t++),o>=55296&&56319>=o&&u>t?(n=e.charCodeAt(t++),56320==(64512&n)?r.push(((1023&o)<<10)+(1023&n)+65536):(r.push(o),t--)):r.push(o);return r}function u(e){return n(e,function(e){var o="";return e>65535&&(e-=65536,o+=P(e>>>10&1023|55296),e=56320|1023&e),o+=P(e)}).join("")}function i(e){return 10>e-48?e-22:26>e-65?e-65:26>e-97?e-97:b}function f(e,o){return e+22+75*(26>e)-((0!=o)<<5)}function c(e,o,n){var r=0;for(e=n?M(e/j):e>>1,e+=M(e/o);e>L*C>>1;r+=b)e=M(e/L);return M(r+(L+1)*e/(e+m))}function l(e){var n,r,t,f,l,s,d,a,p,h,v=[],g=e.length,w=0,m=I,j=A;for(r=e.lastIndexOf(E),0>r&&(r=0),t=0;r>t;++t)e.charCodeAt(t)>=128&&o("not-basic"),v.push(e.charCodeAt(t));for(f=r>0?r+1:0;g>f;){for(l=w,s=1,d=b;f>=g&&o("invalid-input"),a=i(e.charCodeAt(f++)),(a>=b||a>M((x-w)/s))&&o("overflow"),w+=a*s,p=j>=d?y:d>=j+C?C:d-j,!(p>a);d+=b)h=b-p,s>M(x/h)&&o("overflow"),s*=h;n=v.length+1,j=c(w-l,n,0==l),M(w/n)>x-m&&o("overflow"),m+=M(w/n),w%=n,v.splice(w++,0,m)}return u(v)}function s(e){var n,r,u,i,l,s,d,a,p,h,v,g,w,m,j,F=[];for(e=t(e),g=e.length,n=I,r=0,l=A,s=0;g>s;++s)v=e[s],128>v&&F.push(P(v));for(u=i=F.length,i&&F.push(E);g>u;){for(d=x,s=0;g>s;++s)v=e[s],v>=n&&d>v&&(d=v);for(w=u+1,d-n>M((x-r)/w)&&o("overflow"),r+=(d-n)*w,n=d,s=0;g>s;++s)if(v=e[s],n>v&&++r>x&&o("overflow"),v==n){for(a=r,p=b;h=l>=p?y:p>=l+C?C:p-l,!(h>a);p+=b)j=a-h,m=b-h,F.push(P(f(h+j%m,0))),a=M(j/m);F.push(P(f(a,0))),l=c(r,w,u==i),r=0,++u}++r,++n}return F.join("")}function d(e){return r(e,function(e){return F.test(e)?l(e.slice(4).toLowerCase()):e})}function a(e){return r(e,function(e){return O.test(e)?"xn--"+s(e):e})}var p="object"==typeof exports&&exports&&!exports.nodeType&&exports,h="object"==typeof module&&module&&!module.nodeType&&module,v="object"==typeof global&&global;(v.global===v||v.window===v||v.self===v)&&(e=v);var g,w,x=2147483647,b=36,y=1,C=26,m=38,j=700,A=72,I=128,E="-",F=/^xn--/,O=/[^\x20-\x7E]/,S=/[\x2E\u3002\uFF0E\uFF61]/g,T={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},L=b-y,M=Math.floor,P=String.fromCharCode;if(g={version:"1.3.2",ucs2:{decode:t,encode:u},decode:l,encode:s,toASCII:a,toUnicode:d},"function"==typeof define&&"object"==typeof define.amd&&define.amd)define("punycode",function(){return g});else if(p&&h)if(module.exports==p)h.exports=g;else for(w in g)g.hasOwnProperty(w)&&(p[w]=g[w]);else e.punycode=g}(this); 116 | 117 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 118 | 119 | },{}],13:[function(require,module,exports){ 120 | "use strict";var Stringify=require("./stringify"),Parse=require("./parse");module.exports={stringify:Stringify,parse:Parse}; 121 | 122 | },{"./parse":14,"./stringify":15}],14:[function(require,module,exports){ 123 | "use strict";var Utils=require("./utils"),defaults={delimiter:"&",depth:5,arrayLimit:20,parameterLimit:1e3,strictNullHandling:!1,plainObjects:!1,allowPrototypes:!1,allowDots:!1,decoder:Utils.decode},parseValues=function(e,t){for(var r={},l=e.split(t.delimiter,t.parameterLimit===1/0?void 0:t.parameterLimit),a=0;a=0&&l.parseArrays&&s<=l.arrayLimit?(a=[],a[s]=e(t,r,l)):a[o]=e(t,r,l)}return a},parseKeys=function(e,t,r){if(e){var l=r.allowDots?e.replace(/\.([^\.\[]+)/g,"[$1]"):e,a=/^([^\[\]]*)/,i=/(\[[^\[\]]*\])/g,o=a.exec(l),s=[];if(o[1]){if(!r.plainObjects&&Object.prototype.hasOwnProperty(o[1])&&!r.allowPrototypes)return;s.push(o[1])}for(var n=0;null!==(o=i.exec(l))&&nr;++r)e[r]="%"+((16>r?"0":"")+r.toString(16)).toUpperCase();return e}();exports.arrayToObject=function(e,r){for(var t=r.plainObjects?Object.create(null):{},o=0;o=48&&57>=n||n>=65&&90>=n||n>=97&&122>=n?t+=r.charAt(o):128>n?t+=hexTable[n]:2048>n?t+=hexTable[192|n>>6]+hexTable[128|63&n]:55296>n||n>=57344?t+=hexTable[224|n>>12]+hexTable[128|n>>6&63]+hexTable[128|63&n]:(o+=1,n=65536+((1023&n)<<10|1023&r.charCodeAt(o)),t+=hexTable[240|n>>18]+hexTable[128|n>>12&63]+hexTable[128|n>>6&63]+hexTable[128|63&n])}return t},exports.compact=function(e,r){if("object"!=typeof e||null===e)return e;var t=r||[],o=t.indexOf(e);if(-1!==o)return t[o];if(t.push(e),Array.isArray(e)){for(var n=[],c=0;c0&&p>s&&(p=s);for(var y=0;p>y;++y){var u,c,i,l,f=r[y].replace(a,"%20"),v=f.indexOf(t);v>=0?(u=f.substr(0,v),c=f.substr(v+1)):(u=f,c=""),i=decodeURIComponent(u),l=decodeURIComponent(c),hasOwnProperty(o,i)?isArray(o[i])?o[i].push(l):o[i]=[o[i],l]:o[i]=l}return o};var isArray=Array.isArray||function(r){return"[object Array]"===Object.prototype.toString.call(r)}; 133 | 134 | },{}],18:[function(require,module,exports){ 135 | "use strict";function map(r,e){if(r.map)return r.map(e);for(var t=[],n=0;nr;)u=n.call(null,u,l[r],++r,l);return u}; 142 | 143 | },{}],21:[function(require,module,exports){ 144 | function noop(){}function serialize(e){if(!isObject(e))return e;var t=[];for(var r in e)null!=e[r]&&pushEncodedKeyValuePair(t,r,e[r]);return t.join("&")}function pushEncodedKeyValuePair(e,t,r){if(Array.isArray(r))return r.forEach(function(r){pushEncodedKeyValuePair(e,t,r)});if(isObject(r))for(var s in r)pushEncodedKeyValuePair(e,t+"["+s+"]",r[s]);else e.push(encodeURIComponent(t)+"="+encodeURIComponent(r))}function parseString(e){for(var t,r,s={},n=e.split("&"),i=0,o=n.length;o>i;++i)t=n[i],r=t.indexOf("="),-1==r?s[decodeURIComponent(t)]="":s[decodeURIComponent(t.slice(0,r))]=decodeURIComponent(t.slice(r+1));return s}function parseHeader(e){var t,r,s,n,i=e.split(/\r?\n/),o={};i.pop();for(var u=0,a=i.length;a>u;++u)r=i[u],t=r.indexOf(":"),s=r.slice(0,t).toLowerCase(),n=trim(r.slice(t+1)),o[s]=n;return o}function isJSON(e){return/[\/+]json\b/.test(e)}function type(e){return e.split(/ *; */).shift()}function params(e){return reduce(e.split(/ *; */),function(e,t){var r=t.split(/ *= */),s=r.shift(),n=r.shift();return s&&n&&(e[s]=n),e},{})}function Response(e,t){t=t||{},this.req=e,this.xhr=this.req.xhr,this.text="HEAD"!=this.req.method&&(""===this.xhr.responseType||"text"===this.xhr.responseType)||"undefined"==typeof this.xhr.responseType?this.xhr.responseText:null,this.statusText=this.req.xhr.statusText,this._setStatusProperties(this.xhr.status),this.header=this.headers=parseHeader(this.xhr.getAllResponseHeaders()),this.header["content-type"]=this.xhr.getResponseHeader("content-type"),this._setHeaderProperties(this.header),this.body="HEAD"!=this.req.method?this._parseBody(this.text?this.text:this.xhr.response):null}function Request(e,t){var r=this;this._query=this._query||[],this.method=e,this.url=t,this.header={},this._header={},this.on("end",function(){var e=null,t=null;try{t=new Response(r)}catch(s){return e=new Error("Parser is unable to parse the response"),e.parse=!0,e.original=s,e.rawResponse=r.xhr&&r.xhr.responseText?r.xhr.responseText:null,e.statusCode=r.xhr&&r.xhr.status?r.xhr.status:null,r.callback(e)}if(r.emit("response",t),e)return r.callback(e,t);try{if(t.status>=200&&t.status<300)return r.callback(e,t);var n=new Error(t.statusText||"Unsuccessful HTTP response");n.original=e,n.response=t,n.status=t.status,r.callback(n,t)}catch(s){r.callback(s)}})}function del(e,t){var r=request("DELETE",e);return t&&r.end(t),r}var Emitter=require("emitter"),reduce=require("reduce"),requestBase=require("./request-base"),isObject=require("./is-object"),root;root="undefined"!=typeof window?window:"undefined"!=typeof self?self:this;var request=module.exports=require("./request").bind(null,Request);request.getXHR=function(){if(!(!root.XMLHttpRequest||root.location&&"file:"==root.location.protocol&&root.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(e){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(e){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(e){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(e){}return!1};var trim="".trim?function(e){return e.trim()}:function(e){return e.replace(/(^\s*|\s*$)/g,"")};request.serializeObject=serialize,request.parseString=parseString,request.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},request.serialize={"application/x-www-form-urlencoded":serialize,"application/json":JSON.stringify},request.parse={"application/x-www-form-urlencoded":parseString,"application/json":JSON.parse},Response.prototype.get=function(e){return this.header[e.toLowerCase()]},Response.prototype._setHeaderProperties=function(e){var t=this.header["content-type"]||"";this.type=type(t);var r=params(t);for(var s in r)this[s]=r[s]},Response.prototype._parseBody=function(e){var t=request.parse[this.type];return!t&&isJSON(this.type)&&(t=request.parse["application/json"]),t&&e&&(e.length||e instanceof Object)?t(e):null},Response.prototype._setStatusProperties=function(e){1223===e&&(e=204);var t=e/100|0;this.status=this.statusCode=e,this.statusType=t,this.info=1==t,this.ok=2==t,this.clientError=4==t,this.serverError=5==t,this.error=4==t||5==t?this.toError():!1,this.accepted=202==e,this.noContent=204==e,this.badRequest=400==e,this.unauthorized=401==e,this.notAcceptable=406==e,this.notFound=404==e,this.forbidden=403==e},Response.prototype.toError=function(){var e=this.req,t=e.method,r=e.url,s="cannot "+t+" "+r+" ("+this.status+")",n=new Error(s);return n.status=this.status,n.method=t,n.url=r,n},request.Response=Response,Emitter(Request.prototype);for(var key in requestBase)Request.prototype[key]=requestBase[key];Request.prototype.type=function(e){return this.set("Content-Type",request.types[e]||e),this},Request.prototype.responseType=function(e){return this._responseType=e,this},Request.prototype.accept=function(e){return this.set("Accept",request.types[e]||e),this},Request.prototype.auth=function(e,t,r){switch(r||(r={type:"basic"}),r.type){case"basic":var s=btoa(e+":"+t);this.set("Authorization","Basic "+s);break;case"auto":this.username=e,this.password=t}return this},Request.prototype.query=function(e){return"string"!=typeof e&&(e=serialize(e)),e&&this._query.push(e),this},Request.prototype.attach=function(e,t,r){return this._getFormData().append(e,t,r||t.name),this},Request.prototype._getFormData=function(){return this._formData||(this._formData=new root.FormData),this._formData},Request.prototype.callback=function(e,t){var r=this._callback;this.clearTimeout(),r(e,t)},Request.prototype.crossDomainError=function(){var e=new Error("Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.");e.crossDomain=!0,e.status=this.status,e.method=this.method,e.url=this.url,this.callback(e)},Request.prototype._timeoutError=function(){var e=this._timeout,t=new Error("timeout of "+e+"ms exceeded");t.timeout=e,this.callback(t)},Request.prototype._appendQueryString=function(){var e=this._query.join("&");e&&(this.url+=~this.url.indexOf("?")?"&"+e:"?"+e)},Request.prototype.end=function(e){var t=this,r=this.xhr=request.getXHR(),s=this._timeout,n=this._formData||this._data;this._callback=e||noop,r.onreadystatechange=function(){if(4==r.readyState){var e;try{e=r.status}catch(s){e=0}if(0==e){if(t.timedout)return t._timeoutError();if(t._aborted)return;return t.crossDomainError()}t.emit("end")}};var i=function(e){e.total>0&&(e.percent=e.loaded/e.total*100),e.direction="download",t.emit("progress",e)};this.hasListeners("progress")&&(r.onprogress=i);try{r.upload&&this.hasListeners("progress")&&(r.upload.onprogress=i)}catch(o){}if(s&&!this._timer&&(this._timer=setTimeout(function(){t.timedout=!0,t.abort()},s)),this._appendQueryString(),this.username&&this.password?r.open(this.method,this.url,!0,this.username,this.password):r.open(this.method,this.url,!0),this._withCredentials&&(r.withCredentials=!0),"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof n&&!this._isHost(n)){var u=this._header["content-type"],a=this._serializer||request.serialize[u?u.split(";")[0]:""];!a&&isJSON(u)&&(a=request.serialize["application/json"]),a&&(n=a(n))}for(var h in this.header)null!=this.header[h]&&r.setRequestHeader(h,this.header[h]);return this._responseType&&(r.responseType=this._responseType),this.emit("request",this),r.send("undefined"!=typeof n?n:null),this},request.Request=Request,request.get=function(e,t,r){var s=request("GET",e);return"function"==typeof t&&(r=t,t=null),t&&s.query(t),r&&s.end(r),s},request.head=function(e,t,r){var s=request("HEAD",e);return"function"==typeof t&&(r=t,t=null),t&&s.send(t),r&&s.end(r),s},request.options=function(e,t,r){var s=request("OPTIONS",e);return"function"==typeof t&&(r=t,t=null),t&&s.send(t),r&&s.end(r),s},request.del=del,request["delete"]=del,request.patch=function(e,t,r){var s=request("PATCH",e);return"function"==typeof t&&(r=t,t=null),t&&s.send(t),r&&s.end(r),s},request.post=function(e,t,r){var s=request("POST",e);return"function"==typeof t&&(r=t,t=null),t&&s.send(t),r&&s.end(r),s},request.put=function(e,t,r){var s=request("PUT",e);return"function"==typeof t&&(r=t,t=null),t&&s.send(t),r&&s.end(r),s}; 145 | 146 | },{"./is-object":22,"./request":24,"./request-base":23,"emitter":5,"reduce":20}],22:[function(require,module,exports){ 147 | function isObject(e){return null!==e&&"object"==typeof e}module.exports=isObject; 148 | 149 | },{}],23:[function(require,module,exports){ 150 | var isObject=require("./is-object");exports.clearTimeout=function(){return this._timeout=0,clearTimeout(this._timer),this},exports.parse=function(t){return this._parser=t,this},exports.serialize=function(t){return this._serializer=t,this},exports.timeout=function(t){return this._timeout=t,this},exports.then=function(t,e){if(!this._fullfilledPromise){var i=this;this._fullfilledPromise=new Promise(function(t,e){i.end(function(i,r){i?e(i):t(r)})})}return this._fullfilledPromise.then(t,e)},exports.use=function(t){return t(this),this},exports.get=function(t){return this._header[t.toLowerCase()]},exports.getHeader=exports.get,exports.set=function(t,e){if(isObject(t)){for(var i in t)this.set(i,t[i]);return this}return this._header[t.toLowerCase()]=e,this.header[t]=e,this},exports.unset=function(t){return delete this._header[t.toLowerCase()],delete this.header[t],this},exports.field=function(t,e){return this._getFormData().append(t,e),this},exports.abort=function(){return this._aborted?this:(this._aborted=!0,this.xhr&&this.xhr.abort(),this.req&&this.req.abort(),this.clearTimeout(),this.emit("abort"),this)},exports.withCredentials=function(){return this._withCredentials=!0,this},exports.redirects=function(t){return this._maxRedirects=t,this},exports.toJSON=function(){return{method:this.method,url:this.url,data:this._data}},exports._isHost=function(t){var e={}.toString.call(t);switch(e){case"[object File]":case"[object Blob]":case"[object FormData]":return!0;default:return!1}},exports.send=function(t){var e=isObject(t),i=this._header["content-type"];if(e&&isObject(this._data))for(var r in t)this._data[r]=t[r];else"string"==typeof t?(i||this.type("form"),i=this._header["content-type"],"application/x-www-form-urlencoded"==i?this._data=this._data?this._data+"&"+t:t:this._data=(this._data||"")+t):this._data=t;return!e||this._isHost(t)?this:(i||this.type("json"),this)}; 151 | 152 | },{"./is-object":22}],24:[function(require,module,exports){ 153 | function request(e,n,t){return"function"==typeof t?new e("GET",n).end(t):2==arguments.length?new e("GET",n):new e(n,t)}module.exports=request; 154 | 155 | },{}],25:[function(require,module,exports){ 156 | "use strict";function Url(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}function urlParse(t,s,e){if(t&&util.isObject(t)&&t instanceof Url)return t;var h=new Url;return h.parse(t,s,e),h}function urlFormat(t){return util.isString(t)&&(t=urlParse(t)),t instanceof Url?t.format():Url.prototype.format.call(t)}function urlResolve(t,s){return urlParse(t,!1,!0).resolve(s)}function urlResolveObject(t,s){return t?urlParse(t,!1,!0).resolveObject(s):s}var punycode=require("punycode"),util=require("./util");exports.parse=urlParse,exports.resolve=urlResolve,exports.resolveObject=urlResolveObject,exports.format=urlFormat,exports.Url=Url;var protocolPattern=/^([a-z0-9.+-]+:)/i,portPattern=/:[0-9]*$/,simplePathPattern=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,delims=["<",">",'"',"`"," ","\r","\n"," "],unwise=["{","}","|","\\","^","`"].concat(delims),autoEscape=["'"].concat(unwise),nonHostChars=["%","/","?",";","#"].concat(autoEscape),hostEndingChars=["/","?","#"],hostnameMaxLen=255,hostnamePartPattern=/^[+a-z0-9A-Z_-]{0,63}$/,hostnamePartStart=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,unsafeProtocol={javascript:!0,"javascript:":!0},hostlessProtocol={javascript:!0,"javascript:":!0},slashedProtocol={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},querystring=require("querystring");Url.prototype.parse=function(t,s,e){if(!util.isString(t))throw new TypeError("Parameter 'url' must be a string, not "+typeof t);var h=t.indexOf("?"),r=-1!==h&&hm)&&(c=m)}var v,g;g=-1===c?n.lastIndexOf("@"):n.lastIndexOf("@",c),-1!==g&&(v=n.slice(0,g),n=n.slice(g+1),this.auth=decodeURIComponent(v)),c=-1;for(var f=0;fm)&&(c=m)}-1===c&&(c=n.length),this.host=n.slice(0,c),n=n.slice(c),this.parseHost(),this.hostname=this.hostname||"";var y="["===this.hostname[0]&&"]"===this.hostname[this.hostname.length-1];if(!y)for(var P=this.hostname.split(/\./),f=0,d=P.length;d>f;f++){var q=P[f];if(q&&!q.match(hostnamePartPattern)){for(var b="",O=0,j=q.length;j>O;O++)b+=q.charCodeAt(O)>127?"x":q[O];if(!b.match(hostnamePartPattern)){var x=P.slice(0,f),U=P.slice(f+1),C=q.match(hostnamePartStart);C&&(x.push(C[1]),U.unshift(C[2])),U.length&&(n="/"+U.join(".")+n),this.hostname=x.join(".");break}}}this.hostname.length>hostnameMaxLen?this.hostname="":this.hostname=this.hostname.toLowerCase(),y||(this.hostname=punycode.toASCII(this.hostname));var A=this.port?":"+this.port:"",w=this.hostname||"";this.host=w+A,this.href+=this.host,y&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==n[0]&&(n="/"+n))}if(!unsafeProtocol[u])for(var f=0,d=autoEscape.length;d>f;f++){var E=autoEscape[f];if(-1!==n.indexOf(E)){var I=encodeURIComponent(E);I===E&&(I=escape(E)),n=n.split(E).join(I)}}var R=n.indexOf("#");-1!==R&&(this.hash=n.substr(R),n=n.slice(0,R));var S=n.indexOf("?");if(-1!==S?(this.search=n.substr(S),this.query=n.substr(S+1),s&&(this.query=querystring.parse(this.query)),n=n.slice(0,S)):s&&(this.search="",this.query={}),n&&(this.pathname=n),slashedProtocol[u]&&this.hostname&&!this.pathname&&(this.pathname="/"),this.pathname||this.search){var A=this.pathname||"",k=this.search||"";this.path=A+k}return this.href=this.format(),this},Url.prototype.format=function(){var t=this.auth||"";t&&(t=encodeURIComponent(t),t=t.replace(/%3A/i,":"),t+="@");var s=this.protocol||"",e=this.pathname||"",h=this.hash||"",r=!1,a="";this.host?r=t+this.host:this.hostname&&(r=t+(-1===this.hostname.indexOf(":")?this.hostname:"["+this.hostname+"]"),this.port&&(r+=":"+this.port)),this.query&&util.isObject(this.query)&&Object.keys(this.query).length&&(a=querystring.stringify(this.query));var o=this.search||a&&"?"+a||"";return s&&":"!==s.substr(-1)&&(s+=":"),this.slashes||(!s||slashedProtocol[s])&&r!==!1?(r="//"+(r||""),e&&"/"!==e.charAt(0)&&(e="/"+e)):r||(r=""),h&&"#"!==h.charAt(0)&&(h="#"+h),o&&"?"!==o.charAt(0)&&(o="?"+o),e=e.replace(/[?#]/g,function(t){return encodeURIComponent(t)}),o=o.replace("#","%23"),s+r+e+o+h},Url.prototype.resolve=function(t){return this.resolveObject(urlParse(t,!1,!0)).format()},Url.prototype.resolveObject=function(t){if(util.isString(t)){var s=new Url;s.parse(t,!1,!0),t=s}for(var e=new Url,h=Object.keys(this),r=0;r0?e.host.split("@"):!1;b&&(e.auth=b.shift(),e.host=e.hostname=b.shift())}return e.search=t.search,e.query=t.query,util.isNull(e.pathname)&&util.isNull(e.search)||(e.path=(e.pathname?e.pathname:"")+(e.search?e.search:"")),e.href=e.format(),e}if(!d.length)return e.pathname=null,e.search?e.path="/"+e.search:e.path=null,e.href=e.format(),e;for(var O=d.slice(-1)[0],j=(e.host||t.host||d.length>1)&&("."===O||".."===O)||""===O,x=0,U=d.length;U>=0;U--)O=d[U],"."===O?d.splice(U,1):".."===O?(d.splice(U,1),x++):x&&(d.splice(U,1),x--);if(!y&&!P)for(;x--;x)d.unshift("..");!y||""===d[0]||d[0]&&"/"===d[0].charAt(0)||d.unshift(""),j&&"/"!==d.join("/").substr(-1)&&d.push("");var C=""===d[0]||d[0]&&"/"===d[0].charAt(0);if(q){e.hostname=e.host=C?"":d.length?d.shift():"";var b=e.host&&e.host.indexOf("@")>0?e.host.split("@"):!1;b&&(e.auth=b.shift(),e.host=e.hostname=b.shift())}return y=y||e.host&&d.length,y&&!C&&d.unshift(""),d.length?e.pathname=d.join("/"):(e.pathname=null,e.path=null),util.isNull(e.pathname)&&util.isNull(e.search)||(e.path=(e.pathname?e.pathname:"")+(e.search?e.search:"")),e.auth=t.auth||e.auth,e.slashes=e.slashes||t.slashes,e.href=e.format(),e},Url.prototype.parseHost=function(){var t=this.host,s=portPattern.exec(t);s&&(s=s[0],":"!==s&&(this.port=s.substr(1)),t=t.substr(0,t.length-s.length)),t&&(this.hostname=t)}; 157 | 158 | },{"./util":26,"punycode":12,"querystring":19}],26:[function(require,module,exports){ 159 | "use strict";module.exports={isString:function(n){return"string"==typeof n},isObject:function(n){return"object"==typeof n&&null!==n},isNull:function(n){return null===n},isNullOrUndefined:function(n){return null==n}}; 160 | 161 | },{}],27:[function(require,module,exports){ 162 | module.exports=function(o){return o&&"object"==typeof o&&"function"==typeof o.copy&&"function"==typeof o.fill&&"function"==typeof o.readUInt8}; 163 | 164 | },{}],28:[function(require,module,exports){ 165 | (function (process,global){ 166 | function inspect(e,r){var t={seen:[],stylize:stylizeNoColor};return arguments.length>=3&&(t.depth=arguments[2]),arguments.length>=4&&(t.colors=arguments[3]),isBoolean(r)?t.showHidden=r:r&&exports._extend(t,r),isUndefined(t.showHidden)&&(t.showHidden=!1),isUndefined(t.depth)&&(t.depth=2),isUndefined(t.colors)&&(t.colors=!1),isUndefined(t.customInspect)&&(t.customInspect=!0),t.colors&&(t.stylize=stylizeWithColor),formatValue(t,e,t.depth)}function stylizeWithColor(e,r){var t=inspect.styles[r];return t?"["+inspect.colors[t][0]+"m"+e+"["+inspect.colors[t][1]+"m":e}function stylizeNoColor(e,r){return e}function arrayToHash(e){var r={};return e.forEach(function(e,t){r[e]=!0}),r}function formatValue(e,r,t){if(e.customInspect&&r&&isFunction(r.inspect)&&r.inspect!==exports.inspect&&(!r.constructor||r.constructor.prototype!==r)){var n=r.inspect(t,e);return isString(n)||(n=formatValue(e,n,t)),n}var i=formatPrimitive(e,r);if(i)return i;var o=Object.keys(r),s=arrayToHash(o);if(e.showHidden&&(o=Object.getOwnPropertyNames(r)),isError(r)&&(o.indexOf("message")>=0||o.indexOf("description")>=0))return formatError(r);if(0===o.length){if(isFunction(r)){var u=r.name?": "+r.name:"";return e.stylize("[Function"+u+"]","special")}if(isRegExp(r))return e.stylize(RegExp.prototype.toString.call(r),"regexp");if(isDate(r))return e.stylize(Date.prototype.toString.call(r),"date");if(isError(r))return formatError(r)}var a="",c=!1,l=["{","}"];if(isArray(r)&&(c=!0,l=["[","]"]),isFunction(r)){var p=r.name?": "+r.name:"";a=" [Function"+p+"]"}if(isRegExp(r)&&(a=" "+RegExp.prototype.toString.call(r)),isDate(r)&&(a=" "+Date.prototype.toUTCString.call(r)),isError(r)&&(a=" "+formatError(r)),0===o.length&&(!c||0==r.length))return l[0]+a+l[1];if(0>t)return isRegExp(r)?e.stylize(RegExp.prototype.toString.call(r),"regexp"):e.stylize("[Object]","special");e.seen.push(r);var f;return f=c?formatArray(e,r,t,s,o):o.map(function(n){return formatProperty(e,r,t,s,n,c)}),e.seen.pop(),reduceToSingleString(f,a,l)}function formatPrimitive(e,r){if(isUndefined(r))return e.stylize("undefined","undefined");if(isString(r)){var t="'"+JSON.stringify(r).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(t,"string")}return isNumber(r)?e.stylize(""+r,"number"):isBoolean(r)?e.stylize(""+r,"boolean"):isNull(r)?e.stylize("null","null"):void 0}function formatError(e){return"["+Error.prototype.toString.call(e)+"]"}function formatArray(e,r,t,n,i){for(var o=[],s=0,u=r.length;u>s;++s)hasOwnProperty(r,String(s))?o.push(formatProperty(e,r,t,n,String(s),!0)):o.push("");return i.forEach(function(i){i.match(/^\d+$/)||o.push(formatProperty(e,r,t,n,i,!0))}),o}function formatProperty(e,r,t,n,i,o){var s,u,a;if(a=Object.getOwnPropertyDescriptor(r,i)||{value:r[i]},a.get?u=a.set?e.stylize("[Getter/Setter]","special"):e.stylize("[Getter]","special"):a.set&&(u=e.stylize("[Setter]","special")),hasOwnProperty(n,i)||(s="["+i+"]"),u||(e.seen.indexOf(a.value)<0?(u=isNull(t)?formatValue(e,a.value,null):formatValue(e,a.value,t-1),u.indexOf("\n")>-1&&(u=o?u.split("\n").map(function(e){return" "+e}).join("\n").substr(2):"\n"+u.split("\n").map(function(e){return" "+e}).join("\n"))):u=e.stylize("[Circular]","special")),isUndefined(s)){if(o&&i.match(/^\d+$/))return u;s=JSON.stringify(""+i),s.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(s=s.substr(1,s.length-2),s=e.stylize(s,"name")):(s=s.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),s=e.stylize(s,"string"))}return s+": "+u}function reduceToSingleString(e,r,t){var n=0,i=e.reduce(function(e,r){return n++,r.indexOf("\n")>=0&&n++,e+r.replace(/\u001b\[\d\d?m/g,"").length+1},0);return i>60?t[0]+(""===r?"":r+"\n ")+" "+e.join(",\n ")+" "+t[1]:t[0]+r+" "+e.join(", ")+" "+t[1]}function isArray(e){return Array.isArray(e)}function isBoolean(e){return"boolean"==typeof e}function isNull(e){return null===e}function isNullOrUndefined(e){return null==e}function isNumber(e){return"number"==typeof e}function isString(e){return"string"==typeof e}function isSymbol(e){return"symbol"==typeof e}function isUndefined(e){return void 0===e}function isRegExp(e){return isObject(e)&&"[object RegExp]"===objectToString(e)}function isObject(e){return"object"==typeof e&&null!==e}function isDate(e){return isObject(e)&&"[object Date]"===objectToString(e)}function isError(e){return isObject(e)&&("[object Error]"===objectToString(e)||e instanceof Error)}function isFunction(e){return"function"==typeof e}function isPrimitive(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||"undefined"==typeof e}function objectToString(e){return Object.prototype.toString.call(e)}function pad(e){return 10>e?"0"+e.toString(10):e.toString(10)}function timestamp(){var e=new Date,r=[pad(e.getHours()),pad(e.getMinutes()),pad(e.getSeconds())].join(":");return[e.getDate(),months[e.getMonth()],r].join(" ")}function hasOwnProperty(e,r){return Object.prototype.hasOwnProperty.call(e,r)}var formatRegExp=/%[sdj%]/g;exports.format=function(e){if(!isString(e)){for(var r=[],t=0;t=i)return e;switch(e){case"%s":return String(n[t++]);case"%d":return Number(n[t++]);case"%j":try{return JSON.stringify(n[t++])}catch(r){return"[Circular]"}default:return e}}),s=n[t];i>t;s=n[++t])o+=isNull(s)||!isObject(s)?" "+s:" "+inspect(s);return o},exports.deprecate=function(e,r){function t(){if(!n){if(process.throwDeprecation)throw new Error(r);process.traceDeprecation?console.trace(r):console.error(r),n=!0}return e.apply(this,arguments)}if(isUndefined(global.process))return function(){return exports.deprecate(e,r).apply(this,arguments)};if(process.noDeprecation===!0)return e;var n=!1;return t};var debugs={},debugEnviron;exports.debuglog=function(e){if(isUndefined(debugEnviron)&&(debugEnviron=process.env.NODE_DEBUG||""),e=e.toUpperCase(),!debugs[e])if(new RegExp("\\b"+e+"\\b","i").test(debugEnviron)){var r=process.pid;debugs[e]=function(){var t=exports.format.apply(exports,arguments);console.error("%s %d: %s",e,r,t)}}else debugs[e]=function(){};return debugs[e]},exports.inspect=inspect,inspect.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},inspect.styles={special:"cyan",number:"yellow","boolean":"yellow",undefined:"grey","null":"bold",string:"green",date:"magenta",regexp:"red"},exports.isArray=isArray,exports.isBoolean=isBoolean,exports.isNull=isNull,exports.isNullOrUndefined=isNullOrUndefined,exports.isNumber=isNumber,exports.isString=isString,exports.isSymbol=isSymbol,exports.isUndefined=isUndefined,exports.isRegExp=isRegExp,exports.isObject=isObject,exports.isDate=isDate,exports.isError=isError,exports.isFunction=isFunction,exports.isPrimitive=isPrimitive,exports.isBuffer=require("./support/isBuffer");var months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];exports.log=function(){console.log("%s - %s",timestamp(),exports.format.apply(exports,arguments))},exports.inherits=require("inherits"),exports._extend=function(e,r){if(!r||!isObject(r))return e;for(var t=Object.keys(r),n=t.length;n--;)e[t[n]]=r[t[n]];return e}; 167 | 168 | }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 169 | 170 | },{"./support/isBuffer":27,"_process":11,"inherits":7}]},{},[1])(1) 171 | }); 172 | //# sourceMappingURL=chai-http.min.js.map 173 | -------------------------------------------------------------------------------- /mocha-chai/lib/chai-json-schema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Chai-JSON-Schema plugin 3 | * v1.5.0 (2017-07-12) 4 | * http://chaijs.com/plugins/chai-json-schema/ 5 | * https://cdn.rawgit.com/chaijs/chai-json-schema/da14f449/index.js 6 | */ 7 | (function () { 8 | 'use strict'; 9 | /*jshint -W003*/ 10 | 11 | if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { 12 | // NodeJS 13 | module.exports = getPayload( 14 | require('tv4'), 15 | require('jsonpointer.js') 16 | ); 17 | } else if (typeof define === 'function' && define.amd) { 18 | // AMD 19 | define('chai-json-schema', [ 20 | 'tv4', 21 | 'jsonpointer' 22 | ], function (tv4, jsonpointer) { 23 | return getPayload(tv4, jsonpointer); 24 | }); 25 | } else { 26 | // Other environment (usually