]> git.proxmox.com Git - mirror_novnc.git/blobdiff - tests/test.rfb.js
Peter is no longer part of the noVNC team
[mirror_novnc.git] / tests / test.rfb.js
index cb72f4c970dc80af7bebcf52a107642546fbcc44..17320e46921a26b7eb7268cf5fb09c6cb10020be 100644 (file)
@@ -5,13 +5,12 @@ import Websock from '../core/websock.js';
 import { encodings } from '../core/encodings.js';
 
 import FakeWebSocket from './fake.websocket.js';
-import sinon from '../vendor/sinon.js';
 
 /* UIEvent constructor polyfill for IE */
-(function () {
+(() => {
     if (typeof window.UIEvent === "function") return;
 
-    function UIEvent ( event, params ) {
+    function UIEvent( event, params ) {
         params = params || { bubbles: false, cancelable: false, view: window, detail: undefined };
         const evt = document.createEvent( 'UIEvent' );
         evt.initUIEvent( event, params.bubbles, params.cancelable, params.view, params.detail );
@@ -23,26 +22,33 @@ import sinon from '../vendor/sinon.js';
     window.UIEvent = UIEvent;
 })();
 
-const push8 = function (arr, num) {
+function push8(arr, num) {
     "use strict";
     arr.push(num & 0xFF);
-};
+}
 
-const push16 = function (arr, num) {
+function push16(arr, num) {
     "use strict";
     arr.push((num >> 8) & 0xFF,
-              num & 0xFF);
-};
+             num & 0xFF);
+}
 
-const push32 = function (arr, num) {
+function push32(arr, num) {
     "use strict";
     arr.push((num >> 24) & 0xFF,
-              (num >> 16) & 0xFF,
-              (num >>  8) & 0xFF,
-              num & 0xFF);
-};
+             (num >> 16) & 0xFF,
+             (num >>  8) & 0xFF,
+             num & 0xFF);
+}
+
+function pushString(arr, string) {
+    let utf8 = unescape(encodeURIComponent(string));
+    for (let i = 0; i < utf8.length; i++) {
+        arr.push(utf8.charCodeAt(i));
+    }
+}
 
-describe('Remote Frame Buffer Protocol Client', function() {
+describe('Remote Frame Buffer Protocol Client', function () {
     let clock;
     let raf;
 
@@ -100,7 +106,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
         container = null;
     });
 
-    function make_rfb (url, options) {
+    function make_rfb(url, options) {
         url = url || 'wss://host:8675';
         const rfb = new RFB(container, url, options);
         clock.tick();
@@ -272,7 +278,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
             it('should move focus to canvas object', function () {
                 client._canvas.focus = sinon.spy();
                 client.focus();
-                expect(client._canvas.focus).to.have.been.called.once;
+                expect(client._canvas.focus).to.have.been.calledOnce;
             });
         });
 
@@ -280,14 +286,14 @@ describe('Remote Frame Buffer Protocol Client', function() {
             it('should remove focus from canvas object', function () {
                 client._canvas.blur = sinon.spy();
                 client.blur();
-                expect(client._canvas.blur).to.have.been.called.once;
+                expect(client._canvas.blur).to.have.been.calledOnce;
             });
         });
 
         describe('#clipboardPasteFrom', function () {
             it('should send the given text in a paste event', function () {
                 const expected = {_sQ: new Uint8Array(11), _sQlen: 0,
-                                _sQbufferSize: 11, flush: () => {}};
+                                  _sQbufferSize: 11, flush: () => {}};
                 RFB.messages.clientCutText(expected, 'abc');
                 client.clipboardPasteFrom('abc');
                 expect(client._sock).to.have.sent(expected._sQ);
@@ -354,7 +360,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
             client.clipViewport = false;
             expect(spy.set).to.have.been.calledOnce;
             expect(spy.set).to.have.been.calledWith(false);
-            spy.set.reset();
+            spy.set.resetHistory();
 
             client.clipViewport = true;
             expect(spy.set).to.have.been.calledOnce;
@@ -377,10 +383,10 @@ describe('Remote Frame Buffer Protocol Client', function() {
         it('should update the viewport when the remote session resizes', function () {
             // Simple ExtendedDesktopSize FBU message
             const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-                             0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xcc,
-                             0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                             0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
-                             0x00, 0x00, 0x00, 0x00 ];
+                               0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xcc,
+                               0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
+                               0x00, 0x00, 0x00, 0x00 ];
 
             sinon.spy(client._display, "viewportChangeSize");
 
@@ -439,7 +445,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 client._handleMouseButton(13, 9, 0x000);
                 expect(RFB.messages.pointerEvent).to.have.been.calledTwice;
 
-                RFB.messages.pointerEvent.reset();
+                RFB.messages.pointerEvent.resetHistory();
 
                 // Small movement
                 client._handleMouseButton(13, 9, 0x001);
@@ -473,7 +479,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 expect(client._display.viewportChangePos).to.have.been.calledOnce;
                 expect(client._display.viewportChangePos).to.have.been.calledWith(-30, 0);
 
-                client._display.viewportChangePos.reset();
+                client._display.viewportChangePos.resetHistory();
 
                 // Now a small movement should move right away
 
@@ -544,7 +550,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
             expect(spy.set).to.have.been.calledOnce;
             expect(spy.set).to.have.been.calledWith(true);
 
-            spy.set.reset();
+            spy.set.resetHistory();
 
             client.scaleViewport = true;
             expect(spy.set).to.have.been.calledOnce;
@@ -567,10 +573,10 @@ describe('Remote Frame Buffer Protocol Client', function() {
         it('should update the scaling when the remote session resizes', function () {
             // Simple ExtendedDesktopSize FBU message
             const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-                             0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xcc,
-                             0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                             0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
-                             0x00, 0x00, 0x00, 0x00 ];
+                               0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xcc,
+                               0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
+                               0x00, 0x00, 0x00, 0x00 ];
 
             sinon.spy(client._display, "autoscale");
 
@@ -620,10 +626,10 @@ describe('Remote Frame Buffer Protocol Client', function() {
         it('should request a resize when initially connecting', function () {
             // Simple ExtendedDesktopSize FBU message
             const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-                             0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xcc,
-                             0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                             0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04,
-                             0x00, 0x00, 0x00, 0x00 ];
+                               0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xcc,
+                               0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04,
+                               0x00, 0x00, 0x00, 0x00 ];
 
             // First message should trigger a resize
 
@@ -634,7 +640,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
             expect(RFB.messages.setDesktopSize).to.have.been.calledOnce;
             expect(RFB.messages.setDesktopSize).to.have.been.calledWith(sinon.match.object, 70, 80, 0, 0);
 
-            RFB.messages.setDesktopSize.reset();
+            RFB.messages.setDesktopSize.resetHistory();
 
             // Second message should not trigger a resize
 
@@ -716,10 +722,10 @@ describe('Remote Frame Buffer Protocol Client', function() {
         it('should not try to override a server resize', function () {
             // Simple ExtendedDesktopSize FBU message
             const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-                             0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xcc,
-                             0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                             0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04,
-                             0x00, 0x00, 0x00, 0x00 ];
+                               0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xcc,
+                               0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04,
+                               0x00, 0x00, 0x00, 0x00 ];
 
             client._sock._websocket._receive_data(new Uint8Array(incoming));
 
@@ -828,7 +834,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
         describe('connecting', function () {
             it('should open the websocket connection', function () {
                 const client = new RFB(document.createElement('div'),
-                                     'ws://HOST:8675/PATH');
+                                       'ws://HOST:8675/PATH');
                 sinon.spy(client._sock, 'open');
                 this.clock.tick();
                 expect(client._sock.open).to.have.been.calledOnce;
@@ -852,7 +858,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
             it('should not result in a connect event if the state is not "connected"', function () {
                 const spy = sinon.spy();
                 client.addEventListener("connect", spy);
-                client._sock._websocket.open = function () {};  // explicitly don't call onopen
+                client._sock._websocket.open = () => {};  // explicitly don't call onopen
                 client._updateConnectionState('connecting');
                 expect(spy).to.not.have.been.called;
             });
@@ -866,7 +872,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
 
             it('should force disconnect if we do not call Websock.onclose within the disconnection timeout', function () {
                 sinon.spy(client, '_updateConnectionState');
-                client._sock._websocket.close = function () {};  // explicitly don't call onclose
+                client._sock._websocket.close = () => {};  // explicitly don't call onclose
                 client._updateConnectionState('disconnecting');
                 this.clock.tick(3 * 1000);
                 expect(client._updateConnectionState).to.have.been.calledTwice;
@@ -891,7 +897,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
             it('should not result in a disconnect event', function () {
                 const spy = sinon.spy();
                 client.addEventListener("disconnect", spy);
-                client._sock._websocket.close = function () {};  // explicitly don't call onclose
+                client._sock._websocket.close = () => {};  // explicitly don't call onclose
                 client._updateConnectionState('disconnecting');
                 expect(spy).to.not.have.been.called;
             });
@@ -932,7 +938,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
         });
 
         describe('ProtocolVersion', function () {
-            function send_ver (ver, client) {
+            function send_ver(ver, client) {
                 const arr = new Uint8Array(12);
                 for (let i = 0; i < ver.length; i++) {
                     arr[i+4] = ver.charCodeAt(i);
@@ -1040,14 +1046,14 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 const auth_scheme_raw = [1, 2, 3, 4];
                 const auth_scheme = (auth_scheme_raw[0] << 24) + (auth_scheme_raw[1] << 16) +
                                   (auth_scheme_raw[2] << 8) + auth_scheme_raw[3];
-                client._sock._websocket._receive_data(auth_scheme_raw);
+                client._sock._websocket._receive_data(new Uint8Array(auth_scheme_raw));
                 expect(client._rfb_auth_scheme).to.equal(auth_scheme);
             });
 
             it('should prefer no authentication is possible', function () {
                 client._rfb_version = 3.7;
                 const auth_schemes = [2, 1, 3];
-                client._sock._websocket._receive_data(auth_schemes);
+                client._sock._websocket._receive_data(new Uint8Array(auth_schemes));
                 expect(client._rfb_auth_scheme).to.equal(1);
                 expect(client._sock).to.have.sent(new Uint8Array([1, 1]));
             });
@@ -1055,7 +1061,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
             it('should choose for the most prefered scheme possible for versions >= 3.7', function () {
                 client._rfb_version = 3.7;
                 const auth_schemes = [2, 22, 16];
-                client._sock._websocket._receive_data(auth_schemes);
+                client._sock._websocket._receive_data(new Uint8Array(auth_schemes));
                 expect(client._rfb_auth_scheme).to.equal(22);
                 expect(client._sock).to.have.sent(new Uint8Array([22]));
             });
@@ -1064,7 +1070,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 sinon.spy(client, "_fail");
                 client._rfb_version = 3.7;
                 const auth_schemes = [1, 32];
-                client._sock._websocket._receive_data(auth_schemes);
+                client._sock._websocket._receive_data(new Uint8Array(auth_schemes));
                 expect(client._fail).to.have.been.calledOnce;
             });
 
@@ -1072,7 +1078,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 client._rfb_version = 3.7;
                 const failure_data = [0, 0, 0, 0, 6, 119, 104, 111, 111, 112, 115];
                 sinon.spy(client, '_fail');
-                client._sock._websocket._receive_data(failure_data);
+                client._sock._websocket._receive_data(new Uint8Array(failure_data));
 
                 expect(client._fail).to.have.been.calledOnce;
                 expect(client._fail).to.have.been.calledWith(
@@ -1083,7 +1089,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 client._rfb_version = 3.7;
                 const auth_schemes = [1, 1];
                 client._negotiate_authentication = sinon.spy();
-                client._sock._websocket._receive_data(auth_schemes);
+                client._sock._websocket._receive_data(new Uint8Array(auth_schemes));
                 expect(client._rfb_init_state).to.equal('Authentication');
                 expect(client._negotiate_authentication).to.have.been.calledOnce;
             });
@@ -1193,7 +1199,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                     expect(client._negotiate_std_vnc_auth).to.have.been.calledOnce;
                 });
 
-                it('should fire the credentialsrequired event if all credentials are missing', function() {
+                it('should fire the credentialsrequired event if all credentials are missing', function () {
                     const spy = sinon.spy();
                     client.addEventListener("credentialsrequired", spy);
                     client._rfb_credentials = {};
@@ -1204,7 +1210,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                     expect(spy.args[0][0].detail.types).to.have.members(["username", "password", "target"]);
                 });
 
-                it('should fire the credentialsrequired event if some credentials are missing', function() {
+                it('should fire the credentialsrequired event if some credentials are missing', function () {
                     const spy = sinon.spy();
                     client.addEventListener("credentialsrequired", spy);
                     client._rfb_credentials = { username: 'user',
@@ -1239,11 +1245,10 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 });
 
                 function send_num_str_pairs(pairs, client) {
-                    const pairs_len = pairs.length;
                     const data = [];
-                    push32(data, pairs_len);
+                    push32(data, pairs.length);
 
-                    for (let i = 0; i < pairs_len; i++) {
+                    for (let i = 0; i < pairs.length; i++) {
                         push32(data, pairs[i][0]);
                         for (let j = 0; j < 4; j++) {
                             data.push(pairs[i][1].charCodeAt(j));
@@ -1359,7 +1364,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 const spy = sinon.spy();
                 client.addEventListener("securityfailure", spy);
                 const failure_data = [0, 0, 0, 1, 0, 0, 0, 12, 115, 117, 99, 104,
-                                    32, 102, 97, 105, 108, 117, 114, 101];
+                                      32, 102, 97, 105, 108, 117, 114, 101];
                 client._sock._websocket._receive_data(new Uint8Array(failure_data));
                 expect(spy.args[0][0].detail.status).to.equal(1);
                 expect(spy.args[0][0].detail.reason).to.equal('such failure');
@@ -1418,8 +1423,8 @@ describe('Remote Frame Buffer Protocol Client', function() {
 
             function send_server_init(opts, client) {
                 const full_opts = { width: 10, height: 12, bpp: 24, depth: 24, big_endian: 0,
-                                  true_color: 1, red_max: 255, green_max: 255, blue_max: 255,
-                                  red_shift: 16, green_shift: 8, blue_shift: 0, name: 'a name' };
+                                    true_color: 1, red_max: 255, green_max: 255, blue_max: 255,
+                                    red_shift: 16, green_shift: 8, blue_shift: 0, name: 'a name' };
                 for (let opt in opts) {
                     full_opts[opt] = opts[opt];
                 }
@@ -1448,10 +1453,11 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 client._sock._websocket._receive_data(new Uint8Array(data));
 
                 const name_data = [];
-                push32(name_data, full_opts.name.length);
-                for (let i = 0; i < full_opts.name.length; i++) {
-                    name_data.push(full_opts.name.charCodeAt(i));
-                }
+                let name_len = [];
+                pushString(name_data, full_opts.name);
+                push32(name_len, name_data.length);
+
+                client._sock._websocket._receive_data(new Uint8Array(name_len));
                 client._sock._websocket._receive_data(new Uint8Array(name_data));
             }
 
@@ -1466,11 +1472,11 @@ describe('Remote Frame Buffer Protocol Client', function() {
             it('should set the framebuffer name and call the callback', function () {
                 const spy = sinon.spy();
                 client.addEventListener("desktopname", spy);
-                send_server_init({ name: 'some name' }, client);
+                send_server_init({ name: 'som€ nam€' }, client);
 
-                expect(client._fb_name).to.equal('some name');
+                expect(client._fb_name).to.equal('som€ nam€');
                 expect(spy).to.have.been.calledOnce;
-                expect(spy.args[0][0].detail.name).to.equal('some name');
+                expect(spy.args[0][0].detail.name).to.equal('som€ nam€');
             });
 
             it('should handle the extended init message of the tight encoding', function () {
@@ -1487,7 +1493,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 for (let i = 0; i < 16 + 32 + 48; i++) {
                     tight_data.push(i);
                 }
-                client._sock._websocket._receive_data(tight_data);
+                client._sock._websocket._receive_data(new Uint8Array(tight_data));
 
                 expect(client._rfb_connection_state).to.equal('connected');
             });
@@ -1590,7 +1596,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 target_data_check = new Uint8Array(target_data_check_arr);
             });
 
-            function send_fbu_msg (rect_info, rect_data, client, rect_cnt) {
+            function send_fbu_msg(rect_info, rect_data, client, rect_cnt) {
                 let data = [];
 
                 if (!rect_cnt || rect_cnt > -1) {
@@ -1618,7 +1624,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 const expected_msg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: () => {}};
                 RFB.messages.fbUpdateRequest(expected_msg, true, 0, 0, 640, 20);
 
-                client._framebufferUpdate = function () { return true; };
+                client._framebufferUpdate = () => true;
                 client._sock._websocket._receive_data(new Uint8Array([0]));
 
                 expect(client._sock).to.have.sent(expected_msg._sQ);
@@ -1637,7 +1643,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 3]));
                 expect(client._sock._websocket._get_sent_data()).to.have.length(0);
 
-                client._framebufferUpdate = function () { this._sock.rQskip8(); return true; };  // we magically have enough data
+                client._framebufferUpdate = function () { this._sock.rQskipBytes(1); return true; };  // we magically have enough data
                 // 247 should *not* be used as the message type here
                 client._sock._websocket._receive_data(new Uint8Array([247]));
                 expect(client._sock).to.have.sent(expected_msg._sQ);
@@ -1645,7 +1651,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
 
             it('should not send a request in continuous updates mode', function () {
                 client._enabledContinuousUpdates = true;
-                client._framebufferUpdate = function () { return true; };
+                client._framebufferUpdate = () => true;
                 client._sock._websocket._receive_data(new Uint8Array([0]));
 
                 expect(client._sock._websocket._get_sent_data()).to.have.length(0);
@@ -1666,7 +1672,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 client._display.blitRgbxImage(0, 0, 4, 2, new Uint8Array(target_data_check_arr.slice(0, 32)), 0);
 
                 const info = [{ x: 0, y: 2, width: 2, height: 2, encoding: 0x01},
-                            { x: 2, y: 2, width: 2, height: 2, encoding: 0x01}];
+                              { x: 2, y: 2, width: 2, height: 2, encoding: 0x01}];
                 // data says [{ old_x: 2, old_y: 0 }, { old_x: 0, old_y: 0 }]
                 const rects = [[0, 2, 0, 0], [0, 0, 0, 0]];
                 send_fbu_msg([info[0]], [rects[0]], client, 2);
@@ -1685,9 +1691,9 @@ describe('Remote Frame Buffer Protocol Client', function() {
 
                 it('should handle the RAW encoding', function () {
                     const info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
-                                { x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
-                                { x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
-                                { x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
+                                  { x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
+                                  { x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
+                                  { x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
                     // data is in bgrx
                     const rects = [
                         [0x00, 0x00, 0xff, 0, 0x00, 0xff, 0x00, 0, 0x00, 0xff, 0x00, 0, 0x00, 0x00, 0xff, 0],
@@ -1700,9 +1706,9 @@ describe('Remote Frame Buffer Protocol Client', function() {
 
                 it('should handle the RAW encoding in low colour mode', function () {
                     const info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
-                                { x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
-                                { x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
-                                { x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
+                                  { x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
+                                  { x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
+                                  { x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
                     const rects = [
                         [0x03, 0x03, 0x03, 0x03],
                         [0x0c, 0x0c, 0x0c, 0x0c],
@@ -1718,7 +1724,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                     client._display.blitRgbxImage(0, 0, 4, 2, new Uint8Array(target_data_check_arr.slice(0, 32)), 0);
 
                     const info = [{ x: 0, y: 2, width: 2, height: 2, encoding: 0x01},
-                                { x: 2, y: 2, width: 2, height: 2, encoding: 0x01}];
+                                  { x: 2, y: 2, width: 2, height: 2, encoding: 0x01}];
                     // data says [{ old_x: 0, old_y: 0 }, { old_x: 0, old_y: 0 }]
                     const rects = [[0, 2, 0, 0], [0, 0, 0, 0]];
                     send_fbu_msg(info, rects, client);
@@ -1878,7 +1884,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                     });
 
                     it('should fail on an invalid subencoding', function () {
-                        sinon.spy(client,"_fail");
+                        sinon.spy(client, "_fail");
                         const info = [{ x: 0, y: 0, width: 4, height: 4, encoding: 0x05 }];
                         const rects = [[45]];  // an invalid subencoding
                         send_fbu_msg(info, rects, client);
@@ -1914,7 +1920,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                         sinon.spy(client._display, 'resize');
                     });
 
-                    function make_screen_data (nr_of_screens) {
+                    function make_screen_data(nr_of_screens) {
                         const data = [];
                         push8(data, nr_of_screens);   // number-of-screens
                         push8(data, 0);               // padding
@@ -1990,14 +1996,325 @@ describe('Remote Frame Buffer Protocol Client', function() {
                     });
                 });
 
-                it.skip('should handle the Cursor pseudo-encoding', function () {
-                    // TODO(directxman12): test
+                describe('the Cursor pseudo-encoding handler', function () {
+                    beforeEach(function () {
+                        sinon.spy(client._cursor, 'change');
+                    });
+
+                    it('should handle a standard cursor', function () {
+                        const info = { x: 5, y: 7,
+                                       width: 4, height: 4,
+                                       encoding: -239};
+                        let rect = [];
+                        let expected = [];
+
+                        for (let i = 0;i < info.width*info.height;i++) {
+                            push32(rect, 0x11223300);
+                        }
+                        push32(rect, 0xa0a0a0a0);
+
+                        for (let i = 0;i < info.width*info.height/2;i++) {
+                            push32(expected, 0x332211ff);
+                            push32(expected, 0x33221100);
+                        }
+                        expected = new Uint8Array(expected);
+
+                        send_fbu_msg([info], [rect], client);
+
+                        expect(client._cursor.change).to.have.been.calledOnce;
+                        expect(client._cursor.change).to.have.been.calledWith(expected, 5, 7, 4, 4);
+                    });
+
+                    it('should handle an empty cursor', function () {
+                        const info = { x: 0, y: 0,
+                                       width: 0, height: 0,
+                                       encoding: -239};
+                        const rect = [];
+
+                        send_fbu_msg([info], [rect], client);
+
+                        expect(client._cursor.change).to.have.been.calledOnce;
+                        expect(client._cursor.change).to.have.been.calledWith(new Uint8Array, 0, 0, 0, 0);
+                    });
+
+                    it('should handle a transparent cursor', function () {
+                        const info = { x: 5, y: 7,
+                                       width: 4, height: 4,
+                                       encoding: -239};
+                        let rect = [];
+                        let expected = [];
+
+                        for (let i = 0;i < info.width*info.height;i++) {
+                            push32(rect, 0x11223300);
+                        }
+                        push32(rect, 0x00000000);
+
+                        for (let i = 0;i < info.width*info.height;i++) {
+                            push32(expected, 0x33221100);
+                        }
+                        expected = new Uint8Array(expected);
+
+                        send_fbu_msg([info], [rect], client);
+
+                        expect(client._cursor.change).to.have.been.calledOnce;
+                        expect(client._cursor.change).to.have.been.calledWith(expected, 5, 7, 4, 4);
+                    });
+
+                    describe('dot for empty cursor', function () {
+                        beforeEach(function () {
+                            client.showDotCursor = true;
+                            // Was called when we enabled dot cursor
+                            client._cursor.change.resetHistory();
+                        });
+
+                        it('should show a standard cursor', function () {
+                            const info = { x: 5, y: 7,
+                                           width: 4, height: 4,
+                                           encoding: -239};
+                            let rect = [];
+                            let expected = [];
+
+                            for (let i = 0;i < info.width*info.height;i++) {
+                                push32(rect, 0x11223300);
+                            }
+                            push32(rect, 0xa0a0a0a0);
+
+                            for (let i = 0;i < info.width*info.height/2;i++) {
+                                push32(expected, 0x332211ff);
+                                push32(expected, 0x33221100);
+                            }
+                            expected = new Uint8Array(expected);
+
+                            send_fbu_msg([info], [rect], client);
+
+                            expect(client._cursor.change).to.have.been.calledOnce;
+                            expect(client._cursor.change).to.have.been.calledWith(expected, 5, 7, 4, 4);
+                        });
+
+                        it('should handle an empty cursor', function () {
+                            const info = { x: 0, y: 0,
+                                           width: 0, height: 0,
+                                           encoding: -239};
+                            const rect = [];
+                            const dot = RFB.cursors.dot;
+
+                            send_fbu_msg([info], [rect], client);
+
+                            expect(client._cursor.change).to.have.been.calledOnce;
+                            expect(client._cursor.change).to.have.been.calledWith(dot.rgbaPixels,
+                                                                                  dot.hotx,
+                                                                                  dot.hoty,
+                                                                                  dot.w,
+                                                                                  dot.h);
+                        });
+
+                        it('should handle a transparent cursor', function () {
+                            const info = { x: 5, y: 7,
+                                           width: 4, height: 4,
+                                           encoding: -239};
+                            let rect = [];
+                            const dot = RFB.cursors.dot;
+
+                            for (let i = 0;i < info.width*info.height;i++) {
+                                push32(rect, 0x11223300);
+                            }
+                            push32(rect, 0x00000000);
+
+                            send_fbu_msg([info], [rect], client);
+
+                            expect(client._cursor.change).to.have.been.calledOnce;
+                            expect(client._cursor.change).to.have.been.calledWith(dot.rgbaPixels,
+                                                                                  dot.hotx,
+                                                                                  dot.hoty,
+                                                                                  dot.w,
+                                                                                  dot.h);
+                        });
+                    });
+                });
+
+                describe('the VMware Cursor pseudo-encoding handler', function () {
+                    beforeEach(function () {
+                        sinon.spy(client._cursor, 'change');
+                    });
+                    afterEach(function () {
+                        client._cursor.change.resetHistory();
+                    });
+
+                    it('should handle the VMware cursor pseudo-encoding', function () {
+                        let data = [0x00, 0x00, 0xff, 0,
+                                    0x00, 0xff, 0x00, 0,
+                                    0x00, 0xff, 0x00, 0,
+                                    0x00, 0x00, 0xff, 0];
+                        let rect = [];
+                        push8(rect, 0);
+                        push8(rect, 0);
+
+                        //AND-mask
+                        for (let i = 0; i < data.length; i++) {
+                            push8(rect, data[i]);
+                        }
+                        //XOR-mask
+                        for (let i = 0; i < data.length; i++) {
+                            push8(rect, data[i]);
+                        }
+
+                        send_fbu_msg([{ x: 0, y: 0, width: 2, height: 2,
+                                        encoding: 0x574d5664}],
+                                     [rect], client);
+                        expect(client._FBU.rects).to.equal(0);
+                    });
+
+                    it('should handle insufficient cursor pixel data', function () {
+
+                        // Specified 14x23 pixels for the cursor,
+                        // but only send 2x2 pixels worth of data
+                        let w = 14;
+                        let h = 23;
+                        let data = [0x00, 0x00, 0xff, 0,
+                                    0x00, 0xff, 0x00, 0];
+                        let rect = [];
+
+                        push8(rect, 0);
+                        push8(rect, 0);
+
+                        //AND-mask
+                        for (let i = 0; i < data.length; i++) {
+                            push8(rect, data[i]);
+                        }
+                        //XOR-mask
+                        for (let i = 0; i < data.length; i++) {
+                            push8(rect, data[i]);
+                        }
+
+                        send_fbu_msg([{ x: 0, y: 0, width: w, height: h,
+                                        encoding: 0x574d5664}],
+                                     [rect], client);
+
+                        // expect one FBU to remain unhandled
+                        expect(client._FBU.rects).to.equal(1);
+                    });
+
+                    it('should update the cursor when type is classic', function () {
+                        let and_mask =
+                            [0xff, 0xff, 0xff, 0xff,  //Transparent
+                             0xff, 0xff, 0xff, 0xff,  //Transparent
+                             0x00, 0x00, 0x00, 0x00,  //Opaque
+                             0xff, 0xff, 0xff, 0xff]; //Inverted
+
+                        let xor_mask =
+                            [0x00, 0x00, 0x00, 0x00,  //Transparent
+                             0x00, 0x00, 0x00, 0x00,  //Transparent
+                             0x11, 0x22, 0x33, 0x44,  //Opaque
+                             0xff, 0xff, 0xff, 0x44]; //Inverted
+
+                        let rect = [];
+                        push8(rect, 0); //cursor_type
+                        push8(rect, 0); //padding
+                        let hotx = 0;
+                        let hoty = 0;
+                        let w = 2;
+                        let h = 2;
+
+                        //AND-mask
+                        for (let i = 0; i < and_mask.length; i++) {
+                            push8(rect, and_mask[i]);
+                        }
+                        //XOR-mask
+                        for (let i = 0; i < xor_mask.length; i++) {
+                            push8(rect, xor_mask[i]);
+                        }
+
+                        let expected_rgba = [0x00, 0x00, 0x00, 0x00,
+                                             0x00, 0x00, 0x00, 0x00,
+                                             0x33, 0x22, 0x11, 0xff,
+                                             0x00, 0x00, 0x00, 0xff];
+
+                        send_fbu_msg([{ x: hotx, y: hoty,
+                                        width: w, height: h,
+                                        encoding: 0x574d5664}],
+                                     [rect], client);
+
+                        expect(client._cursor.change)
+                            .to.have.been.calledOnce;
+                        expect(client._cursor.change)
+                            .to.have.been.calledWith(expected_rgba,
+                                                     hotx, hoty,
+                                                     w, h);
+                    });
+
+                    it('should update the cursor when type is alpha', function () {
+                        let data = [0xee, 0x55, 0xff, 0x00, // bgra
+                                    0x00, 0xff, 0x00, 0xff,
+                                    0x00, 0xff, 0x00, 0x22,
+                                    0x00, 0xff, 0x00, 0x22,
+                                    0x00, 0xff, 0x00, 0x22,
+                                    0x00, 0x00, 0xff, 0xee];
+                        let rect = [];
+                        push8(rect, 1); //cursor_type
+                        push8(rect, 0); //padding
+                        let hotx = 0;
+                        let hoty = 0;
+                        let w = 3;
+                        let h = 2;
+
+                        for (let i = 0; i < data.length; i++) {
+                            push8(rect, data[i]);
+                        }
+
+                        let expected_rgba = [0xff, 0x55, 0xee, 0x00,
+                                             0x00, 0xff, 0x00, 0xff,
+                                             0x00, 0xff, 0x00, 0x22,
+                                             0x00, 0xff, 0x00, 0x22,
+                                             0x00, 0xff, 0x00, 0x22,
+                                             0xff, 0x00, 0x00, 0xee];
+
+                        send_fbu_msg([{ x: hotx, y: hoty,
+                                        width: w, height: h,
+                                        encoding: 0x574d5664}],
+                                     [rect], client);
+
+                        expect(client._cursor.change)
+                            .to.have.been.calledOnce;
+                        expect(client._cursor.change)
+                            .to.have.been.calledWith(expected_rgba,
+                                                     hotx, hoty,
+                                                     w, h);
+                    });
+
+                    it('should not update cursor when incorrect cursor type given', function () {
+                        let rect = [];
+                        push8(rect, 3); // invalid cursor type
+                        push8(rect, 0); // padding
+
+                        client._cursor.change.resetHistory();
+                        send_fbu_msg([{ x: 0, y: 0, width: 2, height: 2,
+                                        encoding: 0x574d5664}],
+                                     [rect], client);
+
+                        expect(client._cursor.change)
+                            .to.not.have.been.called;
+                    });
                 });
 
                 it('should handle the last_rect pseudo-encoding', function () {
                     send_fbu_msg([{ x: 0, y: 0, width: 0, height: 0, encoding: -224}], [[]], client, 100);
                     expect(client._FBU.rects).to.equal(0);
                 });
+
+                it('should handle the DesktopName pseudo-encoding', function () {
+                    let data = [];
+                    push32(data, 13);
+                    pushString(data, "som€ nam€");
+
+                    const spy = sinon.spy();
+                    client.addEventListener("desktopname", spy);
+
+                    send_fbu_msg([{ x: 0, y: 0, width: 0, height: 0, encoding: -307 }], [data], client);
+
+                    expect(client._fb_name).to.equal('som€ nam€');
+                    expect(spy).to.have.been.calledOnce;
+                    expect(spy.args[0][0].detail.name).to.equal('som€ nam€');
+                });
             });
         });
 
@@ -2186,7 +2503,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
 
         describe('WebSocket event handlers', function () {
             // message events
-            it ('should do nothing if we receive an empty message and have nothing in the queue', function () {
+            it('should do nothing if we receive an empty message and have nothing in the queue', function () {
                 client._normal_msg = sinon.spy();
                 client._sock._websocket._receive_data(new Uint8Array([]));
                 expect(client._normal_msg).to.not.have.been.called;
@@ -2195,7 +2512,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
             it('should handle a message in the connected state as a normal message', function () {
                 client._normal_msg = sinon.spy();
                 client._sock._websocket._receive_data(new Uint8Array([1, 2, 3]));
-                expect(client._normal_msg).to.have.been.calledOnce;
+                expect(client._normal_msg).to.have.been.called;
             });
 
             it('should handle a message in any non-disconnected/failed state like an init message', function () {
@@ -2203,7 +2520,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
                 client._rfb_init_state = 'ProtocolVersion';
                 client._init_msg = sinon.spy();
                 client._sock._websocket._receive_data(new Uint8Array([1, 2, 3]));
-                expect(client._init_msg).to.have.been.calledOnce;
+                expect(client._init_msg).to.have.been.called;
             });
 
             it('should process all normal messages directly', function () {
@@ -2231,7 +2548,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
             // close events
             it('should transition to "disconnected" from "disconnecting" on a close event', function () {
                 const real = client._sock._websocket.close;
-                client._sock._websocket.close = function () {};
+                client._sock._websocket.close = () => {};
                 client.disconnect();
                 expect(client._rfb_connection_state).to.equal('disconnecting');
                 client._sock._websocket.close = real;