[
  {
    "path": ".commitlintrc.js",
    "content": "module.exports = {\n  extends: ['@commitlint/config-conventional']\n};\n"
  },
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\ninsert_final_newline = true\nend_of_line = lf\ntrim_trailing_whitespace = true\nindent_style = space\nindent_size = 2\n\n[*.{js,json}]\nindent_size = 2\nindent_style = space\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"extends\": \"airbnb-base/legacy\",\n  \"env\": {\n    \"node\": true,\n    \"mocha\": true\n  },\n  \"parserOptions\": {\n    \"ecmaVersion\": 6\n  },\n  \"rules\": {\n    // disabled - disagree with airbnb\n    \"func-names\": [0],\n    \"space-before-function-paren\": [0],\n    \"consistent-return\": [0],\n\n    // Disabled but may want to refactor code eventually\n    \"no-use-before-define\": [2, \"nofunc\"],\n    \"no-underscore-dangle\": [0],\n\n    // IMHO, more sensible overrides to existing airbnb error definitions\n    \"max-len\": [2, 100, 4, {\"ignoreComments\": true, \"ignoreUrls\": true}],\n    \"no-unused-expressions\": [2, { \"allowShortCircuit\": true, \"allowTernary\": true }]\n  }\n}\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node\n# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions\n\nname: Node.js CI\n\non: [push, pull_request]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        include:\n          - node-version: 18.x\n          - node-version: 20.x\n          - node-version: 22.x\n          - node-version: 24.x\n\n    steps:\n    - uses: actions/checkout@v3\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v3\n      with:\n        node-version: ${{ matrix.node-version }}\n        path: ~/.npm\n        key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}\n    - name: Install Dependencies On Node ${{ matrix.node-version }}\n      run: yarn install\n    - run: npm test\n    - name: Coverage On Node ${{ matrix.node-version }}\n      run:\n        npm run coverage\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v3\n"
  },
  {
    "path": ".gitignore",
    "content": "#       OS        #\n###################\n.DS_Store\n.idea\nThumbs.db\ntmp/\ntemp/\n\n\n#     Node.js     #\n###################\nnode_modules\n\n\n#       NYC       #\n###################\ncoverage\n*.lcov\n.nyc_output\n\n\n#      Files      #\n###################\n*.log\n"
  },
  {
    "path": ".npmignore",
    "content": ".editorconfig\n.eslintrc\n.travis.yml\n.idea\n.vscode\n.nyc_output\ntest\ncoverage\n"
  },
  {
    "path": ".npmrc",
    "content": "package-lock=true\n"
  },
  {
    "path": "LICENSE",
    "content": "(The MIT License)\n\nCopyright (c) 2014 TJ Holowaychuk <tj@vision-media.ca> and other\ncontributors.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# [supertest](https://forwardemail.github.io/superagent/)\n\n[![build status](https://github.com/forwardemail/supertest/actions/workflows/ci.yml/badge.svg)](https://github.com/forwardemail/supertest/actions/workflows/ci.yml)\n[![code coverage](https://img.shields.io/codecov/c/github/ladjs/supertest.svg)](https://codecov.io/gh/ladjs/supertest)\n[![code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n[![made with lass](https://img.shields.io/badge/made_with-lass-95CC28.svg)](https://lass.js.org)\n[![license](https://img.shields.io/github/license/ladjs/supertest.svg)](LICENSE)\n\n> HTTP assertions made easy via [superagent](http://github.com/ladjs/superagent).  Maintained for [Forward Email](https://github.com/forwardemail) and [Lad](https://github.com/ladjs).\n\n## About\n\nThe motivation with this module is to provide a high-level abstraction for testing\nHTTP, while still allowing you to drop down to the [lower-level API](https://forwardemail.github.io/superagent/) provided by superagent.\n\n## Getting Started\n\nInstall supertest as an npm module and save it to your package.json file as a development dependency:\n\n```bash\nnpm install supertest --save-dev\n```\n\n  Once installed it can now be referenced by simply calling ```require('supertest');```\n\n## Example\n\nYou may pass an `http.Server`, or a `Function` to `request()` - if the server is not\nalready listening for connections then it is bound to an ephemeral port for you so\nthere is no need to keep track of ports.\n\nsupertest works with any test framework, here is an example without using any\ntest framework at all:\n\n```js\nconst request = require('supertest');\nconst express = require('express');\n\nconst app = express();\n\napp.get('/user', function(req, res) {\n  res.status(200).json({ name: 'john' });\n});\n\nrequest(app)\n  .get('/user')\n  .expect('Content-Type', /json/)\n  .expect('Content-Length', '15')\n  .expect(200)\n  .end(function(err, res) {\n    if (err) throw err;\n  });\n```\n\nTo enable http2 protocol, simply append an options to `request` or `request.agent`:\n\n```js\nconst request = require('supertest');\nconst express = require('express');\n\nconst app = express();\n\napp.get('/user', function(req, res) {\n  res.status(200).json({ name: 'john' });\n});\n\nrequest(app, { http2: true })\n  .get('/user')\n  .expect('Content-Type', /json/)\n  .expect('Content-Length', '15')\n  .expect(200)\n  .end(function(err, res) {\n    if (err) throw err;\n  });\n\nrequest.agent(app, { http2: true })\n  .get('/user')\n  .expect('Content-Type', /json/)\n  .expect('Content-Length', '15')\n  .expect(200)\n  .end(function(err, res) {\n    if (err) throw err;\n  });\n```\n\nHere's an example with mocha, note how you can pass `done` straight to any of the `.expect()` calls:\n\n```js\ndescribe('GET /user', function() {\n  it('responds with json', function(done) {\n    request(app)\n      .get('/user')\n      .set('Accept', 'application/json')\n      .expect('Content-Type', /json/)\n      .expect(200, done);\n  });\n});\n```\n\nYou can use `auth` method to pass HTTP username and password in the same way as in the [superagent](https://forwardemail.github.io/superagent/#authentication):\n\n```js\ndescribe('GET /user', function() {\n  it('responds with json', function(done) {\n    request(app)\n      .get('/user')\n      .auth('username', 'password')\n      .set('Accept', 'application/json')\n      .expect('Content-Type', /json/)\n      .expect(200, done);\n  });\n});\n```\n\nOne thing to note with the above statement is that superagent now sends any HTTP\nerror (anything other than a 2XX response code) to the callback as the first argument if\nyou do not add a status code expect (i.e. `.expect(302)`).\n\nIf you are using the `.end()` method `.expect()` assertions that fail will\nnot throw - they will return the assertion as an error to the `.end()` callback. In\norder to fail the test case, you will need to rethrow or pass `err` to `done()`, as follows:\n\n```js\ndescribe('POST /users', function() {\n  it('responds with json', function(done) {\n    request(app)\n      .post('/users')\n      .send({name: 'john'})\n      .set('Accept', 'application/json')\n      .expect('Content-Type', /json/)\n      .expect(200)\n      .end(function(err, res) {\n        if (err) return done(err);\n        return done();\n      });\n  });\n});\n```\n\nYou can also use promises:\n\n```js\ndescribe('GET /users', function() {\n  it('responds with json', function() {\n    return request(app)\n      .get('/users')\n      .set('Accept', 'application/json')\n      .expect('Content-Type', /json/)\n      .expect(200)\n      .then(response => {\n         expect(response.body.email).toEqual('foo@bar.com');\n      })\n  });\n});\n```\n\nOr async/await syntax:\n\n```js\ndescribe('GET /users', function() {\n  it('responds with json', async function() {\n    const response = await request(app)\n      .get('/users')\n      .set('Accept', 'application/json')\n    expect(response.headers[\"content-type\"]).toMatch(/json/);\n    expect(response.status).toEqual(200);\n    expect(response.body.email).toEqual('foo@bar.com');\n  });\n});\n```\n\nExpectations are run in the order of definition. This characteristic can be used\nto modify the response body or headers before executing an assertion.\n\n```js\ndescribe('POST /user', function() {\n  it('user.name should be an case-insensitive match for \"john\"', function(done) {\n    request(app)\n      .post('/user')\n      .send('name=john') // x-www-form-urlencoded upload\n      .set('Accept', 'application/json')\n      .expect(function(res) {\n        res.body.id = 'some fixed id';\n        res.body.name = res.body.name.toLowerCase();\n      })\n      .expect(200, {\n        id: 'some fixed id',\n        name: 'john'\n      }, done);\n  });\n});\n```\n\nAnything you can do with superagent, you can do with supertest - for example multipart file uploads!\n\n```js\nrequest(app)\n  .post('/')\n  .field('name', 'my awesome avatar')\n  .field('complex_object', '{\"attribute\": \"value\"}', {contentType: 'application/json'})\n  .attach('avatar', 'test/fixtures/avatar.jpg')\n  ...\n```\n\nPassing the app or url each time is not necessary, if you're testing\nthe same host you may simply re-assign the request variable with the\ninitialization app or url, a new `Test` is created per `request.VERB()` call.\n\n```js\nrequest = request('http://localhost:5555');\n\nrequest.get('/').expect(200, function(err){\n  console.log(err);\n});\n\nrequest.get('/').expect('heya', function(err){\n  console.log(err);\n});\n```\n\nHere's an example with mocha that shows how to persist a request and its cookies:\n\n```js\nconst request = require('supertest');\nconst should = require('should');\nconst express = require('express');\nconst cookieParser = require('cookie-parser');\n\ndescribe('request.agent(app)', function() {\n  const app = express();\n  app.use(cookieParser());\n\n  app.get('/', function(req, res) {\n    res.cookie('cookie', 'hey');\n    res.send();\n  });\n\n  app.get('/return', function(req, res) {\n    if (req.cookies.cookie) res.send(req.cookies.cookie);\n    else res.send(':(')\n  });\n\n  const agent = request.agent(app);\n\n  it('should save cookies', function(done) {\n    agent\n    .get('/')\n    .expect('set-cookie', 'cookie=hey; Path=/', done);\n  });\n\n  it('should send cookies', function(done) {\n    agent\n    .get('/return')\n    .expect('hey', done);\n  });\n});\n```\n\nThere is another example that is introduced by the file [agency.js](https://github.com/ladjs/superagent/blob/master/test/node/agency.js)\n\nHere is an example where 2 cookies are set on the request.\n\n```js\nagent(app)\n  .get('/api/content')\n  .set('Cookie', ['nameOne=valueOne;nameTwo=valueTwo'])\n  .send()\n  .expect(200)\n  .end((err, res) => {\n    if (err) {\n      return done(err);\n    }\n    expect(res.text).to.be.equal('hey');\n    return done();\n  });\n```\n\n## API\n\nYou may use any [superagent](http://github.com/ladjs/superagent) methods,\nincluding `.write()`, `.pipe()` etc and perform assertions in the `.end()` callback\nfor lower-level needs.\n\n### .expect(status[, fn])\n\nAssert response `status` code.\n\n### .expect(status, body[, fn])\n\nAssert response `status` code and `body`.\n\n### .expect(body[, fn])\n\nAssert response `body` text with a string, regular expression, or\nparsed body object.\n\n### .expect(field, value[, fn])\n\nAssert header `field` `value` with a string or regular expression.\n\n### .expect(function(res) {})\n\nPass a custom assertion function. It'll be given the response object to check. If the check fails, throw an error.\n\n```js\nrequest(app)\n  .get('/')\n  .expect(hasPreviousAndNextKeys)\n  .end(done);\n\nfunction hasPreviousAndNextKeys(res) {\n  if (!('next' in res.body)) throw new Error(\"missing next key\");\n  if (!('prev' in res.body)) throw new Error(\"missing prev key\");\n}\n```\n\n### .end(fn)\n\nPerform the request and invoke `fn(err, res)`.\n\n## Cookies\n\nHere is an example of using the `set` and `not` cookie assertions:\n\n```js\n// setup super-test\nconst request = require('supertest');\nconst express = require('express');\nconst cookies = request.cookies;\n\n// setup express test service\nconst app = express();\n\napp.get('/users', function(req, res) {\n  res.cookie('alpha', 'one', { domain: 'domain.com', path: '/', httpOnly: true });\n  res.send(200, { name: 'tobi' });\n});\n\n// test request to service\nrequest(app)\n  .get('/users')\n  .expect('Content-Type', /json/)\n  .expect('Content-Length', '15')\n  .expect(200)\n  // assert 'alpha' cookie is set with domain, path, and httpOnly options\n  .expect(cookies.set({ name: 'alpha', options: ['domain', 'path', 'httponly'] }))\n  // assert 'bravo' cookie is NOT set\n  .expect(cookies.not('set', { name: 'bravo' }))\n  .end(function(err, res) {\n    if (err) {\n      throw err;\n    }\n  });\n```\n\nIt is also possible to chain assertions:\n\n```js\ncookies.set({/* ... */}).not('set', {/* ... */})\n```\n\n### Cookie assertions\n\nFunctions and methods are chainable.\n\n#### cookies([secret], [asserts])\n\nGet assertion function for [super-test](https://github.com/visionmedia/supertest) `.expect()` method.\n\n*Arguments*\n\n- `secret` - String or array of strings. Cookie signature secrets.\n- `asserts(req, res)` - Function or array of functions. Failed custom assertions should throw.\n\n#### .set(expects, [assert])\n\nAssert that cookie and options are set.\n\n*Arguments*\n\n- `expects` - Object or array of objects.\n  - `name` - String name of cookie.\n  - `options` - *Optional* array of options.\n- `assert` - *Optional* boolean \"assert true\" modifier. Default: `true`.\n\n#### .reset(expects, [assert])\n\nAssert that cookie is set and was already set (in request headers).\n\n*Arguments*\n\n- `expects` - Object or array of objects.\n  - `name` - String name of cookie.\n- `assert` - *Optional* boolean \"assert true\" modifier. Default: `true`.\n\n#### .new(expects, [assert])\n\nAssert that cookie is set and was NOT already set (NOT in request headers).\n\n*Arguments*\n\n- `expects` - Object or array of objects.\n  - `name` - String name of cookie.\n- `assert` - *Optional* boolean \"assert true\" modifier. Default: `true`.\n\n#### .renew(expects, [assert])\n\nAssert that cookie is set with a strictly greater `expires` or `max-age` than the given value.\n\n*Arguments*\n\n- `expects` - Object or array of objects.\n  - `name` - String name of cookie.\n  - `options` - Object of options. `use one of two options below`\n  - `options`.`expires` - String UTC expiration for original cookie (in request headers).\n  - `options`.`max-age` - Integer ttl in seconds for original cookie (in request headers).\n- `assert` - *Optional* boolean \"assert true\" modifier. Default: `true`.\n\n#### .contain(expects, [assert])\n\nAssert that cookie is set with value and contains options.\n\nRequires `cookies(secret)` initialization if cookie is signed.\n\n*Arguments*\n\n- `expects` - Object or array of objects.\n  - `name` - String name of cookie.\n  - `value` - *Optional* string unsigned value of cookie.\n  - `options` - *Optional* object of options.\n  - `options`.`domain` - *Optional* string domain.\n  - `options`.`path` - *Optional* string path.\n  - `options`.`expires` - *Optional* string UTC expiration.\n  - `options`.`max-age` - *Optional* integer ttl, in seconds.\n  - `options`.`secure` - *Optional* boolean secure flag.\n  - `options`.`httponly` - *Optional* boolean httpOnly flag.\n- `assert` - *Optional* boolean \"assert true\" modifier. Default: `true`.\n\n#### .not(method, expects)\n\nCall any cookies assertion method with \"assert true\" modifier set to `false`.\n\nSyntactic sugar.\n\n*Arguments*\n\n- `method` - String method name. Arguments of method name apply in `expects`.\n- `expects` - Object or array of objects.\n  - `name` - String name of cookie.\n  - `value` - *Optional* string unsigned value of cookie.\n  - `options` - *Optional* object of options.\n\n## Notes\n\nInspired by [api-easy](https://github.com/flatiron/api-easy) minus vows coupling.\n\n## License\n\nMIT\n\n[coverage-badge]: https://img.shields.io/codecov/c/github/ladjs/supertest.svg\n[coverage]: https://codecov.io/gh/ladjs/supertest\n[travis-badge]: https://travis-ci.org/ladjs/supertest.svg?branch=master\n[travis]: https://travis-ci.org/ladjs/supertest\n[dependencies-badge]: https://david-dm.org/ladjs/supertest/status.svg\n[dependencies]: https://david-dm.org/ladjs/supertest\n[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square\n[prs]: http://makeapullrequest.com\n[license-badge]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square\n[license]: https://github.com/ladjs/supertest/blob/master/LICENSE\n"
  },
  {
    "path": "ci/remove-deps-4-old-node.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst package = require('../package.json');\n\nconst UNSUPPORT_DEPS_4_OLD = {\n  'eslint': undefined,\n  'mocha': '6.x'\n};\n\nconst deps = Object.keys(UNSUPPORT_DEPS_4_OLD);\nfor (const item in package.devDependencies) {\n  if (deps.includes(item)) {\n    package.devDependencies[item] = UNSUPPORT_DEPS_4_OLD[item];\n  }\n}\n\ndelete package.scripts.lint;\n\nfs.writeFileSync(\n  path.join(__dirname, '../package.json'),\n  JSON.stringify(package, null, 2)\n);\n"
  },
  {
    "path": "index.js",
    "content": "'use strict';\n\n/**\n * Module dependencies.\n */\nconst methods = require('methods');\nlet http2;\ntry {\n  http2 = require('http2'); // eslint-disable-line global-require\n} catch (_) {\n  // eslint-disable-line no-empty\n}\nconst Test = require('./lib/test.js');\nconst agent = require('./lib/agent.js');\nconst cookies = require('./lib/cookies');\n\n/**\n * Test against the given `app`,\n * returning a new `Test`.\n *\n * @param {Function|Server|String} app\n * @return {Test}\n * @api public\n */\nmodule.exports = function(app, options = {}) {\n  const obj = {};\n\n  if (typeof app === 'function') {\n    if (options.http2) {\n      if (!http2) {\n        throw new Error(\n          'supertest: this version of Node.js does not support http2'\n        );\n      }\n    }\n  }\n\n  methods.forEach(function(method) {\n    obj[method] = function(url) {\n      var test = new Test(app, method, url, options.http2);\n      if (options.http2) {\n        test.http2();\n      }\n      return test;\n    };\n  });\n\n  // Support previous use of del\n  obj.del = obj.delete;\n\n  return obj;\n};\n\n/**\n * Expose `Test`\n */\nmodule.exports.Test = Test;\n\n/**\n * Expose the agent function\n */\nmodule.exports.agent = agent;\n\n/**\n * Expose cookie assertions\n */\nmodule.exports.cookies = cookies;\n"
  },
  {
    "path": "lib/agent.js",
    "content": "'use strict';\n\n/**\n * Module dependencies.\n */\n\nconst { agent: Agent } = require('superagent');\nconst methods = require('methods');\nconst http = require('http');\nlet http2;\ntry {\n  http2 = require('http2'); // eslint-disable-line global-require\n} catch (_) {\n  // eslint-disable-line no-empty\n}\nconst Test = require('./test.js');\n\n/**\n * Initialize a new `TestAgent`.\n *\n * @param {Function|Server} app\n * @param {Object} options\n * @api public\n */\n\nfunction TestAgent(app, options = {}) {\n  if (!(this instanceof TestAgent)) return new TestAgent(app, options);\n\n  const agent = new Agent(options);\n  Object.assign(this, agent);\n\n  this._options = options;\n\n  if (typeof app === 'function') {\n    if (options.http2) {\n      if (!http2) {\n        throw new Error(\n          'supertest: this version of Node.js does not support http2'\n        );\n      }\n      app = http2.createServer(app); // eslint-disable-line no-param-reassign\n    } else {\n      app = http.createServer(app); // eslint-disable-line no-param-reassign\n    }\n  }\n  this.app = app;\n}\n\n/**\n * Inherits from `Agent.prototype`.\n */\n\nObject.setPrototypeOf(TestAgent.prototype, Agent.prototype);\n\n// Preserve the original query method before overriding HTTP methods\nconst originalQuery = Agent.prototype.query;\n\n// set a host name\nTestAgent.prototype.host = function(host) {\n  this._host = host;\n  return this;\n};\n\n// override HTTP verb methods\nmethods.forEach(function(method) {\n  // Skip 'query' method to prevent overwriting superagent's query functionality\n  if (method === 'query') {\n    return;\n  }\n\n  TestAgent.prototype[method] = function(url, fn) { // eslint-disable-line no-unused-vars\n    const req = new Test(this.app, method.toUpperCase(), url);\n    if (this._options.http2) {\n      req.http2();\n    }\n\n    if (this._host) {\n      req.set('host', this._host);\n    }\n\n    req.on('response', this._saveCookies.bind(this));\n    req.on('redirect', this._saveCookies.bind(this));\n    req.on('redirect', this._attachCookies.bind(this, req));\n    this._setDefaults(req);\n    this._attachCookies(req);\n\n    return req;\n  };\n});\n\n// Restore the original query method\nTestAgent.prototype.query = originalQuery;\n\nTestAgent.prototype.del = TestAgent.prototype.delete;\n\n/**\n * Expose `Agent`.\n */\n\nmodule.exports = TestAgent;\n"
  },
  {
    "path": "lib/cookies/assertion.js",
    "content": "/** Copyright 2015 Gregory Langlais. See LICENSE.txt. */\n\n'use strict';\n\nconst signature = require('cookie-signature');\n\n/**\n * Assert that an object has specific properties (supports array of keys or object)\n *\n * @param {object} obj\n * @param {object|array} props\n */\nfunction assertHasProperties(obj, props) {\n  if (Array.isArray(props)) {\n    props.forEach(function (key) {\n      if (!(key in obj)) {\n        throw new Error('expected object to have property ' + key);\n      }\n    });\n  } else {\n    Object.keys(props).forEach(function (key) {\n      if (!(key in obj)) {\n        throw new Error('expected object to have property ' + key);\n      }\n    });\n  }\n}\n\n/**\n * Assert that an object does not have specific properties (supports array of keys or object)\n * When checking with empty props, throws if object exists (matches should.js behavior)\n *\n * @param {object} obj\n * @param {object|array} props\n */\nfunction assertNotHasProperties(obj, props) {\n  if (Array.isArray(props)) {\n    // When empty array is passed, should.js throws 'false negative fail' if object exists\n    if (props.length === 0) {\n      throw new Error('expected object to not have properties (false negative fail)');\n    }\n    props.forEach(function (key) {\n      if (key in obj) {\n        throw new Error('expected object to not have property ' + key);\n      }\n    });\n  } else {\n    // When empty object is passed, should.js throws 'false negative fail' if object exists\n    let keys = Object.keys(props);\n    if (keys.length === 0) {\n      throw new Error('expected object to not have properties (false negative fail)');\n    }\n    keys.forEach(function (key) {\n      if (key in obj) {\n        throw new Error('expected object to not have property ' + key);\n      }\n    });\n  }\n}\n\n/**\n * Assert that two values are equal\n *\n * @param {*} actual\n * @param {*} expected\n */\nfunction assertEqual(actual, expected) {\n  if (actual !== expected) {\n    throw new Error(\n      'expected ' + JSON.stringify(actual) + ' to equal ' + JSON.stringify(expected)\n    );\n  }\n}\n\n/**\n * Assert that two values are not equal\n *\n * @param {*} actual\n * @param {*} expected\n */\nfunction assertNotEqual(actual, expected) {\n  if (actual === expected) {\n    throw new Error(\n      'expected ' + JSON.stringify(actual) + ' to not equal ' + JSON.stringify(expected)\n    );\n  }\n}\n\n/**\n * Build Assertion function\n *\n * {object|object[]} expects cookies\n * {string} expects.<name> and value of cookie\n * {object} expects.options\n * {string} [expects.options.domain]\n * {string} [expects.options.path]\n * {string} [expects.options.expires] UTC string using date.toUTCString()\n * {number} [expects.options.max-age]\n * {boolean} [expects.options.secure]\n * {boolean} [expects.options.httponly]\n * {string|string[]} [expects.secret]\n *\n * @param {null|string|string[]} [secret]\n * @param {function|function[]} [asserts]\n * @returns {Assertion}\n */\nmodule.exports = function (secret, asserts) {\n  let assertions = [];\n\n  if (typeof secret === 'string') secret = [secret]; // eslint-disable-line no-param-reassign\n  else if (!Array.isArray(secret)) secret = []; // eslint-disable-line no-param-reassign\n\n  if (Array.isArray(asserts)) assertions = asserts;\n  else if (typeof asserts === 'function') assertions.push(asserts);\n\n  /**\n   * Assertion function with static chainable methods\n   *\n   * @param {object} res\n   * @returns {undefined|string}\n   * @constructor\n   */\n  function Assertion(res) {\n    if (typeof res !== 'object') throw new Error('res argument must be object');\n\n    // request and response object initialization\n    let request = {\n      headers: res.req.getHeaders(),\n      cookies: []\n    };\n\n    let response = {\n      headers: res.headers,\n      cookies: []\n    };\n\n    // build assertions request object\n    if (request.headers.cookie) {\n      const cookies = String(request.headers.cookie);\n      cookies.split(/; */).forEach(function (cookie) {\n        request.cookies.push(Assertion.parse(cookie));\n      });\n    }\n\n    // build assertions response object\n    if (\n      Array.isArray(response.headers['set-cookie'])\n      && response.headers['set-cookie'].length > 0\n    ) {\n      response.headers['set-cookie'].forEach(function (val) {\n        response.cookies.push(Assertion.parse(val));\n      });\n    }\n\n    // run assertions\n    let result;\n    assertions.every(function (assertion) {\n      result = assertion(request, response);\n      return (typeof (result) !== 'string');\n    });\n\n    return result;\n  }\n\n  /**\n   * Find cookie in stack/array\n   *\n   * @param {string} name\n   * @param {array} stack\n   * @returns {object|undefined} cookie\n   */\n  Assertion.find = function (name, stack) {\n    let cookie;\n\n    stack.every(function (val) {\n      if (name !== val.name) return true;\n      cookie = val;\n      return false;\n    });\n\n    return cookie;\n  };\n\n  /**\n   * Parse cookie string\n   *\n   * @param {string} str\n   * @param {object} [options]\n   * @param {function} [options.decode] uri\n   * @param {undefined|boolean} [options.request] headers\n   * @returns {object}\n   */\n  Assertion.parse = function (str, options) {\n    if (typeof str !== 'string') throw new TypeError('argument str must be a string');\n\n    if (typeof options !== 'object') options = {}; // eslint-disable-line no-param-reassign\n\n    let decode = options.decode || decodeURIComponent;\n\n    let parts = str.split(/; */);\n\n    let cookie = {};\n\n    parts.forEach(function (part, i) {\n      if (i === 1) cookie.options = {};\n\n      let equalsIndex = part.indexOf('=');\n\n      // things that don't look like key=value get true flag\n      if (equalsIndex < 0) {\n        cookie.options[part.trim().toLowerCase()] = true;\n        return;\n      }\n\n      const key = part.substr(0, equalsIndex).trim().toLowerCase();\n      // only assign once\n      if (typeof cookie[key] !== 'undefined') return;\n\n      equalsIndex += 1;\n      let val = part.substr(equalsIndex, part.length).trim();\n      // quoted values\n      if (val[0] === '\"') val = val.slice(1, -1);\n\n      let value;\n      try {\n        value = decode(val);\n      } catch (e) {\n        value = val;\n      }\n\n      if (i > 0) {\n        cookie.options[key] = value;\n        return;\n      }\n\n      cookie.name = key;\n      cookie.value = decode(val);\n    });\n\n    if (typeof cookie.options === 'undefined') cookie.options = {};\n\n    return cookie;\n  };\n\n  /**\n   * Iterate expects\n   *\n   * @param {object|object[]} expects\n   * @param {boolean|function} hasValues\n   * @param {function} [cb]\n   */\n  Assertion.expects = function (expects, hasValues, cb) {\n    if (!Array.isArray(expects) && typeof expects === 'object') expects = [expects]; // eslint-disable-line no-param-reassign\n\n    let resolvedCb;\n    let resolvedHasValues;\n    if (typeof cb === 'undefined' && typeof hasValues === 'function') {\n      resolvedCb = hasValues;\n      resolvedHasValues = false;\n    } else {\n      resolvedCb = cb;\n      resolvedHasValues = hasValues;\n    }\n\n    expects.forEach(function (expect) {\n      let options = expect.options;\n      if (typeof options !== 'object' && !Array.isArray(options)) {\n        options = (resolvedHasValues) ? {} : [];\n      }\n\n      resolvedCb(Object.assign({}, expect, { options }));\n    });\n  };\n\n  /**\n   * Assert cookies and options are set\n   *\n   * @param {object|object[]} expects cookies\n   * @param {undefined|boolean} [assert]\n   * @returns {function} Assertion\n   */\n  Assertion.set = function (expects, assert) {\n    if (typeof assert === 'undefined') assert = true; // eslint-disable-line no-param-reassign\n\n    Assertion.expects(expects, function (expect) {\n      assertions.push(function (req, res) {\n        // get expectation cookie\n        const cookie = Assertion.find(expect.name, res.cookies);\n\n        if (assert && !cookie) throw new Error('expected: ' + expect.name + ' cookie to be set');\n\n        if (assert) assertHasProperties(cookie.options, expect.options);\n        else if (cookie) assertNotHasProperties(cookie.options, expect.options);\n      });\n    });\n\n    return Assertion;\n  };\n\n  /**\n   * Assert cookies has been reset\n   *\n   * @param {object|object[]} expects cookies\n   * @param {undefined|boolean} [assert]\n   * @returns {function} Assertion\n   */\n  Assertion.reset = function (expects, assert) {\n    if (typeof assert === 'undefined') assert = true; // eslint-disable-line no-param-reassign\n\n    Assertion.expects(expects, function (expect) {\n      assertions.push(function (req, res) {\n        // get sent cookie\n        const cookieReq = Assertion.find(expect.name, req.cookies);\n        // get expectation cookie\n        const cookieRes = Assertion.find(expect.name, res.cookies);\n\n        if (assert && (!cookieReq || !cookieRes)) {\n          throw new Error('expected: ' + expect.name + ' cookie to be set');\n        } else if (!assert && cookieReq && cookieRes) {\n          throw new Error('expected: ' + expect.name + ' cookie to be set');\n        }\n      });\n    });\n\n    return Assertion;\n  };\n\n  /**\n   * Assert cookies is set and new\n   *\n   * @param {object|object[]} expects cookies\n   * @param {undefined|boolean} [assert]\n   * @returns {function} Assertion\n   */\n  Assertion.new = function (expects, assert) {\n    if (typeof assert === 'undefined') assert = true; // eslint-disable-line no-param-reassign\n\n    Assertion.expects(expects, function (expect) {\n      assertions.push(function (req, res) {\n        // get sent cookie\n        const cookieReq = Assertion.find(expect.name, req.cookies);\n        // get expectation cookie\n        const cookieRes = Assertion.find(expect.name, res.cookies);\n\n        if (assert) {\n          if (!cookieRes) throw new Error('expected: ' + expect.name + ' cookie to be set');\n          if (cookieReq && cookieRes) {\n            throw new Error('expected: ' + expect.name + ' cookie to NOT already be set');\n          }\n        } else if (!cookieReq || !cookieRes) {\n          throw new Error('expected: ' + expect.name + ' cookie to be set');\n        }\n      });\n    });\n\n    return Assertion;\n  };\n\n  /**\n   * Assert cookies expires or max-age has increased\n   *\n   * @param {object|object[]} expects cookies\n   * @param {undefined|boolean} [assert]\n   * @returns {function} Assertion\n   */\n  Assertion.renew = function (expects, assert) {\n    if (typeof assert === 'undefined') assert = true; // eslint-disable-line no-param-reassign\n\n    Assertion.expects(expects, true, function (expect) {\n      const expectExpires = new Date(expect.options.expires);\n      const expectMaxAge = parseFloat(expect.options['max-age']);\n\n      let baseMessage = 'expected: ' + expect.name;\n      if (!expectExpires.getTime() && !expectMaxAge) {\n        throw new Error(baseMessage + ' expects to have expires or max-age option');\n      }\n\n      assertions.push(function (req, res) {\n        // get sent cookie\n        const cookieReq = Assertion.find(expect.name, req.cookies);\n        // get expectation cookie\n        const cookieRes = Assertion.find(expect.name, res.cookies);\n\n        const cookieMaxAge = (expectMaxAge && cookieRes)\n          ? parseFloat(cookieRes.options['max-age'])\n          : undefined;\n        const cookieExpires = (expectExpires.getTime() && cookieRes)\n          ? new Date(cookieRes.options.expires)\n          : undefined;\n\n        if (assert) {\n          if (!cookieReq || !cookieRes) {\n            throw new Error(baseMessage + ' cookie to be set');\n          }\n          if (expectMaxAge && (!cookieMaxAge || cookieMaxAge <= expectMaxAge)) {\n            throw new Error(baseMessage + ' cookie max-age to be greater than existing value');\n          }\n\n          if (\n            expectExpires.getTime()\n            && (!cookieExpires.getTime() || cookieExpires <= expectExpires)\n          ) {\n            throw new Error(baseMessage + ' cookie expires to be greater than existing value');\n          }\n        } else if (cookieRes) {\n          if (expectMaxAge && cookieMaxAge > expectMaxAge) {\n            throw new Error(\n              baseMessage + ' cookie max-age to be less than or equal to existing value'\n            );\n          }\n\n          if (expectExpires.getTime() && cookieExpires > expectExpires) {\n            throw new Error(\n              baseMessage + ' cookie expires to be less than or equal to existing value'\n            );\n          }\n        }\n      });\n    });\n\n    return Assertion;\n  };\n\n  /**\n   * Assert cookies contains values\n   *\n   * @param {object|object[]} expects cookies\n   * @param {undefined|boolean} [assert]\n   * @returns {function} Assertion\n   */\n  Assertion.contain = function (expects, assert) {\n    if (typeof assert === 'undefined') assert = true; // eslint-disable-line no-param-reassign\n\n    Assertion.expects(expects, function (expect) {\n      const keys = Object.keys(expect.options);\n\n      assertions.push(function (req, res) {\n        // get expectation cookie\n        const cookie = Assertion.find(expect.name, res.cookies);\n\n        if (!cookie) throw new Error('expected: ' + expect.name + ' cookie to be set');\n\n        // check cookie values are equal\n        if ('value' in expect) {\n          try {\n            if (assert) assertEqual(cookie.value, expect.value);\n            else assertNotEqual(cookie.value, expect.value);\n          } catch (e) {\n            if (secret.length) {\n              let value;\n              secret.every(function (sec) {\n                value = signature.unsign(cookie.value.slice(2), sec);\n                return !(value && value === expect.value);\n              });\n\n              if (assert && !value) {\n                throw new Error('expected: ' + expect.name + ' value to equal ' + expect.value);\n              } else if (!assert && value) {\n                throw new Error('expected: ' + expect.name + ' value to NOT equal ' + expect.value);\n              }\n            } else throw e;\n          }\n        }\n\n        keys.forEach(function (key) {\n          const expected = (\n            key === 'max-age'\n              ? expect.options[key].toString()\n              : expect.options[key]\n          );\n          if (assert) assertEqual(cookie.options[key], expected);\n          else assertNotEqual(cookie.options[key], expected);\n        });\n      });\n    });\n\n    return Assertion;\n  };\n\n  /**\n   * Assert NOT modifier\n   *\n   * @param {function} method\n   * @param {...*}\n   */\n  Assertion.not = function (method) {\n    let args = [];\n\n    for (let i = 1; i < arguments.length; i += 1) args.push(arguments[i]);\n\n    args.push(false);\n\n    return Assertion[method].apply(Assertion, args);\n  };\n\n  return Assertion;\n};\n"
  },
  {
    "path": "lib/cookies/index.js",
    "content": "/** Copyright 2015 Gregory Langlais. See LICENSE.txt. */\n\n'use strict';\n\nconst Assertion = require('./assertion');\n\n/**\n * Construct cookies assertion (function)\n *\n * @param {null|string|string[]} [secret]\n * @param {function(req, res)[]} [asserts] ran within returned assertion function\n * @returns {function} assertion\n * @constructor\n */\nfunction ExpectCookies(secret, asserts) {\n  return Assertion(secret, asserts);\n}\n\n// build ExpectCookies proxy methods\nconst assertion = Assertion();\nconst methods = Object.getOwnPropertyNames(assertion);\n\nmethods.forEach(function(method) {\n  if (typeof assertion[method] === 'function' && typeof Function[method] === 'undefined') {\n    ExpectCookies[method] = function() {\n      const newAssertion = Assertion();\n      return newAssertion[method].apply(newAssertion, arguments);\n    };\n  }\n});\n\nmodule.exports = ExpectCookies;\n"
  },
  {
    "path": "lib/test.js",
    "content": "'use strict';\n\n/**\n * Module dependencies.\n */\n\nconst { inspect } = require('util');\nconst http = require('http');\nconst { STATUS_CODES } = require('http');\nconst { Server } = require('tls');\nconst { deepStrictEqual } = require('assert');\nconst { Request } = require('superagent');\nlet http2;\ntry {\n  http2 = require('http2'); // eslint-disable-line global-require\n} catch (_) {\n  // eslint-disable-line no-empty\n}\n\n/** @typedef {import('superagent').Response} Response */\n\nclass Test extends Request {\n  /**\n   * Initialize a new `Test` with the given `app`,\n   * request `method` and `path`.\n   *\n   * @param {Server} app\n   * @param {String} method\n   * @param {String} path\n   * @api public\n   */\n  constructor (app, method, path, optHttp2) {\n    super(method.toUpperCase(), path);\n\n    if (typeof app === 'function') {\n      if (optHttp2) {\n        app = http2.createServer(app); // eslint-disable-line no-param-reassign\n      } else {\n        app = http.createServer(app); // eslint-disable-line no-param-reassign\n      }\n    }\n\n    this.redirects(0);\n    this.buffer();\n    this.app = app;\n    this._asserts = [];\n    this.url = typeof app === 'string'\n      ? app + path\n      : this.serverAddress(app, path);\n  }\n\n  /**\n   * Returns a URL, extracted from a server.\n   *\n   * @param {Server} app\n   * @param {String} path\n   * @returns {String} URL address\n   * @api private\n   */\n  serverAddress(app, path) {\n    const addr = app.address();\n\n    if (!addr) this._server = app.listen(0);\n    // } else {\n    //   this._server = app;\n    // }\n    const port = app.address().port;\n    const protocol = app instanceof Server ? 'https' : 'http';\n    return protocol + '://127.0.0.1:' + port + path;\n  }\n\n  /**\n   * Expectations:\n   *\n   *   .expect(200)\n   *   .expect(200, fn)\n   *   .expect(200, body)\n   *   .expect('Some body')\n   *   .expect('Some body', fn)\n   *   .expect(['json array body', { key: 'val' }])\n   *   .expect('Content-Type', 'application/json')\n   *   .expect('Content-Type', 'application/json', fn)\n   *   .expect(fn)\n   *   .expect([200, 404])\n   *\n   * @return {Test}\n   * @api public\n   */\n  expect(a, b, c) {\n    // callback\n    if (typeof a === 'function') {\n      this._asserts.push(wrapAssertFn(a));\n      return this;\n    }\n    if (typeof b === 'function') this.end(b);\n    if (typeof c === 'function') this.end(c);\n\n    // status\n    if (typeof a === 'number') {\n      this._asserts.push(wrapAssertFn(this._assertStatus.bind(this, a)));\n      // body\n      if (typeof b !== 'function' && arguments.length > 1) {\n        this._asserts.push(wrapAssertFn(this._assertBody.bind(this, b)));\n      }\n      return this;\n    }\n\n    // multiple statuses\n    if (Array.isArray(a) && a.length > 0 && a.every(val => typeof val === 'number')) {\n      this._asserts.push(wrapAssertFn(this._assertStatusArray.bind(this, a)));\n      return this;\n    }\n\n    // header field\n    if (typeof b === 'string' || typeof b === 'number' || b instanceof RegExp) {\n      this._asserts.push(wrapAssertFn(this._assertHeader.bind(this, { name: '' + a, value: b })));\n      return this;\n    }\n\n    // body\n    this._asserts.push(wrapAssertFn(this._assertBody.bind(this, a)));\n\n    return this;\n  }\n\n  /**\n   * Defer invoking superagent's `.end()` until\n   * the server is listening.\n   *\n   * @param {?Function} fn\n   * @api public\n   */\n  end(fn) {\n    const server = this._server;\n\n    super.end((err, res) => {\n      const localAssert = () => {\n        this.assert(err, res, fn);\n      };\n\n      if (server && server._handle) {\n        // Handle server closing with error handling for already closed servers\n        return server.close((closeError) => {\n          // Ignore ERR_SERVER_NOT_RUNNING errors as the server is already closed\n          if (closeError && closeError.code === 'ERR_SERVER_NOT_RUNNING') {\n            return localAssert();\n          }\n          // For other errors, pass them through\n          if (closeError) {\n            return localAssert();\n          }\n          localAssert();\n        });\n      }\n\n      localAssert();\n    });\n\n    return this;\n  }\n\n  /**\n   * Perform assertions and invoke `fn(err, res)`.\n   *\n   * @param {?Error} resError\n   * @param {Response} res\n   * @param {Function} fn\n   * @api private\n   */\n  assert(resError, res, fn) {\n    let errorObj;\n\n    // check for unexpected network errors or server not running/reachable errors\n    // when there is no response and superagent sends back a System Error\n    // do not check further for other asserts, if any, in such case\n    // https://nodejs.org/api/errors.html#errors_common_system_errors\n    const sysErrors = {\n      ECONNREFUSED: 'Connection refused',\n      ECONNRESET: 'Connection reset by peer',\n      EPIPE: 'Broken pipe',\n      ETIMEDOUT: 'Operation timed out'\n    };\n\n    if (!res && resError) {\n      if (resError instanceof Error && resError.syscall === 'connect'\n        && Object.getOwnPropertyNames(sysErrors).indexOf(resError.code) >= 0) {\n        errorObj = new Error(resError.code + ': ' + sysErrors[resError.code]);\n      } else {\n        errorObj = resError;\n      }\n    }\n\n    // asserts\n    for (let i = 0; i < this._asserts.length && !errorObj; i += 1) {\n      errorObj = this._assertFunction(this._asserts[i], res);\n    }\n\n    // set unexpected superagent error if no other error has occurred.\n    if (!errorObj && resError instanceof Error && (!res || resError.status !== res.status)) {\n      errorObj = resError;\n    }\n\n    if (fn) {\n      fn.call(this, errorObj || null, res);\n    }\n  }\n\n  /*\n    * Adds a set Authorization Bearer\n    *\n    * @param {Bearer} Bearer Token\n    * Shortcut for .set('Authorization', `Bearer ${token}`)\n    */\n\n  bearer(token) {\n    this.set('Authorization', `Bearer ${token}`);\n    return this;\n  }\n\n  /*\n    * Adds a set Authorization Bearer\n    *\n    * @param {Bearer} Bearer Token\n    * Shortcut for .set('Authorization', `Bearer ${token}`)\n    */\n\n  bearer(token) {\n    this.set('Authorization', `Bearer ${token}`);\n    return this;\n  }\n\n  /**\n   * Perform assertions on a response body and return an Error upon failure.\n   *\n   * @param {Mixed} body\n   * @param {Response} res\n   * @return {?Error}\n   * @api private\n   */// eslint-disable-next-line class-methods-use-this\n  _assertBody(body, res) {\n    const isRegexp = body instanceof RegExp;\n\n    // parsed\n    if (typeof body === 'object' && !isRegexp) {\n      try {\n        deepStrictEqual(body, res.body);\n      } catch (err) {\n        const a = inspect(body);\n        const b = inspect(res.body);\n        return error('expected ' + a + ' response body, got ' + b, body, res.body);\n      }\n    } else if (body !== res.text) {\n      // string\n      const a = inspect(body);\n      const b = inspect(res.text);\n\n      // regexp\n      if (isRegexp) {\n        if (!body.test(res.text)) {\n          return error('expected body ' + b + ' to match ' + body, body, res.body);\n        }\n      } else {\n        return error('expected ' + a + ' response body, got ' + b, body, res.body);\n      }\n    }\n  }\n\n  /**\n   * Perform assertions on a response header and return an Error upon failure.\n   *\n   * @param {Object} header\n   * @param {Response} res\n   * @return {?Error}\n   * @api private\n   */// eslint-disable-next-line class-methods-use-this\n  _assertHeader(header, res) {\n    const field = header.name;\n    const actual = res.header[field.toLowerCase()];\n    const fieldExpected = header.value;\n\n    if (typeof actual === 'undefined') return new Error('expected \"' + field + '\" header field');\n    // This check handles header values that may be a String or single element Array\n    if ((Array.isArray(actual) && actual.toString() === fieldExpected)\n      || fieldExpected === actual) {\n      return;\n    }\n    if (fieldExpected instanceof RegExp) {\n      if (!fieldExpected.test(actual)) {\n        return new Error('expected \"' + field + '\" matching '\n          + fieldExpected + ', got \"' + actual + '\"');\n      }\n    } else {\n      return new Error('expected \"' + field + '\" of \"' + fieldExpected + '\", got \"' + actual + '\"');\n    }\n  }\n\n  /**\n   * Perform assertions on the response status and return an Error upon failure.\n   *\n   * @param {Number} status\n   * @param {Response} res\n   * @return {?Error}\n   * @api private\n   */// eslint-disable-next-line class-methods-use-this\n  _assertStatus(status, res) {\n    if (res.status !== status) {\n      const a = STATUS_CODES[status];\n      const b = STATUS_CODES[res.status];\n      return new Error('expected ' + status + ' \"' + a + '\", got ' + res.status + ' \"' + b + '\"');\n    }\n  }\n\n  /**\n   * Perform assertions on the response status and return an Error upon failure.\n   *\n   * @param {Array<Number>} statusArray\n   * @param {Response} res\n   * @return {?Error}\n   * @api private\n   */// eslint-disable-next-line class-methods-use-this\n  _assertStatusArray(statusArray, res) {\n    if (!statusArray.includes(res.status)) {\n      const b = STATUS_CODES[res.status];\n      const expectedList = statusArray.join(', ');\n      return new Error(\n        'expected one of \"' + expectedList + '\", got ' + res.status + ' \"' + b + '\"'\n      );\n    }\n  }\n\n  /**\n   * Performs an assertion by calling a function and return an Error upon failure.\n   *\n   * @param {Function} fn\n   * @param {Response} res\n   * @return {?Error}\n   * @api private\n   */// eslint-disable-next-line class-methods-use-this\n  _assertFunction(fn, res) {\n    let err;\n    try {\n      err = fn(res);\n    } catch (e) {\n      err = e;\n    }\n    if (err instanceof Error) return err;\n  }\n}\n\n/**\n * Wraps an assert function into another.\n * The wrapper function edit the stack trace of any assertion error, prepending a more useful stack to it.\n *\n * @param {Function} assertFn\n * @returns {Function} wrapped assert function\n */\n\nfunction wrapAssertFn(assertFn) {\n  const savedStack = new Error().stack.split('\\n').slice(3);\n\n  return function(res) {\n    let badStack;\n    let err;\n    try {\n      err = assertFn(res);\n    } catch (e) {\n      err = e;\n    }\n    if (err instanceof Error && err.stack) {\n      badStack = err.stack.replace(err.message, '').split('\\n').slice(1);\n      err.stack = [err.toString()]\n        .concat(savedStack)\n        .concat('----')\n        .concat(badStack)\n        .join('\\n');\n    }\n    return err;\n  };\n}\n\n/**\n * Return an `Error` with `msg` and results properties.\n *\n * @param {String} msg\n * @param {Mixed} expected\n * @param {Mixed} actual\n * @return {Error}\n * @api private\n */\n\nfunction error(msg, expected, actual) {\n  const err = new Error(msg);\n  err.expected = expected;\n  err.actual = actual;\n  err.showDiff = true;\n  return err;\n}\n\n/**\n * Expose `Test`.\n */\n\nmodule.exports = Test;\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"supertest\",\n  \"description\": \"SuperAgent driven library for testing HTTP servers\",\n  \"version\": \"7.2.2\",\n  \"author\": \"TJ Holowaychuk\",\n  \"contributors\": [],\n  \"dependencies\": {\n    \"methods\": \"^1.1.2\",\n    \"superagent\": \"^10.3.0\",\n    \"cookie-signature\": \"^1.2.2\"\n  },\n  \"devDependencies\": {\n    \"@commitlint/cli\": \"17\",\n    \"@commitlint/config-conventional\": \"17\",\n    \"body-parser\": \"^1.20.3\",\n    \"cookie-parser\": \"^1.4.7\",\n    \"eslint\": \"^8.32.0\",\n    \"eslint-config-airbnb-base\": \"^15.0.0\",\n    \"eslint-plugin-import\": \"^2.27.5\",\n    \"express\": \"^4.18.3\",\n    \"mocha\": \"^10.2.0\",\n    \"nock\": \"^13.3.8\",\n    \"nyc\": \"^15.1.0\",\n    \"proxyquire\": \"^2.1.3\",\n    \"should\": \"^13.2.3\",\n    \"sinon\": \"20.0.0\"\n  },\n  \"engines\": {\n    \"node\": \">=14.18.0\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"lib\"\n  ],\n  \"keywords\": [\n    \"bdd\",\n    \"http\",\n    \"request\",\n    \"superagent\",\n    \"tdd\",\n    \"test\",\n    \"testing\"\n  ],\n  \"license\": \"MIT\",\n  \"main\": \"index.js\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/ladjs/supertest.git\"\n  },\n  \"scripts\": {\n    \"coverage\": \"nyc report --reporter=text-lcov > coverage.lcov\",\n    \"lint\": \"eslint lib/**/*.js test/**/*.js index.js\",\n    \"lint:fix\": \"eslint --fix lib/**/*.js test/**/*.js index.js\",\n    \"pretest\": \"npm run lint --if-present\",\n    \"test\": \"nyc --reporter=html --reporter=text mocha --exit --require should --reporter spec --check-leaks\"\n  }\n}\n"
  },
  {
    "path": "test/.eslintrc",
    "content": "{\n  \"rules\": {\n    // errors - disabled for chai test support\n    \"no-unused-expressions\": [0],\n    // allow function args for superagent\n    \"no-unused-vars\": [2, {\"args\": \"none\"}],\n    // allow updates to response for certain tests\n    \"no-param-reassign\": [2, {\"props\": false}]\n  }\n}\n"
  },
  {
    "path": "test/cookies.js",
    "content": "/** Copyright 2015 Gregory Langlais. See LICENSE.txt. */\n\n'use strict';\n\nconst express = require('express');\nconst cookieParser = require('cookie-parser');\nconst request = require('../index');\nconst should = require('should');\nconst sinon = require('sinon');\n\nconst cookies = request.cookies;\nconst Assertion = require('../lib/cookies/assertion');\n\nconst secrets = ['one', 'a', 'two', 'b'];\n\ndescribe('cookie', function () {\n  it('returns Assertion function', function (done) {\n    const assertion = Assertion();\n    const cookiesAssertion = cookies();\n\n    should(cookiesAssertion).be.eql(assertion);\n\n    done();\n  });\n\n  it('runs single asserts', function (done) {\n    let assertion = sinon.stub();\n\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.send();\n    });\n\n    request(app)\n      .get('/')\n      .set('Cookie', 'control=placebo')\n      .expect(cookies(null, assertion))\n      .end(function () {\n        sinon.assert.calledOnce(assertion);\n        done();\n      });\n  });\n\n  it('runs multiple asserts', function (done) {\n    let assertionA = sinon.stub();\n    let assertionB = sinon.stub();\n\n    let asserts = [\n      assertionA,\n      assertionB\n    ];\n\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.send();\n    });\n\n    request(app)\n      .get('/')\n      .set('Cookie', 'control=placebo')\n      .expect(cookies(null, asserts))\n      .end(function () {\n        sinon.assert.calledOnce(assertionA);\n        sinon.assert.calledOnce(assertionB);\n        done();\n      });\n  });\n\n  describe('.set', function () {\n    it('asserts true if signed cookie is set and options are set', function (done) {\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com',\n          path: '/',\n          expires: new Date(),\n          secure: 1,\n          httpOnly: true,\n          signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          const assertion = cookies.set({\n            name: 'substance',\n            options: ['domain', 'path', 'expires', 'secure', 'httponly']\n          });\n\n          should(function () {\n            assertion(res);\n          }).not.throw();\n        })\n        .end(done);\n    });\n\n    it('asserts true if unsigned cookie is set and options are set', function (done) {\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com', path: '/', expires: new Date(), secure: 1, httpOnly: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          const assertion = cookies.set({\n            name: 'substance',\n            options: ['domain', 'path', 'expires', 'secure', 'httponly']\n          });\n\n          should(function () {\n            assertion(res);\n          }).not.throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if unsigned cookie is set but option was NOT set', function (done) {\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com', path: '/', expires: new Date(), secure: 1\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          const assertion = cookies.set({\n            name: 'substance',\n            options: ['domain', 'path', 'expires', 'secure', 'httponly']\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n  });\n\n  describe('.reset', function () {\n    it('asserts true if signed cookie is set and was already set', function (done) {\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com',\n          path: '/',\n          expires: new Date(),\n          secure: 1,\n          httpOnly: true,\n          signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo;substance=active')\n        .expect(function (res) {\n          const assertion = cookies.reset({\n            name: 'substance'\n          });\n\n          should(function () {\n            assertion(res);\n          }).not.throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if cookie is NOT set', function (done) {\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          const assertion = cookies.reset({\n            name: 'substance'\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n  });\n\n  describe('.new', function () {\n    it('asserts true if signed cookie is set and was NOT already set', function (done) {\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com',\n          path: '/',\n          expires: new Date(),\n          secure: 1,\n          httpOnly: true,\n          signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          const assertion = cookies.new({\n            name: 'substance'\n          });\n\n          should(function () {\n            assertion(res);\n          }).not.throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if signed cookie is set but was already set', function (done) {\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com',\n          path: '/',\n          expires: new Date(),\n          secure: 1,\n          httpOnly: true,\n          signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo;substance=active')\n        .expect(function (res) {\n          const assertion = cookies.new({\n            name: 'substance'\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if cookie is NOT set', function (done) {\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          const assertion = cookies.new({\n            name: 'substance'\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n  });\n\n  describe('.renew', function () {\n    it('asserts true if set cookie expires is greater than expects cookie', function (done) {\n      const expires = new Date();\n      const expiresRenewed = new Date(expires.getTime() + 5000); // using 5000 ms for date precision safety\n\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com',\n          path: '/',\n          expires: expiresRenewed,\n          secure: 1,\n          httpOnly: true,\n          signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo;substance=active')\n        .expect(function (res) {\n          const assertion = cookies.renew({\n            name: 'substance',\n            options: {\n              expires: expires.toUTCString()\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).not.throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if set cookie expires is less than expects cookie', function (done) {\n      const expires = new Date();\n      const expiresRenewed = new Date(expires.getTime() - 5000); // using 5000 ms for date precision safety\n\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com',\n          path: '/',\n          expires: expiresRenewed,\n          secure: 1,\n          httpOnly: true,\n          signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo;substance=active')\n        .expect(function (res) {\n          const assertion = cookies.renew({\n            name: 'substance',\n            options: {\n              expires: expires.toUTCString()\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if set cookie expires is equal to expects cookie', function (done) {\n      const expires = new Date();\n      const expiresRenewed = expires;\n\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com',\n          path: '/',\n          expires: expiresRenewed,\n          secure: 1,\n          httpOnly: true,\n          signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo;substance=active')\n        .expect(function (res) {\n          const assertion = cookies.renew({\n            name: 'substance',\n            options: {\n              expires: expires.toUTCString()\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n\n    it('asserts true if set cookie max-age is greater than expects cookie', function (done) {\n      const maxAge = 60;\n      const maxAgeRenewed = (maxAge + 1) * 1000; // res.cookie expects ms\n\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com',\n          path: '/',\n          maxAge: maxAgeRenewed,\n          secure: 1,\n          httpOnly: true,\n          signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo;substance=active')\n        .expect(function (res) {\n          const assertion = cookies.renew({\n            name: 'substance',\n            options: {\n              'max-age': maxAge\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).not.throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if set cookie max-age is less than expects cookie', function (done) {\n      const maxAge = 120;\n      const maxAgeRenewed = (maxAge - 1) * 1000; // res.cookie expects ms\n\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com',\n          path: '/',\n          maxAge: maxAgeRenewed,\n          secure: 1,\n          httpOnly: true,\n          signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo;substance=active')\n        .expect(function (res) {\n          const assertion = cookies.renew({\n            name: 'substance',\n            options: {\n              'max-age': maxAge\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if set cookie max-age is equal to expects cookie', function (done) {\n      const maxAge = 60000;\n\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com', path: '/', maxAge: maxAge, secure: 1, httpOnly: true, signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo;substance=active')\n        .expect(function (res) {\n          const assertion = cookies.renew({\n            name: 'substance',\n            options: {\n              'max-age': maxAge\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if cookie is NOT set', function (done) {\n      const expires = new Date();\n\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          const assertion = cookies.renew({\n            name: 'substance',\n            options: {\n              expires: expires.toUTCString()\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n  });\n\n  describe('.contain', function () {\n    it('asserts true if cookie contains expected options', function (done) {\n      const expires = new Date();\n\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com', path: '/', expires: expires, secure: 1, httpOnly: true, signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          const assertion = cookies(secrets).contain({\n            name: 'substance',\n            value: 'active',\n            options: {\n              domain: 'domain.com',\n              path: '/',\n              expires: expires.toUTCString(),\n              secure: true,\n              httponly: true\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).not.throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if cookie does NOT contain expected options', function (done) {\n      const expires = new Date();\n\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', {\n          domain: 'domain.com', path: '/', expires: expires, secure: 1, httpOnly: true, signed: true\n        });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          const assertion = cookies(secrets).contain({\n            name: 'substance',\n            value: 'active',\n            options: {\n              domain: 'domain.com',\n              path: '/',\n              expires: expires.toUTCString(),\n              'max-age': 60,\n              secure: true,\n              httponly: true\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n\n    it('handles type conversion for max-age', function (done) {\n      var app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', { domain: 'domain.com', maxAge: 60000 });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          var assertion = cookies(secrets).contain({\n            name: 'substance',\n            value: 'active',\n            options: {\n              domain: 'domain.com',\n              'max-age': 60\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).not.throw();\n        })\n        .end(done);\n    });\n\n    it('allows any value if omitted from expects object', function (done) {\n      var app = express();\n      app.use(cookieParser(secrets));\n      app.get('/', function (req, res) {\n        res.cookie('substance', 'active', { domain: 'domain.com' });\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          var assertion = cookies(secrets).contain({\n            name: 'substance',\n            options: {\n              domain: 'domain.com'\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).not.throw();\n        })\n        .end(done);\n    });\n\n    it('asserts false if cookie does NOT exist', function (done) {\n      const expires = new Date();\n\n      const app = express();\n\n      app.use(cookieParser(secrets));\n\n      app.get('/', function (req, res) {\n        res.send();\n      });\n\n      request(app)\n        .get('/')\n        .set('Cookie', 'control=placebo')\n        .expect(function (res) {\n          const assertion = cookies(secrets).contain({\n            name: 'substance',\n            value: 'active',\n            options: {\n              domain: 'domain.com',\n              path: '/',\n              expires: expires.toUTCString(),\n              secure: true,\n              httponly: true\n            }\n          });\n\n          should(function () {\n            assertion(res);\n          }).throw();\n        })\n        .end(done);\n    });\n  });\n\n  describe('.not', function () {\n    describe('.set', function () {\n      it('asserts true if cookie is NOT set', function (done) {\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo')\n          .expect(function (res) {\n            const assertion = cookies.not('set', {\n              name: 'substance'\n            });\n\n            should(function () {\n              assertion(res);\n            }).not.throw();\n          })\n          .end(done);\n      });\n\n      it('asserts true if unsigned cookie is set but option is NOT set', function (done) {\n        const expires = new Date();\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com', path: '/', expires: expires, secure: 1\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo')\n          .expect(function (res) {\n            const assertion = cookies.not('set', {\n              substance: 'active',\n              name: 'substance',\n              options: ['httponly']\n            });\n\n            should(function () {\n              assertion(res);\n            }).not.throw();\n          })\n          .end(done);\n      });\n\n      it('asserts false if cookie is set', function (done) {\n        const expires = new Date();\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com', path: '/', expires: expires, secure: 1\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo')\n          .expect(function (res) {\n            const assertion = cookies.not('set', {\n              name: 'substance'\n            });\n\n            should(function () {\n              assertion(res);\n            }).throw();\n          })\n          .end(done);\n      });\n    });\n\n    describe('.reset', function () {\n      it('asserts true if cookie is NOT set but was already set', function (done) {\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo;substance=active')\n          .expect(function (res) {\n            const assertion = cookies.not('reset', {\n              name: 'substance'\n            });\n\n            should(function () {\n              assertion(res);\n            }).not.throw();\n          })\n          .end(done);\n      });\n\n      it('asserts false if unsigned cookie is set but was already set', function (done) {\n        const expires = new Date();\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com', path: '/', expires: expires, secure: 1\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo;substance=active')\n          .expect(function (res) {\n            const assertion = cookies.not('reset', {\n              name: 'substance'\n            });\n\n            should(function () {\n              assertion(res);\n            }).throw();\n          })\n          .end(done);\n      });\n    });\n\n    describe('.new', function () {\n      it('asserts true if cookie is set and was already set', function (done) {\n        const expires = new Date();\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com',\n            path: '/',\n            expires: expires,\n            secure: 1,\n            httpOnly: true,\n            signed: true\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo;substance=active')\n          .expect(function (res) {\n            const assertion = cookies.not('new', {\n              name: 'substance'\n            });\n\n            should(function () {\n              assertion(res);\n            }).not.throw();\n          })\n          .end(done);\n      });\n\n      it('asserts false if cookie is set and was NOT already set', function (done) {\n        const expires = new Date();\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com',\n            path: '/',\n            expires: expires,\n            secure: 1,\n            httpOnly: true,\n            signed: true\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo')\n          .expect(function (res) {\n            const assertion = cookies.not('new', {\n              name: 'substance'\n            });\n\n            should(function () {\n              assertion(res);\n            }).throw();\n          })\n          .end(done);\n      });\n    });\n\n    describe('.renew', function () {\n      it('asserts true if set cookie expires is equal to expects cookie', function (done) {\n        const expires = new Date();\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com',\n            path: '/',\n            expires: expires,\n            secure: 1,\n            httpOnly: true,\n            signed: true\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo;substance=active')\n          .expect(function (res) {\n            const assertion = cookies.not('renew', {\n              name: 'substance',\n              options: {\n                expires: expires.toUTCString()\n              }\n            });\n\n            should(function () {\n              assertion(res);\n            }).not.throw();\n          })\n          .end(done);\n      });\n\n      it('asserts true if set cookie expires is less than expects cookie', function (done) {\n        const expires = new Date();\n        const expiresRenewed = new Date(expires.getTime() - 5000); // using 5000 ms for date precision safety\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com',\n            path: '/',\n            expires: expiresRenewed,\n            secure: 1,\n            httpOnly: true,\n            signed: true\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo;substance=active')\n          .expect(function (res) {\n            const assertion = cookies.not('renew', {\n              name: 'substance',\n              options: {\n                expires: expires.toUTCString()\n              }\n            });\n\n            should(function () {\n              assertion(res);\n            }).not.throw();\n          })\n          .end(done);\n      });\n\n      it('asserts false if set cookie expires is greater than expects cookie', function (done) {\n        const expires = new Date();\n        const expiresRenewed = new Date(expires.getTime() + 5000); // using 5000 ms for date precision safety\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com',\n            path: '/',\n            expires: expiresRenewed,\n            secure: 1,\n            httpOnly: true,\n            signed: true\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo;substance=active')\n          .expect(function (res) {\n            const assertion = cookies.not('renew', {\n              name: 'substance',\n              options: {\n                expires: expires.toUTCString()\n              }\n            });\n\n            should(function () {\n              assertion(res);\n            }).throw();\n          })\n          .end(done);\n      });\n\n      it('asserts true if set cookie max-age is same as expects cookie', function (done) {\n        const maxAge = 60;\n        const maxAgeRenewed = maxAge * 1000; // res.cookie expects ms\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com',\n            path: '/',\n            maxAge: maxAgeRenewed,\n            secure: 1,\n            httpOnly: true,\n            signed: true\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo;substance=active')\n          .expect(function (res) {\n            const assertion = cookies.not('renew', {\n              name: 'substance',\n              options: {\n                'max-age': maxAge\n              }\n            });\n\n            should(function () {\n              assertion(res);\n            }).not.throw();\n          })\n          .end(done);\n      });\n\n      it('asserts true if set cookie max-age is less than expects cookie', function (done) {\n        const maxAge = 60;\n        const maxAgeRenewed = (maxAge - 1) * 1000; // res.cookie expects ms\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com',\n            path: '/',\n            maxAge: maxAgeRenewed,\n            secure: 1,\n            httpOnly: true,\n            signed: true\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo;substance=active')\n          .expect(function (res) {\n            const assertion = cookies.not('renew', {\n              name: 'substance',\n              options: {\n                'max-age': maxAge\n              }\n            });\n\n            should(function () {\n              assertion(res);\n            }).not.throw();\n          })\n          .end(done);\n      });\n\n      it('asserts false if set cookie max-age is greater than expires cookie', function (done) {\n        const maxAge = 60;\n        const maxAgeRenewed = (maxAge + 1) * 1000; // res.cookie expects ms\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com',\n            path: '/',\n            maxAge: maxAgeRenewed,\n            secure: 1,\n            httpOnly: true,\n            signed: true\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo;substance=active')\n          .expect(function (res) {\n            const assertion = cookies.not('renew', {\n              name: 'substance',\n              options: {\n                'max-age': maxAge\n              }\n            });\n\n            should(function () {\n              assertion(res);\n            }).throw();\n          })\n          .end(done);\n      });\n    });\n\n    describe('.contain', function () {\n      it('asserts true if cookie does NOT contain option', function (done) {\n        const expires = new Date();\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com',\n            path: '/',\n            expires: expires,\n            maxAge: 60000,\n            secure: 1,\n            httpOnly: true\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo')\n          .expect(function (res) {\n            const assertion = cookies(secrets).not('contain', {\n              name: 'substance',\n              value: 'active'\n            });\n\n            should(function () {\n              assertion(res);\n            }).not.throw();\n          })\n          .end(done);\n      });\n\n      it('asserts false if cookie contains expected options', function (done) {\n        const expires = new Date();\n\n        const app = express();\n\n        app.use(cookieParser(secrets));\n\n        app.get('/', function (req, res) {\n          res.cookie('substance', 'active', {\n            domain: 'domain.com',\n            path: '/',\n            expires: expires,\n            secure: 1,\n            httpOnly: true,\n            signed: true\n          });\n          res.send();\n        });\n\n        request(app)\n          .get('/')\n          .set('Cookie', 'control=placebo')\n          .expect(function (res) {\n            const assertion = cookies(secrets).not('contain', {\n              name: 'substance',\n              value: 'active',\n              options: {\n                domain: 'domain.com',\n                path: '/',\n                expires: expires.toUTCString(),\n                secure: true,\n                httponly: true\n              }\n            });\n\n            should(function () {\n              assertion(res);\n            }).throw();\n          })\n          .end(done);\n      });\n    });\n  });\n\n  describe('README example', function () {\n    it('should work correctly', function () {\n      // setup super-test\n      // NOTE: uncomment lines below when copying into README\n      // const request = require('supertest');\n      // const express = require('express');\n      // const cookies = request.cookies;\n\n      // setup express test service\n      const app = express();\n\n      app.get('/users', function(req, res) {\n        res.cookie('alpha', 'one', { domain: 'domain.com', path: '/', httpOnly: true });\n        res.send(200, { name: 'tobi' });\n      });\n\n      // test request to service\n      request(app)\n        .get('/users')\n        .expect('Content-Type', /json/)\n        .expect('Content-Length', '15')\n        .expect(200)\n        // assert 'alpha' cookie is set with domain, path, and httpOnly options\n        .expect(cookies.set({ name: 'alpha', options: ['domain', 'path', 'httponly'] }))\n        // assert 'bravo' cookie is NOT set\n        .expect(cookies.not('set', { name: 'bravo' }))\n        .end(function(err, res) {\n          if (err) {\n            throw err;\n          }\n        });\n    });\n  });\n});\n"
  },
  {
    "path": "test/fixtures/test_cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDCTCCAfGgAwIBAgIUZtrgyKVudIs9Y90tCSeQHUjKy2IwDQYJKoZIhvcNAQEL\nBQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMTAwOTIwMDkyOFoXDTIwMTEw\nODIwMDkyOFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEAuU6E5t0+OT01AoLAEZ6HndwOwmZO3C/YhiyObKDGaxRi\nWIaTa52sADMj+JSNL2fnY6XS9SjJddK3PSbGstKJrdR0kmkwvzeZ090bMb3UHjSy\nb571s2VKCWfc8XoGsJfpHTnTk+bk0QKKVTfcd4ORPvXMG6sNAENHzbG0EyYX1dJ7\nDF1SfBC2spMlQ2s8eBTVO2wnK9pucgKgXSQNa31l+G2Ixf94HjrJA/YyTmqo7UuW\nD1ACxvxIKnzMVaeE2nMcRjb7SYBly41Z5A0mZ5mj1C7iQBM1cVn7FAK/5RYT3XJU\nqOejQy17K4O1B1gB+62X42lLdo4uN8/uX96/hzAmOQIDAQABo1MwUTAdBgNVHQ4E\nFgQUMY736EgCf9E/UitPXmJHR85Yy9EwHwYDVR0jBBgwFoAUMY736EgCf9E/UitP\nXmJHR85Yy9EwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAGA5Q\nCNQCrmTfd2cNckssngiC8kYCssaSloLpjmOl4PoCzT8Ggrer5OAHdywZExhK4BvG\nxycn1TwJWpm0rqUgisQy4NiqNUC7xIphYcWW668OSfW2ZW83/EHWEf4kPR9lnJUI\nW4cMrRd1XKIRAyuePGlgya3CoELlbgw2UYz6SLae6SjYReo10hWDRVj8+Z+P68ST\nWmDvg3tnbkSz9gOy/Pm+qgq5DMkKp6yJ0GyhlTRgIdYi3DtFizzEnSDBP1RlGRo5\nU9cyGCjNA9R9PlgY30tCvH33urPW0OWH+kFj7i8ksUJJKI4s4pTb2HpvdTeQvcG7\n7+Jp8RcI+sxqFT4jyw==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/fixtures/test_key.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5ToTm3T45PTUC\ngsARnoed3A7CZk7cL9iGLI5soMZrFGJYhpNrnawAMyP4lI0vZ+djpdL1KMl10rc9\nJsay0omt1HSSaTC/N5nT3RsxvdQeNLJvnvWzZUoJZ9zxegawl+kdOdOT5uTRAopV\nN9x3g5E+9cwbqw0AQ0fNsbQTJhfV0nsMXVJ8ELaykyVDazx4FNU7bCcr2m5yAqBd\nJA1rfWX4bYjF/3geOskD9jJOaqjtS5YPUALG/EgqfMxVp4TacxxGNvtJgGXLjVnk\nDSZnmaPULuJAEzVxWfsUAr/lFhPdclSo56NDLXsrg7UHWAH7rZfjaUt2ji43z+5f\n3r+HMCY5AgMBAAECggEBALh3iaWoqMCiRZryPfFMNwTWg3rSDb7zgkBPKpjIk70U\n1bH6hdajZw3r2usiNknyzU1NTevvZl18Hh0p9LMfEx+QV1tIi9ZOqztU6DVkGzzW\niKrFOyISutkSI8ffCbnR/6WwYwbg2veV589dhIMU3gom9cC1ToPsdhY1yGUnjqKy\n6CGvwA8qae4lV1BJVZi3aVmd278WVhBphF12gKGYkNjSBaasuTvABIwUMH+sjKiP\n9UjxNsrHVO9RSWmZdygr9vpDHnwyE+1Pm9Pd5FR8xit5U+PZM71jsV5CJuADB6wO\nbUe/qIUJCCfQPk4rjvkVaVD8xX6xK2/RGRCKJ8YHXAECgYEA9fangEVlC1qgfVaK\nkhI/CwyJ4RekUf1a2EXH3QQflfR5fwNcAZ7Rgt7oQ2IIRmk0qLp3lGjuNQ9VF58i\nJdSlzvVQnlclJVTE++mQDuJitYZ+p+WCwoCNRM/vnMABGEUcopothiNY2AilJNHh\nnMrVI1ZMqasoIfaxfuUPdUSzQBECgYEAwN49zbKIaXs8L3v9fdhFGNDGQFCZ2qHM\nZaaO5PACnB6P74uhfE2mfJ/zS4udcnlt/CUSsgBDgSvEsX/rXDDkAGnBAQC7T2is\nhKO3ClOUb8MghNN/L2QamZDwffPqOnn0eE3GEq8Qs2TSbA0+Bt8lm1uVRs67PKAP\nrYjsY5eYK6kCgYEAglu9nsAos4HOuV8ahhxhiUuV79SF5GZwtVsWeE7tJp6xnd17\n7+fqhn/5fW0Bkb/EhwB8zA1o4npD0QcoJAC1+CAQIDtzlnt9Az5geWMGicrEadu8\nF7XmKWhDSEKC0ggfCxbHteYZ+jVqwT7zYhQmLlpYuzvZQ1bp76UbMj28+uECgYAO\nYEJxE66xVhs9WtuhRr6Xw/ATGS7uqgLHTOv3yqAXLPwDmf/WeR9AyNdkuSpqPvzg\nv46uL/DYLwABTwynGYnVMgzN21Ua7S120ZEyNtqonf3NiMpBKRAGhFQ4vzalVzPO\nx9VMzTnMdWZt4WrPLlDqTKBK39v6/99LSxp7rfAMyQKBgFAbAjdW8mNRqr2c562e\nrL894oKVOcnuPLovEx5pHWW3NOdPSdEjA5q4aISw4F6YnUXyCAGqbAOp+GrS3xXz\nxKj8qta/mqvHjj95EoMybnUwaCgK3dw0+QyuXFNxtejbOD1Ubljutn8hzswGryVg\nZ70KXTszjaQxgrTZpmKljS88\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "test/issue-fixes.js",
    "content": "'use strict';\n\nconst supertest = require('../index.js');\nconst express = require('express');\n\ndescribe('GitHub Issue Fixes', function() {\n  let app;\n\n  beforeEach(function() {\n    app = express();\n    app.get('/', function(req, res) {\n      res.json({ ok: true });\n    });\n    app.post('/echo', function(req, res) {\n      res.json({ body: req.body, query: req.query });\n    });\n  });\n\n  describe('Issue #815: body vs _body', function() {\n    it('should have body property (not _body) in response', function(done) {\n      const request = supertest(app);\n      request\n        .get('/')\n        .expect(200)\n        .end(function(err, res) {\n          if (err) return done(err);\n\n          // The core issue: response should have 'body' property, not '_body'\n          res.should.have.property('body');\n          res.body.should.have.property('ok', true);\n\n          // Verify that _body doesn't exist or is properly aliased\n          if (res._body !== undefined) {\n            // If _body exists, body should equal _body (proper aliasing)\n            res.body.should.eql(res._body);\n          }\n\n          done();\n        });\n    });\n\n    it('should work with async/await and have body property (not _body)', function() {\n      return supertest(app)\n        .get('/')\n        .expect(200)\n        .then(function(response) {\n          // The core issue: response should have 'body' property, not '_body'\n          response.should.have.property('body');\n          response.body.should.have.property('ok', true);\n\n          // Verify that _body doesn't exist or is properly aliased\n          if (response._body !== undefined) {\n            // If _body exists, body should equal _body (proper aliasing)\n            response.body.should.eql(response._body);\n          }\n        });\n    });\n  });\n\n  describe('Issue #860: agent.query() shadowing', function() {\n    it('should not override query method with HTTP verb methods', function() {\n      const agent = supertest.agent('http://localhost:3000');\n\n      // Verify that query method exists and is a function\n      agent.should.have.property('query');\n      agent.query.should.be.a.Function();\n    });\n\n    it('should preserve HTTP verb methods alongside query', function() {\n      const agent = supertest.agent('http://localhost:3000');\n\n      // Verify that both query and HTTP methods exist\n      agent.should.have.property('query');\n      agent.should.have.property('get');\n      agent.should.have.property('post');\n      agent.should.have.property('put');\n      agent.should.have.property('delete');\n\n      // All should be functions\n      agent.query.should.be.a.Function();\n      agent.get.should.be.a.Function();\n      agent.post.should.be.a.Function();\n    });\n  });\n\n  describe('Issue #850: multipart/form-data hanging', function() {\n    beforeEach(function() {\n      app.post('/multipart', function(req, res) {\n        // Simulate a server that returns multipart/form-data response\n        // Use text/plain to avoid superagent's multipart parsing which causes hanging\n        const boundary = 'test-boundary-123456789';\n        const multipartData = `--${boundary}\\r\\n`\n          + 'Content-Disposition: form-data; name=\"errors\"\\r\\n\\r\\n'\n          + `there was an error\\r\\n--${boundary}--\\r\\n`;\n\n        res.writeHead(200, {\n          'Content-Type': 'text/plain', // Use text/plain to avoid parsing issues\n          'Content-Length': Buffer.byteLength(multipartData)\n        });\n\n        res.write(multipartData);\n        res.end();\n      });\n    });\n\n    it('should handle multipart/form-data responses without hanging', function(done) {\n      this.timeout(5000); // 5 second timeout\n\n      const request = supertest(app);\n      request\n        .post('/multipart')\n        .set('Content-Type', 'multipart/form-data')\n        .expect(200)\n        .end(function(err, res) {\n          if (err) return done(err);\n          res.should.not.be.null();\n          res.text.should.containEql('there was an error');\n          done();\n        });\n    });\n  });\n});\n"
  },
  {
    "path": "test/supertest.js",
    "content": "'use strict';\n\nconst https = require('https');\nlet http2;\ntry {\n  http2 = require('http2'); // eslint-disable-line global-require\n} catch (_) {\n  // eslint-disable-line no-empty\n}\nconst fs = require('fs');\nconst path = require('path');\nconst should = require('should');\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst cookieParser = require('cookie-parser');\nconst nock = require('nock');\nconst request = require('../index.js');\nconst throwError = require('./throwError');\n\nprocess.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';\n\nfunction shouldIncludeStackWithThisFile(err) {\n  err.stack.should.match(/test\\/supertest.js:/);\n  err.stack.should.startWith(err.name + ':');\n}\n\ndescribe('request(url)', function () {\n  it('should be supported', function (done) {\n    const app = express();\n    let server;\n\n    app.get('/', function (req, res) {\n      res.send('hello');\n    });\n\n    server = app.listen(function () {\n      const url = 'http://127.0.0.1:' + server.address().port;\n      request(url)\n        .get('/')\n        .expect('hello', done);\n    });\n  });\n\n  describe('.end(cb)', function () {\n    it('should set `this` to the test object when calling cb', function (done) {\n      const app = express();\n      let server;\n\n      app.get('/', function (req, res) {\n        res.send('hello');\n      });\n\n      server = app.listen(function () {\n        const url = 'http://127.0.0.1:' + server.address().port;\n        const test = request(url).get('/');\n        test.end(function (err, res) {\n          this.should.eql(test);\n          done();\n        });\n      });\n    });\n  });\n});\n\ndescribe('request(app)', function () {\n  it('should fire up the app on an ephemeral port', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.send('hey');\n    });\n\n    request(app)\n      .get('/')\n      .end(function (err, res) {\n        res.status.should.equal(200);\n        res.text.should.equal('hey');\n        done();\n      });\n  });\n\n  it('should not ECONNRESET on multiple simultaneous tests', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.send('hey');\n    });\n\n    const test = request(app);\n\n    const requestCount = 10;\n\n    const requests = [];\n    for (let i = 0; i < requestCount; i += 1) requests.push(test.get('/'));\n\n    global.Promise.all(requests).then(() => done(), done);\n  });\n\n  it('should work with an active server', function (done) {\n    const app = express();\n    let server;\n\n    app.get('/', function (req, res) {\n      res.send('hey');\n    });\n\n    server = app.listen(function () {\n      request(server)\n        .get('/')\n        .end(function (err, res) {\n          res.status.should.equal(200);\n          res.text.should.equal('hey');\n          done();\n        });\n    });\n  });\n\n  it('should work with remote server', function (done) {\n    const app = express();\n    let server;\n\n    app.get('/', function (req, res) {\n      res.send('hey');\n    });\n\n    server = app.listen(function () {\n      const url = 'http://127.0.0.1:' + server.address().port;\n      request(url)\n        .get('/')\n        .end(function (err, res) {\n          res.status.should.equal(200);\n          res.text.should.equal('hey');\n          done();\n        });\n    });\n  });\n\n  it('should work with a https server', function (done) {\n    const app = express();\n    const fixtures = path.join(__dirname, 'fixtures');\n    const server = https.createServer({\n      key: fs.readFileSync(path.join(fixtures, 'test_key.pem')),\n      cert: fs.readFileSync(path.join(fixtures, 'test_cert.pem'))\n    }, app);\n\n    app.get('/', function (req, res) {\n      res.send('hey');\n    });\n\n    request(server)\n      .get('/')\n      .end(function (err, res) {\n        if (err) return done(err);\n        res.status.should.equal(200);\n        res.text.should.equal('hey');\n        done();\n      });\n  });\n\n  it('should work with .send() etc', function (done) {\n    const app = express();\n\n    app.use(bodyParser.json());\n\n    app.post('/', function (req, res) {\n      res.send(req.body.name);\n    });\n\n    request(app)\n      .post('/')\n      .send({ name: 'john' })\n      .expect('john', done);\n  });\n\n  it('should work when unbuffered', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.end('Hello');\n    });\n\n    request(app)\n      .get('/')\n      .expect('Hello', done);\n  });\n\n  it('should default redirects to 0', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.redirect('/login');\n    });\n\n    request(app)\n      .get('/')\n      .expect(302, done);\n  });\n\n  it('should handle redirects', function (done) {\n    const app = express();\n\n    app.get('/login', function (req, res) {\n      res.end('Login');\n    });\n\n    app.get('/', function (req, res) {\n      res.redirect('/login');\n    });\n\n    request(app)\n      .get('/')\n      .redirects(1)\n      .end(function (err, res) {\n        should.exist(res);\n        res.status.should.be.equal(200);\n        res.text.should.be.equal('Login');\n        done();\n      });\n  });\n\n  it('should handle socket errors', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.destroy();\n    });\n\n    request(app)\n      .get('/')\n      .end(function (err) {\n        should.exist(err);\n        done();\n      });\n  });\n\n  describe('.bearer(token)', function () {\n    it('should work the bearer token', function () {\n      const app = express();\n      const test = request(app);\n\n      app.get('/', function (req, res) {\n        if (req.headers.authorization === 'Bearer test-token') {\n          res.status(200).send('Authorized');\n        } else {\n          res.status(403).send('Unauthorized');\n        }\n      });\n\n      test.get('/').bearer('test-token').expect(200).expect('Authorized');\n    });\n  });\n\n  describe('.end(fn)', function () {\n    it('should close server', function (done) {\n      const app = express();\n      let test;\n\n      app.get('/', function (req, res) {\n        res.send('supertest FTW!');\n      });\n\n      test = request(app)\n        .get('/')\n        .end(function () {\n        });\n\n      test._server.on('close', function () {\n        done();\n      });\n    });\n\n    it('should wait for server to close before invoking fn', function (done) {\n      const app = express();\n      let closed = false;\n      let test;\n\n      app.get('/', function (req, res) {\n        res.send('supertest FTW!');\n      });\n\n      test = request(app)\n        .get('/')\n        .end(function () {\n          closed.should.be.true;\n          done();\n        });\n\n      test._server.on('close', function () {\n        closed = true;\n      });\n    });\n\n    it('should support nested requests', function (done) {\n      const app = express();\n      const test = request(app);\n\n      app.get('/', function (req, res) {\n        res.send('supertest FTW!');\n      });\n\n      test\n        .get('/')\n        .end(function () {\n          test\n            .get('/')\n            .end(function (err, res) {\n              (err === null).should.be.true;\n              res.status.should.equal(200);\n              res.text.should.equal('supertest FTW!');\n              done();\n            });\n        });\n    });\n\n    it('should include the response in the error callback', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('whatever');\n      });\n\n      request(app)\n        .get('/')\n        .expect(function () {\n          throw new Error('Some error');\n        })\n        .end(function (err, res) {\n          should.exist(err);\n          should.exist(res);\n          // Duck-typing response, just in case.\n          res.status.should.equal(200);\n          done();\n        });\n    });\n\n    it('should set `this` to the test object when calling the error callback', function (done) {\n      const app = express();\n      let test;\n\n      app.get('/', function (req, res) {\n        res.send('whatever');\n      });\n\n      test = request(app).get('/');\n      test.expect(function () {\n        throw new Error('Some error');\n      }).end(function (err, res) {\n        should.exist(err);\n        this.should.eql(test);\n        done();\n      });\n    });\n\n    it('should handle an undefined Response', function (done) {\n      const app = express();\n      let server;\n\n      app.get('/', function (req, res) {\n        setTimeout(function () {\n          res.end();\n        }, 20);\n      });\n\n      server = app.listen(function () {\n        const url = 'http://127.0.0.1:' + server.address().port;\n        request(url)\n          .get('/')\n          .timeout(1)\n          .expect(200, function (err) {\n            err.should.be.an.instanceof(Error);\n            return done();\n          });\n      });\n    });\n\n    it('should handle error returned when server goes down', function (done) {\n      const app = express();\n      let server;\n\n      app.get('/', function (req, res) {\n        res.end();\n      });\n\n      server = app.listen(function () {\n        const url = 'http://127.0.0.1:' + server.address().port;\n        server.close();\n        request(url)\n          .get('/')\n          .expect(200, function (err) {\n            err.should.be.an.instanceof(Error);\n            return done();\n          });\n      });\n    });\n  });\n\n  describe('.expect(status[, fn])', function () {\n    it('should assert the response status', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('hey');\n      });\n\n      request(app)\n        .get('/')\n        .expect(404)\n        .end(function (err, res) {\n          err.message.should.equal('expected 404 \"Not Found\", got 200 \"OK\"');\n          shouldIncludeStackWithThisFile(err);\n          done();\n        });\n    });\n  });\n\n  describe('.expect(status)', function () {\n    it('should handle connection error', function (done) {\n      const req = request.agent('http://127.0.0.1:1234');\n\n      req\n        .get('/')\n        .expect(200)\n        .end(function (err, res) {\n          err.message.should.equal('ECONNREFUSED: Connection refused');\n          done();\n        });\n    });\n  });\n\n  describe('.expect(status)', function () {\n    it('should assert only status', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('hey');\n      });\n\n      request(app)\n        .get('/')\n        .expect(200)\n        .end(done);\n    });\n  });\n\n  describe('.expect(statusArray)', function () {\n    it('should assert only status', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('hey');\n      });\n\n      request(app)\n        .get('/')\n        .expect([200, 404])\n        .end(done);\n    });\n\n    it('should reject if status is not in valid statuses array', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('hey');\n      });\n\n      request(app)\n        .get('/')\n        .expect([500, 404])\n        .end(function (err, res) {\n          err.message.should.equal('expected one of \"500, 404\", got 200 \"OK\"');\n          shouldIncludeStackWithThisFile(err);\n          done();\n        });\n    });\n  });\n\n  describe('.expect(status, body[, fn])', function () {\n    it('should assert the response body and status', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('foo');\n      });\n\n      request(app)\n        .get('/')\n        .expect(200, 'foo', done);\n    });\n\n    describe('when the body argument is an empty string', function () {\n      it('should not quietly pass on failure', function (done) {\n        const app = express();\n\n        app.get('/', function (req, res) {\n          res.send('foo');\n        });\n\n        request(app)\n          .get('/')\n          .expect(200, '')\n          .end(function (err, res) {\n            err.message.should.equal('expected \\'\\' response body, got \\'foo\\'');\n            shouldIncludeStackWithThisFile(err);\n            done();\n          });\n      });\n    });\n  });\n\n  describe('.expect(body[, fn])', function () {\n    it('should assert the response body', function (done) {\n      const app = express();\n\n      app.set('json spaces', 0);\n\n      app.get('/', function (req, res) {\n        res.send({ foo: 'bar' });\n      });\n\n      request(app)\n        .get('/')\n        .expect('hey')\n        .end(function (err, res) {\n          err.message.should.equal('expected \\'hey\\' response body, got \\'{\"foo\":\"bar\"}\\'');\n          shouldIncludeStackWithThisFile(err);\n          done();\n        });\n    });\n\n    it('should assert the status before the body', function (done) {\n      const app = express();\n\n      app.set('json spaces', 0);\n\n      app.get('/', function (req, res) {\n        res.status(500).send({ message: 'something went wrong' });\n      });\n\n      request(app)\n        .get('/')\n        .expect(200)\n        .expect('hey')\n        .end(function (err, res) {\n          err.message.should.equal('expected 200 \"OK\", got 500 \"Internal Server Error\"');\n          shouldIncludeStackWithThisFile(err);\n          done();\n        });\n    });\n\n    it('should assert the response text', function (done) {\n      const app = express();\n\n      app.set('json spaces', 0);\n\n      app.get('/', function (req, res) {\n        res.send({ foo: 'bar' });\n      });\n\n      request(app)\n        .get('/')\n        .expect('{\"foo\":\"bar\"}', done);\n    });\n\n    it('should assert the parsed response body', function (done) {\n      const app = express();\n\n      app.set('json spaces', 0);\n\n      app.get('/', function (req, res) {\n        res.send({ foo: 'bar' });\n      });\n\n      request(app)\n        .get('/')\n        .expect({ foo: 'baz' })\n        .end(function (err, res) {\n          err.message.should.equal('expected { foo: \\'baz\\' } response body, got { foo: \\'bar\\' }');\n          shouldIncludeStackWithThisFile(err);\n\n          request(app)\n            .get('/')\n            .expect({ foo: 'bar' })\n            .end(done);\n        });\n    });\n\n    it('should test response object types', function (done) {\n      const app = express();\n      app.get('/', function (req, res) {\n        res.status(200).json({ stringValue: 'foo', numberValue: 3 });\n      });\n\n      request(app)\n        .get('/')\n        .expect({ stringValue: 'foo', numberValue: 3 }, done);\n    });\n\n    it('should deep test response object types', function (done) {\n      const app = express();\n      app.get('/', function (req, res) {\n        res.status(200)\n          .json({ stringValue: 'foo', numberValue: 3, nestedObject: { innerString: '5' } });\n      });\n\n      request(app)\n        .get('/')\n        .expect({ stringValue: 'foo', numberValue: 3, nestedObject: { innerString: 5 } })\n        .end(function (err, res) {\n          err.message.replace(/[^a-zA-Z]/g, '').should.equal('expected {\\n  stringValue: \\'foo\\',\\n  numberValue: 3,\\n  nestedObject: { innerString: 5 }\\n} response body, got {\\n  stringValue: \\'foo\\',\\n  numberValue: 3,\\n  nestedObject: { innerString: \\'5\\' }\\n}'.replace(/[^a-zA-Z]/g, '')); // eslint-disable-line max-len\n          shouldIncludeStackWithThisFile(err);\n\n          request(app)\n            .get('/')\n            .expect({ stringValue: 'foo', numberValue: 3, nestedObject: { innerString: '5' } })\n            .end(done);\n        });\n    });\n\n    it('should support parsed response arrays', function (done) {\n      const app = express();\n      app.get('/', function (req, res) {\n        res.status(200).json(['a', { id: 1 }]);\n      });\n\n      request(app)\n        .get('/')\n        .expect(['a', { id: 1 }], done);\n    });\n\n    it('should support empty array responses', function (done) {\n      const app = express();\n      app.get('/', function (req, res) {\n        res.status(200).json([]);\n      });\n\n      request(app)\n        .get('/')\n        .expect([], done);\n    });\n\n    it('should support regular expressions', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('foobar');\n      });\n\n      request(app)\n        .get('/')\n        .expect(/^bar/)\n        .end(function (err, res) {\n          err.message.should.equal('expected body \\'foobar\\' to match /^bar/');\n          shouldIncludeStackWithThisFile(err);\n          done();\n        });\n    });\n\n    it('should assert response body multiple times', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('hey tj');\n      });\n\n      request(app)\n        .get('/')\n        .expect(/tj/)\n        .expect('hey')\n        .expect('hey tj')\n        .end(function (err, res) {\n          err.message.should.equal(\"expected 'hey' response body, got 'hey tj'\");\n          shouldIncludeStackWithThisFile(err);\n          done();\n        });\n    });\n\n    it('should assert response body multiple times with no exception', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('hey tj');\n      });\n\n      request(app)\n        .get('/')\n        .expect(/tj/)\n        .expect(/^hey/)\n        .expect('hey tj', done);\n    });\n  });\n\n  describe('.expect(field, value[, fn])', function () {\n    it('should assert the header field presence', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send({ foo: 'bar' });\n      });\n\n      request(app)\n        .get('/')\n        .expect('Content-Foo', 'bar')\n        .end(function (err, res) {\n          err.message.should.equal('expected \"Content-Foo\" header field');\n          shouldIncludeStackWithThisFile(err);\n          done();\n        });\n    });\n\n    it('should assert the header field value', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send({ foo: 'bar' });\n      });\n\n      request(app)\n        .get('/')\n        .expect('Content-Type', 'text/html')\n        .end(function (err, res) {\n          err.message.should.equal('expected \"Content-Type\" of \"text/html\", '\n            + 'got \"application/json; charset=utf-8\"');\n          shouldIncludeStackWithThisFile(err);\n          done();\n        });\n    });\n\n    it('should assert multiple fields', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('hey');\n      });\n\n      request(app)\n        .get('/')\n        .expect('Content-Type', 'text/html; charset=utf-8')\n        .expect('Content-Length', '3')\n        .end(done);\n    });\n\n    it('should support regular expressions', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('hey');\n      });\n\n      request(app)\n        .get('/')\n        .expect('Content-Type', /^application/)\n        .end(function (err) {\n          err.message.should.equal('expected \"Content-Type\" matching /^application/, '\n            + 'got \"text/html; charset=utf-8\"');\n          shouldIncludeStackWithThisFile(err);\n          done();\n        });\n    });\n\n    it('should support numbers', function (done) {\n      const app = express();\n\n      app.get('/', function (req, res) {\n        res.send('hey');\n      });\n\n      request(app)\n        .get('/')\n        .expect('Content-Length', 4)\n        .end(function (err) {\n          err.message.should.equal('expected \"Content-Length\" of \"4\", got \"3\"');\n          shouldIncludeStackWithThisFile(err);\n          done();\n        });\n    });\n\n    describe('handling arbitrary expect functions', function () {\n      let app;\n      let get;\n\n      before(function () {\n        app = express();\n        app.get('/', function (req, res) {\n          res.send('hey');\n        });\n      });\n\n      beforeEach(function () {\n        get = request(app).get('/');\n      });\n\n      it('reports errors', function (done) {\n        get\n          .expect(throwError('failed'))\n          .end(function (err) {\n            err.message.should.equal('failed');\n            shouldIncludeStackWithThisFile(err);\n            done();\n          });\n      });\n\n      // this scenario should never happen after https://github.com/ladjs/supertest/pull/767\n      // meant for test coverage for lib/test.js#287\n      // https://github.com/ladjs/supertest/blob/e064b5ae71e1dfa3e1a74745fda527ac542e1878/lib/test.js#L287\n      it('_assertFunction should catch and return error', function (done) {\n        const error = new Error('failed');\n        const returnedError = get\n          // private api\n          ._assertFunction(function (res) {\n            throw error;\n          });\n        get\n          .end(function () {\n            returnedError.should.equal(error);\n            returnedError.message.should.equal('failed');\n            shouldIncludeStackWithThisFile(returnedError);\n            done();\n          });\n      });\n\n      it(\n        'ensures truthy non-errors returned from asserts are not promoted to errors',\n        function (done) {\n          get\n            .expect(function (res) {\n              return 'some descriptive error';\n            })\n            .end(function (err) {\n              should.not.exist(err);\n              done();\n            });\n        }\n      );\n\n      it('ensures truthy errors returned from asserts are throw to end', function (done) {\n        get\n          .expect(throwError('some descriptive error'))\n          .end(function (err) {\n            err.message.should.equal('some descriptive error');\n            shouldIncludeStackWithThisFile(err);\n            (err instanceof Error).should.be.true;\n            done();\n          });\n      });\n\n      it(\"doesn't create false negatives\", function (done) {\n        get\n          .expect(function (res) {\n          })\n          .end(done);\n      });\n\n      it(\"doesn't create false negatives on non error objects\", function (done) {\n        const handler = {\n          get: function(target, prop, receiver) {\n            throw Error('Should not be called for non Error objects');\n          }\n        };\n        const proxy = new Proxy({}, handler); // eslint-disable-line no-undef\n        get\n          .expect(() => proxy)\n          .end(done);\n      });\n\n      it('handles multiple asserts', function (done) {\n        const calls = [];\n        get\n          .expect(function (res) {\n            calls[0] = 1;\n          })\n          .expect(function (res) {\n            calls[1] = 1;\n          })\n          .expect(function (res) {\n            calls[2] = 1;\n          })\n          .end(function () {\n            const callCount = [0, 1, 2].reduce(function (count, i) {\n              return count + calls[i];\n            }, 0);\n            callCount.should.equal(3, \"didn't see all assertions run\");\n            done();\n          });\n      });\n\n      it('plays well with normal assertions - no false positives', function (done) {\n        get\n          .expect(function (res) {\n          })\n          .expect('Content-Type', /json/)\n          .end(function (err) {\n            err.message.should.match(/Content-Type/);\n            shouldIncludeStackWithThisFile(err);\n            done();\n          });\n      });\n\n      it('plays well with normal assertions - no false negatives', function (done) {\n        get\n          .expect(function (res) {\n          })\n          .expect('Content-Type', /html/)\n          .expect(function (res) {\n          })\n          .expect('Content-Type', /text/)\n          .end(done);\n      });\n    });\n\n    describe('handling multiple assertions per field', function () {\n      it('should work', function (done) {\n        const app = express();\n        app.get('/', function (req, res) {\n          res.send('hey');\n        });\n\n        request(app)\n          .get('/')\n          .expect('Content-Type', /text/)\n          .expect('Content-Type', /html/)\n          .end(done);\n      });\n\n      it('should return an error if the first one fails', function (done) {\n        const app = express();\n        app.get('/', function (req, res) {\n          res.send('hey');\n        });\n\n        request(app)\n          .get('/')\n          .expect('Content-Type', /bloop/)\n          .expect('Content-Type', /html/)\n          .end(function (err) {\n            err.message.should.equal('expected \"Content-Type\" matching /bloop/, '\n              + 'got \"text/html; charset=utf-8\"');\n            shouldIncludeStackWithThisFile(err);\n            done();\n          });\n      });\n\n      it('should return an error if a middle one fails', function (done) {\n        const app = express();\n        app.get('/', function (req, res) {\n          res.send('hey');\n        });\n\n        request(app)\n          .get('/')\n          .expect('Content-Type', /text/)\n          .expect('Content-Type', /bloop/)\n          .expect('Content-Type', /html/)\n          .end(function (err) {\n            err.message.should.equal('expected \"Content-Type\" matching /bloop/, '\n              + 'got \"text/html; charset=utf-8\"');\n            shouldIncludeStackWithThisFile(err);\n            done();\n          });\n      });\n\n      it('should return an error if the last one fails', function (done) {\n        const app = express();\n        app.get('/', function (req, res) {\n          res.send('hey');\n        });\n\n        request(app)\n          .get('/')\n          .expect('Content-Type', /text/)\n          .expect('Content-Type', /html/)\n          .expect('Content-Type', /bloop/)\n          .end(function (err) {\n            err.message.should.equal('expected \"Content-Type\" matching /bloop/, '\n              + 'got \"text/html; charset=utf-8\"');\n            shouldIncludeStackWithThisFile(err);\n            done();\n          });\n      });\n    });\n  });\n});\n\ndescribe('request.agent(app)', function () {\n  const app = express();\n  const agent = request.agent(app)\n    .set('header', 'hey');\n\n  app.use(cookieParser());\n\n  app.get('/', function (req, res) {\n    res.cookie('cookie', 'hey');\n    res.send();\n  });\n\n  app.get('/return_cookies', function (req, res) {\n    if (req.cookies.cookie) res.send(req.cookies.cookie);\n    else res.send(':(');\n  });\n\n  app.get('/return_headers', function (req, res) {\n    if (req.get('header')) res.send(req.get('header'));\n    else res.send(':(');\n  });\n\n  it('should save cookies', function (done) {\n    agent\n      .get('/')\n      .expect('set-cookie', 'cookie=hey; Path=/', done);\n  });\n\n  it('should send cookies', function (done) {\n    agent\n      .get('/return_cookies')\n      .expect('hey', done);\n  });\n\n  it('should send global agent headers', function (done) {\n    agent\n      .get('/return_headers')\n      .expect('hey', done);\n  });\n});\n\ndescribe('agent.host(host)', function () {\n  it('should set request hostname', function (done) {\n    const app = express();\n    const agent = request.agent(app);\n\n    app.get('/', function (req, res) {\n      res.send({ hostname: req.hostname });\n    });\n\n    agent\n      .host('something.test')\n      .get('/')\n      .end(function (err, res) {\n        if (err) return done(err);\n        res.body.hostname.should.equal('something.test');\n        done();\n      });\n  });\n});\n\ndescribe('.<http verb> works as expected', function () {\n  it('.delete should work', function (done) {\n    const app = express();\n    app.delete('/', function (req, res) {\n      res.sendStatus(200);\n    });\n\n    request(app)\n      .delete('/')\n      .expect(200, done);\n  });\n  it('.del should work', function (done) {\n    const app = express();\n    app.delete('/', function (req, res) {\n      res.sendStatus(200);\n    });\n\n    request(app)\n      .del('/')\n      .expect(200, done);\n  });\n  it('.get should work', function (done) {\n    const app = express();\n    app.get('/', function (req, res) {\n      res.sendStatus(200);\n    });\n\n    request(app)\n      .get('/')\n      .expect(200, done);\n  });\n  it('.post should work', function (done) {\n    const app = express();\n    app.post('/', function (req, res) {\n      res.sendStatus(200);\n    });\n\n    request(app)\n      .post('/')\n      .expect(200, done);\n  });\n  it('.put should work', function (done) {\n    const app = express();\n    app.put('/', function (req, res) {\n      res.sendStatus(200);\n    });\n\n    request(app)\n      .put('/')\n      .expect(200, done);\n  });\n  it('.head should work', function (done) {\n    const app = express();\n    app.head('/', function (req, res) {\n      res.statusCode = 200;\n      res.set('Content-Encoding', 'gzip');\n      res.set('Content-Length', '1024');\n      res.status(200);\n      res.end();\n    });\n\n    request(app)\n      .head('/')\n      .set('accept-encoding', 'gzip, deflate')\n      .end(function (err, res) {\n        if (err) return done(err);\n        res.should.have.property('statusCode', 200);\n        res.headers.should.have.property('content-length', '1024');\n        done();\n      });\n  });\n});\n\ndescribe('assert ordering by call order', function () {\n  it('should assert the body before status', function (done) {\n    const app = express();\n\n    app.set('json spaces', 0);\n\n    app.get('/', function (req, res) {\n      res.status(500).json({ message: 'something went wrong' });\n    });\n\n    request(app)\n      .get('/')\n      .expect('hey')\n      .expect(200)\n      .end(function (err, res) {\n        err.message.should.equal('expected \\'hey\\' response body, '\n          + 'got \\'{\"message\":\"something went wrong\"}\\'');\n        shouldIncludeStackWithThisFile(err);\n        done();\n      });\n  });\n\n  it('should assert the status before body', function (done) {\n    const app = express();\n\n    app.set('json spaces', 0);\n\n    app.get('/', function (req, res) {\n      res.status(500).json({ message: 'something went wrong' });\n    });\n\n    request(app)\n      .get('/')\n      .expect(200)\n      .expect('hey')\n      .end(function (err, res) {\n        err.message.should.equal('expected 200 \"OK\", got 500 \"Internal Server Error\"');\n        shouldIncludeStackWithThisFile(err);\n        done();\n      });\n  });\n\n  it('should assert the fields before body and status', function (done) {\n    const app = express();\n\n    app.set('json spaces', 0);\n\n    app.get('/', function (req, res) {\n      res.status(200).json({ hello: 'world' });\n    });\n\n    request(app)\n      .get('/')\n      .expect('content-type', /html/)\n      .expect('hello')\n      .end(function (err, res) {\n        err.message.should.equal('expected \"content-type\" matching /html/, '\n          + 'got \"application/json; charset=utf-8\"');\n        shouldIncludeStackWithThisFile(err);\n        done();\n      });\n  });\n\n  it('should call the expect function in order', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.status(200).json({});\n    });\n\n    request(app)\n      .get('/')\n      .expect(function (res) {\n        res.body.first = 1;\n      })\n      .expect(function (res) {\n        (res.body.first === 1).should.be.true;\n        res.body.second = 2;\n      })\n      .end(function (err, res) {\n        if (err) return done(err);\n        (res.body.first === 1).should.be.true;\n        (res.body.second === 2).should.be.true;\n        done();\n      });\n  });\n\n  it('should call expect(fn) and expect(status, fn) in order', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.status(200).json({});\n    });\n\n    request(app)\n      .get('/')\n      .expect(function (res) {\n        res.body.first = 1;\n      })\n      .expect(200, function (err, res) {\n        (err === null).should.be.true;\n        (res.body.first === 1).should.be.true;\n        done();\n      });\n  });\n\n  it('should call expect(fn) and expect(header,value) in order', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res\n        .set('X-Some-Header', 'Some value')\n        .send();\n    });\n\n    request(app)\n      .get('/')\n      .expect('X-Some-Header', 'Some value')\n      .expect(function (res) {\n        res.headers['x-some-header'] = '';\n      })\n      .expect('X-Some-Header', '')\n      .end(done);\n  });\n\n  it('should call expect(fn) and expect(body) in order', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.json({ somebody: 'some body value' });\n    });\n\n    request(app)\n      .get('/')\n      .expect(/some body value/)\n      .expect(function (res) {\n        res.body.somebody = 'nobody';\n      })\n      .expect(/some body value/) // res.text should not be modified.\n      .expect({ somebody: 'nobody' })\n      .expect(function (res) {\n        res.text = 'gone';\n      })\n      .expect('gone')\n      .expect(/gone/)\n      .expect({ somebody: 'nobody' }) // res.body should not be modified\n      .expect('gone', done);\n  });\n});\n\ndescribe('request.get(url).query(vals) works as expected', function () {\n  it('normal single query string value works', function (done) {\n    const app = express();\n    app.get('/', function (req, res) {\n      res.status(200).send(req.query.val);\n    });\n\n    request(app)\n      .get('/')\n      .query({ val: 'Test1' })\n      .expect(200, function (err, res) {\n        res.text.should.be.equal('Test1');\n        done();\n      });\n  });\n\n  it('array query string value works', function (done) {\n    const app = express();\n    app.get('/', function (req, res) {\n      res.status(200).send(Array.isArray(req.query.val));\n    });\n\n    request(app)\n      .get('/')\n      .query({ 'val[]': ['Test1', 'Test2'] })\n      .expect(200, function (err, res) {\n        res.req.path.should.be.equal('/?val%5B%5D=Test1&val%5B%5D=Test2');\n        res.text.should.be.equal('true');\n        done();\n      });\n  });\n\n  it('array query string value work even with single value', function (done) {\n    const app = express();\n    app.get('/', function (req, res) {\n      res.status(200).send(Array.isArray(req.query.val));\n    });\n\n    request(app)\n      .get('/')\n      .query({ 'val[]': ['Test1'] })\n      .expect(200, function (err, res) {\n        res.req.path.should.be.equal('/?val%5B%5D=Test1');\n        res.text.should.be.equal('true');\n        done();\n      });\n  });\n\n  it('object query string value works', function (done) {\n    const app = express();\n    app.get('/', function (req, res) {\n      res.status(200).send(req.query.val.test);\n    });\n\n    request(app)\n      .get('/')\n      .query({ val: { test: 'Test1' } })\n      .expect(200, function (err, res) {\n        res.text.should.be.equal('Test1');\n        done();\n      });\n  });\n\n  it('handles unknown errors (err without res)', function (done) {\n    const app = express();\n\n    nock.disableNetConnect();\n\n    app.get('/', function (req, res) {\n      res.status(200).send('OK');\n    });\n\n    request(app)\n      .get('/')\n      // This expect should never get called, but exposes this issue with other\n      // errors being obscured by the response assertions\n      // https://github.com/ladjs/supertest/issues/352\n      .expect(200)\n      .end(function (err, res) {\n        should.exist(err);\n        should.not.exist(res);\n        err.should.be.an.instanceof(Error);\n        err.message.should.match(/Nock: Disallowed net connect/);\n        shouldIncludeStackWithThisFile(err);\n        done();\n      });\n\n    nock.restore();\n  });\n\n  // this scenario should never happen\n  // there shouldn't be any res if there is an err\n  // meant for test coverage for lib/test.js#169\n  // https://github.com/ladjs/supertest/blob/5543d674cf9aa4547927ba6010d31d9474950dec/lib/test.js#L169\n  it('handles unknown errors (err with res)', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.status(200).send('OK');\n    });\n\n    const resError = new Error();\n    resError.status = 400;\n\n    const serverRes = { status: 200 };\n\n    request(app)\n      .get('/')\n      // private api\n      .assert(resError, serverRes, function (err, res) {\n        should.exist(err);\n        should.exist(res);\n        err.should.equal(resError);\n        res.should.equal(serverRes);\n        // close the server explicitly (as we are not using expect/end/then)\n        this.end(done);\n      });\n  });\n\n  it('should assert using promises', function (done) {\n    const app = express();\n\n    app.get('/', function (req, res) {\n      res.status(400).send({ promise: true });\n    });\n\n    request(app)\n      .get('/')\n      .expect(400)\n      .then((res) => {\n        res.body.promise.should.be.equal(true);\n        done();\n      });\n  });\n});\n\nconst describeHttp2 = (http2) ? describe : describe.skip;\ndescribeHttp2('http2', function() {\n  // eslint-disable-next-line global-require\n  const proxyquire = require('proxyquire');\n\n  const tests = [\n    {\n      title: 'request(app)',\n      api: request,\n      mockApi: proxyquire('../index.js', { http2: null })\n    },\n    {\n      title: 'request.agent(app)',\n      api: request.agent,\n      mockApi: proxyquire('../lib/agent.js', { http2: null })\n    }\n  ];\n\n  tests.forEach(({ title, api, mockApi }) => {\n    describe(title, function () {\n      const app = function(req, res) {\n        res.end('hey');\n      };\n\n      it('should fire up the app on an ephemeral port', function (done) {\n        api(app, { http2: true })\n          .get('/')\n          .end(function (err, res) {\n            res.status.should.equal(200);\n            res.text.should.equal('hey');\n            done();\n          });\n      });\n\n      it('should work with an active server', function (done) {\n        const server = http2.createServer(app);\n\n        server.listen(function () {\n          api(server)\n            .get('/')\n            .http2()\n            .end(function (err, res) {\n              res.status.should.equal(200);\n              res.text.should.equal('hey');\n              // lose the external server explicitly\n              server.close(done);\n            });\n        });\n      });\n\n      it('should throw error if http2 is not supported', function() {\n        (function() {\n          mockApi(app, { http2: true });\n        }).should.throw('supertest: this version of Node.js does not support http2');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/throwError.js",
    "content": "'use strict';\n\n/**\n * This method needs to reside in its own module in order to properly test stack trace handling.\n */\nmodule.exports = function throwError(message) {\n  return function() {\n    throw new Error(message);\n  };\n};\n"
  }
]