<commit_before>
/*!
 * socket.io-node
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Test dependencies.
 */

var sio = require('socket.io')
  , http = require('http')
  , should = require('./common')
  , ports = 15100;

/**
 * Test.
 */

module.exports = {

  'test setting and getting a configuration flag': function (done) {
    done();
  },

  'test enabling and disabling a configuration flag': function (done) {
    var port = ++ports
      , io = sio.listen(http.createServer());

    io.enable('flag');
    io.enabled('flag').should.be.true;
    io.disabled('flag').should.be.false;

    io.disable('flag');
    var port = ++ports
      , io = sio.listen(http.createServer());

    io.configure(function () {
      io.set('a', 'b');
      io.enable('tobi');
    });

    io.get('a').should.eql('b');
    io.enabled('tobi').should.be.true;

    done();
  },

  'test configuration callbacks with envs': function (done) {
    var port = ++ports
      , io = sio.listen(http.createServer());

    process.env.NODE_ENV = 'development';

    io.configure('production', function () {
      io.set('ferret', 'tobi');
    });

    io.configure('development', function () {
      io.set('ferret', 'jane');
    });

    io.get('ferret').should.eql('jane');
    done();
  },

  'test configuration callbacks conserve scope': function (done) {
    var port = ++ports
      , io = sio.listen(http.createServer())
      , calls = 0;

    process.env.NODE_ENV = 'development';

    io.configure(function () {
      this.should.eql(io);
      calls++;
    });

    io.configure('development', function () {
      this.should.eql(io);
      calls++;
    });

    calls.should.eql(2);
    done();
  },

  'test configuration update notifications': function (done) {
    var port = ++ports
      , io = sio.listen(http.createServer())
      , calls = 0;

    io.on('set:foo', function () {
      calls++;
    });

    io.set('foo', 'bar');
    io.set('baz', 'bar');

    calls.should.eql(1);

    io.enable('foo');
    io.disable('foo');

    calls.should.eql(3);
    done();
  },

  'test that normal requests are still served': function (done) {
    var server = http.createServer(function (req, res) {
      res.writeHead(200);
      res.end('woot');
    });

    var io = sio.listen(server)
      , port = ++ports
      , cl = client(port);

    server.listen(ports);

    cl.get('/socket.io', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.eql('Welcome to socket.io.');

      cl.get('/woot', function (res, data) {
        res.statusCode.should.eql(200);
        data.should.eql('woot');

        cl.end();
        server.close();
        done();
      });
    });
  },

  'test that the client is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.match(/([0-9]+)/);
      should.strictEqual(res.headers.etag, undefined);

      data.should.match(/XMLHttpRequest/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test that the client etag is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.enable('browser client etag');
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.match(/([0-9]+)/);
      res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);

      data.should.match(/XMLHttpRequest/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test that the cached client is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.match(/([0-9]+)/);
      should.strictEqual(res.headers.etag, undefined);

      data.should.match(/XMLHttpRequest/);
      var static = sio.Manager.static;
      static.cache['/socket.io.js'].content.should.match(/XMLHttpRequest/);

      cl.get('/socket.io/socket.io.js', function (res, data) {
        res.headers['content-type'].should.eql('application/javascript');
        res.headers['content-length'].should.match(/([0-9]+)/);
        should.strictEqual(res.headers.etag, undefined);

        data.should.match(/XMLHttpRequest/);

        cl.end();
        io.server.close();
        done();
      });
    });
  },

  'test that the cached client etag is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.enable('browser client etag');
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.match(/([0-9]+)/);
      res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);

      data.should.match(/XMLHttpRequest/);
      var static = sio.Manager.static
        , cache = static.cache['/socket.io.js'];

      cache.content.toString().should.match(/XMLHttpRequest/);
      Buffer.isBuffer(cache.content).should.be.true;

      cl.get('/socket.io/socket.io.js', function (res, data) {
        res.headers['content-type'].should.eql('application/javascript');
        res.headers['content-length'].should.match(/([0-9]+)/);
        res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);

        data.should.match(/XMLHttpRequest/);

        cl.end();
        io.server.close();
        done();
      });
    });
  },

  'test that the cached client sends a 304 header': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

     io.configure(function () {
      io.enable('browser client etag');
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      cl.get('/socket.io/socket.io.js', {headers:{'if-none-match':res.headers.etag}}, function (res, data) {
        res.statusCode.should.eql(304);

        cl.end();
        io.server.close();
        done();
      });
    });
  },

  'test that client minification works': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.enable('browser client minification');
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      var length = data.length;

      cl.end();
      io.server.close();

      // start a new server with minification enabled and compare lengths
      var port = ++ports
        , io2 = sio.listen(port)
        , cl2 = client(port);

      cl2.get('/socket.io/socket.io.js', function (res, data) {
        res.headers['content-type'].should.eql('application/javascript');
        res.headers['content-length'].should.match(/([0-9]+)/);
        should.strictEqual(res.headers.etag, undefined);

        data.should.match(/XMLHttpRequest/);
        data.length.should.be.greaterThan(length);

        cl2.end();
        io2.server.close();
        done();
      });
    });
  },

  'test that the WebSocketMain.swf is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/static/flashsocket/WebSocketMain.swf', function (res, data) {
      res.headers['content-type'].should.eql('application/x-shockwave-flash');
      res.headers['content-length'].should.match(/([0-9]+)/);
      should.strictEqual(res.headers.etag, undefined);

      var static = sio.Manager.static
        , cache = static.cache['/static/flashsocket/WebSocketMain.swf'];

      Buffer.isBuffer(cache.content).should.be.true;

      cl.end();
      io.server.close();
      done();
    });
  },

  'test that the WebSocketMainInsecure.swf is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/static/flashsocket/WebSocketMainInsecure.swf', function (res, data) {
      res.headers['content-type'].should.eql('application/x-shockwave-flash');
      res.headers['content-length'].should.match(/([0-9]+)/);
      should.strictEqual(res.headers.etag, undefined);

      var static = sio.Manager.static
        , cache = static.cache['/static/flashsocket/WebSocketMain.swf'];

      Buffer.isBuffer(cache.content).should.be.true;

      cl.end();
      io.server.close();
      done();
    });
  },

  'test that you can serve custom clients': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.set('browser client handler', function (req, res) {
        res.writeHead(200, {
            'Content-Type': 'application/javascript'
          , 'Content-Length': 13
          , 'ETag': '1.0'
        });
        res.end('custom_client');
      });
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.eql(13);
      res.headers.etag.should.eql('1.0');

      data.should.eql('custom_client');

      cl.end();
      io.server.close();
      done();
    });
  },

  'test that you can disable clients': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.disable('browser client');
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.eql('Welcome to socket.io.');

      cl.end();
      io.server.close();
      done();
    });
  },

  'test handshake': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.match(/([^:]+):([0-9]+)?:([0-9]+)?:(.+)/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test handshake with unsupported protocol version': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/-1/', function (res, data) {
      res.statusCode.should.eql(500);
      data.should.match(/Protocol version not supported/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test authorization failure in handshake': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      function auth (data, fn) {
        fn(null, false);
      };

      io.set('authorization', auth);
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(403);
      data.should.match(/handshake unauthorized/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test a handshake error': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      function auth (data, fn) {
        fn(new Error);
      };

      io.set('authorization', auth);
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(500);
      data.should.match(/handshake error/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test limiting the supported transports for a manager': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.set('transports', ['tobi', 'jane']);
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.match(/([^:]+):([0-9]+)?:([0-9]+)?:tobi,jane/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test setting a custom close timeout': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.set('close timeout', 66);
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.match(/([^:]+):([0-9]+)?:66?:(.*)/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test setting a custom heartbeat timeout': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.set('heartbeat timeout', 33);
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.match(/([^:]+):33:([0-9]+)?:(.*)/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test disabling timeouts': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.set('heartbeat timeout', null);
      io.set('close timeout', '');
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.match(/([^:]+)::?:(.*)/);

      cl.end();
      io.server.close();
      done();
    });
  }

};
<commit_msg>Fixed; bind both servers at the same time do that the test never times out.<commit_after>
/*!
 * socket.io-node
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Test dependencies.
 */

var sio = require('socket.io')
  , http = require('http')
  , should = require('./common')
  , ports = 15100;

/**
 * Test.
 */

module.exports = {

  'test setting and getting a configuration flag': function (done) {
    done();
  },

  'test enabling and disabling a configuration flag': function (done) {
    var port = ++ports
      , io = sio.listen(http.createServer());

    io.enable('flag');
    io.enabled('flag').should.be.true;
    io.disabled('flag').should.be.false;

    io.disable('flag');
    var port = ++ports
      , io = sio.listen(http.createServer());

    io.configure(function () {
      io.set('a', 'b');
      io.enable('tobi');
    });

    io.get('a').should.eql('b');
    io.enabled('tobi').should.be.true;

    done();
  },

  'test configuration callbacks with envs': function (done) {
    var port = ++ports
      , io = sio.listen(http.createServer());

    process.env.NODE_ENV = 'development';

    io.configure('production', function () {
      io.set('ferret', 'tobi');
    });

    io.configure('development', function () {
      io.set('ferret', 'jane');
    });

    io.get('ferret').should.eql('jane');
    done();
  },

  'test configuration callbacks conserve scope': function (done) {
    var port = ++ports
      , io = sio.listen(http.createServer())
      , calls = 0;

    process.env.NODE_ENV = 'development';

    io.configure(function () {
      this.should.eql(io);
      calls++;
    });

    io.configure('development', function () {
      this.should.eql(io);
      calls++;
    });

    calls.should.eql(2);
    done();
  },

  'test configuration update notifications': function (done) {
    var port = ++ports
      , io = sio.listen(http.createServer())
      , calls = 0;

    io.on('set:foo', function () {
      calls++;
    });

    io.set('foo', 'bar');
    io.set('baz', 'bar');

    calls.should.eql(1);

    io.enable('foo');
    io.disable('foo');

    calls.should.eql(3);
    done();
  },

  'test that normal requests are still served': function (done) {
    var server = http.createServer(function (req, res) {
      res.writeHead(200);
      res.end('woot');
    });

    var io = sio.listen(server)
      , port = ++ports
      , cl = client(port);

    server.listen(ports);

    cl.get('/socket.io', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.eql('Welcome to socket.io.');

      cl.get('/woot', function (res, data) {
        res.statusCode.should.eql(200);
        data.should.eql('woot');

        cl.end();
        server.close();
        done();
      });
    });
  },

  'test that the client is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.match(/([0-9]+)/);
      should.strictEqual(res.headers.etag, undefined);

      data.should.match(/XMLHttpRequest/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test that the client etag is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.enable('browser client etag');
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.match(/([0-9]+)/);
      res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);

      data.should.match(/XMLHttpRequest/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test that the cached client is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.match(/([0-9]+)/);
      should.strictEqual(res.headers.etag, undefined);

      data.should.match(/XMLHttpRequest/);
      var static = sio.Manager.static;
      static.cache['/socket.io.js'].content.should.match(/XMLHttpRequest/);

      cl.get('/socket.io/socket.io.js', function (res, data) {
        res.headers['content-type'].should.eql('application/javascript');
        res.headers['content-length'].should.match(/([0-9]+)/);
        should.strictEqual(res.headers.etag, undefined);

        data.should.match(/XMLHttpRequest/);

        cl.end();
        io.server.close();
        done();
      });
    });
  },

  'test that the cached client etag is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.enable('browser client etag');
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.match(/([0-9]+)/);
      res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);

      data.should.match(/XMLHttpRequest/);
      var static = sio.Manager.static
        , cache = static.cache['/socket.io.js'];

      cache.content.toString().should.match(/XMLHttpRequest/);
      Buffer.isBuffer(cache.content).should.be.true;

      cl.get('/socket.io/socket.io.js', function (res, data) {
        res.headers['content-type'].should.eql('application/javascript');
        res.headers['content-length'].should.match(/([0-9]+)/);
        res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);

        data.should.match(/XMLHttpRequest/);

        cl.end();
        io.server.close();
        done();
      });
    });
  },

  'test that the cached client sends a 304 header': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

     io.configure(function () {
      io.enable('browser client etag');
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      cl.get('/socket.io/socket.io.js', {headers:{'if-none-match':res.headers.etag}}, function (res, data) {
        res.statusCode.should.eql(304);

        cl.end();
        io.server.close();
        done();
      });
    });
  },

  'test that client minification works': function (done) {
    // server 1
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    // server 2
    var port = ++ports
      , io2 = sio.listen(port)
      , cl2 = client(port);

    io.configure(function () {
      io.enable('browser client minification');
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      var length = data.length;

      cl.end();
      io.server.close();

      cl2.get('/socket.io/socket.io.js', function (res, data) {
        res.headers['content-type'].should.eql('application/javascript');
        res.headers['content-length'].should.match(/([0-9]+)/);
        should.strictEqual(res.headers.etag, undefined);

        data.should.match(/XMLHttpRequest/);
        data.length.should.be.greaterThan(length);

        cl2.end();
        io2.server.close();
        done();
      });
    });
  },

  'test that the WebSocketMain.swf is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/static/flashsocket/WebSocketMain.swf', function (res, data) {
      res.headers['content-type'].should.eql('application/x-shockwave-flash');
      res.headers['content-length'].should.match(/([0-9]+)/);
      should.strictEqual(res.headers.etag, undefined);

      var static = sio.Manager.static
        , cache = static.cache['/static/flashsocket/WebSocketMain.swf'];

      Buffer.isBuffer(cache.content).should.be.true;

      cl.end();
      io.server.close();
      done();
    });
  },

  'test that the WebSocketMainInsecure.swf is served': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/static/flashsocket/WebSocketMainInsecure.swf', function (res, data) {
      res.headers['content-type'].should.eql('application/x-shockwave-flash');
      res.headers['content-length'].should.match(/([0-9]+)/);
      should.strictEqual(res.headers.etag, undefined);

      var static = sio.Manager.static
        , cache = static.cache['/static/flashsocket/WebSocketMain.swf'];

      Buffer.isBuffer(cache.content).should.be.true;

      cl.end();
      io.server.close();
      done();
    });
  },

  'test that you can serve custom clients': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.set('browser client handler', function (req, res) {
        res.writeHead(200, {
            'Content-Type': 'application/javascript'
          , 'Content-Length': 13
          , 'ETag': '1.0'
        });
        res.end('custom_client');
      });
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.eql(13);
      res.headers.etag.should.eql('1.0');

      data.should.eql('custom_client');

      cl.end();
      io.server.close();
      done();
    });
  },

  'test that you can disable clients': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.disable('browser client');
    });

    cl.get('/socket.io/socket.io.js', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.eql('Welcome to socket.io.');

      cl.end();
      io.server.close();
      done();
    });
  },

  'test handshake': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.match(/([^:]+):([0-9]+)?:([0-9]+)?:(.+)/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test handshake with unsupported protocol version': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    cl.get('/socket.io/-1/', function (res, data) {
      res.statusCode.should.eql(500);
      data.should.match(/Protocol version not supported/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test authorization failure in handshake': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      function auth (data, fn) {
        fn(null, false);
      };

      io.set('authorization', auth);
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(403);
      data.should.match(/handshake unauthorized/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test a handshake error': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      function auth (data, fn) {
        fn(new Error);
      };

      io.set('authorization', auth);
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(500);
      data.should.match(/handshake error/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test limiting the supported transports for a manager': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.set('transports', ['tobi', 'jane']);
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.match(/([^:]+):([0-9]+)?:([0-9]+)?:tobi,jane/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test setting a custom close timeout': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.set('close timeout', 66);
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.match(/([^:]+):([0-9]+)?:66?:(.*)/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test setting a custom heartbeat timeout': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.set('heartbeat timeout', 33);
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.match(/([^:]+):33:([0-9]+)?:(.*)/);

      cl.end();
      io.server.close();
      done();
    });
  },

  'test disabling timeouts': function (done) {
    var port = ++ports
      , io = sio.listen(port)
      , cl = client(port);

    io.configure(function () {
      io.set('heartbeat timeout', null);
      io.set('close timeout', '');
    });

    cl.get('/socket.io/{protocol}/', function (res, data) {
      res.statusCode.should.eql(200);
      data.should.match(/([^:]+)::?:(.*)/);

      cl.end();
      io.server.close();
      done();
    });
  }

};
<|endoftext|>


