]> git.proxmox.com Git - mirror_novnc.git/blame - tests/test.mouse.js
Use fat arrow functions `const foo = () => { ... };` for callbacks
[mirror_novnc.git] / tests / test.mouse.js
CommitLineData
2b5f94fa 1const expect = chai.expect;
c509e6d9 2
0aaf59c2
SM
3import sinon from '../vendor/sinon.js';
4
c509e6d9
SM
5import Mouse from '../core/input/mouse.js';
6import * as eventUtils from '../core/util/events.js';
7
c509e6d9
SM
8describe('Mouse Event Handling', function() {
9 "use strict";
10
11 sinon.stub(eventUtils, 'setCapture');
12 // This function is only used on target (the canvas)
13 // and for these tests we can assume that the canvas is 100x100
14 // located at coordinates 10x10
15 sinon.stub(Element.prototype, 'getBoundingClientRect').returns(
16 {left: 10, right: 110, top: 10, bottom: 110, width: 100, height: 100});
2b5f94fa 17 const target = document.createElement('canvas');
c509e6d9
SM
18
19 // The real constructors might not work everywhere we
20 // want to run these tests
651c23ec 21 const mouseevent = (typeArg, MouseEventInit) => {
2b5f94fa
JD
22 const e = { type: typeArg };
23 for (let key in MouseEventInit) {
c509e6d9
SM
24 e[key] = MouseEventInit[key];
25 }
26 e.stopPropagation = sinon.spy();
27 e.preventDefault = sinon.spy();
28 return e;
29 };
2b5f94fa 30 const touchevent = mouseevent;
c509e6d9
SM
31
32 describe('Decode Mouse Events', function() {
33 it('should decode mousedown events', function(done) {
2b5f94fa 34 const mouse = new Mouse(target);
651c23ec 35 mouse.onmousebutton = (x, y, down, bmask) => {
747b4623
PO
36 expect(bmask).to.be.equal(0x01);
37 expect(down).to.be.equal(1);
38 done();
39 };
c509e6d9
SM
40 mouse._handleMouseDown(mouseevent('mousedown', { button: '0x01' }));
41 });
42 it('should decode mouseup events', function(done) {
2b5f94fa
JD
43 let calls = 0;
44 const mouse = new Mouse(target);
651c23ec 45 mouse.onmousebutton = (x, y, down, bmask) => {
747b4623
PO
46 expect(bmask).to.be.equal(0x01);
47 if (calls++ === 1) {
48 expect(down).to.not.be.equal(1);
49 done();
3d7bb020 50 }
747b4623 51 };
c509e6d9
SM
52 mouse._handleMouseDown(mouseevent('mousedown', { button: '0x01' }));
53 mouse._handleMouseUp(mouseevent('mouseup', { button: '0x01' }));
54 });
55 it('should decode mousemove events', function(done) {
2b5f94fa 56 const mouse = new Mouse(target);
651c23ec 57 mouse.onmousemove = (x, y) => {
747b4623
PO
58 // Note that target relative coordinates are sent
59 expect(x).to.be.equal(40);
60 expect(y).to.be.equal(10);
61 done();
62 };
c509e6d9
SM
63 mouse._handleMouseMove(mouseevent('mousemove',
64 { clientX: 50, clientY: 20 }));
65 });
66 it('should decode mousewheel events', function(done) {
2b5f94fa
JD
67 let calls = 0;
68 const mouse = new Mouse(target);
651c23ec 69 mouse.onmousebutton = (x, y, down, bmask) => {
747b4623
PO
70 calls++;
71 expect(bmask).to.be.equal(1<<6);
72 if (calls === 1) {
73 expect(down).to.be.equal(1);
74 } else if (calls === 2) {
75 expect(down).to.not.be.equal(1);
76 done();
3d7bb020 77 }
747b4623 78 };
c509e6d9
SM
79 mouse._handleMouseWheel(mouseevent('mousewheel',
80 { deltaX: 50, deltaY: 0,
81 deltaMode: 0}));
82 });
83 });
84
85 describe('Double-click for Touch', function() {
86
87 beforeEach(function () { this.clock = sinon.useFakeTimers(); });
88 afterEach(function () { this.clock.restore(); });
89
90 it('should use same pos for 2nd tap if close enough', function(done) {
2b5f94fa
JD
91 let calls = 0;
92 const mouse = new Mouse(target);
651c23ec 93 mouse.onmousebutton = (x, y, down, bmask) => {
747b4623
PO
94 calls++;
95 if (calls === 1) {
96 expect(down).to.be.equal(1);
97 expect(x).to.be.equal(68);
98 expect(y).to.be.equal(36);
99 } else if (calls === 3) {
100 expect(down).to.be.equal(1);
101 expect(x).to.be.equal(68);
102 expect(y).to.be.equal(36);
103 done();
3d7bb020 104 }
747b4623 105 };
c509e6d9
SM
106 // touch events are sent in an array of events
107 // with one item for each touch point
108 mouse._handleMouseDown(touchevent(
109 'touchstart', { touches: [{ clientX: 78, clientY: 46 }]}));
110 this.clock.tick(10);
111 mouse._handleMouseUp(touchevent(
112 'touchend', { touches: [{ clientX: 79, clientY: 45 }]}));
113 this.clock.tick(200);
114 mouse._handleMouseDown(touchevent(
115 'touchstart', { touches: [{ clientX: 67, clientY: 35 }]}));
116 this.clock.tick(10);
117 mouse._handleMouseUp(touchevent(
118 'touchend', { touches: [{ clientX: 66, clientY: 36 }]}));
119 });
120
121 it('should not modify 2nd tap pos if far apart', function(done) {
2b5f94fa
JD
122 let calls = 0;
123 const mouse = new Mouse(target);
651c23ec 124 mouse.onmousebutton = (x, y, down, bmask) => {
747b4623
PO
125 calls++;
126 if (calls === 1) {
127 expect(down).to.be.equal(1);
128 expect(x).to.be.equal(68);
129 expect(y).to.be.equal(36);
130 } else if (calls === 3) {
131 expect(down).to.be.equal(1);
132 expect(x).to.not.be.equal(68);
133 expect(y).to.not.be.equal(36);
134 done();
3d7bb020 135 }
747b4623 136 };
c509e6d9
SM
137 mouse._handleMouseDown(touchevent(
138 'touchstart', { touches: [{ clientX: 78, clientY: 46 }]}));
139 this.clock.tick(10);
140 mouse._handleMouseUp(touchevent(
141 'touchend', { touches: [{ clientX: 79, clientY: 45 }]}));
142 this.clock.tick(200);
143 mouse._handleMouseDown(touchevent(
144 'touchstart', { touches: [{ clientX: 57, clientY: 35 }]}));
145 this.clock.tick(10);
146 mouse._handleMouseUp(touchevent(
147 'touchend', { touches: [{ clientX: 56, clientY: 36 }]}));
148 });
149
150 it('should not modify 2nd tap pos if not soon enough', function(done) {
2b5f94fa
JD
151 let calls = 0;
152 const mouse = new Mouse(target);
651c23ec 153 mouse.onmousebutton = (x, y, down, bmask) => {
747b4623
PO
154 calls++;
155 if (calls === 1) {
156 expect(down).to.be.equal(1);
157 expect(x).to.be.equal(68);
158 expect(y).to.be.equal(36);
159 } else if (calls === 3) {
160 expect(down).to.be.equal(1);
161 expect(x).to.not.be.equal(68);
162 expect(y).to.not.be.equal(36);
163 done();
3d7bb020 164 }
747b4623 165 };
c509e6d9
SM
166 mouse._handleMouseDown(touchevent(
167 'touchstart', { touches: [{ clientX: 78, clientY: 46 }]}));
168 this.clock.tick(10);
169 mouse._handleMouseUp(touchevent(
170 'touchend', { touches: [{ clientX: 79, clientY: 45 }]}));
171 this.clock.tick(500);
172 mouse._handleMouseDown(touchevent(
173 'touchstart', { touches: [{ clientX: 67, clientY: 35 }]}));
174 this.clock.tick(10);
175 mouse._handleMouseUp(touchevent(
176 'touchend', { touches: [{ clientX: 66, clientY: 36 }]}));
177 });
178
179 it('should not modify 2nd tap pos if not touch', function(done) {
2b5f94fa
JD
180 let calls = 0;
181 const mouse = new Mouse(target);
651c23ec 182 mouse.onmousebutton = (x, y, down, bmask) => {
747b4623
PO
183 calls++;
184 if (calls === 1) {
185 expect(down).to.be.equal(1);
186 expect(x).to.be.equal(68);
187 expect(y).to.be.equal(36);
188 } else if (calls === 3) {
189 expect(down).to.be.equal(1);
190 expect(x).to.not.be.equal(68);
191 expect(y).to.not.be.equal(36);
192 done();
3d7bb020 193 }
747b4623 194 };
c509e6d9
SM
195 mouse._handleMouseDown(mouseevent(
196 'mousedown', { button: '0x01', clientX: 78, clientY: 46 }));
197 this.clock.tick(10);
198 mouse._handleMouseUp(mouseevent(
199 'mouseup', { button: '0x01', clientX: 79, clientY: 45 }));
200 this.clock.tick(200);
201 mouse._handleMouseDown(mouseevent(
202 'mousedown', { button: '0x01', clientX: 67, clientY: 35 }));
203 this.clock.tick(10);
204 mouse._handleMouseUp(mouseevent(
205 'mouseup', { button: '0x01', clientX: 66, clientY: 36 }));
206 });
207
208 });
209
28b004fd
SM
210 describe('Accumulate mouse wheel events with small delta', function() {
211
212 beforeEach(function () { this.clock = sinon.useFakeTimers(); });
213 afterEach(function () { this.clock.restore(); });
214
215 it('should accumulate wheel events if small enough', function () {
2b5f94fa 216 const mouse = new Mouse(target);
747b4623 217 mouse.onmousebutton = sinon.spy();
28b004fd
SM
218
219 mouse._handleMouseWheel(mouseevent(
220 'mousewheel', { clientX: 18, clientY: 40,
221 deltaX: 4, deltaY: 0, deltaMode: 0 }));
222 this.clock.tick(10);
223 mouse._handleMouseWheel(mouseevent(
224 'mousewheel', { clientX: 18, clientY: 40,
225 deltaX: 4, deltaY: 0, deltaMode: 0 }));
226
227 // threshold is 10
228 expect(mouse._accumulatedWheelDeltaX).to.be.equal(8);
229
230 this.clock.tick(10);
231 mouse._handleMouseWheel(mouseevent(
232 'mousewheel', { clientX: 18, clientY: 40,
233 deltaX: 4, deltaY: 0, deltaMode: 0 }));
234
747b4623 235 expect(mouse.onmousebutton).to.have.callCount(2); // mouse down and up
28b004fd
SM
236
237 this.clock.tick(10);
238 mouse._handleMouseWheel(mouseevent(
239 'mousewheel', { clientX: 18, clientY: 40,
240 deltaX: 4, deltaY: 9, deltaMode: 0 }));
241
242 expect(mouse._accumulatedWheelDeltaX).to.be.equal(4);
243 expect(mouse._accumulatedWheelDeltaY).to.be.equal(9);
244
747b4623 245 expect(mouse.onmousebutton).to.have.callCount(2); // still
28b004fd
SM
246 });
247
248 it('should not accumulate large wheel events', function () {
2b5f94fa 249 const mouse = new Mouse(target);
747b4623 250 mouse.onmousebutton = sinon.spy();
28b004fd
SM
251
252 mouse._handleMouseWheel(mouseevent(
253 'mousewheel', { clientX: 18, clientY: 40,
254 deltaX: 11, deltaY: 0, deltaMode: 0 }));
255 this.clock.tick(10);
256 mouse._handleMouseWheel(mouseevent(
257 'mousewheel', { clientX: 18, clientY: 40,
258 deltaX: 0, deltaY: 70, deltaMode: 0 }));
259 this.clock.tick(10);
260 mouse._handleMouseWheel(mouseevent(
261 'mousewheel', { clientX: 18, clientY: 40,
262 deltaX: 400, deltaY: 400, deltaMode: 0 }));
263
747b4623 264 expect(mouse.onmousebutton).to.have.callCount(8); // mouse down and up
28b004fd
SM
265 });
266
267 it('should send even small wheel events after a timeout', function () {
2b5f94fa 268 const mouse = new Mouse(target);
747b4623 269 mouse.onmousebutton = sinon.spy();
28b004fd
SM
270
271 mouse._handleMouseWheel(mouseevent(
272 'mousewheel', { clientX: 18, clientY: 40,
273 deltaX: 1, deltaY: 0, deltaMode: 0 }));
274 this.clock.tick(51); // timeout on 50 ms
275
747b4623 276 expect(mouse.onmousebutton).to.have.callCount(2); // mouse down and up
28b004fd
SM
277 });
278
279 it('should account for non-zero deltaMode', function () {
2b5f94fa 280 const mouse = new Mouse(target);
747b4623 281 mouse.onmousebutton = sinon.spy();
28b004fd
SM
282
283 mouse._handleMouseWheel(mouseevent(
284 'mousewheel', { clientX: 18, clientY: 40,
285 deltaX: 0, deltaY: 2, deltaMode: 1 }));
286
287 this.clock.tick(10);
288
289 mouse._handleMouseWheel(mouseevent(
290 'mousewheel', { clientX: 18, clientY: 40,
291 deltaX: 1, deltaY: 0, deltaMode: 2 }));
292
747b4623 293 expect(mouse.onmousebutton).to.have.callCount(4); // mouse down and up
28b004fd
SM
294 });
295 });
296
c509e6d9 297});