12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * TestFixture for testing the formatting of settings pages.
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @extends {testing.Test}
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @constructor
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function SettingsFormatWebUITest() {}
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Map of rule exemptions grouped by test.
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SettingsFormatWebUITest.Filters = {
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /**
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * Exemption for checkboxes that do not require an id or pref property.
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * Input methods use inputMethodId instead of id for unique identification.
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   */
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  'pref': ['language-options-input-method-template',
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           'language-options-input-method-list']
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Collection of error messages.
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SettingsFormatWebUITest.Messages = {
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MISSING_CHECK_WRAPPER: 'Element $1 should be enclosed in <div class="$2">',
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MISSING_ID_OR_PREF: 'Missing id or pref preoperty for checkbox $1.',
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MISSING_RADIO_BUTTON_NAME: 'Radio button $1 is missing the name property',
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MISSING_RADIO_BUTTON_VALUE: 'Radio button $1 is missing the value property',
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SettingsFormatWebUITest.prototype = {
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  __proto__: testing.Test.prototype,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /**
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * Navigate to browser settings.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   */
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  browsePreload: 'chrome://settings-frame/',
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /**
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * List of errors generated during a test. Used instead of expect* functions
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * to suppress verbosity. The implementation of errorsToMessage in the
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * testing API generates a call stack for each error produced which greatly
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * reduces readability.
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * @type {Array.<string>}
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   */
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  errors: null,
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  setUp: function() {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.errors = [];
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  },
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  tearDown: function() {
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    assertTrue(this.errors.length == 0, '\n' + this.errors.join('\n'));
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  },
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /**
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * Generates a failure message. During tear down of the test, the accumulation
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * of pending messages triggers a test failure.
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * @param {string} key Label of the message formatting string.
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * @param {!Element} element The element that triggered the failure.
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * @param {...string} args Additional arguments for formatting the message.
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   */
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fail: function(key, element, args) {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var subs = [this.getLabel(element)].concat(
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        Array.prototype.slice.call(arguments, 2));
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var message = SettingsFormatWebUITest.Messages[key].replace(
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        /\$\d/g,
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        function(m) {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return subs[m[1] - 1] || '$' + m[1];
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    });
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    assertFalse(/\$\d/.test(message), 'found unreplaced subs');
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.errors.push(message);
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  },
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /**
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  * String for identifying a node within an error message.
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  * @param {!Element} element The target element to identify.
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  * @return {string} Name to facilitate tracking down the element.
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  */
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  getLabel: function(element) {
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (element.id)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return element.id;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (element.pref)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return element.pref;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (element.name && element.value)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return element.name + '-' + element.value;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return this.getLabel(element.parentNode);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  },
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /**
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * Checks if the node is exempt from following the formatting rule.
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * @param {!Element} element The candidate element.
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * @param {Array.<string>} filters List of exemptions.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * @return {boolean} True if the element is exempt.
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   */
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  isExempt: function(element, filters) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var target = this.getLabel(element);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (var i = 0; i < filters.length; i++) {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (filters[i] == target)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return true;
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Ensure that radio and checkbox buttons have consistent layout.
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F('SettingsFormatWebUITest', 'RadioCheckboxStyleCheck', function() {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var settings = $('settings');
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  assertTrue(settings != null, 'Unable to access settings');
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var query = 'input[type=checkbox], input[type=radio]';
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var elements = document.querySelectorAll(query);
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  assertTrue(elements.length > 0);
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (var i = 0; i < elements.length; i++) {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var element = elements[i];
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!findAncestorByClass(element, element.type))
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this.fail('MISSING_CHECK_WRAPPER', element, element.type);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)});
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Each checkbox requires an id or pref property.
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F('SettingsFormatWebUITest', 'CheckboxIdOrPrefCheck', function() {
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var query =
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      'input[type=checkbox]:not([pref]):not([id]):not(.spacer-checkbox)';
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var elements = document.querySelectorAll(query);
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (var i = 0; i < elements.length; i++) {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var element = elements[i];
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!this.isExempt(element, SettingsFormatWebUITest.Filters['pref']))
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this.fail('MISSING_ID_OR_PREF', element);
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)});
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Each radio button requires name and value properties.
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F('SettingsFormatWebUITest', 'RadioButtonNameValueCheck', function() {
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var elements = document.querySelectorAll('input[type=radio]');
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (var i = 0; i < elements.length; i++) {
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var element = elements[i];
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!element.name)
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this.fail('MISSING_RADIO_BUTTON_NAME', element);
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (!element.getAttribute('value'))
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this.fail('MISSING_RADIO_BUTTON_VALUE', element);
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)});
159