<commit_before>/*global describe, it, beforeEach, afterEach*/
var memoizeAsync = require('../lib/memoizeAsync'),
    LRUCache = require('lru-cache'),
    expect = require('unexpected').clone().installPlugin(require('unexpected-sinon')),
    passError = require('passerror'),
    async = require('async'),
    sinon = require('sinon');

describe('memoizeAsync', function () {
    it('on a zero-param function should keep returning the same result', function (done) {
        var nextNumber = 1,
            memoizedGetNextNumber = memoizeAsync(function getNextNumber(cb) {
                process.nextTick(function () {
                    cb(null, nextNumber);
                    nextNumber += 1;
                });
            });

        memoizedGetNextNumber(function (err, nextNumber) {
            expect(nextNumber, 'to equal', 1);
            memoizedGetNextNumber(function (err, nextNextNumber) {
                expect(nextNextNumber, 'to equal', 1);
                done();
            });
        });
    });

    it('on a multi-param function should only return the same result when the parameters are the same', function (done) {
        var nextNumber = 1,
            memoizedSumOfOperandsPlusNextNumber = memoizeAsync(function sumOfOperandsPlusNextNumber(op1, op2, cb) {
                process.nextTick(function () {
                    cb(null, op1 + op2 + nextNumber);
                    nextNumber += 1;
                });
            });

        memoizedSumOfOperandsPlusNextNumber(10, 10, passError(done, function (sumPlusNextNumber) {
            expect(sumPlusNextNumber, 'to equal', 21);
            expect(memoizedSumOfOperandsPlusNextNumber.peek(10, 10)[1], 'to equal', 21);
            memoizedSumOfOperandsPlusNextNumber(10, 10, passError(done, function (sumPlusNextNextNumber) {
                expect(sumPlusNextNextNumber, 'to equal', 21);
                memoizedSumOfOperandsPlusNextNumber(10, 20, passError(done, function (sumPlusNextNextNextNumber) {
                    expect(sumPlusNextNextNextNumber, 'to equal', 32);
                    memoizedSumOfOperandsPlusNextNumber.purge(10, 20);
                    memoizedSumOfOperandsPlusNextNumber(10, 20, passError(done, function (number) {
                        expect(number, 'to equal', 33);
                        memoizedSumOfOperandsPlusNextNumber(10, 10, passError(done, function (number) {
                            expect(number, 'to equal', 21);
                            memoizedSumOfOperandsPlusNextNumber.purgeAll();
                            memoizedSumOfOperandsPlusNextNumber(10, 20, passError(done, function (number) {
                                expect(number, 'to equal', 34);
                                memoizedSumOfOperandsPlusNextNumber(10, 10, passError(done, function (number) {
                                    expect(number, 'to equal', 25);
                                    done();
                                }));
                            }));
                        }));
                    }));
                }));
            }));
        }));
    });

    it('should produce a function that works as a method', function (done) {
        function Counter() {
            this.nextNumber = 1;
        }

        Counter.prototype.getNextNumber = memoizeAsync(function (cb) {
            var that = this;
            process.nextTick(function () {
                cb(null, that.nextNumber);
                that.nextNumber += 1;
            });
        });

        var counter = new Counter();

        counter.getNextNumber(passError(done, function (nextNumber) {
            expect(nextNumber, 'to equal', 1);
            expect(counter.nextNumber, 'to equal', 2);
            counter.getNextNumber(passError(done, function (nextNextNumber) {
                expect(nextNextNumber, 'to equal', 1);
                expect(counter.nextNumber, 'to equal', 2);
                done();
            }));
        }));
    });

    it('should deliver the same result to multiple callbacks that are queued before the result is available', function (done) {
        var nextNumber = 1,
            memoizedGetNextNumber = memoizeAsync(function getNextNumber(cb) {
                process.nextTick(function () {
                    cb(null, nextNumber);
                    nextNumber += 1;
                });
            });

        var results = [];
        function receiveResultAndProceedIfReady(err, number) {
            results.push(number);
            if (results.length === 2) {
                expect(results[0], 'to equal', 1);
                expect(results[1], 'to equal', 1);
                done();
            }
        }
        memoizedGetNextNumber(receiveResultAndProceedIfReady);
        memoizedGetNextNumber(receiveResultAndProceedIfReady);
    });

    it('should work with a custom argumentsStringifier', function (done) {
        function toCanonicalJson(obj) {
            return JSON.stringify((function traverseAndSortKeys(obj) {
                if (Array.isArray(obj)) {
                    return obj.map(traverseAndSortKeys);
                } else if (typeof obj === 'object' && obj !== null) {
                    var resultObj = {};
                    Object.keys(obj).sort().forEach(function (key) {
                        resultObj[key] = traverseAndSortKeys(obj[key]);
                    });
                    return resultObj;
                } else {
                    return obj;
                }
            }(obj)));
        }

        var nextNumber = 1,
            memoizedGetNextNumber = memoizeAsync(function getNextNumber(obj, cb) {
                process.nextTick(function () {
                    cb(null, nextNumber);
                    nextNumber += 1;
                });
            }, {
                argumentsStringifier: function (args) {
                    return args.map(toCanonicalJson).join('\x1d');
                }
            });

        memoizedGetNextNumber({foo: 'bar', quux: 'baz'}, passError(done, function (nextNumber) {
            expect(nextNumber, 'to equal', 1);
            memoizedGetNextNumber({quux: 'baz', foo: 'bar'}, passError(done, function (nextNumber) {
                expect(nextNumber, 'to equal', 1);
                memoizedGetNextNumber({barf: 'baz'}, passError(done, function (nextNumber) {
                    expect(nextNumber, 'to equal', 2);
                    done();
                }));
            }));
        }));
    });

    it('with a maxAge should recompute the value after an item has become stale', function (done) {
        var nextNumber = 1,
            memoizedGetNextNumber = memoizeAsync(function getNextNumber(cb) {
                process.nextTick(function () {
                    cb(null, nextNumber);
                    nextNumber += 1;
                });
            }, {maxAge: 10});

        memoizedGetNextNumber(passError(done, function (nextNumber) {
            expect(nextNumber, 'to equal', 1);
            memoizedGetNextNumber(passError(done, function (nextNumber) {
                expect(nextNumber, 'to equal', 1);
                setTimeout(function () {
                    memoizedGetNextNumber(passError(done, function (nextNumber) {
                        expect(nextNumber, 'to equal', 2);
                        done();
                    }));
                }, 15);
            }));
        }));
    });

    it('with a max limit should purge the least recently used result', function (done) {
        var nextNumber = 1,
            memoizedGetNextNumberPlusOtherNumber = memoizeAsync(function getNextNumber(otherNumber, cb) {
                process.nextTick(function () {
                    cb(null, otherNumber + nextNumber);
                    nextNumber += 1;
                });
            }, {max: 2});

        memoizedGetNextNumberPlusOtherNumber(1, passError(done, function (nextNumberPlusOne) {
            expect(nextNumberPlusOne, 'to equal', 2);
            memoizedGetNextNumberPlusOtherNumber(2, passError(done, function (nextNumberPlusTwo) {
                expect(nextNumberPlusTwo, 'to equal', 4);
                memoizedGetNextNumberPlusOtherNumber(1, passError(done, function (nextNumberPlusOneAgain) {
                    expect(nextNumberPlusOne, 'to equal', 2);
                    // This will purge memoizedGetNextNumberPlusOtherNumber(2, ...):
                    memoizedGetNextNumberPlusOtherNumber(3, passError(done, function (nextNumberPlusThree) {
                        expect(nextNumberPlusThree, 'to equal', 6);
                        memoizedGetNextNumberPlusOtherNumber(2, passError(done, function (nextNumberPlusTwoAgain) {
                            expect(nextNumberPlusTwoAgain, 'to equal', 6);
                            done();
                        }));
                    }));
                }));
            }));
        }));
    });

    it('with a length function should call the length function with the result callback parameters as regular arguments', function (done) {
        var shouldErrorNextTime = false,
            functionThatErrorsEverySecondTime = function (number, cb) {
                process.nextTick(function () {
                    if (shouldErrorNextTime) {
                        cb(new Error());
                    } else {
                        cb(null, 'the result');
                    }
                    shouldErrorNextTime = !shouldErrorNextTime;
                });
            },
            memoizedFunctionThatErrorsEverySecondTime = memoizeAsync(functionThatErrorsEverySecondTime, {
                length: function (err, result) {
                    return err ? 1 : result.length;
                },
                errors: true
            });
        memoizedFunctionThatErrorsEverySecondTime(1, passError(done, function (result) {
            expect(result, 'to equal', 'the result');
            expect(memoizedFunctionThatErrorsEverySecondTime.cache.length, 'to equal', 10);
            memoizedFunctionThatErrorsEverySecondTime(2, function (err, result2) {
                expect(err, 'to be an', Error);
                expect(result2, 'to be undefined');
                expect(memoizedFunctionThatErrorsEverySecondTime.cache.length, 'to equal', 11);
                done();
            });
        }));
    });

    it('should leave unrelated values in the cache when purgeAll is called', function (done) {
        var memoizedAsyncSum = memoizeAsync(function asyncSum(a, b, cb) {
            process.nextTick(function () {
                cb(null, a + b);
            });
        });
        var cache = memoizedAsyncSum.cache;
        memoizedAsyncSum(1, 2, passError(done, function (sum) {
            expect(sum, 'to equal', 3);
            expect(cache.keys().length, 'to equal', 1);
            cache.set('foo', 'bar');
            expect(cache.keys().length, 'to equal', 2);
            memoizedAsyncSum.purgeAll();
            expect(cache.keys().length, 'to equal', 1);
            expect(cache.get('foo'), 'to equal', 'bar');
            done();
        }));
    });

    it('should allow passing an existing lru-cache instance in the options object', function (done) {
        function asyncSum(a, b, cb) {
            process.nextTick(function () {
                cb(null, a + b);
            });
        }
        var cache = new LRUCache(),
            memoizedAsyncSum1 = memoizeAsync(asyncSum, {cache: cache});
        expect(memoizedAsyncSum1.cache, 'to be', cache);

        var memoizedAsyncSum2 = memoizeAsync(asyncSum, {cache: cache});
        expect(memoizedAsyncSum2.cache, 'to be', cache);
        memoizedAsyncSum1(1, 2, passError(done, function (sum) {
            expect(sum, 'to equal', 3);
            expect(cache.keys().length, 'to equal', 1);
            expect(cache.get(memoizedAsyncSum1.cacheKeyPrefix + memoizedAsyncSum1.argumentsStringifier([1, 2])), 'to equal', [null, 3]);
            memoizedAsyncSum2(1, 2, passError(done, function (sum) {
                expect(sum, 'to equal', 3);
                expect(cache.keys().length, 'to equal', 2);
                done();
            }));
        }));
    });

    it('should allow specifying a custom cacheKeyPrefix', function (done) {
        var memoizedAsyncSum = memoizeAsync(function (a, b, cb) {
            process.nextTick(function () {
                cb(null, a + b);
            });
        }, {
            cacheKeyPrefix: 999
        });

        expect(memoizedAsyncSum.cacheKeyPrefix, 'to equal', '999');

        memoizedAsyncSum(1, 2, passError(done, function (sum) {
            expect(sum, 'to equal', 3);
            expect(memoizedAsyncSum.cache.get('999' + memoizedAsyncSum.argumentsStringifier([1, 2])), 'to equal', [null, 3]);
            done();
        }));
    });

    it('should call the memoized function in options.context if specified', function (done) {
        var memoizedFunction = memoizeAsync(function (a, cb) {
            var sum = this.foo + a;
            process.nextTick(function () {
                cb(null, sum);
            });
        }, {context: {foo: 4}});
        memoizedFunction(8, passError(done, function (sum) {
            expect(sum, 'to equal', 12);
            done();
        }));
    });

    it('should not memoize errors per default', function (done) {
        var memoizedFunction = memoizeAsync(function (cb) {
            process.nextTick(function () {
                cb(new Error('foo'));
            });
        });
        memoizedFunction(function (err) {
            expect(err, 'to be an', Error);
            expect(err.message, 'to equal', 'foo');
            memoizedFunction(function (err2) {
                expect(err2, 'to be an', Error);
                expect(err2.message, 'to equal', 'foo');
                expect(err2, 'not to be', err);
                done();
            });
        });
    });

    it('should memoize errors if the `errors` option is set to true', function (done) {
        var memoizedFunction = memoizeAsync(function (cb) {
            process.nextTick(function () {
                cb(new Error('foo'));
            });
        }, {errors: true});
        memoizedFunction(function (err) {
            expect(err, 'to be an', Error);
            expect(err.message, 'to equal', 'foo');
            memoizedFunction(function (err2) {
                expect(err2, 'to be an', Error);
                expect(err2.message, 'to equal', 'foo');
                expect(err2, 'to be', err);
                done();
            });
        });
    });

    describe('refreshTime', function () {
        var clock;
        var currentTick = 0;

        function gotoTick(n) {
            var toTick = n - currentTick;
            currentTick = n;
            clock.tick(toTick);
        }

        beforeEach(function () {
            currentTick = 0;
            clock = sinon.useFakeTimers();
        });
        afterEach(function () {
            clock.restore();
        });
        it('should refresh async but return stale value immediately', function (done) {
            var nextNumber = 1,
                method = sinon.spy(function getNextNumber(cb) {
                    setTimeout(function () {
                        cb(null, nextNumber);
                        nextNumber += 1;
                    }, 5);
                }),
                memoizedGetNextNumber = memoizeAsync(method, { maxAge: 20, refreshAge: 10 });

            async.series([
                function (callback) {
                    // initial call
                    memoizedGetNextNumber(passError(callback, function (nextNumber) {
                        expect(nextNumber, 'to be', 1);
                        expect(method, 'was called once');
                        gotoTick(10);
                        callback();
                    }));
                    // going to tick 6 to allow it to finish
                    gotoTick(6);
                },
                function (callback) {
                    // still below refreshAge
                    memoizedGetNextNumber(passError(callback, function (nextNumber) {
                        expect(nextNumber, 'to be', 1);
                        expect(method, 'was called once');
                        gotoTick(17);
                        callback();
                    }));
                },
                function (callback) {
                    // above refreshAge below maxAge immediate result
                    memoizedGetNextNumber(passError(callback, function (nextNumber) {
                        expect(nextNumber, 'to be', 1);
                        expect(method, 'was called twice');
                        gotoTick(27);
                        callback();
                    }));
                },
                function (callback) {
                    // above initial maxAge but immediate result because refresh
                    memoizedGetNextNumber(passError(callback, function (nextNumber) {
                        expect(nextNumber, 'to be', 2);
                        expect(method, 'was called twice');
                        callback();
                    }));
                }
            ], done);
        });
    });
});
<commit_msg>Added some describes to the tests so the mocha output reads a little better.<commit_after>/*global describe, it, beforeEach, afterEach*/
var memoizeAsync = require('../lib/memoizeAsync'),
    LRUCache = require('lru-cache'),
    expect = require('unexpected').clone().installPlugin(require('unexpected-sinon')),
    passError = require('passerror'),
    async = require('async'),
    sinon = require('sinon');

