blob: 2f607a6c346f89ac8ce641a50d4330115bd8c4e3 [file] [log] [blame]
Dmitrii Filippovacd39a22020-04-02 10:31:43 +02001/**
2 * @license
3 * Copyright (C) 2015 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
Andrew Bonventre547b8ab2015-12-01 01:02:00 -050017
Dmitrii Filippovacd39a22020-04-02 10:31:43 +020018import '../../../test/common-test-setup-karma.js';
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010019import '../../edit/gr-edit-constants.js';
20import './gr-change-view.js';
Dmitrii Filippove903bbf2020-05-06 12:57:39 +020021import {PrimaryTab, SecondaryTab, ChangeStatus} from '../../../constants/constants.js';
Tao Zhou4fd32d52020-04-06 17:23:10 +020022
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010023import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
Dmitrii Filippov56e58de2020-04-03 18:07:10 +020024import {KeyboardShortcutBinder} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
Dmitrii Filippov0028b582020-03-24 11:58:55 +010025import {GrEditConstants} from '../../edit/gr-edit-constants.js';
Dmitrii Filippovf97fc6e2020-04-07 09:59:22 +020026import {_testOnly_resetEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints.js';
Tao Zhou7b7d16b2020-06-10 15:48:38 +020027import {getComputedStyleValue} from '../../../utils/dom-util.js';
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +020028import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
Dmitrii Filippovf97fc6e2020-04-07 09:59:22 +020029import {pluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
Dmitrii Filippov5f25dc02020-04-07 18:49:00 +020030import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
Dmitrii Filippov35aea692020-04-07 12:14:11 +020031
Dmitrii Filippovacd39a22020-04-02 10:31:43 +020032import 'lodash/lodash.js';
33
Dmitrii Filippov5f25dc02020-04-07 18:49:00 +020034const pluginApi = _testOnly_initGerritPluginApi();
Dmitrii Filippovacd39a22020-04-02 10:31:43 +020035const fixture = fixtureFromElement('gr-change-view');
Dmitrii Filippov0028b582020-03-24 11:58:55 +010036
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010037suite('gr-change-view tests', () => {
Dmitrii Filippov56e58de2020-04-03 18:07:10 +020038 const kb = KeyboardShortcutBinder;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010039 kb.bindShortcut(kb.Shortcut.SEND_REPLY, 'ctrl+enter');
40 kb.bindShortcut(kb.Shortcut.REFRESH_CHANGE, 'shift+r');
41 kb.bindShortcut(kb.Shortcut.OPEN_REPLY_DIALOG, 'a');
42 kb.bindShortcut(kb.Shortcut.OPEN_DOWNLOAD_DIALOG, 'd');
43 kb.bindShortcut(kb.Shortcut.TOGGLE_DIFF_MODE, 'm');
44 kb.bindShortcut(kb.Shortcut.TOGGLE_CHANGE_STAR, 's');
45 kb.bindShortcut(kb.Shortcut.UP_TO_DASHBOARD, 'u');
46 kb.bindShortcut(kb.Shortcut.EXPAND_ALL_MESSAGES, 'x');
47 kb.bindShortcut(kb.Shortcut.COLLAPSE_ALL_MESSAGES, 'z');
48 kb.bindShortcut(kb.Shortcut.OPEN_DIFF_PREFS, ',');
49 kb.bindShortcut(kb.Shortcut.EDIT_TOPIC, 't');
Logan Hanks5cde0842018-10-05 15:56:10 -070050
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010051 let element;
52 let sandbox;
53 let navigateToChangeStub;
54 const TEST_SCROLL_TOP_PX = 100;
Andrew Bonventre547b8ab2015-12-01 01:02:00 -050055
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010056 const ROBOT_COMMENTS_LIMIT = 10;
57
Tao Zhou18738b92020-05-04 19:44:51 +020058 // TODO: should have a mock service to generate VALID fake data
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010059 const THREADS = [
60 {
61 comments: [
62 {
63 __path: '/COMMIT_MSG',
64 author: {
65 _account_id: 1000000,
66 name: 'user',
67 username: 'user',
68 },
69 patch_set: 2,
70 robot_id: 'rb1',
Tao Zhou18738b92020-05-04 19:44:51 +020071 id: 'ecf0b9fa_fe1a5f62',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010072 line: 5,
73 updated: '2018-02-08 18:49:18.000000000',
74 message: 'test',
75 unresolved: true,
76 },
77 {
78 __path: '/COMMIT_MSG',
79 author: {
80 _account_id: 1000000,
81 name: 'user',
82 username: 'user',
83 },
84 patch_set: 4,
Tao Zhou18738b92020-05-04 19:44:51 +020085 id: 'ecf0b9fa_fe1a5f62_1',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010086 line: 5,
87 updated: '2018-02-08 18:49:18.000000000',
88 message: 'test',
89 unresolved: true,
90 },
91 {
92 id: '503008e2_0ab203ee',
93 path: '/COMMIT_MSG',
94 line: 5,
95 in_reply_to: 'ecf0b9fa_fe1a5f62',
96 updated: '2018-02-13 22:48:48.018000000',
97 message: 'draft',
98 unresolved: false,
99 __draft: true,
100 __draftID: '0.m683trwff68',
101 __editing: false,
102 patch_set: '2',
103 },
104 ],
105 patchNum: 4,
106 path: '/COMMIT_MSG',
107 line: 5,
108 rootId: 'ecf0b9fa_fe1a5f62',
109 start_datetime: '2018-02-08 18:49:18.000000000',
110 },
111 {
112 comments: [
113 {
114 __path: '/COMMIT_MSG',
115 author: {
116 _account_id: 1000000,
117 name: 'user',
118 username: 'user',
119 },
120 patch_set: 3,
121 id: 'ecf0b9fa_fe5f62',
122 robot_id: 'rb2',
123 line: 5,
124 updated: '2018-02-08 18:49:18.000000000',
125 message: 'test',
126 unresolved: true,
127 },
128 {
129 __path: 'test.txt',
130 author: {
131 _account_id: 1000000,
132 name: 'user',
133 username: 'user',
134 },
135 patch_set: 3,
136 id: '09a9fb0a_1484e6cf',
137 side: 'PARENT',
138 updated: '2018-02-13 22:47:19.000000000',
139 message: 'Some comment on another patchset.',
140 unresolved: false,
141 },
142 ],
143 patchNum: 3,
144 path: 'test.txt',
145 rootId: '09a9fb0a_1484e6cf',
146 start_datetime: '2018-02-13 22:47:19.000000000',
147 commentSide: 'PARENT',
148 },
149 {
150 comments: [
151 {
152 __path: '/COMMIT_MSG',
153 author: {
154 _account_id: 1000000,
155 name: 'user',
156 username: 'user',
157 },
158 patch_set: 2,
159 id: '8caddf38_44770ec1',
160 line: 4,
161 updated: '2018-02-13 22:48:40.000000000',
162 message: 'Another unresolved comment',
163 unresolved: true,
164 },
165 ],
166 patchNum: 2,
167 path: '/COMMIT_MSG',
168 line: 4,
169 rootId: '8caddf38_44770ec1',
170 start_datetime: '2018-02-13 22:48:40.000000000',
171 },
172 {
173 comments: [
174 {
175 __path: '/COMMIT_MSG',
176 author: {
177 _account_id: 1000000,
178 name: 'user',
179 username: 'user',
180 },
181 patch_set: 2,
182 id: 'scaddf38_44770ec1',
183 line: 4,
184 updated: '2018-02-14 22:48:40.000000000',
185 message: 'Yet another unresolved comment',
186 unresolved: true,
187 },
188 ],
189 patchNum: 2,
190 path: '/COMMIT_MSG',
191 line: 4,
192 rootId: 'scaddf38_44770ec1',
193 start_datetime: '2018-02-14 22:48:40.000000000',
194 },
195 {
196 comments: [
197 {
198 id: 'zcf0b9fa_fe1a5f62',
199 path: '/COMMIT_MSG',
200 line: 6,
201 updated: '2018-02-15 22:48:48.018000000',
202 message: 'resolved draft',
203 unresolved: false,
204 __draft: true,
205 __draftID: '0.m683trwff68',
206 __editing: false,
207 patch_set: '2',
208 },
209 ],
210 patchNum: 4,
211 path: '/COMMIT_MSG',
212 line: 6,
213 rootId: 'zcf0b9fa_fe1a5f62',
214 start_datetime: '2018-02-09 18:49:18.000000000',
215 },
216 {
217 comments: [
218 {
219 __path: '/COMMIT_MSG',
220 author: {
221 _account_id: 1000000,
222 name: 'user',
223 username: 'user',
224 },
225 patch_set: 4,
226 id: 'rc1',
227 line: 5,
228 updated: '2019-02-08 18:49:18.000000000',
229 message: 'test',
230 unresolved: true,
231 robot_id: 'rc1',
232 },
233 ],
234 patchNum: 4,
235 path: '/COMMIT_MSG',
236 line: 5,
237 rootId: 'rc1',
238 start_datetime: '2019-02-08 18:49:18.000000000',
239 },
240 {
241 comments: [
242 {
243 __path: '/COMMIT_MSG',
244 author: {
245 _account_id: 1000000,
246 name: 'user',
247 username: 'user',
248 },
249 patch_set: 4,
250 id: 'rc2',
251 line: 5,
252 updated: '2019-03-08 18:49:18.000000000',
253 message: 'test',
254 unresolved: true,
255 robot_id: 'rc2',
256 },
257 {
258 __path: '/COMMIT_MSG',
259 author: {
260 _account_id: 1000000,
261 name: 'user',
262 username: 'user',
263 },
264 patch_set: 4,
265 id: 'c2_1',
266 line: 5,
267 updated: '2019-03-08 18:49:18.000000000',
268 message: 'test',
269 unresolved: true,
270 },
271 ],
272 patchNum: 4,
273 path: '/COMMIT_MSG',
274 line: 5,
275 rootId: 'rc2',
276 start_datetime: '2019-03-08 18:49:18.000000000',
277 },
278 ];
279
280 setup(() => {
281 sandbox = sinon.sandbox.create();
Dmitrii Filippovf97fc6e2020-04-07 09:59:22 +0200282 // Since pluginEndpoints are global, must reset state.
283 _testOnly_resetEndpoints();
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +0200284 navigateToChangeStub = sandbox.stub(GerritNav, 'navigateToChange');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100285 stub('gr-rest-api-interface', {
286 getConfig() { return Promise.resolve({test: 'config'}); },
287 getAccount() { return Promise.resolve(null); },
288 getDiffComments() { return Promise.resolve({}); },
289 getDiffRobotComments() { return Promise.resolve({}); },
290 getDiffDrafts() { return Promise.resolve({}); },
291 _fetchSharedCacheURL() { return Promise.resolve({}); },
292 });
Dmitrii Filippovacd39a22020-04-02 10:31:43 +0200293 element = fixture.instantiate();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100294 sandbox.stub(element.$.actions, 'reload').returns(Promise.resolve());
Dmitrii Filippov35aea692020-04-07 12:14:11 +0200295 pluginLoader.loadPlugins([]);
Dmitrii Filippov5f25dc02020-04-07 18:49:00 +0200296 pluginApi.install(
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100297 plugin => {
298 plugin.registerDynamicCustomComponent(
299 'change-view-tab-header',
300 'gr-checks-change-view-tab-header-view'
301 );
302 plugin.registerDynamicCustomComponent(
303 'change-view-tab-content',
304 'gr-checks-view'
305 );
306 },
307 '0.1',
308 'http://some/plugins/url.html'
309 );
310 });
311
312 teardown(done => {
313 flush(() => {
314 sandbox.restore();
315 done();
316 });
317 });
318
319 const getCustomCssValue =
Tao Zhou7b7d16b2020-06-10 15:48:38 +0200320 cssParam => getComputedStyleValue(cssParam, element);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100321
Dhruv Srivastava163de6f2020-06-04 09:40:28 +0000322 test('_handleMessageAnchorTap', () => {
323 element._changeNum = '1';
324 element._patchRange = {
325 basePatchNum: 'PARENT',
326 patchNum: 1,
327 };
328 const getUrlStub = sandbox.stub(GerritNav, 'getUrlForChange');
329 const replaceStateStub = sandbox.stub(history, 'replaceState');
330 element._handleMessageAnchorTap({detail: {id: 'a12345'}});
331
332 assert.equal(getUrlStub.lastCall.args[4], '#message-a12345');
333 assert.isTrue(replaceStateStub.called);
334 });
335
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200336 test('_handleDiffAgainstBase', () => {
337 element._changeNum = '1';
338 element._patchRange = {
339 patchNum: 3,
340 basePatchNum: 1,
341 };
342 sandbox.stub(element, 'computeLatestPatchNum').returns(10);
343 sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
344 element._handleDiffAgainstBase(new CustomEvent(''));
345 assert(navigateToChangeStub.called);
346 const args = navigateToChangeStub.getCall(0).args;
347 assert.equal(args[1], 3);
348 assert.isNotOk(args[0]);
349 });
350
351 test('_handleDiffAgainstLatest', () => {
352 element._changeNum = '1';
353 element._patchRange = {
354 basePatchNum: 1,
355 patchNum: 3,
356 };
357 sandbox.stub(element, 'computeLatestPatchNum').returns(10);
358 sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
359 element._handleDiffAgainstLatest(new CustomEvent(''));
360 assert(navigateToChangeStub.called);
361 const args = navigateToChangeStub.getCall(0).args;
362 assert.equal(args[1], 10);
363 assert.equal(args[2], 1);
364 });
365
366 test('_handleDiffBaseAgainstLeft', () => {
367 element._changeNum = '1';
368 element._patchRange = {
369 patchNum: 3,
370 basePatchNum: 1,
371 };
372 sandbox.stub(element, 'computeLatestPatchNum').returns(10);
373 sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
374 element._handleDiffBaseAgainstLeft(new CustomEvent(''));
375 assert(navigateToChangeStub.called);
376 const args = navigateToChangeStub.getCall(0).args;
377 assert.equal(args[1], 1);
378 assert.isNotOk(args[0]);
379 });
380
381 test('_handleDiffRightAgainstLatest', () => {
382 element._changeNum = '1';
383 element._patchRange = {
384 basePatchNum: 1,
385 patchNum: 3,
386 };
387 sandbox.stub(element, 'computeLatestPatchNum').returns(10);
388 sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
389 element._handleDiffRightAgainstLatest(new CustomEvent(''));
390 assert(navigateToChangeStub.called);
391 const args = navigateToChangeStub.getCall(0).args;
392 assert.equal(args[1], 10);
393 assert.equal(args[2], 3);
394 });
395
396 test('_handleDiffBaseAgainstLatest', () => {
397 element._changeNum = '1';
398 element._patchRange = {
399 basePatchNum: 1,
400 patchNum: 3,
401 };
402 sandbox.stub(element, 'computeLatestPatchNum').returns(10);
403 sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
404 element._handleDiffBaseAgainstLatest(new CustomEvent(''));
405 assert(navigateToChangeStub.called);
406 const args = navigateToChangeStub.getCall(0).args;
407 assert.equal(args[1], 10);
408 assert.isNotOk(args[2]);
409 });
410
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100411 suite('plugins adding to file tab', () => {
412 setup(done => {
413 // Resolving it here instead of during setup() as other tests depend
414 // on flush() not being called during setup.
415 flush(() => done());
Andrew Bonventre547b8ab2015-12-01 01:02:00 -0500416 });
417
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100418 test('plugin added tab shows up as a dynamic endpoint', () => {
419 assert(element._dynamicTabHeaderEndpoints.includes(
420 'change-view-tab-header-url'));
421 const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
Dhruv Srivastava929af7f2020-05-13 19:10:05 +0200422 // 4 Tabs are : Files, Comment Threads, Plugin, Findings
423 assert.equal(paperTabs.querySelectorAll('paper-tab').length, 4);
424 assert.equal(paperTabs.querySelectorAll('paper-tab')[2].dataset.name,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100425 'change-view-tab-header-url');
426 });
427
Tao Zhou4fd32d52020-04-06 17:23:10 +0200428 test('_setActivePrimaryTab switched tab correctly', done => {
429 element._setActivePrimaryTab({detail:
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100430 {tab: 'change-view-tab-header-url'}});
Becky Siegelba3f5892017-05-12 12:28:13 -0700431 flush(() => {
Tao Zhou4fd32d52020-04-06 17:23:10 +0200432 assert.equal(element._activeTabs[0], 'change-view-tab-header-url');
433 done();
434 });
435 });
436
437 test('show-primary-tab switched primary tab correctly', done => {
Paladox none6b055dc2020-06-28 14:53:18 +0000438 element.dispatchEvent(
439 new CustomEvent('show-primary-tab', {
440 composed: true,
441 bubbles: true,
442 detail: {
443 tab: 'change-view-tab-header-url',
444 },
445 }));
Tao Zhou4fd32d52020-04-06 17:23:10 +0200446 flush(() => {
447 assert.equal(element._activeTabs[0], 'change-view-tab-header-url');
448 done();
449 });
450 });
451
452 test('param change should switch primary tab correctly', done => {
Dmitrii Filippove903bbf2020-05-06 12:57:39 +0200453 assert.equal(element._activeTabs[0], PrimaryTab.FILES);
Tao Zhou4fd32d52020-04-06 17:23:10 +0200454 const queryMap = new Map();
Dmitrii Filippove903bbf2020-05-06 12:57:39 +0200455 queryMap.set('tab', PrimaryTab.FINDINGS);
Tao Zhou4fd32d52020-04-06 17:23:10 +0200456 // view is required
457 element.params = Object.assign(
458 {
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +0200459 view: GerritNav.View.CHANGE,
Tao Zhou4fd32d52020-04-06 17:23:10 +0200460 },
461 element.params, {queryMap});
462 flush(() => {
Dmitrii Filippove903bbf2020-05-06 12:57:39 +0200463 assert.equal(element._activeTabs[0], PrimaryTab.FINDINGS);
Tao Zhou4fd32d52020-04-06 17:23:10 +0200464 done();
465 });
466 });
467
468 test('invalid param change should not switch primary tab', done => {
Dmitrii Filippove903bbf2020-05-06 12:57:39 +0200469 assert.equal(element._activeTabs[0], PrimaryTab.FILES);
Tao Zhou4fd32d52020-04-06 17:23:10 +0200470 const queryMap = new Map();
471 queryMap.set('tab', 'random');
472 // view is required
473 element.params = Object.assign(
474 {
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +0200475 view: GerritNav.View.CHANGE,
Tao Zhou4fd32d52020-04-06 17:23:10 +0200476 },
477 element.params, {queryMap});
478 flush(() => {
Dmitrii Filippove903bbf2020-05-06 12:57:39 +0200479 assert.equal(element._activeTabs[0], PrimaryTab.FILES);
Viktar Donich29e1ce52017-03-28 17:02:44 -0700480 done();
481 });
Kasper Nilssonf0743732016-10-18 13:01:10 -0700482 });
483
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100484 test('switching tab sets _selectedTabPluginEndpoint', done => {
485 const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
Dhruv Srivastava929af7f2020-05-13 19:10:05 +0200486 MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[2]);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100487 flush(() => {
488 assert.equal(element._selectedTabPluginEndpoint,
489 'change-view-tab-content-url');
490 done();
491 });
492 });
493 });
Paladox none7acb7ac2017-11-09 18:06:18 +0000494
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100495 suite('keyboard shortcuts', () => {
496 test('t to add topic', () => {
497 const editStub = sandbox.stub(element.$.metadata, 'editTopic');
498 MockInteractions.pressAndReleaseKeyOn(element, 83, null, 't');
499 assert(editStub.called);
500 });
501
502 test('S should toggle the CL star', () => {
503 const starStub = sandbox.stub(element.$.changeStar, 'toggleStar');
504 MockInteractions.pressAndReleaseKeyOn(element, 83, null, 's');
505 assert(starStub.called);
506 });
507
508 test('U should navigate to root if no backPage set', () => {
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +0200509 const relativeNavStub = sandbox.stub(GerritNav,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100510 'navigateToRelativeUrl');
511 MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
512 assert.isTrue(relativeNavStub.called);
513 assert.isTrue(relativeNavStub.lastCall.calledWithExactly(
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +0200514 GerritNav.getUrlForRoot()));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100515 });
516
517 test('U should navigate to backPage if set', () => {
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +0200518 const relativeNavStub = sandbox.stub(GerritNav,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100519 'navigateToRelativeUrl');
520 element.backPage = '/dashboard/self';
521 MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
522 assert.isTrue(relativeNavStub.called);
523 assert.isTrue(relativeNavStub.lastCall.calledWithExactly(
524 '/dashboard/self'));
525 });
526
527 test('A fires an error event when not logged in', done => {
528 sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(false));
529 const loggedInErrorSpy = sandbox.spy();
530 element.addEventListener('show-auth-required', loggedInErrorSpy);
531 MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
532 flush(() => {
533 assert.isFalse(element.$.replyOverlay.opened);
534 assert.isTrue(loggedInErrorSpy.called);
535 done();
536 });
537 });
538
539 test('shift A does not open reply overlay', done => {
540 sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
541 MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
542 flush(() => {
543 assert.isFalse(element.$.replyOverlay.opened);
544 done();
545 });
546 });
547
548 test('A toggles overlay when logged in', done => {
549 sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
550 sandbox.stub(element.$.replyDialog, 'fetchChangeUpdates')
551 .returns(Promise.resolve({isLatest: true}));
552 element._change = {labels: {}};
553 const openSpy = sandbox.spy(element, '_openReplyDialog');
554
555 MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
556 flush(() => {
557 assert.isTrue(element.$.replyOverlay.opened);
558 element.$.replyOverlay.close();
559 assert.isFalse(element.$.replyOverlay.opened);
560 assert(openSpy.lastCall.calledWithExactly(
561 element.$.replyDialog.FocusTarget.ANY),
562 '_openReplyDialog should have been passed ANY');
563 assert.equal(openSpy.callCount, 1);
564 done();
565 });
566 });
567
568 test('fullscreen-overlay-opened hides content', () => {
569 element._loggedIn = true;
570 element._loading = false;
571 element._change = {
572 owner: {_account_id: 1},
573 labels: {},
574 actions: {
575 abandon: {
576 enabled: true,
577 label: 'Abandon',
578 method: 'POST',
579 title: 'Abandon',
580 },
581 },
582 };
583 sandbox.spy(element, '_handleHideBackgroundContent');
Tao Zhou0a3c9862020-04-08 14:45:37 +0200584 element.$.replyDialog.dispatchEvent(
585 new CustomEvent('fullscreen-overlay-opened', {
586 composed: true, bubbles: true,
587 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100588 assert.isTrue(element._handleHideBackgroundContent.called);
589 assert.isTrue(element.$.mainContent.classList.contains('overlayOpen'));
590 assert.equal(getComputedStyle(element.$.actions).display, 'flex');
591 });
592
593 test('fullscreen-overlay-closed shows content', () => {
594 element._loggedIn = true;
595 element._loading = false;
596 element._change = {
597 owner: {_account_id: 1},
598 labels: {},
599 actions: {
600 abandon: {
601 enabled: true,
602 label: 'Abandon',
603 method: 'POST',
604 title: 'Abandon',
605 },
606 },
607 };
608 sandbox.spy(element, '_handleShowBackgroundContent');
Tao Zhou0a3c9862020-04-08 14:45:37 +0200609 element.$.replyDialog.dispatchEvent(
610 new CustomEvent('fullscreen-overlay-closed', {
611 composed: true, bubbles: true,
612 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100613 assert.isTrue(element._handleShowBackgroundContent.called);
614 assert.isFalse(element.$.mainContent.classList.contains('overlayOpen'));
615 });
616
617 test('expand all messages when expand-diffs fired', () => {
618 const handleExpand =
619 sandbox.stub(element.$.fileList, 'expandAllDiffs');
Tao Zhou0a3c9862020-04-08 14:45:37 +0200620 element.$.fileListHeader.dispatchEvent(
621 new CustomEvent('expand-diffs', {
622 composed: true, bubbles: true,
623 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100624 assert.isTrue(handleExpand.called);
625 });
626
627 test('collapse all messages when collapse-diffs fired', () => {
628 const handleCollapse =
629 sandbox.stub(element.$.fileList, 'collapseAllDiffs');
Tao Zhou0a3c9862020-04-08 14:45:37 +0200630 element.$.fileListHeader.dispatchEvent(
631 new CustomEvent('collapse-diffs', {
632 composed: true, bubbles: true,
633 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100634 assert.isTrue(handleCollapse.called);
635 });
636
637 test('X should expand all messages', done => {
638 flush(() => {
639 const handleExpand = sandbox.stub(element.messagesList,
640 'handleExpandCollapse');
641 MockInteractions.pressAndReleaseKeyOn(element, 88, null, 'x');
642 assert(handleExpand.calledWith(true));
643 done();
644 });
645 });
646
647 test('Z should collapse all messages', done => {
648 flush(() => {
649 const handleExpand = sandbox.stub(element.messagesList,
650 'handleExpandCollapse');
651 MockInteractions.pressAndReleaseKeyOn(element, 90, null, 'z');
652 assert(handleExpand.calledWith(false));
653 done();
654 });
655 });
656
657 test('shift + R should fetch and navigate to the latest patch set',
658 done => {
659 element._changeNum = '42';
660 element._patchRange = {
661 basePatchNum: 'PARENT',
662 patchNum: 1,
663 };
664 element._change = {
665 change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
666 _number: 42,
667 revisions: {
668 rev1: {_number: 1, commit: {parents: []}},
669 },
670 current_revision: 'rev1',
671 status: 'NEW',
672 labels: {},
673 actions: {},
674 };
675
676 navigateToChangeStub.restore();
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +0200677 navigateToChangeStub = sandbox.stub(GerritNav, 'navigateToChange',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100678 (change, patchNum, basePatchNum) => {
679 assert.equal(change, element._change);
680 assert.isUndefined(patchNum);
681 assert.isUndefined(basePatchNum);
682 done();
683 });
684
685 MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
686 });
687
688 test('d should open download overlay', () => {
Dhruv Srivastava9f488b62020-06-26 13:43:50 +0200689 const stub = sandbox.stub(element.$.downloadOverlay, 'open').returns(
690 new Promise(resolve => {})
691 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100692 MockInteractions.pressAndReleaseKeyOn(element, 68, null, 'd');
693 assert.isTrue(stub.called);
694 });
695
696 test(', should open diff preferences', () => {
697 const stub = sandbox.stub(
698 element.$.fileList.$.diffPreferencesDialog, 'open');
699 element._loggedIn = false;
700 element.disableDiffPrefs = true;
701 MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
702 assert.isFalse(stub.called);
703
704 element._loggedIn = true;
705 MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
706 assert.isFalse(stub.called);
707
708 element.disableDiffPrefs = false;
709 MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
710 assert.isTrue(stub.called);
711 });
712
713 test('m should toggle diff mode', () => {
714 sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
715 const setModeStub = sandbox.stub(element.$.fileListHeader,
716 'setDiffViewMode');
717 const e = {preventDefault: () => {}};
718 flushAsynchronousOperations();
719
720 element.viewState.diffMode = 'SIDE_BY_SIDE';
721 element._handleToggleDiffMode(e);
722 assert.isTrue(setModeStub.calledWith('UNIFIED_DIFF'));
723
724 element.viewState.diffMode = 'UNIFIED_DIFF';
725 element._handleToggleDiffMode(e);
726 assert.isTrue(setModeStub.calledWith('SIDE_BY_SIDE'));
727 });
728 });
729
730 suite('reloading drafts', () => {
731 let reloadStub;
732 const drafts = {
733 'testfile.txt': [
734 {
735 patch_set: 5,
736 id: 'dd2982f5_c01c9e6a',
737 line: 1,
738 updated: '2017-11-08 18:47:45.000000000',
739 message: 'test',
740 unresolved: true,
741 },
742 ],
743 };
744 setup(() => {
745 // Fake computeDraftCount as its required for ChangeComments,
746 // see gr-comment-api#reloadDrafts.
747 reloadStub = sandbox.stub(element.$.commentAPI, 'reloadDrafts')
748 .returns(Promise.resolve({
749 drafts,
750 getAllThreadsForChange: () => ([]),
751 computeDraftCount: () => 1,
752 }));
753 });
754
755 test('drafts are reloaded when reload-drafts fired', done => {
Tao Zhou0a3c9862020-04-08 14:45:37 +0200756 element.$.fileList.dispatchEvent(
757 new CustomEvent('reload-drafts', {
758 detail: {
759 resolve: () => {
760 assert.isTrue(reloadStub.called);
761 assert.deepEqual(element._diffDrafts, drafts);
762 done();
763 },
764 },
765 composed: true, bubbles: true,
766 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100767 });
768
769 test('drafts are reloaded when comment-refresh fired', () => {
Tao Zhou0a3c9862020-04-08 14:45:37 +0200770 element.dispatchEvent(
771 new CustomEvent('comment-refresh', {
772 composed: true, bubbles: true,
773 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100774 assert.isTrue(reloadStub.called);
775 });
776 });
777
Tao Zhou18738b92020-05-04 19:44:51 +0200778 suite('_recomputeComments', () => {
779 setup(() => {
780 // Fake computeDraftCount as its required for ChangeComments,
781 // see gr-comment-api#reloadDrafts.
782 sandbox.stub(element.$.commentAPI, 'reloadDrafts')
783 .returns(Promise.resolve({
784 drafts: {},
785 getAllThreadsForChange: () => THREADS,
786 computeDraftCount: () => 0,
787 }));
788 });
789
790 test('draft threads should be a new copy with correct states', done => {
791 element.$.fileList.dispatchEvent(
792 new CustomEvent('reload-drafts', {
793 detail: {
794 resolve: () => {
795 assert.equal(element._draftCommentThreads.length, 2);
796 assert.equal(
797 element._draftCommentThreads[0].rootId,
798 THREADS[0].rootId
799 );
800 assert.notEqual(
801 element._draftCommentThreads[0].comments,
802 THREADS[0].comments
803 );
804 assert.notEqual(
805 element._draftCommentThreads[0].comments[0],
806 THREADS[0].comments[0]
807 );
808 assert.isTrue(
809 element._draftCommentThreads[0]
810 .comments
811 .slice(0, 2)
812 .every(c => c.collapsed === true)
813 );
814
815 assert.isTrue(
816 element._draftCommentThreads[0]
817 .comments[2]
818 .collapsed === false
819 );
820 done();
821 },
822 },
823 composed: true, bubbles: true,
824 }));
825 });
826 });
827
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100828 test('diff comments modified', () => {
829 sandbox.spy(element, '_handleReloadCommentThreads');
830 return element._reloadComments().then(() => {
Tao Zhou0a3c9862020-04-08 14:45:37 +0200831 element.dispatchEvent(
832 new CustomEvent('diff-comments-modified', {
833 composed: true, bubbles: true,
834 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100835 assert.isTrue(element._handleReloadCommentThreads.called);
836 });
837 });
838
839 test('thread list modified', () => {
840 sandbox.spy(element, '_handleReloadDiffComments');
Dhruv Srivastava929af7f2020-05-13 19:10:05 +0200841 element._activeTabs = [PrimaryTab.COMMENT_THREADS, SecondaryTab.CHANGE_LOG];
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100842 flushAsynchronousOperations();
843
844 return element._reloadComments().then(() => {
Tao Zhou0a3c9862020-04-08 14:45:37 +0200845 element.threadList.dispatchEvent(
846 new CustomEvent('thread-list-modified', {
847 composed: true, bubbles: true,
848 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100849 assert.isTrue(element._handleReloadDiffComments.called);
850
851 let draftStub = sinon.stub(element._changeComments, 'computeDraftCount')
852 .returns(1);
853 assert.equal(element._computeTotalCommentCounts(5,
854 element._changeComments), '5 unresolved, 1 draft');
855 assert.equal(element._computeTotalCommentCounts(0,
856 element._changeComments), '1 draft');
857 draftStub.restore();
858 draftStub = sinon.stub(element._changeComments, 'computeDraftCount')
859 .returns(0);
860 assert.equal(element._computeTotalCommentCounts(0,
861 element._changeComments), '');
862 assert.equal(element._computeTotalCommentCounts(1,
863 element._changeComments), '1 unresolved');
864 draftStub.restore();
865 draftStub = sinon.stub(element._changeComments, 'computeDraftCount')
866 .returns(2);
867 assert.equal(element._computeTotalCommentCounts(1,
868 element._changeComments), '1 unresolved, 2 drafts');
869 draftStub.restore();
870 });
871 });
872
873 suite('thread list and change log tabs', () => {
874 setup(() => {
Kasper Nilsson9c1a3db2018-10-19 15:11:07 -0700875 element._changeNum = '1';
876 element._patchRange = {
877 basePatchNum: 'PARENT',
878 patchNum: 1,
879 };
Becky Siegel9b03dd22017-10-26 14:57:32 -0700880 element._change = {
881 change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
882 revisions: {
Wyatt Allena744e232017-11-08 15:33:48 -0800883 rev2: {_number: 2, commit: {parents: []}},
884 rev1: {_number: 1, commit: {parents: []}},
885 rev13: {_number: 13, commit: {parents: []}},
886 rev3: {_number: 3, commit: {parents: []}},
Kasper Nilssonf0743732016-10-18 13:01:10 -0700887 },
888 current_revision: 'rev3',
889 status: 'NEW',
890 labels: {
891 test: {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100892 all: [],
Kasper Nilssonf0743732016-10-18 13:01:10 -0700893 default_value: 0,
894 values: [],
895 approved: {},
896 },
897 },
898 };
Kasper Nilsson34a5d892018-04-11 11:10:53 -0700899 sandbox.stub(element.$.relatedChanges, 'reload');
900 sandbox.stub(element, '_reload').returns(Promise.resolve());
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100901 sandbox.spy(element, '_paramsChanged');
902 element.params = {view: 'change', changeNum: '1'};
Kasper Nilsson34a5d892018-04-11 11:10:53 -0700903 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100904 });
905
906 suite('Findings comment tab', () => {
907 setup(done => {
Kasper Nilssonbbd28672018-08-01 10:23:23 -0700908 element._change = {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100909 change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
910 revisions: {
911 rev2: {_number: 2, commit: {parents: []}},
912 rev1: {_number: 1, commit: {parents: []}},
913 rev13: {_number: 13, commit: {parents: []}},
914 rev3: {_number: 3, commit: {parents: []}},
915 rev4: {_number: 4, commit: {parents: []}},
916 },
917 current_revision: 'rev4',
Kasper Nilssonbbd28672018-08-01 10:23:23 -0700918 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100919 element._commentThreads = THREADS;
920 const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
Dhruv Srivastava929af7f2020-05-13 19:10:05 +0200921 MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[3]);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100922 flush(() => {
923 done();
924 });
Kasper Nilssonbbd28672018-08-01 10:23:23 -0700925 });
Milutin Kristofic7a86db12019-08-07 15:26:13 +0200926
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100927 test('robot comments count per patchset', () => {
928 const count = element._robotCommentCountPerPatchSet(THREADS);
929 const expectedCount = {
930 2: 1,
931 3: 1,
932 4: 2,
933 };
934 assert.deepEqual(count, expectedCount);
935 assert.equal(element._computeText({_number: 2}, THREADS),
936 'Patchset 2 (1 finding)');
937 assert.equal(element._computeText({_number: 4}, THREADS),
938 'Patchset 4 (2 findings)');
939 assert.equal(element._computeText({_number: 5}, THREADS),
940 'Patchset 5');
941 });
Milutin Kristofic7a86db12019-08-07 15:26:13 +0200942
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100943 test('only robot comments are rendered', () => {
944 assert.equal(element._robotCommentThreads.length, 2);
945 assert.equal(element._robotCommentThreads[0].comments[0].robot_id,
946 'rc1');
947 assert.equal(element._robotCommentThreads[1].comments[0].robot_id,
948 'rc2');
949 });
950
951 test('changing patchsets resets robot comments', done => {
952 element.set('_change.current_revision', 'rev3');
953 flush(() => {
954 assert.equal(element._robotCommentThreads.length, 1);
955 done();
956 });
957 });
958
959 test('Show more button is hidden', () => {
960 assert.isNull(element.shadowRoot.querySelector('.show-robot-comments'));
961 });
962
963 suite('robot comments show more button', () => {
964 setup(done => {
965 const arr = [];
966 for (let i = 0; i <= 30; i++) {
967 arr.push(...THREADS);
968 }
969 element._commentThreads = arr;
Milutin Kristofic7a86db12019-08-07 15:26:13 +0200970 flush(() => {
Milutin Kristofic7a86db12019-08-07 15:26:13 +0200971 done();
972 });
973 });
974
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100975 test('Show more button is rendered', () => {
976 assert.isOk(element.shadowRoot.querySelector('.show-robot-comments'));
977 assert.equal(element._robotCommentThreads.length,
978 ROBOT_COMMENTS_LIMIT);
979 });
980
981 test('Clicking show more button renders all comments', done => {
982 MockInteractions.tap(element.shadowRoot.querySelector(
983 '.show-robot-comments'));
Milutin Kristofic7a86db12019-08-07 15:26:13 +0200984 flush(() => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100985 assert.equal(element._robotCommentThreads.length, 62);
Milutin Kristofic7a86db12019-08-07 15:26:13 +0200986 done();
987 });
988 });
989 });
Andrew Bonventre547b8ab2015-12-01 01:02:00 -0500990 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100991
992 test('reply button is not visible when logged out', () => {
993 assert.equal(getComputedStyle(element.$.replyBtn).display, 'none');
994 element._loggedIn = true;
995 assert.notEqual(getComputedStyle(element.$.replyBtn).display, 'none');
996 });
997
998 test('download tap calls _handleOpenDownloadDialog', () => {
999 sandbox.stub(element, '_handleOpenDownloadDialog');
Tao Zhou0a3c9862020-04-08 14:45:37 +02001000 element.$.actions.dispatchEvent(
1001 new CustomEvent('download-tap', {
1002 composed: true, bubbles: true,
1003 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001004 assert.isTrue(element._handleOpenDownloadDialog.called);
1005 });
1006
1007 test('fetches the server config on attached', done => {
1008 flush(() => {
1009 assert.equal(element._serverConfig.test, 'config');
1010 done();
1011 });
1012 });
1013
1014 test('_changeStatuses', () => {
1015 sandbox.stub(element, 'changeStatuses').returns(
1016 ['Merged', 'WIP']);
1017 element._loading = false;
1018 element._change = {
1019 change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
1020 revisions: {
1021 rev2: {_number: 2},
1022 rev1: {_number: 1},
1023 rev13: {_number: 13},
1024 rev3: {_number: 3},
1025 },
1026 current_revision: 'rev3',
1027 labels: {
1028 test: {
1029 all: [],
1030 default_value: 0,
1031 values: [],
1032 approved: {},
1033 },
1034 },
1035 };
1036 element._mergeable = true;
1037 const expectedStatuses = ['Merged', 'WIP'];
1038 assert.deepEqual(element._changeStatuses, expectedStatuses);
1039 assert.equal(element._changeStatus, expectedStatuses.join(', '));
1040 flushAsynchronousOperations();
1041 const statusChips = dom(element.root)
1042 .querySelectorAll('gr-change-status');
1043 assert.equal(statusChips.length, 2);
1044 });
1045
1046 test('diff preferences open when open-diff-prefs is fired', () => {
1047 const overlayOpenStub = sandbox.stub(element.$.fileList,
1048 'openDiffPrefs');
Tao Zhou0a3c9862020-04-08 14:45:37 +02001049 element.$.fileListHeader.dispatchEvent(
1050 new CustomEvent('open-diff-prefs', {
1051 composed: true, bubbles: true,
1052 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001053 assert.isTrue(overlayOpenStub.called);
1054 });
1055
1056 test('_prepareCommitMsgForLinkify', () => {
1057 let commitMessage = 'R=test@google.com';
1058 let result = element._prepareCommitMsgForLinkify(commitMessage);
1059 assert.equal(result, 'R=\u200Btest@google.com');
1060
1061 commitMessage = 'R=test@google.com\nR=test@google.com';
1062 result = element._prepareCommitMsgForLinkify(commitMessage);
1063 assert.equal(result, 'R=\u200Btest@google.com\nR=\u200Btest@google.com');
1064
1065 commitMessage = 'CC=test@google.com';
1066 result = element._prepareCommitMsgForLinkify(commitMessage);
1067 assert.equal(result, 'CC=\u200Btest@google.com');
David Ostrovskya2401c12020-05-03 19:29:26 +02001068 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001069
1070 test('_isSubmitEnabled', () => {
1071 assert.isFalse(element._isSubmitEnabled({}));
1072 assert.isFalse(element._isSubmitEnabled({submit: {}}));
1073 assert.isTrue(element._isSubmitEnabled(
1074 {submit: {enabled: true}}));
1075 });
1076
1077 test('_reload is called when an approved label is removed', () => {
1078 const vote = {_account_id: 1, name: 'bojack', value: 1};
1079 element._changeNum = '42';
1080 element._patchRange = {
1081 basePatchNum: 'PARENT',
1082 patchNum: 1,
1083 };
1084 element._change = {
1085 change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
1086 owner: {email: 'abc@def'},
1087 revisions: {
1088 rev2: {_number: 2, commit: {parents: []}},
1089 rev1: {_number: 1, commit: {parents: []}},
1090 rev13: {_number: 13, commit: {parents: []}},
1091 rev3: {_number: 3, commit: {parents: []}},
1092 },
1093 current_revision: 'rev3',
1094 status: 'NEW',
1095 labels: {
1096 test: {
1097 all: [vote],
1098 default_value: 0,
1099 values: [],
1100 approved: {},
1101 },
1102 },
1103 };
1104 flushAsynchronousOperations();
1105 const reloadStub = sandbox.stub(element, '_reload');
1106 element.splice('_change.labels.test.all', 0, 1);
1107 assert.isFalse(reloadStub.called);
1108 element._change.labels.test.all.push(vote);
1109 element._change.labels.test.all.push(vote);
1110 element._change.labels.test.approved = vote;
1111 flushAsynchronousOperations();
1112 element.splice('_change.labels.test.all', 0, 2);
1113 assert.isTrue(reloadStub.called);
1114 assert.isTrue(reloadStub.calledOnce);
1115 });
1116
1117 test('reply button has updated count when there are drafts', () => {
1118 const getLabel = element._computeReplyButtonLabel;
1119
1120 assert.equal(getLabel(null, false), 'Reply');
Ben Rohlfs706d72b2020-05-28 14:56:55 +02001121 assert.equal(getLabel(null, true), 'Start Review');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001122
1123 const changeRecord = {base: null};
1124 assert.equal(getLabel(changeRecord, false), 'Reply');
1125
1126 changeRecord.base = {};
1127 assert.equal(getLabel(changeRecord, false), 'Reply');
1128
1129 changeRecord.base = {
1130 'file1.txt': [{}],
1131 'file2.txt': [{}, {}],
1132 };
1133 assert.equal(getLabel(changeRecord, false), 'Reply (3)');
1134 });
1135
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001136 test('comment events properly update diff drafts', () => {
1137 element._patchRange = {
1138 basePatchNum: 'PARENT',
1139 patchNum: 2,
1140 };
1141 const draft = {
1142 __draft: true,
1143 id: 'id1',
1144 path: '/foo/bar.txt',
1145 text: 'hello',
1146 };
1147 element._handleCommentSave({detail: {comment: draft}});
1148 draft.patch_set = 2;
1149 assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
1150 draft.patch_set = null;
1151 draft.text = 'hello, there';
1152 element._handleCommentSave({detail: {comment: draft}});
1153 draft.patch_set = 2;
1154 assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
1155 const draft2 = {
1156 __draft: true,
1157 id: 'id2',
1158 path: '/foo/bar.txt',
1159 text: 'hola',
1160 };
1161 element._handleCommentSave({detail: {comment: draft2}});
1162 draft2.patch_set = 2;
1163 assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft, draft2]});
1164 draft.patch_set = null;
1165 element._handleCommentDiscard({detail: {comment: draft}});
1166 draft.patch_set = 2;
1167 assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft2]});
1168 element._handleCommentDiscard({detail: {comment: draft2}});
1169 assert.deepEqual(element._diffDrafts, {});
1170 });
1171
1172 test('change num change', () => {
1173 element._changeNum = null;
1174 element._patchRange = {
1175 basePatchNum: 'PARENT',
1176 patchNum: 2,
1177 };
1178 element._change = {
1179 change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
1180 labels: {},
1181 };
1182 element.viewState.changeNum = null;
1183 element.viewState.diffMode = 'UNIFIED';
1184 assert.equal(element.viewState.numFilesShown, 200);
1185 assert.equal(element._numFilesShown, 200);
1186 element._numFilesShown = 150;
1187 flushAsynchronousOperations();
1188 assert.equal(element.viewState.diffMode, 'UNIFIED');
1189 assert.equal(element.viewState.numFilesShown, 150);
1190
1191 element._changeNum = '1';
1192 element.params = {changeNum: '1'};
1193 element._change.newProp = '1';
1194 flushAsynchronousOperations();
1195 assert.equal(element.viewState.diffMode, 'UNIFIED');
1196 assert.equal(element.viewState.changeNum, '1');
1197
1198 element._changeNum = '2';
1199 element.params = {changeNum: '2'};
1200 element._change.newProp = '2';
1201 flushAsynchronousOperations();
1202 assert.equal(element.viewState.diffMode, 'UNIFIED');
1203 assert.equal(element.viewState.changeNum, '2');
1204 assert.equal(element.viewState.numFilesShown, 200);
1205 assert.equal(element._numFilesShown, 200);
1206 });
1207
1208 test('_setDiffViewMode is called with reset when new change is loaded',
1209 () => {
1210 sandbox.stub(element, '_setDiffViewMode');
1211 element.viewState = {changeNum: 1};
1212 element._changeNum = 2;
1213 element._resetFileListViewState();
1214 assert.isTrue(
1215 element._setDiffViewMode.lastCall.calledWithExactly(true));
1216 });
1217
1218 test('diffViewMode is propagated from file list header', () => {
1219 element.viewState = {diffMode: 'UNIFIED'};
1220 element.$.fileListHeader.diffViewMode = 'SIDE_BY_SIDE';
1221 assert.equal(element.viewState.diffMode, 'SIDE_BY_SIDE');
1222 });
1223
1224 test('diffMode defaults to side by side without preferences', done => {
1225 sandbox.stub(element.$.restAPI, 'getPreferences').returns(
1226 Promise.resolve({}));
1227 // No user prefs or diff view mode set.
1228
1229 element._setDiffViewMode().then(() => {
1230 assert.equal(element.viewState.diffMode, 'SIDE_BY_SIDE');
1231 done();
1232 });
1233 });
1234
1235 test('diffMode defaults to preference when not already set', done => {
1236 sandbox.stub(element.$.restAPI, 'getPreferences').returns(
1237 Promise.resolve({default_diff_view: 'UNIFIED'}));
1238
1239 element._setDiffViewMode().then(() => {
1240 assert.equal(element.viewState.diffMode, 'UNIFIED');
1241 done();
1242 });
1243 });
1244
1245 test('existing diffMode overrides preference', done => {
1246 element.viewState.diffMode = 'SIDE_BY_SIDE';
1247 sandbox.stub(element.$.restAPI, 'getPreferences').returns(
1248 Promise.resolve({default_diff_view: 'UNIFIED'}));
1249 element._setDiffViewMode().then(() => {
1250 assert.equal(element.viewState.diffMode, 'SIDE_BY_SIDE');
1251 done();
1252 });
1253 });
1254
1255 test('don’t reload entire page when patchRange changes', () => {
1256 const reloadStub = sandbox.stub(element, '_reload',
1257 () => Promise.resolve());
1258 const reloadPatchDependentStub = sandbox.stub(element,
1259 '_reloadPatchNumDependentResources',
1260 () => Promise.resolve());
1261 const relatedClearSpy = sandbox.spy(element.$.relatedChanges, 'clear');
1262 const collapseStub = sandbox.stub(element.$.fileList, 'collapseAllDiffs');
1263
1264 const value = {
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02001265 view: GerritNav.View.CHANGE,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001266 patchNum: '1',
1267 };
1268 element._paramsChanged(value);
1269 assert.isTrue(reloadStub.calledOnce);
1270 assert.isTrue(relatedClearSpy.calledOnce);
1271
1272 element._initialLoadComplete = true;
1273
1274 value.basePatchNum = '1';
1275 value.patchNum = '2';
1276 element._paramsChanged(value);
1277 assert.isFalse(reloadStub.calledTwice);
1278 assert.isTrue(reloadPatchDependentStub.calledOnce);
1279 assert.isTrue(relatedClearSpy.calledOnce);
1280 assert.isTrue(collapseStub.calledTwice);
1281 });
1282
1283 test('reload entire page when patchRange doesnt change', () => {
1284 const reloadStub = sandbox.stub(element, '_reload',
1285 () => Promise.resolve());
1286 const collapseStub = sandbox.stub(element.$.fileList, 'collapseAllDiffs');
1287 const value = {
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02001288 view: GerritNav.View.CHANGE,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001289 };
1290 element._paramsChanged(value);
1291 assert.isTrue(reloadStub.calledOnce);
1292 element._initialLoadComplete = true;
1293 element._paramsChanged(value);
1294 assert.isTrue(reloadStub.calledTwice);
1295 assert.isTrue(collapseStub.calledTwice);
1296 });
1297
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001298 test('related changes are not updated after other action', done => {
1299 sandbox.stub(element, '_reload', () => Promise.resolve());
1300 sandbox.stub(element.$.relatedChanges, 'reload');
1301 const e = {detail: {action: 'abandon'}};
1302 element._handleReloadChange(e).then(() => {
1303 assert.isFalse(navigateToChangeStub.called);
1304 done();
1305 });
1306 });
1307
1308 test('_computeMergedCommitInfo', () => {
1309 const dummyRevs = {
1310 1: {commit: {commit: 1}},
1311 2: {commit: {}},
1312 };
1313 assert.deepEqual(element._computeMergedCommitInfo(0, dummyRevs), {});
1314 assert.deepEqual(element._computeMergedCommitInfo(1, dummyRevs),
1315 dummyRevs[1].commit);
1316
1317 // Regression test for issue 5337.
1318 const commit = element._computeMergedCommitInfo(2, dummyRevs);
1319 assert.notDeepEqual(commit, dummyRevs[2]);
1320 assert.deepEqual(commit, {commit: 2});
1321 });
1322
1323 test('_computeCopyTextForTitle', () => {
1324 const change = {
1325 _number: 123,
1326 subject: 'test subject',
1327 revisions: {
1328 rev1: {_number: 1},
1329 rev3: {_number: 3},
1330 },
1331 current_revision: 'rev3',
1332 };
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02001333 sandbox.stub(GerritNav, 'getUrlForChange')
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001334 .returns('/change/123');
1335 assert.equal(
1336 element._computeCopyTextForTitle(change),
Paladox noned619ebc2020-03-22 00:19:41 +00001337 `123: test subject | http://${location.host}/change/123`
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001338 );
1339 });
1340
1341 test('get latest revision', () => {
1342 let change = {
1343 revisions: {
1344 rev1: {_number: 1},
1345 rev3: {_number: 3},
1346 },
1347 current_revision: 'rev3',
1348 };
1349 assert.equal(element._getLatestRevisionSHA(change), 'rev3');
1350 change = {
1351 revisions: {
1352 rev1: {_number: 1},
1353 },
1354 };
1355 assert.equal(element._getLatestRevisionSHA(change), 'rev1');
1356 });
1357
1358 test('show commit message edit button', () => {
1359 const _change = {
Dmitrii Filippov4e4522e2020-05-06 12:50:49 +02001360 status: ChangeStatus.MERGED,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001361 };
1362 assert.isTrue(element._computeHideEditCommitMessage(false, false, {}));
1363 assert.isTrue(element._computeHideEditCommitMessage(true, true, {}));
1364 assert.isTrue(element._computeHideEditCommitMessage(false, true, {}));
1365 assert.isFalse(element._computeHideEditCommitMessage(true, false, {}));
1366 assert.isTrue(element._computeHideEditCommitMessage(true, false,
1367 _change));
1368 assert.isTrue(element._computeHideEditCommitMessage(true, false, {},
1369 true));
1370 assert.isFalse(element._computeHideEditCommitMessage(true, false, {},
1371 false));
1372 });
1373
1374 test('_handleCommitMessageSave trims trailing whitespace', () => {
1375 const putStub = sandbox.stub(element.$.restAPI, 'putChangeCommitMessage')
1376 .returns(Promise.resolve({}));
1377
1378 const mockEvent = content => { return {detail: {content}}; };
1379
1380 element._handleCommitMessageSave(mockEvent('test \n test '));
1381 assert.equal(putStub.lastCall.args[1], 'test\n test');
1382
1383 element._handleCommitMessageSave(mockEvent(' test\ntest'));
1384 assert.equal(putStub.lastCall.args[1], ' test\ntest');
1385
1386 element._handleCommitMessageSave(mockEvent('\n\n\n\n\n\n\n\n'));
1387 assert.equal(putStub.lastCall.args[1], '\n\n\n\n\n\n\n\n');
1388 });
1389
1390 test('_computeChangeIdCommitMessageError', () => {
1391 let commitMessage =
1392 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483';
1393 let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
1394 assert.equal(
1395 element._computeChangeIdCommitMessageError(commitMessage, change),
1396 null);
1397
1398 change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
1399 assert.equal(
1400 element._computeChangeIdCommitMessageError(commitMessage, change),
1401 'mismatch');
1402
1403 commitMessage = 'This is the greatest change.';
1404 assert.equal(
1405 element._computeChangeIdCommitMessageError(commitMessage, change),
1406 'missing');
1407 });
1408
1409 test('multiple change Ids in commit message picks last', () => {
1410 const commitMessage = [
1411 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
1412 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
1413 ].join('\n');
1414 let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
1415 assert.equal(
1416 element._computeChangeIdCommitMessageError(commitMessage, change),
1417 null);
1418 change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
1419 assert.equal(
1420 element._computeChangeIdCommitMessageError(commitMessage, change),
1421 'mismatch');
1422 });
1423
1424 test('does not count change Id that starts mid line', () => {
1425 const commitMessage = [
1426 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
1427 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
1428 ].join(' and ');
1429 let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
1430 assert.equal(
1431 element._computeChangeIdCommitMessageError(commitMessage, change),
1432 null);
1433 change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
1434 assert.equal(
1435 element._computeChangeIdCommitMessageError(commitMessage, change),
1436 'mismatch');
1437 });
1438
1439 test('_computeTitleAttributeWarning', () => {
1440 let changeIdCommitMessageError = 'missing';
1441 assert.equal(
1442 element._computeTitleAttributeWarning(changeIdCommitMessageError),
1443 'No Change-Id in commit message');
1444
1445 changeIdCommitMessageError = 'mismatch';
1446 assert.equal(
1447 element._computeTitleAttributeWarning(changeIdCommitMessageError),
1448 'Change-Id mismatch');
1449 });
1450
1451 test('_computeChangeIdClass', () => {
1452 let changeIdCommitMessageError = 'missing';
1453 assert.equal(
1454 element._computeChangeIdClass(changeIdCommitMessageError), '');
1455
1456 changeIdCommitMessageError = 'mismatch';
1457 assert.equal(
1458 element._computeChangeIdClass(changeIdCommitMessageError), 'warning');
1459 });
1460
1461 test('topic is coalesced to null', done => {
1462 sandbox.stub(element, '_changeChanged');
1463 sandbox.stub(element.$.restAPI, 'getChangeDetail', () => Promise.resolve({
1464 id: '123456789',
1465 labels: {},
1466 current_revision: 'foo',
1467 revisions: {foo: {commit: {}}},
1468 }));
1469
1470 element._getChangeDetail().then(() => {
1471 assert.isNull(element._change.topic);
1472 done();
1473 });
1474 });
1475
1476 test('commit sha is populated from getChangeDetail', done => {
1477 sandbox.stub(element, '_changeChanged');
1478 sandbox.stub(element.$.restAPI, 'getChangeDetail', () => Promise.resolve({
1479 id: '123456789',
1480 labels: {},
1481 current_revision: 'foo',
1482 revisions: {foo: {commit: {}}},
1483 }));
1484
1485 element._getChangeDetail().then(() => {
1486 assert.equal('foo', element._commitInfo.commit);
1487 done();
1488 });
1489 });
1490
1491 test('edit is added to change', () => {
1492 sandbox.stub(element, '_changeChanged');
1493 sandbox.stub(element.$.restAPI, 'getChangeDetail', () => Promise.resolve({
1494 id: '123456789',
1495 labels: {},
1496 current_revision: 'foo',
1497 revisions: {foo: {commit: {}}},
1498 }));
1499 sandbox.stub(element, '_getEdit', () => Promise.resolve({
1500 base_patch_set_number: 1,
1501 commit: {commit: 'bar'},
1502 }));
1503 element._patchRange = {};
1504
1505 return element._getChangeDetail().then(() => {
1506 const revs = element._change.revisions;
1507 assert.equal(Object.keys(revs).length, 2);
1508 assert.deepEqual(revs['foo'], {commit: {commit: 'foo'}});
1509 assert.deepEqual(revs['bar'], {
1510 _number: element.EDIT_NAME,
1511 basePatchNum: 1,
1512 commit: {commit: 'bar'},
1513 fetch: undefined,
1514 });
1515 });
1516 });
1517
1518 test('_getBasePatchNum', () => {
1519 const _change = {
1520 _number: 42,
1521 revisions: {
1522 '98da160735fb81604b4c40e93c368f380539dd0e': {
1523 _number: 1,
1524 commit: {
1525 parents: [],
1526 },
1527 },
1528 },
1529 };
1530 const _patchRange = {
1531 basePatchNum: 'PARENT',
1532 };
1533 assert.equal(element._getBasePatchNum(_change, _patchRange), 'PARENT');
1534
1535 element._prefs = {
1536 default_base_for_merges: 'FIRST_PARENT',
1537 };
1538
1539 const _change2 = {
1540 _number: 42,
1541 revisions: {
1542 '98da160735fb81604b4c40e93c368f380539dd0e': {
1543 _number: 1,
1544 commit: {
1545 parents: [
1546 {
1547 commit: '6e12bdf1176eb4ab24d8491ba3b6d0704409cde8',
1548 subject: 'test',
1549 },
1550 {
1551 commit: '22f7db4754b5d9816fc581f3d9a6c0ef8429c841',
1552 subject: 'test3',
1553 },
1554 ],
1555 },
1556 },
1557 },
1558 };
1559 assert.equal(element._getBasePatchNum(_change2, _patchRange), -1);
1560
1561 _patchRange.patchNum = 1;
1562 assert.equal(element._getBasePatchNum(_change2, _patchRange), 'PARENT');
1563 });
1564
1565 test('_openReplyDialog called with `ANY` when coming from tap event',
1566 () => {
1567 const openStub = sandbox.stub(element, '_openReplyDialog');
1568 element._serverConfig = {};
1569 MockInteractions.tap(element.$.replyBtn);
1570 assert(openStub.lastCall.calledWithExactly(
1571 element.$.replyDialog.FocusTarget.ANY),
1572 '_openReplyDialog should have been passed ANY');
1573 assert.equal(openStub.callCount, 1);
1574 });
1575
1576 test('_openReplyDialog called with `BODY` when coming from message reply' +
1577 'event', done => {
1578 flush(() => {
1579 const openStub = sandbox.stub(element, '_openReplyDialog');
Tao Zhou0a3c9862020-04-08 14:45:37 +02001580 element.messagesList.dispatchEvent(
1581 new CustomEvent('reply', {
1582 detail:
1583 {message: {message: 'text'}},
1584 composed: true, bubbles: true,
1585 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001586 assert(openStub.lastCall.calledWithExactly(
1587 element.$.replyDialog.FocusTarget.BODY),
1588 '_openReplyDialog should have been passed BODY');
1589 assert.equal(openStub.callCount, 1);
1590 done();
1591 });
1592 });
1593
1594 test('reply dialog focus can be controlled', () => {
1595 const FocusTarget = element.$.replyDialog.FocusTarget;
1596 const openStub = sandbox.stub(element, '_openReplyDialog');
1597
1598 const e = {detail: {}};
1599 element._handleShowReplyDialog(e);
1600 assert(openStub.lastCall.calledWithExactly(FocusTarget.REVIEWERS),
1601 '_openReplyDialog should have been passed REVIEWERS');
1602 assert.equal(openStub.callCount, 1);
1603
1604 e.detail.value = {ccsOnly: true};
1605 element._handleShowReplyDialog(e);
1606 assert(openStub.lastCall.calledWithExactly(FocusTarget.CCS),
1607 '_openReplyDialog should have been passed CCS');
1608 assert.equal(openStub.callCount, 2);
1609 });
1610
1611 test('getUrlParameter functionality', () => {
1612 const locationStub = sandbox.stub(element, '_getLocationSearch');
1613
1614 locationStub.returns('?test');
1615 assert.equal(element._getUrlParameter('test'), 'test');
1616 locationStub.returns('?test2=12&test=3');
1617 assert.equal(element._getUrlParameter('test'), 'test');
1618 locationStub.returns('');
1619 assert.isNull(element._getUrlParameter('test'));
1620 locationStub.returns('?');
1621 assert.isNull(element._getUrlParameter('test'));
1622 locationStub.returns('?test2');
1623 assert.isNull(element._getUrlParameter('test'));
1624 });
1625
1626 test('revert dialog opened with revert param', done => {
1627 sandbox.stub(element.$.restAPI, 'getLoggedIn', () => Promise.resolve(true));
Dmitrii Filippovf97fc6e2020-04-07 09:59:22 +02001628 sandbox.stub(pluginLoader, 'awaitPluginsLoaded', () => Promise.resolve());
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001629
1630 element._patchRange = {
1631 basePatchNum: 'PARENT',
1632 patchNum: 2,
1633 };
1634 element._change = {
1635 change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
1636 revisions: {
1637 rev1: {_number: 1, commit: {parents: []}},
1638 rev2: {_number: 2, commit: {parents: []}},
1639 },
1640 current_revision: 'rev1',
Dmitrii Filippov4e4522e2020-05-06 12:50:49 +02001641 status: ChangeStatus.MERGED,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001642 labels: {},
1643 actions: {},
1644 };
1645
1646 sandbox.stub(element, '_getUrlParameter',
1647 param => {
1648 assert.equal(param, 'revert');
1649 return param;
1650 });
1651
1652 sandbox.stub(element.$.actions, 'showRevertDialog',
1653 done);
1654
1655 element._maybeShowRevertDialog();
Dmitrii Filippovf97fc6e2020-04-07 09:59:22 +02001656 assert.isTrue(pluginLoader.awaitPluginsLoaded.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001657 });
1658
1659 suite('scroll related tests', () => {
1660 test('document scrolling calls function to set scroll height', done => {
1661 const originalHeight = document.body.scrollHeight;
1662 const scrollStub = sandbox.stub(element, '_handleScroll',
1663 () => {
1664 assert.isTrue(scrollStub.called);
1665 document.body.style.height = originalHeight + 'px';
1666 scrollStub.restore();
1667 done();
1668 });
1669 document.body.style.height = '10000px';
1670 element._handleScroll();
1671 });
1672
1673 test('scrollTop is set correctly', () => {
1674 element.viewState = {scrollTop: TEST_SCROLL_TOP_PX};
1675
1676 sandbox.stub(element, '_reload', () => {
1677 // When element is reloaded, ensure that the history
1678 // state has the scrollTop set earlier. This will then
1679 // be reset.
1680 assert.isTrue(element.viewState.scrollTop == TEST_SCROLL_TOP_PX);
1681 return Promise.resolve({});
1682 });
1683
1684 // simulate reloading component, which is done when route
1685 // changes to match a regex of change view type.
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02001686 element._paramsChanged({view: GerritNav.View.CHANGE});
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001687 });
1688
1689 test('scrollTop is reset when new change is loaded', () => {
1690 element._resetFileListViewState();
1691 assert.equal(element.viewState.scrollTop, 0);
1692 });
1693 });
1694
1695 suite('reply dialog tests', () => {
1696 setup(() => {
1697 sandbox.stub(element.$.replyDialog, '_draftChanged');
1698 sandbox.stub(element.$.replyDialog, 'fetchChangeUpdates',
1699 () => Promise.resolve({isLatest: true}));
1700 element._change = {labels: {}};
1701 });
1702
1703 test('reply from comment adds quote text', () => {
1704 const e = {detail: {message: {message: 'quote text'}}};
1705 element._handleMessageReply(e);
1706 assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
1707 });
1708
1709 test('reply from comment replaces quote text', () => {
1710 element.$.replyDialog.draft = '> old quote text\n\n some draft text';
1711 element.$.replyDialog.quote = '> old quote text\n\n';
1712 const e = {detail: {message: {message: 'quote text'}}};
1713 element._handleMessageReply(e);
1714 assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
1715 });
1716
1717 test('reply from same comment preserves quote text', () => {
1718 element.$.replyDialog.draft = '> quote text\n\n some draft text';
1719 element.$.replyDialog.quote = '> quote text\n\n';
1720 const e = {detail: {message: {message: 'quote text'}}};
1721 element._handleMessageReply(e);
1722 assert.equal(element.$.replyDialog.draft,
1723 '> quote text\n\n some draft text');
1724 assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
1725 });
1726
1727 test('reply from top of page contains previous draft', () => {
1728 const div = document.createElement('div');
1729 element.$.replyDialog.draft = '> quote text\n\n some draft text';
1730 element.$.replyDialog.quote = '> quote text\n\n';
1731 const e = {target: div, preventDefault: sandbox.spy()};
1732 element._handleReplyTap(e);
1733 assert.equal(element.$.replyDialog.draft,
1734 '> quote text\n\n some draft text');
1735 assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
1736 });
1737 });
1738
1739 test('reply button is disabled until server config is loaded', () => {
1740 assert.isTrue(element._replyDisabled);
1741 element._serverConfig = {};
1742 assert.isFalse(element._replyDisabled);
1743 });
1744
1745 suite('commit message expand/collapse', () => {
1746 setup(() => {
1747 sandbox.stub(element, 'fetchChangeUpdates',
1748 () => Promise.resolve({isLatest: false}));
1749 });
1750
1751 test('commitCollapseToggle hidden for short commit message', () => {
1752 element._latestCommitMessage = '';
1753 assert.isTrue(element.$.commitCollapseToggle.hasAttribute('hidden'));
1754 });
1755
1756 test('commitCollapseToggle shown for long commit message', () => {
1757 element._latestCommitMessage = _.times(31, String).join('\n');
1758 assert.isFalse(element.$.commitCollapseToggle.hasAttribute('hidden'));
1759 });
1760
1761 test('commitCollapseToggle functions', () => {
1762 element._latestCommitMessage = _.times(35, String).join('\n');
1763 assert.isTrue(element._commitCollapsed);
1764 assert.isTrue(element._commitCollapsible);
1765 assert.isTrue(
1766 element.$.commitMessageEditor.hasAttribute('collapsed'));
1767 MockInteractions.tap(element.$.commitCollapseToggleButton);
1768 assert.isFalse(element._commitCollapsed);
1769 assert.isTrue(element._commitCollapsible);
1770 assert.isFalse(
1771 element.$.commitMessageEditor.hasAttribute('collapsed'));
1772 });
1773 });
1774
1775 suite('related changes expand/collapse', () => {
1776 let updateHeightSpy;
1777 setup(() => {
1778 updateHeightSpy = sandbox.spy(element, '_updateRelatedChangeMaxHeight');
1779 });
1780
1781 test('relatedChangesToggle shown height greater than changeInfo height',
1782 () => {
1783 assert.isFalse(element.$.relatedChangesToggle.classList
1784 .contains('showToggle'));
1785 sandbox.stub(element, '_getOffsetHeight', () => 50);
1786 sandbox.stub(element, '_getScrollHeight', () => 60);
1787 sandbox.stub(element, '_getLineHeight', () => 5);
1788 sandbox.stub(window, 'matchMedia', () => { return {matches: true}; });
1789 element.$.relatedChanges.dispatchEvent(
1790 new CustomEvent('new-section-loaded'));
1791 assert.isTrue(element.$.relatedChangesToggle.classList
1792 .contains('showToggle'));
1793 assert.equal(updateHeightSpy.callCount, 1);
1794 });
1795
1796 test('relatedChangesToggle hidden height less than changeInfo height',
1797 () => {
1798 assert.isFalse(element.$.relatedChangesToggle.classList
1799 .contains('showToggle'));
1800 sandbox.stub(element, '_getOffsetHeight', () => 50);
1801 sandbox.stub(element, '_getScrollHeight', () => 40);
1802 sandbox.stub(element, '_getLineHeight', () => 5);
1803 sandbox.stub(window, 'matchMedia', () => { return {matches: true}; });
1804 element.$.relatedChanges.dispatchEvent(
1805 new CustomEvent('new-section-loaded'));
1806 assert.isFalse(element.$.relatedChangesToggle.classList
1807 .contains('showToggle'));
1808 assert.equal(updateHeightSpy.callCount, 1);
1809 });
1810
1811 test('relatedChangesToggle functions', () => {
1812 sandbox.stub(element, '_getOffsetHeight', () => 50);
1813 sandbox.stub(window, 'matchMedia', () => { return {matches: false}; });
1814 element._relatedChangesLoading = false;
1815 assert.isTrue(element._relatedChangesCollapsed);
1816 assert.isTrue(
1817 element.$.relatedChanges.classList.contains('collapsed'));
1818 MockInteractions.tap(element.$.relatedChangesToggleButton);
1819 assert.isFalse(element._relatedChangesCollapsed);
1820 assert.isFalse(
1821 element.$.relatedChanges.classList.contains('collapsed'));
1822 });
1823
1824 test('_updateRelatedChangeMaxHeight without commit toggle', () => {
1825 sandbox.stub(element, '_getOffsetHeight', () => 50);
1826 sandbox.stub(element, '_getLineHeight', () => 12);
1827 sandbox.stub(window, 'matchMedia', () => { return {matches: false}; });
1828
1829 // 50 (existing height) - 30 (extra height) = 20 (adjusted height).
1830 // 20 (max existing height) % 12 (line height) = 6 (remainder).
1831 // 20 (adjusted height) - 8 (remainder) = 12 (max height to set).
1832
1833 element._updateRelatedChangeMaxHeight();
1834 assert.equal(getCustomCssValue('--relation-chain-max-height'),
1835 '12px');
1836 assert.equal(getCustomCssValue('--related-change-btn-top-padding'),
1837 '');
1838 });
1839
1840 test('_updateRelatedChangeMaxHeight with commit toggle', () => {
1841 element._latestCommitMessage = _.times(31, String).join('\n');
1842 sandbox.stub(element, '_getOffsetHeight', () => 50);
1843 sandbox.stub(element, '_getLineHeight', () => 12);
1844 sandbox.stub(window, 'matchMedia', () => { return {matches: false}; });
1845
1846 // 50 (existing height) % 12 (line height) = 2 (remainder).
1847 // 50 (existing height) - 2 (remainder) = 48 (max height to set).
1848
1849 element._updateRelatedChangeMaxHeight();
1850 assert.equal(getCustomCssValue('--relation-chain-max-height'),
1851 '48px');
1852 assert.equal(getCustomCssValue('--related-change-btn-top-padding'),
1853 '2px');
1854 });
1855
1856 test('_updateRelatedChangeMaxHeight in small screen mode', () => {
1857 element._latestCommitMessage = _.times(31, String).join('\n');
1858 sandbox.stub(element, '_getOffsetHeight', () => 50);
1859 sandbox.stub(element, '_getLineHeight', () => 12);
1860 sandbox.stub(window, 'matchMedia', () => { return {matches: true}; });
1861
1862 element._updateRelatedChangeMaxHeight();
1863
1864 // 400 (new height) % 12 (line height) = 4 (remainder).
1865 // 400 (new height) - 4 (remainder) = 396.
1866
1867 assert.equal(getCustomCssValue('--relation-chain-max-height'),
1868 '396px');
1869 });
1870
1871 test('_updateRelatedChangeMaxHeight in medium screen mode', () => {
1872 element._latestCommitMessage = _.times(31, String).join('\n');
1873 sandbox.stub(element, '_getOffsetHeight', () => 50);
1874 sandbox.stub(element, '_getLineHeight', () => 12);
1875 sandbox.stub(window, 'matchMedia', () => {
1876 if (window.matchMedia.lastCall.args[0] === '(max-width: 75em)') {
1877 return {matches: true};
1878 } else {
1879 return {matches: false};
1880 }
1881 });
1882
1883 // 100 (new height) % 12 (line height) = 4 (remainder).
1884 // 100 (new height) - 4 (remainder) = 96.
1885 element._updateRelatedChangeMaxHeight();
1886 assert.equal(getCustomCssValue('--relation-chain-max-height'),
1887 '96px');
1888 });
1889
1890 suite('update checks', () => {
1891 setup(() => {
1892 sandbox.spy(element, '_startUpdateCheckTimer');
1893 sandbox.stub(element, 'async', f => {
1894 // Only fire the async callback one time.
1895 if (element.async.callCount > 1) { return; }
1896 f.call(element);
1897 });
1898 });
1899
1900 test('_startUpdateCheckTimer negative delay', () => {
1901 sandbox.stub(element, 'fetchChangeUpdates');
1902
1903 element._serverConfig = {change: {update_delay: -1}};
1904
1905 assert.isTrue(element._startUpdateCheckTimer.called);
1906 assert.isFalse(element.fetchChangeUpdates.called);
1907 });
1908
1909 test('_startUpdateCheckTimer up-to-date', () => {
1910 sandbox.stub(element, 'fetchChangeUpdates',
1911 () => Promise.resolve({isLatest: true}));
1912
1913 element._serverConfig = {change: {update_delay: 12345}};
1914
1915 assert.isTrue(element._startUpdateCheckTimer.called);
1916 assert.isTrue(element.fetchChangeUpdates.called);
1917 assert.equal(element.async.lastCall.args[1], 12345 * 1000);
1918 });
1919
1920 test('_startUpdateCheckTimer out-of-date shows an alert', done => {
1921 sandbox.stub(element, 'fetchChangeUpdates',
1922 () => Promise.resolve({isLatest: false}));
1923 element.addEventListener('show-alert', e => {
1924 assert.equal(e.detail.message,
1925 'A newer patch set has been uploaded');
1926 done();
1927 });
1928 element._serverConfig = {change: {update_delay: 12345}};
1929 });
1930
1931 test('_startUpdateCheckTimer new status shows an alert', done => {
1932 sandbox.stub(element, 'fetchChangeUpdates')
1933 .returns(Promise.resolve({
1934 isLatest: true,
Dmitrii Filippov4e4522e2020-05-06 12:50:49 +02001935 newStatus: ChangeStatus.MERGED,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001936 }));
1937 element.addEventListener('show-alert', e => {
1938 assert.equal(e.detail.message, 'This change has been merged');
1939 done();
1940 });
1941 element._serverConfig = {change: {update_delay: 12345}};
1942 });
1943
1944 test('_startUpdateCheckTimer new messages shows an alert', done => {
1945 sandbox.stub(element, 'fetchChangeUpdates')
1946 .returns(Promise.resolve({
1947 isLatest: true,
1948 newMessages: true,
1949 }));
1950 element.addEventListener('show-alert', e => {
1951 assert.equal(e.detail.message,
1952 'There are new messages on this change');
1953 done();
1954 });
1955 element._serverConfig = {change: {update_delay: 12345}};
1956 });
1957 });
1958
1959 test('canStartReview computation', () => {
1960 const change1 = {};
1961 const change2 = {
1962 actions: {
1963 ready: {
1964 enabled: true,
1965 },
1966 },
1967 };
1968 const change3 = {
1969 actions: {
1970 ready: {
1971 label: 'Ready for Review',
1972 },
1973 },
1974 };
1975 assert.isFalse(element._computeCanStartReview(change1));
1976 assert.isTrue(element._computeCanStartReview(change2));
1977 assert.isFalse(element._computeCanStartReview(change3));
1978 });
1979 });
1980
1981 test('header class computation', () => {
1982 assert.equal(element._computeHeaderClass(), 'header');
1983 assert.equal(element._computeHeaderClass(true), 'header editMode');
1984 });
1985
1986 test('_maybeScrollToMessage', done => {
1987 flush(() => {
1988 const scrollStub = sandbox.stub(element.messagesList,
1989 'scrollToMessage');
1990
1991 element._maybeScrollToMessage('');
1992 assert.isFalse(scrollStub.called);
1993 element._maybeScrollToMessage('message');
1994 assert.isFalse(scrollStub.called);
1995 element._maybeScrollToMessage('#message-TEST');
1996 assert.isTrue(scrollStub.called);
1997 assert.equal(scrollStub.lastCall.args[0], 'TEST');
1998 done();
1999 });
2000 });
2001
2002 test('topic update reloads related changes', () => {
2003 sandbox.stub(element.$.relatedChanges, 'reload');
2004 element.dispatchEvent(new CustomEvent('topic-changed'));
2005 assert.isTrue(element.$.relatedChanges.reload.calledOnce);
2006 });
2007
2008 test('_computeEditMode', () => {
2009 const callCompute = (range, params) =>
2010 element._computeEditMode({base: range}, {base: params});
2011 assert.isFalse(callCompute({}, {}));
2012 assert.isTrue(callCompute({}, {edit: true}));
2013 assert.isFalse(callCompute({basePatchNum: 'PARENT', patchNum: 1}, {}));
2014 assert.isFalse(callCompute({basePatchNum: 'edit', patchNum: 1}, {}));
2015 assert.isTrue(callCompute({basePatchNum: 1, patchNum: 'edit'}, {}));
2016 });
2017
2018 test('_processEdit', () => {
2019 element._patchRange = {};
2020 const change = {
2021 current_revision: 'foo',
2022 revisions: {foo: {commit: {}, actions: {cherrypick: {enabled: true}}}},
2023 };
2024 let mockChange;
2025
2026 // With no edit, mockChange should be unmodified.
2027 element._processEdit(mockChange = _.cloneDeep(change), null);
2028 assert.deepEqual(mockChange, change);
2029
2030 // When edit is not based on the latest PS, current_revision should be
2031 // unmodified.
2032 const edit = {
2033 base_patch_set_number: 1,
2034 commit: {commit: 'bar'},
2035 fetch: true,
2036 };
2037 element._processEdit(mockChange = _.cloneDeep(change), edit);
2038 assert.notDeepEqual(mockChange, change);
2039 assert.equal(mockChange.revisions.bar._number, element.EDIT_NAME);
2040 assert.equal(mockChange.current_revision, change.current_revision);
2041 assert.deepEqual(mockChange.revisions.bar.commit, {commit: 'bar'});
2042 assert.notOk(mockChange.revisions.bar.actions);
2043
2044 edit.base_revision = 'foo';
2045 element._processEdit(mockChange = _.cloneDeep(change), edit);
2046 assert.notDeepEqual(mockChange, change);
2047 assert.equal(mockChange.current_revision, 'bar');
2048 assert.deepEqual(mockChange.revisions.bar.actions,
2049 mockChange.revisions.foo.actions);
2050
2051 // If _patchRange.patchNum is defined, do not load edit.
2052 element._patchRange.patchNum = 'baz';
2053 change.current_revision = 'baz';
2054 element._processEdit(mockChange = _.cloneDeep(change), edit);
2055 assert.equal(element._patchRange.patchNum, 'baz');
2056 assert.notOk(mockChange.revisions.bar.actions);
2057 });
2058
2059 test('file-action-tap handling', () => {
2060 element._patchRange = {
2061 basePatchNum: 'PARENT',
2062 patchNum: 1,
2063 };
2064 const fileList = element.$.fileList;
2065 const Actions = GrEditConstants.Actions;
Milutin Kristofic21b0dc92020-05-18 22:44:11 +02002066 element.$.fileListHeader.editMode = true;
2067 flushAsynchronousOperations();
2068 const controls = element.$.fileListHeader
2069 .shadowRoot.querySelector('#editControls');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002070 sandbox.stub(controls, 'openDeleteDialog');
2071 sandbox.stub(controls, 'openRenameDialog');
2072 sandbox.stub(controls, 'openRestoreDialog');
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02002073 sandbox.stub(GerritNav, 'getEditUrlForDiff');
2074 sandbox.stub(GerritNav, 'navigateToRelativeUrl');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002075
2076 // Delete
2077 fileList.dispatchEvent(new CustomEvent('file-action-tap', {
2078 detail: {action: Actions.DELETE.id, path: 'foo'},
2079 bubbles: true,
2080 composed: true,
2081 }));
2082 flushAsynchronousOperations();
2083
2084 assert.isTrue(controls.openDeleteDialog.called);
2085 assert.equal(controls.openDeleteDialog.lastCall.args[0], 'foo');
2086
2087 // Restore
2088 fileList.dispatchEvent(new CustomEvent('file-action-tap', {
2089 detail: {action: Actions.RESTORE.id, path: 'foo'},
2090 bubbles: true,
2091 composed: true,
2092 }));
2093 flushAsynchronousOperations();
2094
2095 assert.isTrue(controls.openRestoreDialog.called);
2096 assert.equal(controls.openRestoreDialog.lastCall.args[0], 'foo');
2097
2098 // Rename
2099 fileList.dispatchEvent(new CustomEvent('file-action-tap', {
2100 detail: {action: Actions.RENAME.id, path: 'foo'},
2101 bubbles: true,
2102 composed: true,
2103 }));
2104 flushAsynchronousOperations();
2105
2106 assert.isTrue(controls.openRenameDialog.called);
2107 assert.equal(controls.openRenameDialog.lastCall.args[0], 'foo');
2108
2109 // Open
2110 fileList.dispatchEvent(new CustomEvent('file-action-tap', {
2111 detail: {action: Actions.OPEN.id, path: 'foo'},
2112 bubbles: true,
2113 composed: true,
2114 }));
2115 flushAsynchronousOperations();
2116
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02002117 assert.isTrue(GerritNav.getEditUrlForDiff.called);
2118 assert.equal(GerritNav.getEditUrlForDiff.lastCall.args[1], 'foo');
2119 assert.equal(GerritNav.getEditUrlForDiff.lastCall.args[2], '1');
2120 assert.isTrue(GerritNav.navigateToRelativeUrl.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002121 });
2122
2123 test('_selectedRevision updates when patchNum is changed', () => {
2124 const revision1 = {_number: 1, commit: {parents: []}};
2125 const revision2 = {_number: 2, commit: {parents: []}};
2126 sandbox.stub(element.$.restAPI, 'getChangeDetail').returns(
2127 Promise.resolve({
2128 revisions: {
2129 aaa: revision1,
2130 bbb: revision2,
2131 },
2132 labels: {},
2133 actions: {},
2134 current_revision: 'bbb',
2135 change_id: 'loremipsumdolorsitamet',
2136 }));
2137 sandbox.stub(element, '_getEdit').returns(Promise.resolve());
2138 sandbox.stub(element, '_getPreferences').returns(Promise.resolve({}));
2139 element._patchRange = {patchNum: '2'};
2140 return element._getChangeDetail().then(() => {
2141 assert.strictEqual(element._selectedRevision, revision2);
2142
2143 element.set('_patchRange.patchNum', '1');
2144 assert.strictEqual(element._selectedRevision, revision1);
2145 });
2146 });
2147
2148 test('_selectedRevision is assigned when patchNum is edit', () => {
2149 const revision1 = {_number: 1, commit: {parents: []}};
2150 const revision2 = {_number: 2, commit: {parents: []}};
2151 const revision3 = {_number: 'edit', commit: {parents: []}};
2152 sandbox.stub(element.$.restAPI, 'getChangeDetail').returns(
2153 Promise.resolve({
2154 revisions: {
2155 aaa: revision1,
2156 bbb: revision2,
2157 ccc: revision3,
2158 },
2159 labels: {},
2160 actions: {},
2161 current_revision: 'ccc',
2162 change_id: 'loremipsumdolorsitamet',
2163 }));
2164 sandbox.stub(element, '_getEdit').returns(Promise.resolve());
2165 sandbox.stub(element, '_getPreferences').returns(Promise.resolve({}));
2166 element._patchRange = {patchNum: 'edit'};
2167 return element._getChangeDetail().then(() => {
2168 assert.strictEqual(element._selectedRevision, revision3);
2169 });
2170 });
2171
2172 test('_sendShowChangeEvent', () => {
2173 element._change = {labels: {}};
2174 element._patchRange = {patchNum: 4};
2175 element._mergeable = true;
2176 const showStub = sandbox.stub(element.$.jsAPI, 'handleEvent');
2177 element._sendShowChangeEvent();
2178 assert.isTrue(showStub.calledOnce);
2179 assert.equal(
2180 showStub.lastCall.args[0], element.$.jsAPI.EventType.SHOW_CHANGE);
2181 assert.deepEqual(showStub.lastCall.args[1], {
2182 change: {labels: {}},
2183 patchNum: 4,
2184 info: {mergeable: true},
2185 });
2186 });
2187
2188 suite('_handleEditTap', () => {
2189 let fireEdit;
2190
2191 setup(() => {
2192 fireEdit = () => {
2193 element.$.actions.dispatchEvent(new CustomEvent('edit-tap'));
2194 };
2195 navigateToChangeStub.restore();
2196
2197 element._change = {revisions: {rev1: {_number: 1}}};
2198 });
2199
2200 test('edit exists in revisions', done => {
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02002201 sandbox.stub(GerritNav, 'navigateToChange', (...args) => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002202 assert.equal(args.length, 2);
2203 assert.equal(args[1], element.EDIT_NAME); // patchNum
2204 done();
2205 });
2206
2207 element.set('_change.revisions.rev2', {_number: element.EDIT_NAME});
2208 flushAsynchronousOperations();
2209
2210 fireEdit();
2211 });
2212
2213 test('no edit exists in revisions, non-latest patchset', done => {
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02002214 sandbox.stub(GerritNav, 'navigateToChange', (...args) => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002215 assert.equal(args.length, 4);
2216 assert.equal(args[1], 1); // patchNum
2217 assert.equal(args[3], true); // opt_isEdit
2218 done();
2219 });
2220
2221 element.set('_change.revisions.rev2', {_number: 2});
2222 element._patchRange = {patchNum: 1};
2223 flushAsynchronousOperations();
2224
2225 fireEdit();
2226 });
2227
2228 test('no edit exists in revisions, latest patchset', done => {
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02002229 sandbox.stub(GerritNav, 'navigateToChange', (...args) => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002230 assert.equal(args.length, 4);
2231 // No patch should be specified when patchNum == latest.
2232 assert.isNotOk(args[1]); // patchNum
2233 assert.equal(args[3], true); // opt_isEdit
2234 done();
2235 });
2236
2237 element.set('_change.revisions.rev2', {_number: 2});
2238 element._patchRange = {patchNum: 2};
2239 flushAsynchronousOperations();
2240
2241 fireEdit();
2242 });
2243 });
2244
2245 test('_handleStopEditTap', done => {
2246 sandbox.stub(element.$.metadata, '_computeLabelNames');
2247 navigateToChangeStub.restore();
2248 sandbox.stub(element, 'computeLatestPatchNum').returns(1);
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02002249 sandbox.stub(GerritNav, 'navigateToChange', (...args) => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002250 assert.equal(args.length, 2);
2251 assert.equal(args[1], 1); // patchNum
2252 done();
2253 });
2254
2255 element._patchRange = {patchNum: 1};
2256 element.$.actions.dispatchEvent(new CustomEvent('stop-edit-tap',
2257 {bubbles: false}));
2258 });
2259
2260 suite('plugin endpoints', () => {
2261 test('endpoint params', done => {
2262 element._change = {labels: {}};
2263 element._selectedRevision = {};
2264 let hookEl;
2265 let plugin;
Dmitrii Filippov5f25dc02020-04-07 18:49:00 +02002266 pluginApi.install(
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002267 p => {
2268 plugin = p;
2269 plugin.hook('change-view-integration').getLastAttached()
2270 .then(
2271 el => hookEl = el);
2272 },
2273 '0.1',
2274 'http://some/plugins/url.html');
2275 flush(() => {
2276 assert.strictEqual(hookEl.plugin, plugin);
2277 assert.strictEqual(hookEl.change, element._change);
2278 assert.strictEqual(hookEl.revision, element._selectedRevision);
2279 done();
2280 });
2281 });
2282 });
2283
2284 suite('_getMergeability', () => {
2285 let getMergeableStub;
2286
2287 setup(() => {
2288 element._change = {labels: {}};
2289 getMergeableStub = sandbox.stub(element.$.restAPI, 'getMergeable')
2290 .returns(Promise.resolve({mergeable: true}));
2291 });
2292
2293 test('merged change', () => {
2294 element._mergeable = null;
Dmitrii Filippov4e4522e2020-05-06 12:50:49 +02002295 element._change.status = ChangeStatus.MERGED;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002296 return element._getMergeability().then(() => {
2297 assert.isFalse(element._mergeable);
2298 assert.isFalse(getMergeableStub.called);
2299 });
2300 });
2301
2302 test('abandoned change', () => {
2303 element._mergeable = null;
Dmitrii Filippov4e4522e2020-05-06 12:50:49 +02002304 element._change.status = ChangeStatus.ABANDONED;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002305 return element._getMergeability().then(() => {
2306 assert.isFalse(element._mergeable);
2307 assert.isFalse(getMergeableStub.called);
2308 });
2309 });
2310
2311 test('open change', () => {
2312 element._mergeable = null;
2313 return element._getMergeability().then(() => {
2314 assert.isTrue(element._mergeable);
2315 assert.isTrue(getMergeableStub.called);
2316 });
2317 });
2318 });
2319
2320 test('_paramsChanged sets in projectLookup', () => {
2321 sandbox.stub(element.$.relatedChanges, 'reload');
2322 sandbox.stub(element, '_reload').returns(Promise.resolve());
2323 const setStub = sandbox.stub(element.$.restAPI, 'setInProjectLookup');
2324 element._paramsChanged({
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02002325 view: GerritNav.View.CHANGE,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002326 changeNum: 101,
2327 project: 'test-project',
2328 });
2329 assert.isTrue(setStub.calledOnce);
2330 assert.isTrue(setStub.calledWith(101, 'test-project'));
2331 });
2332
2333 test('_handleToggleStar called when star is tapped', () => {
2334 element._change = {
2335 owner: {_account_id: 1},
2336 starred: false,
2337 };
2338 element._loggedIn = true;
2339 const stub = sandbox.stub(element, '_handleToggleStar');
2340 flushAsynchronousOperations();
2341
2342 MockInteractions.tap(element.$.changeStar.shadowRoot
2343 .querySelector('button'));
2344 assert.isTrue(stub.called);
2345 });
2346
2347 suite('gr-reporting tests', () => {
2348 setup(() => {
2349 element._patchRange = {
2350 basePatchNum: 'PARENT',
2351 patchNum: 1,
2352 };
2353 sandbox.stub(element, '_getChangeDetail').returns(Promise.resolve());
2354 sandbox.stub(element, '_getProjectConfig').returns(Promise.resolve());
2355 sandbox.stub(element, '_reloadComments').returns(Promise.resolve());
2356 sandbox.stub(element, '_getMergeability').returns(Promise.resolve());
2357 sandbox.stub(element, '_getLatestCommitMessage')
2358 .returns(Promise.resolve());
2359 });
2360
2361 test('don\'t report changedDisplayed on reply', done => {
2362 const changeDisplayStub =
Milutin Kristoficda88b332020-03-24 10:19:12 +01002363 sandbox.stub(element.reporting, 'changeDisplayed');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002364 const changeFullyLoadedStub =
Milutin Kristoficda88b332020-03-24 10:19:12 +01002365 sandbox.stub(element.reporting, 'changeFullyLoaded');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002366 element._handleReplySent();
2367 flush(() => {
2368 assert.isFalse(changeDisplayStub.called);
2369 assert.isFalse(changeFullyLoadedStub.called);
2370 done();
2371 });
2372 });
2373
2374 test('report changedDisplayed on _paramsChanged', done => {
2375 const changeDisplayStub =
Milutin Kristoficda88b332020-03-24 10:19:12 +01002376 sandbox.stub(element.reporting, 'changeDisplayed');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002377 const changeFullyLoadedStub =
Milutin Kristoficda88b332020-03-24 10:19:12 +01002378 sandbox.stub(element.reporting, 'changeFullyLoaded');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002379 element._paramsChanged({
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02002380 view: GerritNav.View.CHANGE,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002381 changeNum: 101,
2382 project: 'test-project',
2383 });
2384 flush(() => {
2385 assert.isTrue(changeDisplayStub.called);
2386 assert.isTrue(changeFullyLoadedStub.called);
2387 done();
2388 });
2389 });
2390 });
2391});