SuperAgent - Ajax with less suck

# request

# with a callback

should invoke .end()

      request
      .get(uri + '/login', function(err, res){
        assert.equal(res.status, 200);
        done();
      })

# .end()

should issue a request

      request
      .get(uri + '/login')
      .end(function(err, res){
        assert.equal(res.status, 200);
        done();
      });

# res.error

should should be an Error object

      request
      .get(uri + '/error')
      .end(function(err, res){
        if (NODE) {
          res.error.message.should.equal('cannot GET /error (500)');
        }
        else {
          res.error.message.should.equal('cannot GET ' + uri + '/error (500)');
        }
        assert.strictEqual(res.error.status, 500);
        assert(err, 'should have an error for 500');
        assert.equal(err.message, 'Internal Server Error');
        done();
      });

# res.header

should be an object

      request
      .get(uri + '/login')
      .end(function(err, res){
        assert.equal('Express', res.header['x-powered-by']);
        done();
      });

# res.charset

should be set when present

      request
      .get(uri + '/login')
      .end(function(err, res){
        res.charset.should.equal('utf-8');
        done();
      });

# res.statusType

should provide the first digit

      request
      .get(uri + '/login')
      .end(function(err, res){
        assert(!err, 'should not have an error for success responses');
        assert.equal(200, res.status);
        assert.equal(2, res.statusType);
        done();
      });

# res.type

should provide the mime-type void of params

      request
      .get(uri + '/login')
      .end(function(err, res){
        res.type.should.equal('text/html');
        res.charset.should.equal('utf-8');
        done();
      });

# req.set(field, val)

should set the header field

      request
      .post(uri + '/echo')
      .set('X-Foo', 'bar')
      .set('X-Bar', 'baz')
      .end(function(err, res){
        assert.equal('bar', res.header['x-foo']);
        assert.equal('baz', res.header['x-bar']);
        done();
      })

# req.set(obj)

should set the header fields

      request
      .post(uri + '/echo')
      .set({ 'X-Foo': 'bar', 'X-Bar': 'baz' })
      .end(function(err, res){
        assert.equal('bar', res.header['x-foo']);
        assert.equal('baz', res.header['x-bar']);
        done();
      })

# req.type(str)

should set the Content-Type

      request
      .post(uri + '/echo')
      .type('text/x-foo')
      .end(function(err, res){
        res.header['content-type'].should.equal('text/x-foo');
        done();
      });

should map "json"

      request
      .post(uri + '/echo')
      .type('json')
      .send('{"a": 1}')
      .end(function(err, res){
        res.should.be.json;
        done();
      });

should map "html"

      request
      .post(uri + '/echo')
      .type('html')
      .end(function(err, res){
        res.header['content-type'].should.equal('text/html');
        done();
      });

# req.accept(str)

should set Accept

      request
      .get(uri + '/echo')
      .accept('text/x-foo')
      .end(function(err, res){
         res.header['accept'].should.equal('text/x-foo');
         done();
      });

should map "json"

      request
      .get(uri + '/echo')
      .accept('json')
      .end(function(err, res){
        res.header['accept'].should.equal('application/json');
        done();
      });

should map "xml"

      request
      .get(uri + '/echo')
      .accept('xml')
      .end(function(err, res){
        res.header['accept'].should.equal('application/xml');
        done();
      });

should map "html"

      request
      .get(uri + '/echo')
      .accept('html')
      .end(function(err, res){
        res.header['accept'].should.equal('text/html');
        done();
      });

# req.send(str)

should write the string

      request
      .post(uri + '/echo')
      .type('json')
      .send('{"name":"tobi"}')
      .end(function(err, res){
        res.text.should.equal('{"name":"tobi"}');
        done();
      });

# req.send(Object)

should default to json

      request
      .post(uri + '/echo')
      .send({ name: 'tobi' })
      .end(function(err, res){
        res.should.be.json
        res.text.should.equal('{"name":"tobi"}');
        done();
      });

# when called several times

should merge the objects

      request
      .post(uri + '/echo')
      .send({ name: 'tobi' })
      .send({ age: 1 })
      .end(function(err, res){
        res.should.be.json
        if (NODE) {
          res.buffered.should.be.true;
        }
        res.text.should.equal('{"name":"tobi","age":1}');
        done();
      });

# .end(fn)

should check arity

      request
      .post(uri + '/echo')
      .send({ name: 'tobi' })
      .end(function(err, res){
        assert.equal(null, err);
        res.text.should.equal('{"name":"tobi"}');
        done();
      });

should emit request

      var req = request.post(uri + '/echo');
      req.on('request', function(request){
        assert.equal(req, request);
        done();
      });
      req.end();

should emit response

      request
      .post(uri + '/echo')
      .send({ name: 'tobi' })
      .on('response', function(res){
        res.text.should.equal('{"name":"tobi"}');
        done();
      })
      .end();

# .then(fulfill, reject)

should support successful fulfills with .then(fulfill)

      request
      .post(uri + '/echo')
      .send({ name: 'tobi' })
      .then(function(res) {
        res.text.should.equal('{"name":"tobi"}');
        done();
      })

should reject an error with .then(null, reject)

      request
      .get(uri + '/error')
      .then(null, function(err) {
        assert.equal(err.status, 500);
        assert.equal(err.response.text, 'boom');
        done();
      })

# .abort()