describe('memoizeAsync', function () {
    describe('on a zero-param function', function () {
        it('should keep returning the same result', function (done) {
            var nextNumber = 1,
                memoizedGetNextNumber = memoizeAsync(function getNextNumber(cb) {
                    process.nextTick(function () {
                        cb(null, nextNumber);
                        nextNumber += 1;
                    });
                });

            memoizedGetNextNumber(function (err, nextNumber) {
                expect(nextNumber, 'to equal', 1);
                memoizedGetNextNumber(function (err, nextNextNumber) {
                    expect(nextNextNumber, 'to equal', 1);
                    done();
                });
            });
        });
    });

    describe('on a multi-param function', function () {
        it('should only return the same result when the parameters are the same', function (done) {
            var nextNumber = 1,
                memoizedSumOfOperandsPlusNextNumber = memoizeAsync(function sumOfOperandsPlusNextNumber(op1, op2, cb) {
                    process.nextTick(function () {
                        cb(null, op1 + op2 + nextNumber);
                        nextNumber += 1;
                    });
                });

            memoizedSumOfOperandsPlusNextNumber(10, 10, passError(done, function (sumPlusNextNumber) {
                expect(sumPlusNextNumber, 'to equal', 21);
                expect(memoizedSumOfOperandsPlusNextNumber.peek(10, 10)[1], 'to equal', 21);
                memoizedSumOfOperandsPlusNextNumber(10, 10, passError(done, function (sumPlusNextNextNumber) {
                    expect(sumPlusNextNextNumber, 'to equal', 21);
                    memoizedSumOfOperandsPlusNextNumber(10, 20, passError(done, function (sumPlusNextNextNextNumber) {
                        expect(sumPlusNextNextNextNumber, 'to equal', 32);
                        memoizedSumOfOperandsPlusNextNumber.purge(10, 20);
                        memoizedSumOfOperandsPlusNextNumber(10, 20, passError(done, function (number) {
                            expect(number, 'to equal', 33);
                            memoizedSumOfOperandsPlusNextNumber(10, 10, passError(done, function (number) {
                                expect(number, 'to equal', 21);
                                memoizedSumOfOperandsPlusNextNumber.purgeAll();
                                memoizedSumOfOperandsPlusNextNumber(10, 20, passError(done, function (number) {
                                    expect(number, 'to equal', 34);
                                    memoizedSumOfOperandsPlusNextNumber(10, 10, passError(done, function (number) {
                                        expect(number, 'to equal', 25);
                                        done();
                                    }));
                                }));
                            }));
                        }));
                    }));
                }));
            }));
        });
    });

    it('should produce a function that works as a method', function (done) {
        function Counter() {
            this.nextNumber = 1;
        }

        Counter.prototype.getNextNumber = memoizeAsync(function (cb) {
            var that = this;
            process.nextTick(function () {
                cb(null, that.nextNumber);
                that.nextNumber += 1;
            });
        });

        var counter = new Counter();

        counter.getNextNumber(passError(done, function (nextNumber) {
            expect(nextNumber, 'to equal', 1);
            expect(counter.nextNumber, 'to equal', 2);
            counter.getNextNumber(passError(done, function (nextNextNumber) {
                expect(nextNextNumber, 'to equal', 1);
                expect(counter.nextNumber, 'to equal', 2);
                done();
            }));
        }));
    });

    it('should deliver the same result to multiple callbacks that are queued before the result is available', function (done) {
        var nextNumber = 1,
            memoizedGetNextNumber = memoizeAsync(function getNextNumber(cb) {
                process.nextTick(function () {
                    cb(null, nextNumber);
                    nextNumber += 1;
                });
            });

        var results = [];
        function receiveResultAndProceedIfReady(err, number) {
            results.push(number);
            if (results.length === 2) {
                expect(results[0], 'to equal', 1);
                expect(results[1], 'to equal', 1);
                done();
            }
        }
        memoizedGetNextNumber(receiveResultAndProceedIfReady);
        memoizedGetNextNumber(receiveResultAndProceedIfReady);
    });

    it('should work with a custom argumentsStringifier', function (done) {
        function toCanonicalJson(obj) {
            return JSON.stringify((function traverseAndSortKeys(obj) {
                if (Array.isArray(obj)) {
                    return obj.map(traverseAndSortKeys);
                } else if (typeof obj === 'object' && obj !== null) {
                    var resultObj = {};
                    Object.keys(obj).sort().forEach(function (key) {
                        resultObj[key] = traverseAndSortKeys(obj[key]);
                    });
                    return resultObj;
                } else {
                    return obj;
                }
            }(obj)));
        }

        var nextNumber = 1,
            memoizedGetNextNumber = memoizeAsync(function getNextNumber(obj, cb) {
                process.nextTick(function () {
                    cb(null, nextNumber);
                    nextNumber += 1;
                });
            }, {
                argumentsStringifier: function (args) {
                    return args.map(toCanonicalJson).join('\x1d');
                }
            });

        memoizedGetNextNumber({foo: 'bar', quux: 'baz'}, passError(done, function (nextNumber) {
            expect(nextNumber, 'to equal', 1);
            memoizedGetNextNumber({quux: 'baz', foo: 'bar'}, passError(done, function (nextNumber) {
                expect(nextNumber, 'to equal', 1);
                memoizedGetNextNumber({barf: 'baz'}, passError(done, function (nextNumber) {
                    expect(nextNumber, 'to equal', 2);
                    done();
                }));
            }));
        }));
    });

    describe('with a maxAge', function () {
        it('should recompute the value after an item has become stale', function (done) {
            var nextNumber = 1,
                memoizedGetNextNumber = memoizeAsync(function getNextNumber(cb) {
                    process.nextTick(function () {
                        cb(null, nextNumber);
                        nextNumber += 1;
                    });
                }, {maxAge: 10});

            memoizedGetNextNumber(passError(done, function (nextNumber) {
                expect(nextNumber, 'to equal', 1);
                memoizedGetNextNumber(passError(done, function (nextNumber) {
                    expect(nextNumber, 'to equal', 1);
                    setTimeout(function () {
                        memoizedGetNextNumber(passError(done, function (nextNumber) {
                            expect(nextNumber, 'to equal', 2);
                            done();
                        }));
                    }, 15);
                }));
            }));
        });
    });

    describe('with a max limit', function () {
        it('with a max limit should purge the least recently used result', function (done) {
            var nextNumber = 1,
                memoizedGetNextNumberPlusOtherNumber = memoizeAsync(function getNextNumber(otherNumber, cb) {
                    process.nextTick(function () {
                        cb(null, otherNumber + nextNumber);
                        nextNumber += 1;
                    });
                }, {max: 2});

            memoizedGetNextNumberPlusOtherNumber(1, passError(done, function (nextNumberPlusOne) {
                expect(nextNumberPlusOne, 'to equal', 2);
                memoizedGetNextNumberPlusOtherNumber(2, passError(done, function (nextNumberPlusTwo) {
                    expect(nextNumberPlusTwo, 'to equal', 4);
                    memoizedGetNextNumberPlusOtherNumber(1, passError(done, function (nextNumberPlusOneAgain) {
                        expect(nextNumberPlusOne, 'to equal', 2);
                        // This will purge memoizedGetNextNumberPlusOtherNumber(2, ...):
                        memoizedGetNextNumberPlusOtherNumber(3, passError(done, function (nextNumberPlusThree) {
                            expect(nextNumberPlusThree, 'to equal', 6);
                            memoizedGetNextNumberPlusOtherNumber(2, passError(done, function (nextNumberPlusTwoAgain) {
                                expect(nextNumberPlusTwoAgain, 'to equal', 6);
                                done();
                            }));
                        }));
                    }));
                }));
            }));
        });
    });

    describe('with a length function', function () {
        it('should call the length function with the result callback parameters as regular arguments', function (done) {
            var shouldErrorNextTime = false,
                functionThatErrorsEverySecondTime = function (number, cb) {
                    process.nextTick(function () {
                        if (shouldErrorNextTime) {
                            cb(new Error());
                        } else {
                            cb(null, 'the result');
                        }
                        shouldErrorNextTime = !shouldErrorNextTime;
                    });
                },
                memoizedFunctionThatErrorsEverySecondTime = memoizeAsync(functionThatErrorsEverySecondTime, {
                    length: function (err, result) {
                        return err ? 1 : result.length;
                    },
                    errors: true
                });
            memoizedFunctionThatErrorsEverySecondTime(1, passError(done, function (result) {
                expect(result, 'to equal', 'the result');
                expect(memoizedFunctionThatErrorsEverySecondTime.cache.length, 'to equal', 10);
                memoizedFunctionThatErrorsEverySecondTime(2, function (err, result2) {
                    expect(err, 'to be an', Error);
                    expect(result2, 'to be undefined');
                    expect(memoizedFunctionThatErrorsEverySecondTime.cache.length, 'to equal', 11);
                    done();
                });
            }));
        });
    });

    it('should leave unrelated values in the cache when purgeAll is called', function (done) {
        var memoizedAsyncSum = memoizeAsync(function asyncSum(a, b, cb) {
            process.nextTick(function () {
                cb(null, a + b);
            });
        });
        var cache = memoizedAsyncSum.cache;
        memoizedAsyncSum(1, 2, passError(done, function (sum) {
            expect(sum, 'to equal', 3);
            expect(cache.keys().length, 'to equal', 1);
            cache.set('foo', 'bar');
            expect(cache.keys().length, 'to equal', 2);
            memoizedAsyncSum.purgeAll();
            expect(cache.keys().length, 'to equal', 1);
            expect(cache.get('foo'), 'to equal', 'bar');
            done();
        }));
    });

    it('should allow passing an existing lru-cache instance in the options object', function (done) {
        function asyncSum(a, b, cb) {
            process.nextTick(function () {
                cb(null, a + b);
            });
        }
        var cache = new LRUCache(),
            memoizedAsyncSum1 = memoizeAsync(asyncSum, {cache: cache});
        expect(memoizedAsyncSum1.cache, 'to be', cache);

        var memoizedAsyncSum2 = memoizeAsync(asyncSum, {cache: cache});
        expect(memoizedAsyncSum2.cache, 'to be', cache);
        memoizedAsyncSum1(1, 2, passError(done, function (sum) {
            expect(sum, 'to equal', 3);
            expect(cache.keys().length, 'to equal', 1);
            expect(cache.get(memoizedAsyncSum1.cacheKeyPrefix + memoizedAsyncSum1.argumentsStringifier([1, 2])), 'to equal', [null, 3]);
            memoizedAsyncSum2(1, 2, passError(done, function (sum) {
                expect(sum, 'to equal', 3);
                expect(cache.keys().length, 'to equal', 2);
                done();
            }));
        }));
    });

    it('should allow specifying a custom cacheKeyPrefix', function (done) {
        var memoizedAsyncSum = memoizeAsync(function (a, b, cb) {
            process.nextTick(function () {
                cb(null, a + b);
            });
        }, {
            cacheKeyPrefix: 999
        });

        expect(memoizedAsyncSum.cacheKeyPrefix, 'to equal', '999');

        memoizedAsyncSum(1, 2, passError(done, function (sum) {
            expect(sum, 'to equal', 3);
            expect(memoizedAsyncSum.cache.get('999' + memoizedAsyncSum.argumentsStringifier([1, 2])), 'to equal', [null, 3]);
            done();
        }));
    });

    it('should call the memoized function in options.context if specified', function (done) {
        var memoizedFunction = memoizeAsync(function (a, cb) {
            var sum = this.foo + a;
            process.nextTick(function () {
                cb(null, sum);
            });
        }, {context: {foo: 4}});
        memoizedFunction(8, passError(done, function (sum) {
            expect(sum, 'to equal', 12);
            done();
        }));
    });

    it('should not memoize errors per default', function (done) {
        var memoizedFunction = memoizeAsync(function (cb) {
            process.nextTick(function () {
                cb(new Error('foo'));
            });
        });
        memoizedFunction(function (err) {
            expect(err, 'to be an', Error);
            expect(err.message, 'to equal', 'foo');
            memoizedFunction(function (err2) {
                expect(err2, 'to be an', Error);
                expect(err2.message, 'to equal', 'foo');
                expect(err2, 'not to be', err);
                done();
            });
        });
    });

    it('should memoize errors if the `errors` option is set to true', function (done) {
        var memoizedFunction = memoizeAsync(function (cb) {
            process.nextTick(function () {
                cb(new Error('foo'));
            });
        }, {errors: true});
        memoizedFunction(function (err) {
            expect(err, 'to be an', Error);
            expect(err.message, 'to equal', 'foo');
            memoizedFunction(function (err2) {
                expect(err2, 'to be an', Error);
                expect(err2.message, 'to equal', 'foo');
                expect(err2, 'to be', err);
                done();
            });
        });
    });

    describe('with refreshTime', function () {
        var clock;
        var currentTick = 0;

        function gotoTick(n) {
            var toTick = n - currentTick;
            currentTick = n;
            clock.tick(toTick);
        }

        beforeEach(function () {
            currentTick = 0;
            clock = sinon.useFakeTimers();
        });
        afterEach(function () {
            clock.restore();
        });
        it('should refresh async but return stale value immediately', function (done) {
            var nextNumber = 1,
                method = sinon.spy(function getNextNumber(cb) {
                    setTimeout(function () {
                        cb(null, nextNumber);
                        nextNumber += 1;
                    }, 5);
                }),
                memoizedGetNextNumber = memoizeAsync(method, { maxAge: 20, refreshAge: 10 });

            async.series([
                function (callback) {
                    // initial call
                    memoizedGetNextNumber(passError(callback, function (nextNumber) {
                        expect(nextNumber, 'to be', 1);
                        expect(method, 'was called once');
                        gotoTick(10);
                        callback();
                    }));
                    // going to tick 6 to allow it to finish
                    gotoTick(6);
                },
                function (callback) {
                    // still below refreshAge
                    memoizedGetNextNumber(passError(callback, function (nextNumber) {
                        expect(nextNumber, 'to be', 1);
                        expect(method, 'was called once');
                        gotoTick(17);
                        callback();
                    }));
                },
                function (callback) {
                    // above refreshAge below maxAge immediate result
                    memoizedGetNextNumber(passError(callback, function (nextNumber) {
                        expect(nextNumber, 'to be', 1);
                        expect(method, 'was called twice');
                        gotoTick(27);
                        callback();
                    }));
                },
                function (callback) {
                    // above initial maxAge but immediate result because refresh
                    memoizedGetNextNumber(passError(callback, function (nextNumber) {
                        expect(nextNumber, 'to be', 2);
                        expect(method, 'was called twice');
                        callback();
                    }));
                }
            ], done);
        });
    });
});
<|endoftext|>


