settings_format_browsertest.js revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * TestFixture for testing the formatting of settings pages.
7 * @extends {testing.Test}
8 * @constructor
9 */
10function SettingsFormatWebUITest() {}
11
12/**
13 * Map of rule exemptions grouped by test.
14 * @const
15 */
16SettingsFormatWebUITest.Filters = {
17  /**
18   * Exemption for checkboxes that do not require an id or pref property.
19   * Input methods use inputMethodId instead of id for unique identification.
20   */
21  'pref': ['language-options-input-method-template',
22           'language-options-input-method-list']
23};
24
25/**
26 * Collection of error messages.
27 * @const
28 */
29SettingsFormatWebUITest.Messages = {
30    MISSING_CHECK_WRAPPER: 'Element $1 should be enclosed in <div class="$2">',
31    MISSING_ID_OR_PREF: 'Missing id or pref preoperty for checkbox $1.',
32    MISSING_RADIO_BUTTON_NAME: 'Radio button $1 is missing the name property',
33    MISSING_RADIO_BUTTON_VALUE: 'Radio button $1 is missing the value property',
34};
35
36SettingsFormatWebUITest.prototype = {
37  __proto__: testing.Test.prototype,
38
39  /**
40   * Navigate to browser settings.
41   */
42  browsePreload: 'chrome://settings-frame/',
43
44  /**
45   * List of errors generated during a test. Used instead of expect* functions
46   * to suppress verbosity. The implementation of errorsToMessage in the
47   * testing API generates a call stack for each error produced which greatly
48   * reduces readability.
49   * @type {Array.<string>}
50   */
51  errors: null,
52
53  setUp: function() {
54    this.errors = [];
55  },
56
57  tearDown: function() {
58    assertTrue(this.errors.length == 0, '\n' + this.errors.join('\n'));
59  },
60
61  /**
62   * Generates a failure message. During tear down of the test, the accumulation
63   * of pending messages triggers a test failure.
64   * @param {string} key Label of the message formatting string.
65   * @param {!Element} element The element that triggered the failure.
66   * @param {...string} args Additional arguments for formatting the message.
67   */
68  fail: function(key, element, args) {
69    var subs = [this.getLabel(element)].concat(
70        Array.prototype.slice.call(arguments, 2));
71    var message = SettingsFormatWebUITest.Messages[key].replace(
72        /\$\d/g,
73        function(m) {
74      return subs[m[1] - 1] || '$' + m[1];
75    });
76    assertFalse(/\$\d/.test(message), 'found unreplaced subs');
77    this.errors.push(message);
78  },
79
80 /**
81  * String for identifying a node within an error message.
82  * @param {!Element} element The target element to identify.
83  * @return {string} Name to facilitate tracking down the element.
84  */
85  getLabel: function(element) {
86    if (element.id)
87      return element.id;
88
89    if (element.pref)
90      return element.pref;
91
92    if (element.name && element.value)
93      return element.name + '-' + element.value;
94
95    return this.getLabel(element.parentNode);
96  },
97
98
99  /**
100   * Checks if the node is exempt from following the formatting rule.
101   * @param {!Element} element The candidate element.
102   * @param {Array.<string>} filters List of exemptions.
103   * @return {boolean} True if the element is exempt.
104   */
105  isExempt: function(element, filters) {
106    var target = this.getLabel(element);
107    for (var i = 0; i < filters.length; i++) {
108      if (filters[i] == target)
109        return true;
110    }
111    return false;
112  }
113};
114
115/**
116 * Ensure that radio and checkbox buttons have consistent layout.
117 */
118TEST_F('SettingsFormatWebUITest', 'RadioCheckboxStyleCheck', function() {
119  var settings = $('settings');
120  assertTrue(settings != null, 'Unable to access settings');
121  var query = 'input[type=checkbox], input[type=radio]';
122  var elements = document.querySelectorAll(query);
123  assertTrue(elements.length > 0);
124  for (var i = 0; i < elements.length; i++) {
125    var element = elements[i];
126    if (!findAncestorByClass(element, element.type))
127      this.fail('MISSING_CHECK_WRAPPER', element, element.type);
128  }
129});
130
131/**
132 * Each checkbox requires an id or pref property.
133 */
134TEST_F('SettingsFormatWebUITest', 'CheckboxIdOrPrefCheck', function() {
135  var query =
136      'input[type=checkbox]:not([pref]):not([id]):not(.spacer-checkbox)';
137  var elements = document.querySelectorAll(query);
138  for (var i = 0; i < elements.length; i++) {
139    var element = elements[i];
140    if (!this.isExempt(element, SettingsFormatWebUITest.Filters['pref']))
141      this.fail('MISSING_ID_OR_PREF', element);
142  }
143});
144
145/**
146 * Each radio button requires name and value properties.
147 */
148TEST_F('SettingsFormatWebUITest', 'RadioButtonNameValueCheck', function() {
149  var elements = document.querySelectorAll('input[type=radio]');
150  for (var i = 0; i < elements.length; i++) {
151    var element = elements[i];
152    if (!element.name)
153      this.fail('MISSING_RADIO_BUTTON_NAME', element);
154
155    if (!element.getAttribute('value'))
156      this.fail('MISSING_RADIO_BUTTON_VALUE', element);
157  }
158});
159