text: // transpile:mocha
  /* global describe:true, it:true */
  
  import { JWProxy } from '../..';
  import request from './mock-request';
  import chai from 'chai';
  import chaiAsPromised from 'chai-as-promised';
  
  
  const should = chai.should();
  chai.use(chaiAsPromised);
  
  function buildReqRes (url, method, body) {
    let req = {originalUrl: url, method, body};
    let res = {};
    res.headers = {};
    res.set = (k, v) => { res[k] = v; };
    res.status = (code) => {
      res.sentCode = code;
      return res;
    };
    res.send = (body) => {
      try {
        body = JSON.parse(body);
      } catch (e) {}
      res.sentBody = body;
    };
    return [req, res];
  }
  
  function mockProxy (opts = {}) {
    let proxy = new JWProxy(opts);
    proxy.request = async function (...args) {
      return await request(...args);
    };
    return proxy;
  }
  
  describe('proxy', () => {
    it('should override default params', () => {
      let j = mockProxy({server: '127.0.0.2'});
      j.server.should.equal('127.0.0.2');
      j.port.should.equal(4444);
    });
    it('should save session id on session creation', async () => {
      let j = mockProxy();
      let [res, body] = await j.proxy('/session', 'POST', {desiredCapabilities: {}});
      res.statusCode.should.equal(200);
      body.should.eql({status: 0, sessionId: '123', value: {browserName: 'boo'}});
      j.sessionId.should.equal('123');
    });
    it('should save session id on session creation with 303', async () => {
      let j = mockProxy();
      let [res, body] = await j.proxy('/session', 'POST', {desiredCapabilities: {redirect: true}});
      res.statusCode.should.equal(303);
      body.should.eql('http://localhost:4444/wd/hub/session/123');
      j.sessionId.should.equal('123');
    });
    describe('getUrlForProxy', () => {
      it('should modify session id, host, and port', async () => {
        let j = mockProxy({sessionId: '123'});
        j.getUrlForProxy('http://host.com:1234/wd/hub/session/456/element/200/value')
         .should.eql('http://localhost:4444/wd/hub/session/123/element/200/value');
      });
      it('should prepend scheme, host and port if not provided', async () => {
        let j = mockProxy({sessionId: '123'});
        j.getUrlForProxy('/wd/hub/session/456/element/200/value')
         .should.eql('http://localhost:4444/wd/hub/session/123/element/200/value');
      });
      it('should work with urls which do not have sessiopn ids', async () => {
        let j = mockProxy({sessionId: '123'});
        j.getUrlForProxy('http://host.com:1234/wd/hub/session')
         .should.eql('http://localhost:4444/wd/hub/session');
  
        let newUrl = j.getUrlForProxy('/wd/hub/session');
        newUrl.should.eql('http://localhost:4444/wd/hub/session');
      });
      it('should throw an error if url requires a sessionId but its null', async () => {
        let j = mockProxy();
        let e;
        try {
          j.getUrlForProxy('/wd/hub/session/456/element/200/value');
        } catch (err) {
          e = err;
        }
        should.exist(e);
        e.message.should.contain('without session id');
      });
      it('should not throw an error if url does not require a session id and its null', async () => {
        let j = mockProxy();
        let newUrl = j.getUrlForProxy('/wd/hub/status');
  
        should.exist(newUrl);
      });
    });
    describe('straight proxy', () => {
      it('should successfully proxy straight', async () => {
        let j = mockProxy();
        let [res, body] = await j.proxy('/status', 'GET');
        res.statusCode.should.equal(200);
        body.should.eql({status: 0, value: {foo: 'bar'}});
      });
      it('should pass along request errors', async () => {
        let j = mockProxy({sessionId: '123'});
        j.proxy('/badurl', 'GET').should.eventually.be.rejectedWith("Could not proxy");
      });
      it('should proxy error responses and codes', async () => {
        let j = mockProxy({sessionId: '123'});
        let [res, body] = await j.proxy('/element/bad/text', 'GET');
        res.statusCode.should.equal(500);
        body.should.eql({status: 11, value: {message: 'Invisible element'}});
      });
    });
    describe('command proxy', () => {
      it('should successfully proxy command', async () => {
        let j = mockProxy();
        let res = await j.command('/status', 'GET');
        res.should.eql({foo: 'bar'});
      });
      it('should pass along request errors', async () => {
        let j = mockProxy({sessionId: '123'});
        j.command('/badurl', 'GET').should.eventually.be.rejectedWith("Could not proxy");
      });
      it('should throw when a command fails', async () => {
        let j = mockProxy({sessionId: '123'});
        let e = null;
        try {
          await j.command('/element/bad/text', 'GET');
        } catch (err) {
          e = err;
        }
        should.exist(e);
        e.message.should.contain('Original error: Invisible element');
        e.value.should.eql({message: 'Invisible element'});
        e.status.should.equal(11);
      });
      it('should return response body when a command fails with a 200', async () => {
        let j = mockProxy({sessionId: '123'});
        let res = await j.command('/element/200/text', 'GET');
        res.value.should.eql({message: 'Invisible element'});
        res.status.should.eql(11);
      });
      it('should throw when a command fails with a 100', async () => {
        let j = mockProxy({sessionId: '123'});
        let e = null;
        try {
          await j.command('/session/badchrome/nochrome', 'GET');
        } catch (err) {
          e = err;
        }
        should.exist(e);
        e.message.should.contain('Original error: chrome not reachable');
        e.value.should.eql({message: 'chrome not reachable'});
        e.status.should.equal(0);
      });
    });
    describe('req/res proxy', () => {
      it('should successfully proxy via req and send to res', async () => {
        let j = mockProxy();
        let [req, res] = buildReqRes('/status', 'GET');
        await j.proxyReqRes(req, res);
        res.headers['Content-type'].should.equal('application/json');
        res.sentCode.should.equal(200);
        res.sentBody.should.eql({status: 0, value: {foo: 'bar'}});
      });
      it('should rewrite the inner session id so it doesnt change', async () => {
        let j = mockProxy({sessionId: '123'});
        let [req, res] = buildReqRes('/element/200/value', 'GET');
        await j.proxyReqRes(req, res);
        res.sentBody.should.eql({status: 0, value: 'foobar', sessionId: '123'});
      });
      it('should rewrite the inner session id with sessionId in url', async () => {
        let j = mockProxy({sessionId: '123'});
        let [req, res] = buildReqRes('/wd/hub/session/456/element/200/value', 'POST');
        await j.proxyReqRes(req, res);
        res.sentBody.should.eql({status: 0, value: 'foobar', sessionId: '456'});
      });
      it('should pass through urls that do not require session IDs', async () => {
        let j = mockProxy({sessionId: '123'});
        let [req, res] = buildReqRes('/wd/hub/status', 'GET');
        await j.proxyReqRes(req, res);
        res.sentBody.should.eql({status: 0, value: {'foo':'bar'}});
      });
      it('should proxy strange responses', async () => {
        let j = mockProxy({sessionId: '123'});
        let [req, res] = buildReqRes('/nochrome', 'GET');
        await j.proxyReqRes(req, res);
        res.sentCode.should.equal(100);
        res.sentBody.should.eql({status: 0, value: {message: 'chrome not reachable'}});
      });
    });
  });
  