<commit_before>var Album = {
    init: function() {
        this._initSoundCloudWidget();
        this._initPopup();
        this._initControls();
    },

    _popup: null,
    _sound: null,

    _initPopup: function() {
        this._popup = $('.popup-gallery').magnificPopup({

            delegate: '.mfp-image',
            type: 'image',

            tLoading: 'Loading image #%curr%...',
            mainClass: 'mfp-album-popup',

            gallery: {
                enabled: true,
                navigateByImgClick: true,
                preload: [0, 2],
            },

            image: {
                cursor: null,
                tError: 'The image #%curr% could not be loaded.',

                titleSrc: function (item) {
                    return '
'+
                                '
'+ item.el.attr('data-photographer') + '
' +
                                '
' + item.el.attr('data-date') + '
' +
                                '
' + item.el.attr('data-location') + '
' +
                                '
' + item.el.attr('data-location-description') + '
' +
                                '
' + item.el.attr('title') + '
' +
                                '
'+
                                    '
'+
                                        ''+
                                        ''+
                                        ''+
                                    '
'+
                                '
'+
                            '
'
                },

                markup: '
'+
                            '

'+
                            '
'+
                                '

'+
                                '
'+
                                    ''+
                                '
'+
                            '
'+
                            '
'+
                                '

'+
                                '

'+
                            '
'+
                        '
'
            },
            closeBtnInside: true,
            callbacks: {
                updateStatus: $.proxy(function () {

                    this._initImage();

                    var audio = $('.mfp-title .image-caption').data('audio');
                    var controls = $('.mfp-controls');
                    if(audio && audio != "") {
                        var slideshow = this._popup.data('slideshow');
                        slideshow ? this._initPauseButton() : this._initPlayButton();

                        controls.show();
                        controls.off('click');
                        controls.on('click', $.proxy(this._toggleWidget, this));

                        this._reloadWidget(audio, slideshow);
                    } else {
                        controls.hide();
                    }
                }, this),
                close: $.proxy(function () {
                    this._stopWidget();
                    this._popup.removeData('slideshow');
                }, this)
            }
        });
    },

    _initSoundCloudWidget: function() {
        SC.initialize({
            client_id: "d129911dd3c35ec537c30a06990bd902",
        });
    },

    _reloadWidget: function(audio, autoplay) {
        SC.stream("/tracks/" + audio, $.proxy(function(sound){
            if(this._sound){
                this._sound.stop();
            }
            this._sound = sound;
            if(autoplay){
                this._playWidget();
            }
        }, this));
    },

    _playWidget: function() {
        this._sound.play({
            onfinish: this._initPlayButton
        });
    },

    _toggleWidget: function() {
        this._togglePlayButton();
        if(this._sound.playState === 0) {
            this._playWidget();
            return;
        }
        this._sound.togglePause();
    },

    _stopWidget: function() {
        if(this._sound){
            this._sound.stop();
        }
    },

    _initControls: function() {
        $('.album-controls').click($.proxy(function () {
            this._popup.data('slideshow', 'true');
            this._popup.magnificPopup('open');
        }, this));
    },

    _initImage: function() {
        $('.btn-fullscreen').on('click', function() {
            $('.mfp-container').addClass('mfp-container-fullscreen');
            return false;
        });

        $('.mfp-figure').on('click', function() {
            $('.mfp-container').removeClass('mfp-container-fullscreen');
        });
    },

    _togglePlayButton: function() {
        $('.audio').toggle();
    },

    _initPlayButton: function(){
        $('.icon-play', '.mfp-controls').show();
        $('.icon-pause', '.mfp-controls').hide();
    },

    _initPauseButton: function(){
        $('.icon-play', '.mfp-controls').hide();
        $('.icon-pause', '.mfp-controls').show();
    }
}

