Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
9
gaia/apps/keyboard/test/marionette/.jshintrc
Executable file
9
gaia/apps/keyboard/test/marionette/.jshintrc
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "../../../../.jshintrc",
|
||||
"node": true,
|
||||
"predef": [
|
||||
"test",
|
||||
"setup",
|
||||
"marionette"
|
||||
]
|
||||
}
|
||||
16
gaia/apps/keyboard/test/marionette/apps/imetestapp/index.html
Executable file
16
gaia/apps/keyboard/test/marionette/apps/imetestapp/index.html
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title>Keyboard Test App</title>
|
||||
<script type="text/javascript" src="js/main.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="style/keyboard.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="keyboard" class="ime-test-app">
|
||||
<button id="sendKey" class="key">Send Key: \o/ </button>
|
||||
<button id="switchLayout" class="key">Switch layout</button>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
73
gaia/apps/keyboard/test/marionette/apps/imetestapp/js/main.js
Executable file
73
gaia/apps/keyboard/test/marionette/apps/imetestapp/js/main.js
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
'use strict';
|
||||
|
||||
/* global KeyEvent */
|
||||
|
||||
var inputContext = null;
|
||||
var keyboardElement;
|
||||
|
||||
function init() {
|
||||
keyboardElement = document.getElementById('keyboard');
|
||||
|
||||
window.navigator.mozInputMethod.oninputcontextchange = function() {
|
||||
inputContext = navigator.mozInputMethod.inputcontext;
|
||||
resizeWindow();
|
||||
};
|
||||
|
||||
window.addEventListener('resize', resizeWindow);
|
||||
|
||||
keyboardElement.addEventListener('mousedown', function onMouseDown(evt) {
|
||||
// Prevent loosing focus to the currently focused app
|
||||
// Otherwise, right after mousedown event, the app will receive a focus event.
|
||||
evt.preventDefault();
|
||||
});
|
||||
|
||||
var sendKeyElement = document.getElementById('sendKey');
|
||||
sendKeyElement.addEventListener('click', function sendKeyHandler() {
|
||||
var testString = '\\o/';
|
||||
for (var i = 0; i < testString.length; i++) {
|
||||
sendKey(testString.charCodeAt(i));
|
||||
}
|
||||
});
|
||||
|
||||
var switchElement = document.getElementById('switchLayout');
|
||||
switchElement.addEventListener('click', function switchHandler() {
|
||||
var mgmt = navigator.mozInputMethod.mgmt;
|
||||
mgmt.next();
|
||||
});
|
||||
|
||||
// long press to trigger IME menu
|
||||
var menuTimeout = 0;
|
||||
switchElement.addEventListener('touchstart', function longHandler() {
|
||||
menuTimeout = window.setTimeout(function menuTimeout() {
|
||||
var mgmt = navigator.mozInputMethod.mgmt;
|
||||
mgmt.showAll();
|
||||
}, 700);
|
||||
});
|
||||
|
||||
switchElement.addEventListener('touchend', function longHandler() {
|
||||
clearTimeout(menuTimeout);
|
||||
});
|
||||
}
|
||||
|
||||
function resizeWindow() {
|
||||
window.resizeTo(window.innerWidth, keyboardElement.clientHeight);
|
||||
}
|
||||
|
||||
function sendKey(keyCode) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.DOM_VK_BACK_SPACE:
|
||||
case KeyEvent.DOM_VK_RETURN:
|
||||
if (inputContext) {
|
||||
inputContext.sendKey(keyCode, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (inputContext) {
|
||||
inputContext.sendKey(0, keyCode, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('load', init);
|
||||
19
gaia/apps/keyboard/test/marionette/apps/imetestapp/js/settings.js
Executable file
19
gaia/apps/keyboard/test/marionette/apps/imetestapp/js/settings.js
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
/* global MozActivity */
|
||||
|
||||
document.getElementById('back').addEventListener('click', function() {
|
||||
document.addEventListener('visibilitychange', function() {
|
||||
// Close ourself after the activity transition is completed.
|
||||
window.close();
|
||||
});
|
||||
|
||||
var activity = new MozActivity({
|
||||
name: 'configure',
|
||||
data: {
|
||||
target: 'device'
|
||||
}
|
||||
});
|
||||
|
||||
activity.onerror = function() {};
|
||||
});
|
||||
25
gaia/apps/keyboard/test/marionette/apps/imetestapp/manifest.webapp
Executable file
25
gaia/apps/keyboard/test/marionette/apps/imetestapp/manifest.webapp
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "LOL Keyboard",
|
||||
"description": "An useless virtual keyboard that sends \\o/.",
|
||||
"type": "privileged",
|
||||
"role": "input",
|
||||
"launch_path": "/settings.html",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"permissions": {
|
||||
"input": {
|
||||
"description": "Send key events and characters to user focused input fields."
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"lol": {
|
||||
"launch_path": "/index.html",
|
||||
"name": "\\o/",
|
||||
"description": "LOL layout",
|
||||
"types": ["text", "number"]
|
||||
}
|
||||
},
|
||||
"default_locale": "en-US"
|
||||
}
|
||||
19
gaia/apps/keyboard/test/marionette/apps/imetestapp/settings.html
Executable file
19
gaia/apps/keyboard/test/marionette/apps/imetestapp/settings.html
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title>LOL Keyboard Settings</title>
|
||||
<script defer src="./js/settings.js"></script>
|
||||
<style>
|
||||
button {
|
||||
font-size: 2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LOL Keyboard Settings</h1>
|
||||
<p>Nothing to see here.</p>
|
||||
<button id="back">< Back</button>
|
||||
</body>
|
||||
</html>
|
||||
25
gaia/apps/keyboard/test/marionette/apps/imetestapp/style/keyboard.css
Executable file
25
gaia/apps/keyboard/test/marionette/apps/imetestapp/style/keyboard.css
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
html {
|
||||
font-size: 10px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#keyboard {
|
||||
width: 100%;
|
||||
height: 20rem;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.key {
|
||||
background-color: #333;
|
||||
font-size: 2.4rem;
|
||||
border: 0.2rem solid gray;
|
||||
color: white;
|
||||
margin: 0.2rem;
|
||||
}
|
||||
48
gaia/apps/keyboard/test/marionette/apps/keyboardtestapp/index.html
Executable file
48
gaia/apps/keyboard/test/marionette/apps/keyboardtestapp/index.html
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Keyboard APP Test</title>
|
||||
<script defer src="script.js"></script>
|
||||
</head>
|
||||
<body class="keyboard-test-app">
|
||||
<div>
|
||||
<label for="textInput">Text</label>
|
||||
<input type="text" id="textInput"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="textareInput">Textarea</label>
|
||||
<textarea id="textareaInput"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label for="urlInput">URL</label>
|
||||
<input type="url" id="urlInput"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="emailInput">Email</label>
|
||||
<input type="email" id="emailInput"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="passwordInput">Password</label>
|
||||
<input type="password" id="passwordInput"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="searchInput">Search</label>
|
||||
<input type="search" id="searchInput"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="numberInput">Number</label>
|
||||
<input type="number" id="numberInput"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="telInput">Tel</label>
|
||||
<input type="tel" id="telInput"/>
|
||||
</div>
|
||||
<div>
|
||||
<div id="nonInput" style="height: 100px;">
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="triggerPromptButton">Prompt</button>
|
||||
<p id="promptResult"></p>
|
||||
</body>
|
||||
</html>
|
||||
9
gaia/apps/keyboard/test/marionette/apps/keyboardtestapp/manifest.webapp
Executable file
9
gaia/apps/keyboard/test/marionette/apps/keyboardtestapp/manifest.webapp
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "keyboard tests",
|
||||
"description": "A keyboard testing app.",
|
||||
"launch_path": "/index.html",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
}
|
||||
}
|
||||
9
gaia/apps/keyboard/test/marionette/apps/keyboardtestapp/script.js
Executable file
9
gaia/apps/keyboard/test/marionette/apps/keyboardtestapp/script.js
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
'use strict';
|
||||
|
||||
document.getElementById('triggerPromptButton').onclick = () => {
|
||||
// setTimeout is needed so we don't block marionette itself.
|
||||
window.setTimeout(() => {
|
||||
var str = window.prompt('The quick brown fox jumps over a', '');
|
||||
document.getElementById('promptResult').textContent = str;
|
||||
});
|
||||
};
|
||||
187
gaia/apps/keyboard/test/marionette/auto_correction_test.js
Executable file
187
gaia/apps/keyboard/test/marionette/auto_correction_test.js
Executable file
|
|
@ -0,0 +1,187 @@
|
|||
/* global suite */
|
||||
|
||||
'use strict';
|
||||
|
||||
var KeyboardTestApp = require('./lib/keyboard_test_app'),
|
||||
Keyboard = require('./lib/keyboard'),
|
||||
KeyboardSettings = require('./lib/keyboard_settings.js'),
|
||||
assert = require('assert');
|
||||
|
||||
|
||||
marionette('Keyboard Auto correction tests', function() {
|
||||
var apps = {};
|
||||
var keyboardTestApp = null;
|
||||
var keyboard = null;
|
||||
var keyboardSettings = null;
|
||||
var client = null;
|
||||
var system = null;
|
||||
|
||||
apps[KeyboardTestApp.ORIGIN] = __dirname + '/apps/keyboardtestapp';
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
apps: apps,
|
||||
prefs: {
|
||||
'focusmanager.testmode': true
|
||||
},
|
||||
settings: {
|
||||
'lockscreen.enabled': false,
|
||||
'ftu.manifestURL': null,
|
||||
'keyboard.autocorrect': true
|
||||
}
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
system = client.loader.getAppClass('system');
|
||||
system.waitForFullyLoaded();
|
||||
|
||||
keyboard = new Keyboard(client);
|
||||
keyboardSettings = new KeyboardSettings(client);
|
||||
keyboardTestApp = new KeyboardTestApp(client);
|
||||
|
||||
keyboard.waitForKeyboardReady();
|
||||
});
|
||||
|
||||
suite('AutoCorrect switch', function() {
|
||||
setup(function() {
|
||||
keyboardSettings.launch();
|
||||
});
|
||||
|
||||
test('Auto correct switch should equal to settings context',
|
||||
function() {
|
||||
var currentSwitch = client.settings.get('keyboard.autocorrect');
|
||||
|
||||
keyboardSettings.switchTo();
|
||||
|
||||
// Toggle one time
|
||||
keyboardSettings.clickAutoCorrectOption();
|
||||
assert.equal(keyboardSettings.autoCorrect, !currentSwitch);
|
||||
|
||||
// Toggle again
|
||||
keyboardSettings.clickAutoCorrectOption();
|
||||
assert.equal(keyboardSettings.autoCorrect, !!currentSwitch);
|
||||
});
|
||||
});
|
||||
|
||||
suite('With autocorrect on', function() {
|
||||
setup(function () {
|
||||
keyboardTestApp.launch();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.textInput.tap();
|
||||
|
||||
keyboard.switchTo();
|
||||
});
|
||||
|
||||
test('Predictive tests', function() {
|
||||
// Test 1 - type first 7 letters of the expected word
|
||||
// select suggestion will append a space.
|
||||
var expectedWord = 'keyboard ';
|
||||
keyboard.type(expectedWord.slice(0, 7));
|
||||
keyboard.tapAutoCorrectWord();
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), expectedWord);
|
||||
|
||||
// Test 2 - tap second suggestion, then press space
|
||||
keyboard.switchTo();
|
||||
keyboard.type('Tes');
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), 'keyboard Tes');
|
||||
|
||||
keyboard.switchTo();
|
||||
keyboard.tapSuggestionWord('Tea');
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), 'keyboard Tea ');
|
||||
|
||||
// Test 3 - type something with autocorrect and press space
|
||||
keyboard.switchTo();
|
||||
keyboard.type('ye ');
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), 'keyboard Tea he ');
|
||||
|
||||
// Test 4 - autocorrect, dot and backspace
|
||||
keyboard.switchTo();
|
||||
keyboard.type('wot.');
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'),
|
||||
'keyboard Tea he wit.');
|
||||
|
||||
keyboard.switchTo();
|
||||
keyboard.tapBackspaceKey();
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), 'keyboard Tea he wot');
|
||||
});
|
||||
|
||||
// For Bug 1073870
|
||||
test('Move caret before autocorrect', function() {
|
||||
keyboard.type('Hello worl');
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
client.executeScript(
|
||||
'var el = document.activeElement;' +
|
||||
'el.selectionStart = el.selectionEnd = 5;');
|
||||
|
||||
keyboard.switchTo();
|
||||
keyboard.type(' ');
|
||||
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), 'Hello worl');
|
||||
});
|
||||
});
|
||||
|
||||
suite('With autocorrect off', function() {
|
||||
setup(function () {
|
||||
client.settings.set('keyboard.autocorrect', false);
|
||||
|
||||
keyboardTestApp.launch();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.textInput.tap();
|
||||
|
||||
keyboard.switchTo();
|
||||
});
|
||||
|
||||
test('No autocorrect while typing', function() {
|
||||
keyboard.type('Tes');
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), 'Tes');
|
||||
|
||||
keyboard.switchTo();
|
||||
keyboard.tapSuggestionWord('Tea');
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), 'Tea ');
|
||||
|
||||
keyboard.switchTo();
|
||||
keyboard.type('ye.');
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), 'Tea ye.');
|
||||
|
||||
keyboard.switchTo();
|
||||
keyboard.tapBackspaceKey();
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), 'Tea ye');
|
||||
});
|
||||
});
|
||||
});
|
||||
84
gaia/apps/keyboard/test/marionette/dismiss_test.js
Executable file
84
gaia/apps/keyboard/test/marionette/dismiss_test.js
Executable file
|
|
@ -0,0 +1,84 @@
|
|||
'use strict';
|
||||
|
||||
var KeyboardTestApp = require('./lib/keyboard_test_app'),
|
||||
Keyboard = require('./lib/keyboard'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('Dimiss the keyboard', function() {
|
||||
var apps = {};
|
||||
var keyboardTestApp = null;
|
||||
var keyboard = null;
|
||||
var systemInputMgmt = null;
|
||||
var system = null;
|
||||
var actions;
|
||||
|
||||
apps[KeyboardTestApp.ORIGIN] = __dirname + '/apps/keyboardtestapp';
|
||||
|
||||
var client = marionette.client({
|
||||
profile: {
|
||||
apps: apps,
|
||||
prefs: {
|
||||
'focusmanager.testmode': true
|
||||
}
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
systemInputMgmt = client.loader.getAppClass('system', 'input_management');
|
||||
system = client.loader.getAppClass('system');
|
||||
system.waitForFullyLoaded();
|
||||
actions = client.loader.getActions();
|
||||
|
||||
keyboard = new Keyboard(client);
|
||||
keyboardTestApp = new KeyboardTestApp(client);
|
||||
|
||||
keyboard.waitForKeyboardReady();
|
||||
|
||||
keyboardTestApp.launch();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.textInput.click();
|
||||
|
||||
keyboard.switchTo();
|
||||
});
|
||||
|
||||
test('Longpressing the space bar should dismiss the keyboard', function() {
|
||||
// The time needed for dismiss is 500ms.
|
||||
keyboard.longPressSpaceBar(0.7);
|
||||
|
||||
client.waitFor(() => {
|
||||
return !systemInputMgmt.keyboardFrameDisplayed();
|
||||
});
|
||||
|
||||
assert.ok(true);
|
||||
});
|
||||
|
||||
test('Longpressing for only 0.5 sec should not dimiss keyboard', function() {
|
||||
keyboard.longPressSpaceBar(0.5);
|
||||
|
||||
var keyboardContainer = keyboard.currentPanel;
|
||||
|
||||
assert.ok(keyboardContainer.displayed());
|
||||
});
|
||||
|
||||
test('Click on a non-input field, should dimiss keyboard', function() {
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.nonInputArea.click();
|
||||
|
||||
client.waitFor(() => {
|
||||
return !systemInputMgmt.keyboardFrameDisplayed();
|
||||
});
|
||||
|
||||
assert.ok(true);
|
||||
});
|
||||
|
||||
test('Pressing [Home] button should dimiss keyboard', function() {
|
||||
system.tapHome();
|
||||
|
||||
client.waitFor(() => {
|
||||
return !systemInputMgmt.keyboardFrameDisplayed();
|
||||
});
|
||||
|
||||
assert.ok(true);
|
||||
});
|
||||
});
|
||||
81
gaia/apps/keyboard/test/marionette/email_keyboard_test.js
Executable file
81
gaia/apps/keyboard/test/marionette/email_keyboard_test.js
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
'use strict';
|
||||
|
||||
var KeyboardTestApp = require('./lib/keyboard_test_app'),
|
||||
Keyboard = require('./lib/keyboard'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('Email keyboard input tests', function() {
|
||||
var apps = {};
|
||||
var keyboardTestApp = null;
|
||||
var keyboard = null;
|
||||
var client = null;
|
||||
var system = null;
|
||||
|
||||
apps[KeyboardTestApp.ORIGIN] = __dirname + '/apps/keyboardtestapp';
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
apps: apps,
|
||||
prefs: {
|
||||
'focusmanager.testmode': true
|
||||
},
|
||||
settings: {
|
||||
'lockscreen.enabled': false,
|
||||
'ftu.manifestURL': null
|
||||
}
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
system = client.loader.getAppClass('system');
|
||||
system.waitForFullyLoaded();
|
||||
|
||||
keyboard = new Keyboard(client);
|
||||
keyboardTestApp = new KeyboardTestApp(client);
|
||||
|
||||
keyboard.waitForKeyboardReady();
|
||||
|
||||
keyboardTestApp.launch();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.emailInput.tap();
|
||||
|
||||
keyboard.switchTo();
|
||||
});
|
||||
|
||||
test('Should be email layout', function() {
|
||||
var atSymbol = '@';
|
||||
var commaSymbol = ',';
|
||||
|
||||
assert.equal(keyboard.isKeyPresent(atSymbol), true);
|
||||
assert.equal(keyboard.isKeyPresent(commaSymbol), false);
|
||||
});
|
||||
|
||||
test('Type post@mydomain.com', function() {
|
||||
keyboard.type('post');
|
||||
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.emailInput.tap();
|
||||
keyboard.switchTo();
|
||||
|
||||
keyboard.type('@');
|
||||
keyboard.type('mydomain.com');
|
||||
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.emailInput.getAttribute('value'), 'post@mydomain.com');
|
||||
});
|
||||
|
||||
test('Type post123@mydomain.com', function() {
|
||||
keyboard.type('post123');
|
||||
keyboard.type('@');
|
||||
keyboard.type('mydomain.com');
|
||||
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.emailInput.getAttribute('value'),
|
||||
'post123@mydomain.com');
|
||||
});
|
||||
});
|
||||
119
gaia/apps/keyboard/test/marionette/launch_test.js
Executable file
119
gaia/apps/keyboard/test/marionette/launch_test.js
Executable file
|
|
@ -0,0 +1,119 @@
|
|||
'use strict';
|
||||
|
||||
var KeyboardTestApp = require('./lib/keyboard_test_app'),
|
||||
Keyboard = require('./lib/keyboard'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('Launch Keyboard APP', function() {
|
||||
var apps = {};
|
||||
var keyboardTestApp = null;
|
||||
var keyboard = null;
|
||||
var client = null;
|
||||
var system = null;
|
||||
|
||||
apps[KeyboardTestApp.ORIGIN] = __dirname + '/apps/keyboardtestapp';
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
apps: apps,
|
||||
prefs: {
|
||||
'focusmanager.testmode': true
|
||||
}
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
system = client.loader.getAppClass('system');
|
||||
system.waitForFullyLoaded();
|
||||
|
||||
keyboard = new Keyboard(client);
|
||||
keyboardTestApp = new KeyboardTestApp(client);
|
||||
|
||||
keyboard.waitForKeyboardReady();
|
||||
|
||||
keyboardTestApp.launch();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.textInput.click();
|
||||
|
||||
keyboard.switchTo();
|
||||
});
|
||||
|
||||
test('Should show lowercase layout', function() {
|
||||
// XXX: Workaround
|
||||
// To get the #keyboard element to instead of the body element.
|
||||
// The value of `client.findElement('body').displayed()` could not be true
|
||||
// when the keyboard app is show up in the screen currently.
|
||||
// Please refer to http://bugzil.la/995865.
|
||||
var keyboardContainer = keyboard.currentPanel;
|
||||
assert.ok(keyboardContainer.displayed());
|
||||
|
||||
var shiftKey = keyboard.shiftKey;
|
||||
assert.ok(shiftKey.getAttribute('aria-pressed') === 'false');
|
||||
|
||||
var alphaKey = keyboard.getKey('a');
|
||||
assert.ok(alphaKey.displayed());
|
||||
});
|
||||
|
||||
test('Switch between inputs w/o waiting for layout loading', function() {
|
||||
var keyboardContainer = keyboard.currentPanel;
|
||||
assert.ok(keyboardContainer.displayed());
|
||||
|
||||
var shiftKey = keyboard.shiftKey;
|
||||
var alphaKey = keyboard.getKey('a');
|
||||
|
||||
assert.ok(shiftKey.getAttribute('aria-pressed') === 'false');
|
||||
assert.ok(alphaKey.displayed());
|
||||
|
||||
// Switch to test app frame.
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
// Focus on the 2nd input
|
||||
keyboardTestApp.numberInput.click();
|
||||
|
||||
// Without waiting for the keyboard, focus the 3rd input
|
||||
keyboardTestApp.textareaInput.click();
|
||||
|
||||
// Switch back to keyboard
|
||||
keyboard.switchTo();
|
||||
|
||||
// Should remain, or switched back to alpha keyboard.
|
||||
client.waitFor(() => {
|
||||
return alphaKey.displayed();
|
||||
});
|
||||
|
||||
// Since the 3rd input is a <textarea>,
|
||||
// we should reach upper case at this point.
|
||||
client.waitFor(() => {
|
||||
return (shiftKey.getAttribute('aria-pressed') === 'true');
|
||||
});
|
||||
});
|
||||
|
||||
test('Keys and buttons should be have aria-label set', function() {
|
||||
var returnKey = keyboard.returnKey;
|
||||
client.waitFor(() => {
|
||||
return (returnKey.getAttribute('aria-label') === 'return');
|
||||
});
|
||||
|
||||
var dismissSuggestionsKey = keyboard.dismissSuggestionsKey;
|
||||
client.waitFor(() => {
|
||||
var label = dismissSuggestionsKey.getAttribute('aria-label');
|
||||
return (label === 'Dismiss');
|
||||
});
|
||||
});
|
||||
|
||||
test('Touching the status bar should not dismiss keyboard', function() {
|
||||
// Click on the status bar
|
||||
client.switchToFrame();
|
||||
var topPanel = client.findElement('#top-panel');
|
||||
topPanel.click();
|
||||
|
||||
client.helper.wait(3000);
|
||||
|
||||
keyboard.switchTo();
|
||||
|
||||
var keyboardContainer = keyboard.currentPanel;
|
||||
|
||||
assert.ok(keyboardContainer.displayed());
|
||||
});
|
||||
});
|
||||
10
gaia/apps/keyboard/test/marionette/lib/.jshintrc
Executable file
10
gaia/apps/keyboard/test/marionette/lib/.jshintrc
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "../../../../../.jshintrc",
|
||||
"node": true,
|
||||
"predef": [
|
||||
"test",
|
||||
"setup",
|
||||
"marionette",
|
||||
"client"
|
||||
]
|
||||
}
|
||||
34
gaia/apps/keyboard/test/marionette/lib/base.js
Executable file
34
gaia/apps/keyboard/test/marionette/lib/base.js
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
'use strict';
|
||||
|
||||
function Base(client, origin) {
|
||||
this.client = client;
|
||||
this.origin = origin;
|
||||
|
||||
this.elements = {};
|
||||
}
|
||||
|
||||
Base.prototype = {
|
||||
launch: function() {
|
||||
this.client.apps.launch(this.origin);
|
||||
|
||||
this.switchTo();
|
||||
},
|
||||
|
||||
switchTo: function() {
|
||||
this.client.switchToFrame();
|
||||
this.client.apps.switchToApp(this.origin);
|
||||
|
||||
this.waitForReady();
|
||||
},
|
||||
|
||||
close: function() {
|
||||
this.client.apps.close(this.origin);
|
||||
},
|
||||
|
||||
waitForReady: function() {
|
||||
this.client.helper.waitForElement('body');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = Base;
|
||||
48
gaia/apps/keyboard/test/marionette/lib/ime_test_app.js
Executable file
48
gaia/apps/keyboard/test/marionette/lib/ime_test_app.js
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
'use strict';
|
||||
|
||||
/*
|
||||
* A helper module for the testing 3rd-party IME app.
|
||||
*/
|
||||
var Base = require('./base');
|
||||
|
||||
function ImeTestApp(client) {
|
||||
Base.call(this, client, ImeTestApp.ORIGIN);
|
||||
}
|
||||
|
||||
module.exports = ImeTestApp;
|
||||
|
||||
ImeTestApp.ORIGIN = 'app://imetestapp.gaiamobile.org';
|
||||
ImeTestApp.MANIFEST_URL = 'app://imetestapp.gaiamobile.org/manifest.webapp';
|
||||
|
||||
ImeTestApp.Selectors = Object.freeze({
|
||||
sendKeyButton: '#sendKey',
|
||||
switchLayoutButton: '#switchLayout'
|
||||
});
|
||||
|
||||
ImeTestApp.prototype = {
|
||||
__proto__: Base.prototype,
|
||||
|
||||
get sendKeyButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
ImeTestApp.Selectors.sendKeyButton);
|
||||
},
|
||||
|
||||
get switchLayoutButton() {
|
||||
return this.client.helper.waitForElement(
|
||||
ImeTestApp.Selectors.switchLayoutButton);
|
||||
},
|
||||
|
||||
switchTo: function() {
|
||||
var systemInputMgmt = this.client.loader.getAppClass(
|
||||
'system', 'input_management');
|
||||
var imeKeyboard;
|
||||
|
||||
systemInputMgmt.waitForKeyboardFrameDisplayed();
|
||||
systemInputMgmt.switchToActiveKeyboardFrame();
|
||||
|
||||
imeKeyboard = this.client.helper.waitForElement('#keyboard.ime-test-app');
|
||||
this.client.waitFor(() => {
|
||||
return imeKeyboard.displayed();
|
||||
});
|
||||
}
|
||||
};
|
||||
340
gaia/apps/keyboard/test/marionette/lib/keyboard.js
Executable file
340
gaia/apps/keyboard/test/marionette/lib/keyboard.js
Executable file
|
|
@ -0,0 +1,340 @@
|
|||
'use strict';
|
||||
|
||||
var Base = require('./base');
|
||||
var Marionette = require('marionette-client');
|
||||
|
||||
|
||||
function Keyboard(client) {
|
||||
Base.call(this, client);
|
||||
|
||||
this.actions = new Marionette.Actions(client);
|
||||
this.currentLayout = null;
|
||||
}
|
||||
|
||||
module.exports = Keyboard;
|
||||
|
||||
Keyboard.Selectors = Object.freeze({
|
||||
currentPanel:
|
||||
'.keyboard-type-container[data-active]',
|
||||
imeSwitchingKey:
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'.keyboard-key[data-keycode="-3"]',
|
||||
backspaceKey:
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'.keyboard-key[data-keycode="8"]',
|
||||
returnKey:
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'.keyboard-key[data-l10n-id="returnKey2"]',
|
||||
spaceBarKey: '.keyboard-type-container[data-active]' +
|
||||
' .keyboard-key[data-keycode="32"]',
|
||||
dismissSuggestionsKey:
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'.dismiss-suggestions-button',
|
||||
shiftKey:
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'button.keyboard-key[data-l10n-id="upperCaseKey2"]',
|
||||
autoCorrectWord:
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'.autocorrect',
|
||||
});
|
||||
|
||||
Keyboard.Templates = Object.freeze({
|
||||
key:
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'button.keyboard-key[data-keycode="%s"], ' +
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'button.keyboard-key[data-keycode-upper="%s"]',
|
||||
upperCaseKey:
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'button.keyboard-key[data-keycode-upper="%s"]',
|
||||
pageSwitchingKey:
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'button.keyboard-key[data-target-page="%s"]',
|
||||
suggestionKey:
|
||||
'.keyboard-type-container[data-active] ' +
|
||||
'.suggestions-container span[data-data="%s"]',
|
||||
});
|
||||
|
||||
Keyboard.LONGPRESS_CHARS = Object.freeze({
|
||||
'0': 'º',
|
||||
'?': '¿',
|
||||
'$': '€£¥',
|
||||
'!': '¡',
|
||||
'a': 'áàâäåãāæ',
|
||||
'c': 'çćč',
|
||||
'e': 'éèêëēę€ɛ',
|
||||
'i': 'įīîìíï',
|
||||
'l': '£ł',
|
||||
'n': 'ńñ',
|
||||
'o': 'ɵøœōôòóö',
|
||||
's': 'ßśš$',
|
||||
'u': 'ūûùúü',
|
||||
'y': '¥ÿ',
|
||||
'z': 'žźż',
|
||||
'A': 'ÁÀÂÄÅÃĀÆ',
|
||||
'C': 'ÇĆČ',
|
||||
'E': 'ÉÈÊËĒĘ€Ɛ',
|
||||
'I': 'ĮĪÎÌÍÏ',
|
||||
'L': '£Ł',
|
||||
'N': 'ŃÑ',
|
||||
'O': 'ƟØŒŌÔÒÓÖ',
|
||||
'S': 'ŚŠŞ',
|
||||
'U': 'ŪÛÙÚÜ',
|
||||
'Y': '¥Ÿ',
|
||||
'Z': 'ŽŹŻ'
|
||||
});
|
||||
|
||||
Keyboard.TypeGroupMap = Object.freeze({
|
||||
'text': 'text',
|
||||
'textarea': 'text',
|
||||
'url': 'url',
|
||||
'email': 'email',
|
||||
'password': 'password',
|
||||
'search': 'text',
|
||||
'number': 'number',
|
||||
'tel': 'number'
|
||||
});
|
||||
|
||||
Keyboard.prototype = {
|
||||
__proto__: Base.prototype,
|
||||
|
||||
get currentPanel() {
|
||||
return this.client.findElement(Keyboard.Selectors.currentPanel);
|
||||
},
|
||||
|
||||
get imeSwitchingKey() {
|
||||
return this.client.findElement(Keyboard.Selectors.imeSwitchingKey);
|
||||
},
|
||||
|
||||
get backspaceKey() {
|
||||
return this.client.findElement(Keyboard.Selectors.backspaceKey);
|
||||
},
|
||||
|
||||
get returnKey() {
|
||||
return this.client.findElement(Keyboard.Selectors.returnKey);
|
||||
},
|
||||
|
||||
get spaceBarKey() {
|
||||
return this.client.findElement(Keyboard.Selectors.spaceBarKey);
|
||||
},
|
||||
|
||||
get shiftKey() {
|
||||
return this.client.findElement(Keyboard.Selectors.shiftKey);
|
||||
},
|
||||
|
||||
get dismissSuggestionsKey() {
|
||||
return this.client.findElement(Keyboard.Selectors.dismissSuggestionsKey);
|
||||
},
|
||||
|
||||
get autoCorrectWord() {
|
||||
return this.client.findElement(Keyboard.Selectors.autoCorrectWord);
|
||||
},
|
||||
|
||||
getKey: function(char) {
|
||||
var selector = Keyboard.Templates.key.replace(/%s/g, char.charCodeAt(0));
|
||||
return this.client.findElement(selector);
|
||||
},
|
||||
|
||||
getPageSwitchingKey: function(index) {
|
||||
var selector = Keyboard.Templates.pageSwitchingKey.replace(/%s/g, index);
|
||||
return this.client.findElement(selector);
|
||||
},
|
||||
|
||||
getSuggestionKey: function(word) {
|
||||
var selector = Keyboard.Templates.suggestionKey.replace(/%s/, word);
|
||||
return this.client.findElement(selector);
|
||||
},
|
||||
|
||||
getLongPressCharMiddleKey: function(char) {
|
||||
var chars = Keyboard.LONGPRESS_CHARS;
|
||||
|
||||
for (var middleChar in chars) {
|
||||
if (chars[middleChar].indexOf(char) !== -1) {
|
||||
return middleChar;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getCurrentInputType: function() {
|
||||
return this.client.executeScript(
|
||||
'return window.wrappedJSObject.app.getBasicInputType();');
|
||||
},
|
||||
|
||||
getCurrentInputMode: function() {
|
||||
return this.client.executeScript(
|
||||
'return window.wrappedJSObject.app.inputContext.inputMode;');
|
||||
},
|
||||
|
||||
getCurrentPageIndex: function() {
|
||||
return this.client.executeScript(
|
||||
'return window.wrappedJSObject.app.layoutManager.currentPageIndex;');
|
||||
},
|
||||
|
||||
getCurrentKeyboardLayout: function() {
|
||||
var keyboardFrame;
|
||||
|
||||
this.client.switchToFrame();
|
||||
|
||||
keyboardFrame = this.client.findElement(
|
||||
'#keyboards .inputWindow.active iframe');
|
||||
this.currentLayout = keyboardFrame.getAttribute('data-frame-name');
|
||||
this.switchTo();
|
||||
|
||||
return this.currentLayout;
|
||||
},
|
||||
|
||||
getSymbolPageIndex: function(key) {
|
||||
this.switchToPage(1);
|
||||
|
||||
if (this.isKeyPresent(key)) {
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
},
|
||||
|
||||
tapBackspaceKey: function(word) {
|
||||
this.backspaceKey.tap();
|
||||
},
|
||||
|
||||
tapAutoCorrectWord: function() {
|
||||
this.client.waitFor(() => {
|
||||
return this.autoCorrectWord.displayed();
|
||||
});
|
||||
this.autoCorrectWord.tap();
|
||||
},
|
||||
|
||||
tapSuggestionWord: function(word) {
|
||||
this.getSuggestionKey(word).tap();
|
||||
},
|
||||
|
||||
isUpperCase: function() {
|
||||
return this.client.executeScript(
|
||||
'return ' +
|
||||
'window.wrappedJSObject.app.upperCaseStateManager.isUpperCase;');
|
||||
},
|
||||
|
||||
isElementPresent: function(selector) {
|
||||
var pollClient = this.client.scope({ searchTimeout: 50 });
|
||||
|
||||
try {
|
||||
pollClient.findElement(selector);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
isKeyPresent: function(key) {
|
||||
var keyTemplate = Keyboard.Templates.key;
|
||||
|
||||
return this.isElementPresent(keyTemplate.replace(/%s/g, key.charCodeAt(0)));
|
||||
},
|
||||
|
||||
switchCase: function(isUpperCase) {
|
||||
if (isUpperCase === undefined || this.isUpperCase() === isUpperCase) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.shiftKey.tap();
|
||||
this.client.waitFor(() => {
|
||||
var expected = isUpperCase ? 'true' : 'false';
|
||||
|
||||
return (this.shiftKey.getAttribute('aria-pressed') === expected);
|
||||
});
|
||||
},
|
||||
|
||||
switchToPage: function(index) {
|
||||
var pageIndex = this.getCurrentPageIndex();
|
||||
|
||||
if (index === undefined || pageIndex === index) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.getPageSwitchingKey(index).tap();
|
||||
this.client.waitFor(() => {
|
||||
return (this.getCurrentPageIndex() === index);
|
||||
});
|
||||
this.waitForPageReady();
|
||||
},
|
||||
|
||||
switchToKeyLayout: function(key) {
|
||||
var page;
|
||||
var upperCase;
|
||||
var currentLayout = this.currentLayout || this.getCurrentKeyboardLayout();
|
||||
|
||||
if (['number'].indexOf(currentLayout) !== -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key >= '0' && key <= '9') {
|
||||
page = 1;
|
||||
} else if (key >= 'A' && key <='Z') {
|
||||
page = 0;
|
||||
upperCase = true;
|
||||
} else if (key >= 'a' && key <= 'z') {
|
||||
page = 0;
|
||||
upperCase = false;
|
||||
} else if (key === ' ' || key === '\u0008' || key === '\u000d') {
|
||||
|
||||
} else {
|
||||
page = this.getSymbolPageIndex(key);
|
||||
}
|
||||
|
||||
this.switchToPage(page);
|
||||
this.switchCase(upperCase);
|
||||
},
|
||||
|
||||
type: function(string) {
|
||||
string.split('').forEach((char) => {
|
||||
var middleChar = this.getLongPressCharMiddleKey(char);
|
||||
var lookingForKey = middleChar || char;
|
||||
var keyElement;
|
||||
|
||||
this.switchToKeyLayout(lookingForKey);
|
||||
|
||||
if (!middleChar) {
|
||||
keyElement = this.getKey(char);
|
||||
|
||||
this.actions.wait(0.1).tap(keyElement).perform();
|
||||
} else {
|
||||
keyElement = this.getKey(middleChar);
|
||||
|
||||
this.actions
|
||||
.press(keyElement).wait(1.5).perform()
|
||||
.move(this.getKey(char)).wait(0.2).release().perform();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
longPressSpaceBar: function(time) {
|
||||
this.actions.longPress(this.spaceBarKey, time).perform();
|
||||
},
|
||||
|
||||
switchTo: function() {
|
||||
var systemInputMgmt = this.client.loader.getAppClass(
|
||||
'system', 'input_management');
|
||||
|
||||
systemInputMgmt.waitForKeyboardFrameDisplayed();
|
||||
systemInputMgmt.switchToActiveKeyboardFrame();
|
||||
|
||||
this.waitForPageReady();
|
||||
},
|
||||
|
||||
waitForPageReady: function() {
|
||||
this.client.waitFor(() => {
|
||||
return this.currentPanel.displayed();
|
||||
});
|
||||
},
|
||||
|
||||
waitForKeyboardReady: function() {
|
||||
this.client.switchToFrame();
|
||||
|
||||
this.client.waitFor(() => {
|
||||
return this.client.findElement(
|
||||
'#keyboards .inputWindow .browser-container');
|
||||
});
|
||||
}
|
||||
};
|
||||
50
gaia/apps/keyboard/test/marionette/lib/keyboard_settings.js
Executable file
50
gaia/apps/keyboard/test/marionette/lib/keyboard_settings.js
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
'use strict';
|
||||
|
||||
var Base = require('./base.js');
|
||||
|
||||
|
||||
function KeyboardSettings(client) {
|
||||
this.client = client.scope({ searchTimeout: 500 });
|
||||
|
||||
Base.call(this, client, KeyboardSettings.ORIGIN);
|
||||
}
|
||||
|
||||
module.exports = KeyboardSettings;
|
||||
|
||||
KeyboardSettings.ORIGIN = 'app://keyboard.gaiamobile.org';
|
||||
|
||||
KeyboardSettings.Selectors = Object.freeze({
|
||||
autoCorrectCheckBox: '#cb-autoCorrect'
|
||||
});
|
||||
|
||||
KeyboardSettings.prototype = {
|
||||
__proto__: Base.prototype,
|
||||
|
||||
get autoCorrectCheckBox() {
|
||||
return this.client.findElement(
|
||||
KeyboardSettings.Selectors.autoCorrectCheckBox);
|
||||
},
|
||||
|
||||
get autoCorrect() {
|
||||
return this.autoCorrectCheckBox.scriptWith(function(ele) {
|
||||
return ele.wrappedJSObject.checked;
|
||||
});
|
||||
},
|
||||
|
||||
clickAutoCorrectOption: function() {
|
||||
var currentSwitch = this.client.settings.get('keyboard.autocorrect');
|
||||
|
||||
this.autoCorrectCheckBox.click();
|
||||
|
||||
this.client.waitFor(() => {
|
||||
return (this.autoCorrect !== currentSwitch);
|
||||
});
|
||||
},
|
||||
|
||||
waitForReady: function() {
|
||||
this.client.waitFor(() => {
|
||||
return this.autoCorrectCheckBox.displayed();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
97
gaia/apps/keyboard/test/marionette/lib/keyboard_test_app.js
Executable file
97
gaia/apps/keyboard/test/marionette/lib/keyboard_test_app.js
Executable file
|
|
@ -0,0 +1,97 @@
|
|||
'use strict';
|
||||
|
||||
var Base = require('./base');
|
||||
|
||||
|
||||
function KeyboardTests(client) {
|
||||
Base.call(this, client, KeyboardTests.ORIGIN);
|
||||
}
|
||||
|
||||
module.exports = KeyboardTests;
|
||||
|
||||
KeyboardTests.ORIGIN = 'app://keyboardtestapp.gaiamobile.org';
|
||||
|
||||
KeyboardTests.Selector = Object.freeze({
|
||||
textInput: '#textInput',
|
||||
textareaInput: '#textareaInput',
|
||||
urlInput: '#urlInput',
|
||||
emailInput: '#emailInput',
|
||||
passwordInput: '#passwordInput',
|
||||
searchInput: '#searchInput',
|
||||
numberInput: '#numberInput',
|
||||
telInput: '#telInput',
|
||||
nonInputArea: '#nonInput',
|
||||
triggerPromptButton: '#triggerPromptButton',
|
||||
promptResult: '#promptResult'
|
||||
});
|
||||
|
||||
KeyboardTests.prototype = {
|
||||
__proto__: Base.prototype,
|
||||
|
||||
get textInput() {
|
||||
return this.client.findElement(KeyboardTests.Selector.textInput);
|
||||
},
|
||||
|
||||
get textareaInput() {
|
||||
return this.client.findElement(KeyboardTests.Selector.textareaInput);
|
||||
},
|
||||
|
||||
get urlInput() {
|
||||
return this.client.findElement(KeyboardTests.Selector.urlInput);
|
||||
},
|
||||
|
||||
get emailInput() {
|
||||
return this.client.findElement(KeyboardTests.Selector.emailInput);
|
||||
},
|
||||
|
||||
get passwordInput() {
|
||||
return this.client.findElement(KeyboardTests.Selector.passwordInput);
|
||||
},
|
||||
|
||||
get searchInput() {
|
||||
return this.client.findElement(KeyboardTests.Selector.searchInput);
|
||||
},
|
||||
|
||||
get numberInput() {
|
||||
return this.client.findElement(KeyboardTests.Selector.numberInput);
|
||||
},
|
||||
|
||||
get telInput() {
|
||||
return this.client.findElement(KeyboardTests.Selector.telInput);
|
||||
},
|
||||
|
||||
get nonInputArea() {
|
||||
return this.client.findElement(KeyboardTests.Selector.nonInputArea);
|
||||
},
|
||||
|
||||
get triggerPromptButton() {
|
||||
return this.client.findElement(KeyboardTests.Selector.triggerPromptButton);
|
||||
},
|
||||
|
||||
get promptResult() {
|
||||
return this.client.findElement(KeyboardTests.Selector.promptResult);
|
||||
},
|
||||
|
||||
triggerPromptModalDialog: function() {
|
||||
this.triggerPromptButton.tap();
|
||||
},
|
||||
|
||||
waitForReady: function() {
|
||||
var inputs = [
|
||||
this.textInput,
|
||||
this.textareaInput,
|
||||
this.urlInput,
|
||||
this.emailInput,
|
||||
this.passwordInput,
|
||||
this.searchInput,
|
||||
this.numberInput,
|
||||
this.telInput
|
||||
];
|
||||
|
||||
this.client.waitFor(() => {
|
||||
return inputs.every((ele) => {
|
||||
return ele.displayed();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
74
gaia/apps/keyboard/test/marionette/number_keyboard_test.js
Executable file
74
gaia/apps/keyboard/test/marionette/number_keyboard_test.js
Executable file
|
|
@ -0,0 +1,74 @@
|
|||
'use strict';
|
||||
|
||||
var KeyboardTestApp = require('./lib/keyboard_test_app'),
|
||||
Keyboard = require('./lib/keyboard'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('Number keyboard input tests', function() {
|
||||
var apps = {};
|
||||
var keyboardTestApp = null;
|
||||
var keyboard = null;
|
||||
var client = null;
|
||||
var system = null;
|
||||
|
||||
apps[KeyboardTestApp.ORIGIN] = __dirname + '/apps/keyboardtestapp';
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
apps: apps,
|
||||
prefs: {
|
||||
'focusmanager.testmode': true
|
||||
},
|
||||
settings: {
|
||||
'lockscreen.enabled': false,
|
||||
'ftu.manifestURL': null
|
||||
}
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
system = client.loader.getAppClass('system');
|
||||
system.waitForFullyLoaded();
|
||||
|
||||
keyboard = new Keyboard(client);
|
||||
keyboardTestApp = new KeyboardTestApp(client);
|
||||
|
||||
keyboard.waitForKeyboardReady();
|
||||
|
||||
keyboardTestApp.launch();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.numberInput.tap();
|
||||
|
||||
keyboard.switchTo();
|
||||
});
|
||||
|
||||
test('Should be number layout', function() {
|
||||
assert.equal(
|
||||
keyboard.getCurrentKeyboardLayout(), Keyboard.TypeGroupMap.number);
|
||||
});
|
||||
|
||||
test('Alphabet should not present on keyboard', function() {
|
||||
var testAlphabetKey = 'a';
|
||||
|
||||
assert.equal(keyboard.isKeyPresent(testAlphabetKey), false);
|
||||
});
|
||||
|
||||
test('Type 1', function() {
|
||||
var inputString = '1';
|
||||
keyboard.type(inputString);
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.numberInput.getAttribute('value'), inputString);
|
||||
});
|
||||
|
||||
test('Type 7997979979', function() {
|
||||
var inputString = '7997979979';
|
||||
keyboard.type(inputString);
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.numberInput.getAttribute('value'), inputString);
|
||||
});
|
||||
});
|
||||
134
gaia/apps/keyboard/test/marionette/switching_test.js
Executable file
134
gaia/apps/keyboard/test/marionette/switching_test.js
Executable file
|
|
@ -0,0 +1,134 @@
|
|||
'use strict';
|
||||
|
||||
var KeyboardTestApp = require('./lib/keyboard_test_app');
|
||||
var ImeTestApp = require('./lib/ime_test_app');
|
||||
var Keyboard = require('./lib/keyboard');
|
||||
var assert = require('assert');
|
||||
|
||||
marionette('Switch Keyboard App', function() {
|
||||
var keyboardTestApp = null;
|
||||
var keyboard = null;
|
||||
var systemInputMgmt = null;
|
||||
var imeTestApp = null;
|
||||
var client = null;
|
||||
var actions = null;
|
||||
var apps = {};
|
||||
var system = null;
|
||||
|
||||
// Pre-install keyboard testing app
|
||||
apps[KeyboardTestApp.ORIGIN] = __dirname + '/apps/keyboardtestapp';
|
||||
|
||||
// And a testing 3rd-party IME app
|
||||
apps[ImeTestApp.ORIGIN] = __dirname + '/apps/imetestapp';
|
||||
|
||||
var keyboardSettings = {};
|
||||
keyboardSettings[Keyboard.MANIFEST_URL] = {
|
||||
'en': true,
|
||||
'number': true
|
||||
};
|
||||
|
||||
// Enable a testing IME app
|
||||
keyboardSettings[ImeTestApp.MANIFEST_URL] = {
|
||||
'lol': true
|
||||
};
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
apps: apps,
|
||||
prefs: {
|
||||
'focusmanager.testmode': true
|
||||
},
|
||||
settings: {
|
||||
'keyboard.enabled-layouts': keyboardSettings
|
||||
}
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
/*
|
||||
* To check the 3rd-party IME is shown.
|
||||
*/
|
||||
function check3rdPartyIme() {
|
||||
// switch back to system
|
||||
client.switchToFrame();
|
||||
|
||||
// wait for the 2nd keyboard is loaded
|
||||
systemInputMgmt.ensureInputWindowCount(2);
|
||||
systemInputMgmt.switchToActiveKeyboardFrame();
|
||||
|
||||
assert.ok(imeTestApp.sendKeyButton.displayed());
|
||||
}
|
||||
|
||||
setup(function() {
|
||||
actions = client.loader.getActions();
|
||||
systemInputMgmt = client.loader.getAppClass('system', 'input_management');
|
||||
system = client.loader.getAppClass('system');
|
||||
system.waitForFullyLoaded();
|
||||
|
||||
|
||||
imeTestApp = new ImeTestApp(client);
|
||||
keyboard = new Keyboard(client);
|
||||
keyboardTestApp = new KeyboardTestApp(client);
|
||||
|
||||
keyboard.waitForKeyboardReady();
|
||||
|
||||
keyboardTestApp.launch();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.urlInput.click();
|
||||
keyboard.switchTo();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.textInput.click();
|
||||
|
||||
// Wait for the keyboard pop up and switch to it
|
||||
keyboard.switchTo();
|
||||
});
|
||||
|
||||
test('Checking the switching IME function is available', function() {
|
||||
var imeSwitchingKey = keyboard.imeSwitchingKey;
|
||||
assert.ok(imeSwitchingKey.displayed());
|
||||
|
||||
// Click to switch to next IME
|
||||
imeSwitchingKey.click();
|
||||
check3rdPartyIme();
|
||||
});
|
||||
|
||||
test('Long press to show the IME menu', function() {
|
||||
var imeSwitchingKey = keyboard.imeSwitchingKey;
|
||||
|
||||
// Long press to show IME menu
|
||||
actions.longPress(imeSwitchingKey, 0.7).perform();
|
||||
|
||||
// switch back to system
|
||||
client.switchToFrame();
|
||||
var imeMenu = systemInputMgmt.imeMenu;
|
||||
assert.ok(imeMenu.displayed());
|
||||
|
||||
// select the 3rd-party IME
|
||||
systemInputMgmt.selectImeOption(1);
|
||||
check3rdPartyIme();
|
||||
});
|
||||
|
||||
test('Drag down the utility tray', function() {
|
||||
// Swipe to drag down the utility tray
|
||||
systemInputMgmt.dragDownUtilityTray();
|
||||
|
||||
// Check the IME switching buttion in notification
|
||||
var imeNotification = systemInputMgmt.imeNotification;
|
||||
client.waitFor(function() {
|
||||
return imeNotification.displayed();
|
||||
});
|
||||
|
||||
imeNotification.click();
|
||||
|
||||
assert.ok(systemInputMgmt.imeMenu.displayed());
|
||||
//XXX: Wait for the previous keyboard to hide or we may not be able to
|
||||
// switch to the next keyboard.
|
||||
client.waitFor(function() {
|
||||
return systemInputMgmt.keyboardFrameHidden();
|
||||
});
|
||||
|
||||
// select the 3rd-party IME
|
||||
systemInputMgmt.selectImeOption(1);
|
||||
check3rdPartyIme();
|
||||
});
|
||||
});
|
||||
119
gaia/apps/keyboard/test/marionette/text_keyboard_test.js
Executable file
119
gaia/apps/keyboard/test/marionette/text_keyboard_test.js
Executable file
|
|
@ -0,0 +1,119 @@
|
|||
'use strict';
|
||||
|
||||
var KeyboardTestApp = require('./lib/keyboard_test_app'),
|
||||
Dialog = require('../../../system/test/marionette/lib/dialog'),
|
||||
Keyboard = require('./lib/keyboard'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('Text keyboard input tests', function() {
|
||||
var apps = {};
|
||||
var keyboardTestApp = null;
|
||||
var keyboard = null;
|
||||
var systemInputMgmt = null;
|
||||
var client = null;
|
||||
var system = null;
|
||||
|
||||
apps[KeyboardTestApp.ORIGIN] = __dirname + '/apps/keyboardtestapp';
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
apps: apps,
|
||||
prefs: {
|
||||
'focusmanager.testmode': true
|
||||
},
|
||||
settings: {
|
||||
'lockscreen.enabled': false,
|
||||
'ftu.manifestURL': null
|
||||
}
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
systemInputMgmt = client.loader.getAppClass('system', 'input_management');
|
||||
system = client.loader.getAppClass('system');
|
||||
system.waitForFullyLoaded();
|
||||
|
||||
keyboard = new Keyboard(client);
|
||||
keyboardTestApp = new KeyboardTestApp(client);
|
||||
|
||||
keyboard.waitForKeyboardReady();
|
||||
|
||||
keyboardTestApp.launch();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.textInput.tap();
|
||||
|
||||
keyboard.switchTo();
|
||||
});
|
||||
|
||||
test('Type abc', function() {
|
||||
var inputString = 'abc';
|
||||
keyboard.type(inputString);
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), inputString);
|
||||
});
|
||||
|
||||
test('Type multiple alphabet', function() {
|
||||
var inputString = 'aGDsaIabcmvljdDFDFDDs śZîd';
|
||||
keyboard.type(inputString);
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), inputString);
|
||||
});
|
||||
|
||||
test('Type number and then alphabet', function() {
|
||||
var inputString = '123abc';
|
||||
keyboard.type(inputString);
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), inputString);
|
||||
});
|
||||
|
||||
test('Type alphabet and then number', function() {
|
||||
var inputString = 'abc123';
|
||||
keyboard.type(inputString);
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), inputString);
|
||||
});
|
||||
|
||||
test('Type symbols', function() {
|
||||
var inputString = 'aG1 !@#$&*-_/(),.:;"\'?[]{}<>+=`^~|\\%';
|
||||
keyboard.type(inputString);
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textInput.getAttribute('value'), inputString);
|
||||
});
|
||||
|
||||
var dialog;
|
||||
|
||||
test('Type into an window.prompt() dialog and hit enter', function() {
|
||||
// Hide keyboard before click prompt
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.nonInputArea.tap();
|
||||
client.waitFor(() => {
|
||||
return !systemInputMgmt.keyboardFrameDisplayed();
|
||||
});
|
||||
|
||||
dialog = new Dialog(client);
|
||||
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.triggerPromptModalDialog();
|
||||
client.switchToFrame();
|
||||
|
||||
dialog.promptInput.tap();
|
||||
keyboard.switchTo();
|
||||
keyboard.type('lazy dog.');
|
||||
keyboard.getKey('\u000d').tap();
|
||||
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal('lazy dog.', keyboardTestApp.promptResult.text());
|
||||
});
|
||||
});
|
||||
100
gaia/apps/keyboard/test/marionette/textarea_keyboard_test.js
Executable file
100
gaia/apps/keyboard/test/marionette/textarea_keyboard_test.js
Executable file
|
|
@ -0,0 +1,100 @@
|
|||
'use strict';
|
||||
|
||||
var KeyboardTestApp = require('./lib/keyboard_test_app'),
|
||||
Keyboard = require('./lib/keyboard'),
|
||||
assert = require('assert');
|
||||
|
||||
marionette('Textarea keyboard input tests', function() {
|
||||
var apps = {};
|
||||
var keyboardTestApp = null;
|
||||
var keyboard = null;
|
||||
var client = null;
|
||||
var system = null;
|
||||
|
||||
apps[KeyboardTestApp.ORIGIN] = __dirname + '/apps/keyboardtestapp';
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
apps: apps,
|
||||
prefs: {
|
||||
'focusmanager.testmode': true
|
||||
},
|
||||
settings: {
|
||||
'lockscreen.enabled': false,
|
||||
'ftu.manifestURL': null
|
||||
}
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
system = client.loader.getAppClass('system');
|
||||
system.waitForFullyLoaded();
|
||||
|
||||
keyboard = new Keyboard(client);
|
||||
keyboardTestApp = new KeyboardTestApp(client);
|
||||
|
||||
keyboard.waitForKeyboardReady();
|
||||
|
||||
keyboardTestApp.launch();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.textareaInput.tap();
|
||||
|
||||
keyboard.switchTo();
|
||||
});
|
||||
|
||||
test('Type Abc', function() {
|
||||
var inputString = 'Abc';
|
||||
keyboard.type(inputString.substring(0, 1));
|
||||
|
||||
var shiftKey = keyboard.shiftKey;
|
||||
client.waitFor(function() {
|
||||
return (shiftKey.getAttribute('aria-pressed') === 'false');
|
||||
});
|
||||
keyboard.type(inputString.substring(1));
|
||||
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
keyboardTestApp.textareaInput.getAttribute('value'), inputString);
|
||||
});
|
||||
|
||||
test('Double tapping space bar', function() {
|
||||
var inputString = 'Aa';
|
||||
keyboard.type(inputString);
|
||||
|
||||
client.waitFor(() => {
|
||||
return keyboard.autoCorrectWord.displayed();
|
||||
});
|
||||
// type 2 spaces
|
||||
keyboard.type(' ');
|
||||
|
||||
// Switch to test app frame.
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal(
|
||||
'As. ', keyboardTestApp.textareaInput.getAttribute('value'));
|
||||
});
|
||||
|
||||
test('Tap space bar and then wait for a while before tapping again',
|
||||
function() {
|
||||
var inputString = 'Aa';
|
||||
keyboard.type(inputString);
|
||||
|
||||
client.waitFor(() => {
|
||||
return keyboard.autoCorrectWord.displayed();
|
||||
});
|
||||
|
||||
// type one space and then tap again after a while
|
||||
keyboard.type(' ');
|
||||
|
||||
// The timeout for double tapping is set as 700ms.
|
||||
client.helper.wait(800);
|
||||
keyboard.type(' ');
|
||||
|
||||
// Switch to test app frame.
|
||||
keyboardTestApp.switchTo();
|
||||
|
||||
assert.equal('As ', keyboardTestApp.textareaInput.getAttribute('value'));
|
||||
});
|
||||
});
|
||||
127
gaia/apps/keyboard/test/marionette/uninstallation_test.js
Executable file
127
gaia/apps/keyboard/test/marionette/uninstallation_test.js
Executable file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* This test is to ensure that system's keyboard manager would
|
||||
* correctly show the built-in keyboard app after the previous activated
|
||||
* keyboard has been removed.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var KeyboardTestApp = require('./lib/keyboard_test_app');
|
||||
var ImeTestApp = require('./lib/ime_test_app');
|
||||
var Keyboard = require('./lib/keyboard');
|
||||
var assert = require('assert');
|
||||
|
||||
marionette('Show keyboard app after uninstallation', function() {
|
||||
var keyboardTestApp = null;
|
||||
var keyboard = null;
|
||||
var systemInputMgmt = null;
|
||||
var system = null;
|
||||
var imeTestApp = null;
|
||||
var appInstall = null;
|
||||
var client = null;
|
||||
var apps = {};
|
||||
var confirmDialog = null;
|
||||
|
||||
// Pre-install keyboard testing app
|
||||
apps[KeyboardTestApp.ORIGIN] = __dirname + '/apps/keyboardtestapp';
|
||||
|
||||
// And a testing 3rd-party IME app
|
||||
apps[ImeTestApp.ORIGIN] = __dirname + '/apps/imetestapp';
|
||||
|
||||
var keyboardSettings = {};
|
||||
keyboardSettings[Keyboard.MANIFEST_URL] = {
|
||||
'en': true,
|
||||
'number': true
|
||||
};
|
||||
|
||||
// Enable a testing IME app
|
||||
keyboardSettings[ImeTestApp.MANIFEST_URL] = {
|
||||
'lol': true
|
||||
};
|
||||
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
apps: apps,
|
||||
prefs: {
|
||||
'focusmanager.testmode': true
|
||||
},
|
||||
settings: {
|
||||
'keyboard.enabled-layouts': keyboardSettings
|
||||
}
|
||||
},
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
|
||||
/*
|
||||
* To check the 3rd-party IME is shown.
|
||||
*/
|
||||
function check3rdPartyIme() {
|
||||
// switch back to system
|
||||
client.switchToFrame();
|
||||
|
||||
// wait for the 2nd keyboard is loaded
|
||||
systemInputMgmt.ensureInputWindowCount(2);
|
||||
systemInputMgmt.switchToActiveKeyboardFrame();
|
||||
|
||||
return imeTestApp.sendKeyButton.displayed();
|
||||
}
|
||||
|
||||
setup(function() {
|
||||
systemInputMgmt = client.loader.getAppClass('system', 'input_management');
|
||||
system = client.loader.getAppClass('system');
|
||||
system.waitForFullyLoaded();
|
||||
|
||||
keyboard = new Keyboard(client);
|
||||
appInstall = client.loader.getAppClass('system', 'app_install');
|
||||
confirmDialog = client.loader.getAppClass('system', 'confirm_dialog');
|
||||
imeTestApp = new ImeTestApp(client);
|
||||
|
||||
keyboard.waitForKeyboardReady();
|
||||
|
||||
// create a keyboard test app
|
||||
keyboardTestApp = new KeyboardTestApp(client);
|
||||
keyboardTestApp.launch();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.urlInput.click();
|
||||
keyboard.switchTo();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.textInput.click();
|
||||
keyboard.switchTo();
|
||||
keyboard.imeSwitchingKey.click();
|
||||
|
||||
// Click to switch to next IME
|
||||
check3rdPartyIme();
|
||||
|
||||
|
||||
// XXX: Blur the input field, otherwise the keyboard frame has higher
|
||||
// z-index than dialog and we can't click it
|
||||
systemInputMgmt.waitForKeyboardFrameDisplayed();
|
||||
keyboardTestApp.switchTo();
|
||||
keyboardTestApp.nonInputArea.click();
|
||||
|
||||
// Uninstall the current active IME
|
||||
appInstall.uninstall(ImeTestApp.MANIFEST_URL);
|
||||
client.switchToFrame();
|
||||
confirmDialog.confirm('remove');
|
||||
|
||||
// Click the input field again to check the built-in keyboard
|
||||
keyboardTestApp.switchTo();
|
||||
// XXX: do something to remove the focus
|
||||
keyboardTestApp.nonInputArea.click();
|
||||
keyboardTestApp.textInput.click();
|
||||
|
||||
// Wait for the keyboard pop up and switch to it
|
||||
keyboard.switchTo();
|
||||
});
|
||||
|
||||
test('Fallback to built-in keyboard when the active IME has been ' +
|
||||
'uninstalled', function() {
|
||||
assert.ok(keyboard.currentPanel.displayed());
|
||||
});
|
||||
|
||||
test('Should not show IME switching key after uninstallation', function() {
|
||||
// Since the switching key is gone, we would show ',' on the first page
|
||||
var commaKey = keyboard.getKey(',');
|
||||
assert.ok(commaKey.displayed());
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue