chromium/chrome/test/data/chromeos/virtual_keyboard/default_extension/layout_test.js

/*
 * Copyright 2014 The Chromium Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * Verifies that the layout matches with expectations.
 * @param {Array<string>} rows List of strings where each string indicates the
 *     expected sequence of characters on the corresponding row.
 */
function verifyLayout(rows) {
  var rowIndex = 1;
  rows.forEach(function(sequence) {
    var rowId = 'row' + rowIndex++;
    var first = sequence[0];
    var key = findKey(first, rowId);
    assertTrue(!!key, 'Unable to find "' + first + '" in "' + rowId + '"');
    key = getSoftKeyView(key);
    for (var i = 1; i < sequence.length; i++) {
      var next = key.nextSibling;
      assertTrue(
          !!next, 'Unable to find key to right of "' + sequence[i - 1] + '"');
      assertTrue(
          hasLabel(next, sequence[i]),
          'Unexpected label: expected: "' + sequence[i] + '" to follow "' +
              sequence[i - 1] + '"');
      key = next;
    }
  });
}

/**
 * Validates full layout for a US QWERTY keyboard.
 */
function testFullQwertyLayoutAsync(testDoneCallback) {
  var testCallback = function() {
    var lowercase =
        ['`1234567890-=', 'qwertyuiop[]\\', 'asdfghjkl;\'', 'zxcvbnm,./'];
    var uppercase =
        ['~!@#$%^&*()_+', 'QWERTYUIOP{}', 'ASDFGHJKL:"', 'ZXCVBNM<>?'];
    var view = getActiveView();
    assertTrue(!!view, 'Unable to find active view');
    assertEquals('us', view.id, 'Expecting full layout');
    verifyLayout(lowercase);
    mockTap(findKeyById('ShiftLeft'));
    verifyLayout(uppercase);
    mockTap(findKeyById('ShiftRight'));
    verifyLayout(lowercase);
    testDoneCallback();
  };
  var config =
      {keyset: 'us', languageCode: 'en', passwordLayout: 'us', name: 'English'};
  onKeyboardReady(testCallback, config);
}

/**
 * Validates compact layout for a US QWERTY keyboard.
 */
function testCompactQwertyLayoutAsync(testDoneCallback) {
  var testCallback = function() {
    var lowercase = ['qwertyuiop', 'asdfghjkl', 'zxcvbnm!?'];
    var uppercase = ['QWERTYUIOP', 'ASDFGHJKL', 'ZXCVBNM!?'];
    var symbol = ['1234567890', '@#$%&-+()', '\\=*"\':;!?'];
    var more = [
      '~`|', '\u00a3\u00a2\u20ac\u00a5^\u00b0={}',
      '\\\u00a9\u00ae\u2122\u2105[]\u00a1\u00bf'
    ];
    var view = getActiveView();
    assertTrue(!!view, 'Unable to find active view');
    assertEquals('us-compact-qwerty', view.id, 'Expecting compact layout');
    verifyLayout(lowercase);
    mockTap(findKeyById('ShiftLeft'));
    verifyLayout(uppercase);
    // Keyset views for symbol and more on the compact layout are lazy
    // initialized. Wait for view creation to complete before continuing the
    // test.
    onKeysetsReady(['us.compact.symbol', 'us.compact.more'], function() {
      onSwitchToKeyset('us.compact.symbol', function() {
        assertEquals(
            'us-compact-symbol', getActiveView().id, 'Expecting symbol layout');
        verifyLayout(symbol);
        onSwitchToKeyset('us.compact.more', function() {
          assertEquals(
              'us-compact-more', getActiveView().id,
              'Expecting more symbols layout');
          verifyLayout(more);
          onSwitchToKeyset('us.compact.qwerty', function() {
            assertEquals(
                'us-compact-qwerty', getActiveView().id,
                'Expecting compact text layout');
            verifyLayout(lowercase);
            testDoneCallback();
          });
          mockTap(findKey('abc'));
        });
        mockTap(findKey('~[<'));
      });
      mockTap(findKey('?123'));
    });
  };
  var config = {
    keyset: 'us.compact.qwerty',
    languageCode: 'en',
    passwordLayout: 'us',
    name: 'English'
  };
  onKeyboardReady(testCallback, config);
}

/**
 * Tests that handwriting support is disabled by default.
 */
function testHandwritingSupportAsync(testDoneCallback) {
  onKeyboardReady(function() {
    var menu = document.querySelector('.inputview-menu-view');
    assertTrue(!!menu, 'Unable to access keyboard menu');
    assertEquals(
        'none', getComputedStyle(menu)['display'],
        'Menu should not be visible until activated');
    mockTap(findKeyById('Menu'));
    assertEquals(
        'block', getComputedStyle(menu)['display'],
        'Menu should be visible once activated');
    var hwt = menu.querySelector('#handwriting');
    assertFalse(!!hwt, 'Handwriting should be disabled by default');
    testDoneCallback();
  });
}

