gecko/dom/inputmethod/mochitest/test_bug1137557.html
Tim Chien 758988db97 Bug 1137557 - Part 3: Allow content to pass a dict representing the property of the keyboard event to send. r=masayuki, sr=smaug
- Overloading MozInputContext#sendKey() so it could take a dict.
- An optional trailing argument for setComposition() and endComposition() methods for these methods to take the dict.
- New keydown() and keyup() methods that takes dict as the only argument.
2015-08-23 21:19:00 -04:00

1675 lines
44 KiB
HTML

<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1137557
-->
<head>
<title>Test for new API arguments accepting D3E properties</title>
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1137557">Mozilla Bug 1137557</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
inputmethod_setup(function() {
runTest();
});
let gEventDetails = [];
let gCurrentValue = '';
let gTestDescription = '';
let appFrameScript = function appFrameScript() {
let input = content.document.body.firstElementChild;
input.focus();
function sendEventDetail(evt) {
var eventDetail;
switch (evt.type) {
case 'compositionstart':
case 'compositionupdate':
case 'compositionend':
eventDetail = {
type: evt.type,
value: input.value,
data: evt.data
};
break;
case 'input':
eventDetail = {
type: evt.type,
value: input.value
};
break;
default: // keyboard events
eventDetail = {
type: evt.type,
charCode: evt.charCode,
keyCode: evt.keyCode,
key: evt.key,
code: evt.code,
location: evt.location,
repeat: evt.repeat,
value: input.value,
shift: evt.getModifierState('Shift'),
capsLock: evt.getModifierState('CapsLock'),
control: evt.getModifierState('Control'),
alt: evt.getModifierState('Alt')
};
break;
}
sendAsyncMessage('test:eventDetail', eventDetail);
}
input.addEventListener('compositionstart', sendEventDetail);
input.addEventListener('compositionupdate', sendEventDetail);
input.addEventListener('compositionend', sendEventDetail);
input.addEventListener('input', sendEventDetail);
input.addEventListener('keydown', sendEventDetail);
input.addEventListener('keypress', sendEventDetail);
input.addEventListener('keyup', sendEventDetail);
};
function waitForInputContextChange() {
return new Promise((resolve) => {
navigator.mozInputMethod.oninputcontextchange = resolve;
});
}
function assertEventDetail(expectedDetails, testName) {
is(gEventDetails.length, expectedDetails.length,
testName + ' expects ' + expectedDetails.map(d => d.type).join(', ') + ' events, got ' + gEventDetails.map(d => d.type).join(', '));
expectedDetails.forEach((expectedDetail, j) => {
for (let key in expectedDetail) {
is(gEventDetails[j][key], expectedDetail[key],
testName + ' expects ' + key + ' of ' + gEventDetails[j].type + ' to be equal to ' + expectedDetail[key]);
}
});
}
function sendKeyAndAssertResult(testdata) {
var dict = testdata.dict;
var testName = gTestDescription + 'sendKey(' + JSON.stringify(dict) + ')';
var promise = navigator.mozInputMethod.inputcontext.sendKey(dict);
if (testdata.expectedReject) {
promise = promise
.then(() => {
ok(false, testName + ' should not resolve.');
}, (e) => {
ok(true, testName + ' rejects.');
ok(e instanceof testdata.expectedReject, 'Reject with type.');
})
return promise;
}
promise = promise
.then((res) => {
is(res, true,
testName + ' should resolve to true.');
var expectedEventDetail = [];
var expectedValues = testdata.expectedValues;
expectedEventDetail.push({
type: 'keydown',
key: expectedValues.key,
charCode: 0,
code: expectedValues.code || '',
keyCode: expectedValues.keyCode || 0,
location: 0,
repeat: expectedValues.repeat || false,
value: gCurrentValue,
shift: false,
capsLock: false,
control: false,
alt: false
});
if (testdata.expectedKeypress) {
expectedEventDetail.push({
type: 'keypress',
key: expectedValues.key,
charCode: expectedValues.charCode,
code: expectedValues.code || '',
keyCode: expectedValues.charCode ? 0 : expectedValues.keyCode,
location: 0,
repeat: expectedValues.repeat || false,
value: gCurrentValue,
shift: false,
capsLock: false,
control: false,
alt: false
});
}
if (testdata.expectedInput) {
expectedEventDetail.push({
type: 'input',
value: gCurrentValue += testdata.expectedInput
});
}
if (!testdata.expectedRepeat) {
expectedEventDetail.push({
type: 'keyup',
key: expectedValues.key,
charCode: 0,
code: expectedValues.code || '',
keyCode: expectedValues.keyCode || 0,
location: 0,
repeat: expectedValues.repeat || false,
value: gCurrentValue,
shift: false,
capsLock: false,
control: false,
alt: false
});
}
assertEventDetail(expectedEventDetail, testName);
gEventDetails = [];
}, (e) => {
ok(false, testName + ' should not reject. ' + e);
});
return promise;
}
function runSendKeyAlphabetTests() {
gTestDescription = 'runSendKeyAlphabetTests(): ';
var promiseQueue = Promise.resolve();
// Test the plain alphabets
var codeA = 'A'.charCodeAt(0);
for (var i = 0; i < 26; i++) {
// callbacks in then() are deferred; must only reference these block-scoped
// variable instead of i.
let keyCode = codeA + i;
let code = 'Key' + String.fromCharCode(keyCode);
[String.fromCharCode(keyCode),
String.fromCharCode(keyCode).toLowerCase()]
.forEach((chr) => {
// Test plain alphabet
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain alphabet with keyCode set
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: keyCode
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain alphabet with keyCode set to keyCode + 1,
// expects keyCode to follow key value and ignore the incorrect value.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: keyCode + 1
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain alphabet with code set
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: code
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: code,
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain alphabet with code set to Digit1,
// expects keyCode to follow key value.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'Digit1'
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'Digit1',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain alphabet with keyCode set to DOM_VK_1,
// expects keyCode to follow key value.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: KeyboardEvent.DOM_VK_1
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain alphabet with code set to Digit1
// and keyCode set to DOM_VK_1,
// expects keyCode to follow key value.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'Digit1',
keyCode: KeyboardEvent.DOM_VK_1
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'Digit1',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
});
}
return promiseQueue;
}
function runSendKeyNumberTests() {
gTestDescription = 'runSendKeyNumberTests(): ';
var promiseQueue = Promise.resolve();
// Test numbers
var code0 = '0'.charCodeAt(0);
for (var i = 0; i < 10; i++) {
// callbacks in then() are deferred; must only reference these block-scoped
// variable instead of i.
let keyCode = code0 + i;
let chr = String.fromCharCode(keyCode);
// Test plain number
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain number with keyCode set
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: keyCode
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain number with keyCode set to keyCode + 1,
// expects keyCode to follow key value and ignore the incorrect value.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: keyCode + 1
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain number with code set
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'Digit' + chr
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'Digit' + chr,
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain upper caps alphabet with code set to KeyA,
// expects keyCode to follow key value.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'KeyA'
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'KeyA',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain upper caps alphabet with code set to KeyA,
// and keyCode set to DOM_VK_A.
// expects keyCode to follow key value.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'KeyA',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
}
return promiseQueue;
}
function runSendKeyDvorakTests() {
gTestDescription = 'runSendKeyDvorakTests(): ';
var promiseQueue = Promise.resolve();
// Test Dvorak layout emulation
var qwertyCodeForDvorakKeys = [
'KeyR', 'KeyT', 'KeyY', 'KeyU', 'KeyI', 'KeyO', 'KeyP',
'KeyA', 'KeyS', 'KeyD', 'KeyF', 'KeyG',
'KeyH', 'KeyJ', 'KeyK', 'KeyL', 'Semicolon',
'KeyX', 'KeyC', 'KeyV', 'KeyB', 'KeyN',
'KeyM', 'Comma', 'Period', 'Slash'];
var dvorakKeys = 'PYFGCRL' +
'AOEUIDHTNS' +
'QJKXBMWVZ';
for (var i = 0; i < dvorakKeys.length; i++) {
// callbacks in then() are deferred; must only reference these block-scoped
// variable instead of i.
let keyCode = dvorakKeys.charCodeAt(i);
let code = qwertyCodeForDvorakKeys[i];
[dvorakKeys.charAt(i), dvorakKeys.charAt(i).toLowerCase()]
.forEach((chr) => {
// Test alphabet with code set to Qwerty code,
// expects keyCode to follow key value.
// (This is *NOT* the expected scenario for emulating a Dvorak keyboard,
// even though expected results are the same.)
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: code
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: code,
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test alphabet with code set to Qwerty code and keyCode set,
// expects keyCode to follow key/keyCode value.
// (This is the expected scenario for emulating a Dvorak keyboard)
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: keyCode,
code: code
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: code,
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
});
}
var qwertyCodeForDvorakSymbols = [
'Minus', 'Equal',
'KeyQ', 'KeyW', 'KeyE', 'BracketLeft', 'BracketRight', 'Backslash',
'Quote', 'KeyZ'];
var shiftDvorakSymbols = '{}\"<>?+|_:';
var dvorakSymbols = '[]\',./=\\-;';
var dvorakSymbolsKeyCodes = [
KeyboardEvent.DOM_VK_OPEN_BRACKET,
KeyboardEvent.DOM_VK_CLOSE_BRACKET,
KeyboardEvent.DOM_VK_QUOTE,
KeyboardEvent.DOM_VK_COMMA,
KeyboardEvent.DOM_VK_PERIOD,
KeyboardEvent.DOM_VK_SLASH,
KeyboardEvent.DOM_VK_EQUALS,
KeyboardEvent.DOM_VK_BACK_SLASH,
KeyboardEvent.DOM_VK_HYPHEN_MINUS,
KeyboardEvent.DOM_VK_SEMICOLON
];
for (var i = 0; i < dvorakSymbols.length; i++) {
// callbacks in then() are deferred; must only reference these block-scoped
// variable instead of i.
let keyCode = dvorakSymbolsKeyCodes[i];
let code = qwertyCodeForDvorakSymbols[i];
[dvorakSymbols.charAt(i), shiftDvorakSymbols.charAt(i)]
.forEach((chr) => {
// Test symbols with code set to Qwerty code,
// expects keyCode to be 0.
// (This is *NOT* the expected scenario for emulating a Dvorak keyboard)
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: code
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: code,
keyCode: 0,
charCode: chr.charCodeAt(0)
}
});
});
// Test alphabet with code set to Qwerty code and keyCode set,
// expects keyCode to follow keyCode value.
// (This is the expected scenario for emulating a Dvorak keyboard)
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: keyCode,
code: code
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: code,
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
});
}
return promiseQueue;
}
function runSendKeyDigitKeySymbolsTests() {
gTestDescription = 'runSendKeyDigitKeySymbolsTests(): ';
var promiseQueue = Promise.resolve();
var digitKeySymbols = ')!@#$%^&*(';
for (var i = 0; i < digitKeySymbols.length; i++) {
// callbacks in then() are deferred; must only reference these block-scoped
// variable instead of i.
let keyCode = KeyboardEvent['DOM_VK_' + i];
let chr = digitKeySymbols.charAt(i);
let code = 'Digit' + i;
// Test plain symbol
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '', keyCode: 0,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain symbol with keyCode set
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: keyCode
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain symbol with code set
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: code
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: code,
keyCode: 0,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain symbol with code set to KeyA,
// expects keyCode to be 0.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'KeyA'
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'KeyA',
keyCode: 0,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain symbol with keyCode set to DOM_VK_A,
// expects keyCode to follow the keyCode set.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: KeyboardEvent.DOM_VK_A
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: KeyboardEvent.DOM_VK_A,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain symbol with code set to KeyA
// expects keyCode to follow the keyCode set.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A,
charCode: chr.charCodeAt(0)
}
});
});
}
return promiseQueue;
}
function runSendKeyUSKeyboardSymbolsTests() {
gTestDescription = 'runSendKeyUSKeyboardSymbolsTests(): ';
var promiseQueue = Promise.resolve();
// Test printable symbols on US Keyboard
var symbols = ' ;:=+,<-_.>/?`~[{\\|]}\'\"';
var symbolKeyCodes = [
KeyboardEvent.DOM_VK_SPACE,
KeyboardEvent.DOM_VK_SEMICOLON,
KeyboardEvent.DOM_VK_SEMICOLON,
KeyboardEvent.DOM_VK_EQUALS,
KeyboardEvent.DOM_VK_EQUALS,
KeyboardEvent.DOM_VK_COMMA,
KeyboardEvent.DOM_VK_COMMA,
KeyboardEvent.DOM_VK_HYPHEN_MINUS,
KeyboardEvent.DOM_VK_HYPHEN_MINUS,
KeyboardEvent.DOM_VK_PERIOD,
KeyboardEvent.DOM_VK_PERIOD,
KeyboardEvent.DOM_VK_SLASH,
KeyboardEvent.DOM_VK_SLASH,
KeyboardEvent.DOM_VK_BACK_QUOTE,
KeyboardEvent.DOM_VK_BACK_QUOTE,
KeyboardEvent.DOM_VK_OPEN_BRACKET,
KeyboardEvent.DOM_VK_OPEN_BRACKET,
KeyboardEvent.DOM_VK_BACK_SLASH,
KeyboardEvent.DOM_VK_BACK_SLASH,
KeyboardEvent.DOM_VK_CLOSE_BRACKET,
KeyboardEvent.DOM_VK_CLOSE_BRACKET,
KeyboardEvent.DOM_VK_QUOTE,
KeyboardEvent.DOM_VK_QUOTE
];
var symbolCodes = [
'Space',
'Semicolon',
'Semicolon',
'Equal',
'Equal',
'Comma',
'Comma',
'Minus',
'Minus',
'Period',
'Period',
'Slash',
'Slash',
'Backquote',
'Backquote',
'BracketLeft',
'BracketLeft',
'Backslash',
'Backslash',
'BracketRight',
'BracketRight',
'Quote',
'Quote'
];
for (var i = 0; i < symbols.length; i++) {
// callbacks in then() are deferred; must only reference these block-scoped
// variable instead of i.
let keyCode = symbolKeyCodes[i];
let chr = symbols.charAt(i);
let code = symbolCodes[i];
// Test plain symbol
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: 0,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain symbol with keyCode set
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: keyCode
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain symbol with code set
// expects keyCode to be 0.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: code
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: code,
keyCode: 0,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain symbol with code set to KeyA,
// expects keyCode to be 0.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'KeyA'
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'KeyA',
keyCode: 0,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain symbol with keyCode set to DOM_VK_A,
// expects keyCode to follow the keyCode set.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: KeyboardEvent.DOM_VK_A
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: KeyboardEvent.DOM_VK_A,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain symbol with code set to KeyA
// expects keyCode to follow the keyCode set.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A,
charCode: chr.charCodeAt(0)
}
});
});
}
return promiseQueue;
}
function runSendKeyGreekLettersTests() {
gTestDescription = 'runSendKeyGreekLettersTests(): ';
var promiseQueue = Promise.resolve();
// Test Greek letters
var greekLetters =
'\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c' +
'\u039d\u039e\u039f\u03a0\u03a1\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9' +
'\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc' +
'\u03bd\u03be\u03bf\u03c0\u03c1\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9' +
'\u03c2';
var greekLettersLayoutMap =
'ABGDEZHUIKLMNJOPRSTYFXCVABGDEZHUIKLMNJOPRSTYFXCVQ';
for (var i = 0; i < greekLetters.length; i++) {
// callbacks in then() are deferred; must only reference these block-scoped
// variable instead of i.
let keyCode = greekLettersLayoutMap.charCodeAt(i);
let chr = greekLetters.charAt(i);
let code = 'Key' + greekLettersLayoutMap.charAt(i);
// Test plain alphabet
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: 0,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain alphabet with keyCode set
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
keyCode: keyCode
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: '',
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain alphabet with code set,
// expects keyCode to be 0.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: code
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: code,
keyCode: 0,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain alphabet with code set to Digit1,
// expects keyCode to be 0.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'Digit1'
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'Digit1',
keyCode: 0,
charCode: chr.charCodeAt(0)
}
});
});
// Test plain alphabet with code set to Digit1,
// and keyCode set to DOM_VK_A.
// expects keyCode to follow the keyCode set.
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: chr,
code: 'Digit1',
keyCode: KeyboardEvent.DOM_VK_A
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: 'Digit1',
keyCode: KeyboardEvent.DOM_VK_A,
charCode: chr.charCodeAt(0)
}
});
});
}
return promiseQueue;
}
function runSendKeyEnterTests() {
gTestDescription = 'runSendKeyEnterTests(): ';
var promiseQueue = Promise.resolve();
// Test Enter with code unset
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: 'Enter'
},
expectedKeypress: true,
expectedInput: '\n',
expectedValues: {
key: 'Enter', code: '',
keyCode: KeyboardEvent.DOM_VK_RETURN,
charCode: 0
}
});
});
// Test Enter with code set
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: 'Enter',
code: 'Enter'
},
expectedKeypress: true,
expectedInput: '\n',
expectedValues: {
key: 'Enter', code: 'Enter',
keyCode: KeyboardEvent.DOM_VK_RETURN,
charCode: 0
}
});
});
// Test Enter with keyCode explict set to zero
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: {
key: 'Enter',
keyCode: 0
},
expectedKeypress: true,
expectedValues: {
key: 'Enter', code: '',
keyCode: 0,
charCode: 0
}
});
});
return promiseQueue;
}
function runSendKeyRejectionTests() {
gTestDescription = 'runSendKeyRejectionTests(): ';
var promiseQueue = Promise.resolve();
promiseQueue = promiseQueue.then(() => {
return sendKeyAndAssertResult({
dict: undefined,
expectedReject: TypeError
});
});
return promiseQueue;
}
function setCompositionAndAssertResult(testdata) {
var dict = testdata.dict;
var testName;
var promise;
if (dict) {
testName = gTestDescription +
'setComposition(' + testdata.text +
', undefined, undefined, '
+ JSON.stringify(dict) + ')';
promise = navigator.mozInputMethod.inputcontext
.setComposition(testdata.text, undefined, undefined, dict);
} else {
testName = gTestDescription +
'setComposition(' + testdata.text + ')';
promise = navigator.mozInputMethod.inputcontext
.setComposition(testdata.text);
}
if (testdata.expectedReject) {
promise = promise
.then(() => {
ok(false, testName + ' should not resolve.');
}, (e) => {
ok(true, testName + ' rejects.');
ok(e instanceof testdata.expectedReject, 'Reject with type.');
})
return promise;
}
promise = promise
.then((res) => {
is(res, true,
testName + ' should resolve to true.');
var expectedEventDetail = [];
var expectedValues = testdata.expectedValues;
if (testdata.expectsKeyEvents &&
(testdata.startsComposition ||
testdata.dispatchKeyboardEventDuringComposition)) {
expectedEventDetail.push({
type: 'keydown',
key: expectedValues.key,
charCode: 0,
code: expectedValues.code || '',
keyCode: expectedValues.keyCode || 0,
location: 0,
repeat: expectedValues.repeat || false,
value: gCurrentValue,
shift: false,
capsLock: false,
control: false,
alt: false
});
}
if (testdata.startsComposition) {
expectedEventDetail.push({
type: 'compositionstart',
data: '',
value: gCurrentValue
});
}
expectedEventDetail.push({
type: 'compositionupdate',
data: testdata.text,
value: gCurrentValue
});
expectedEventDetail.push({
type: 'input',
value: gCurrentValue += testdata.expectedInput
});
if (testdata.expectsKeyEvents &&
testdata.dispatchKeyboardEventDuringComposition) {
expectedEventDetail.push({
type: 'keyup',
key: expectedValues.key,
charCode: 0,
code: expectedValues.code || '',
keyCode: expectedValues.keyCode || 0,
location: 0,
repeat: expectedValues.repeat || false,
value: gCurrentValue,
shift: false,
capsLock: false,
control: false,
alt: false
});
}
assertEventDetail(expectedEventDetail, testName);
gEventDetails = [];
}, (e) => {
ok(false, testName + ' should not reject. ' + e);
});
return promise;
}
function endCompositionAndAssertResult(testdata) {
var dict = testdata.dict;
var testName;
var promise;
if (dict) {
testName = gTestDescription +
'endComposition(' + testdata.text + ', ' + JSON.stringify(dict) + ')';
promise = navigator.mozInputMethod.inputcontext
.endComposition(testdata.text, dict);
} else {
testName = gTestDescription +
'endComposition(' + testdata.text + ')';
promise = navigator.mozInputMethod.inputcontext
.endComposition(testdata.text);
}
if (testdata.expectedReject) {
promise = promise
.then(() => {
ok(false, testName + ' should not resolve.');
}, (e) => {
ok(true, testName + ' rejects.');
ok(e instanceof testdata.expectedReject, 'Reject with type.');
})
return promise;
}
promise = promise
.then((res) => {
is(res, true,
testName + ' should resolve to true.');
var expectedEventDetail = [];
var expectedValues = testdata.expectedValues;
if (testdata.expectsKeyEvents &&
testdata.dispatchKeyboardEventDuringComposition) {
expectedEventDetail.push({
type: 'keydown',
key: expectedValues.key,
charCode: 0,
code: expectedValues.code || '',
keyCode: expectedValues.keyCode || 0,
location: 0,
repeat: expectedValues.repeat || false,
value: gCurrentValue,
shift: false,
capsLock: false,
control: false,
alt: false
});
}
expectedEventDetail.push({
type: 'compositionend',
data: testdata.text,
value: gCurrentValue
});
expectedEventDetail.push({
type: 'input',
value: gCurrentValue
});
if (testdata.expectsKeyEvents) {
expectedEventDetail.push({
type: 'keyup',
key: expectedValues.key,
charCode: 0,
code: expectedValues.code || '',
keyCode: expectedValues.keyCode || 0,
location: 0,
repeat: expectedValues.repeat || false,
value: gCurrentValue,
shift: false,
capsLock: false,
control: false,
alt: false
});
}
assertEventDetail(expectedEventDetail, testName);
gEventDetails = [];
}, (e) => {
ok(false, testName + ' should not reject. ' + e);
});
return promise;
}
function runCompositionWithKeyEventTests() {
var promiseQueue = Promise.resolve();
[true, false].forEach((dispatchKeyboardEventDuringComposition) => {
gTestDescription = 'runCompositionWithKeyEventTests() (dispatchKeyboardEvent =' + dispatchKeyboardEventDuringComposition + '): ';
promiseQueue = promiseQueue
.then(() => {
SpecialPowers.setBoolPref(
'dom.keyboardevent.dispatch_during_composition',
dispatchKeyboardEventDuringComposition);
})
.then(() => {
return setCompositionAndAssertResult({
text: 'foo',
expectsKeyEvents: true,
startsComposition: true,
dispatchKeyboardEventDuringComposition: dispatchKeyboardEventDuringComposition,
expectedInput: 'foo',
dict: {
key: 'a',
code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A
},
expectedValues: {
key: 'a',
code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A
}
});
})
.then(() => {
return setCompositionAndAssertResult({
text: 'foobar',
expectsKeyEvents: true,
startsComposition: false,
dispatchKeyboardEventDuringComposition: dispatchKeyboardEventDuringComposition,
expectedInput: 'bar',
dict: {
key: 'a',
code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A
},
expectedValues: {
key: 'a',
code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A
}
});
})
.then(() => {
return endCompositionAndAssertResult({
text: 'foobar',
expectsKeyEvents: true,
dispatchKeyboardEventDuringComposition: dispatchKeyboardEventDuringComposition,
expectedInput: '',
dict: {
key: 'a',
code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A
},
expectedValues: {
key: 'a',
code: 'KeyA',
keyCode: KeyboardEvent.DOM_VK_A
}
});
})
.then(() => {
SpecialPowers.clearUserPref(
'dom.keyboardevent.dispatch_during_composition');
});
});
return promiseQueue;
}
function runCompositionWithoutKeyEventTests() {
var promiseQueue = Promise.resolve();
gTestDescription = 'runCompositionWithoutKeyEventTests(): ';
promiseQueue = promiseQueue
.then(() => {
return setCompositionAndAssertResult({
text: 'foo',
expectsKeyEvents: false,
startsComposition: true,
expectedInput: 'foo'
});
})
.then(() => {
return setCompositionAndAssertResult({
text: 'foobar',
expectsKeyEvents: false,
startsComposition: false,
expectedInput: 'bar'
});
})
.then(() => {
return endCompositionAndAssertResult({
text: 'foobar',
expectsKeyEvents: false,
expectedInput: ''
});
});
return promiseQueue;
}
function keydownAndAssertResult(testdata) {
var dict = testdata.dict;
var testName = gTestDescription + 'keydown(' + JSON.stringify(dict) + ')';
var promise = navigator.mozInputMethod.inputcontext.keydown(dict);
if (testdata.expectedReject) {
promise = promise
.then(() => {
ok(false, testName + ' should not resolve.');
}, (e) => {
ok(true, testName + ' rejects.');
ok(e instanceof testdata.expectedReject, 'Reject with type.');
})
return promise;
}
promise = promise
.then((res) => {
is(res, true,
testName + ' should resolve to true.');
var expectedEventDetail = [];
var expectedValues = testdata.expectedValues;
expectedEventDetail.push({
type: 'keydown',
key: expectedValues.key,
charCode: 0,
code: expectedValues.code || '',
keyCode: expectedValues.keyCode || 0,
location: 0,
repeat: expectedValues.repeat || false,
value: gCurrentValue,
shift: false,
capsLock: false,
control: false,
alt: false
});
if (testdata.expectedKeypress) {
expectedEventDetail.push({
type: 'keypress',
key: expectedValues.key,
charCode: expectedValues.charCode,
code: expectedValues.code || '',
keyCode: expectedValues.charCode ? 0 : expectedValues.keyCode,
location: 0,
repeat: expectedValues.repeat || false,
value: gCurrentValue,
shift: false,
capsLock: false,
control: false,
alt: false
});
}
if (testdata.expectedInput) {
expectedEventDetail.push({
type: 'input',
value: gCurrentValue += testdata.expectedInput
});
}
assertEventDetail(expectedEventDetail, testName);
gEventDetails = [];
}, (e) => {
ok(false, testName + ' should not reject. ' + e);
});
return promise;
}
function keyupAndAssertResult(testdata) {
var dict = testdata.dict;
var testName = gTestDescription + 'keyup(' + JSON.stringify(dict) + ')';
var promise = navigator.mozInputMethod.inputcontext.keyup(dict);
if (testdata.expectedReject) {
promise = promise
.then(() => {
ok(false, testName + ' should not resolve.');
}, (e) => {
ok(true, testName + ' rejects.');
ok(e instanceof testdata.expectedReject, 'Reject with type.');
})
return promise;
}
promise = promise
.then((res) => {
is(res, true,
testName + ' should resolve to true.');
var expectedEventDetail = [];
var expectedValues = testdata.expectedValues;
expectedEventDetail.push({
type: 'keyup',
key: expectedValues.key,
charCode: 0,
code: expectedValues.code || '',
keyCode: expectedValues.keyCode || 0,
location: 0,
repeat: expectedValues.repeat || false,
value: gCurrentValue,
shift: false,
capsLock: false,
control: false,
alt: false
});
assertEventDetail(expectedEventDetail, testName);
gEventDetails = [];
}, (e) => {
ok(false, testName + ' should not reject. ' + e);
});
return promise;
}
function runKeyDownUpTests() {
gTestDescription = 'runKeyDownUpTests(): ';
var promiseQueue = Promise.resolve();
let chr = 'a';
let code = 'KeyA';
let keyCode = KeyboardEvent.DOM_VK_A;
promiseQueue = promiseQueue
.then(() => {
return keydownAndAssertResult({
dict: {
key: chr,
code: code,
keyCode: keyCode
},
expectedKeypress: true,
expectedInput: chr,
expectedValues: {
key: chr, code: code,
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
})
.then(() => {
return keyupAndAssertResult({
dict: {
key: chr,
code: code,
keyCode: keyCode
},
expectedValues: {
key: chr, code: code,
keyCode: keyCode,
charCode: chr.charCodeAt(0)
}
});
});
return promiseQueue;
}
function runKeyDownUpRejectionTests() {
gTestDescription = 'runKeyDownUpRejectionTests(): ';
var promiseQueue = Promise.resolve();
promiseQueue = promiseQueue.then(() => {
return keydownAndAssertResult({
dict: undefined,
expectedReject: TypeError
});
});
promiseQueue = promiseQueue.then(() => {
return keyupAndAssertResult({
dict: undefined,
expectedReject: TypeError
});
});
return promiseQueue;
}
function runRepeatTests() {
gTestDescription = 'runRepeatTests(): ';
var promiseQueue = Promise.resolve();
// Test repeat
promiseQueue = promiseQueue
.then(() => {
return sendKeyAndAssertResult({
dict: {
key: 'A',
repeat: true
},
expectedKeypress: true,
expectedRepeat: true,
expectedInput: 'A',
expectedValues: {
repeat: true,
key: 'A', code: '',
keyCode: KeyboardEvent.DOM_VK_A,
charCode: 'A'.charCodeAt(0)
}
});
})
.then(() => {
return keyupAndAssertResult({
dict: {
key: 'A'
},
expectedKeypress: true,
expectedRepeat: true,
expectedInput: 'A',
expectedValues: {
key: 'A', code: '',
keyCode: KeyboardEvent.DOM_VK_A,
charCode: 'A'.charCodeAt(0)
}
});
});
return promiseQueue;
}
function runTest() {
let im = navigator.mozInputMethod;
// Set current page as an input method.
SpecialPowers.wrap(im).setActive(true);
let iframe = document.createElement('iframe');
iframe.src = 'data:text/html,<html><body><textarea rows=30 cols=30></textarea></body></html>';
iframe.setAttribute('mozbrowser', true);
document.body.appendChild(iframe);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
iframe.addEventListener('mozbrowserloadend', function() {
mm.addMessageListener('test:eventDetail', function(msg) {
gEventDetails.push(msg.data);
});
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
});
waitForInputContextChange()
.then(() => {
var inputcontext = navigator.mozInputMethod.inputcontext;
ok(!!inputcontext, 'Receving the first input context');
})
.then(() => runSendKeyAlphabetTests())
.then(() => runSendKeyNumberTests())
.then(() => runSendKeyDvorakTests())
.then(() => runSendKeyDigitKeySymbolsTests())
.then(() => runSendKeyUSKeyboardSymbolsTests())
.then(() => runSendKeyGreekLettersTests())
.then(() => runSendKeyEnterTests())
.then(() => runSendKeyRejectionTests())
.then(() => runCompositionWithKeyEventTests())
.then(() => runCompositionWithoutKeyEventTests())
.then(() => runKeyDownUpTests())
.then(() => runKeyDownUpRejectionTests())
.then(() => runRepeatTests())
.catch((err) => {
console.error(err);
is(false, err.message);
})
.then(() => {
var p = waitForInputContextChange();
// Revoke our right from using the IM API.
SpecialPowers.wrap(im).setActive(false);
return p;
})
.then(() => {
var inputcontext = navigator.mozInputMethod.inputcontext;
is(inputcontext, null, 'Receving null input context');
inputmethod_cleanup();
})
.catch((err) => {
console.error(err);
is(false, err.message);
});
}
</script>
</pre>
</body>
</html>