should abort the request

      var req = request
      .get(uri + '/delay/3000')
      .end(function(err, res){
        assert(false, 'should not complete the request');
      });
      req.on('abort', done);
      setTimeout(function() {
        req.abort();
      }, 1000);

# request

# persistent agent

should gain a session on POST

      agent3
        .post('http://localhost:4000/signin')
        .end(function(err, res) {
          should.not.exist(err);
          res.should.have.status(200);
          should.not.exist(res.headers['set-cookie']);
          res.text.should.containEql('dashboard');
          done();
        });

should start with empty session (set cookies)

      agent1
        .get('http://localhost:4000/dashboard')
        .end(function(err, res) {
          should.exist(err);
          res.should.have.status(401);
          should.exist(res.headers['set-cookie']);
          done();
        });

should gain a session (cookies already set)

      agent1
        .post('http://localhost:4000/signin')
        .end(function(err, res) {
          should.not.exist(err);
          res.should.have.status(200);
          should.not.exist(res.headers['set-cookie']);
          res.text.should.containEql('dashboard');
          done();
        });

should persist cookies across requests

      agent1
        .get('http://localhost:4000/dashboard')
        .end(function(err, res) {
          should.not.exist(err);
          res.should.have.status(200);
          done();
        });

should have the cookie set in the end callback

      agent4
        .post('http://localhost:4000/setcookie')
        .end(function(err, res) {
          agent4
            .get('http://localhost:4000/getcookie')
            .end(function(err, res) {
              should.not.exist(err);
              res.should.have.status(200);
              assert.strictEqual(res.text, 'jar');
              done();
            });
        });

should not share cookies

      agent2
        .get('http://localhost:4000/dashboard')
        .end(function(err, res) {
          should.exist(err);
          res.should.have.status(401);
          done();
        });

should not lose cookies between agents

      agent1
        .get('http://localhost:4000/dashboard')
        .end(function(err, res) {
          should.not.exist(err);
          res.should.have.status(200);
          done();
        });

should be able to follow redirects

      agent1
        .get('http://localhost:4000/')
        .end(function(err, res) {
          should.not.exist(err);
          res.should.have.status(200);
          res.text.should.containEql('dashboard');
          done();
        });

should be able to post redirects

      agent1
        .post('http://localhost:4000/redirect')
        .send({ foo: 'bar', baz: 'blaaah' })
        .end(function(err, res) {
          should.not.exist(err);
          res.should.have.status(200);
          res.text.should.containEql('simple');
          res.redirects.should.eql(['http://localhost:4000/simple']);
          done();
        });

should be able to limit redirects

      agent1
        .get('http://localhost:4000/')
        .redirects(0)
        .end(function(err, res) {
          should.exist(err);
          res.should.have.status(302);
          res.redirects.should.eql([]);
          res.header.location.should.equal('/dashboard');
          done();
        });

should be able to create a new session (clear cookie)

      agent1
        .post('http://localhost:4000/signout')
        .end(function(err, res) {
          should.not.exist(err);
          res.should.have.status(200);
          should.exist(res.headers['set-cookie']);
          done();
        });

should regenerate with an empty session

      agent1
        .get('http://localhost:4000/dashboard')
        .end(function(err, res) {
          should.exist(err);
          res.should.have.status(401);
          should.not.exist(res.headers['set-cookie']);
          done();
        });

# Basic auth

# when credentials are present in url

should set Authorization

      request
      .get('http://tobi:learnboost@localhost:3010')
      .end(function(err, res){
        res.status.should.equal(200);
        done();
      });

# req.auth(user, pass)

should set Authorization

      request
      .get('http://localhost:3010')
      .auth('tobi', 'learnboost')
      .end(function(err, res){
        res.status.should.equal(200);
        done();
      });

# req.auth(user + ":" + pass)

should set authorization

      request
      .get('http://localhost:3010/again')
      .auth('tobi')
      .end(function(err, res){
        res.status.should.eql(200);
        done();
      });

# [node] request

# res.statusCode

should set statusCode

      request
      .get('http://localhost:5000/login', function(err, res){
        assert.strictEqual(res.statusCode, 200);
        done();
      })

# with an object

should format the url

      request
      .get(url.parse('http://localhost:5000/login'))
      .end(function(err, res){
        assert(res.ok);
        done();
      })

# without a schema

should default to http

      request
      .get('localhost:5000/login')
      .end(function(err, res){
        assert.equal(res.status, 200);
        done();
      })

# req.toJSON()

should describe the request

      request
      .post(':5000/echo')
      .send({ foo: 'baz' })
      .end(function(err, res){
        var obj = res.request.toJSON();
        assert.equal('POST', obj.method);
        assert.equal(':5000/echo', obj.url);
        assert.equal('baz', obj.data.foo);
        done();
      });

# should allow the send shorthand

with callback in the method call

      request
      .get('http://localhost:5000/login', function(err, res) {
          assert.equal(res.status, 200);
          done();
      });

with data in the method call

      request
      .post('http://localhost:5000/echo', { foo: 'bar' })
      .end(function(err, res) {
        assert.equal('{"foo":"bar"}', res.text);
        done();
      });

with callback and data in the method call

      request
      .post('http://localhost:5000/echo', { foo: 'bar' }, function(err, res) {
        assert.equal('{"foo":"bar"}', res.text);
        done();
      });

# res.toJSON()