$(function() {
    Album.init();
});
<commit_msg>Adding a slideshow button to the album images<commit_after>var Album = {
    init: function() {
        this._initSoundCloudWidget();
        this._initPopup();
        this._initControls();
    },

    _popup: null,
    _sound: null,

    _initPopup: function() {
        this._popup = $('.popup-gallery').magnificPopup({

            delegate: '.mfp-image',
            type: 'image',

            tLoading: 'Loading image #%curr%...',
            mainClass: 'mfp-album-popup',

            gallery: {
                enabled: true,
                navigateByImgClick: true,
                preload: [0, 2],
            },

            image: {
                cursor: null,
                tError: 'The image #%curr% could not be loaded.',

                titleSrc: $.proxy(function (item) {
                    var slideshow = this._popup.data('slideshow');
                    var icon = slideshow ? "pause" : "play";
                    return '
'+
                                '
'+ item.el.attr('data-photographer') + '
' +
                                '
' + item.el.attr('data-date') + '
' +
                                '
' + item.el.attr('data-location') + '
' +
                                '
' + item.el.attr('data-location-description') + '
' +
                                '
' + item.el.attr('title') + '
' +
                                '
'+
                                    '
'+
                                        'Slideshow '+
                                        ''+
                                        ''+
                                        ''+
                                    '
'+
                                '
'+
                            '
'
                }, this),

                markup: '
'+
                            '

'+
                            '
'+
                                '

'+
                                '
'+
                                    ''+
                                '
'+
                            '
'+
                            '
'+
                                '

'+
                                '

'+
                            '
'+
                        '
'
            },
            closeBtnInside: true,
            callbacks: {
                updateStatus: $.proxy(function () {
                    this._initImage();
                    this._initAudio();
                }, this),
                close: $.proxy(function () {
                    this._stopWidget();
                    this._popup.removeData('slideshow');
                }, this)
            }
        });
    },

    _initSoundCloudWidget: function() {
        SC.initialize({
            client_id: "d129911dd3c35ec537c30a06990bd902",
        });
    },

    _reloadWidget: function(audio, autoplay) {
        SC.stream("/tracks/" + audio, $.proxy(function(sound){
            if(this._sound){
                this._sound.stop();
            }
            this._sound = sound;
            if(autoplay){
                this._playWidget();
            }
        }, this));
    },

    _playWidget: function() {
        this._sound.play({
            onfinish: $.proxy(this._onSoundFinish, this)
        });
    },

    _toggleWidget: function() {
        this._togglePlayButton();
        if(this._sound.playState === 0) {
            this._playWidget();
            return;
        }
        this._sound.togglePause();
    },

    _updateSlideshowButtonIcon: function () {
        var slideshow = this._popup.data('slideshow');
        var slideshowButton = $('.btn-slideshow i');
        if(slideshow) {
            slideshowButton.addClass('icon-pause');
            slideshowButton.removeClass('icon-play');
        } else {
            slideshowButton.addClass('icon-play');
            slideshowButton.removeClass('icon-pause');

        }

    },

    _stopWidget: function() {
        if(this._sound){
            this._sound.stop();
        }
    },

    _onSoundFinish: function() {
        var slideshow = this._popup.data('slideshow');
        if(slideshow) {
            var magnificPopup = $.magnificPopup.instance;
            magnificPopup.next();
            return;
        }
        this._initPlayButton();
    },

    _initControls: function() {
        $('.album-controls').click($.proxy(function () {
            this._popup.data('slideshow', 'true');
            this._popup.magnificPopup('open');
        }, this));
    },

    _initImage: function() {
        $('.btn-fullscreen').on('click', function() {
            $('.mfp-container').addClass('mfp-container-fullscreen');
            return false;
        });

        $('.btn-slideshow').on('click', $.proxy(function() {
            var slideshow = this._popup.data("slideshow");
            if(slideshow) {
                this._popup.removeData('slideshow');
            } else {
                this._popup.data('slideshow', 'true');
            }

            this._updateSlideshowButtonIcon();
            this._initAudio();

            return false;
        }, this));

        $('.mfp-figure').on('click', function() {
            $('.mfp-container').removeClass('mfp-container-fullscreen');
        });
    },

    _initAudio: function() {
        var audio = $('.mfp-title .image-caption').data('audio');
        var controls = $('.mfp-controls');
        var slideshow = this._popup.data('slideshow');

        if(audio && audio != "") {
            slideshow ? this._initPauseButton() : this._initPlayButton();

            controls.show();
            controls.off('click');
            controls.on('click', $.proxy(this._toggleWidget, this));

            this._reloadWidget(audio, slideshow);
        } else {
            controls.hide();
        }
    },

    _togglePlayButton: function() {
        $('.audio').toggle();
    },

    _initPlayButton: function(){
        $('.icon-play', '.mfp-controls').show();
        $('.icon-pause', '.mfp-controls').hide();
    },

    _initPauseButton: function(){
        $('.icon-play', '.mfp-controls').hide();
        $('.icon-pause', '.mfp-controls').show();
    }
}

