"use strict";

var _Object$keys = require("@babel/runtime-corejs2/core-js/object/keys");
var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptors");
var _Object$defineProperties = require("@babel/runtime-corejs2/core-js/object/define-properties");
var _Object$defineProperty2 = require("@babel/runtime-corejs2/core-js/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/define-property"));
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
var _construct2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/construct"));
var _defineProperty3 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
var _forEach2 = _interopRequireDefault(require("lodash/forEach"));
var _crypto = require("crypto");
var _testHelperChai = require("@webex/test-helper-chai");
var _testHelperMockWebSocket = _interopRequireDefault(require("@webex/test-helper-mock-web-socket"));
var _sinon = _interopRequireDefault(require("sinon"));
var _errors = require("./errors");
var _config = _interopRequireDefault(require("./config"));
var _socket = _interopRequireDefault(require("./socket"));
var _constants = require("./socket/constants");
function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty3.default)(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { _Object$defineProperty2(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; } /*!
 * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
 */
if (!crypto.randomUUID) {
  (0, _defineProperty2.default)(crypto, 'randomUUID', {
    value: _crypto.randomUUID,
    configurable: true
  });
}
describe('plugin-mobius-socket', function () {
  describe('Socket', function () {
    var mockWebSocket;
    var socket;
    var usingFakeTimers;
    var mockoptions = _objectSpread({
      logger: console,
      token: 'mocktoken',
      trackingId: 'mocktrackingid'
    }, _config.default.mobiusSocket);
    var emitAuthResponse = function emitAuthResponse() {
      var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
        _ref$statusCode = _ref.statusCode,
        statusCode = _ref$statusCode === void 0 ? 200 : _ref$statusCode,
        _ref$statusMessage = _ref.statusMessage,
        statusMessage = _ref$statusMessage === void 0 ? 'OK' : _ref$statusMessage;
      var authRequest = JSON.parse(mockWebSocket.send.lastCall.args[0]);
      mockWebSocket.emit('message', {
        data: (0, _stringify.default)({
          type: 'response_event',
          subtype: _constants.MESSAGE_TYPES.AUTH,
          trackingId: authRequest.trackingId,
          statusCode: statusCode,
          statusMessage: statusMessage
        })
      });
    };
    beforeEach(function () {
      jest.useFakeTimers({
        doNotFake: ['nextTick']
      });
      usingFakeTimers = true;
    });
    beforeEach(function () {
      _sinon.default.stub(_socket.default, 'getWebSocketConstructor').callsFake(function () {
        return function () {
          for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
            args[_key] = arguments[_key];
          }
          mockWebSocket = (0, _construct2.default)(_testHelperMockWebSocket.default, args);
          return mockWebSocket;
        };
      });
      socket = new _socket.default();
      var promise = socket.open('ws://example.com', mockoptions);
      mockWebSocket.open();
      // Simulate Mobius auth response (MockWebSocket.open auto-sends mercury.buffer_state which Mobius ignores)
      process.nextTick(function () {
        emitAuthResponse();
      });
      return promise;
    });
    afterEach(function () {
      if (usingFakeTimers) {
        jest.useRealTimers();
        usingFakeTimers = false;
      }
      _socket.default.getWebSocketConstructor.restore();
      return _promise.default.resolve(socket && socket.close()).then(function () {
        mockWebSocket = undefined;
        socket = undefined;
      });
    });
    describe('#open()', function () {
      var freshSocket;
      beforeEach(function () {
        freshSocket = new _socket.default();
      });
      afterEach(function () {
        return freshSocket.close().catch(function () {
          return undefined;
        });
      });
      it('requires a url', function () {
        return _testHelperChai.assert.isRejected(freshSocket.open(), /`url` is required/);
      });
      it('requires a forceCloseDelay option', function () {
        return _testHelperChai.assert.isRejected(freshSocket.open('ws://example.com'), /missing required property forceCloseDelay/);
      });
      it('requires a token option', function () {
        return _testHelperChai.assert.isRejected(freshSocket.open('ws://example.com', {
          forceCloseDelay: mockoptions.forceCloseDelay
        }), /missing required property token/);
      });
      it('requires a trackingId option', function () {
        return _testHelperChai.assert.isRejected(freshSocket.open('ws://example.com', {
          forceCloseDelay: mockoptions.forceCloseDelay,
          token: 'mocktoken'
        }), /missing required property trackingId/);
      });
      it('requires a logger option', function () {
        return _testHelperChai.assert.isRejected(freshSocket.open('ws://example.com', {
          forceCloseDelay: mockoptions.forceCloseDelay,
          token: 'mocktoken',
          trackingId: 'mocktrackingid'
        }), /missing required property logger/);
      });
      it('accepts a logLevelToken option', function () {
        var openPromise = freshSocket.open('ws://example.com', {
          forceCloseDelay: mockoptions.forceCloseDelay,
          wssResponseTimeout: mockoptions.wssResponseTimeout,
          logger: console,
          token: 'mocktoken',
          trackingId: 'mocktrackingid',
          logLevelToken: 'mocklogleveltoken'
        });
        mockWebSocket.readyState = 1;
        mockWebSocket.emit('open');
        emitAuthResponse();
        return openPromise.then(function () {
          _testHelperChai.assert.equal(freshSocket.logLevelToken, 'mocklogleveltoken');
        });
      });
    });
    describe('#binaryType', function () {
      it('proxies to the underlying socket', function () {
        _testHelperChai.assert.notEqual(socket.binaryType, 'test');
        mockWebSocket.binaryType = 'test';
        _testHelperChai.assert.equal(socket.binaryType, 'test');
      });
    });
    describe('#bufferedAmount', function () {
      it('proxies to the underlying socket', function () {
        _testHelperChai.assert.notEqual(socket.bufferedAmount, 'test');
        mockWebSocket.bufferedAmount = 'test';
        _testHelperChai.assert.equal(socket.bufferedAmount, 'test');
      });
    });
    describe('#extensions', function () {
      it('proxies to the underlying socket', function () {
        _testHelperChai.assert.notEqual(socket.extensions, 'test');
        mockWebSocket.extensions = 'test';
        _testHelperChai.assert.equal(socket.extensions, 'test');
      });
    });
    describe('#protocol', function () {
      it('proxies to the underlying socket', function () {
        _testHelperChai.assert.notEqual(socket.protocol, 'test');
        mockWebSocket.protocol = 'test';
        _testHelperChai.assert.equal(socket.protocol, 'test');
      });
    });
    describe('#readyState', function () {
      it('proxies to the underlying socket', function () {
        _testHelperChai.assert.notEqual(socket.readyState, 'test');
        mockWebSocket.readyState = 'test';
        _testHelperChai.assert.equal(socket.readyState, 'test');
      });
    });
    describe('#url', function () {
      it('proxies to the underlying socket', function () {
        _testHelperChai.assert.notEqual(socket.url, 'test');
        mockWebSocket.url = 'test';
        _testHelperChai.assert.equal(socket.url, 'test');
      });
    });
    describe('#open()', function () {
      it('requires a url parameter', function () {
        var s = new _socket.default();
        return _testHelperChai.assert.isRejected(s.open(), /`url` is required/);
      });
      it('cannot be called more than once', function () {
        return _testHelperChai.assert.isRejected(socket.open('ws://example.com'), /Socket#open\(\) can only be called once/);
      });
      it("sets the underlying socket's binary type", function () {
        return _testHelperChai.assert.equal(socket.binaryType, 'arraybuffer');
      });
      describe('when connection fails because this is a service account', function () {
        it('rejects with a BadRequest', function () {
          var s = new _socket.default();
          var promise = s.open('ws://example.com', mockoptions);
          mockWebSocket.readyState = 1;
          mockWebSocket.emit('open');
          var firstCallArgs = JSON.parse(mockWebSocket.send.firstCall.args[0]);
          _testHelperChai.assert.equal(firstCallArgs.type, _constants.MESSAGE_TYPES.AUTH);
          mockWebSocket.emit('close', {
            code: 4400,
            reason: "Service accounts can't use this endpoint"
          });
          return _testHelperChai.assert.isRejected(promise).then(function (reason) {
            _testHelperChai.assert.instanceOf(reason, _errors.BadRequest);
            _testHelperChai.assert.match(reason.code, 4400);
            _testHelperChai.assert.match(reason.reason, /Service accounts can't use this endpoint/);
            _testHelperChai.assert.match(reason.message, /Service accounts can't use this endpoint/);
            return s.close();
          });
        });
      });
      describe('when connection fails because of an invalid token', function () {
        it('rejects with a NotAuthorized', function () {
          var s = new _socket.default();
          var promise = s.open('ws://example.com', mockoptions);
          mockWebSocket.readyState = 1;
          mockWebSocket.emit('open');
          var firstCallArgs = JSON.parse(mockWebSocket.send.firstCall.args[0]);
          _testHelperChai.assert.equal(firstCallArgs.type, _constants.MESSAGE_TYPES.AUTH);
          mockWebSocket.emit('close', {
            code: 4401,
            reason: 'Authorization Failed'
          });
          return _testHelperChai.assert.isRejected(promise).then(function (reason) {
            _testHelperChai.assert.instanceOf(reason, _errors.NotAuthorized);
            _testHelperChai.assert.match(reason.code, 4401);
            _testHelperChai.assert.match(reason.reason, /Authorization Failed/);
            _testHelperChai.assert.match(reason.message, /Authorization Failed/);
            return s.close();
          });
        });
      });
      describe('when connection fails because of a missing entitlement', function () {
        it('rejects with a Forbidden', function () {
          var s = new _socket.default();
          var promise = s.open('ws://example.com', mockoptions);
          mockWebSocket.readyState = 1;
          mockWebSocket.emit('open');
          var firstCallArgs = JSON.parse(mockWebSocket.send.firstCall.args[0]);
          _testHelperChai.assert.equal(firstCallArgs.type, _constants.MESSAGE_TYPES.AUTH);
          mockWebSocket.emit('close', {
            code: 4403,
            reason: 'Not entitled'
          });
          return _testHelperChai.assert.isRejected(promise).then(function (reason) {
            _testHelperChai.assert.instanceOf(reason, _errors.Forbidden);
            _testHelperChai.assert.match(reason.code, 4403);
            _testHelperChai.assert.match(reason.reason, /Not entitled/);
            _testHelperChai.assert.match(reason.message, /Not entitled/);
            return s.close();
          });
        });
      });
      describe('when connection fails for non-authorization reasons', function () {
        it("rejects with the close event's reason", function () {
          var s = new _socket.default();
          var promise = s.open('ws://example.com', mockoptions);
          mockWebSocket.emit('close', {
            code: 4001,
            reason: 'No'
          });
          return _testHelperChai.assert.isRejected(promise).then(function (reason) {
            _testHelperChai.assert.instanceOf(reason, _errors.ConnectionError);
            _testHelperChai.assert.match(reason.code, 4001);
            _testHelperChai.assert.match(reason.reason, /No/);
            _testHelperChai.assert.match(reason.message, /No/);
            return s.close();
          });
        });
      });
      describe('when the connection succeeds', function () {
        it('sends an auth message up the socket', function () {
          var firstCallArgs = JSON.parse(mockWebSocket.send.firstCall.args[0]);
          _testHelperChai.assert.equal(firstCallArgs.type, _constants.MESSAGE_TYPES.AUTH);
          _testHelperChai.assert.property(firstCallArgs, 'data');
          _testHelperChai.assert.property(firstCallArgs.data, 'token');
          _testHelperChai.assert.equal(firstCallArgs.data.token, 'mocktoken');
          _testHelperChai.assert.property(firstCallArgs, 'trackingId');
        });
        describe('when logLevelToken is set', function () {
          it('includes auth payload with token', function () {
            var s = new _socket.default();
            s.open('ws://example.com', {
              forceCloseDelay: mockoptions.forceCloseDelay,
              wssResponseTimeout: mockoptions.wssResponseTimeout,
              logger: console,
              token: 'mocktoken',
              trackingId: 'mocktrackingid'
            }).catch(function (reason) {
              return console.error(reason);
            });
            mockWebSocket.readyState = 1;
            mockWebSocket.emit('open');
            var firstCallArgs = JSON.parse(mockWebSocket.send.firstCall.args[0]);
            _testHelperChai.assert.equal(firstCallArgs.type, _constants.MESSAGE_TYPES.AUTH);
            _testHelperChai.assert.property(firstCallArgs, 'data');
            _testHelperChai.assert.equal(firstCallArgs.data.token, 'mocktoken');
            _testHelperChai.assert.property(firstCallArgs, 'trackingId');
            return s.close();
          });
        });
        it('resolves upon receiving response_event auth response', function () {
          var s = new _socket.default();
          var promise = s.open('ws://example.com', mockoptions);
          mockWebSocket.readyState = 1;
          mockWebSocket.emit('open');
          emitAuthResponse();
          return promise.then(function () {
            return s.close();
          });
        });
        it('rejects upon receiving a non-2xx auth response_event', function () {
          var s = new _socket.default();
          var promise = s.open('ws://example.com', mockoptions);
          mockWebSocket.readyState = 1;
          mockWebSocket.emit('open');
          emitAuthResponse({
            statusCode: 401,
            statusMessage: 'Unauthorized'
          });
          return _testHelperChai.assert.isRejected(promise).then(function (reason) {
            _testHelperChai.assert.equal(reason.name, 'MobiusSocketResponseError');
            _testHelperChai.assert.equal(reason.statusCode, 401);
            _testHelperChai.assert.match(reason.statusMessage, /Unauthorized/);
            return s.close();
          });
        });
      });
    });
    describe('#close()', function () {
      it('closes the socket', function () {
        return socket.close().then(function () {
          return _testHelperChai.assert.called(mockWebSocket.close);
        });
      });
      it('only accepts valid close codes', function () {
        return _promise.default.all([_testHelperChai.assert.isRejected(socket.close({
          code: 1001
        }), /`options.code` must be 1000 or between 3000 and 4999 \(inclusive\)/), socket.close({
          code: 1000
        })]);
      });
      it('accepts a reason', function () {
        return socket.close({
          code: 3001,
          reason: 'Custom Normal'
        }).then(function () {
          return _testHelperChai.assert.calledWith(mockWebSocket.close, 3001, 'Custom Normal');
        });
      });
      it('accepts the logout reason', function () {
        return socket.close({
          code: 3050,
          reason: 'done (permanent)'
        }).then(function () {
          return _testHelperChai.assert.calledWith(mockWebSocket.close, 3050, 'done (permanent)');
        });
      });
      it('can safely be called called multiple times', function () {
        var p1 = socket.close();
        mockWebSocket.readyState = 2;
        var p2 = socket.close();
        return _promise.default.all([p1, p2]);
      });
      it('signals closure if no close frame is received within the specified window', function () {
        var transientSocket = new _socket.default();
        var openPromise = transientSocket.open('ws://example.com', mockoptions);
        mockWebSocket.readyState = 1;
        mockWebSocket.emit('open');
        emitAuthResponse();
        return openPromise.then(function () {
          var spy = _sinon.default.spy();
          transientSocket.on('close', spy);
          mockWebSocket.close = function () {
            return new _promise.default(function () {
              /* eslint no-inline-comments: [0] */
            });
          };
          mockWebSocket.removeAllListeners('close');
          var closePromise = transientSocket.close();
          jest.advanceTimersByTime(mockoptions.forceCloseDelay);
          return closePromise.then(function () {
            _testHelperChai.assert.called(spy);
            _testHelperChai.assert.calledWith(spy, {
              code: 1000,
              reason: 'Done (forced)'
            });
          });
        });
      });
      it('signals closure if no close frame is received within the specified window, but uses the initial options as 3050 if specified by options call', function () {
        var transientSocket = new _socket.default();
        var openPromise = transientSocket.open('ws://example.com', mockoptions);
        mockWebSocket.readyState = 1;
        mockWebSocket.emit('open');
        emitAuthResponse();
        return openPromise.then(function () {
          var spy = _sinon.default.spy();
          transientSocket.on('close', spy);
          mockWebSocket.close = function () {
            return new _promise.default(function () {
              /* eslint no-inline-comments: [0] */
            });
          };
          mockWebSocket.removeAllListeners('close');
          var closePromise = transientSocket.close({
            code: 3050,
            reason: 'done (permanent)'
          });
          jest.advanceTimersByTime(mockoptions.forceCloseDelay);
          return closePromise.then(function () {
            _testHelperChai.assert.called(spy);
            _testHelperChai.assert.calledWith(spy, {
              code: 3050,
              reason: 'done (permanent)'
            });
          });
        });
      });
      it('signals closure if no close frame is received within the specified window, and uses default options as 1000 if the code is not 3050', function () {
        var transientSocket = new _socket.default();
        var openPromise = transientSocket.open('ws://example.com', mockoptions);
        mockWebSocket.readyState = 1;
        mockWebSocket.emit('open');
        emitAuthResponse();
        return openPromise.then(function () {
          var spy = _sinon.default.spy();
          transientSocket.on('close', spy);
          mockWebSocket.close = function () {
            return new _promise.default(function () {
              /* eslint no-inline-comments: [0] */
            });
          };
          mockWebSocket.removeAllListeners('close');
          var closePromise = transientSocket.close({
            code: 1000,
            reason: 'test'
          });
          jest.advanceTimersByTime(mockoptions.forceCloseDelay);
          return closePromise.then(function () {
            _testHelperChai.assert.called(spy);
            _testHelperChai.assert.calledWith(spy, {
              code: 1000,
              reason: 'test'
            });
          });
        });
      });
      it('signals closure if no close frame is received within the specified window, and uses default options as 1000 if the code is not 3050', function () {
        var transientSocket = new _socket.default();
        var openPromise = transientSocket.open('ws://example.com', mockoptions);
        mockWebSocket.readyState = 1;
        mockWebSocket.emit('open');
        emitAuthResponse();
        return openPromise.then(function () {
          var spy = _sinon.default.spy();
          transientSocket.on('close', spy);
          mockWebSocket.close = function () {
            return new _promise.default(function () {
              /* eslint no-inline-comments: [0] */
            });
          };
          mockWebSocket.removeAllListeners('close');
          var closePromise = transientSocket.close({
            code: 1000
          });
          jest.advanceTimersByTime(mockoptions.forceCloseDelay);
          return closePromise.then(function () {
            _testHelperChai.assert.called(spy);
            _testHelperChai.assert.calledWith(spy, {
              code: 1000,
              reason: 'Done (unknown)'
            });
          });
        });
      });
      [{
        description: 'manually triggers close handler when socket is still connecting',
        closeOptions: {
          code: 3001,
          reason: 'Custom close while connecting'
        },
        expectedCode: 3001,
        expectedReason: 'Custom close while connecting'
      }, {
        description: 'manually triggers close handler with default code when socket is connecting',
        closeOptions: undefined,
        expectedCode: 1000,
        expectedReason: 'Done'
      }].forEach(function (_ref2) {
        var description = _ref2.description,
          closeOptions = _ref2.closeOptions,
          expectedCode = _ref2.expectedCode,
          expectedReason = _ref2.expectedReason;
        it(description, /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee() {
          var s, socketInstance, previousStub, closeSpy, result;
          return _regenerator.default.wrap(function (_context) {
            while (1) switch (_context.prev = _context.next) {
              case 0:
                s = new _socket.default();
                // Save the current stub and replace it
                previousStub = _socket.default.getWebSocketConstructor;
                _socket.default.getWebSocketConstructor = _sinon.default.stub().callsFake(function () {
                  return function () {
                    for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
                      args[_key2] = arguments[_key2];
                    }
                    socketInstance = (0, _construct2.default)(_testHelperMockWebSocket.default, args);
                    return socketInstance;
                  };
                });

                // open the socket
                s.open('ws://example.com', mockoptions);

                // Keep socket in CONNECTING state (readyState 0)
                socketInstance.readyState = 0;
                closeSpy = _sinon.default.spy();
                s.on('close', closeSpy);

                // Call close and await the result
                _context.next = 1;
                return s.close(closeOptions);
              case 1:
                result = _context.sent;
                // Verify the promise resolved with the correct close event
                _testHelperChai.assert.equal(result.code, expectedCode);
                _testHelperChai.assert.equal(result.reason, expectedReason);

                // Verify close handler was called with expected code/reason
                _testHelperChai.assert.calledOnce(closeSpy);
                _testHelperChai.assert.calledWith(closeSpy, {
                  code: expectedCode,
                  reason: expectedReason
                });

                // Verify the underlying socket.close was called with the correct params
                _testHelperChai.assert.calledOnce(socketInstance.close);
                _testHelperChai.assert.calledWith(socketInstance.close, expectedCode, expectedReason);

                // Restore the previous stub
                _socket.default.getWebSocketConstructor = previousStub;
              case 2:
              case "end":
                return _context.stop();
            }
          }, _callee);
        })));
      });
    });
    describe('#send()', function () {
      describe('when the socket is not in the OPEN state', function () {
        it('fails', function () {
          mockWebSocket.readyState = 0;
          return _testHelperChai.assert.isRejected(socket.send('test0'), /INVALID_STATE_ERROR/).then(function () {
            mockWebSocket.readyState = 2;
            return _testHelperChai.assert.isRejected(socket.send('test2'), /INVALID_STATE_ERROR/);
          }).then(function () {
            mockWebSocket.readyState = 3;
            return _testHelperChai.assert.isRejected(socket.send('test3'), /INVALID_STATE_ERROR/);
          }).then(function () {
            mockWebSocket.readyState = 1;
            return socket.send('test1');
          });
        });
      });
      it('sends strings', function () {
        socket.send('this is a string');
        _testHelperChai.assert.calledWith(mockWebSocket.send, 'this is a string');
      });
      it('sends JSON.stringifyable object', function () {
        socket.send({
          json: true
        });
        _testHelperChai.assert.calledWith(mockWebSocket.send, '{"json":true}');
      });
    });
    describe('#onclose()', function () {
      describe('when it receives close code 1005', function () {
        (0, _forEach2.default)({
          Replaced: 4000,
          'Authentication Failed': 1008,
          'Authentication did not happen within the timeout window of 30000 seconds.': 1008
        }, function (code, reason) {
          it("emits code ".concat(code, " for reason ").concat(reason), function () {
            var spy = _sinon.default.spy();
            socket.on('close', spy);
            mockWebSocket.emit('close', {
              code: 1005,
              reason: reason
            });
            _testHelperChai.assert.called(spy);
            _testHelperChai.assert.calledWith(spy, {
              code: code,
              reason: reason
            });
          });
        });
      });
      describe('when it receives close code 3050', function () {
        it('emits code 3050 for code 3050', function () {
          var code = 3050;
          var reason = 'done (permanent)';
          var spy = _sinon.default.spy();
          socket.on('close', spy);
          mockWebSocket.emit('close', {
            code: code,
            reason: reason
          });
          _testHelperChai.assert.called(spy);
          _testHelperChai.assert.calledWith(spy, {
            code: code,
            reason: reason
          });
        });
      });
    });
    describe('#onmessage()', function () {
      var spy;
      beforeEach(function () {
        spy = _sinon.default.spy();
        socket.on('message', spy);
      });
      it('emits messages from the underlying socket', function () {
        mockWebSocket.emit('message', {
          data: (0, _stringify.default)({
            id: 'mockid'
          })
        });
        _testHelperChai.assert.called(spy);
      });
      it('parses received messages', function () {
        mockWebSocket.emit('message', {
          data: (0, _stringify.default)({
            id: 'mockid',
            type: 'test'
          })
        });
        _testHelperChai.assert.calledWith(spy, {
          data: {
            id: 'mockid',
            type: 'test'
          }
        });
      });
      it('preserves top-level type and eventId for async_event envelopes', function () {
        mockWebSocket.emit('message', {
          data: (0, _stringify.default)({
            type: 'async_event',
            trackingId: 'SRV_bb000000-0000-0000-0000-000000000006',
            eventId: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
            data: {
              eventType: 'mobius.callinfo',
              callId: 'fcf86aa5-5539-4c9f-8b72-667786ae9b6c',
              deviceId: '334f3d50-1d26-4712-93f1-4972390cc565'
            }
          })
        });
        _testHelperChai.assert.calledWith(spy, {
          data: {
            type: 'async_event',
            trackingId: 'SRV_bb000000-0000-0000-0000-000000000006',
            eventId: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
            data: {
              eventType: 'mobius.callinfo',
              callId: 'fcf86aa5-5539-4c9f-8b72-667786ae9b6c',
              deviceId: '334f3d50-1d26-4712-93f1-4972390cc565'
            }
          }
        });
      });
      it('acknowledges async_event messages only', function () {
        _sinon.default.spy(socket, 'acknowledge');
        mockWebSocket.emit('message', {
          data: (0, _stringify.default)({
            type: 'async_event',
            eventId: 'event-123',
            trackingId: 'tracking-123'
          })
        });
        _testHelperChai.assert.called(socket.acknowledge);
      });
      it('does not acknowledge non-async_event messages', function () {
        _sinon.default.spy(socket, 'acknowledge');
        mockWebSocket.emit('message', {
          data: (0, _stringify.default)({
            type: 'regular',
            id: 'mockid'
          })
        });
        _testHelperChai.assert.notCalled(socket.acknowledge);
      });
    });
    describe('#acknowledge', function () {
      it('requires an event', function () {
        return _testHelperChai.assert.isRejected(socket.acknowledge(), /`event` is required/);
      });
      it('acknowledges async events using event_ack and eventId', function () {
        return socket.acknowledge({
          data: {
            eventId: 'event-123',
            trackingId: 'tracking-123'
          }
        }).then(function () {
          _testHelperChai.assert.calledWith(mockWebSocket.send, (0, _stringify.default)({
            type: _constants.MESSAGE_TYPES.EVENT_ACK,
            trackingId: 'tracking-123',
            eventId: 'event-123'
          }));
        });
      });
    });
  });
});
//# sourceMappingURL=socket.test.js.map
