blob: 24266b2ad7d3e10de684f30ba4c0ecded31a2ff9 [file] [log] [blame]
Mike Frysinger598e8012022-09-07 08:38:34 -04001// Copyright 2022 The ChromiumOS Authors
Jason Linabad7562022-08-22 14:49:05 +10002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * @fileoverview Unit tests for terminal_emulator.js.
7 */
8
Mike Frysinger75895da2022-10-04 00:42:28 +05459import {lib} from './deps_local.concat.js';
10
Jason Linabad7562022-08-22 14:49:05 +100011import {sleep} from './terminal_common.js';
Jason Lina8adea52022-10-25 13:14:14 +110012import {A11yButtons, Modifier, XtermTerminal, XtermTerminalTestParams,
13 encodeKeyCombo} from './terminal_emulator.js';
Jason Lin5690e752022-08-30 15:36:45 +100014import {MockFunction, MockObject} from './terminal_test_mocks.js';
Jason Lina8adea52022-10-25 13:14:14 +110015import {Terminal} from './xterm.js';
Jason Linabad7562022-08-22 14:49:05 +100016
17describe('terminal_emulator_tests.js', function() {
18 describe('XtermTerminal', function() {
19 beforeEach(async function() {
20 this.mocks = {
Jason Line9231bc2022-09-01 13:54:02 +100021 term: new MockObject({
22 options: {},
23 parser: {
24 registerOscHandler: () => {},
25 },
26 }),
Jason Linabad7562022-08-22 14:49:05 +100027 fontManager: new MockObject(),
Jason Lin2649da22022-10-12 10:16:44 +110028 xtermInternal: new MockObject({
29 getActualCellDimensions: () => ({width: 9, height: 22}),
30 }),
Jason Linabad7562022-08-22 14:49:05 +100031 };
32 const testParams = {};
33 for (const prop in this.mocks) {
34 testParams[prop] = this.mocks[prop].proxy;
35 }
36
37 this.terminal = new XtermTerminal({
38 storage: new lib.Storage.Memory(),
39 profileId: 'test',
40 enableWebGL: true,
41 testParams: /** @type {!XtermTerminalTestParams} */(testParams),
42 });
Jason Linc2504ae2022-09-02 13:03:31 +100043
44 // Some hacking because we don't run the decorate() function. Maybe we
45 // should just run it.
46 this.terminal.container_ = /** @type {!Element} */({
47 offsetWidth: 1000,
48 offsetHeight: 500,
49 });
Jason Lin8de3d282022-09-01 21:29:05 +100050 this.terminal.inited_ = true;
Jason Linabad7562022-08-22 14:49:05 +100051 });
52
53 describe('updateFont_()', function() {
54 it('updates font', async function() {
55 const updateFontPromise = this.terminal.updateFont_('font one');
56 assert.deepEqual(
57 await this.mocks.fontManager.whenCalled('loadFont'),
58 [['font one']]);
59 assert.equal(this.mocks.term.baseObj.options.fontFamily, undefined);
60 assert.isNotNull(this.terminal.pendingFont_);
Jason Linc2504ae2022-09-02 13:03:31 +100061 assert.equal(this.mocks.term.popMethodHistory('resize').length, 0);
Jason Linabad7562022-08-22 14:49:05 +100062
63 await updateFontPromise;
64 assert.equal(this.mocks.term.baseObj.options.fontFamily, 'font one');
65 assert.isNull(this.terminal.pendingFont_);
66 await sleep(0);
Jason Linc2504ae2022-09-02 13:03:31 +100067 assert.equal(this.mocks.term.popMethodHistory('resize').length, 1);
Jason Linabad7562022-08-22 14:49:05 +100068 });
69
70 it('refresh font when the font is the same', async function() {
71 this.mocks.term.baseObj.options.fontFamily = 'font one';
72 const updateFontPromise = this.terminal.updateFont_('font one');
73 assert.deepEqual(
74 await this.mocks.fontManager.whenCalled('loadFont'),
75 [['font one']]);
76 assert.equal(this.mocks.term.baseObj.options.fontFamily, 'font one');
77 assert.isNotNull(this.terminal.pendingFont_);
Jason Linc2504ae2022-09-02 13:03:31 +100078 assert.equal(this.mocks.term.popMethodHistory('resize').length, 0);
Jason Linabad7562022-08-22 14:49:05 +100079
80 await updateFontPromise;
81 // Note the extra space at the end.
82 assert.equal(this.mocks.term.baseObj.options.fontFamily, 'font one ');
83 assert.isNull(this.terminal.pendingFont_);
84 await sleep(0);
Jason Linc2504ae2022-09-02 13:03:31 +100085 assert.equal(this.mocks.term.popMethodHistory('resize').length, 1);
Jason Linabad7562022-08-22 14:49:05 +100086 });
87
88 it('aborts if pendingFont_ was changed', async function() {
89 const updateFontPromise = this.terminal.updateFont_('font one');
90 assert.deepEqual(
91 await this.mocks.fontManager.whenCalled('loadFont'),
92 [['font one']]);
93 assert.equal(this.mocks.term.baseObj.options.fontFamily, undefined);
94 assert.isNotNull(this.terminal.pendingFont_);
Jason Linc2504ae2022-09-02 13:03:31 +100095 assert.equal(this.mocks.term.popMethodHistory('resize').length, 0);
Jason Linabad7562022-08-22 14:49:05 +100096
97 this.terminal.pendingFont_ = 'font two';
98
99 await updateFontPromise;
100 assert.equal(this.mocks.term.baseObj.options.fontFamily, undefined);
101 assert.equal(this.terminal.pendingFont_, 'font two');
102 await sleep(0);
Jason Linc2504ae2022-09-02 13:03:31 +1000103 assert.equal(this.mocks.term.popMethodHistory('resize').length, 0);
Jason Linabad7562022-08-22 14:49:05 +1000104 });
105 });
Jason Lin5690e752022-08-30 15:36:45 +1000106
107 it('customKeyEventHandler_', async function() {
108 const mockHandler = new MockFunction();
109 const fakeEvent = {
110 type: 'keydown',
111 keyCode: 65,
112 ctrlKey: true,
113 };
114 this.terminal.keyDownHandlers_.set(encodeKeyCombo(Modifier.Ctrl, 65),
115 mockHandler.proxy);
116 assert.isFalse(this.terminal.customKeyEventHandler_(fakeEvent));
117 const history = mockHandler.popHistory();
118 assert.equal(history.length, 1);
119 assert.equal(history[0][0], fakeEvent);
120
121 assert.isFalse(this.terminal.customKeyEventHandler_({...fakeEvent,
122 type: 'keypress'}));
123 assert.isEmpty(mockHandler.popHistory());
124
125 assert.isTrue(this.terminal.customKeyEventHandler_({...fakeEvent,
126 shiftKey: true}));
127 assert.isEmpty(mockHandler.popHistory());
128
129 assert.isTrue(this.terminal.customKeyEventHandler_({...fakeEvent,
130 keyCode: 66}));
131 assert.isEmpty(mockHandler.popHistory());
132
133 assert.isTrue(this.terminal.customKeyEventHandler_({...fakeEvent,
134 ctrlKey: false}));
135 assert.isEmpty(mockHandler.popHistory());
136 });
Jason Linabad7562022-08-22 14:49:05 +1000137 });
Jason Lina8adea52022-10-25 13:14:14 +1100138
139 describe('A11yButtons', () => {
140 const ROWS = 5;
141
142 beforeEach(function() {
143 this.elem = document.createElement('div');
144 this.elem.style.height = '500px';
145 this.elem.style.width = '500px';
146 document.body.appendChild(this.elem);
147
148 this.terminal = new Terminal({cols: 80, rows: ROWS,
149 allowProposedApi: true});
150 this.htermA11yReaderMock = new MockObject();
151 this.a11yButtons = new A11yButtons(this.terminal, this.elem,
152 /** @type {!hterm.AccessibilityReader} */(
153 this.htermA11yReaderMock.proxy));
154
155 this.write = async (content) => {
156 return new Promise((resolve) => this.terminal.write(content, resolve));
157 };
158 });
159
160 afterEach(function() {
161 this.terminal.dispose();
162 document.body.removeChild(this.elem);
163 });
164
165 it('announceScreenContent_', async function() {
166 this.a11yButtons.announceScreenContent_();
167 assert.deepEqual(
168 this.htermA11yReaderMock.popMethodHistory('assertiveAnnounce'),
169 [['100% scrolled,']]);
170
171 await this.write('hello');
172 this.a11yButtons.announceScreenContent_();
173 assert.deepEqual(
174 this.htermA11yReaderMock.popMethodHistory('assertiveAnnounce'),
175 [['100% scrolled,\nhello']]);
176
177 await this.write('\r\nworld');
178 this.a11yButtons.announceScreenContent_();
179 assert.deepEqual(
180 this.htermA11yReaderMock.popMethodHistory('assertiveAnnounce'),
181 [['100% scrolled,\nhello\nworld']]);
182
183 for (let i = 0; i < ROWS; ++i) {
184 await this.write(`\r\n${i}`);
185 }
186 this.a11yButtons.announceScreenContent_();
187 assert.deepEqual(
188 this.htermA11yReaderMock.popMethodHistory('assertiveAnnounce'),
189 [['100% scrolled,\n0\n1\n2\n3\n4']]);
190
191 this.terminal.scrollLines(-1);
192 this.a11yButtons.announceScreenContent_();
193 assert.deepEqual(
194 this.htermA11yReaderMock.popMethodHistory('assertiveAnnounce'),
195 [['50% scrolled,\nworld\n0\n1\n2\n3']]);
196
197 this.terminal.scrollLines(-1);
198 this.a11yButtons.announceScreenContent_();
199 assert.deepEqual(
200 this.htermA11yReaderMock.popMethodHistory('assertiveAnnounce'),
201 [['0% scrolled,\nhello\nworld\n0\n1\n2']]);
202 });
203 });
Jason Linabad7562022-08-22 14:49:05 +1000204});