Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Side by Side Diff: chrome/test/data/webui/settings/languages_page_tests.js

Issue 2867213002: Fix CrSettingsLanguagesPageTest dialog flake (Closed)
Patch Set: Use MutationObserver Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/test/data/webui/settings/cr_settings_browsertest.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 cr.define('languages_page_tests', function() { 5 cr.define('languages_page_tests', function() {
6 /** @enum {string} */ 6 /** @enum {string} */
7 const TestNames = { 7 const TestNames = {
8 AddLanguagesDialog: 'add languages dialog', 8 AddLanguagesDialog: 'add languages dialog',
9 LanguageMenu: 'language menu', 9 LanguageMenu: 'language menu',
10 InputMethods: 'input methods', 10 InputMethods: 'input methods',
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 70
71 teardown(function() { 71 teardown(function() {
72 PolymerTest.clearBody(); 72 PolymerTest.clearBody();
73 }); 73 });
74 74
75 suite(TestNames.AddLanguagesDialog, function() { 75 suite(TestNames.AddLanguagesDialog, function() {
76 var dialog; 76 var dialog;
77 var dialogItems; 77 var dialogItems;
78 var cancelButton; 78 var cancelButton;
79 var actionButton; 79 var actionButton;
80 var dialogClosedResolver;
81 var dialogClosedObserver;
82
83 // Resolves the PromiseResolver if the mutation includes removal of the
84 // settings-add-languages-dialog.
85 // TODO(michaelpg): Extract into a common method similar to
86 // test_util.whenAttributeIs for use elsewhere.
87 var onMutation = function(mutations, observer) {
dpapad 2017/05/16 00:19:43 Is this actually called with multiple mutations? C
michaelpg 2017/05/16 19:57:39 It's called a number of times, sometimes with seve
88 if (mutations.some(function(mutation) {
89 return mutation.type == 'childList' &&
90 Array.from(mutation.removedNodes).includes(dialog);
91 })) {
92 // Sanity check: the dialog should no longer be in the DOM.
93 assertEquals(null, languagesPage.$$('settings-add-languages-dialog'));
94 observer.disconnect();
95 assertTrue(!!dialogClosedResolver);
96 dialogClosedResolver.resolve();
97 }
98 };
80 99
81 setup(function(done) { 100 setup(function(done) {
82 var addLanguagesButton = 101 var addLanguagesButton =
83 languagesCollapse.querySelector('#addLanguages'); 102 languagesCollapse.querySelector('#addLanguages');
84 MockInteractions.tap(addLanguagesButton); 103 MockInteractions.tap(addLanguagesButton);
85 104
86 // The page stamps the dialog, registers listeners, and populates the 105 // The page stamps the dialog, registers listeners, and populates the
87 // iron-list asynchronously at microtask timing, so wait for a new task. 106 // iron-list asynchronously at microtask timing, so wait for a new task.
88 setTimeout(function() { 107 setTimeout(function() {
89 dialog = languagesPage.$$('settings-add-languages-dialog'); 108 dialog = languagesPage.$$('settings-add-languages-dialog');
90 assertTrue(!!dialog); 109 assertTrue(!!dialog);
91 110
111 // Observe the removal of the dialog via MutationObserver since the
112 // HTMLDialogElement 'close' event fires at an unpredictable time.
113 dialogClosedResolver = new PromiseResolver;
dpapad 2017/05/16 00:19:43 Nit (optional): new PromiseResolver()? It seems th
michaelpg 2017/05/16 19:57:39 Done. but I'm wary of forcing style opinions with
114 dialogClosedObserver = new MutationObserver(onMutation);
115 dialogClosedObserver.observe(languagesPage.root, {childList: true});
116
92 actionButton = assert(dialog.$$('.action-button')); 117 actionButton = assert(dialog.$$('.action-button'));
93 cancelButton = assert(dialog.$$('.cancel-button')); 118 cancelButton = assert(dialog.$$('.cancel-button'));
94 119
95 // The fixed-height dialog's iron-list should stamp far fewer than 120 // The fixed-height dialog's iron-list should stamp far fewer than
96 // 50 items. 121 // 50 items.
97 dialogItems = 122 dialogItems =
98 dialog.$.dialog.querySelectorAll('.list-item:not([hidden])'); 123 dialog.$.dialog.querySelectorAll('.list-item:not([hidden])');
99 assertGT(dialogItems.length, 1); 124 assertGT(dialogItems.length, 1);
100 assertLT(dialogItems.length, 50); 125 assertLT(dialogItems.length, 50);
101 126
102 // No languages have been checked, so the action button is disabled. 127 // No languages have been checked, so the action button is disabled.
103 assertTrue(actionButton.disabled); 128 assertTrue(actionButton.disabled);
104 assertFalse(cancelButton.disabled); 129 assertFalse(cancelButton.disabled);
105 130
106 done(); 131 done();
107 }); 132 });
108 }); 133 });
109 134
110 // After every test, check that the dialog is removed from the DOM.
111 teardown(function() { 135 teardown(function() {
112 Polymer.dom.flush(); 136 dialogClosedObserver.disconnect();
113 assertEquals(null, languagesPage.$$('settings-add-languages-dialog'));
114 }); 137 });
115 138
116 test('cancel', function() { 139 test('cancel', function() {
117 // Canceling the dialog should close and remove it. 140 // Canceling the dialog should close and remove it.
118 MockInteractions.tap(cancelButton); 141 MockInteractions.tap(cancelButton);
142
143 return dialogClosedResolver.promise;
119 }); 144 });
120 145
121 test('add languages and cancel', function(done) { 146 test('add languages and cancel', function() {
122 // Check some languages. 147 // Check some languages.
123 MockInteractions.tap(dialogItems[1]); // en-CA. 148 MockInteractions.tap(dialogItems[1]); // en-CA.
124 MockInteractions.tap(dialogItems[2]); // tk. 149 MockInteractions.tap(dialogItems[2]); // tk.
125 150
126 // Canceling the dialog should close and remove it without enabling 151 // Canceling the dialog should close and remove it without enabling
127 // the checked languages. A small timeout lets us check this. 152 // the checked languages.
128 MockInteractions.tap(cancelButton); 153 MockInteractions.tap(cancelButton);
129 setTimeout(function() { 154 return dialogClosedResolver.promise.then(function() {
130 assertEquals(initialLanguages, 155 assertEquals(initialLanguages,
131 languageHelper.getPref(languagesPref).value); 156 languageHelper.getPref(languagesPref).value);
132 done(); 157 });
133 }, 100);
134 }); 158 });
135 159
136 test('add languages and confirm', function() { 160 test('add languages and confirm', function() {
137 // No languages have been checked, so the action button is inert. 161 // No languages have been checked, so the action button is inert.
138 MockInteractions.tap(actionButton); 162 MockInteractions.tap(actionButton);
139 Polymer.dom.flush(); 163 Polymer.dom.flush();
140 assertEquals(dialog, languagesPage.$$('settings-add-languages-dialog')); 164 assertEquals(dialog, languagesPage.$$('settings-add-languages-dialog'));
141 165
142 // Check and uncheck one language. 166 // Check and uncheck one language.
143 MockInteractions.tap(dialogItems[0]); 167 MockInteractions.tap(dialogItems[0]);
144 assertFalse(actionButton.disabled); 168 assertFalse(actionButton.disabled);
145 MockInteractions.tap(dialogItems[0]); 169 MockInteractions.tap(dialogItems[0]);
146 assertTrue(actionButton.disabled); 170 assertTrue(actionButton.disabled);
147 171
148 // Check multiple languages. 172 // Check multiple languages.
149 MockInteractions.tap(dialogItems[0]); // en. 173 MockInteractions.tap(dialogItems[0]); // en.
150 MockInteractions.tap(dialogItems[2]); // tk. 174 MockInteractions.tap(dialogItems[2]); // tk.
151 assertFalse(actionButton.disabled); 175 assertFalse(actionButton.disabled);
152 176
153 // The action button should close and remove the dialog, enabling the 177 // The action button should close and remove the dialog, enabling the
154 // checked languages. 178 // checked languages.
155 MockInteractions.tap(actionButton); 179 MockInteractions.tap(actionButton);
156 180
157 assertEquals( 181 assertEquals(
158 initialLanguages + ',en,tk', 182 initialLanguages + ',en,tk',
159 languageHelper.getPref(languagesPref).value); 183 languageHelper.getPref(languagesPref).value);
184
185 return dialogClosedResolver.promise;
160 }); 186 });
161 }); 187 });
162 188
163 suite(TestNames.LanguageMenu, function() { 189 suite(TestNames.LanguageMenu, function() {
164 /* 190 /*
165 * Finds, asserts and returns the menu item for the given i18n key. 191 * Finds, asserts and returns the menu item for the given i18n key.
166 * @param {string} i18nKey Name of the i18n string for the item's text. 192 * @param {string} i18nKey Name of the i18n string for the item's text.
167 * @return {!HTMLElement} Menu item. 193 * @return {!HTMLElement} Menu item.
168 */ 194 */
169 function getMenuItem(i18nKey) { 195 function getMenuItem(i18nKey) {
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 // Now the secondary row is empty, so it shouldn't be shown. 412 // Now the secondary row is empty, so it shouldn't be shown.
387 assertFalse(triggerRow.classList.contains('two-line')); 413 assertFalse(triggerRow.classList.contains('two-line'));
388 assertEquals( 414 assertEquals(
389 0, triggerRow.querySelector('.secondary').textContent.length); 415 0, triggerRow.querySelector('.secondary').textContent.length);
390 } 416 }
391 }); 417 });
392 }); 418 });
393 419
394 return {TestNames: TestNames}; 420 return {TestNames: TestNames};
395 }); 421 });
OLDNEW
« no previous file with comments | « chrome/test/data/webui/settings/cr_settings_browsertest.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698