]> git.proxmox.com Git - mirror_xterm.js.git/blob - test/test.js
Separate dummy keyDown and keyPress events in tests
[mirror_xterm.js.git] / test / test.js
1 var assert = require('chai').assert;
2 var expect = require('chai').expect;
3 var Terminal = require('../src/xterm');
4
5 describe('xterm.js', function() {
6 var xterm;
7
8 beforeEach(function () {
9 xterm = new Terminal();
10 xterm.refresh = function(){};
11 });
12
13 describe('evaluateKeyEscapeSequence', function() {
14 it('should return the correct escape sequence for unmodified keys', function() {
15 // Backspace
16 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 8 }).key, '\x7f'); // ^?
17 // Tab
18 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 9 }).key, '\t');
19 // Return/enter
20 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 13 }).key, '\r'); // CR
21 // Escape
22 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 27 }).key, '\x1b');
23 // Page up, page down
24 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 33 }).key, '\x1b[5~'); // CSI 5 ~
25 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 34 }).key, '\x1b[6~'); // CSI 6 ~
26 // End, Home
27 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 35 }).key, '\x1bOF'); // SS3 F
28 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 36 }).key, '\x1bOH'); // SS3 H
29 // Left, up, right, down arrows
30 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 37 }).key, '\x1b[D'); // CSI D
31 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 38 }).key, '\x1b[A'); // CSI A
32 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 39 }).key, '\x1b[C'); // CSI C
33 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 40 }).key, '\x1b[B'); // CSI B
34 // Insert
35 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 45 }).key, '\x1b[2~'); // CSI 2 ~
36 // Delete
37 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 46 }).key, '\x1b[3~'); // CSI 3 ~
38 // F1-F12
39 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 112 }).key, '\x1bOP'); // SS3 P
40 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 113 }).key, '\x1bOQ'); // SS3 Q
41 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 114 }).key, '\x1bOR'); // SS3 R
42 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 115 }).key, '\x1bOS'); // SS3 S
43 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 116 }).key, '\x1b[15~'); // CSI 1 5 ~
44 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 117 }).key, '\x1b[17~'); // CSI 1 7 ~
45 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 118 }).key, '\x1b[18~'); // CSI 1 8 ~
46 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 119 }).key, '\x1b[19~'); // CSI 1 9 ~
47 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 120 }).key, '\x1b[20~'); // CSI 2 0 ~
48 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 121 }).key, '\x1b[21~'); // CSI 2 1 ~
49 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 122 }).key, '\x1b[23~'); // CSI 2 3 ~
50 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 123 }).key, '\x1b[24~'); // CSI 2 4 ~
51 });
52 it('should return \\x1b[5D for ctrl+left', function() {
53 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 37 }).key, '\x1b[5D'); // CSI 5 D
54 });
55 it('should return \\x1b[5C for ctrl+right', function() {
56 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 39 }).key, '\x1b[5C'); // CSI 5 C
57 });
58 });
59
60 describe('evaluateCopiedTextProcessing', function () {
61 it('should strip trailing whitespaces and replace nbsps with spaces', function () {
62 var nonBreakingSpace = String.fromCharCode(160),
63 copiedText = 'echo' + nonBreakingSpace + 'hello' + nonBreakingSpace,
64 processedText = Terminal.prepareCopiedTextForClipboard(copiedText);
65
66 // No trailing spaces
67 assert.equal(processedText.match(/\s+$/), null);
68
69 // No non-breaking space
70 assert.equal(processedText.indexOf(nonBreakingSpace), -1);
71 });
72 });
73
74 describe('Third level shift', function() {
75 var evKeyDown = {
76 preventDefault: function() {},
77 stopPropagation: function() {},
78 type: 'keydown'
79 },
80 evKeyPress = {
81 preventDefault: function() {},
82 stopPropagation: function() {},
83 type: 'keypress'
84 };
85
86 beforeEach(function() {
87 xterm.handler = function() {};
88 xterm.showCursor = function() {};
89 xterm.clearSelection = function() {};
90 });
91
92 describe('On Mac OS', function() {
93 beforeEach(function() {
94 xterm.isMac = true;
95 });
96
97 it('should not interfere with the alt key on keyDown', function() {
98 assert.equal(
99 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 81 })),
100 true
101 );
102 assert.equal(
103 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 192 })),
104 true
105 );
106 });
107
108 it('should interefere with the alt + arrow keys', function() {
109 assert.equal(
110 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 37 })),
111 false
112 );
113 assert.equal(
114 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 39 })),
115 false
116 );
117 });
118
119 it('should emit key with alt + key on keyPress', function(done) {
120 var keys = ['@', '@', '\\', '\\', '|', '|'];
121
122 xterm.on('keypress', function(key) {
123 if (key) {
124 var index = keys.indexOf(key);
125 assert(index !== -1, "Emitted wrong key: " + key);
126 keys.splice(index, 1);
127 }
128 if (keys.length === 0) done();
129 });
130
131 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 64 })); // @
132 // Firefox
133 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 64, keyCode: 0 }));
134 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 92 })); // \
135 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 92, keyCode: 0 }));
136 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 124 })); // |
137 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 124, keyCode: 0 }));
138 });
139 });
140
141 describe('On MS Windows', function() {
142 beforeEach(function() {
143 xterm.isMSWindows = true;
144 });
145
146 it('should not interfere with the alt + ctrl key on keyDown', function() {
147 assert.equal(
148 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 81 })),
149 true
150 );
151 assert.equal(
152 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 192 })),
153 true
154 );
155 });
156
157 it('should interefere with the alt + ctrl + arrow keys', function() {
158 assert.equal(
159 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 37 })),
160 false
161 );
162 assert.equal(
163 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 39 })),
164 false
165 );
166 });
167
168 it('should emit key with alt + ctrl + key on keyPress', function(done) {
169 var keys = ['@', '@', '\\', '\\', '|', '|'];
170
171 xterm.on('keypress', function(key) {
172 if (key) {
173 var index = keys.indexOf(key);
174 assert(index !== -1, "Emitted wrong key: " + key);
175 keys.splice(index, 1);
176 }
177 if (keys.length === 0) done();
178 });
179
180 xterm.keyPress(
181 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 64 })
182 ); // @
183 xterm.keyPress(
184 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 64, keyCode: 0 })
185 );
186 xterm.keyPress(
187 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 92 })
188 ); // \
189 xterm.keyPress(
190 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 92, keyCode: 0 })
191 );
192 xterm.keyPress(
193 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 124 })
194 ); // |
195 xterm.keyPress(
196 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 124, keyCode: 0 })
197 );
198 });
199 });
200 });
201
202 describe('unicode - surrogates', function() {
203 it('2 characters per cell', function () {
204 var high = '\uD800';
205 for (var i=0xDC00; i<=0xDCFF; ++i) {
206 xterm.write(high + String.fromCharCode(i));
207 var tchar = xterm.lines[0][0];
208 expect(tchar[1]).eql(high + String.fromCharCode(i));
209 expect(tchar[1].length).eql(2);
210 expect(tchar[2]).eql(1);
211 expect(xterm.lines[0][1][1]).eql(' ');
212 xterm.reset();
213 }
214 });
215 it('2 characters at last cell', function() {
216 var high = '\uD800';
217 for (var i=0xDC00; i<=0xDCFF; ++i) {
218 xterm.x = xterm.cols - 1;
219 xterm.write(high + String.fromCharCode(i));
220 expect(xterm.lines[0][xterm.x-1][1]).eql(high + String.fromCharCode(i));
221 expect(xterm.lines[0][xterm.x-1][1].length).eql(2);
222 expect(xterm.lines[1][0][1]).eql(' ');
223 xterm.reset();
224 }
225 });
226 it('2 characters per cell over line end with autowrap', function() {
227 var high = '\uD800';
228 for (var i=0xDC00; i<=0xDCFF; ++i) {
229 xterm.x = xterm.cols - 1;
230 xterm.wraparoundMode = true;
231 xterm.write('a' + high + String.fromCharCode(i));
232 expect(xterm.lines[0][xterm.cols-1][1]).eql('a');
233 expect(xterm.lines[1][0][1]).eql(high + String.fromCharCode(i));
234 expect(xterm.lines[1][0][1].length).eql(2);
235 expect(xterm.lines[1][1][1]).eql(' ');
236 xterm.reset();
237 }
238 });
239 it('2 characters per cell over line end without autowrap', function() {
240 var high = '\uD800';
241 for (var i=0xDC00; i<=0xDCFF; ++i) {
242 xterm.x = xterm.cols - 1;
243 xterm.wraparoundMode = false;
244 xterm.write('a' + high + String.fromCharCode(i));
245 expect(xterm.lines[0][xterm.cols-1][1]).eql(high + String.fromCharCode(i));
246 expect(xterm.lines[0][xterm.cols-1][1].length).eql(2);
247 expect(xterm.lines[1][1][1]).eql(' ');
248 xterm.reset();
249 }
250 });
251 it('splitted surrogates', function() {
252 var high = '\uD800';
253 for (var i=0xDC00; i<=0xDCFF; ++i) {
254 xterm.write(high);
255 xterm.write(String.fromCharCode(i));
256 var tchar = xterm.lines[0][0];
257 expect(tchar[1]).eql(high + String.fromCharCode(i));
258 expect(tchar[1].length).eql(2);
259 expect(tchar[2]).eql(1);
260 expect(xterm.lines[0][1][1]).eql(' ');
261 xterm.reset();
262 }
263 });
264 });
265
266 describe('unicode - combining characters', function() {
267 it('café', function () {
268 xterm.write('cafe\u0301');
269 expect(xterm.lines[0][3][1]).eql('e\u0301');
270 expect(xterm.lines[0][3][1].length).eql(2);
271 expect(xterm.lines[0][3][2]).eql(1);
272 });
273 it('café - end of line', function() {
274 xterm.x = xterm.cols - 1 - 3;
275 xterm.write('cafe\u0301');
276 expect(xterm.lines[0][xterm.cols-1][1]).eql('e\u0301');
277 expect(xterm.lines[0][xterm.cols-1][1].length).eql(2);
278 expect(xterm.lines[0][xterm.cols-1][2]).eql(1);
279 expect(xterm.lines[0][1][1]).eql(' ');
280 expect(xterm.lines[0][1][1].length).eql(1);
281 expect(xterm.lines[0][1][2]).eql(1);
282 });
283 it('multiple combined é', function() {
284 xterm.wraparoundMode = true;
285 xterm.write(Array(100).join('e\u0301'));
286 for (var i=0; i<xterm.cols; ++i) {
287 var tchar = xterm.lines[0][i];
288 expect(tchar[1]).eql('e\u0301');
289 expect(tchar[1].length).eql(2);
290 expect(tchar[2]).eql(1);
291 }
292 tchar = xterm.lines[1][0];
293 expect(tchar[1]).eql('e\u0301');
294 expect(tchar[1].length).eql(2);
295 expect(tchar[2]).eql(1);
296 });
297 it('multiple surrogate with combined', function() {
298 xterm.wraparoundMode = true;
299 xterm.write(Array(100).join('\uD800\uDC00\u0301'));
300 for (var i=0; i<xterm.cols; ++i) {
301 var tchar = xterm.lines[0][i];
302 expect(tchar[1]).eql('\uD800\uDC00\u0301');
303 expect(tchar[1].length).eql(3);
304 expect(tchar[2]).eql(1);
305 }
306 tchar = xterm.lines[1][0];
307 expect(tchar[1]).eql('\uD800\uDC00\u0301');
308 expect(tchar[1].length).eql(3);
309 expect(tchar[2]).eql(1);
310 });
311 });
312
313 describe('unicode - fullwidth characters', function() {
314 it('cursor movement even', function() {
315 expect(xterm.x).eql(0);
316 xterm.write('¥');
317 expect(xterm.x).eql(2);
318 });
319 it('cursor movement odd', function() {
320 xterm.x = 1;
321 expect(xterm.x).eql(1);
322 xterm.write('¥');
323 expect(xterm.x).eql(3);
324 });
325 it('line of ¥ even', function() {
326 xterm.wraparoundMode = true;
327 xterm.write(Array(50).join('¥'));
328 for (var i=0; i<xterm.cols; ++i) {
329 var tchar = xterm.lines[0][i];
330 if (i % 2) {
331 expect(tchar[1]).eql('');
332 expect(tchar[1].length).eql(0);
333 expect(tchar[2]).eql(0);
334 } else {
335 expect(tchar[1]).eql('¥');
336 expect(tchar[1].length).eql(1);
337 expect(tchar[2]).eql(2);
338 }
339 }
340 tchar = xterm.lines[1][0];
341 expect(tchar[1]).eql('¥');
342 expect(tchar[1].length).eql(1);
343 expect(tchar[2]).eql(2);
344 });
345 it('line of ¥ odd', function() {
346 xterm.wraparoundMode = true;
347 xterm.x = 1;
348 xterm.write(Array(50).join('¥'));
349 for (var i=1; i<xterm.cols-1; ++i) {
350 var tchar = xterm.lines[0][i];
351 if (!(i % 2)) {
352 expect(tchar[1]).eql('');
353 expect(tchar[1].length).eql(0);
354 expect(tchar[2]).eql(0);
355 } else {
356 expect(tchar[1]).eql('¥');
357 expect(tchar[1].length).eql(1);
358 expect(tchar[2]).eql(2);
359 }
360 }
361 tchar = xterm.lines[0][xterm.cols-1];
362 expect(tchar[1]).eql(' ');
363 expect(tchar[1].length).eql(1);
364 expect(tchar[2]).eql(1);
365 tchar = xterm.lines[1][0];
366 expect(tchar[1]).eql('¥');
367 expect(tchar[1].length).eql(1);
368 expect(tchar[2]).eql(2);
369 });
370 it('line of ¥ with combining odd', function() {
371 xterm.wraparoundMode = true;
372 xterm.x = 1;
373 xterm.write(Array(50).join('¥\u0301'));
374 for (var i=1; i<xterm.cols-1; ++i) {
375 var tchar = xterm.lines[0][i];
376 if (!(i % 2)) {
377 expect(tchar[1]).eql('');
378 expect(tchar[1].length).eql(0);
379 expect(tchar[2]).eql(0);
380 } else {
381 expect(tchar[1]).eql('¥\u0301');
382 expect(tchar[1].length).eql(2);
383 expect(tchar[2]).eql(2);
384 }
385 }
386 tchar = xterm.lines[0][xterm.cols-1];
387 expect(tchar[1]).eql(' ');
388 expect(tchar[1].length).eql(1);
389 expect(tchar[2]).eql(1);
390 tchar = xterm.lines[1][0];
391 expect(tchar[1]).eql('¥\u0301');
392 expect(tchar[1].length).eql(2);
393 expect(tchar[2]).eql(2);
394 });
395 it('line of ¥ with combining even', function() {
396 xterm.wraparoundMode = true;
397 xterm.write(Array(50).join('¥\u0301'));
398 for (var i=0; i<xterm.cols; ++i) {
399 var tchar = xterm.lines[0][i];
400 if (i % 2) {
401 expect(tchar[1]).eql('');
402 expect(tchar[1].length).eql(0);
403 expect(tchar[2]).eql(0);
404 } else {
405 expect(tchar[1]).eql('¥\u0301');
406 expect(tchar[1].length).eql(2);
407 expect(tchar[2]).eql(2);
408 }
409 }
410 tchar = xterm.lines[1][0];
411 expect(tchar[1]).eql('¥\u0301');
412 expect(tchar[1].length).eql(2);
413 expect(tchar[2]).eql(2);
414 });
415 it('line of surrogate fullwidth with combining odd', function() {
416 xterm.wraparoundMode = true;
417 xterm.x = 1;
418 xterm.write(Array(50).join('\ud843\ude6d\u0301'));
419 for (var i=1; i<xterm.cols-1; ++i) {
420 var tchar = xterm.lines[0][i];
421 if (!(i % 2)) {
422 expect(tchar[1]).eql('');
423 expect(tchar[1].length).eql(0);
424 expect(tchar[2]).eql(0);
425 } else {
426 expect(tchar[1]).eql('\ud843\ude6d\u0301');
427 expect(tchar[1].length).eql(3);
428 expect(tchar[2]).eql(2);
429 }
430 }
431 tchar = xterm.lines[0][xterm.cols-1];
432 expect(tchar[1]).eql(' ');
433 expect(tchar[1].length).eql(1);
434 expect(tchar[2]).eql(1);
435 tchar = xterm.lines[1][0];
436 expect(tchar[1]).eql('\ud843\ude6d\u0301');
437 expect(tchar[1].length).eql(3);
438 expect(tchar[2]).eql(2);
439 });
440 it('line of surrogate fullwidth with combining even', function() {
441 xterm.wraparoundMode = true;
442 xterm.write(Array(50).join('\ud843\ude6d\u0301'));
443 for (var i=0; i<xterm.cols; ++i) {
444 var tchar = xterm.lines[0][i];
445 if (i % 2) {
446 expect(tchar[1]).eql('');
447 expect(tchar[1].length).eql(0);
448 expect(tchar[2]).eql(0);
449 } else {
450 expect(tchar[1]).eql('\ud843\ude6d\u0301');
451 expect(tchar[1].length).eql(3);
452 expect(tchar[2]).eql(2);
453 }
454 }
455 tchar = xterm.lines[1][0];
456 expect(tchar[1]).eql('\ud843\ude6d\u0301');
457 expect(tchar[1].length).eql(3);
458 expect(tchar[2]).eql(2);
459 });
460 });
461
462 describe('insert mode', function() {
463 it('halfwidth - all', function () {
464 xterm.write(Array(9).join('0123456789').slice(-80));
465 xterm.x = 10;
466 xterm.y = 0;
467 xterm.insertMode = true;
468 xterm.write('abcde');
469 expect(xterm.lines[0].length).eql(xterm.cols);
470 expect(xterm.lines[0][10][1]).eql('a');
471 expect(xterm.lines[0][14][1]).eql('e');
472 expect(xterm.lines[0][15][1]).eql('0');
473 expect(xterm.lines[0][79][1]).eql('4');
474 });
475 it('fullwidth - insert', function() {
476 xterm.write(Array(9).join('0123456789').slice(-80));
477 xterm.x = 10;
478 xterm.y = 0;
479 xterm.insertMode = true;
480 xterm.write('¥¥¥');
481 expect(xterm.lines[0].length).eql(xterm.cols);
482 expect(xterm.lines[0][10][1]).eql('¥');
483 expect(xterm.lines[0][11][1]).eql('');
484 expect(xterm.lines[0][14][1]).eql('¥');
485 expect(xterm.lines[0][15][1]).eql('');
486 expect(xterm.lines[0][79][1]).eql('3');
487 });
488 it('fullwidth - right border', function() {
489 xterm.write(Array(41).join('¥'));
490 xterm.x = 10;
491 xterm.y = 0;
492 xterm.insertMode = true;
493 xterm.write('a');
494 expect(xterm.lines[0].length).eql(xterm.cols);
495 expect(xterm.lines[0][10][1]).eql('a');
496 expect(xterm.lines[0][11][1]).eql('¥');
497 expect(xterm.lines[0][79][1]).eql(' '); // fullwidth char got replaced
498 xterm.write('b');
499 expect(xterm.lines[0].length).eql(xterm.cols);
500 expect(xterm.lines[0][11][1]).eql('b');
501 expect(xterm.lines[0][12][1]).eql('¥');
502 expect(xterm.lines[0][79][1]).eql(''); // empty cell after fullwidth
503 });
504 });
505 });