should describe the response

      request
      .post('http://localhost:5000/echo')
      .send({ foo: 'baz' })
      .end(function(err, res){
        var obj = res.toJSON();
        assert.equal('object', typeof obj.header);
        assert.equal('object', typeof obj.req);
        assert.equal(200, obj.status);
        assert.equal('{"foo":"baz"}', obj.text);
        done();
      });

# res.links

should default to an empty object

      request
      .get('http://localhost:5000/login')
      .end(function(err, res){
        res.links.should.eql({});
        done();
      })

should parse the Link header field

      request
      .get('http://localhost:5000/links')
      .end(function(err, res){
        res.links.next.should.equal('https://api.github.com/repos/visionmedia/mocha/issues?page=2');
        done();
      })

# req.unset(field)

should remove the header field

      request
      .post('http://localhost:5000/echo')
      .unset('User-Agent')
      .end(function(err, res){
        assert.equal(void 0, res.header['user-agent']);
        done();
      })

# req.write(str)

should write the given data

      var req = request.post('http://localhost:5000/echo');
      req.set('Content-Type', 'application/json');
      req.write('{"name"').should.be.a.boolean;
      req.write(':"tobi"}').should.be.a.boolean;
      req.end(function(err, res){
        res.text.should.equal('{"name":"tobi"}');
        done();
      });

# req.pipe(stream)

should pipe the response to the given stream

      var stream = new EventEmitter;
      stream.buf = '';
      stream.writable = true;
      stream.write = function(chunk){
        this.buf += chunk;
      };
      stream.end = function(){
        this.buf.should.equal('{"name":"tobi"}');
        done();
      };
      request
      .post('http://localhost:5000/echo')
      .send('{"name":"tobi"}')
      .pipe(stream);

# .buffer()

should enable buffering

      request
      .get('http://localhost:5000/custom')
      .buffer()
      .end(function(err, res){
        assert.equal(null, err);
        assert.equal('custom stuff', res.text);
        assert(res.buffered);
        done();
      });

# .buffer(false)

should disable buffering

      request
      .post('http://localhost:5000/echo')
      .type('application/x-dog')
      .send('hello this is dog')
      .buffer(false)
      .end(function(err, res){
        assert.equal(null, err);
        assert.equal(null, res.text);
        res.body.should.eql({});
        var buf = '';
        res.setEncoding('utf8');
        res.on('data', function(chunk){ buf += chunk });
        res.on('end', function(){
          buf.should.equal('hello this is dog');
          done();
        });
      });

# .agent()

should return the defaut agent

      var req = request.post('http://localhost:5000/echo');
      req.agent().should.equal(false);
      done();

# .agent(undefined)

should set an agent to undefined and ensure it is chainable

      var req = request.get('http://localhost:5000/echo');
      var ret = req.agent(undefined);
      ret.should.equal(req);
      assert.strictEqual(req.agent(), undefined);
      done();

# .agent(new http.Agent())

should set passed agent

      var http = require('http');
      var req = request.get('http://localhost:5000/echo');
      var agent = new http.Agent();
      var ret = req.agent(agent);
      ret.should.equal(req);
      req.agent().should.equal(agent)
      done();

# with a content type other than application/json or text/*

should disable buffering

      request
      .post('http://localhost:5000/echo')
      .type('application/x-dog')
      .send('hello this is dog')
      .end(function(err, res){
        assert.equal(null, err);
        assert.equal(null, res.text);
        res.body.should.eql({});
        var buf = '';
        res.setEncoding('utf8');
        res.buffered.should.be.false;
        res.on('data', function(chunk){ buf += chunk });
        res.on('end', function(){
          buf.should.equal('hello this is dog');
          done();
        });
      });

# content-length

should be set to the byte length of a non-buffer object

      var decoder = new StringDecoder('utf8');
      var img = fs.readFileSync(__dirname + '/fixtures/test.png');
      img = decoder.write(img);
      request
      .post('http://localhost:5000/echo')
      .type('application/x-image')
      .send(img)
      .buffer(false)
      .end(function(err, res){
        assert.equal(null, err);
        assert(!res.buffered);
        assert.equal(res.header['content-length'], Buffer.byteLength(img));
        done();
      });

should be set to the length of a buffer object

      var img = fs.readFileSync(__dirname + '/fixtures/test.png');
      request
      .post('http://localhost:5000/echo')
      .type('application/x-image')
      .send(img)
      .buffer(true)
      .end(function(err, res){
        assert.equal(null, err);
        assert(res.buffered);
        assert.equal(res.header['content-length'], img.length);
        done();
      });

# req.set("Content-Type", contentType)

should work with just the contentType component

      request
      .post('http://localhost:3005/echo')
      .set('Content-Type', 'application/json')
      .send({ name: 'tobi' })
      .end(function(err, res){
        assert(!err);
        done();
      });

should work with the charset component

      request
      .post('http://localhost:3005/echo')
      .set('Content-Type', 'application/json; charset=utf-8')
      .send({ name: 'tobi' })
      .end(function(err, res){
        assert(!err);
        done();
      });

# exports

should expose Part

      request.Part.should.be.a.function;

should expose .protocols

      Object.keys(request.protocols)
        .should.eql(['http:', 'https:']);

should expose .serialize

      Object.keys(request.serialize)
        .should.eql(['application/x-www-form-urlencoded', 'application/json']);

should expose .parse

      Object.keys(request.parse)
        .should.eql(['application/x-www-form-urlencoded', 'application/json', 'text', 'image']);