$(function() {
    Album.init();
});
<|endoftext|>


<commit_before>/* global describe */
/* global before */
/* global afterEach */
/* global it */

var chai = require('chai');
chai.use(require("chai-as-promised"));
var expect = chai.expect;
var Promise = require('bluebird');
var sinon = require('sinon');

var TestHelper = require('./test-helper.js');
var Reviews = require('../srv/reviews.js');

var sandbox = sinon.sandbox.create();
var sender = {
	sendMail: function (options, callback) { }
};

var Data = {};
var Notification;

describe('Notification', function () {
	before(function () {
		var config = TestHelper.setupTestFolder(__filename, ['reviews.db']);
		config.mailserver.host = "localhost";

		var nodemailer = require('nodemailer');
		sinon.stub(nodemailer, 'createTransport').returns(sender);

		var ThrottleQueue = require('../srv/util/ThrottleQueue.js');
		ThrottleQueue.prototype.throttleDelay = 1e12;	// We'll trigger processQueue manually for testing
	});

	afterEach(function () {
		sandbox.restore();
	})

	it('module should initialize properly', function () {
		Notification = require('../srv/notification.js');
		expect(Notification).to.be.ok;
		Notification.logEvents = false;
	});

	describe('newReview', function () {
		it('should send emails immediately', function () {
			Notification.newReview(Data.reviews[2]);
			return expect(waitForSendMail()).to.be.fulfilled;
		});

		it('should send mail with expected values', function () {
			Notification.newReview(Data.reviews[2]);
			return expect(waitForSendMail()
				.then(function (sendSpy) {
					expect(sendSpy.callCount).to.equal(1);
					expect(sendSpy.firstCall.args).to.have.length(2);
					expect(sendSpy.firstCall.args[0].subject).to.equal("New Review 2: Bob's Code Review #2");
					expect(sendSpy.firstCall.args[0].to).to.have.length(5);
					expect(sendSpy.firstCall.args[0].replyTo).to.equal("John Doe <john.doe@example.com>");
				})).to.be.fulfilled;
		});
	});
});

function waitForSendMail() {
	return new Promise(function (resolve, reject) {
		var sendSpy = sandbox.spy(sender, 'sendMail');
		function check() {
			if (sendSpy.called) {
				resolve(sendSpy);
			} else {
				setTimeout(check, 5);
			}
		}
		check();
	});
}

Data.reviews = {
	2: {
		"ix":2,
		"id":"7kULUz32rDthib47gMQQMoc",
		"title":"Bob's Code Review #2",
		"description":"",
		"owner":"John Doe <john.doe@example.com>",
		"whenCreated":1440047582964,
		"status":"complete",
		"statusLabel":null,
		"whenUpdated":1440559322417,
		"reviewers":[
			{"name":"bob.smith@example.com","status":null,"statusLabel":null},
			{"name":"bonzai@foo.com","status":null,"statusLabel":null},
			{"name":"john.doe@example.com","status":null,"statusLabel":null},
			{"name":"john.smith@example.com","status":null,"statusLabel":null}
		]
	},
	6: {
		"ix":6,
		"id":"7kULUz32rDthib47gMQQMo0",
		"title":null,
		"description":null,
		"owner":null,
		"whenCreated":null,
		"status":"active",
		"statusLabel":null,
		"whenUpdated":null,
		"reviewers":[]
	}
}<commit_msg>added test for Notification.reviewerJoined<commit_after>/* global describe */
/* global before */
/* global afterEach */
/* global it */

var chai = require('chai');
chai.use(require("chai-as-promised"));
var expect = chai.expect;
var Promise = require('bluebird');
var sinon = require('sinon');

var TestHelper = require('./test-helper.js');
var Reviews = require('../srv/reviews.js');

var sandbox = sinon.sandbox.create();
var sender = {
	sendMail: function (options, callback) { }
};

var Data = {};
var Notification;