/**
 * Validates Handwriting layout. Though handwriting is disabled for the system
 * VK, the layout is still available and useful for testing expected behavior of
 * the IME-VKs since the codebase is shared.
 */
function testHandwritingLayoutAsync(testDoneCallback) {
  var compactKeysets = [
    'us.compact.qwerty', 'us.compact.symbol', 'us.compact.more',
    'us.compact.numberpad'
  ];
  var testCallback = function() {
    // Non-active keysets are lazy loaded in order to reduce latency before
    // the virtual keyboard is shown. Wait until the load is complete to
    // continue testing.
    onKeysetsReady(compactKeysets, function() {
      var menu = document.querySelector('.inputview-menu-view');
      assertEquals(
          'none', getComputedStyle(menu).display,
          'Menu should be hidden initially');
      mockTap(findKeyById('Menu'));
      assertFalse(
          menu.hidden,
          'Menu should be visible after tapping menu toggle button');
      var menuBounds = menu.getBoundingClientRect();
      assertTrue(
          menuBounds.width > 0 && menuBounds.height > 0,
          'Expect non-zero menu bounds.');
      var hwtSelect = menu.querySelector('#handwriting');
      assertTrue(!!hwtSelect, 'Handwriting should be available for testing');
      var hwtSelectBounds = hwtSelect.getBoundingClientRect();
      assertTrue(
          hwtSelectBounds.width > 0 && hwtSelectBounds.height > 0,
          'Expect non-zero size for hwt select button.');
      onSwitchToKeyset('hwt', function() {
        // The tests below for handwriting part is for material design.
        var view = getActiveView();
        assertEquals('hwt', view.id, 'Handwriting layout is not active.');
        var hwtCanvasView = view.querySelector('#canvasView');
        assertTrue(!!hwtCanvasView, 'Unable to find canvas view');
        var panelView = document.getElementById('panelView');
        assertTrue(!!panelView, 'Unable to find panel view');
        var backButton = panelView.querySelector('#backToKeyboard');
        assertTrue(!!backButton, 'Unable to find back button.');
        onSwitchToKeyset('us.compact.qwerty', function() {
          assertEquals(
              'us-compact-qwerty', getActiveView().id,
              'compact layout is not active.');
          testDoneCallback();
        });
        mockTap(backButton);
      });
      mockTap(hwtSelect);
    });
  };
  var config = {
    keyset: 'us.compact.qwerty',
    languageCode: 'en',
    passwordLayout: 'us',
    name: 'English',
    options: {enableHwtForTesting: true}
  };
  onKeyboardReady(testCallback, config);
}

/**
 * Test that IME switching from the InputView menu works.
 */
function testKeyboardSwitchIMEAsync(testDoneCallback) {
  var testCallback = function() {
    // Ensure that the menu key is present and displays the menu when pressed.
    var menu = document.querySelector('.inputview-menu-view');
    assertEquals(
        'none', getComputedStyle(menu).display,
        'Menu should be hidden initially');
    mockTap(findKeyById('Menu'));
    assertFalse(
        menu.hidden, 'Menu should be visible after tapping menu toggle button');
    var menuBounds = menu.getBoundingClientRect();
    assertTrue(
        menuBounds.width > 0 && menuBounds.height > 0,
        'Expect non-zero menu bounds.');

    var imes = menu.querySelectorAll('.inputview-menu-list-indicator-name');
    assertEquals(3, imes.length, 'Unexpected number of IMEs in menu view.');
    assertEquals('US', imes[0].innerText, 'Unexpected IMEs in menu view');
    assertEquals('Fr', imes[1].innerText, 'Unexpected IMEs in menu view');
    assertEquals('De', imes[2].innerText, 'Unexpected IMEs in menu view');

    // Expect a call to change to the German IME.
    chrome.inputMethodPrivate.setCurrentInputMethod.addExpectation('de');

    // Select the German IME and ensure that the menu is dismissed.
    mockTap(imes[2]);
    assertEquals('none', menu.style.display, 'Menu didn\'t hide on switch.');

    testDoneCallback();
  };
  var config = {
    keyset: 'us.compact.qwerty',
    languageCode: 'en',
    passwordLayout: 'us',
    name: 'English'
  };
  // Explicitly set up the available input methods.
  chrome.inputMethodPrivate.getInputMethods.setCallbackData([
    {id: 'us', name: 'US Keyboard', indicator: 'US'},
    {id: 'fr', name: 'French Keyboard', indicator: 'Fr'},
    {id: 'de', name: 'German Keyboard', indicator: 'De'}
  ]);
  onKeyboardReady(testCallback, config);
}