# flags

# with 4xx response

should set res.error and res.clientError

      request
      .get('http://localhost:3004/notfound')
      .end(function(err, res){
        assert(err);
        assert(!res.ok, 'response should not be ok');
        assert(res.error, 'response should be an error');
        assert(res.clientError, 'response should be a client error');
        assert(!res.serverError, 'response should not be a server error');
        done();
      });

# with 5xx response

should set res.error and res.serverError

      request
      .get('http://localhost:3004/error')
      .end(function(err, res){
        assert(err);
        assert(!res.ok, 'response should not be ok');
        assert(!res.notFound, 'response should not be notFound');
        assert(res.error, 'response should be an error');
        assert(!res.clientError, 'response should not be a client error');
        assert(res.serverError, 'response should be a server error');
        done();
      });

# with 404 Not Found

should res.notFound

      request
      .get('http://localhost:3004/notfound')
      .end(function(err, res){
        assert(err);
        assert(res.notFound, 'response should be .notFound');
        done();
      });

# with 400 Bad Request

should set req.badRequest

      request
      .get('http://localhost:3004/bad-request')
      .end(function(err, res){
        assert(err);
        assert(res.badRequest, 'response should be .badRequest');
        done();
      });

# with 401 Bad Request

should set res.unauthorized

      request
      .get('http://localhost:3004/unauthorized')
      .end(function(err, res){
        assert(err);
        assert(res.unauthorized, 'response should be .unauthorized');
        done();
      });

# with 406 Not Acceptable

should set res.notAcceptable

      request
      .get('http://localhost:3004/not-acceptable')
      .end(function(err, res){
        assert(err);
        assert(res.notAcceptable, 'response should be .notAcceptable');
        done();
      });

# with 204 No Content

should set res.noContent

      request
      .get('http://localhost:3004/no-content')
      .end(function(err, res){
        assert(!err);
        assert(res.noContent, 'response should be .noContent');
        done();
      });

# req.send(Object) as "form"

# with req.type() set to form

should send x-www-form-urlencoded data

      request
      .post('http://localhost:3002/echo')
      .type('form')
      .send({ name: 'tobi' })
      .end(function(err, res){
        res.header['content-type'].should.equal('application/x-www-form-urlencoded');
        res.text.should.equal('name=tobi');
        done();
      });

# when called several times

should merge the objects

      request
      .post('http://localhost:3002/echo')
      .type('form')
      .send({ name: { first: 'tobi', last: 'holowaychuk' } })
      .send({ age: '1' })
      .end(function(err, res){
        res.header['content-type'].should.equal('application/x-www-form-urlencoded');
        res.text.should.equal('name%5Bfirst%5D=tobi&name%5Blast%5D=holowaychuk&age=1');
        done();
      });

# req.send(String)

should default to "form"

      request
      .post('http://localhost:3002/echo')
      .send('user[name]=tj')
      .send('user[email]=tj@vision-media.ca')
      .end(function(err, res){
        res.header['content-type'].should.equal('application/x-www-form-urlencoded');
        res.body.should.eql({ user: { name: 'tj', email: 'tj@vision-media.ca' } });
        done();
      })

# res.body

# application/x-www-form-urlencoded

should parse the body

      request
      .get('http://localhost:3002/form-data')
      .end(function(err, res){
        res.text.should.equal('pet[name]=manny');
        res.body.should.eql({ pet: { name: 'manny' }});
        done();
      });

# https

# request

should give a good response

      request
      .get('https://localhost:8443/')
      .ca(cert)
      .end(function(err, res){
        assert(res.ok);
        assert.strictEqual('Safe and secure!', res.text);
        done();
      });

# .agent

should be able to make multiple requests without redefining the certificate

      var agent = request.agent({ca: cert});
      agent
      .get('https://localhost:8443/')
      .end(function(err, res){
        assert(res.ok);
        assert.strictEqual('Safe and secure!', res.text);
        agent
        .get(url.parse('https://localhost:8443/'))
        .end(function(err, res){
          assert(res.ok);
          assert.strictEqual('Safe and secure!', res.text);
          done();
        });
      });

# res.body

# image/png

should parse the body

      request
      .get('http://localhost:3011/image')
      .end(function(err, res){
        (res.body.length - img.length).should.equal(0);
        done();
      });

# zlib

should deflate the content

      request
        .get('http://localhost:3080')
        .end(function(err, res){
          res.should.have.status(200);
          res.text.should.equal(subject);
          res.headers['content-length'].should.be.below(subject.length);
          done();
        });

should handle corrupted responses

      request
        .get('http://localhost:3080/corrupt')
        .end(function(err, res){
          assert(err, 'missing error');
          assert(!res, 'response should not be defined');
          done();
        });

# without encoding set

should emit buffers

      request
        .get('http://localhost:3080/binary')
        .end(function(err, res){
          res.should.have.status(200);
          res.headers['content-length'].should.be.below(subject.length);
          res.on('data', function(chunk){
            chunk.should.have.length(subject.length);
          });
          res.on('end', done);
        });

# req.send(Object) as "json"

should default to json

      request
      .post('http://localhost:3005/echo')
      .send({ name: 'tobi' })
      .end(function(err, res){
        res.should.be.json
        res.text.should.equal('{"name":"tobi"}');
        done();
      });

should work with arrays

      request
      .post('http://localhost:3005/echo')
      .send([1,2,3])
      .end(function(err, res){
        res.should.be.json
        res.text.should.equal('[1,2,3]');
        done();
      });