describe('Notification', function () {
	before(function () {
		var config = TestHelper.setupTestFolder(__filename, ['reviews.db']);
		config.mailserver.host = "localhost";

		var nodemailer = require('nodemailer');
		sinon.stub(nodemailer, 'createTransport').returns(sender);

		var ThrottleQueue = require('../srv/util/ThrottleQueue.js');
		ThrottleQueue.prototype.throttleDelay = 1e12;	// We'll trigger processQueue manually for testing
	});

	afterEach(function () {
		sandbox.restore();
	})

	it('module should initialize properly', function () {
		Notification = require('../srv/notification.js');
		expect(Notification).to.be.ok;
		Notification.logEvents = false;
	});

	describe('newReview', function () {
		it('should send emails immediately', function () {
			Notification.newReview(Data.reviews[2]);
			return expect(waitForSendMail()).to.be.fulfilled;
		});

		it('should send mail with expected values', function () {
			Notification.newReview(Data.reviews[2]);
			return expect(waitForSendMail()
				.then(function (sendSpy) {
					expect(sendSpy.callCount).to.equal(1);
					expect(sendSpy.firstCall.args).to.have.length(2);
					expect(sendSpy.firstCall.args[0].subject).to.equal("New Review 2: Bob's Code Review #2");
					expect(sendSpy.firstCall.args[0].to).to.have.length(4);
					expect(sendSpy.firstCall.args[0].replyTo).to.equal("John Doe <john.doe@example.com>");
				})).to.be.fulfilled;
		});
	});

	describe('reviewerJoined', function () {
		it('should send emails immediately', function () {
			sandbox.stub(Reviews, 'getReview', function (ixOrId) {
				return Promise.resolve(Data.reviews[2]);
			});
			Notification.reviewerJoined(2, "John Smith <john.smith@example.com>");
			return expect(waitForSendMail()).to.be.fulfilled;
		});

		it('should send mail with expected values', function () {
			sandbox.stub(Reviews, 'getReview', function (ixOrId) {
				return Promise.resolve(Data.reviews[2]);
			});
			Notification.reviewerJoined(2, "John Smith <john.smith@example.com>");
			return expect(waitForSendMail()
				.then(function (sendSpy) {
					expect(sendSpy.callCount).to.equal(1);
					expect(sendSpy.firstCall.args).to.have.length(2);
					expect(sendSpy.firstCall.args[0].subject).to.equal("Review 2: John Smith Joined!");
					expect(sendSpy.firstCall.args[0].to).to.equal("John Doe <john.doe@example.com>");
					expect(sendSpy.firstCall.args[0].replyTo).to.equal("John Doe <john.doe@example.com>");
				})).to.be.fulfilled;
		});
	});
});

function waitForSendMail() {
	return new Promise(function (resolve, reject) {
		var sendSpy = sandbox.spy(sender, 'sendMail');
		function check() {
			if (sendSpy.called) {
				resolve(sendSpy);
			} else {
				setTimeout(check, 5);
			}
		}
		check();
	});
}

Data.reviews = {
	2: {
		"ix":2,
		"id":"7kULUz32rDthib47gMQQMoc",
		"title":"Bob's Code Review #2",
		"description":"",
		"owner":"John Doe <john.doe@example.com>",
		"whenCreated":1440047582964,
		"status":"complete",
		"statusLabel":null,
		"whenUpdated":1440559322417,
		"reviewers":[
			{"name":"bob.smith@example.com","status":null,"statusLabel":null},
			{"name":"john.doe@example.com","status":null,"statusLabel":null},
			{"name":"John Smith <john.smith@example.com>","status":null,"statusLabel":null}
		]
	},
	6: {
		"ix":6,
		"id":"7kULUz32rDthib47gMQQMo0",
		"title":null,
		"description":null,
		"owner":null,
		"whenCreated":null,
		"status":"active",
		"statusLabel":null,
		"whenUpdated":null,
		"reviewers":[]
	}
}<|endoftext|>


<commit_before>var assert = require('assert');
var OpenTok = require('../lib/opentok.js');

describe('OpenTok', function() {
  it('should initialize with a valid apiKey and apiSecret', function() {
    assert.ok(new OpenTok('123123123', 'abcdefghijklmnop') instanceof OpenTok);
  });
  it('should initialize without `new`', function() {
    assert.ok(OpenTok('123123123', 'abcdefghijklmnop') instanceof OpenTok);
  });
  it('should not initialize with just an apiKey but no apiSecret', function() {
    assert.ok(!(new OpenTok('123123123') instanceof OpenTok));
  });
  it('should not initialize with incorrect type parameters', function() {
    assert.ok(!(new OpenTok(new Date(), 'asdasdasdasdasd') instanceof OpenTok));
    assert.ok(!(new OpenTok(4, {}) instanceof OpenTok));
  });
  it('should be able to take an number or a string for the apiKey', function() {
    assert.ok(new OpenTok('123123123', 'abcdefghijklmnop') instanceof OpenTok);
    assert.ok(new OpenTok(123123123, 'abcdefghijklmnop') instanceof OpenTok);
  });

  describe('#createSession', function() {

    it('creates a new session', function(done) {
      // pass no options parameter
      done();
    });

    it('creates a peer to peer session', function(done) {
      // 2 expectations: if a session created without the flag isn't peer to peer,
      //                 if a session created with the flag is peer to peer
      // try passing an invalid value to the p2p flag
      done();
    });

    it('adds a location hint to the created session', function(done) {
      // 2 expectations: if a session created without the hint doesn't have a hint,
      //                 if a session created with the hint has the hint
      // try passing an invalid hint
      done();
    });

    it('optionally takes a config parameter', function(done) {
      // creates a session without the config param
      // creates a session with a config param
      // doesn't pass unidentified options to the server
      done();
    });

    it('complains when there is no callback function', function(done) {
      done();
    });

    it('compains when a server error takes place', function(done) {
      done();
    });

  });

  describe('#generateToken', function() {

    var sessionId;
    var opentok = new OpenTok('123456', 'APISECRET');

    beforeEach(function(done) {
      // TODO: use a stub here instead of making a real request
      opentok.createSession(function(err, freshSessionId) {
        sessionId = freshSessionId;
        done();
      });
    });

    it('generates a token', function() {
      // call generateToken with no options
      var token = opentok.generateToken(sessionId);
      assert.ok(typeof token == 'string');
      // TODO: decode token and verify signature
    });

    it('assigns a role in the token', function() {
      // expects one with no role defined to assign "publisher"
      var defaultRoleToken = opentok.generateToken(sessionId);
      // TODO: decode token, verify signature, make sure "role" matches 'publisher'
      // expects one with a valid role defined to set it
      var subscriberToken = opentok.generateToken(sessionId, { role : 'subscriber' });
      // TODO: decode token, verify signature, make sure "role" matches 'subscriber'
      // expects one with an invalid role to complain
      var invalidToken = opentok.generateToken(sessionId, { role : 5 });
      assert.ok(invalidToken === false);
    });

    it('sets an expiration time for the token', function() {
      // expects a token with no expiration time to assign 1 day
      // expects a token with an expiration time to have it
      // expects a token with an invalid expiration time to complain
    });

    it('sets connection data in the token', function() {
      // expects a token with no connection data to have none
      // expects a token with a connection data to have it
      // expects a token with invalid connection to complain
    });

    it('complains if the sessionId is not valid', function() {
      // complains if there is no sessionId
      // complains if the sessionId doesn't belong to the apiKey
    });

    it('contains a unique nonce', function() {
      // generate a few and show the nonce exists each time and that they are different
    });
  });

  // existence of constants on the constructor and the instance

});
<commit_msg>comments out incomplete tests<commit_after>var assert = require('assert');
var OpenTok = require('../lib/opentok.js');

describe('OpenTok', function() {
  it('should initialize with a valid apiKey and apiSecret', function() {
    assert.ok(new OpenTok('123123123', 'abcdefghijklmnop') instanceof OpenTok);
  });
  it('should initialize without `new`', function() {
    assert.ok(OpenTok('123123123', 'abcdefghijklmnop') instanceof OpenTok);
  });
  it('should not initialize with just an apiKey but no apiSecret', function() {
    assert.ok(!(new OpenTok('123123123') instanceof OpenTok));
  });
  it('should not initialize with incorrect type parameters', function() {
    assert.ok(!(new OpenTok(new Date(), 'asdasdasdasdasd') instanceof OpenTok));
    assert.ok(!(new OpenTok(4, {}) instanceof OpenTok));
  });
  it('should be able to take an number or a string for the apiKey', function() {
    assert.ok(new OpenTok('123123123', 'abcdefghijklmnop') instanceof OpenTok);
    assert.ok(new OpenTok(123123123, 'abcdefghijklmnop') instanceof OpenTok);
  });

  describe('#createSession', function() {

    it('creates a new session', function(done) {
      // pass no options parameter
      done();
    });

    it('creates a peer to peer session', function(done) {
      // 2 expectations: if a session created without the flag isn't peer to peer,
      //                 if a session created with the flag is peer to peer
      // try passing an invalid value to the p2p flag
      done();
    });

    it('adds a location hint to the created session', function(done) {
      // 2 expectations: if a session created without the hint doesn't have a hint,
      //                 if a session created with the hint has the hint
      // try passing an invalid hint
      done();
    });

    it('optionally takes a config parameter', function(done) {
      // creates a session without the config param
      // creates a session with a config param
      // doesn't pass unidentified options to the server
      done();
    });

    it('complains when there is no callback function', function(done) {
      done();
    });

    it('compains when a server error takes place', function(done) {
      done();
    });

  });

  describe('#generateToken', function() {

    var sessionId;
    var opentok = new OpenTok('123456', 'APISECRET');

    beforeEach(function(done) {
      // TODO: use a stub here instead of making a real request
      //opentok.createSession(function(err, freshSessionId) {
      //  sessionId = freshSessionId;
        done();
      //});
    });

    it('generates a token', function() {
      // call generateToken with no options
      //var token = opentok.generateToken(sessionId);
      //assert.ok(typeof token == 'string');
      // TODO: decode token and verify signature
    });

    it('assigns a role in the token', function() {
      // expects one with no role defined to assign "publisher"
      //var defaultRoleToken = opentok.generateToken(sessionId);
      // TODO: decode token, verify signature, make sure "role" matches 'publisher'
      // expects one with a valid role defined to set it
      //var subscriberToken = opentok.generateToken(sessionId, { role : 'subscriber' });
      // TODO: decode token, verify signature, make sure "role" matches 'subscriber'
      // expects one with an invalid role to complain
      //var invalidToken = opentok.generateToken(sessionId, { role : 5 });
      //assert.ok(invalidToken === false);
    });

    it('sets an expiration time for the token', function() {
      // expects a token with no expiration time to assign 1 day
      // expects a token with an expiration time to have it
      // expects a token with an invalid expiration time to complain
    });

    it('sets connection data in the token', function() {
      // expects a token with no connection data to have none
      // expects a token with a connection data to have it
      // expects a token with invalid connection to complain
    });

    it('complains if the sessionId is not valid', function() {
      // complains if there is no sessionId
      // complains if the sessionId doesn't belong to the apiKey
    });

    it('contains a unique nonce', function() {
      // generate a few and show the nonce exists each time and that they are different
    });
  });

  // existence of constants on the constructor and the instance

});
<|endoftext|>


