Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/test/browser/controller/textAreaInput.test.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import { Emitter, Event } from '../../../../base/common/event.js';
8
import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js';
9
import { OperatingSystem } from '../../../../base/common/platform.js';
10
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
11
import { Position } from '../../../common/core/position.js';
12
import { IRecorded, IRecordedEvent, IRecordedTextareaState } from './imeRecordedTypes.js';
13
import { TestAccessibilityService } from '../../../../platform/accessibility/test/common/testAccessibilityService.js';
14
import { NullLogService } from '../../../../platform/log/common/log.js';
15
import { IBrowser, ICompleteTextAreaWrapper, ITextAreaInputHost, TextAreaInput } from '../../../browser/controller/editContext/textArea/textAreaEditContextInput.js';
16
import { ClipboardDataToCopy } from '../../../browser/controller/editContext/clipboardUtils.js';
17
import { TextAreaState } from '../../../browser/controller/editContext/textArea/textAreaEditContextState.js';
18
19
suite('TextAreaInput', () => {
20
21
ensureNoDisposablesAreLeakedInTestSuite();
22
23
interface OutgoingType {
24
type: 'type';
25
text: string;
26
replacePrevCharCnt: number;
27
replaceNextCharCnt: number;
28
positionDelta: number;
29
}
30
interface OutgoingCompositionStart {
31
type: 'compositionStart';
32
data: string;
33
}
34
interface OutgoingCompositionUpdate {
35
type: 'compositionUpdate';
36
data: string;
37
}
38
interface OutgoingCompositionEnd {
39
type: 'compositionEnd';
40
}
41
type OutoingEvent = OutgoingType | OutgoingCompositionStart | OutgoingCompositionUpdate | OutgoingCompositionEnd;
42
43
function yieldNow(): Promise<void> {
44
return new Promise((resolve, reject) => {
45
queueMicrotask(resolve);
46
});
47
}
48
49
async function simulateInteraction(recorded: IRecorded): Promise<OutoingEvent[]> {
50
const disposables = new DisposableStore();
51
const host: ITextAreaInputHost = {
52
getDataToCopy: function (): ClipboardDataToCopy {
53
throw new Error('Function not implemented.');
54
},
55
getScreenReaderContent: function (): TextAreaState {
56
return new TextAreaState('', 0, 0, null, undefined);
57
},
58
deduceModelPosition: function (viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position {
59
throw new Error('Function not implemented.');
60
}
61
};
62
const wrapper = disposables.add(new class extends Disposable implements ICompleteTextAreaWrapper {
63
private _onKeyDown = this._register(new Emitter<KeyboardEvent>());
64
readonly onKeyDown = this._onKeyDown.event;
65
66
private _onKeyPress = this._register(new Emitter<KeyboardEvent>());
67
readonly onKeyPress = this._onKeyPress.event;
68
69
private _onKeyUp = this._register(new Emitter<KeyboardEvent>());
70
readonly onKeyUp = this._onKeyUp.event;
71
72
private _onCompositionStart = this._register(new Emitter<CompositionEvent>());
73
readonly onCompositionStart = this._onCompositionStart.event;
74
75
private _onCompositionUpdate = this._register(new Emitter<CompositionEvent>());
76
readonly onCompositionUpdate = this._onCompositionUpdate.event;
77
78
private _onCompositionEnd = this._register(new Emitter<CompositionEvent>());
79
readonly onCompositionEnd = this._onCompositionEnd.event;
80
81
private _onBeforeInput = this._register(new Emitter<InputEvent>());
82
readonly onBeforeInput = this._onBeforeInput.event;
83
84
private _onInput = this._register(new Emitter<InputEvent>());
85
readonly onInput = this._onInput.event;
86
87
readonly onCut = Event.None;
88
readonly onCopy = Event.None;
89
readonly onPaste = Event.None;
90
readonly onFocus = Event.None;
91
readonly onBlur = Event.None;
92
readonly onSyntheticTap = Event.None;
93
94
private _state: IRecordedTextareaState;
95
private _currDispatchingEvent: IRecordedEvent | null;
96
97
public ownerDocument = document;
98
99
constructor() {
100
super();
101
this._state = {
102
selectionDirection: 'none',
103
selectionEnd: 0,
104
selectionStart: 0,
105
value: ''
106
};
107
this._currDispatchingEvent = null;
108
}
109
110
public _initialize(state: IRecordedTextareaState): void {
111
this._state.value = state.value;
112
this._state.selectionStart = state.selectionStart;
113
this._state.selectionEnd = state.selectionEnd;
114
}
115
116
public _dispatchRecordedEvent(event: IRecordedEvent): void {
117
this._currDispatchingEvent = event;
118
this._state.value = event.state.value;
119
this._state.selectionStart = event.state.selectionStart;
120
this._state.selectionEnd = event.state.selectionEnd;
121
this._state.selectionDirection = event.state.selectionDirection;
122
123
if (event.type === 'keydown' || event.type === 'keypress' || event.type === 'keyup') {
124
const mockEvent = <KeyboardEvent>{
125
timeStamp: event.timeStamp,
126
type: event.type,
127
altKey: event.altKey,
128
charCode: event.charCode,
129
code: event.code,
130
ctrlKey: event.ctrlKey,
131
isComposing: event.isComposing,
132
key: event.key,
133
keyCode: event.keyCode,
134
location: event.location,
135
metaKey: event.metaKey,
136
repeat: event.repeat,
137
shiftKey: event.shiftKey,
138
getModifierState: (keyArg: string) => false
139
};
140
if (event.type === 'keydown') {
141
this._onKeyDown.fire(mockEvent);
142
} else if (event.type === 'keypress') {
143
this._onKeyPress.fire(mockEvent);
144
} else {
145
this._onKeyUp.fire(mockEvent);
146
}
147
} else if (event.type === 'compositionstart' || event.type === 'compositionupdate' || event.type === 'compositionend') {
148
const mockEvent = <CompositionEvent>{
149
timeStamp: event.timeStamp,
150
type: event.type,
151
data: event.data
152
};
153
if (event.type === 'compositionstart') {
154
this._onCompositionStart.fire(mockEvent);
155
} else if (event.type === 'compositionupdate') {
156
this._onCompositionUpdate.fire(mockEvent);
157
} else {
158
this._onCompositionEnd.fire(mockEvent);
159
}
160
} else if (event.type === 'beforeinput' || event.type === 'input') {
161
const mockEvent = <InputEvent>{
162
timeStamp: event.timeStamp,
163
type: event.type,
164
data: event.data,
165
inputType: event.inputType,
166
isComposing: event.isComposing,
167
};
168
if (event.type === 'beforeinput') {
169
this._onBeforeInput.fire(mockEvent);
170
} else {
171
this._onInput.fire(mockEvent);
172
}
173
} else {
174
throw new Error(`Not Implemented`);
175
}
176
this._currDispatchingEvent = null;
177
}
178
179
getValue(): string {
180
return this._state.value;
181
}
182
setValue(reason: string, value: string): void {
183
if (this._currDispatchingEvent?.type === 'compositionstart') {
184
assert.fail('should not change the state of the textarea in a compositionstart');
185
}
186
this._state.value = value;
187
}
188
getSelectionStart(): number {
189
return this._state.selectionDirection === 'backward' ? this._state.selectionEnd : this._state.selectionStart;
190
}
191
getSelectionEnd(): number {
192
return this._state.selectionDirection === 'backward' ? this._state.selectionStart : this._state.selectionEnd;
193
}
194
setSelectionRange(reason: string, selectionStart: number, selectionEnd: number): void {
195
if (this._currDispatchingEvent?.type === 'compositionstart') {
196
assert.fail('should not change the state of the textarea in a compositionstart');
197
}
198
this._state.selectionStart = selectionStart;
199
this._state.selectionEnd = selectionEnd;
200
this._state.selectionDirection = (selectionStart !== selectionEnd ? 'forward' : 'none');
201
}
202
203
public setIgnoreSelectionChangeTime(reason: string): void { }
204
public getIgnoreSelectionChangeTime(): number { return Date.now(); }
205
public resetSelectionChangeTime(): void { }
206
207
public hasFocus(): boolean { return true; }
208
});
209
const input = disposables.add(new TextAreaInput(host, wrapper, recorded.env.OS, recorded.env.browser, new TestAccessibilityService(), new NullLogService()));
210
211
wrapper._initialize(recorded.initial);
212
input._initializeFromTest();
213
214
const outgoingEvents: OutoingEvent[] = [];
215
216
disposables.add(input.onType((e) => outgoingEvents.push({
217
type: 'type',
218
text: e.text,
219
replacePrevCharCnt: e.replacePrevCharCnt,
220
replaceNextCharCnt: e.replaceNextCharCnt,
221
positionDelta: e.positionDelta,
222
})));
223
disposables.add(input.onCompositionStart((e) => outgoingEvents.push({
224
type: 'compositionStart',
225
data: e.data,
226
})));
227
disposables.add(input.onCompositionUpdate((e) => outgoingEvents.push({
228
type: 'compositionUpdate',
229
data: e.data,
230
})));
231
disposables.add(input.onCompositionEnd((e) => outgoingEvents.push({
232
type: 'compositionEnd'
233
})));
234
235
for (const event of recorded.events) {
236
wrapper._dispatchRecordedEvent(event);
237
await yieldNow();
238
}
239
240
disposables.dispose();
241
242
return outgoingEvents;
243
}
244
245
function interpretTypeEvents(OS: OperatingSystem, browser: IBrowser, initialState: IRecordedTextareaState, events: OutoingEvent[]): IRecordedTextareaState {
246
let text = initialState.value;
247
let selectionStart = initialState.selectionStart;
248
let selectionEnd = initialState.selectionEnd;
249
for (const event of events) {
250
if (event.type === 'type') {
251
text = (
252
text.substring(0, selectionStart - event.replacePrevCharCnt)
253
+ event.text
254
+ text.substring(selectionEnd + event.replaceNextCharCnt)
255
);
256
selectionStart = selectionStart - event.replacePrevCharCnt + event.text.length;
257
selectionEnd = selectionStart;
258
259
if (event.positionDelta) {
260
selectionStart += event.positionDelta;
261
selectionEnd += event.positionDelta;
262
}
263
}
264
}
265
return {
266
value: text,
267
selectionStart: selectionStart,
268
selectionEnd: selectionEnd,
269
selectionDirection: (browser.isFirefox || OS === OperatingSystem.Windows || OS === OperatingSystem.Linux) ? 'forward' : 'none'
270
};
271
}
272
273
test('macOS - Chrome - Korean using 2-Set Korean (1)', async () => {
274
// macOS, 2-Set Korean, type 'dkrk' and click
275
const recorded: IRecorded = {
276
env: { OS: OperatingSystem.Macintosh, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
277
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' },
278
events: [
279
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyD', ctrlKey: false, isComposing: false, key: 'ㅇ', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
280
{ timeStamp: 6.20, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionstart', data: '' },
281
{ timeStamp: 6.40, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'beforeinput', data: 'ㅇ', inputType: 'insertCompositionText', isComposing: true },
282
{ timeStamp: 6.50, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionupdate', data: 'ㅇ' },
283
{ timeStamp: 6.90, state: { value: 'aaㅇaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 'ㅇ', inputType: 'insertCompositionText', isComposing: true },
284
{ timeStamp: 136.10, state: { value: 'aaㅇaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyD', ctrlKey: false, isComposing: true, key: 'ㅇ', keyCode: 68, location: 0, metaKey: false, repeat: false, shiftKey: false },
285
{ timeStamp: 288.10, state: { value: 'aaㅇaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'ㅏ', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
286
{ timeStamp: 296.00, state: { value: 'aaㅇaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: '아', inputType: 'insertCompositionText', isComposing: true },
287
{ timeStamp: 296.00, state: { value: 'aaㅇaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: '아' },
288
{ timeStamp: 296.40, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: '아', inputType: 'insertCompositionText', isComposing: true },
289
{ timeStamp: 368.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'ㅏ', keyCode: 75, location: 0, metaKey: false, repeat: false, shiftKey: false },
290
{ timeStamp: 536.10, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'ㄱ', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
291
{ timeStamp: 543.20, state: { value: 'aa아aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: '악', inputType: 'insertCompositionText', isComposing: true },
292
{ timeStamp: 543.30, state: { value: 'aa아aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: '악' },
293
{ timeStamp: 543.60, state: { value: 'aa악aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: '악', inputType: 'insertCompositionText', isComposing: true },
294
{ timeStamp: 632.00, state: { value: 'aa악aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'ㄱ', keyCode: 82, location: 0, metaKey: false, repeat: false, shiftKey: false },
295
{ timeStamp: 783.90, state: { value: 'aa악aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'ㅏ', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
296
{ timeStamp: 790.70, state: { value: 'aa악aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: '아', inputType: 'insertCompositionText', isComposing: true },
297
{ timeStamp: 790.80, state: { value: 'aa악aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: '아' },
298
{ timeStamp: 791.20, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: '아', inputType: 'insertCompositionText', isComposing: true },
299
{ timeStamp: 791.20, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionend', data: '아' },
300
{ timeStamp: 791.30, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionstart', data: '' },
301
{ timeStamp: 791.30, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: '가', inputType: 'insertCompositionText', isComposing: true },
302
{ timeStamp: 791.30, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: '가' },
303
{ timeStamp: 791.50, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'input', data: '가', inputType: 'insertCompositionText', isComposing: true },
304
{ timeStamp: 880.10, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'ㅏ', keyCode: 75, location: 0, metaKey: false, repeat: false, shiftKey: false },
305
{ timeStamp: 2209.00, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'compositionend', data: '가' }
306
],
307
final: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' },
308
};
309
310
const actualOutgoingEvents = await simulateInteraction(recorded);
311
assert.deepStrictEqual(actualOutgoingEvents, [
312
{ type: 'compositionStart', data: '' },
313
{ type: 'type', text: 'ㅇ', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
314
{ type: 'compositionUpdate', data: 'ㅇ' },
315
{ type: 'type', text: '아', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
316
{ type: 'compositionUpdate', data: '아' },
317
{ type: 'type', text: '악', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
318
{ type: 'compositionUpdate', data: '악' },
319
{ type: 'type', text: '아', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
320
{ type: 'compositionUpdate', data: '아' },
321
{ type: 'type', text: '아', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
322
{ type: 'compositionEnd' },
323
{ type: 'compositionStart', data: '' },
324
{ type: 'type', text: '가', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
325
{ type: 'compositionUpdate', data: '가' },
326
{ type: 'type', text: '가', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
327
{ type: 'compositionEnd' }
328
]);
329
330
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
331
assert.deepStrictEqual(actualResultingState, recorded.final);
332
});
333
334
test('macOS - Chrome - Korean using 2-Set Korean (2)', async () => {
335
// macOS, 2-Set Korean, type 'qud' and click
336
// See https://github.com/microsoft/vscode/issues/134254
337
const recorded: IRecorded = {
338
env: { OS: OperatingSystem.Macintosh, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
339
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' },
340
events: [
341
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyQ', ctrlKey: false, isComposing: false, key: 'ㅂ', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
342
{ timeStamp: 7.40, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionstart', data: '' },
343
{ timeStamp: 7.60, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'beforeinput', data: 'ㅂ', inputType: 'insertCompositionText', isComposing: true },
344
{ timeStamp: 7.60, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionupdate', data: 'ㅂ' },
345
{ timeStamp: 8.20, state: { value: 'aaㅂaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 'ㅂ', inputType: 'insertCompositionText', isComposing: true },
346
{ timeStamp: 136.10, state: { value: 'aaㅂaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyQ', ctrlKey: false, isComposing: true, key: 'ㅂ', keyCode: 81, location: 0, metaKey: false, repeat: false, shiftKey: false },
347
{ timeStamp: 680.10, state: { value: 'aaㅂaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyU', ctrlKey: false, isComposing: true, key: 'ㅕ', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
348
{ timeStamp: 687.20, state: { value: 'aaㅂaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: '벼', inputType: 'insertCompositionText', isComposing: true },
349
{ timeStamp: 687.40, state: { value: 'aaㅂaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: '벼' },
350
{ timeStamp: 688.80, state: { value: 'aa벼aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: '벼', inputType: 'insertCompositionText', isComposing: true },
351
{ timeStamp: 768.10, state: { value: 'aa벼aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyU', ctrlKey: false, isComposing: true, key: 'ㅕ', keyCode: 85, location: 0, metaKey: false, repeat: false, shiftKey: false },
352
{ timeStamp: 1768.00, state: { value: 'aa벼aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyD', ctrlKey: false, isComposing: true, key: 'ㅇ', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
353
{ timeStamp: 1775.00, state: { value: 'aa벼aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: '병', inputType: 'insertCompositionText', isComposing: true },
354
{ timeStamp: 1775.10, state: { value: 'aa벼aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: '병' },
355
{ timeStamp: 1775.60, state: { value: 'aa병aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: '병', inputType: 'insertCompositionText', isComposing: true },
356
{ timeStamp: 1928.10, state: { value: 'aa병aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyD', ctrlKey: false, isComposing: true, key: 'ㅇ', keyCode: 68, location: 0, metaKey: false, repeat: false, shiftKey: false },
357
{ timeStamp: 6565.70, state: { value: 'aa병aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionend', data: '병' }
358
],
359
final: { value: 'aa병aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' },
360
};
361
362
const actualOutgoingEvents = await simulateInteraction(recorded);
363
assert.deepStrictEqual(actualOutgoingEvents, [
364
{ type: 'compositionStart', data: '' },
365
{ type: 'type', text: 'ㅂ', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
366
{ type: 'compositionUpdate', data: 'ㅂ' },
367
{ type: 'type', text: '벼', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
368
{ type: 'compositionUpdate', data: '벼' },
369
{ type: 'type', text: '병', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
370
{ type: 'compositionUpdate', data: '병' },
371
{ type: 'type', text: '병', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
372
{ type: 'compositionEnd' }
373
]);
374
375
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
376
assert.deepStrictEqual(actualResultingState, recorded.final);
377
});
378
379
test('macOS - Chrome - Japanese using Hiragana (Google)', async () => {
380
// macOS, Hiragana (Google), type 'sennsei' and Enter
381
const recorded: IRecorded = {
382
env: { OS: OperatingSystem.Macintosh, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
383
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' },
384
events: [
385
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: false, key: 's', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
386
{ timeStamp: 8.50, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionstart', data: '' },
387
{ timeStamp: 8.70, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'beforeinput', data: 's', inputType: 'insertCompositionText', isComposing: true },
388
{ timeStamp: 8.70, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionupdate', data: 's' },
389
{ timeStamp: 9.30, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 's', inputType: 'insertCompositionText', isComposing: true },
390
{ timeStamp: 111.70, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 's', keyCode: 83, location: 0, metaKey: false, repeat: false, shiftKey: false },
391
{ timeStamp: 439.80, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'e', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
392
{ timeStamp: 444.50, state: { value: 'aasaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: 'せ', inputType: 'insertCompositionText', isComposing: true },
393
{ timeStamp: 444.60, state: { value: 'aasaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: 'せ' },
394
{ timeStamp: 445.20, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 'せ', inputType: 'insertCompositionText', isComposing: true },
395
{ timeStamp: 559.90, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: false, shiftKey: false },
396
{ timeStamp: 1943.90, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'n', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
397
{ timeStamp: 1949.30, state: { value: 'aaせaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: 'せn', inputType: 'insertCompositionText', isComposing: true },
398
{ timeStamp: 1949.40, state: { value: 'aaせaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: 'せn' },
399
{ timeStamp: 1949.90, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'input', data: 'せn', inputType: 'insertCompositionText', isComposing: true },
400
{ timeStamp: 2039.90, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'n', keyCode: 78, location: 0, metaKey: false, repeat: false, shiftKey: false },
401
{ timeStamp: 2207.80, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'n', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
402
{ timeStamp: 2215.70, state: { value: 'aaせnaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'none' }, type: 'beforeinput', data: 'せん', inputType: 'insertCompositionText', isComposing: true },
403
{ timeStamp: 2215.80, state: { value: 'aaせnaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'none' }, type: 'compositionupdate', data: 'せん' },
404
{ timeStamp: 2216.10, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'input', data: 'せん', inputType: 'insertCompositionText', isComposing: true },
405
{ timeStamp: 2311.90, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'n', keyCode: 78, location: 0, metaKey: false, repeat: false, shiftKey: false },
406
{ timeStamp: 2551.90, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 's', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
407
{ timeStamp: 2557.00, state: { value: 'aaせんaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'none' }, type: 'beforeinput', data: 'せんs', inputType: 'insertCompositionText', isComposing: true },
408
{ timeStamp: 2557.00, state: { value: 'aaせんaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'none' }, type: 'compositionupdate', data: 'せんs' },
409
{ timeStamp: 2557.40, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'none' }, type: 'input', data: 'せんs', inputType: 'insertCompositionText', isComposing: true },
410
{ timeStamp: 2671.70, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 's', keyCode: 83, location: 0, metaKey: false, repeat: false, shiftKey: false },
411
{ timeStamp: 2903.80, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'e', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
412
{ timeStamp: 2912.30, state: { value: 'aaせんsaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'none' }, type: 'beforeinput', data: 'せんせ', inputType: 'insertCompositionText', isComposing: true },
413
{ timeStamp: 2912.50, state: { value: 'aaせんsaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'none' }, type: 'compositionupdate', data: 'せんせ' },
414
{ timeStamp: 2912.90, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'none' }, type: 'input', data: 'せんせ', inputType: 'insertCompositionText', isComposing: true },
415
{ timeStamp: 3023.90, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: false, shiftKey: false },
416
{ timeStamp: 3519.90, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'i', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
417
{ timeStamp: 3537.10, state: { value: 'aaせんせaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'none' }, type: 'beforeinput', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
418
{ timeStamp: 3537.10, state: { value: 'aaせんせaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'none' }, type: 'compositionupdate', data: 'せんせい' },
419
{ timeStamp: 3537.60, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'none' }, type: 'input', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
420
{ timeStamp: 3639.90, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'i', keyCode: 73, location: 0, metaKey: false, repeat: false, shiftKey: false },
421
{ timeStamp: 4887.80, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: true, key: 'Enter', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
422
{ timeStamp: 4892.80, state: { value: 'aaせんせいaa', selectionStart: 2, selectionEnd: 6, selectionDirection: 'none' }, type: 'beforeinput', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
423
{ timeStamp: 4892.90, state: { value: 'aaせんせいaa', selectionStart: 2, selectionEnd: 6, selectionDirection: 'none' }, type: 'compositionupdate', data: 'せんせい' },
424
{ timeStamp: 4893.00, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'none' }, type: 'input', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
425
{ timeStamp: 4893.00, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'none' }, type: 'compositionend', data: 'せんせい' },
426
{ timeStamp: 4967.80, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: false, key: 'Enter', keyCode: 13, location: 0, metaKey: false, repeat: false, shiftKey: false }
427
],
428
final: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'none' },
429
};
430
431
const actualOutgoingEvents = await simulateInteraction(recorded);
432
assert.deepStrictEqual(actualOutgoingEvents, [
433
{ type: 'compositionStart', data: '' },
434
{ type: 'type', text: 's', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
435
{ type: 'compositionUpdate', data: 's' },
436
{ type: 'type', text: 'せ', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
437
{ type: 'compositionUpdate', data: 'せ' },
438
{ type: 'type', text: 'せn', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
439
{ type: 'compositionUpdate', data: 'せn' },
440
{ type: 'type', text: 'せん', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
441
{ type: 'compositionUpdate', data: 'せん' },
442
{ type: 'type', text: 'せんs', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
443
{ type: 'compositionUpdate', data: 'せんs' },
444
{ type: 'type', text: 'せんせ', replacePrevCharCnt: 3, replaceNextCharCnt: 0, positionDelta: 0 },
445
{ type: 'compositionUpdate', data: 'せんせ' },
446
{ type: 'type', text: 'せんせい', replacePrevCharCnt: 3, replaceNextCharCnt: 0, positionDelta: 0 },
447
{ type: 'compositionUpdate', data: 'せんせい' },
448
{ type: 'type', text: 'せんせい', replacePrevCharCnt: 4, replaceNextCharCnt: 0, positionDelta: 0 },
449
{ type: 'compositionUpdate', data: 'せんせい' },
450
{ type: 'type', text: 'せんせい', replacePrevCharCnt: 4, replaceNextCharCnt: 0, positionDelta: 0 },
451
{ type: 'compositionEnd' }
452
]);
453
454
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
455
assert.deepStrictEqual(actualResultingState, recorded.final);
456
});
457
458
test('macOS - Chrome - Chinese using Pinyin - Traditional', async () => {
459
// macOS, Pinyin - Traditional, type 'xu' and '1'
460
const recorded: IRecorded = {
461
env: { OS: OperatingSystem.Macintosh, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
462
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' },
463
events: [
464
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyX', ctrlKey: false, isComposing: false, key: 'x', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
465
{ timeStamp: 48.70, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionstart', data: '' },
466
{ timeStamp: 48.80, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'beforeinput', data: 'x', inputType: 'insertCompositionText', isComposing: true },
467
{ timeStamp: 48.90, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionupdate', data: 'x' },
468
{ timeStamp: 49.20, state: { value: 'aaxaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 'x', inputType: 'insertCompositionText', isComposing: true },
469
{ timeStamp: 127.80, state: { value: 'aaxaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyX', ctrlKey: false, isComposing: true, key: 'x', keyCode: 88, location: 0, metaKey: false, repeat: false, shiftKey: false },
470
{ timeStamp: 480.00, state: { value: 'aaxaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyU', ctrlKey: false, isComposing: true, key: 'u', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
471
{ timeStamp: 535.60, state: { value: 'aaxaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: 'xu', inputType: 'insertCompositionText', isComposing: true },
472
{ timeStamp: 535.70, state: { value: 'aaxaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: 'xu' },
473
{ timeStamp: 535.90, state: { value: 'aaxuaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'input', data: 'xu', inputType: 'insertCompositionText', isComposing: true },
474
{ timeStamp: 575.80, state: { value: 'aaxuaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyU', ctrlKey: false, isComposing: true, key: 'u', keyCode: 85, location: 0, metaKey: false, repeat: false, shiftKey: false },
475
{ timeStamp: 1055.90, state: { value: 'aaxuaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'Digit1', ctrlKey: false, isComposing: true, key: '1', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
476
{ timeStamp: 1061.70, state: { value: 'aaxuaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'none' }, type: 'beforeinput', data: '需', inputType: 'insertCompositionText', isComposing: true },
477
{ timeStamp: 1061.80, state: { value: 'aaxuaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'none' }, type: 'compositionupdate', data: '需' },
478
{ timeStamp: 1063.20, state: { value: 'aa需aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: '需', inputType: 'insertCompositionText', isComposing: true },
479
{ timeStamp: 1063.30, state: { value: 'aa需aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionend', data: '需' },
480
{ timeStamp: 1207.90, state: { value: 'aa需aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'Digit1', ctrlKey: false, isComposing: false, key: '1', keyCode: 49, location: 0, metaKey: false, repeat: false, shiftKey: false }
481
],
482
final: { value: 'aa需aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' },
483
};
484
485
const actualOutgoingEvents = await simulateInteraction(recorded);
486
assert.deepStrictEqual(actualOutgoingEvents, [
487
{ type: 'compositionStart', data: '' },
488
{ type: 'type', text: 'x', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
489
{ type: 'compositionUpdate', data: 'x' },
490
{ type: 'type', text: 'xu', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
491
{ type: 'compositionUpdate', data: 'xu' },
492
{ type: 'type', text: '需', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
493
{ type: 'compositionUpdate', data: '需' },
494
{ type: 'type', text: '需', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
495
{ type: 'compositionEnd' }
496
]);
497
498
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
499
assert.deepStrictEqual(actualResultingState, recorded.final);
500
});
501
502
test('macOS - Chrome - long press with arrow keys', async () => {
503
// macOS, English, long press o, press arrow right twice and then press Enter
504
// See https://github.com/microsoft/vscode/issues/67739
505
const recorded: IRecorded = {
506
env: { OS: OperatingSystem.Macintosh, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
507
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' },
508
events: [
509
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: false, key: 'o', keyCode: 79, location: 0, metaKey: false, repeat: false, shiftKey: false },
510
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keypress', altKey: false, charCode: 111, code: 'KeyO', ctrlKey: false, isComposing: false, key: 'o', keyCode: 111, location: 0, metaKey: false, repeat: false, shiftKey: false },
511
{ timeStamp: 2.80, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'beforeinput', data: 'o', inputType: 'insertText', isComposing: false },
512
{ timeStamp: 3.40, state: { value: 'aaoaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 'o', inputType: 'insertText', isComposing: false },
513
{ timeStamp: 500.50, state: { value: 'aaoaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: false, key: 'o', keyCode: 79, location: 0, metaKey: false, repeat: true, shiftKey: false },
514
{ timeStamp: 583.90, state: { value: 'aaoaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: false, key: 'o', keyCode: 79, location: 0, metaKey: false, repeat: true, shiftKey: false },
515
{ timeStamp: 667.60, state: { value: 'aaoaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: false, key: 'o', keyCode: 79, location: 0, metaKey: false, repeat: true, shiftKey: false },
516
{ timeStamp: 750.90, state: { value: 'aaoaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: false, key: 'o', keyCode: 79, location: 0, metaKey: false, repeat: true, shiftKey: false },
517
{ timeStamp: 835.00, state: { value: 'aaoaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: false, key: 'o', keyCode: 79, location: 0, metaKey: false, repeat: true, shiftKey: false },
518
{ timeStamp: 856.10, state: { value: 'aaoaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: false, key: 'o', keyCode: 79, location: 0, metaKey: false, repeat: false, shiftKey: false },
519
{ timeStamp: 1952.10, state: { value: 'aaoaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'ArrowRight', ctrlKey: false, isComposing: false, key: 'ArrowRight', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
520
{ timeStamp: 1956.50, state: { value: 'aaoaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionstart', data: 'o' },
521
{ timeStamp: 1956.80, state: { value: 'aaoaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: 'ô', inputType: 'insertCompositionText', isComposing: true },
522
{ timeStamp: 1956.90, state: { value: 'aaoaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: 'ô' },
523
{ timeStamp: 1960.60, state: { value: 'aaôaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 'ô', inputType: 'insertCompositionText', isComposing: true },
524
{ timeStamp: 2088.10, state: { value: 'aaôaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'ArrowRight', ctrlKey: false, isComposing: true, key: 'ArrowRight', keyCode: 39, location: 0, metaKey: false, repeat: false, shiftKey: false },
525
{ timeStamp: 2480.10, state: { value: 'aaôaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'ArrowRight', ctrlKey: false, isComposing: true, key: 'ArrowRight', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
526
{ timeStamp: 2484.30, state: { value: 'aaôaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: 'ö', inputType: 'insertCompositionText', isComposing: true },
527
{ timeStamp: 2484.40, state: { value: 'aaôaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: 'ö' },
528
{ timeStamp: 2484.70, state: { value: 'aaöaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 'ö', inputType: 'insertCompositionText', isComposing: true },
529
{ timeStamp: 2584.20, state: { value: 'aaöaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'ArrowRight', ctrlKey: false, isComposing: true, key: 'ArrowRight', keyCode: 39, location: 0, metaKey: false, repeat: false, shiftKey: false },
530
{ timeStamp: 6424.20, state: { value: 'aaöaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: true, key: 'Enter', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
531
{ timeStamp: 6431.70, state: { value: 'aaöaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: 'ö', inputType: 'insertCompositionText', isComposing: true },
532
{ timeStamp: 6431.70, state: { value: 'aaöaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: 'ö' },
533
{ timeStamp: 6431.80, state: { value: 'aaöaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 'ö', inputType: 'insertCompositionText', isComposing: true },
534
{ timeStamp: 6431.90, state: { value: 'aaöaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionend', data: 'ö' },
535
{ timeStamp: 6496.20, state: { value: 'aaöaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: false, key: 'Enter', keyCode: 13, location: 0, metaKey: false, repeat: false, shiftKey: false }
536
],
537
final: { value: 'aaöaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' },
538
};
539
540
const actualOutgoingEvents = await simulateInteraction(recorded);
541
assert.deepStrictEqual(actualOutgoingEvents, [
542
{ type: 'type', text: 'o', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
543
{ type: 'compositionStart', data: 'o' },
544
{ type: 'type', text: 'ô', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
545
{ type: 'compositionUpdate', data: 'ô' },
546
{ type: 'type', text: 'ö', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
547
{ type: 'compositionUpdate', data: 'ö' },
548
{ type: 'type', text: 'ö', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
549
{ type: 'compositionUpdate', data: 'ö' },
550
{ type: 'type', text: 'ö', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
551
{ type: 'compositionEnd' }
552
]);
553
554
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
555
assert.deepStrictEqual(actualResultingState, recorded.final);
556
});
557
558
test('macOS - Chrome - pressing quotes on US Intl', async () => {
559
// macOS, US International - PC, press ', ', ;
560
const recorded: IRecorded = {
561
env: { OS: OperatingSystem.Macintosh, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
562
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' },
563
events: [
564
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'Quote', ctrlKey: false, isComposing: false, key: 'Dead', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
565
{ timeStamp: 2.80, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionstart', data: '' },
566
{ timeStamp: 3.10, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'beforeinput', data: '\'', inputType: 'insertCompositionText', isComposing: true },
567
{ timeStamp: 3.20, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionupdate', data: '\'' },
568
{ timeStamp: 3.70, state: { value: 'aa\'aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: '\'', inputType: 'insertCompositionText', isComposing: true },
569
{ timeStamp: 71.90, state: { value: 'aa\'aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'Quote', ctrlKey: false, isComposing: true, key: 'Dead', keyCode: 222, location: 0, metaKey: false, repeat: false, shiftKey: false },
570
{ timeStamp: 144.00, state: { value: 'aa\'aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'Quote', ctrlKey: false, isComposing: true, key: 'Dead', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
571
{ timeStamp: 146.20, state: { value: 'aa\'aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: '\'', inputType: 'insertCompositionText', isComposing: true },
572
{ timeStamp: 146.40, state: { value: 'aa\'aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: '\'' },
573
{ timeStamp: 146.70, state: { value: 'aa\'aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: '\'', inputType: 'insertCompositionText', isComposing: true },
574
{ timeStamp: 146.80, state: { value: 'aa\'aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionend', data: '\'' },
575
{ timeStamp: 147.20, state: { value: 'aa\'aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionstart', data: '' },
576
{ timeStamp: 147.20, state: { value: 'aa\'aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: '\'', inputType: 'insertCompositionText', isComposing: true },
577
{ timeStamp: 147.70, state: { value: 'aa\'aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionupdate', data: '\'' },
578
{ timeStamp: 148.20, state: { value: 'aa\'\'aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'input', data: '\'', inputType: 'insertCompositionText', isComposing: true },
579
{ timeStamp: 208.10, state: { value: 'aa\'\'aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'Quote', ctrlKey: false, isComposing: true, key: 'Dead', keyCode: 222, location: 0, metaKey: false, repeat: false, shiftKey: false },
580
{ timeStamp: 323.70, state: { value: 'aa\'\'aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'Semicolon', ctrlKey: false, isComposing: true, key: ';', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
581
{ timeStamp: 325.70, state: { value: 'aa\'\'aa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'none' }, type: 'beforeinput', data: '\';', inputType: 'insertCompositionText', isComposing: true },
582
{ timeStamp: 325.80, state: { value: 'aa\'\'aa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'none' }, type: 'compositionupdate', data: '\';' },
583
{ timeStamp: 326.30, state: { value: 'aa\'\';aa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'none' }, type: 'input', data: '\';', inputType: 'insertCompositionText', isComposing: true },
584
{ timeStamp: 326.30, state: { value: 'aa\'\';aa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'none' }, type: 'compositionend', data: '\';' },
585
{ timeStamp: 428.00, state: { value: 'aa\'\';aa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'Semicolon', ctrlKey: false, isComposing: false, key: ';', keyCode: 186, location: 0, metaKey: false, repeat: false, shiftKey: false }
586
],
587
final: { value: 'aa\'\';aa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'none' },
588
};
589
590
const actualOutgoingEvents = await simulateInteraction(recorded);
591
assert.deepStrictEqual(actualOutgoingEvents, ([
592
{ type: "compositionStart", data: "" },
593
{ type: "type", text: "'", replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
594
{ type: "compositionUpdate", data: "'" },
595
{ type: "type", text: "'", replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
596
{ type: "compositionUpdate", data: "'" },
597
{ type: "type", text: "'", replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
598
{ type: "compositionEnd" },
599
{ type: "compositionStart", data: "" },
600
{ type: "type", text: "'", replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
601
{ type: "compositionUpdate", data: "'" },
602
{ type: "type", text: "';", replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
603
{ type: "compositionUpdate", data: "';" },
604
{ type: "type", text: "';", replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
605
{ type: "compositionEnd" }
606
]));
607
608
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
609
assert.deepStrictEqual(actualResultingState, recorded.final);
610
});
611
612
test('macOS - Chrome - inserting emoji using ctrl+cmd+space', async () => {
613
// macOS, English, press ctrl+cmd+space, and then pick an emoji using the mouse
614
// See https://github.com/microsoft/vscode/issues/4271
615
const recorded: IRecorded = {
616
env: { OS: OperatingSystem.Macintosh, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
617
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' },
618
events: [
619
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'ControlLeft', ctrlKey: true, isComposing: false, key: 'Control', keyCode: 17, location: 1, metaKey: false, repeat: false, shiftKey: false },
620
{ timeStamp: 600.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'MetaLeft', ctrlKey: true, isComposing: false, key: 'Meta', keyCode: 91, location: 1, metaKey: true, repeat: false, shiftKey: false },
621
{ timeStamp: 1080.10, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'Space', ctrlKey: true, isComposing: false, key: ' ', keyCode: 32, location: 0, metaKey: true, repeat: false, shiftKey: false },
622
{ timeStamp: 1247.90, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'MetaLeft', ctrlKey: true, isComposing: false, key: 'Meta', keyCode: 91, location: 1, metaKey: false, repeat: false, shiftKey: false },
623
{ timeStamp: 1263.80, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: true, isComposing: false, key: ' ', keyCode: 32, location: 0, metaKey: false, repeat: false, shiftKey: false },
624
{ timeStamp: 1367.80, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'ControlLeft', ctrlKey: false, isComposing: false, key: 'Control', keyCode: 17, location: 1, metaKey: false, repeat: false, shiftKey: false },
625
{ timeStamp: 17962.90, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'beforeinput', data: '🥳', inputType: 'insertText', isComposing: false },
626
{ timeStamp: 17966.60, state: { value: 'aa🥳aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'input', data: '🥳', inputType: 'insertText', isComposing: false }
627
],
628
final: { value: 'aa🥳aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' },
629
};
630
631
const actualOutgoingEvents = await simulateInteraction(recorded);
632
assert.deepStrictEqual(actualOutgoingEvents, ([
633
{ type: 'type', text: '🥳', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 }
634
]));
635
636
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
637
assert.deepStrictEqual(actualResultingState, recorded.final);
638
});
639
640
test('macOS - Firefox - long press with mouse', async () => {
641
// macOS, English, long press e and choose using mouse
642
// See https://github.com/microsoft/monaco-editor/issues/2358
643
const recorded: IRecorded = {
644
env: { OS: OperatingSystem.Macintosh, browser: { isAndroid: false, isFirefox: true, isChrome: false, isSafari: false } },
645
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
646
events: [
647
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: false, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: false, shiftKey: false },
648
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keypress', altKey: false, charCode: 101, code: 'KeyE', ctrlKey: false, isComposing: false, key: 'e', keyCode: 101, location: 0, metaKey: false, repeat: false, shiftKey: false },
649
{ timeStamp: 7.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: 'e', inputType: 'insertText', isComposing: false },
650
{ timeStamp: 7.00, state: { value: 'aaeaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'e', inputType: 'insertText', isComposing: false },
651
{ timeStamp: 500.00, state: { value: 'aaeaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: false, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: true, shiftKey: false },
652
{ timeStamp: 667.00, state: { value: 'aaeaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: false, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: true, shiftKey: false },
653
{ timeStamp: 750.00, state: { value: 'aaeaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: false, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: true, shiftKey: false },
654
{ timeStamp: 834.00, state: { value: 'aaeaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: false, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: true, shiftKey: false },
655
{ timeStamp: 917.00, state: { value: 'aaeaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: false, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: true, shiftKey: false },
656
{ timeStamp: 1001.00, state: { value: 'aaeaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: false, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: true, shiftKey: false },
657
{ timeStamp: 1024.00, state: { value: 'aaeaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: false, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: false, shiftKey: false },
658
{ timeStamp: 2988.00, state: { value: 'aaeaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'è', inputType: 'insertText', isComposing: false },
659
{ timeStamp: 2988.00, state: { value: 'aaèaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'è', inputType: 'insertText', isComposing: false }
660
],
661
final: { value: 'aaèaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' },
662
};
663
664
const actualOutgoingEvents = await simulateInteraction(recorded);
665
assert.deepStrictEqual(actualOutgoingEvents, [
666
{ type: 'type', text: 'e', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
667
{ type: 'type', text: 'è', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 }
668
]);
669
670
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
671
assert.deepStrictEqual(actualResultingState, recorded.final);
672
});
673
674
test('macOS - Firefox - inserting emojis', async () => {
675
// macOS, English, from the edit menu, click Emoji & Symbols, select an emoji
676
// See https://github.com/microsoft/vscode/issues/106392
677
const recorded: IRecorded = {
678
env: { OS: OperatingSystem.Macintosh, browser: { isAndroid: false, isFirefox: true, isChrome: false, isSafari: false } },
679
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
680
events: [
681
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: '😍', inputType: 'insertText', isComposing: false },
682
{ timeStamp: 1.00, state: { value: 'aa😍aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '😍', inputType: 'insertText', isComposing: false }
683
],
684
final: { value: 'aa😍aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' },
685
};
686
687
const actualOutgoingEvents = await simulateInteraction(recorded);
688
assert.deepStrictEqual(actualOutgoingEvents, [
689
{ type: 'type', text: '😍', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 }
690
]);
691
692
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
693
assert.deepStrictEqual(actualResultingState, recorded.final);
694
});
695
696
test('macOS - Safari - Chinese - issue #119469', async () => {
697
const recorded: IRecorded = {
698
env: { 'OS': OperatingSystem.Macintosh, 'browser': { 'isAndroid': false, 'isFirefox': false, 'isChrome': false, 'isSafari': true } },
699
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' },
700
events: [
701
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionstart', data: '' },
702
{ timeStamp: 1.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'compositionupdate', data: 'f' },
703
{ timeStamp: 1.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'beforeinput', data: 'f', inputType: 'insertCompositionText', isComposing: undefined },
704
{ timeStamp: 2.00, state: { value: 'aafaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 'f', inputType: 'insertCompositionText', isComposing: undefined },
705
{ timeStamp: -30.00, state: { value: 'aafaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyF', ctrlKey: false, isComposing: true, key: 'f', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
706
{ timeStamp: 106.00, state: { value: 'aafaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyF', ctrlKey: false, isComposing: true, key: 'f', keyCode: 70, location: 0, metaKey: false, repeat: false, shiftKey: false },
707
{ timeStamp: 721.00, state: { value: 'aafaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: null, inputType: 'deleteCompositionText', isComposing: undefined },
708
{ timeStamp: 723.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'input', data: null, inputType: 'deleteCompositionText', isComposing: undefined },
709
{ timeStamp: 723.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'none' }, type: 'beforeinput', data: 'f', inputType: 'insertFromComposition', isComposing: undefined },
710
{ timeStamp: 723.00, state: { value: 'aafaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'input', data: 'f', inputType: 'insertFromComposition', isComposing: undefined },
711
{ timeStamp: 723.00, state: { value: 'aafaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'compositionend', data: 'f' },
712
{ timeStamp: 698.00, state: { value: 'aafaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: false, key: 'Enter', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
713
{ timeStamp: 826.00, state: { value: 'aafaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: false, key: 'Enter', keyCode: 13, location: 0, metaKey: false, repeat: false, shiftKey: false },
714
{ timeStamp: 1114.00, state: { value: 'aafaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keydown', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: false, key: 'Enter', keyCode: 13, location: 0, metaKey: false, repeat: false, shiftKey: false },
715
{ timeStamp: 1114.00, state: { value: 'aafaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'keypress', altKey: false, charCode: 13, code: 'Enter', ctrlKey: false, isComposing: false, key: 'Enter', keyCode: 13, location: 0, metaKey: false, repeat: false, shiftKey: false },
716
{ timeStamp: 1137.00, state: { value: 'aafaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'none' }, type: 'beforeinput', data: null, inputType: 'insertLineBreak', isComposing: undefined },
717
{ timeStamp: 1138.00, state: { value: 'aaf\naa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'input', data: null, inputType: 'insertLineBreak', isComposing: undefined },
718
{ timeStamp: 1250.00, state: { value: 'aaf\naa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none' }, type: 'keyup', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: false, key: 'Enter', keyCode: 13, location: 0, metaKey: false, repeat: false, shiftKey: false }
719
],
720
final: {
721
value: 'aaf\naa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'none'
722
},
723
};
724
725
const actualOutgoingEvents = await simulateInteraction(recorded);
726
assert.deepStrictEqual(actualOutgoingEvents, ([
727
{ type: 'compositionStart', data: '' },
728
{ type: 'type', text: 'f', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
729
{ type: 'compositionUpdate', data: 'f' },
730
{ type: 'type', text: 'f', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
731
{ type: 'compositionEnd' },
732
{ type: 'type', text: '\n', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 }
733
]));
734
735
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
736
assert.deepStrictEqual(actualResultingState, recorded.final);
737
});
738
739
test('Windows - Chrome - Japanese using Hiragana', async () => {
740
// Windows, Japanese/Hiragana, type 'sennsei' and Enter
741
const recorded: IRecorded = {
742
env: { OS: OperatingSystem.Windows, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
743
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
744
events: [
745
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
746
{ timeStamp: 0.80, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
747
{ timeStamp: 0.80, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: 's', inputType: 'insertCompositionText', isComposing: true },
748
{ timeStamp: 0.90, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionupdate', data: 's' },
749
{ timeStamp: 9.30, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 's', inputType: 'insertCompositionText', isComposing: true },
750
{ timeStamp: 97.50, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
751
{ timeStamp: 99.10, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 's', keyCode: 83, location: 0, metaKey: false, repeat: false, shiftKey: false },
752
{ timeStamp: 615.90, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
753
{ timeStamp: 619.80, state: { value: 'aasaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せ', inputType: 'insertCompositionText', isComposing: true },
754
{ timeStamp: 619.80, state: { value: 'aasaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せ' },
755
{ timeStamp: 627.70, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'せ', inputType: 'insertCompositionText', isComposing: true },
756
{ timeStamp: 719.90, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
757
{ timeStamp: 723.60, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: false, shiftKey: false },
758
{ timeStamp: 1816.10, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
759
{ timeStamp: 1828.30, state: { value: 'aaせaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せn', inputType: 'insertCompositionText', isComposing: true },
760
{ timeStamp: 1828.40, state: { value: 'aaせaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せn' },
761
{ timeStamp: 1828.70, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: 'せn', inputType: 'insertCompositionText', isComposing: true },
762
{ timeStamp: 1903.70, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
763
{ timeStamp: 1904.70, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'n', keyCode: 78, location: 0, metaKey: false, repeat: false, shiftKey: false },
764
{ timeStamp: 2111.70, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
765
{ timeStamp: 2123.40, state: { value: 'aaせnaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せん', inputType: 'insertCompositionText', isComposing: true },
766
{ timeStamp: 2123.40, state: { value: 'aaせnaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せん' },
767
{ timeStamp: 2123.70, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: 'せん', inputType: 'insertCompositionText', isComposing: true },
768
{ timeStamp: 2215.80, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
769
{ timeStamp: 2217.10, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'n', keyCode: 78, location: 0, metaKey: false, repeat: false, shiftKey: false },
770
{ timeStamp: 2968.00, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
771
{ timeStamp: 2970.00, state: { value: 'aaせんaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せんs', inputType: 'insertCompositionText', isComposing: true },
772
{ timeStamp: 2970.00, state: { value: 'aaせんaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せんs' },
773
{ timeStamp: 2970.20, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'input', data: 'せんs', inputType: 'insertCompositionText', isComposing: true },
774
{ timeStamp: 3079.70, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
775
{ timeStamp: 3080.70, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 's', keyCode: 83, location: 0, metaKey: false, repeat: false, shiftKey: false },
776
{ timeStamp: 3295.20, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
777
{ timeStamp: 3297.10, state: { value: 'aaせんsaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せんせ', inputType: 'insertCompositionText', isComposing: true },
778
{ timeStamp: 3297.20, state: { value: 'aaせんsaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せんせ' },
779
{ timeStamp: 3297.40, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'input', data: 'せんせ', inputType: 'insertCompositionText', isComposing: true },
780
{ timeStamp: 3408.00, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
781
{ timeStamp: 3409.00, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: false, shiftKey: false },
782
{ timeStamp: 3880.80, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
783
{ timeStamp: 3882.80, state: { value: 'aaせんせaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
784
{ timeStamp: 3882.90, state: { value: 'aaせんせaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せんせい' },
785
{ timeStamp: 3883.30, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'input', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
786
{ timeStamp: 3976.30, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
787
{ timeStamp: 3977.50, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'i', keyCode: 73, location: 0, metaKey: false, repeat: false, shiftKey: false },
788
{ timeStamp: 6364.90, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
789
{ timeStamp: 6367.40, state: { value: 'aaせんせいaa', selectionStart: 2, selectionEnd: 6, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
790
{ timeStamp: 6367.40, state: { value: 'aaせんせいaa', selectionStart: 2, selectionEnd: 6, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せんせい' },
791
{ timeStamp: 6367.60, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'input', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
792
{ timeStamp: 6367.60, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'compositionend', data: 'せんせい' },
793
{ timeStamp: 6479.60, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false }
794
],
795
final: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' },
796
};
797
798
const actualOutgoingEvents = await simulateInteraction(recorded);
799
assert.deepStrictEqual(actualOutgoingEvents, [
800
{ type: 'compositionStart', data: '' },
801
{ type: 'type', text: 's', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
802
{ type: 'compositionUpdate', data: 's' },
803
{ type: 'type', text: 'せ', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
804
{ type: 'compositionUpdate', data: 'せ' },
805
{ type: 'type', text: 'せn', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
806
{ type: 'compositionUpdate', data: 'せn' },
807
{ type: 'type', text: 'せん', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
808
{ type: 'compositionUpdate', data: 'せん' },
809
{ type: 'type', text: 'せんs', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
810
{ type: 'compositionUpdate', data: 'せんs' },
811
{ type: 'type', text: 'せんせ', replacePrevCharCnt: 3, replaceNextCharCnt: 0, positionDelta: 0 },
812
{ type: 'compositionUpdate', data: 'せんせ' },
813
{ type: 'type', text: 'せんせい', replacePrevCharCnt: 3, replaceNextCharCnt: 0, positionDelta: 0 },
814
{ type: 'compositionUpdate', data: 'せんせい' },
815
{ type: 'type', text: 'せんせい', replacePrevCharCnt: 4, replaceNextCharCnt: 0, positionDelta: 0 },
816
{ type: 'compositionUpdate', data: 'せんせい' },
817
{ type: 'type', text: 'せんせい', replacePrevCharCnt: 4, replaceNextCharCnt: 0, positionDelta: 0 },
818
{ type: 'compositionEnd' }
819
]);
820
821
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
822
assert.deepStrictEqual(actualResultingState, recorded.final);
823
});
824
825
test('Windows 11 - Chrome - Japanese using Hiragana', async () => {
826
// Windows, Japanese/Hiragana, type 'sennsei' and Enter
827
const recorded: IRecorded = {
828
env: { OS: OperatingSystem.Windows, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
829
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
830
events: [
831
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
832
{ timeStamp: 15.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
833
{ timeStamp: 15.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: 's', inputType: 'insertCompositionText', isComposing: true },
834
{ timeStamp: 15.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionupdate', data: 's' },
835
{ timeStamp: 20.00, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 's', inputType: 'insertCompositionText', isComposing: true },
836
{ timeStamp: 111.00, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
837
{ timeStamp: 111.00, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 's', keyCode: 83, location: 0, metaKey: false, repeat: false, shiftKey: false },
838
{ timeStamp: 832.00, state: { value: 'aasaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
839
{ timeStamp: 839.00, state: { value: 'aasaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せ', inputType: 'insertCompositionText', isComposing: true },
840
{ timeStamp: 839.00, state: { value: 'aasaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せ' },
841
{ timeStamp: 890.00, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'せ', inputType: 'insertCompositionText', isComposing: true },
842
{ timeStamp: 936.00, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
843
{ timeStamp: 937.00, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: false, shiftKey: false },
844
{ timeStamp: 1456.00, state: { value: 'aaせaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
845
{ timeStamp: 1460.00, state: { value: 'aaせaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せn', inputType: 'insertCompositionText', isComposing: true },
846
{ timeStamp: 1460.00, state: { value: 'aaせaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せn' },
847
{ timeStamp: 1461.00, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: 'せn', inputType: 'insertCompositionText', isComposing: true },
848
{ timeStamp: 1522.00, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
849
{ timeStamp: 1522.00, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'n', keyCode: 78, location: 0, metaKey: false, repeat: false, shiftKey: false },
850
{ timeStamp: 1684.00, state: { value: 'aaせnaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
851
{ timeStamp: 1694.00, state: { value: 'aaせnaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せん', inputType: 'insertCompositionText', isComposing: true },
852
{ timeStamp: 1694.00, state: { value: 'aaせnaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せん' },
853
{ timeStamp: 1694.00, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: 'せん', inputType: 'insertCompositionText', isComposing: true },
854
{ timeStamp: 1763.00, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
855
{ timeStamp: 1763.00, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'n', keyCode: 78, location: 0, metaKey: false, repeat: false, shiftKey: false },
856
{ timeStamp: 1873.00, state: { value: 'aaせんaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
857
{ timeStamp: 1878.00, state: { value: 'aaせんaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せんs', inputType: 'insertCompositionText', isComposing: true },
858
{ timeStamp: 1878.00, state: { value: 'aaせんaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せんs' },
859
{ timeStamp: 1878.00, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'input', data: 'せんs', inputType: 'insertCompositionText', isComposing: true },
860
{ timeStamp: 1969.00, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
861
{ timeStamp: 1969.00, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 's', keyCode: 83, location: 0, metaKey: false, repeat: false, shiftKey: false },
862
{ timeStamp: 2094.00, state: { value: 'aaせんsaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
863
{ timeStamp: 2111.00, state: { value: 'aaせんsaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せんせ', inputType: 'insertCompositionText', isComposing: true },
864
{ timeStamp: 2111.00, state: { value: 'aaせんsaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せんせ' },
865
{ timeStamp: 2111.00, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'input', data: 'せんせ', inputType: 'insertCompositionText', isComposing: true },
866
{ timeStamp: 2222.00, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
867
{ timeStamp: 2222.00, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyE', ctrlKey: false, isComposing: true, key: 'e', keyCode: 69, location: 0, metaKey: false, repeat: false, shiftKey: false },
868
{ timeStamp: 2356.00, state: { value: 'aaせんせaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
869
{ timeStamp: 2367.00, state: { value: 'aaせんせaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
870
{ timeStamp: 2367.00, state: { value: 'aaせんせaa', selectionStart: 2, selectionEnd: 5, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せんせい' },
871
{ timeStamp: 2367.00, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'input', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
872
{ timeStamp: 2456.00, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
873
{ timeStamp: 2456.00, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'i', keyCode: 73, location: 0, metaKey: false, repeat: false, shiftKey: false },
874
{ timeStamp: 3776.00, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
875
{ timeStamp: 3776.00, state: { value: 'aaせんせいaa', selectionStart: 2, selectionEnd: 6, selectionDirection: 'forward' }, type: 'beforeinput', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
876
{ timeStamp: 3776.00, state: { value: 'aaせんせいaa', selectionStart: 2, selectionEnd: 6, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'せんせい' },
877
{ timeStamp: 3785.00, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'input', data: 'せんせい', inputType: 'insertCompositionText', isComposing: true },
878
{ timeStamp: 3785.00, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'compositionend', data: 'せんせい' },
879
{ timeStamp: 3886.00, state: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Enter', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false }
880
],
881
final: { value: 'aaせんせいaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' },
882
};
883
884
const actualOutgoingEvents = await simulateInteraction(recorded);
885
assert.deepStrictEqual(actualOutgoingEvents, ([
886
{ type: 'compositionStart', data: '' },
887
{ type: 'type', text: 's', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
888
{ type: 'compositionUpdate', data: 's' },
889
{ type: 'type', text: 'せ', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
890
{ type: 'compositionUpdate', data: 'せ' },
891
{ type: 'type', text: 'せn', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
892
{ type: 'compositionUpdate', data: 'せn' },
893
{ type: 'type', text: 'せん', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
894
{ type: 'compositionUpdate', data: 'せん' },
895
{ type: 'type', text: 'せんs', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
896
{ type: 'compositionUpdate', data: 'せんs' },
897
{ type: 'type', text: 'せんせ', replacePrevCharCnt: 3, replaceNextCharCnt: 0, positionDelta: 0 },
898
{ type: 'compositionUpdate', data: 'せんせ' },
899
{ type: 'type', text: 'せんせい', replacePrevCharCnt: 3, replaceNextCharCnt: 0, positionDelta: 0 },
900
{ type: 'compositionUpdate', data: 'せんせい' },
901
{ type: 'type', text: 'せんせい', replacePrevCharCnt: 4, replaceNextCharCnt: 0, positionDelta: 0 },
902
{ type: 'compositionUpdate', data: 'せんせい' },
903
{ type: 'type', text: 'せんせい', replacePrevCharCnt: 4, replaceNextCharCnt: 0, positionDelta: 0 },
904
{ type: 'compositionEnd' }
905
]));
906
907
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
908
assert.deepStrictEqual(actualResultingState, recorded.final);
909
});
910
911
test('Windows - Chrome - Korean (1)', async () => {
912
// Windows, Korean, type 'dkrk' and click
913
const recorded: IRecorded = {
914
env: { OS: OperatingSystem.Windows, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
915
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
916
events: [
917
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyD', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
918
{ timeStamp: 23.10, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
919
{ timeStamp: 23.10, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ㅇ', inputType: 'insertCompositionText', isComposing: true },
920
{ timeStamp: 23.20, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ㅇ' },
921
{ timeStamp: 23.60, state: { value: 'aaㅇaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'ㅇ', inputType: 'insertCompositionText', isComposing: true },
922
{ timeStamp: 119.30, state: { value: 'aaㅇaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyD', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
923
{ timeStamp: 215.00, state: { value: 'aaㅇaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
924
{ timeStamp: 215.40, state: { value: 'aaㅇaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '아', inputType: 'insertCompositionText', isComposing: true },
925
{ timeStamp: 215.40, state: { value: 'aaㅇaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '아' },
926
{ timeStamp: 215.90, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '아', inputType: 'insertCompositionText', isComposing: true },
927
{ timeStamp: 303.20, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
928
{ timeStamp: 511.10, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
929
{ timeStamp: 511.70, state: { value: 'aa아aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '악', inputType: 'insertCompositionText', isComposing: true },
930
{ timeStamp: 511.70, state: { value: 'aa아aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '악' },
931
{ timeStamp: 512.10, state: { value: 'aa악aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '악', inputType: 'insertCompositionText', isComposing: true },
932
{ timeStamp: 598.20, state: { value: 'aa악aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
933
{ timeStamp: 791.00, state: { value: 'aa악aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
934
{ timeStamp: 791.50, state: { value: 'aa악aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '아', inputType: 'insertCompositionText', isComposing: true },
935
{ timeStamp: 791.50, state: { value: 'aa악aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '아' },
936
{ timeStamp: 791.80, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '아', inputType: 'insertCompositionText', isComposing: true },
937
{ timeStamp: 791.90, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionend', data: '아' },
938
{ timeStamp: 792.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
939
{ timeStamp: 792.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '가', inputType: 'insertCompositionText', isComposing: true },
940
{ timeStamp: 792.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '가' },
941
{ timeStamp: 792.30, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '가', inputType: 'insertCompositionText', isComposing: true },
942
{ timeStamp: 919.00, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
943
{ timeStamp: 2721.50, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionend', data: '가' }
944
],
945
final: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' },
946
};
947
948
const actualOutgoingEvents = await simulateInteraction(recorded);
949
assert.deepStrictEqual(actualOutgoingEvents, [
950
{ type: 'compositionStart', data: '' },
951
{ type: 'type', text: 'ㅇ', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
952
{ type: 'compositionUpdate', data: 'ㅇ' },
953
{ type: 'type', text: '아', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
954
{ type: 'compositionUpdate', data: '아' },
955
{ type: 'type', text: '악', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
956
{ type: 'compositionUpdate', data: '악' },
957
{ type: 'type', text: '아', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
958
{ type: 'compositionUpdate', data: '아' },
959
{ type: 'type', text: '아', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
960
{ type: 'compositionEnd' },
961
{ type: 'compositionStart', data: '' },
962
{ type: 'type', text: '가', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
963
{ type: 'compositionUpdate', data: '가' },
964
{ type: 'type', text: '가', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
965
{ type: 'compositionEnd' }
966
]);
967
968
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
969
assert.deepStrictEqual(actualResultingState, recorded.final);
970
});
971
972
test('Windows 11 - Chrome - Korean (1)', async () => {
973
// Windows, Korean, type 'dkrk' and Space
974
const recorded: IRecorded = {
975
env: { OS: OperatingSystem.Windows, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
976
977
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
978
events: [
979
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyD', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
980
{ timeStamp: 9.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
981
{ timeStamp: 10.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ㅇ', inputType: 'insertCompositionText', isComposing: true },
982
{ timeStamp: 10.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ㅇ' },
983
{ timeStamp: 26.00, state: { value: 'aaㅇaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'ㅇ', inputType: 'insertCompositionText', isComposing: true },
984
{ timeStamp: 119.00, state: { value: 'aaㅇaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyD', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
985
{ timeStamp: 134.00, state: { value: 'aaㅇaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyD', ctrlKey: false, isComposing: true, key: 'd', keyCode: 68, location: 0, metaKey: false, repeat: false, shiftKey: false },
986
{ timeStamp: 442.00, state: { value: 'aaㅇaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
987
{ timeStamp: 442.00, state: { value: 'aaㅇaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '아', inputType: 'insertCompositionText', isComposing: true },
988
{ timeStamp: 442.00, state: { value: 'aaㅇaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '아' },
989
{ timeStamp: 451.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '아', inputType: 'insertCompositionText', isComposing: true },
990
{ timeStamp: 535.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
991
{ timeStamp: 535.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'k', keyCode: 75, location: 0, metaKey: false, repeat: false, shiftKey: false },
992
{ timeStamp: 879.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
993
{ timeStamp: 879.00, state: { value: 'aa아aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '악', inputType: 'insertCompositionText', isComposing: true },
994
{ timeStamp: 879.00, state: { value: 'aa아aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '악' },
995
{ timeStamp: 881.00, state: { value: 'aa악aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '악', inputType: 'insertCompositionText', isComposing: true },
996
{ timeStamp: 980.00, state: { value: 'aa악aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
997
{ timeStamp: 992.00, state: { value: 'aa악aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'r', keyCode: 82, location: 0, metaKey: false, repeat: false, shiftKey: false },
998
{ timeStamp: 1230.00, state: { value: 'aa악aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
999
{ timeStamp: 1230.00, state: { value: 'aa악aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '아', inputType: 'insertCompositionText', isComposing: true },
1000
{ timeStamp: 1230.00, state: { value: 'aa악aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '아' },
1001
{ timeStamp: 1242.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '아', inputType: 'insertCompositionText', isComposing: true },
1002
{ timeStamp: 1242.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionend', data: '아' },
1003
{ timeStamp: 1242.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
1004
{ timeStamp: 1242.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '가', inputType: 'insertCompositionText', isComposing: true },
1005
{ timeStamp: 1242.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '가' },
1006
{ timeStamp: 1243.00, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '가', inputType: 'insertCompositionText', isComposing: true },
1007
{ timeStamp: 1375.00, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1008
{ timeStamp: 1375.00, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'k', keyCode: 75, location: 0, metaKey: false, repeat: false, shiftKey: false },
1009
{ timeStamp: 3412.00, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionend', data: '가' },
1010
{ timeStamp: 3412.00, state: { value: 'aa아가aa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: null, inputType: 'deleteContentBackward', isComposing: false },
1011
{ timeStamp: 3413.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: null, inputType: 'deleteContentBackward', isComposing: false },
1012
{ timeStamp: 3413.00, state: { value: 'aa아aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '가', inputType: 'insertText', isComposing: false },
1013
{ timeStamp: 3414.00, state: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '가', inputType: 'insertText', isComposing: false }
1014
],
1015
final: { value: 'aa아가aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' },
1016
};
1017
1018
const actualOutgoingEvents = await simulateInteraction(recorded);
1019
assert.deepStrictEqual(actualOutgoingEvents, [
1020
{ type: 'compositionStart', data: '' },
1021
{ type: 'type', text: 'ㅇ', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1022
{ type: 'compositionUpdate', data: 'ㅇ' },
1023
{ type: 'type', text: '아', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1024
{ type: 'compositionUpdate', data: '아' },
1025
{ type: 'type', text: '악', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1026
{ type: 'compositionUpdate', data: '악' },
1027
{ type: 'type', text: '아', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1028
{ type: 'compositionUpdate', data: '아' },
1029
{ type: 'type', text: '아', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1030
{ type: 'compositionEnd' },
1031
{ type: 'compositionStart', data: '' },
1032
{ type: 'type', text: '가', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1033
{ type: 'compositionUpdate', data: '가' },
1034
{ type: 'type', text: '가', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1035
{ type: 'compositionEnd' },
1036
{ type: 'type', text: '', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1037
{ type: 'type', text: '가', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 }
1038
]);
1039
1040
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
1041
assert.deepStrictEqual(actualResultingState, recorded.final);
1042
});
1043
1044
test('Windows - Chrome - Korean (2)', async () => {
1045
// Windows, Korean, type 'gksrmf' and Space
1046
const recorded: IRecorded = {
1047
env: { OS: OperatingSystem.Windows, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
1048
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
1049
events: [
1050
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyG', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1051
{ timeStamp: 23.30, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
1052
{ timeStamp: 23.50, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ㅎ', inputType: 'insertCompositionText', isComposing: true },
1053
{ timeStamp: 23.50, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ㅎ' },
1054
{ timeStamp: 27.30, state: { value: 'aaㅎaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'ㅎ', inputType: 'insertCompositionText', isComposing: true },
1055
{ timeStamp: 111.80, state: { value: 'aaㅎaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyG', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1056
{ timeStamp: 606.80, state: { value: 'aaㅎaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1057
{ timeStamp: 607.40, state: { value: 'aaㅎaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '하', inputType: 'insertCompositionText', isComposing: true },
1058
{ timeStamp: 607.40, state: { value: 'aaㅎaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '하' },
1059
{ timeStamp: 607.80, state: { value: 'aa하aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '하', inputType: 'insertCompositionText', isComposing: true },
1060
{ timeStamp: 705.20, state: { value: 'aa하aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1061
{ timeStamp: 1455.80, state: { value: 'aa하aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1062
{ timeStamp: 1456.40, state: { value: 'aa하aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '한', inputType: 'insertCompositionText', isComposing: true },
1063
{ timeStamp: 1456.50, state: { value: 'aa하aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '한' },
1064
{ timeStamp: 1456.90, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '한', inputType: 'insertCompositionText', isComposing: true },
1065
{ timeStamp: 1567.40, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1066
{ timeStamp: 1963.10, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1067
{ timeStamp: 1963.70, state: { value: 'aa한aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '한', inputType: 'insertCompositionText', isComposing: true },
1068
{ timeStamp: 1963.80, state: { value: 'aa한aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '한' },
1069
{ timeStamp: 1963.80, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '한', inputType: 'insertCompositionText', isComposing: true },
1070
{ timeStamp: 1963.90, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionend', data: '한' },
1071
{ timeStamp: 1964.10, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
1072
{ timeStamp: 1964.10, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ㄱ', inputType: 'insertCompositionText', isComposing: true },
1073
{ timeStamp: 1964.10, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ㄱ' },
1074
{ timeStamp: 1964.40, state: { value: 'aa한ㄱaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: 'ㄱ', inputType: 'insertCompositionText', isComposing: true },
1075
{ timeStamp: 2063.60, state: { value: 'aa한ㄱaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1076
{ timeStamp: 2823.60, state: { value: 'aa한ㄱaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyM', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1077
{ timeStamp: 2824.00, state: { value: 'aa한ㄱaa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: '그', inputType: 'insertCompositionText', isComposing: true },
1078
{ timeStamp: 2824.10, state: { value: 'aa한ㄱaa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: '그' },
1079
{ timeStamp: 2824.40, state: { value: 'aa한그aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '그', inputType: 'insertCompositionText', isComposing: true },
1080
{ timeStamp: 2935.30, state: { value: 'aa한그aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyM', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1081
{ timeStamp: 3187.50, state: { value: 'aa한그aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyF', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1082
{ timeStamp: 3188.00, state: { value: 'aa한그aa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: '글', inputType: 'insertCompositionText', isComposing: true },
1083
{ timeStamp: 3188.00, state: { value: 'aa한그aa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: '글' },
1084
{ timeStamp: 3188.40, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '글', inputType: 'insertCompositionText', isComposing: true },
1085
{ timeStamp: 3319.20, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyF', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1086
{ timeStamp: 3847.30, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1087
{ timeStamp: 3847.80, state: { value: 'aa한글aa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: '글', inputType: 'insertCompositionText', isComposing: true },
1088
{ timeStamp: 3847.80, state: { value: 'aa한글aa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: '글' },
1089
{ timeStamp: 3847.90, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '글', inputType: 'insertCompositionText', isComposing: true },
1090
{ timeStamp: 3848.10, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionend', data: '글' },
1091
{ timeStamp: 3847.70, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: ' ', keyCode: 32, location: 0, metaKey: false, repeat: false, shiftKey: false },
1092
{ timeStamp: 3847.80, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keypress', altKey: false, charCode: 32, code: 'Space', ctrlKey: false, isComposing: false, key: ' ', keyCode: 32, location: 0, metaKey: false, repeat: false, shiftKey: false },
1093
{ timeStamp: 3848.30, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: ' ', inputType: 'insertText', isComposing: false },
1094
{ timeStamp: 3848.60, state: { value: 'aa한글 aa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'input', data: ' ', inputType: 'insertText', isComposing: false },
1095
{ timeStamp: 3919.20, state: { value: 'aa한글 aa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1096
{ timeStamp: 3919.50, state: { value: 'aa한글 aa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: ' ', keyCode: 32, location: 0, metaKey: false, repeat: false, shiftKey: false }
1097
],
1098
final: { value: 'aa한글 aa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' },
1099
};
1100
1101
const actualOutgoingEvents = await simulateInteraction(recorded);
1102
assert.deepStrictEqual(actualOutgoingEvents, [
1103
{ type: 'compositionStart', data: '' },
1104
{ type: 'type', text: 'ㅎ', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1105
{ type: 'compositionUpdate', data: 'ㅎ' },
1106
{ type: 'type', text: '하', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1107
{ type: 'compositionUpdate', data: '하' },
1108
{ type: 'type', text: '한', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1109
{ type: 'compositionUpdate', data: '한' },
1110
{ type: 'type', text: '한', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1111
{ type: 'compositionUpdate', data: '한' },
1112
{ type: 'type', text: '한', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1113
{ type: 'compositionEnd' },
1114
{ type: 'compositionStart', data: '' },
1115
{ type: 'type', text: 'ㄱ', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1116
{ type: 'compositionUpdate', data: 'ㄱ' },
1117
{ type: 'type', text: '그', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1118
{ type: 'compositionUpdate', data: '그' },
1119
{ type: 'type', text: '글', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1120
{ type: 'compositionUpdate', data: '글' },
1121
{ type: 'type', text: '글', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1122
{ type: 'compositionUpdate', data: '글' },
1123
{ type: 'type', text: '글', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1124
{ type: 'compositionEnd' },
1125
{ type: 'type', text: ' ', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 }
1126
]);
1127
1128
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
1129
assert.deepStrictEqual(actualResultingState, recorded.final);
1130
});
1131
1132
test('Windows 11 - Chrome - Korean (2)', async () => {
1133
// Windows, Korean, type 'gksrmf' and Space
1134
const recorded: IRecorded = {
1135
env: { OS: OperatingSystem.Windows, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
1136
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
1137
events: [
1138
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'ControlLeft', ctrlKey: false, isComposing: false, key: 'Control', keyCode: 17, location: 1, metaKey: false, repeat: false, shiftKey: false },
1139
{ timeStamp: 1561.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyG', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1140
{ timeStamp: 1566.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
1141
{ timeStamp: 1566.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ㅎ', inputType: 'insertCompositionText', isComposing: true },
1142
{ timeStamp: 1566.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ㅎ' },
1143
{ timeStamp: 1567.00, state: { value: 'aaㅎaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'ㅎ', inputType: 'insertCompositionText', isComposing: true },
1144
{ timeStamp: 1681.00, state: { value: 'aaㅎaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyG', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1145
{ timeStamp: 1681.00, state: { value: 'aaㅎaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyG', ctrlKey: false, isComposing: true, key: 'g', keyCode: 71, location: 0, metaKey: false, repeat: false, shiftKey: false },
1146
{ timeStamp: 2013.00, state: { value: 'aaㅎaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1147
{ timeStamp: 2013.00, state: { value: 'aaㅎaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '하', inputType: 'insertCompositionText', isComposing: true },
1148
{ timeStamp: 2013.00, state: { value: 'aaㅎaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '하' },
1149
{ timeStamp: 2013.00, state: { value: 'aa하aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '하', inputType: 'insertCompositionText', isComposing: true },
1150
{ timeStamp: 2096.00, state: { value: 'aa하aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1151
{ timeStamp: 2096.00, state: { value: 'aa하aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'k', keyCode: 75, location: 0, metaKey: false, repeat: false, shiftKey: false },
1152
{ timeStamp: 2457.00, state: { value: 'aa하aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1153
{ timeStamp: 2457.00, state: { value: 'aa하aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '한', inputType: 'insertCompositionText', isComposing: true },
1154
{ timeStamp: 2457.00, state: { value: 'aa하aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '한' },
1155
{ timeStamp: 2457.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '한', inputType: 'insertCompositionText', isComposing: true },
1156
{ timeStamp: 2568.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1157
{ timeStamp: 2568.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyS', ctrlKey: false, isComposing: true, key: 's', keyCode: 83, location: 0, metaKey: false, repeat: false, shiftKey: false },
1158
{ timeStamp: 3066.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1159
{ timeStamp: 3066.00, state: { value: 'aa한aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '한', inputType: 'insertCompositionText', isComposing: true },
1160
{ timeStamp: 3066.00, state: { value: 'aa한aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '한' },
1161
{ timeStamp: 3066.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '한', inputType: 'insertCompositionText', isComposing: true },
1162
{ timeStamp: 3066.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionend', data: '한' },
1163
{ timeStamp: 3070.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
1164
{ timeStamp: 3070.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ㄱ', inputType: 'insertCompositionText', isComposing: true },
1165
{ timeStamp: 3070.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ㄱ' },
1166
{ timeStamp: 3071.00, state: { value: 'aa한ㄱaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: 'ㄱ', inputType: 'insertCompositionText', isComposing: true },
1167
{ timeStamp: 3180.00, state: { value: 'aa한ㄱaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1168
{ timeStamp: 3180.00, state: { value: 'aa한ㄱaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'r', keyCode: 82, location: 0, metaKey: false, repeat: false, shiftKey: false },
1169
{ timeStamp: 3650.00, state: { value: 'aa한ㄱaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyM', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1170
{ timeStamp: 3650.00, state: { value: 'aa한ㄱaa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: '그', inputType: 'insertCompositionText', isComposing: true },
1171
{ timeStamp: 3650.00, state: { value: 'aa한ㄱaa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: '그' },
1172
{ timeStamp: 3650.00, state: { value: 'aa한그aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '그', inputType: 'insertCompositionText', isComposing: true },
1173
{ timeStamp: 3753.00, state: { value: 'aa한그aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyM', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1174
{ timeStamp: 3768.00, state: { value: 'aa한그aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyM', ctrlKey: false, isComposing: true, key: 'm', keyCode: 77, location: 0, metaKey: false, repeat: false, shiftKey: false },
1175
{ timeStamp: 4554.00, state: { value: 'aa한그aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyF', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1176
{ timeStamp: 4554.00, state: { value: 'aa한그aa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: '글', inputType: 'insertCompositionText', isComposing: true },
1177
{ timeStamp: 4554.00, state: { value: 'aa한그aa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: '글' },
1178
{ timeStamp: 4558.00, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '글', inputType: 'insertCompositionText', isComposing: true },
1179
{ timeStamp: 4685.00, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyF', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1180
{ timeStamp: 4685.00, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyF', ctrlKey: false, isComposing: true, key: 'f', keyCode: 70, location: 0, metaKey: false, repeat: false, shiftKey: false },
1181
{ timeStamp: 6632.00, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionend', data: '글' },
1182
{ timeStamp: 6634.00, state: { value: 'aa한글aa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: null, inputType: 'deleteContentBackward', isComposing: false },
1183
{ timeStamp: 6634.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: null, inputType: 'deleteContentBackward', isComposing: false },
1184
{ timeStamp: 6634.00, state: { value: 'aa한aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '글', inputType: 'insertText', isComposing: false },
1185
{ timeStamp: 6634.00, state: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '글', inputType: 'insertText', isComposing: false }
1186
],
1187
final: { value: 'aa한글aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' },
1188
1189
};
1190
1191
const actualOutgoingEvents = await simulateInteraction(recorded);
1192
assert.deepStrictEqual(actualOutgoingEvents, [
1193
{ type: 'compositionStart', data: '' },
1194
{ type: 'type', text: 'ㅎ', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1195
{ type: 'compositionUpdate', data: 'ㅎ' },
1196
{ type: 'type', text: '하', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1197
{ type: 'compositionUpdate', data: '하' },
1198
{ type: 'type', text: '한', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1199
{ type: 'compositionUpdate', data: '한' },
1200
{ type: 'type', text: '한', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1201
{ type: 'compositionUpdate', data: '한' },
1202
{ type: 'type', text: '한', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1203
{ type: 'compositionEnd' },
1204
{ type: 'compositionStart', data: '' },
1205
{ type: 'type', text: 'ㄱ', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1206
{ type: 'compositionUpdate', data: 'ㄱ' },
1207
{ type: 'type', text: '그', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1208
{ type: 'compositionUpdate', data: '그' },
1209
{ type: 'type', text: '글', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1210
{ type: 'compositionUpdate', data: '글' },
1211
{ type: 'type', text: '글', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1212
{ type: 'compositionEnd' },
1213
{ type: 'type', text: '', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1214
{ type: 'type', text: '글', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 }
1215
]);
1216
1217
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
1218
assert.deepStrictEqual(actualResultingState, recorded.final);
1219
});
1220
1221
test('Windows - Chrome - Chinese', async () => {
1222
// Windows, Chinese, Type 'ni' press Space and then 'hao' and press Space.
1223
const recorded: IRecorded = {
1224
env: { OS: OperatingSystem.Windows, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
1225
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
1226
events: [
1227
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1228
{ timeStamp: 0.80, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
1229
{ timeStamp: 0.90, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: 'n', inputType: 'insertCompositionText', isComposing: true },
1230
{ timeStamp: 1.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'n' },
1231
{ timeStamp: 1.20, state: { value: 'aanaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'n', inputType: 'insertCompositionText', isComposing: true },
1232
{ timeStamp: 66.80, state: { value: 'aanaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1233
{ timeStamp: 67.90, state: { value: 'aanaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'n', keyCode: 78, location: 0, metaKey: false, repeat: false, shiftKey: false },
1234
{ timeStamp: 466.70, state: { value: 'aanaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1235
{ timeStamp: 470.10, state: { value: 'aanaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ni', inputType: 'insertCompositionText', isComposing: true },
1236
{ timeStamp: 470.20, state: { value: 'aanaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ni' },
1237
{ timeStamp: 470.50, state: { value: 'aaniaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: 'ni', inputType: 'insertCompositionText', isComposing: true },
1238
{ timeStamp: 563.20, state: { value: 'aaniaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1239
{ timeStamp: 564.20, state: { value: 'aaniaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'i', keyCode: 73, location: 0, metaKey: false, repeat: false, shiftKey: false },
1240
{ timeStamp: 1835.00, state: { value: 'aaniaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1241
{ timeStamp: 1837.20, state: { value: 'aaniaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: '你', inputType: 'insertCompositionText', isComposing: true },
1242
{ timeStamp: 1837.30, state: { value: 'aaniaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: '你' },
1243
{ timeStamp: 1837.70, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '你', inputType: 'insertCompositionText', isComposing: true },
1244
{ timeStamp: 1837.80, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionend', data: '你' },
1245
{ timeStamp: 1914.90, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1246
{ timeStamp: 1916.10, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: ' ', keyCode: 32, location: 0, metaKey: false, repeat: false, shiftKey: false },
1247
{ timeStamp: 3000.40, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyH', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1248
{ timeStamp: 3000.80, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
1249
{ timeStamp: 3000.80, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'h', inputType: 'insertCompositionText', isComposing: true },
1250
{ timeStamp: 3000.90, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'h' },
1251
{ timeStamp: 3001.30, state: { value: 'aa你haa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: 'h', inputType: 'insertCompositionText', isComposing: true },
1252
{ timeStamp: 3091.60, state: { value: 'aa你haa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyH', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1253
{ timeStamp: 3092.60, state: { value: 'aa你haa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyH', ctrlKey: false, isComposing: true, key: 'h', keyCode: 72, location: 0, metaKey: false, repeat: false, shiftKey: false },
1254
{ timeStamp: 3131.50, state: { value: 'aa你haa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyA', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1255
{ timeStamp: 3134.80, state: { value: 'aa你haa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ha', inputType: 'insertCompositionText', isComposing: true },
1256
{ timeStamp: 3134.80, state: { value: 'aa你haa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ha' },
1257
{ timeStamp: 3135.10, state: { value: 'aa你haaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'input', data: 'ha', inputType: 'insertCompositionText', isComposing: true },
1258
{ timeStamp: 3234.90, state: { value: 'aa你haaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyA', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1259
{ timeStamp: 3236.20, state: { value: 'aa你haaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyA', ctrlKey: false, isComposing: true, key: 'a', keyCode: 65, location: 0, metaKey: false, repeat: false, shiftKey: false },
1260
{ timeStamp: 3491.70, state: { value: 'aa你haaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1261
{ timeStamp: 3494.80, state: { value: 'aa你haaa', selectionStart: 3, selectionEnd: 5, selectionDirection: 'forward' }, type: 'beforeinput', data: 'hao', inputType: 'insertCompositionText', isComposing: true },
1262
{ timeStamp: 3495.00, state: { value: 'aa你haaa', selectionStart: 3, selectionEnd: 5, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'hao' },
1263
{ timeStamp: 3495.40, state: { value: 'aa你haoaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'input', data: 'hao', inputType: 'insertCompositionText', isComposing: true },
1264
{ timeStamp: 3570.70, state: { value: 'aa你haoaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1265
{ timeStamp: 3572.40, state: { value: 'aa你haoaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: true, key: 'o', keyCode: 79, location: 0, metaKey: false, repeat: false, shiftKey: false },
1266
{ timeStamp: 4739.00, state: { value: 'aa你haoaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1267
{ timeStamp: 4742.10, state: { value: 'aa你haoaa', selectionStart: 3, selectionEnd: 6, selectionDirection: 'forward' }, type: 'beforeinput', data: '好', inputType: 'insertCompositionText', isComposing: true },
1268
{ timeStamp: 4742.10, state: { value: 'aa你haoaa', selectionStart: 3, selectionEnd: 6, selectionDirection: 'forward' }, type: 'compositionupdate', data: '好' },
1269
{ timeStamp: 4742.50, state: { value: 'aa你好aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '好', inputType: 'insertCompositionText', isComposing: true },
1270
{ timeStamp: 4742.60, state: { value: 'aa你好aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionend', data: '好' },
1271
{ timeStamp: 4834.70, state: { value: 'aa你好aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1272
{ timeStamp: 4836.00, state: { value: 'aa你好aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: ' ', keyCode: 32, location: 0, metaKey: false, repeat: false, shiftKey: false }
1273
],
1274
final: { value: 'aa你好aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' },
1275
};
1276
1277
const actualOutgoingEvents = await simulateInteraction(recorded);
1278
assert.deepStrictEqual(actualOutgoingEvents, [
1279
{ type: 'compositionStart', data: '' },
1280
{ type: 'type', text: 'n', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1281
{ type: 'compositionUpdate', data: 'n' },
1282
{ type: 'type', text: 'ni', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1283
{ type: 'compositionUpdate', data: 'ni' },
1284
{ type: 'type', text: '你', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
1285
{ type: 'compositionUpdate', data: '你' },
1286
{ type: 'type', text: '你', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1287
{ type: 'compositionEnd' },
1288
{ type: 'compositionStart', data: '' },
1289
{ type: 'type', text: 'h', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1290
{ type: 'compositionUpdate', data: 'h' },
1291
{ type: 'type', text: 'ha', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1292
{ type: 'compositionUpdate', data: 'ha' },
1293
{ type: 'type', text: 'hao', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
1294
{ type: 'compositionUpdate', data: 'hao' },
1295
{ type: 'type', text: '好', replacePrevCharCnt: 3, replaceNextCharCnt: 0, positionDelta: 0 },
1296
{ type: 'compositionUpdate', data: '好' },
1297
{ type: 'type', text: '好', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1298
{ type: 'compositionEnd' }
1299
]);
1300
1301
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
1302
assert.deepStrictEqual(actualResultingState, recorded.final);
1303
});
1304
1305
test('Windows 11 - Chrome - Chinese', async () => {
1306
// Windows, Chinese, Type 'ni' press Space and then 'hao' and press Space.
1307
const recorded: IRecorded = {
1308
env: { OS: OperatingSystem.Windows, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
1309
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
1310
events: [
1311
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1312
{ timeStamp: 1.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
1313
{ timeStamp: 1.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: 'n', inputType: 'insertCompositionText', isComposing: true },
1314
{ timeStamp: 1.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'n' },
1315
{ timeStamp: 1.00, state: { value: 'aanaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'n', inputType: 'insertCompositionText', isComposing: true },
1316
{ timeStamp: 63.00, state: { value: 'aanaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1317
{ timeStamp: 63.00, state: { value: 'aanaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyN', ctrlKey: false, isComposing: true, key: 'n', keyCode: 78, location: 0, metaKey: false, repeat: false, shiftKey: false },
1318
{ timeStamp: 331.00, state: { value: 'aanaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1319
{ timeStamp: 331.00, state: { value: 'aanaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ni', inputType: 'insertCompositionText', isComposing: true },
1320
{ timeStamp: 331.00, state: { value: 'aanaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ni' },
1321
{ timeStamp: 342.00, state: { value: 'aaniaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: 'ni', inputType: 'insertCompositionText', isComposing: true },
1322
{ timeStamp: 403.00, state: { value: 'aaniaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1323
{ timeStamp: 403.00, state: { value: 'aaniaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyI', ctrlKey: false, isComposing: true, key: 'i', keyCode: 73, location: 0, metaKey: false, repeat: false, shiftKey: false },
1324
{ timeStamp: 614.00, state: { value: 'aaniaa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1325
{ timeStamp: 617.00, state: { value: 'aaniaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: '你', inputType: 'insertCompositionText', isComposing: true },
1326
{ timeStamp: 617.00, state: { value: 'aaniaa', selectionStart: 2, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: '你' },
1327
{ timeStamp: 657.00, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '你', inputType: 'insertCompositionText', isComposing: true },
1328
{ timeStamp: 658.00, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionend', data: '你' },
1329
{ timeStamp: 715.00, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1330
{ timeStamp: 715.00, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: ' ', keyCode: 32, location: 0, metaKey: false, repeat: false, shiftKey: false },
1331
{ timeStamp: 1117.00, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyH', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1332
{ timeStamp: 1117.00, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
1333
{ timeStamp: 1117.00, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: 'h', inputType: 'insertCompositionText', isComposing: true },
1334
{ timeStamp: 1117.00, state: { value: 'aa你aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'h' },
1335
{ timeStamp: 1117.00, state: { value: 'aa你haa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: 'h', inputType: 'insertCompositionText', isComposing: true },
1336
{ timeStamp: 1199.00, state: { value: 'aa你haa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyH', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1337
{ timeStamp: 1199.00, state: { value: 'aa你haa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyH', ctrlKey: false, isComposing: true, key: 'h', keyCode: 72, location: 0, metaKey: false, repeat: false, shiftKey: false },
1338
{ timeStamp: 1317.00, state: { value: 'aa你haa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyA', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1339
{ timeStamp: 1322.00, state: { value: 'aa你haa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ha', inputType: 'insertCompositionText', isComposing: true },
1340
{ timeStamp: 1322.00, state: { value: 'aa你haa', selectionStart: 3, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ha' },
1341
{ timeStamp: 1328.00, state: { value: 'aa你haaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'input', data: 'ha', inputType: 'insertCompositionText', isComposing: true },
1342
{ timeStamp: 1419.00, state: { value: 'aa你haaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyA', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1343
{ timeStamp: 1419.00, state: { value: 'aa你haaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyA', ctrlKey: false, isComposing: true, key: 'a', keyCode: 65, location: 0, metaKey: false, repeat: false, shiftKey: false },
1344
{ timeStamp: 1592.00, state: { value: 'aa你haaa', selectionStart: 5, selectionEnd: 5, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1345
{ timeStamp: 1592.00, state: { value: 'aa你haaa', selectionStart: 3, selectionEnd: 5, selectionDirection: 'forward' }, type: 'beforeinput', data: 'hao', inputType: 'insertCompositionText', isComposing: true },
1346
{ timeStamp: 1592.00, state: { value: 'aa你haaa', selectionStart: 3, selectionEnd: 5, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'hao' },
1347
{ timeStamp: 1606.00, state: { value: 'aa你haoaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'input', data: 'hao', inputType: 'insertCompositionText', isComposing: true },
1348
{ timeStamp: 1666.00, state: { value: 'aa你haoaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1349
{ timeStamp: 1681.00, state: { value: 'aa你haoaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyO', ctrlKey: false, isComposing: true, key: 'o', keyCode: 79, location: 0, metaKey: false, repeat: false, shiftKey: false },
1350
{ timeStamp: 2187.00, state: { value: 'aa你haoaa', selectionStart: 6, selectionEnd: 6, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: true, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1351
{ timeStamp: 2187.00, state: { value: 'aa你haoaa', selectionStart: 3, selectionEnd: 6, selectionDirection: 'forward' }, type: 'beforeinput', data: '好', inputType: 'insertCompositionText', isComposing: true },
1352
{ timeStamp: 2187.00, state: { value: 'aa你haoaa', selectionStart: 3, selectionEnd: 6, selectionDirection: 'forward' }, type: 'compositionupdate', data: '好' },
1353
{ timeStamp: 2199.00, state: { value: 'aa你好aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'input', data: '好', inputType: 'insertCompositionText', isComposing: true },
1354
{ timeStamp: 2199.00, state: { value: 'aa你好aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'compositionend', data: '好' },
1355
{ timeStamp: 2315.00, state: { value: 'aa你好aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: 'Process', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1356
{ timeStamp: 2323.00, state: { value: 'aa你好aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'Space', ctrlKey: false, isComposing: false, key: ' ', keyCode: 32, location: 0, metaKey: false, repeat: false, shiftKey: false }
1357
],
1358
final: { value: 'aa你好aa', selectionStart: 4, selectionEnd: 4, selectionDirection: 'forward' },
1359
};
1360
1361
const actualOutgoingEvents = await simulateInteraction(recorded);
1362
assert.deepStrictEqual(actualOutgoingEvents, [
1363
{ type: 'compositionStart', data: '' },
1364
{ type: 'type', text: 'n', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1365
{ type: 'compositionUpdate', data: 'n' },
1366
{ type: 'type', text: 'ni', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1367
{ type: 'compositionUpdate', data: 'ni' },
1368
{ type: 'type', text: '你', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
1369
{ type: 'compositionUpdate', data: '你' },
1370
{ type: 'type', text: '你', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1371
{ type: 'compositionEnd' },
1372
{ type: 'compositionStart', data: '' },
1373
{ type: 'type', text: 'h', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1374
{ type: 'compositionUpdate', data: 'h' },
1375
{ type: 'type', text: 'ha', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1376
{ type: 'compositionUpdate', data: 'ha' },
1377
{ type: 'type', text: 'hao', replacePrevCharCnt: 2, replaceNextCharCnt: 0, positionDelta: 0 },
1378
{ type: 'compositionUpdate', data: 'hao' },
1379
{ type: 'type', text: '好', replacePrevCharCnt: 3, replaceNextCharCnt: 0, positionDelta: 0 },
1380
{ type: 'compositionUpdate', data: '好' },
1381
{ type: 'type', text: '好', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1382
{ type: 'compositionEnd' }
1383
]);
1384
1385
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
1386
assert.deepStrictEqual(actualResultingState, recorded.final);
1387
});
1388
1389
test('Linux - Chrome - Korean', async () => {
1390
// Linux, fcitx Hangul, Type 'rkr' and then click.
1391
const recorded: IRecorded = {
1392
env: { OS: OperatingSystem.Linux, browser: { isAndroid: false, isFirefox: false, isChrome: true, isSafari: false } },
1393
initial: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' },
1394
events: [
1395
{ timeStamp: 0.00, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: '', ctrlKey: false, isComposing: false, key: 'Unidentified', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1396
{ timeStamp: 1.20, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionstart', data: '' },
1397
{ timeStamp: 1.30, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'beforeinput', data: 'ㄱ', inputType: 'insertCompositionText', isComposing: true },
1398
{ timeStamp: 1.40, state: { value: 'aaaa', selectionStart: 2, selectionEnd: 2, selectionDirection: 'forward' }, type: 'compositionupdate', data: 'ㄱ' },
1399
{ timeStamp: 1.70, state: { value: 'aaㄱaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: 'ㄱ', inputType: 'insertCompositionText', isComposing: true },
1400
{ timeStamp: 104.50, state: { value: 'aaㄱaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'r', keyCode: 82, location: 0, metaKey: false, repeat: false, shiftKey: false },
1401
{ timeStamp: 150.60, state: { value: 'aaㄱaa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: '', ctrlKey: false, isComposing: true, key: 'Unidentified', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1402
{ timeStamp: 151.30, state: { value: 'aaㄱaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '가', inputType: 'insertCompositionText', isComposing: true },
1403
{ timeStamp: 151.40, state: { value: 'aaㄱaa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '가' },
1404
{ timeStamp: 151.80, state: { value: 'aa가aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '가', inputType: 'insertCompositionText', isComposing: true },
1405
{ timeStamp: 248.50, state: { value: 'aa가aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyK', ctrlKey: false, isComposing: true, key: 'k', keyCode: 75, location: 0, metaKey: false, repeat: false, shiftKey: false },
1406
{ timeStamp: 322.90, state: { value: 'aa가aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keydown', altKey: false, charCode: 0, code: '', ctrlKey: false, isComposing: true, key: 'Unidentified', keyCode: 229, location: 0, metaKey: false, repeat: false, shiftKey: false },
1407
{ timeStamp: 323.70, state: { value: 'aa가aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'beforeinput', data: '각', inputType: 'insertCompositionText', isComposing: true },
1408
{ timeStamp: 323.90, state: { value: 'aa가aa', selectionStart: 2, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionupdate', data: '각' },
1409
{ timeStamp: 324.10, state: { value: 'aa각aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'input', data: '각', inputType: 'insertCompositionText', isComposing: true },
1410
{ timeStamp: 448.50, state: { value: 'aa각aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'keyup', altKey: false, charCode: 0, code: 'KeyR', ctrlKey: false, isComposing: true, key: 'r', keyCode: 82, location: 0, metaKey: false, repeat: false, shiftKey: false },
1411
{ timeStamp: 1761.00, state: { value: 'aa각aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' }, type: 'compositionend', data: '각' }
1412
],
1413
final: { value: 'aa각aa', selectionStart: 3, selectionEnd: 3, selectionDirection: 'forward' },
1414
};
1415
1416
const actualOutgoingEvents = await simulateInteraction(recorded);
1417
assert.deepStrictEqual(actualOutgoingEvents, [
1418
{ type: 'compositionStart', data: '' },
1419
{ type: 'type', text: 'ㄱ', replacePrevCharCnt: 0, replaceNextCharCnt: 0, positionDelta: 0 },
1420
{ type: 'compositionUpdate', data: 'ㄱ' },
1421
{ type: 'type', text: '가', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1422
{ type: 'compositionUpdate', data: '가' },
1423
{ type: 'type', text: '각', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1424
{ type: 'compositionUpdate', data: '각' },
1425
{ type: 'type', text: '각', replacePrevCharCnt: 1, replaceNextCharCnt: 0, positionDelta: 0 },
1426
{ type: 'compositionEnd' }
1427
]);
1428
1429
const actualResultingState = interpretTypeEvents(recorded.env.OS, recorded.env.browser, recorded.initial, actualOutgoingEvents);
1430
assert.deepStrictEqual(actualResultingState, recorded.final);
1431
});
1432
1433
});
1434
1435