should work with value null

      request
      .post('http://localhost:3005/echo')
      .type('json')
      .send('null')
      .end(function(err, res){
        res.should.be.json
        assert.strictEqual(res.body, null);
        done();
      });

should work with value false

      request
      .post('http://localhost:3005/echo')
      .type('json')
      .send('false')
      .end(function(err, res){
        res.should.be.json
        res.body.should.equal(false);
        done();
      });

should work with value 0

      request
      .post('http://localhost:3005/echo')
      .type('json')
      .send('0')
      .end(function(err, res){
        res.should.be.json
        res.body.should.equal(0);
        done();
      });

should work with empty string value

      request
      .post('http://localhost:3005/echo')
      .type('json')
      .send('""')
      .end(function(err, res){
        res.should.be.json
        res.body.should.equal("");
        done();
      });

should work with GET

      request
      .get('http://localhost:3005/echo')
      .send({ tobi: 'ferret' })
      .end(function(err, res){
        res.should.be.json
        res.text.should.equal('{"tobi":"ferret"}');
        done();
      });

should work with vendor MIME type

      request
      .post('http://localhost:3005/echo')
      .set('Content-Type', 'application/vnd.example+json')
      .send({ name: 'vendor' })
      .end(function(err, res){
        res.text.should.equal('{"name":"vendor"}');
        done();
      });

# when called several times

should merge the objects

      request
      .post('http://localhost:3005/echo')
      .send({ name: 'tobi' })
      .send({ age: 1 })
      .end(function(err, res){
        res.should.be.json
        res.text.should.equal('{"name":"tobi","age":1}');
        done();
      });

# res.body

# application/json

should parse the body

      request
      .get('http://localhost:3005/json')
      .end(function(err, res){
        res.text.should.equal('{"name":"manny"}');
        res.body.should.eql({ name: 'manny' });
        done();
      });

# HEAD requests

should not throw a parse error

      request
      .head('http://localhost:3005/json')
      .end(function(err, res){
        assert.strictEqual(err, null);
        assert.strictEqual(res.text, undefined)
        assert.strictEqual(Object.keys(res.body).length, 0)
        done();
      });

# Invalid JSON response

should return the raw response

      request
      .get('http://localhost:3005/invalid-json')
      .end(function(err, res){
        assert.deepEqual(err.rawResponse, ")]}', {'header':{'code':200,'text':'OK','version':'1.0'},'data':'some data'}");
        done();
      });

# No content

should not throw a parse error

      request
      .get('http://localhost:3005/no-content')
      .end(function(err, res){
        assert.strictEqual(err, null);
        assert.strictEqual(res.text, '');
        assert.strictEqual(Object.keys(res.body).length, 0);
        done();
      });

# application/json+hal

should parse the body

      request
      .get('http://localhost:3005/json-hal')
      .end(function(err, res){
        if (err) return done(err);
        res.text.should.equal('{"name":"hal 5000"}');
        res.body.should.eql({ name: 'hal 5000' });
        done();
      });

# vnd.collection+json

should parse the body

      request
      .get('http://localhost:3005/collection-json')
      .end(function(err, res){
        res.text.should.equal('{"name":"chewbacca"}');
        res.body.should.eql({ name: 'chewbacca' });
        done();
      });

# Request

# #attach(name, path, filename)

should use the custom filename

      request
      .post(':3005/echo')
      .attach('document', 'test/node/fixtures/user.html', 'doc.html')
      .end(function(err, res){
        if (err) return done(err);
        var html = res.files.document;
        html.name.should.equal('doc.html');
        html.type.should.equal('text/html');
        read(html.path).should.equal('<h1>name</h1>');
        done();
      })

should fire progress event

      var loaded = 0;
      var total = 0;
      request
      .post(':3005/echo')
      .attach('document', 'test/node/fixtures/user.html')
      .on('progress', function (event) {
        total = event.total;
        loaded = event.loaded;
      })
      .end(function(err, res){
        if (err) return done(err);
        var html = res.files.document;
        html.name.should.equal('user.html');
        html.type.should.equal('text/html');
        read(html.path).should.equal('<h1>name</h1>');
        total.should.equal(221);
        loaded.should.equal(221);
        done();
      })

# with network error

should error

      request
      .get('http://localhost:' + this.port + '/')
      .end(function(err, res){
        assert(err, 'expected an error');
        done();
      });

# request

# not modified

should start with 200

      request
      .get('http://localhost:3008/')
      .end(function(err, res){
        res.should.have.status(200)
        res.text.should.match(/^\d+$/);
        ts = +res.text;
        done();
      });

should then be 304

      request
      .get('http://localhost:3008/')
      .set('If-Modified-Since', new Date(ts).toUTCString())
      .end(function(err, res){
        res.should.have.status(304)
        // res.text.should.be.empty
        done();
      });

# req.parse(fn)

should take precedence over default parsers

      request
      .get('http://localhost:3033/manny')
      .parse(request.parse['application/json'])
      .end(function(err, res){
        assert(res.ok);
        assert.equal('{"name":"manny"}', res.text);
        assert.equal('manny', res.body.name);
        done();
      });

should be the only parser

      request
      .get('http://localhost:3033/image')
      .parse(function(res, fn) {
        res.on('data', function() {});
      })
      .end(function(err, res){
        assert(res.ok);
        assert.strictEqual(res.text, undefined);
        res.body.should.eql({});
        done();
      });

