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