<commit_before>export default {
    defaults: {
        // Section508, WCAG2A, WCAG2AA, WCAG2AAA
        allowedStandards: ['WCAG2A'],
        // the level of issue to fail on (exit with code 2): error, warning, notice, none
        level: 'none',
        rootElement: '.c-dashboard__body',
        timeout: 30000
    },
    urls: [
        {
            // homepage
            url: 'http://localhost:8080/#?mpb=topografie&mpz=11&mpv=52.3731081:4.8932945&pgn=home',
            rootElement: ''
        },
        {
            // adressenlijst
            url: 'http://localhost:8080/#?dsd=bag&dsp=1&dsv=TABLE&mpb=topografie&mpz=11&mpv=52.3731081:4.8932945',
            actions: [
                'wait for element .qa-data-selection-content to be visible'
            ]
        },
        {
            // vestigingenlijst
            url: 'http://localhost:8080/#?dsd=hr&dsp=1&dsv=TABLE&mpb=topografie&mpz=11&mpv=52.3731081:4.8932945',
            actions: [
                'wait for element .qa-disabled-message to be visible',
                'click element .qa-menu__login',
                'wait for element .c-form to be visible',
                `set field #email to ${process.env.USERNAME_EMPLOYEE}`,
                `set field #password to ${process.env.PASSWORD_EMPLOYEE}`,
                'click element .c-form-buttons__button[value=employee_plus]',
                'wait for element .qa-data-selection-content to be visible'
            ]
        },
        {
            // straatbeeld
            url: 'http://localhost:8080/#?mpb=topografie&mpz=11&mpo=pano::T&mpv=52.3730353:4.8932471&pgn=home&sbf=Cu&' +
                'sbh=aS&sbi=TMX7315120208-000073_pano_0005_000449&sbl=ZRWBl:3JJZP',
            actions: [
                'wait for element .c-map to be visible',
                'wait for element .c-straatbeeld to be visible'
            ]
        },
        {
            // kaart met 2 kaartlagen: meetbouten en kadastrale perceelgrenzen
            url: 'http://localhost:8080/#?lse=T&mpb=topografie&mpz=12&mpfs=T&mpo=bgem::T:kgem::T:ksec::T:kot::T:mbs::' +
                'T&mpv=52.3731147:4.8933883&pgn=home',
            actions: [
                'wait for element .c-map to be visible'
            ]
        },
        {
            // kaart met geo search
            url: 'http://localhost:8080/#?mpb=topografie&mpz=12&mpo=bgem::T:kgem::T:ksec::T:kot::T:mbs::T&mpv=52.3734' +
                '045:4.8922749&srl=ZRX9J:3JH2b',
            rootElement: '.c-dashboard__body',
            actions: [
                'wait for element .c-map to be visible'
            ]
        },
        {
            // kaart met adressenlijst en getekende ruimte
            url: 'http://localhost:8080/#?dsd=bag&dsgf=ZRcTb::3JDU2:ZRbBw::3JKwW:ZRZF8::3JFFi&dsgd=518,2%2520m%2520en' +
                '%252012.209,9%2520m%25C2%25B2&dsp=1&dsv=LIST&mpb=topografie&mpz=12&mpo=bgem::T:kgem::T:ksec::T:kot::' +
                'T:mbs::T&mpv=52.3734045:4.8922749&srl=ZRX9J:3JH2b',
            actions: [
                'wait for element .c-map to be visible',
                'wait for element .qa-data-selection-content to be visible'
            ]
        },
        {
            // adressenlijst met ingetekende ruimte en 1 filter
            url: 'http://localhost:8080/#?dsd=bag&dsgf=ZRcTb::3JDU2:ZRbBw::3JKwW:ZRZF8::3JFFi&dsgd=518,2%2520m%2520en' +
                '%252012.209,9%2520m%25C2%25B2&dsp=1&dsv=TABLE&dsf=openbare_ruimte::Blaeustraat&mpb=topografie&mpz=12' +
                '&mpo=bgem::T:kgem::T:ksec::T:kot::T:mbs::T&mpv=52.3734045:4.8922749&srl=ZRX9J:3JH2b',
            actions: [
                'wait for element .qa-data-selection-content to be visible'
            ]
        }
    ]
};
<commit_msg>added login page to aria reporting tg-4740<commit_after>export default {
    defaults: {
        // Section508, WCAG2A, WCAG2AA, WCAG2AAA
        allowedStandards: ['WCAG2A'],
        // the level of issue to fail on (exit with code 2): error, warning, notice, none
        level: 'none',
        rootElement: '.c-dashboard__body',
        timeout: 30000
    },
    urls: [
        {
            // homepage
            url: 'http://localhost:8080/#?mpb=topografie&mpz=11&mpv=52.3731081:4.8932945&pgn=home',
            rootElement: ''
        },
        {
            // adressenlijst
            url: 'http://localhost:8080/#?dsd=bag&dsp=1&dsv=TABLE&mpb=topografie&mpz=11&mpv=52.3731081:4.8932945',
            actions: [
                'wait for element .qa-data-selection-content to be visible'
            ]
        },
        {
            // vestigingenlijst
            url: 'http://localhost:8080/#?dsd=hr&dsp=1&dsv=TABLE&mpb=topografie&mpz=11&mpv=52.3731081:4.8932945',
            actions: [
                'wait for element .qa-disabled-message to be visible',
                'click element .qa-menu__login',
                'wait for element .c-form to be visible',
                `set field #email to ${process.env.USERNAME_EMPLOYEE}`,
                `set field #password to ${process.env.PASSWORD_EMPLOYEE}`,
                'click element .c-form-buttons__button[value=employee_plus]',
                'wait for element .qa-data-selection-content to be visible'
            ]
        },
        {
            // straatbeeld
            url: 'http://localhost:8080/#?mpb=topografie&mpz=11&mpo=pano::T&mpv=52.3730353:4.8932471&pgn=home&sbf=Cu&' +
                'sbh=aS&sbi=TMX7315120208-000073_pano_0005_000449&sbl=ZRWBl:3JJZP',
            actions: [
                'wait for element .c-map to be visible',
                'wait for element .c-straatbeeld to be visible'
            ]
        },
        {
            // kaart met 2 kaartlagen: meetbouten en kadastrale perceelgrenzen
            url: 'http://localhost:8080/#?lse=T&mpb=topografie&mpz=12&mpfs=T&mpo=bgem::T:kgem::T:ksec::T:kot::T:mbs::' +
                'T&mpv=52.3731147:4.8933883&pgn=home',
            actions: [
                'wait for element .c-map to be visible'
            ]
        },
        {
            // kaart met geo search
            url: 'http://localhost:8080/#?mpb=topografie&mpz=12&mpo=bgem::T:kgem::T:ksec::T:kot::T:mbs::T&mpv=52.3734' +
                '045:4.8922749&srl=ZRX9J:3JH2b',
            rootElement: '.c-dashboard__body',
            actions: [
                'wait for element .c-map to be visible'
            ]
        },
        {
            // kaart met adressenlijst en getekende ruimte
            url: 'http://localhost:8080/#?dsd=bag&dsgf=ZRcTb::3JDU2:ZRbBw::3JKwW:ZRZF8::3JFFi&dsgd=518,2%2520m%2520en' +
                '%252012.209,9%2520m%25C2%25B2&dsp=1&dsv=LIST&mpb=topografie&mpz=12&mpo=bgem::T:kgem::T:ksec::T:kot::' +
                'T:mbs::T&mpv=52.3734045:4.8922749&srl=ZRX9J:3JH2b',
            actions: [
                'wait for element .c-map to be visible',
                'wait for element .qa-data-selection-content to be visible'
            ]
        },
        {
            // adressenlijst met ingetekende ruimte en 1 filter
            url: 'http://localhost:8080/#?dsd=bag&dsgf=ZRcTb::3JDU2:ZRbBw::3JKwW:ZRZF8::3JFFi&dsgd=518,2%2520m%2520en' +
                '%252012.209,9%2520m%25C2%25B2&dsp=1&dsv=TABLE&dsf=openbare_ruimte::Blaeustraat&mpb=topografie&mpz=12' +
                '&mpo=bgem::T:kgem::T:ksec::T:kot::T:mbs::T&mpv=52.3734045:4.8922749&srl=ZRX9J:3JH2b',
            actions: [
                'wait for element .qa-data-selection-content to be visible'
            ]
        },
        {
            // login page
            url: 'https://acc.api.data.amsterdam.nl/auth/idp/login?callback=https%3A%2F%2Facc.api.data.amsterdam.nl%2' +
                'Foauth2%2Fcallback',
            rootElement: ''
        }
    ]
};
<|endoftext|>