should emit error if parser throws

      request
      .get('http://localhost:3033/manny')
      .parse(function() {
        throw new Error('I am broken');
      })
      .on('error', function(err) {
        err.message.should.equal('I am broken');
        done();
      })
      .end();

should emit error if parser returns an error

      request
      .get('http://localhost:3033/manny')
      .parse(function(res, fn) {
        fn(new Error('I am broken'));
      })
      .on('error', function(err) {
        err.message.should.equal('I am broken');
        done();
      })
      .end()

should not emit error on chunked json

      request
      .get('http://localhost:3033/chunked-json')
      .end(function(err){
        assert(!err);
        done();
      });

should not emit error on aborted chunked json

      var req = request
      .get('http://localhost:3033/chunked-json')
      .end(function(err){
        assert(!err);
        done();
      });
      setTimeout(function(){req.abort()},50);

# pipe on redirect

should follow Location

      var stream = fs.createWriteStream('test/node/fixtures/pipe.txt');
      var redirects = [];
      var req = request
        .get('http://localhost:3012/')
        .on('redirect', function (res) {
          redirects.push(res.headers.location);
        })
        .on('end', function () {
          var arr = [];
          arr.push('/movies');
          arr.push('/movies/all');
          arr.push('/movies/all/0');
          redirects.should.eql(arr);
          fs.readFileSync('test/node/fixtures/pipe.txt', 'utf8').should.eql('first movie page');
          done();
        });
        req.pipe(stream);

# request pipe

should act as a writable stream

      var req = request.post('http://localhost:3020');
      var stream = fs.createReadStream('test/node/fixtures/user.json');
      req.type('json');
      req.on('response', function(res){
        res.body.should.eql({ name: 'tobi' });
        done();
      });
      stream.pipe(req);

should act as a readable stream

      var stream = fs.createWriteStream('test/node/fixtures/tmp.json');
      var req = request.get('http://localhost:3025');
      req.type('json');
      req.on('end', function(){
        JSON.parse(fs.readFileSync('test/node/fixtures/tmp.json', 'utf8')).should.eql({ name: 'tobi' });
        done();
      });
      req.pipe(stream);

# req.query(String)

should supply uri malformed error to the callback

      request
      .get('http://localhost:3006')
      .query('name=toby')
      .query('a=\uD800')
      .query({ b: '\uD800' })
      .end(function(err, res){
        assert(err instanceof Error);
        assert.equal('URIError', err.name);
        done();
      });

should support passing in a string

      request
      .del('http://localhost:3006')
      .query('name=t%F6bi')
      .end(function(err, res){
        res.body.should.eql({ name: 't%F6bi' });
        done();
      });

should work with url query-string and string for query

      request
      .del('http://localhost:3006/?name=tobi')
      .query('age=2%20')
      .end(function(err, res){
        res.body.should.eql({ name: 'tobi', age: '2 ' });
        done();
      });

should support compound elements in a string

      request
        .del('http://localhost:3006/')
        .query('name=t%F6bi&age=2')
        .end(function(err, res){
          res.body.should.eql({ name: 't%F6bi', age: '2' });
          done();
        });

should work when called multiple times with a string

      request
      .del('http://localhost:3006/')
      .query('name=t%F6bi')
      .query('age=2%F6')
      .end(function(err, res){
        res.body.should.eql({ name: 't%F6bi', age: '2%F6' });
        done();
      });

should work with normal `query` object and query string

      request
      .del('http://localhost:3006/')
      .query('name=t%F6bi')
      .query({ age: '2' })
      .end(function(err, res){
        res.body.should.eql({ name: 't%F6bi', age: '2' });
        done();
      });

# req.query(Object)

should construct the query-string

      request
      .del('http://localhost:3006/')
      .query({ name: 'tobi' })
      .query({ order: 'asc' })
      .query({ limit: ['1', '2'] })
      .end(function(err, res){
        res.body.should.eql({ name: 'tobi', order: 'asc', limit: ['1', '2'] });
        done();
      });

should not error on dates

      var date = new Date(0);
      request
      .del('http://localhost:3006/')
      .query({ at: date })
      .end(function(err, res){
        assert.equal(date.toISOString(), res.body.at);
        done();
      });

should work after setting header fields

      request
      .del('http://localhost:3006/')
      .set('Foo', 'bar')
      .set('Bar', 'baz')
      .query({ name: 'tobi' })
      .query({ order: 'asc' })
      .query({ limit: ['1', '2'] })
      .end(function(err, res){
        res.body.should.eql({ name: 'tobi', order: 'asc', limit: ['1', '2'] });
        done();
      });

should append to the original query-string

      request
      .del('http://localhost:3006/?name=tobi')
      .query({ order: 'asc' })
      .end(function(err, res) {
        res.body.should.eql({ name: 'tobi', order: 'asc' });
        done();
      });

should retain the original query-string

      request
      .del('http://localhost:3006/?name=tobi')
      .end(function(err, res) {
        res.body.should.eql({ name: 'tobi' });
        done();
      });

# request.get

# on 301 redirect

should follow Location with a GET request

      var req = request
        .get('http://localhost:3210/test-301')
        .redirects(1)
        .end(function(err, res){
          req.req._headers.host.should.eql('localhost:3211');
          res.status.should.eql(200);
          res.text.should.eql('GET');
          done();
        });

