blob: ef0d9dc6b024748994a93bc7904dfd1e2e1ff374 [file] [log] [blame]
Andrew Bonventref8b026d2015-12-09 17:55:54 -05001<!DOCTYPE html>
2<!--
3Copyright (C) 2015 The Android Open Source Project
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16-->
17
18<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
Andrew Bonventre882043f2016-02-22 18:12:27 -050019<title>gr-reply-dialog</title>
Andrew Bonventref8b026d2015-12-09 17:55:54 -050020
Viktar Donich29e1ce52017-03-28 17:02:44 -070021<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
Andrew Bonventre78792e82016-03-04 17:48:22 -050022<script src="../../../bower_components/web-component-tester/browser.js"></script>
Andrew Bonventref8b026d2015-12-09 17:55:54 -050023
Andrew Bonventre78792e82016-03-04 17:48:22 -050024<link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
25<link rel="import" href="gr-reply-dialog.html">
Andrew Bonventref8b026d2015-12-09 17:55:54 -050026
Viktar Donich29e1ce52017-03-28 17:02:44 -070027<script>void(0);</script>
28
Andrew Bonventref8b026d2015-12-09 17:55:54 -050029<test-fixture id="basic">
30 <template>
Andrew Bonventre882043f2016-02-22 18:12:27 -050031 <gr-reply-dialog></gr-reply-dialog>
Andrew Bonventref8b026d2015-12-09 17:55:54 -050032 </template>
33</test-fixture>
34
35<script>
Kasper Nilssonad908b12017-05-11 11:26:10 -070036 suite('gr-reply-dialog tests', () => {
37 let element;
38 let changeNum;
39 let patchNum;
Wyatt Allen4f4b3a72016-07-28 12:05:53 -070040
Kasper Nilssonad908b12017-05-11 11:26:10 -070041 let sandbox;
42 let getDraftCommentStub;
43 let setDraftCommentStub;
44 let eraseDraftCommentStub;
Andrew Bonventref8b026d2015-12-09 17:55:54 -050045
Kasper Nilssonad908b12017-05-11 11:26:10 -070046 let lastId = 0;
47 const makeAccount = function() { return {_account_id: lastId++}; };
48 const makeGroup = function() { return {id: lastId++}; };
Kasper Nilssona8271552017-01-17 11:54:40 -080049
Kasper Nilssonad908b12017-05-11 11:26:10 -070050 setup(() => {
Wyatt Allen4f4b3a72016-07-28 12:05:53 -070051 sandbox = sinon.sandbox.create();
52
53 changeNum = 42;
54 patchNum = 1;
55
Andrew Bonventre5c09ba92016-05-02 17:31:23 -040056 stub('gr-rest-api-interface', {
Kasper Nilssonad908b12017-05-11 11:26:10 -070057 getConfig() { return Promise.resolve({}); },
58 getAccount() { return Promise.resolve({}); },
Andrew Bonventrecfacb802016-03-29 14:06:39 -040059 });
Wyatt Allen4f4b3a72016-07-28 12:05:53 -070060
Andrew Bonventref8b026d2015-12-09 17:55:54 -050061 element = fixture('basic');
Kasper Nilsson352b68f2016-10-11 11:51:35 -070062 element.change = {
63 _number: changeNum,
64 labels: {
Kasper Nilssonad908b12017-05-11 11:26:10 -070065 'Verified': {
Kasper Nilsson352b68f2016-10-11 11:51:35 -070066 values: {
67 '-1': 'Fails',
68 ' 0': 'No score',
69 '+1': 'Verified',
70 },
71 default_value: 0,
Andrew Bonventref8b026d2015-12-09 17:55:54 -050072 },
Kasper Nilsson352b68f2016-10-11 11:51:35 -070073 'Code-Review': {
74 values: {
75 '-2': 'Do not submit',
76 '-1': 'I would prefer that you didn\'t submit this',
77 ' 0': 'No score',
78 '+1': 'Looks good to me, but someone else must approve',
79 '+2': 'Looks good to me, approved',
80 },
81 default_value: 0,
82 },
Andrew Bonventref8b026d2015-12-09 17:55:54 -050083 },
Andrew Bonventref8b026d2015-12-09 17:55:54 -050084 };
Kasper Nilsson352b68f2016-10-11 11:51:35 -070085 element.patchNum = patchNum;
Andrew Bonventref8b026d2015-12-09 17:55:54 -050086 element.permittedLabels = {
87 'Code-Review': [
88 '-1',
89 ' 0',
Kasper Nilsson352b68f2016-10-11 11:51:35 -070090 '+1',
Andrew Bonventref8b026d2015-12-09 17:55:54 -050091 ],
Kasper Nilssonad908b12017-05-11 11:26:10 -070092 'Verified': [
Andrew Bonventref8b026d2015-12-09 17:55:54 -050093 '-1',
94 ' 0',
Kasper Nilsson352b68f2016-10-11 11:51:35 -070095 '+1',
96 ],
Andrew Bonventref8b026d2015-12-09 17:55:54 -050097 };
Logan Hanksa75fb052016-08-01 13:23:38 -070098 element.serverConfig = {};
Andrew Bonventref8b026d2015-12-09 17:55:54 -050099
Wyatt Allen4f4b3a72016-07-28 12:05:53 -0700100 getDraftCommentStub = sandbox.stub(element.$.storage, 'getDraftComment');
101 setDraftCommentStub = sandbox.stub(element.$.storage, 'setDraftComment');
102 eraseDraftCommentStub = sandbox.stub(element.$.storage,
103 'eraseDraftComment');
104
Wyatt Allen6cf58752017-04-24 16:59:07 +0200105 sandbox.stub(element, 'fetchIsLatestKnown',
Kasper Nilssonad908b12017-05-11 11:26:10 -0700106 () => { return Promise.resolve(true); });
Wyatt Allen6cf58752017-04-24 16:59:07 +0200107
Andrew Bonventref8b026d2015-12-09 17:55:54 -0500108 // Allow the elements created by dom-repeat to be stamped.
109 flushAsynchronousOperations();
110 });
111
Kasper Nilssonad908b12017-05-11 11:26:10 -0700112 teardown(() => {
Wyatt Allen4f4b3a72016-07-28 12:05:53 -0700113 sandbox.restore();
114 });
115
Kasper Nilssonad908b12017-05-11 11:26:10 -0700116 test('default to publishing drafts with reply', done => {
Becky Siegel9efcd572017-03-23 08:28:03 -0700117 // Async tick is needed because iron-selector content is distributed and
118 // distributed content requires an observer to be set up.
119 // Note: Double flush seems to be needed in Safari. {@see Issue 4963}.
Kasper Nilssonad908b12017-05-11 11:26:10 -0700120 flush(() => {
121 flush(() => {
Becky Siegel9efcd572017-03-23 08:28:03 -0700122 element.draft = 'I wholeheartedly disapprove';
123
Kasper Nilssonad908b12017-05-11 11:26:10 -0700124 sandbox.stub(element, '_saveReview', review => {
Becky Siegel9efcd572017-03-23 08:28:03 -0700125 assert.deepEqual(review, {
126 drafts: 'PUBLISH_ALL_REVISIONS',
127 labels: {},
128 message: 'I wholeheartedly disapprove',
129 reviewers: [],
130 });
131 assert.isFalse(element.$.commentList.hidden);
132 done();
133 return Promise.resolve({ok: true});
134 });
135
136 // This is needed on non-Blink engines most likely due to the ways in
137 // which the dom-repeat elements are stamped.
Kasper Nilssonad908b12017-05-11 11:26:10 -0700138 flush(() => {
Becky Siegel9efcd572017-03-23 08:28:03 -0700139 MockInteractions.tap(element.$$('.send'));
140 });
141 });
142 });
143 });
144
Kasper Nilssonad908b12017-05-11 11:26:10 -0700145 test('keep drafts with reply', done => {
Becky Siegel9efcd572017-03-23 08:28:03 -0700146 MockInteractions.tap(element.$$('#includeComments'));
147 assert.equal(element._includeComments, false);
148
149 // Async tick is needed because iron-selector content is distributed and
150 // distributed content requires an observer to be set up.
151 // Note: Double flush seems to be needed in Safari. {@see Issue 4963}.
Kasper Nilssonad908b12017-05-11 11:26:10 -0700152 flush(() => {
153 flush(() => {
Becky Siegel9efcd572017-03-23 08:28:03 -0700154 element.draft = 'I wholeheartedly disapprove';
155
Kasper Nilssonad908b12017-05-11 11:26:10 -0700156 sandbox.stub(element, '_saveReview', review => {
Becky Siegel9efcd572017-03-23 08:28:03 -0700157 assert.deepEqual(review, {
158 drafts: 'KEEP',
159 labels: {},
160 message: 'I wholeheartedly disapprove',
161 reviewers: [],
162 });
163 assert.isTrue(element.$.commentList.hidden);
164 done();
165 return Promise.resolve({ok: true});
166 });
167
168 // This is needed on non-Blink engines most likely due to the ways in
169 // which the dom-repeat elements are stamped.
Kasper Nilssonad908b12017-05-11 11:26:10 -0700170 flush(() => {
Becky Siegel9efcd572017-03-23 08:28:03 -0700171 MockInteractions.tap(element.$$('.send'));
172 });
173 });
174 });
175 });
176
Kasper Nilssonad908b12017-05-11 11:26:10 -0700177 test('label picker', done => {
Becky Siegela499e3d2017-04-06 16:57:13 -0700178 element.draft = 'I wholeheartedly disapprove';
Kasper Nilssonad908b12017-05-11 11:26:10 -0700179 sandbox.stub(element, '_saveReview', review => {
Becky Siegela499e3d2017-04-06 16:57:13 -0700180 assert.deepEqual(review, {
181 drafts: 'PUBLISH_ALL_REVISIONS',
182 labels: {
183 'Code-Review': -1,
184 'Verified': -1,
185 },
186 message: 'I wholeheartedly disapprove',
187 reviewers: [],
Urs Wolferb6036942016-03-06 14:57:02 +0100188 });
Becky Siegela499e3d2017-04-06 16:57:13 -0700189 return Promise.resolve({ok: true});
190 });
191
Kasper Nilssonad908b12017-05-11 11:26:10 -0700192 sandbox.stub(element.$.labelScores, 'getLabelValues', () => {
Becky Siegela499e3d2017-04-06 16:57:13 -0700193 return {
194 'Code-Review': -1,
195 'Verified': -1,
196 };
197 });
198
Kasper Nilssonad908b12017-05-11 11:26:10 -0700199 element.addEventListener('send', () => {
Becky Siegela499e3d2017-04-06 16:57:13 -0700200 assert.isFalse(element.disabled,
201 'Element should be enabled when done sending reply.');
202 assert.equal(element.draft.length, 0);
203 done();
204 });
205
206 // This is needed on non-Blink engines most likely due to the ways in
207 // which the dom-repeat elements are stamped.
Kasper Nilssonad908b12017-05-11 11:26:10 -0700208 flush(() => {
Becky Siegela499e3d2017-04-06 16:57:13 -0700209 MockInteractions.tap(element.$$('.send'));
210 assert.isTrue(element.disabled);
Urs Wolferb6036942016-03-06 14:57:02 +0100211 });
Andrew Bonventref8b026d2015-12-09 17:55:54 -0500212 });
Logan Hanksa008aa92016-07-22 10:31:12 -0700213
Kasper Nilssonad908b12017-05-11 11:26:10 -0700214 test('setlabelValue', () => {
Becky Siegel452a5c62017-05-09 09:59:55 -0700215 element._account = {_account_id: 1};
216 flushAsynchronousOperations();
Kasper Nilssonad908b12017-05-11 11:26:10 -0700217 const label = 'Verified';
218 const value = '+1';
Becky Siegel452a5c62017-05-09 09:59:55 -0700219 element.setLabelValue(label, value);
220 flushAsynchronousOperations();
Kasper Nilssonad908b12017-05-11 11:26:10 -0700221 const labels = element.$.labelScores.getLabelValues();
222 assert.deepEqual(labels, {Verified: 1});
Becky Siegel452a5c62017-05-09 09:59:55 -0700223 });
224
Logan Hanksa008aa92016-07-22 10:31:12 -0700225 function getActiveElement() {
226 return Polymer.IronOverlayManager.deepActiveElement;
227 }
228
229 function isVisible(el) {
230 assert.ok(el);
231 return getComputedStyle(el).getPropertyValue('display') != 'none';
232 }
233
234 function overlayObserver(mode) {
Kasper Nilssonad908b12017-05-11 11:26:10 -0700235 return new Promise(resolve => {
Logan Hanksa008aa92016-07-22 10:31:12 -0700236 function listener() {
237 element.removeEventListener('iron-overlay-' + mode, listener);
238 resolve();
239 }
240 element.addEventListener('iron-overlay-' + mode, listener);
241 });
242 }
243
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800244 function testConfirmationDialog(done, cc) {
Kasper Nilssonad908b12017-05-11 11:26:10 -0700245 const yesButton =
Logan Hanksa008aa92016-07-22 10:31:12 -0700246 element.$$('.reviewerConfirmationButtons gr-button:first-child');
Kasper Nilssonad908b12017-05-11 11:26:10 -0700247 const noButton =
Logan Hanksa008aa92016-07-22 10:31:12 -0700248 element.$$('.reviewerConfirmationButtons gr-button:last-child');
249
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800250 element.serverConfig = {note_db_enabled: true};
251 element._ccPendingConfirmation = null;
Logan Hanksa008aa92016-07-22 10:31:12 -0700252 element._reviewerPendingConfirmation = null;
253 flushAsynchronousOperations();
254 assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
255
256 // Cause the confirmation dialog to display.
Kasper Nilssonad908b12017-05-11 11:26:10 -0700257 let observer = overlayObserver('opened');
258 const group = {
Logan Hanksa008aa92016-07-22 10:31:12 -0700259 id: 'id',
260 name: 'name',
Logan Hanksa008aa92016-07-22 10:31:12 -0700261 };
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800262 if (cc) {
263 element._ccPendingConfirmation = {
Kasper Nilssonad908b12017-05-11 11:26:10 -0700264 group,
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800265 count: 10,
266 };
267 } else {
268 element._reviewerPendingConfirmation = {
Kasper Nilssonad908b12017-05-11 11:26:10 -0700269 group,
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800270 count: 10,
271 };
272 }
273 flushAsynchronousOperations();
274
275 if (cc) {
276 assert.deepEqual(
277 element._ccPendingConfirmation,
278 element._pendingConfirmationDetails);
279 } else {
280 assert.deepEqual(
281 element._reviewerPendingConfirmation,
282 element._pendingConfirmationDetails);
283 }
Logan Hanksa008aa92016-07-22 10:31:12 -0700284
Kasper Nilssonad908b12017-05-11 11:26:10 -0700285 observer.then(() => {
Logan Hanksa008aa92016-07-22 10:31:12 -0700286 assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
287 observer = overlayObserver('closed');
Kasper Nilssonad908b12017-05-11 11:26:10 -0700288 const expected = 'Group name has 10 members';
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800289 assert.notEqual(
290 element.$.reviewerConfirmationOverlay.innerText.indexOf(expected),
291 -1);
Logan Hanksa008aa92016-07-22 10:31:12 -0700292 MockInteractions.tap(noButton); // close the overlay
293 return observer;
Kasper Nilssonad908b12017-05-11 11:26:10 -0700294 }).then(() => {
Logan Hanksa008aa92016-07-22 10:31:12 -0700295 assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
296
297 // We should be focused on account entry input.
298 assert.equal(getActiveElement().id, 'input');
299
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800300 // No reviewer/CC should have been added.
301 assert.equal(element.$$('#ccs').additions().length, 0);
302 assert.equal(element.$.reviewers.additions().length, 0);
Logan Hanksa008aa92016-07-22 10:31:12 -0700303
304 // Reopen confirmation dialog.
305 observer = overlayObserver('opened');
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800306 if (cc) {
307 element._ccPendingConfirmation = {
Kasper Nilssonad908b12017-05-11 11:26:10 -0700308 group,
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800309 count: 10,
310 };
311 } else {
312 element._reviewerPendingConfirmation = {
Kasper Nilssonad908b12017-05-11 11:26:10 -0700313 group,
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800314 count: 10,
315 };
316 }
Logan Hanksa008aa92016-07-22 10:31:12 -0700317 return observer;
Kasper Nilssonad908b12017-05-11 11:26:10 -0700318 }).then(() => {
Logan Hanksa008aa92016-07-22 10:31:12 -0700319 assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
320 observer = overlayObserver('closed');
Becky Siegel8bb09342016-10-17 17:49:31 -0700321 MockInteractions.tap(yesButton); // Confirm the group.
Logan Hanksa008aa92016-07-22 10:31:12 -0700322 return observer;
Kasper Nilssonad908b12017-05-11 11:26:10 -0700323 }).then(() => {
Logan Hanksa008aa92016-07-22 10:31:12 -0700324 assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
Kasper Nilssonad908b12017-05-11 11:26:10 -0700325 const additions = cc ?
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800326 element.$$('#ccs').additions() :
327 element.$.reviewers.additions();
Logan Hanksa008aa92016-07-22 10:31:12 -0700328 assert.deepEqual(
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800329 additions,
Logan Hanksa008aa92016-07-22 10:31:12 -0700330 [
331 {
332 group: {
333 id: 'id',
334 name: 'name',
Logan Hanksa008aa92016-07-22 10:31:12 -0700335 confirmed: true,
336 _group: true,
337 _pendingAdd: true,
338 },
339 },
340 ]);
341
342 // We should be focused on account entry input.
343 assert.equal(getActiveElement().id, 'input');
344 }).then(done);
Kasper Nilssonad908b12017-05-11 11:26:10 -0700345 }
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800346
Kasper Nilssonad908b12017-05-11 11:26:10 -0700347 test('cc confirmation', done => {
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800348 testConfirmationDialog(done, true);
349 });
350
Kasper Nilssonad908b12017-05-11 11:26:10 -0700351 test('reviewer confirmation', done => {
Logan Hanks43d4dbb2016-12-14 18:17:47 -0800352 testConfirmationDialog(done, false);
Logan Hanksa008aa92016-07-22 10:31:12 -0700353 });
Wyatt Allen4f4b3a72016-07-28 12:05:53 -0700354
Kasper Nilssonad908b12017-05-11 11:26:10 -0700355 test('_getStorageLocation', () => {
356 const actual = element._getStorageLocation();
Wyatt Allen4f4b3a72016-07-28 12:05:53 -0700357 assert.equal(actual.changeNum, changeNum);
358 assert.equal(actual.patchNum, patchNum);
359 assert.equal(actual.path, '@change');
360 });
361
Kasper Nilssonad908b12017-05-11 11:26:10 -0700362 test('gets draft from storage on open', () => {
363 const storedDraft = 'hello world';
Wyatt Allen4f4b3a72016-07-28 12:05:53 -0700364 getDraftCommentStub.returns({message: storedDraft});
365 element.open();
366 assert.isTrue(getDraftCommentStub.called);
367 assert.equal(element.draft, storedDraft);
368 });
369
Kasper Nilssonad908b12017-05-11 11:26:10 -0700370 test('blank if no stored draft', () => {
Wyatt Allen4f4b3a72016-07-28 12:05:53 -0700371 getDraftCommentStub.returns(null);
372 element.open();
373 assert.isTrue(getDraftCommentStub.called);
374 assert.equal(element.draft, '');
375 });
376
Kasper Nilssonad908b12017-05-11 11:26:10 -0700377 test('updates stored draft on edits', () => {
378 const firstEdit = 'hello';
379 const location = element._getStorageLocation();
Wyatt Allen4f4b3a72016-07-28 12:05:53 -0700380
381 element.draft = firstEdit;
382 element.flushDebouncer('store');
383
384 assert.isTrue(setDraftCommentStub.calledWith(location, firstEdit));
385
386 element.draft = '';
387 element.flushDebouncer('store');
388
389 assert.isTrue(eraseDraftCommentStub.calledWith(location));
390 });
Logan Hanksf1063a22016-07-22 16:05:04 -0700391
Kasper Nilssonad908b12017-05-11 11:26:10 -0700392 test('400 converts to human-readable server-error', done => {
393 sandbox.stub(window, 'fetch', () => {
394 const text = '....{"reviewers":{"id1":{"error":"first error"}},' +
Logan Hanksf1063a22016-07-22 16:05:04 -0700395 '"ccs":{"id2":{"error":"second error"}}}';
396 return Promise.resolve({
397 ok: false,
398 status: 400,
Kasper Nilssonad908b12017-05-11 11:26:10 -0700399 text() { return Promise.resolve(text); },
Logan Hanksf1063a22016-07-22 16:05:04 -0700400 });
401 });
402
Kasper Nilssonad908b12017-05-11 11:26:10 -0700403 element.addEventListener('server-error', event => {
Logan Hanksf1063a22016-07-22 16:05:04 -0700404 if (event.target !== element) {
405 return;
406 }
Kasper Nilssonad908b12017-05-11 11:26:10 -0700407 event.detail.response.text().then(body => {
Logan Hanksf1063a22016-07-22 16:05:04 -0700408 assert.equal(body, 'first error, second error');
Logan Hanksf1063a22016-07-22 16:05:04 -0700409 });
410 });
Andrew Bonventreefd0a532016-08-23 17:04:23 -0400411
412 // Async tick is needed because iron-selector content is distributed and
413 // distributed content requires an observer to be set up.
Kasper Nilssonad908b12017-05-11 11:26:10 -0700414 flush(() => { element.send().then(done); });
Logan Hanksa75fb052016-08-01 13:23:38 -0700415 });
Logan Hanksf1063a22016-07-22 16:05:04 -0700416
Kasper Nilssonad908b12017-05-11 11:26:10 -0700417 test('ccs are displayed if NoteDb is enabled', () => {
Logan Hanksa75fb052016-08-01 13:23:38 -0700418 function hasCc() {
419 flushAsynchronousOperations();
420 return !!element.$$('#ccs');
421 }
422
423 element.serverConfig = {};
424 assert.isFalse(hasCc());
425
426 element.serverConfig = {note_db_enabled: true};
427 assert.isTrue(hasCc());
428 });
429
Kasper Nilssonad908b12017-05-11 11:26:10 -0700430 test('filterReviewerSuggestion', () => {
431 const owner = makeAccount();
432 const reviewer1 = makeAccount();
433 const reviewer2 = makeGroup();
434 const cc1 = makeAccount();
435 const cc2 = makeGroup();
Logan Hanksa75fb052016-08-01 13:23:38 -0700436
437 element._owner = owner;
438 element._reviewers = [reviewer1, reviewer2];
439 element._ccs = [cc1, cc2];
440
441 assert.isTrue(
442 element._filterReviewerSuggestion({account: makeAccount()}));
443 assert.isTrue(element._filterReviewerSuggestion({group: makeGroup()}));
444
445 // Owner should be excluded.
446 assert.isFalse(element._filterReviewerSuggestion({account: owner}));
447
448 // Existing and pending reviewers should be excluded.
449 assert.isFalse(element._filterReviewerSuggestion({account: reviewer1}));
450 assert.isFalse(element._filterReviewerSuggestion({group: reviewer2}));
451
452 // Existing and pending CCs should be excluded.
453 assert.isFalse(element._filterReviewerSuggestion({account: cc1}));
454 assert.isFalse(element._filterReviewerSuggestion({group: cc2}));
Logan Hanksf1063a22016-07-22 16:05:04 -0700455 });
Logan Hanksfc57acc2016-08-05 13:54:50 -0700456
Kasper Nilssonad908b12017-05-11 11:26:10 -0700457 test('_chooseFocusTarget', () => {
Logan Hanksfc57acc2016-08-05 13:54:50 -0700458 element._account = null;
459 assert.strictEqual(
460 element._chooseFocusTarget(), element.FocusTarget.BODY);
461
462 element._account = {_account_id: 1};
463 assert.strictEqual(
464 element._chooseFocusTarget(), element.FocusTarget.BODY);
465
466 element.change.owner = {_account_id: 2};
467 assert.strictEqual(
468 element._chooseFocusTarget(), element.FocusTarget.BODY);
469
470 element.change.owner._account_id = 1;
471 element.change._reviewers = null;
472 assert.strictEqual(
473 element._chooseFocusTarget(), element.FocusTarget.REVIEWERS);
474
475 element._reviewers = [];
476 assert.strictEqual(
477 element._chooseFocusTarget(), element.FocusTarget.REVIEWERS);
478
479 element._reviewers.push({});
480 assert.strictEqual(
481 element._chooseFocusTarget(), element.FocusTarget.BODY);
482 });
Logan Hanksca3c4972016-09-14 16:25:56 -0700483
Kasper Nilssonad908b12017-05-11 11:26:10 -0700484 test('only send labels that have changed', done => {
485 flush(() => {
486 sandbox.stub(element, '_saveReview', review => {
Kasper Nilsson4416acd2016-09-16 13:27:11 -0700487 assert.deepEqual(review.labels, {Verified: -1});
488 return Promise.resolve({ok: true});
489 });
Logan Hanksca3c4972016-09-14 16:25:56 -0700490
Kasper Nilssonad908b12017-05-11 11:26:10 -0700491 element.addEventListener('send', () => {
Kasper Nilsson4416acd2016-09-16 13:27:11 -0700492 done();
493 });
494 // Without wrapping this test in flush(), the below two calls to
495 // MockInteractions.tap() cause a race in some situations in shadow DOM.
496 // The send button can be tapped before the others, causing the test to
497 // fail.
Becky Siegela499e3d2017-04-06 16:57:13 -0700498
499 MockInteractions.tap(element.$$('gr-label-scores').$$(
Kasper Nilsson4416acd2016-09-16 13:27:11 -0700500 'iron-selector[data-label="Verified"] > ' +
501 'gr-button[data-value="-1"]'));
502 MockInteractions.tap(element.$$('.send'));
Logan Hanksca3c4972016-09-14 16:25:56 -0700503 });
Logan Hanksca3c4972016-09-14 16:25:56 -0700504 });
Becky Siegel8bb09342016-10-17 17:49:31 -0700505
Kasper Nilssonad908b12017-05-11 11:26:10 -0700506 test('do not display tooltips on touch devices', () => {
Becky Siegel8bb09342016-10-17 17:49:31 -0700507 element._account = {_account_id: 1};
508 element.set(['change', 'labels', 'Verified', 'all'],
509 [{_account_id: 1, value: -1}]);
510 element.labels = {
Kasper Nilssonad908b12017-05-11 11:26:10 -0700511 'Verified': {
Becky Siegel8bb09342016-10-17 17:49:31 -0700512 values: {
513 '-1': 'Fails',
514 ' 0': 'No score',
Kasper Nilssonad908b12017-05-11 11:26:10 -0700515 '+1': 'Verified',
Becky Siegel8bb09342016-10-17 17:49:31 -0700516 },
Kasper Nilssona8271552017-01-17 11:54:40 -0800517 default_value: 0,
Becky Siegel8bb09342016-10-17 17:49:31 -0700518 },
519 'Code-Review': {
520 values: {
521 '-2': 'Do not submit',
522 '-1': 'I would prefer that you didn\'t submit this',
523 ' 0': 'No score',
524 '+1': 'Looks good to me, but someone else must approve',
Kasper Nilssonad908b12017-05-11 11:26:10 -0700525 '+2': 'Looks good to me, approved',
Becky Siegel8bb09342016-10-17 17:49:31 -0700526 },
Kasper Nilssona8271552017-01-17 11:54:40 -0800527 default_value: 0,
528 },
Becky Siegel8bb09342016-10-17 17:49:31 -0700529 };
530
531 flushAsynchronousOperations();
532
Kasper Nilssonad908b12017-05-11 11:26:10 -0700533 const verifiedBtn = element.$$('gr-label-scores').$$(
Becky Siegel8bb09342016-10-17 17:49:31 -0700534 'iron-selector[data-label="Verified"] > ' +
535 'gr-button[data-value="-1"]');
536
537 // On touch devices, tooltips should not be shown.
538 verifiedBtn._isTouchDevice = true;
539 verifiedBtn._handleShowTooltip();
540 assert.isNotOk(verifiedBtn._tooltip);
541 verifiedBtn._handleHideTooltip();
542 assert.isNotOk(verifiedBtn._tooltip);
543
544 // On other devices, tooltips should be shown.
545 verifiedBtn._isTouchDevice = false;
546 verifiedBtn._handleShowTooltip();
547 assert.isOk(verifiedBtn._tooltip);
548 verifiedBtn._handleHideTooltip();
549 assert.isNotOk(verifiedBtn._tooltip);
550 });
Kasper Nilssona8271552017-01-17 11:54:40 -0800551
Kasper Nilssonad908b12017-05-11 11:26:10 -0700552 test('_processReviewerChange', () => {
553 const mockIndexSplices = function(toRemove) {
Kasper Nilssona8271552017-01-17 11:54:40 -0800554 return [{
555 removed: [toRemove],
556 }];
557 };
558
559 element._processReviewerChange(
560 mockIndexSplices(makeAccount()), 'REVIEWER');
561 assert.equal(element._reviewersPendingRemove.REVIEWER.length, 1);
562 });
563
Kasper Nilssonad908b12017-05-11 11:26:10 -0700564 test('_purgeReviewersPendingRemove', () => {
565 const removeStub = sandbox.stub(element, '_removeAccount');
566 const mock = function() {
Kasper Nilssona8271552017-01-17 11:54:40 -0800567 element._reviewersPendingRemove = {
568 test: [makeAccount()],
569 test2: [makeAccount(), makeAccount()],
570 };
571 };
Kasper Nilssonad908b12017-05-11 11:26:10 -0700572 const checkObjEmpty = function(obj) {
573 for (const prop in obj) {
Kasper Nilssona8271552017-01-17 11:54:40 -0800574 if (obj.hasOwnProperty(prop) && obj[prop].length) { return false; }
575 }
576 return true;
577 };
578 mock();
579 element._purgeReviewersPendingRemove(true); // Cancel
580 assert.isFalse(removeStub.called);
581 assert.isTrue(checkObjEmpty(element._reviewersPendingRemove));
582
583 mock();
584 element._purgeReviewersPendingRemove(false); // Submit
585 assert.isTrue(removeStub.called);
586 assert.isTrue(checkObjEmpty(element._reviewersPendingRemove));
587 });
588
Kasper Nilssonad908b12017-05-11 11:26:10 -0700589 test('_removeAccount', done => {
Kasper Nilssona8271552017-01-17 11:54:40 -0800590 sandbox.stub(element.$.restAPI, 'removeChangeReviewer')
591 .returns(Promise.resolve({ok: true}));
Kasper Nilssonad908b12017-05-11 11:26:10 -0700592 const arr = [makeAccount(), makeAccount()];
Kasper Nilssona8271552017-01-17 11:54:40 -0800593 element.change.reviewers = {
594 REVIEWER: arr.slice(),
595 };
596
Kasper Nilssonad908b12017-05-11 11:26:10 -0700597 element._removeAccount(arr[1], 'REVIEWER').then(() => {
Kasper Nilssona8271552017-01-17 11:54:40 -0800598 assert.equal(element.change.reviewers.REVIEWER.length, 1);
599 assert.deepEqual(element.change.reviewers.REVIEWER, arr.slice(0, 1));
600 done();
601 });
602 });
Logan Hanks64451c02017-03-22 13:39:40 -0700603
Kasper Nilssonad908b12017-05-11 11:26:10 -0700604 test('migrate reviewers between states', done => {
Logan Hanks64451c02017-03-22 13:39:40 -0700605 element.serverConfig = {note_db_enabled: true};
606 element._reviewersPendingRemove = {
607 CC: [],
608 REVIEWER: [],
609 };
610 flushAsynchronousOperations();
Kasper Nilssonad908b12017-05-11 11:26:10 -0700611 const reviewers = element.$.reviewers;
612 const ccs = element.$$('#ccs');
613 const reviewer1 = makeAccount();
614 const reviewer2 = makeAccount();
615 const cc1 = makeAccount();
616 const cc2 = makeAccount();
Logan Hanks64451c02017-03-22 13:39:40 -0700617 element._reviewers = [reviewer1, reviewer2];
618 element._ccs = [cc1, cc2];
619
Kasper Nilssonad908b12017-05-11 11:26:10 -0700620 const mutations = [];
Logan Hanks64451c02017-03-22 13:39:40 -0700621
Kasper Nilssonad908b12017-05-11 11:26:10 -0700622 sandbox.stub(element, '_saveReview', review => {
623 mutations.push(...review.reviewers);
Logan Hanks64451c02017-03-22 13:39:40 -0700624 return Promise.resolve({ok: true});
625 });
626
Kasper Nilssonad908b12017-05-11 11:26:10 -0700627 sandbox.stub(element, '_removeAccount', (account, type) => {
628 mutations.push({state: 'REMOVED', account});
Logan Hanks64451c02017-03-22 13:39:40 -0700629 return Promise.resolve();
630 });
631
632 // Remove and add to other field.
633 reviewers.fire('remove', {account: reviewer1});
634 ccs.$.entry.fire('add', {value: {account: reviewer1}});
635 ccs.fire('remove', {account: cc1});
636 reviewers.$.entry.fire('add', {value: {account: cc1}});
637
638 // Add to other field without removing from former field.
639 // (Currently not possible in UI, but this is a good consistency check).
640 reviewers.$.entry.fire('add', {value: {account: cc2}});
641 ccs.$.entry.fire('add', {value: {account: reviewer2}});
Kasper Nilssonad908b12017-05-11 11:26:10 -0700642 const mapReviewer = function(reviewer, opt_state) {
643 const result = {reviewer: reviewer._account_id, confirmed: undefined};
Logan Hanks64451c02017-03-22 13:39:40 -0700644 if (opt_state) {
645 result.state = opt_state;
646 }
647 return result;
648 };
649
650 // Send and purge and verify moves without deletions.
651 element.send()
652 .then(element._purgeReviewersPendingRemove.bind(element))
Kasper Nilssonad908b12017-05-11 11:26:10 -0700653 .then(() => {
654 assert.deepEqual(
655 mutations, [
656 mapReviewer(cc1),
657 mapReviewer(cc2),
658 mapReviewer(reviewer1, 'CC'),
659 mapReviewer(reviewer2, 'CC'),
660 ]);
661 done();
662 });
Logan Hanks64451c02017-03-22 13:39:40 -0700663 });
Kasper Nilssonff0745d2017-03-21 16:41:24 -0700664
Kasper Nilssonad908b12017-05-11 11:26:10 -0700665 test('emits cancel on esc key', () => {
666 const cancelHandler = sandbox.spy();
Kasper Nilssonff0745d2017-03-21 16:41:24 -0700667 element.addEventListener('cancel', cancelHandler);
668 MockInteractions.pressAndReleaseKeyOn(element, 27, null, 'esc');
669 flushAsynchronousOperations();
670
671 assert.isTrue(cancelHandler.called);
672 });
Logan Hanksdc65dde2017-04-27 11:45:23 +0200673
Kasper Nilssonad908b12017-05-11 11:26:10 -0700674 test('_computeMessagePlaceholder', () => {
Logan Hanksdc65dde2017-04-27 11:45:23 +0200675 assert.equal(
676 element._computeMessagePlaceholder(false),
677 'Say something nice...');
678 assert.equal(
679 element._computeMessagePlaceholder(true),
680 'Add a note for your reviewers...');
681 });
682
Kasper Nilssonad908b12017-05-11 11:26:10 -0700683 test('_computeSendButtonLabel', () => {
Logan Hanksdc65dde2017-04-27 11:45:23 +0200684 assert.equal(
685 element._computeSendButtonLabel(false),
686 'Send');
687 assert.equal(
688 element._computeSendButtonLabel(true),
689 'Start review');
690 });
Andrew Bonventref8b026d2015-12-09 17:55:54 -0500691 });
692</script>