# on 302 redirect

should follow Location with a GET request

      var req = request
        .get('http://localhost:3210/test-302')
        .redirects(1)
        .end(function(err, res){
          req.req._headers.host.should.eql('localhost:3211');
          res.status.should.eql(200);
          res.text.should.eql('GET');
          done();
        });

# on 303 redirect

should follow Location with a GET request

      var req = request
        .get('http://localhost:3210/test-303')
        .redirects(1)
        .end(function(err, res){
          req.req._headers.host.should.eql('localhost:3211');
          res.status.should.eql(200);
          res.text.should.eql('GET');
          done();
        });

# on 307 redirect

should follow Location with a GET request

      var req = request
        .get('http://localhost:3210/test-307')
        .redirects(1)
        .end(function(err, res){
          req.req._headers.host.should.eql('localhost:3211');
          res.status.should.eql(200);
          res.text.should.eql('GET');
          done();
        });

# on 308 redirect

should follow Location with a GET request

      var req = request
        .get('http://localhost:3210/test-308')
        .redirects(1)
        .end(function(err, res){
          req.req._headers.host.should.eql('localhost:3211');
          res.status.should.eql(200);
          res.text.should.eql('GET');
          done();
        });

# request.post

# on 301 redirect

should follow Location with a GET request

      var req = request
        .post('http://localhost:3210/test-301')
        .redirects(1)
        .end(function(err, res){
          req.req._headers.host.should.eql('localhost:3211');
          res.status.should.eql(200);
          res.text.should.eql('GET');
          done();
        });

# on 302 redirect

should follow Location with a GET request

      var req = request
        .post('http://localhost:3210/test-302')
        .redirects(1)
        .end(function(err, res){
          req.req._headers.host.should.eql('localhost:3211');
          res.status.should.eql(200);
          res.text.should.eql('GET');
          done();
        });

# on 303 redirect

should follow Location with a GET request

      var req = request
        .post('http://localhost:3210/test-303')
        .redirects(1)
        .end(function(err, res){
          req.req._headers.host.should.eql('localhost:3211');
          res.status.should.eql(200);
          res.text.should.eql('GET');
          done();
        });

# on 307 redirect

should follow Location with a POST request

      var req = request
        .post('http://localhost:3210/test-307')
        .redirects(1)
        .end(function(err, res){
          req.req._headers.host.should.eql('localhost:3211');
          res.status.should.eql(200);
          res.text.should.eql('POST');
          done();
        });

# on 308 redirect

should follow Location with a POST request

      var req = request
        .post('http://localhost:3210/test-308')
        .redirects(1)
        .end(function(err, res){
          req.req._headers.host.should.eql('localhost:3211');
          res.status.should.eql(200);
          res.text.should.eql('POST');
          done();
        });

# request

# on redirect

should follow Location

      var redirects = [];
      request
      .get('http://localhost:3003/')
      .on('redirect', function(res){
        redirects.push(res.headers.location);
      })
      .end(function(err, res){
        var arr = [];
        arr.push('/movies');
        arr.push('/movies/all');
        arr.push('/movies/all/0');
        redirects.should.eql(arr);
        res.text.should.equal('first movie page');
        done();
      });

should retain header fields

      request
      .get('http://localhost:3003/header')
      .set('X-Foo', 'bar')
      .end(function(err, res){
        res.body.should.have.property('x-foo', 'bar');
        done();
      });

should remove Content-* fields

      request
      .post('http://localhost:3003/header')
      .type('txt')
      .set('X-Foo', 'bar')
      .set('X-Bar', 'baz')
      .send('hey')
      .end(function(err, res){
        res.body.should.have.property('x-foo', 'bar');
        res.body.should.have.property('x-bar', 'baz');
        res.body.should.not.have.property('content-type');
        res.body.should.not.have.property('content-length');
        res.body.should.not.have.property('transfer-encoding');
        done();
      });

should retain cookies

      request
      .get('http://localhost:3003/header')
      .set('Cookie', 'foo=bar;')
      .end(function(err, res){
        res.body.should.have.property('cookie', 'foo=bar;');
        done();
      });

should preserve timeout across redirects

      request
      .get('http://localhost:3003/movies/random')
      .timeout(250)
      .end(function(err, res){
        assert(err instanceof Error, 'expected an error');
        err.should.have.property('timeout', 250);
        done();
      });

should not resend query parameters

      var redirects = [];
      var query = [];
      request
      .get('http://localhost:3003/?foo=bar')
      .on('redirect', function(res){
        query.push(res.headers.query);
        redirects.push(res.headers.location);
      })
      .end(function(err, res){
        var arr = [];
        arr.push('/movies');
        arr.push('/movies/all');
        arr.push('/movies/all/0');
        redirects.should.eql(arr);
        res.text.should.equal('first movie page');
        query.should.eql(['{"foo":"bar"}', '{}', '{}']);
        res.headers.query.should.eql('{}');
        done();
      });

should handle no location header

      request
      .get('http://localhost:3003/bad-redirect')
      .end(function(err, res){
        err.message.should.equal('No location header for redirect');
        done();
      });

# when relative

should redirect to a sibling path

      var redirects = [];
      request
      .get('http://localhost:3003/relative')
      .on('redirect', function(res){
        redirects.push(res.headers.location);
      })
      .end(function(err, res){
        var arr = [];
        redirects.should.eql(['tobi']);
        res.text.should.equal('tobi');
        done();
      });

should redirect to a parent path

      var redirects = [];
      request
      .get('http://localhost:3003/relative/sub')
      .on('redirect', function(res){
        redirects.push(res.headers.location);
      })
      .end(function(err, res){
        var arr = [];
        redirects.should.eql(['../tobi']);
        res.text.should.equal('tobi');
        done();
      });

# req.redirects(n)

should alter the default number of redirects to follow

      var redirects = [];
      request
      .get('http://localhost:3003/')
      .redirects(2)
      .on('redirect', function(res){
        redirects.push(res.headers.location);
      })
      .end(function(err, res){
        var arr = [];
        assert(res.redirect, 'res.redirect');
        arr.push('/movies');
        arr.push('/movies/all');
        redirects.should.eql(arr);
        res.text.should.match(/Moved Temporarily|Found/);
        done();
      });

# on POST

should redirect as GET

      var redirects = [];
      request
      .post('http://localhost:3003/movie')
      .send({ name: 'Tobi' })
      .redirects(2)
      .on('redirect', function(res){
        redirects.push(res.headers.location);
      })
      .end(function(err, res){
        var arr = [];
        arr.push('/movies/all/0');
        redirects.should.eql(arr);
        res.text.should.equal('first movie page');
        done();
      });

# on 303

should redirect with same method

      request
      .put('http://localhost:3003/redirect-303')
      .send({msg: "hello"})
      .redirects(1)
      .on('redirect', function(res) {
        res.headers.location.should.equal('/reply-method')
      })
      .end(function(err, res){
        res.text.should.equal('method=get');
        done();
      })

# on 307

should redirect with same method

      request
      .put('http://localhost:3003/redirect-307')
      .send({msg: "hello"})
      .redirects(1)
      .on('redirect', function(res) {
        res.headers.location.should.equal('/reply-method')
      })
      .end(function(err, res){
        res.text.should.equal('method=put');
        done();
      })

# on 308

should redirect with same method

      request
      .put('http://localhost:3003/redirect-308')
      .send({msg: "hello"})
      .redirects(1)
      .on('redirect', function(res) {
        res.headers.location.should.equal('/reply-method')
      })
      .end(function(err, res){
        res.text.should.equal('method=put');
        done();
      })

# response

should act as a readable stream

      var req = request
        .get('http://localhost:3025')
        .buffer(false);
      req.end(function(err,res){
        if (err) return done(err);
        var trackEndEvent = 0;
        var trackCloseEvent = 0;
        res.on('end',function(){
          trackEndEvent++;
          trackEndEvent.should.equal(1);
          trackCloseEvent.should.equal(0);  // close should not have been called
          done();
        });
        res.on('close',function(){
          trackCloseEvent++;
        });

        (function(){ res.pause() }).should.not.throw();
        (function(){ res.resume() }).should.not.throw();
        (function(){ res.destroy() }).should.not.throw();
      });

# .timeout(ms)

# when timeout is exceeded

should error

      request
      .get('http://localhost:3009/500')
      .timeout(150)
      .end(function(err, res){
        assert(err, 'expected an error');
        assert.equal('number', typeof err.timeout, 'expected an error with .timeout');
        assert.equal('ECONNABORTED', err.code, 'expected abort error code')
        done();
      });

# res.toError()

should return an Error

      request
      .get('http://localhost:' + server.address().port)
      .end(function(err, res){
        var err = res.toError();
        assert.equal(err.status, 400);
        assert.equal(err.method, 'GET');
        assert.equal(err.path, '/');
        assert.equal(err.message, 'cannot GET / (400)');
        assert.equal(err.text, 'invalid json');
        done();
      });

# req.get()

should set a default user-agent

      request
      .get('http://localhost:3345/ua')
      .end(function(err, res){
        assert(res.headers);
        assert(res.headers['user-agent']);
        assert(/^node-superagent\/\d+\.\d+\.\d+$/.test(res.headers['user-agent']));
        done();
      });

should be able to override user-agent

      request
      .get('http://localhost:3345/ua')
      .set('User-Agent', 'foo/bar')
      .end(function(err, res){
        assert(res.headers);
        assert.equal(res.headers['user-agent'], 'foo/bar');
        done();
      });

should be able to wipe user-agent

      request
      .get('http://localhost:3345/ua')
      .unset('User-Agent')
      .end(function(err, res){
        assert(res.headers);
        assert.equal(res.headers['user-agent'], void 0);
        done();
      });

# utils.type(str)

should return the mime type

      utils.type('application/json; charset=utf-8')
        .should.equal('application/json');
      utils.type('application/json')
        .should.equal('application/json');

# utils.params(str)

should return the field parameters

      var str = 'application/json; charset=utf-8; foo  = bar';
      var obj = utils.params(str);
      obj.charset.should.equal('utf-8');
      obj.foo.should.equal('bar');
      var str = 'application/json';
      utils.params(str).should.eql({});

# utils.parseLinks(str)

should parse links

      var str = '<https://api.github.com/repos/visionmedia/mocha/issues?page=2>; rel="next", <https://api.github.com/repos/visionmedia/mocha/issues?page=5>; rel="last"';
      var ret = utils.parseLinks(str);
      ret.next.should.equal('https://api.github.com/repos/visionmedia/mocha/issues?page=2');
      ret.last.should.equal('https://api.github.com/repos/visionmedia/mocha/issues?page=5');