blob: 893d6286839ba1039bde92ad64d60180e1d0bb3e [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 Filippov78448cd2020-10-26 17:39:11 +010018import '../../../test/common-test-setup-karma';
19import '../../edit/gr-edit-constants';
20import './gr-change-view';
Dmitrii Filippov0695d402020-10-22 16:57:57 +020021import {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +010022 ChangeStatus,
23 CommentSide,
24 DefaultBase,
25 DiffViewMode,
26 HttpMethod,
27 PrimaryTab,
28 SecondaryTab,
29} from '../../../constants/constants';
30import {GrEditConstants} from '../../edit/gr-edit-constants';
31import {_testOnly_resetEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints';
32import {getComputedStyleValue} from '../../../utils/dom-util';
Ben Rohlfsebe4acc2020-12-11 21:16:10 +010033import {GerritNav} from '../../core/gr-navigation/gr-navigation';
Dmitrii Filippov78448cd2020-10-26 17:39:11 +010034import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
35import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit';
36import {EventType, PluginApi} from '../../plugins/gr-plugin-types';
37
38import 'lodash/lodash';
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +010039import {
40 stubRestApi,
41 TestKeyboardShortcutBinder,
42} from '../../../test/test-utils';
Dmitrii Filippov78448cd2020-10-26 17:39:11 +010043import {SPECIAL_PATCH_SET_NUM} from '../../../utils/patch-set-util';
44import {Shortcut} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
45import {
46 createAppElementChangeViewParams,
47 createApproval,
Dmitrii Filippov0695d402020-10-22 16:57:57 +020048 createChange,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +010049 createChangeConfig,
Dmitrii Filippov0695d402020-10-22 16:57:57 +020050 createChangeMessages,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +010051 createCommit,
52 createMergeable,
53 createPreferences,
54 createRevision,
Dmitrii Filippov0695d402020-10-22 16:57:57 +020055 createRevisions,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +010056 createServerInfo,
57 createUserConfig,
58 TEST_NUMERIC_CHANGE_ID,
59 TEST_PROJECT_NAME,
60 getCurrentRevision,
61 createEditRevision,
62 createAccountWithIdNameAndEmail,
63} from '../../../test/test-data-generators';
64import {ChangeViewPatchRange, GrChangeView} from './gr-change-view';
65import {
66 AccountId,
67 ApprovalInfo,
68 ChangeId,
69 ChangeInfo,
70 CommitId,
71 CommitInfo,
72 EditInfo,
73 EditPatchSetNum,
74 ElementPropertyDeepChange,
75 GitRef,
76 NumericChangeId,
77 ParentPatchSetNum,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +010078 PatchRange,
79 PatchSetNum,
80 RevisionInfo,
81 RobotId,
82 Timestamp,
83 UrlEncodedCommentId,
84} from '../../../types/common';
85import {
86 pressAndReleaseKeyOn,
87 tap,
88} from '@polymer/iron-test-helpers/mock-interactions';
89import {GrEditControls} from '../../edit/gr-edit-controls/gr-edit-controls';
90import {AppElementChangeViewParams} from '../../gr-app-types';
91import {
92 SinonFakeTimers,
93 SinonSpy,
94 SinonStubbedMember,
95} from 'sinon/pkg/sinon-esm';
Ben Rohlfsa9d2cff2021-01-22 21:33:58 +010096import {RestApiService} from '../../../services/gr-rest-api/gr-rest-api';
Dmitrii Filippov78448cd2020-10-26 17:39:11 +010097import {CustomKeyboardEvent} from '../../../types/events';
98import {
99 CommentThread,
100 DraftInfo,
101 UIDraft,
102 UIRobot,
103} from '../../../utils/comment-util';
104import 'lodash/lodash';
105import {ParsedChangeInfo} from '../../shared/gr-rest-api-interface/gr-reviewer-updates-parser';
106import {ChangeComments} from '../../diff/gr-comment-api/gr-comment-api';
Ben Rohlfsebe4acc2020-12-11 21:16:10 +0100107import {GerritView} from '../../../services/router/router-model';
Dmitrii Filippovacd39a22020-04-02 10:31:43 +0200108
Dmitrii Filippov5f25dc02020-04-07 18:49:00 +0200109const pluginApi = _testOnly_initGerritPluginApi();
Dmitrii Filippovacd39a22020-04-02 10:31:43 +0200110const fixture = fixtureFromElement('gr-change-view');
Dmitrii Filippov0028b582020-03-24 11:58:55 +0100111
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100112type SinonSpyMember<F extends (...args: any) => any> = SinonSpy<
113 Parameters<F>,
114 ReturnType<F>
115>;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200116
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100117suite('gr-change-view tests', () => {
118 let element: GrChangeView;
119
120 let navigateToChangeStub: SinonStubbedMember<typeof GerritNav.navigateToChange>;
Dmitrii Filippov06117e82020-06-25 13:26:55 +0200121
122 suiteSetup(() => {
123 const kb = TestKeyboardShortcutBinder.push();
Dmitrii Filippov2dd0a442020-07-11 16:37:25 +0200124 kb.bindShortcut(Shortcut.SEND_REPLY, 'ctrl+enter');
125 kb.bindShortcut(Shortcut.REFRESH_CHANGE, 'shift+r');
126 kb.bindShortcut(Shortcut.OPEN_REPLY_DIALOG, 'a');
127 kb.bindShortcut(Shortcut.OPEN_DOWNLOAD_DIALOG, 'd');
128 kb.bindShortcut(Shortcut.TOGGLE_DIFF_MODE, 'm');
129 kb.bindShortcut(Shortcut.TOGGLE_CHANGE_STAR, 's');
130 kb.bindShortcut(Shortcut.UP_TO_DASHBOARD, 'u');
131 kb.bindShortcut(Shortcut.EXPAND_ALL_MESSAGES, 'x');
132 kb.bindShortcut(Shortcut.COLLAPSE_ALL_MESSAGES, 'z');
133 kb.bindShortcut(Shortcut.OPEN_DIFF_PREFS, ',');
134 kb.bindShortcut(Shortcut.EDIT_TOPIC, 't');
Dmitrii Filippov06117e82020-06-25 13:26:55 +0200135 });
136
137 suiteTeardown(() => {
138 TestKeyboardShortcutBinder.pop();
139 });
140
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100141 const TEST_SCROLL_TOP_PX = 100;
Andrew Bonventre547b8ab2015-12-01 01:02:00 -0500142
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100143 const ROBOT_COMMENTS_LIMIT = 10;
144
Tao Zhou18738b92020-05-04 19:44:51 +0200145 // TODO: should have a mock service to generate VALID fake data
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100146 const THREADS: CommentThread[] = [
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100147 {
148 comments: [
149 {
Dhruv Srivastava3dfaf362020-12-01 21:53:59 +0100150 path: '/COMMIT_MSG',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100151 author: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100152 _account_id: 1000000 as AccountId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100153 name: 'user',
154 username: 'user',
155 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100156 patch_set: 2 as PatchSetNum,
157 robot_id: 'rb1' as RobotId,
158 id: 'ecf0b9fa_fe1a5f62' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100159 line: 5,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100160 updated: '2018-02-08 18:49:18.000000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100161 message: 'test',
162 unresolved: true,
163 },
164 {
Dhruv Srivastava3dfaf362020-12-01 21:53:59 +0100165 path: '/COMMIT_MSG',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100166 author: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100167 _account_id: 1000000 as AccountId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100168 name: 'user',
169 username: 'user',
170 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100171 patch_set: 4 as PatchSetNum,
172 id: 'ecf0b9fa_fe1a5f62_1' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100173 line: 5,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100174 updated: '2018-02-08 18:49:18.000000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100175 message: 'test',
176 unresolved: true,
177 },
178 {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100179 id: '503008e2_0ab203ee' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100180 path: '/COMMIT_MSG',
181 line: 5,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100182 in_reply_to: 'ecf0b9fa_fe1a5f62' as UrlEncodedCommentId,
183 updated: '2018-02-13 22:48:48.018000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100184 message: 'draft',
185 unresolved: false,
186 __draft: true,
187 __draftID: '0.m683trwff68',
188 __editing: false,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100189 patch_set: 2 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100190 },
191 ],
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100192 patchNum: 4 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100193 path: '/COMMIT_MSG',
194 line: 5,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100195 rootId: 'ecf0b9fa_fe1a5f62' as UrlEncodedCommentId,
Dhruv Srivastava794db3a2020-11-11 11:28:08 +0100196 commentSide: CommentSide.REVISION,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100197 },
198 {
199 comments: [
200 {
Dhruv Srivastava3dfaf362020-12-01 21:53:59 +0100201 path: '/COMMIT_MSG',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100202 author: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100203 _account_id: 1000000 as AccountId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100204 name: 'user',
205 username: 'user',
206 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100207 patch_set: 3 as PatchSetNum,
208 id: 'ecf0b9fa_fe5f62' as UrlEncodedCommentId,
209 robot_id: 'rb2' as RobotId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100210 line: 5,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100211 updated: '2018-02-08 18:49:18.000000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100212 message: 'test',
213 unresolved: true,
214 },
215 {
Dhruv Srivastava3dfaf362020-12-01 21:53:59 +0100216 path: 'test.txt',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100217 author: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100218 _account_id: 1000000 as AccountId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100219 name: 'user',
220 username: 'user',
221 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100222 patch_set: 3 as PatchSetNum,
223 id: '09a9fb0a_1484e6cf' as UrlEncodedCommentId,
224 side: CommentSide.PARENT,
225 updated: '2018-02-13 22:47:19.000000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100226 message: 'Some comment on another patchset.',
227 unresolved: false,
228 },
229 ],
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100230 patchNum: 3 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100231 path: 'test.txt',
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100232 rootId: '09a9fb0a_1484e6cf' as UrlEncodedCommentId,
233 commentSide: CommentSide.PARENT,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100234 },
235 {
236 comments: [
237 {
Dhruv Srivastava3dfaf362020-12-01 21:53:59 +0100238 path: '/COMMIT_MSG',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100239 author: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100240 _account_id: 1000000 as AccountId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100241 name: 'user',
242 username: 'user',
243 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100244 patch_set: 2 as PatchSetNum,
245 id: '8caddf38_44770ec1' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100246 line: 4,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100247 updated: '2018-02-13 22:48:40.000000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100248 message: 'Another unresolved comment',
249 unresolved: true,
250 },
251 ],
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100252 patchNum: 2 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100253 path: '/COMMIT_MSG',
254 line: 4,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100255 rootId: '8caddf38_44770ec1' as UrlEncodedCommentId,
Dhruv Srivastava794db3a2020-11-11 11:28:08 +0100256 commentSide: CommentSide.REVISION,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100257 },
258 {
259 comments: [
260 {
Dhruv Srivastava3dfaf362020-12-01 21:53:59 +0100261 path: '/COMMIT_MSG',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100262 author: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100263 _account_id: 1000000 as AccountId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100264 name: 'user',
265 username: 'user',
266 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100267 patch_set: 2 as PatchSetNum,
268 id: 'scaddf38_44770ec1' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100269 line: 4,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100270 updated: '2018-02-14 22:48:40.000000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100271 message: 'Yet another unresolved comment',
272 unresolved: true,
273 },
274 ],
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100275 patchNum: 2 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100276 path: '/COMMIT_MSG',
277 line: 4,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100278 rootId: 'scaddf38_44770ec1' as UrlEncodedCommentId,
Dhruv Srivastava794db3a2020-11-11 11:28:08 +0100279 commentSide: CommentSide.REVISION,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100280 },
281 {
282 comments: [
283 {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100284 id: 'zcf0b9fa_fe1a5f62' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100285 path: '/COMMIT_MSG',
286 line: 6,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100287 updated: '2018-02-15 22:48:48.018000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100288 message: 'resolved draft',
289 unresolved: false,
290 __draft: true,
291 __draftID: '0.m683trwff68',
292 __editing: false,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100293 patch_set: 2 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100294 },
295 ],
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100296 patchNum: 4 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100297 path: '/COMMIT_MSG',
298 line: 6,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100299 rootId: 'zcf0b9fa_fe1a5f62' as UrlEncodedCommentId,
Dhruv Srivastava794db3a2020-11-11 11:28:08 +0100300 commentSide: CommentSide.REVISION,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100301 },
302 {
303 comments: [
304 {
Dhruv Srivastava3dfaf362020-12-01 21:53:59 +0100305 path: '/COMMIT_MSG',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100306 author: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100307 _account_id: 1000000 as AccountId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100308 name: 'user',
309 username: 'user',
310 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100311 patch_set: 4 as PatchSetNum,
312 id: 'rc1' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100313 line: 5,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100314 updated: '2019-02-08 18:49:18.000000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100315 message: 'test',
316 unresolved: true,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100317 robot_id: 'rc1' as RobotId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100318 },
319 ],
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100320 patchNum: 4 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100321 path: '/COMMIT_MSG',
322 line: 5,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100323 rootId: 'rc1' as UrlEncodedCommentId,
Dhruv Srivastava794db3a2020-11-11 11:28:08 +0100324 commentSide: CommentSide.REVISION,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100325 },
326 {
327 comments: [
328 {
Dhruv Srivastava3dfaf362020-12-01 21:53:59 +0100329 path: '/COMMIT_MSG',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100330 author: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100331 _account_id: 1000000 as AccountId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100332 name: 'user',
333 username: 'user',
334 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100335 patch_set: 4 as PatchSetNum,
336 id: 'rc2' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100337 line: 5,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100338 updated: '2019-03-08 18:49:18.000000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100339 message: 'test',
340 unresolved: true,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100341 robot_id: 'rc2' as RobotId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100342 },
343 {
Dhruv Srivastava3dfaf362020-12-01 21:53:59 +0100344 path: '/COMMIT_MSG',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100345 author: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100346 _account_id: 1000000 as AccountId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100347 name: 'user',
348 username: 'user',
349 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100350 patch_set: 4 as PatchSetNum,
351 id: 'c2_1' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100352 line: 5,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100353 updated: '2019-03-08 18:49:18.000000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100354 message: 'test',
355 unresolved: true,
356 },
357 ],
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100358 patchNum: 4 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100359 path: '/COMMIT_MSG',
360 line: 5,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100361 rootId: 'rc2' as UrlEncodedCommentId,
Dhruv Srivastava794db3a2020-11-11 11:28:08 +0100362 commentSide: CommentSide.REVISION,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100363 },
364 ];
365
366 setup(() => {
Dmitrii Filippovf97fc6e2020-04-07 09:59:22 +0200367 // Since pluginEndpoints are global, must reset state.
368 _testOnly_resetEndpoints();
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200369 navigateToChangeStub = sinon.stub(GerritNav, 'navigateToChange');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100370
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +0100371 stubRestApi('getConfig').returns(
372 Promise.resolve({
373 ...createServerInfo(),
374 user: {
375 ...createUserConfig(),
376 anonymous_coward_name: 'test coward name',
377 },
378 })
379 );
380 stubRestApi('getAccount').returns(Promise.resolve(undefined));
381 stubRestApi('getDiffComments').returns(Promise.resolve({}));
382 stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
383 stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
Dmitrii Filippovacd39a22020-04-02 10:31:43 +0200384 element = fixture.instantiate();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100385 element._changeNum = 1 as NumericChangeId;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200386 sinon.stub(element.$.actions, 'reload').returns(Promise.resolve());
Dhruv Srivastava12e2c992020-09-01 16:40:21 +0200387 getPluginLoader().loadPlugins([]);
Dmitrii Filippov5f25dc02020-04-07 18:49:00 +0200388 pluginApi.install(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100389 plugin => {
390 plugin.registerDynamicCustomComponent(
391 'change-view-tab-header',
392 'gr-checks-change-view-tab-header-view'
393 );
394 plugin.registerDynamicCustomComponent(
395 'change-view-tab-content',
396 'gr-checks-view'
397 );
398 },
399 '0.1',
400 'http://some/plugins/url.html'
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100401 );
402 });
403
404 teardown(done => {
405 flush(() => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100406 done();
407 });
408 });
409
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100410 const getCustomCssValue = (cssParam: string) =>
411 getComputedStyleValue(cssParam, element);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100412
Dhruv Srivastava163de6f2020-06-04 09:40:28 +0000413 test('_handleMessageAnchorTap', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100414 element._changeNum = 1 as NumericChangeId;
Dhruv Srivastava163de6f2020-06-04 09:40:28 +0000415 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100416 basePatchNum: ParentPatchSetNum,
417 patchNum: 1 as PatchSetNum,
Dhruv Srivastava163de6f2020-06-04 09:40:28 +0000418 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100419 element._change = createChange();
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200420 const getUrlStub = sinon.stub(GerritNav, 'getUrlForChange');
421 const replaceStateStub = sinon.stub(history, 'replaceState');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100422 element._handleMessageAnchorTap(
423 new CustomEvent('message-anchor-tap', {detail: {id: 'a12345'}})
424 );
Dhruv Srivastava163de6f2020-06-04 09:40:28 +0000425
426 assert.equal(getUrlStub.lastCall.args[4], '#message-a12345');
427 assert.isTrue(replaceStateStub.called);
428 });
429
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200430 test('_handleDiffAgainstBase', () => {
Dmitrii Filippov0695d402020-10-22 16:57:57 +0200431 element._change = {
432 ...createChange(),
433 revisions: createRevisions(10),
434 };
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200435 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100436 patchNum: 3 as PatchSetNum,
437 basePatchNum: 1 as PatchSetNum,
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200438 };
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200439 sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100440 element._handleDiffAgainstBase(new CustomEvent('') as CustomKeyboardEvent);
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200441 assert(navigateToChangeStub.called);
442 const args = navigateToChangeStub.getCall(0).args;
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +0200443 assert.equal(args[0], element._change);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100444 assert.equal(args[1], 3 as PatchSetNum);
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200445 });
446
447 test('_handleDiffAgainstLatest', () => {
Dmitrii Filippov0695d402020-10-22 16:57:57 +0200448 element._change = {
449 ...createChange(),
450 revisions: createRevisions(10),
451 };
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200452 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100453 basePatchNum: 1 as PatchSetNum,
454 patchNum: 3 as PatchSetNum,
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200455 };
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200456 sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100457 element._handleDiffAgainstLatest(
458 new CustomEvent('') as CustomKeyboardEvent
459 );
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200460 assert(navigateToChangeStub.called);
461 const args = navigateToChangeStub.getCall(0).args;
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +0200462 assert.equal(args[0], element._change);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100463 assert.equal(args[1], 10 as PatchSetNum);
464 assert.equal(args[2], 1 as PatchSetNum);
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200465 });
466
467 test('_handleDiffBaseAgainstLeft', () => {
Dmitrii Filippov0695d402020-10-22 16:57:57 +0200468 element._change = {
469 ...createChange(),
470 revisions: createRevisions(10),
471 };
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200472 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100473 patchNum: 3 as PatchSetNum,
474 basePatchNum: 1 as PatchSetNum,
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200475 };
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200476 sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100477 element._handleDiffBaseAgainstLeft(
478 new CustomEvent('') as CustomKeyboardEvent
479 );
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200480 assert(navigateToChangeStub.called);
481 const args = navigateToChangeStub.getCall(0).args;
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +0200482 assert.equal(args[0], element._change);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100483 assert.equal(args[1], 1 as PatchSetNum);
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200484 });
485
486 test('_handleDiffRightAgainstLatest', () => {
Dmitrii Filippov0695d402020-10-22 16:57:57 +0200487 element._change = {
488 ...createChange(),
489 revisions: createRevisions(10),
490 };
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200491 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100492 basePatchNum: 1 as PatchSetNum,
493 patchNum: 3 as PatchSetNum,
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200494 };
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200495 sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100496 element._handleDiffRightAgainstLatest(
497 new CustomEvent('') as CustomKeyboardEvent
498 );
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200499 assert(navigateToChangeStub.called);
500 const args = navigateToChangeStub.getCall(0).args;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100501 assert.equal(args[1], 10 as PatchSetNum);
502 assert.equal(args[2], 3 as PatchSetNum);
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200503 });
504
505 test('_handleDiffBaseAgainstLatest', () => {
Dmitrii Filippov0695d402020-10-22 16:57:57 +0200506 element._change = {
507 ...createChange(),
508 revisions: createRevisions(10),
509 };
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200510 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100511 basePatchNum: 1 as PatchSetNum,
512 patchNum: 3 as PatchSetNum,
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200513 };
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200514 sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100515 element._handleDiffBaseAgainstLatest(
516 new CustomEvent('') as CustomKeyboardEvent
517 );
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200518 assert(navigateToChangeStub.called);
519 const args = navigateToChangeStub.getCall(0).args;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100520 assert.equal(args[1], 10 as PatchSetNum);
Dhruv Srivastava4757b352020-06-12 15:41:42 +0200521 assert.isNotOk(args[2]);
522 });
523
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100524 suite('plugins adding to file tab', () => {
525 setup(done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100526 element._changeNum = 1 as NumericChangeId;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100527 // Resolving it here instead of during setup() as other tests depend
528 // on flush() not being called during setup.
529 flush(() => done());
Andrew Bonventre547b8ab2015-12-01 01:02:00 -0500530 });
531
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100532 test('plugin added tab shows up as a dynamic endpoint', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100533 assert(
534 element._dynamicTabHeaderEndpoints.includes(
535 'change-view-tab-header-url'
536 )
537 );
538 const primaryTabs = element.shadowRoot!.querySelector('#primaryTabs')!;
539 const paperTabs = primaryTabs.querySelectorAll<HTMLElement>('paper-tab');
Dhruv Srivastava929af7f2020-05-13 19:10:05 +0200540 // 4 Tabs are : Files, Comment Threads, Plugin, Findings
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100541 assert.equal(primaryTabs.querySelectorAll('paper-tab').length, 4);
542 assert.equal(paperTabs[2].dataset.name, 'change-view-tab-header-url');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100543 });
544
Tao Zhou4fd32d52020-04-06 17:23:10 +0200545 test('_setActivePrimaryTab switched tab correctly', done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100546 element._setActivePrimaryTab(
547 new CustomEvent('', {
548 detail: {tab: 'change-view-tab-header-url'},
549 })
550 );
Becky Siegelba3f5892017-05-12 12:28:13 -0700551 flush(() => {
Tao Zhou4fd32d52020-04-06 17:23:10 +0200552 assert.equal(element._activeTabs[0], 'change-view-tab-header-url');
553 done();
554 });
555 });
556
557 test('show-primary-tab switched primary tab correctly', done => {
Paladox none6b055dc2020-06-28 14:53:18 +0000558 element.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100559 new CustomEvent('show-primary-tab', {
560 composed: true,
561 bubbles: true,
562 detail: {
563 tab: 'change-view-tab-header-url',
564 },
565 })
566 );
Tao Zhou4fd32d52020-04-06 17:23:10 +0200567 flush(() => {
568 assert.equal(element._activeTabs[0], 'change-view-tab-header-url');
569 done();
570 });
571 });
572
573 test('param change should switch primary tab correctly', done => {
Dmitrii Filippove903bbf2020-05-06 12:57:39 +0200574 assert.equal(element._activeTabs[0], PrimaryTab.FILES);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100575 const queryMap = new Map<string, string>();
Dmitrii Filippove903bbf2020-05-06 12:57:39 +0200576 queryMap.set('tab', PrimaryTab.FINDINGS);
Tao Zhou4fd32d52020-04-06 17:23:10 +0200577 // view is required
Tao Zhou4cd35cb2020-07-22 11:28:22 +0200578 element.params = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100579 ...createAppElementChangeViewParams(),
580 ...element.params,
581 queryMap,
582 };
Tao Zhou4fd32d52020-04-06 17:23:10 +0200583 flush(() => {
Dmitrii Filippove903bbf2020-05-06 12:57:39 +0200584 assert.equal(element._activeTabs[0], PrimaryTab.FINDINGS);
Tao Zhou4fd32d52020-04-06 17:23:10 +0200585 done();
586 });
587 });
588
589 test('invalid param change should not switch primary tab', done => {
Dmitrii Filippove903bbf2020-05-06 12:57:39 +0200590 assert.equal(element._activeTabs[0], PrimaryTab.FILES);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100591 const queryMap = new Map<string, string>();
Tao Zhou4fd32d52020-04-06 17:23:10 +0200592 queryMap.set('tab', 'random');
593 // view is required
Tao Zhou4cd35cb2020-07-22 11:28:22 +0200594 element.params = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100595 ...createAppElementChangeViewParams(),
596 ...element.params,
597 queryMap,
598 };
Tao Zhou4fd32d52020-04-06 17:23:10 +0200599 flush(() => {
Dmitrii Filippove903bbf2020-05-06 12:57:39 +0200600 assert.equal(element._activeTabs[0], PrimaryTab.FILES);
Viktar Donich29e1ce52017-03-28 17:02:44 -0700601 done();
602 });
Kasper Nilssonf0743732016-10-18 13:01:10 -0700603 });
604
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100605 test('switching tab sets _selectedTabPluginEndpoint', done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100606 const paperTabs = element.shadowRoot!.querySelector('#primaryTabs')!;
607 tap(paperTabs.querySelectorAll('paper-tab')[2]);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100608 flush(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100609 assert.equal(
610 element._selectedTabPluginEndpoint,
611 'change-view-tab-content-url'
612 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100613 done();
614 });
615 });
616 });
Paladox none7acb7ac2017-11-09 18:06:18 +0000617
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100618 suite('keyboard shortcuts', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100619 let clock: SinonFakeTimers;
Dhruv Srivastava4caf0842020-09-18 11:50:33 +0200620 setup(() => {
621 clock = sinon.useFakeTimers();
622 });
623
624 teardown(() => {
625 clock.restore();
626 sinon.restore();
627 });
628
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100629 test('t to add topic', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200630 const editStub = sinon.stub(element.$.metadata, 'editTopic');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100631 pressAndReleaseKeyOn(element, 83, null, 't');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100632 assert(editStub.called);
633 });
634
635 test('S should toggle the CL star', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200636 const starStub = sinon.stub(element.$.changeStar, 'toggleStar');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100637 pressAndReleaseKeyOn(element, 83, null, 's');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100638 assert(starStub.called);
639 });
640
Dhruv Srivastava4caf0842020-09-18 11:50:33 +0200641 test('toggle star is throttled', () => {
642 const starStub = sinon.stub(element.$.changeStar, 'toggleStar');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100643 pressAndReleaseKeyOn(element, 83, null, 's');
Dhruv Srivastava4caf0842020-09-18 11:50:33 +0200644 assert(starStub.called);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100645 pressAndReleaseKeyOn(element, 83, null, 's');
Dhruv Srivastava4caf0842020-09-18 11:50:33 +0200646 assert.equal(starStub.callCount, 1);
647 clock.tick(1000);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100648 pressAndReleaseKeyOn(element, 83, null, 's');
Dhruv Srivastava4caf0842020-09-18 11:50:33 +0200649 assert.equal(starStub.callCount, 2);
650 });
651
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100652 test('U should navigate to root if no backPage set', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100653 const relativeNavStub = sinon.stub(GerritNav, 'navigateToRelativeUrl');
654 pressAndReleaseKeyOn(element, 85, null, 'u');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100655 assert.isTrue(relativeNavStub.called);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100656 assert.isTrue(
657 relativeNavStub.lastCall.calledWithExactly(GerritNav.getUrlForRoot())
658 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100659 });
660
661 test('U should navigate to backPage if set', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100662 const relativeNavStub = sinon.stub(GerritNav, 'navigateToRelativeUrl');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100663 element.backPage = '/dashboard/self';
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100664 pressAndReleaseKeyOn(element, 85, null, 'u');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100665 assert.isTrue(relativeNavStub.called);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100666 assert.isTrue(
667 relativeNavStub.lastCall.calledWithExactly('/dashboard/self')
668 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100669 });
670
671 test('A fires an error event when not logged in', done => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200672 sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(false));
673 const loggedInErrorSpy = sinon.spy();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100674 element.addEventListener('show-auth-required', loggedInErrorSpy);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100675 pressAndReleaseKeyOn(element, 65, null, 'a');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100676 flush(() => {
677 assert.isFalse(element.$.replyOverlay.opened);
678 assert.isTrue(loggedInErrorSpy.called);
679 done();
680 });
681 });
682
683 test('shift A does not open reply overlay', done => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200684 sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100685 pressAndReleaseKeyOn(element, 65, 'shift', 'a');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100686 flush(() => {
687 assert.isFalse(element.$.replyOverlay.opened);
688 done();
689 });
690 });
691
692 test('A toggles overlay when logged in', done => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200693 sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
Dmitrii Filippov0695d402020-10-22 16:57:57 +0200694 element._change = {
695 ...createChange(),
696 revisions: createRevisions(1),
697 messages: createChangeMessages(1),
698 };
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +0200699 element._change.labels = {};
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +0100700 stubRestApi('getChangeDetail').callsFake(() =>
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100701 Promise.resolve({
702 ...createChange(),
703 // element has latest info
704 revisions: createRevisions(1),
705 messages: createChangeMessages(1),
706 current_revision: 'rev1' as CommitId,
707 })
708 );
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +0200709
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200710 const openSpy = sinon.spy(element, '_openReplyDialog');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100711
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100712 pressAndReleaseKeyOn(element, 65, null, 'a');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100713 flush(() => {
714 assert.isTrue(element.$.replyOverlay.opened);
715 element.$.replyOverlay.close();
716 assert.isFalse(element.$.replyOverlay.opened);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100717 assert(
718 openSpy.lastCall.calledWithExactly(
719 element.$.replyDialog.FocusTarget.ANY
720 ),
721 '_openReplyDialog should have been passed ANY'
722 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100723 assert.equal(openSpy.callCount, 1);
724 done();
725 });
726 });
727
728 test('fullscreen-overlay-opened hides content', () => {
729 element._loggedIn = true;
730 element._loading = false;
731 element._change = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100732 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100733 labels: {},
734 actions: {
735 abandon: {
736 enabled: true,
737 label: 'Abandon',
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100738 method: HttpMethod.POST,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100739 title: 'Abandon',
740 },
741 },
742 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100743 const handlerSpy = sinon.spy(element, '_handleHideBackgroundContent');
Tao Zhou0a3c9862020-04-08 14:45:37 +0200744 element.$.replyDialog.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100745 new CustomEvent('fullscreen-overlay-opened', {
746 composed: true,
747 bubbles: true,
748 })
749 );
750 assert.isTrue(handlerSpy.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100751 assert.isTrue(element.$.mainContent.classList.contains('overlayOpen'));
752 assert.equal(getComputedStyle(element.$.actions).display, 'flex');
753 });
754
755 test('fullscreen-overlay-closed shows content', () => {
756 element._loggedIn = true;
757 element._loading = false;
758 element._change = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100759 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100760 labels: {},
761 actions: {
762 abandon: {
763 enabled: true,
764 label: 'Abandon',
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100765 method: HttpMethod.POST,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100766 title: 'Abandon',
767 },
768 },
769 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100770 const handlerSpy = sinon.spy(element, '_handleShowBackgroundContent');
Tao Zhou0a3c9862020-04-08 14:45:37 +0200771 element.$.replyDialog.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100772 new CustomEvent('fullscreen-overlay-closed', {
773 composed: true,
774 bubbles: true,
775 })
776 );
777 assert.isTrue(handlerSpy.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100778 assert.isFalse(element.$.mainContent.classList.contains('overlayOpen'));
779 });
780
781 test('expand all messages when expand-diffs fired', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100782 const handleExpand = sinon.stub(element.$.fileList, 'expandAllDiffs');
Tao Zhou0a3c9862020-04-08 14:45:37 +0200783 element.$.fileListHeader.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100784 new CustomEvent('expand-diffs', {
785 composed: true,
786 bubbles: true,
787 })
788 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100789 assert.isTrue(handleExpand.called);
790 });
791
792 test('collapse all messages when collapse-diffs fired', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100793 const handleCollapse = sinon.stub(element.$.fileList, 'collapseAllDiffs');
Tao Zhou0a3c9862020-04-08 14:45:37 +0200794 element.$.fileListHeader.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100795 new CustomEvent('collapse-diffs', {
796 composed: true,
797 bubbles: true,
798 })
799 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100800 assert.isTrue(handleCollapse.called);
801 });
802
803 test('X should expand all messages', done => {
804 flush(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100805 const handleExpand = sinon.stub(
806 element.messagesList!,
807 'handleExpandCollapse'
808 );
809 pressAndReleaseKeyOn(element, 88, null, 'x');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100810 assert(handleExpand.calledWith(true));
811 done();
812 });
813 });
814
815 test('Z should collapse all messages', done => {
816 flush(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100817 const handleExpand = sinon.stub(
818 element.messagesList!,
819 'handleExpandCollapse'
820 );
821 pressAndReleaseKeyOn(element, 90, null, 'z');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100822 assert(handleExpand.calledWith(false));
823 done();
824 });
825 });
826
Dhruv Srivastava8449e772020-07-22 11:57:29 +0200827 test('reload event from reply dialog is processed', () => {
828 const handleReloadStub = sinon.stub(element, '_reload');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100829 element.$.replyDialog.dispatchEvent(
830 new CustomEvent('reload', {
831 detail: {clearPatchset: true},
832 bubbles: true,
833 composed: true,
834 })
835 );
Dhruv Srivastava8449e772020-07-22 11:57:29 +0200836 assert.isTrue(handleReloadStub.called);
837 });
838
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100839 test('shift + R should fetch and navigate to the latest patch set', done => {
840 element._changeNum = TEST_NUMERIC_CHANGE_ID;
841 element._patchRange = {
842 basePatchNum: ParentPatchSetNum,
843 patchNum: 1 as PatchSetNum,
844 };
845 element._change = {
846 ...createChange(),
847 revisions: {
848 rev1: createRevision(),
849 },
850 current_revision: 'rev1' as CommitId,
851 status: ChangeStatus.NEW,
852 labels: {},
853 actions: {},
854 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100855
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100856 const reloadChangeStub = sinon.stub(element, '_reload');
857 pressAndReleaseKeyOn(element, 82, 'shift', 'r');
858 flush(() => {
859 assert.isTrue(reloadChangeStub.called);
860 done();
861 });
862 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100863
864 test('d should open download overlay', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100865 const stub = sinon
866 .stub(element.$.downloadOverlay, 'open')
867 .returns(Promise.resolve());
868 pressAndReleaseKeyOn(element, 68, null, 'd');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100869 assert.isTrue(stub.called);
870 });
871
872 test(', should open diff preferences', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200873 const stub = sinon.stub(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100874 element.$.fileList.$.diffPreferencesDialog,
875 'open'
876 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100877 element._loggedIn = false;
878 element.disableDiffPrefs = true;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100879 pressAndReleaseKeyOn(element, 188, null, ',');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100880 assert.isFalse(stub.called);
881
882 element._loggedIn = true;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100883 pressAndReleaseKeyOn(element, 188, null, ',');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100884 assert.isFalse(stub.called);
885
886 element.disableDiffPrefs = false;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100887 pressAndReleaseKeyOn(element, 188, null, ',');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100888 assert.isTrue(stub.called);
889 });
890
891 test('m should toggle diff mode', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200892 sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100893 const setModeStub = sinon.stub(
894 element.$.fileListHeader,
895 'setDiffViewMode'
896 );
897 const e = {preventDefault: () => {}} as CustomKeyboardEvent;
Ben Rohlfsd47eeb92020-09-25 10:29:48 +0200898 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100899
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100900 element.viewState.diffMode = DiffViewMode.SIDE_BY_SIDE;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100901 element._handleToggleDiffMode(e);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100902 assert.isTrue(setModeStub.calledWith(DiffViewMode.UNIFIED));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100903
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100904 element.viewState.diffMode = DiffViewMode.UNIFIED;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100905 element._handleToggleDiffMode(e);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100906 assert.isTrue(setModeStub.calledWith(DiffViewMode.SIDE_BY_SIDE));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100907 });
908 });
909
910 suite('reloading drafts', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100911 let reloadStub: SinonStubbedMember<typeof element.$.commentAPI.reloadDrafts>;
912 const drafts: {[path: string]: UIDraft[]} = {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100913 'testfile.txt': [
914 {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100915 patch_set: 5 as PatchSetNum,
916 id: 'dd2982f5_c01c9e6a' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100917 line: 1,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100918 updated: '2017-11-08 18:47:45.000000000' as Timestamp,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100919 message: 'test',
920 unresolved: true,
921 },
922 ],
923 };
924 setup(() => {
925 // Fake computeDraftCount as its required for ChangeComments,
926 // see gr-comment-api#reloadDrafts.
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100927 reloadStub = sinon.stub(element.$.commentAPI, 'reloadDrafts').returns(
928 Promise.resolve({
929 drafts,
930 getAllThreadsForChange: () => [] as CommentThread[],
931 computeDraftCount: () => 1,
932 } as ChangeComments)
933 );
934 element._changeNum = 1 as NumericChangeId;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100935 });
936
937 test('drafts are reloaded when reload-drafts fired', done => {
Tao Zhou0a3c9862020-04-08 14:45:37 +0200938 element.$.fileList.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100939 new CustomEvent('reload-drafts', {
940 detail: {
941 resolve: () => {
942 assert.isTrue(reloadStub.called);
943 assert.deepEqual(element._diffDrafts, drafts);
944 done();
Tao Zhou0a3c9862020-04-08 14:45:37 +0200945 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100946 },
947 composed: true,
948 bubbles: true,
949 })
950 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100951 });
952
953 test('drafts are reloaded when comment-refresh fired', () => {
Tao Zhou0a3c9862020-04-08 14:45:37 +0200954 element.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100955 new CustomEvent('comment-refresh', {
956 composed: true,
957 bubbles: true,
958 })
959 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100960 assert.isTrue(reloadStub.called);
961 });
962 });
963
Tao Zhou18738b92020-05-04 19:44:51 +0200964 suite('_recomputeComments', () => {
965 setup(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100966 element._changeNum = TEST_NUMERIC_CHANGE_ID;
967 element._change = createChange();
Ben Rohlfsd47eeb92020-09-25 10:29:48 +0200968 flush();
Tao Zhou18738b92020-05-04 19:44:51 +0200969 // Fake computeDraftCount as its required for ChangeComments,
970 // see gr-comment-api#reloadDrafts.
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100971 sinon.stub(element.$.commentAPI, 'reloadDrafts').returns(
972 Promise.resolve({
973 drafts: {},
974 getAllThreadsForChange: () => THREADS,
975 computeDraftCount: () => 0,
976 } as ChangeComments)
977 );
Dmitrii Filippov0695d402020-10-22 16:57:57 +0200978 element._change = createChange();
Ben Rohlfs739b1d22020-09-21 12:26:31 +0200979 element._changeNum = element._change._number;
Tao Zhou18738b92020-05-04 19:44:51 +0200980 });
981
982 test('draft threads should be a new copy with correct states', done => {
983 element.$.fileList.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +0100984 new CustomEvent('reload-drafts', {
985 detail: {
986 resolve: () => {
987 assert.equal(element._draftCommentThreads!.length, 2);
988 assert.equal(
989 element._draftCommentThreads![0].rootId,
990 THREADS[0].rootId
991 );
992 assert.notEqual(
993 element._draftCommentThreads![0].comments,
994 THREADS[0].comments
995 );
996 assert.notEqual(
997 element._draftCommentThreads![0].comments[0],
998 THREADS[0].comments[0]
999 );
1000 assert.isTrue(
1001 element
1002 ._draftCommentThreads![0].comments.slice(0, 2)
1003 .every(c => c.collapsed === true)
1004 );
Tao Zhou18738b92020-05-04 19:44:51 +02001005
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001006 assert.isTrue(
1007 element._draftCommentThreads![0].comments[2].collapsed === false
1008 );
1009 done();
Tao Zhou18738b92020-05-04 19:44:51 +02001010 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001011 },
1012 composed: true,
1013 bubbles: true,
1014 })
1015 );
Tao Zhou18738b92020-05-04 19:44:51 +02001016 });
1017 });
1018
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001019 test('diff comments modified', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001020 const reloadThreadsSpy = sinon.spy(element, '_handleReloadCommentThreads');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001021 return element._reloadComments().then(() => {
Tao Zhou0a3c9862020-04-08 14:45:37 +02001022 element.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001023 new CustomEvent('diff-comments-modified', {
1024 composed: true,
1025 bubbles: true,
1026 })
1027 );
1028 assert.isTrue(reloadThreadsSpy.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001029 });
1030 });
1031
1032 test('thread list modified', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001033 const reloadDiffSpy = sinon.spy(element, '_handleReloadDiffComments');
Dhruv Srivastava929af7f2020-05-13 19:10:05 +02001034 element._activeTabs = [PrimaryTab.COMMENT_THREADS, SecondaryTab.CHANGE_LOG];
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02001035 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001036
1037 return element._reloadComments().then(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001038 element.threadList!.dispatchEvent(
1039 new CustomEvent('thread-list-modified', {
1040 composed: true,
1041 bubbles: true,
1042 })
1043 );
1044 assert.isTrue(reloadDiffSpy.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001045
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001046 let draftStub = sinon
1047 .stub(element._changeComments!, 'computeDraftCount')
1048 .returns(1);
1049 assert.equal(
1050 element._computeTotalCommentCounts(5, element._changeComments!),
1051 '5 unresolved, 1 draft'
1052 );
1053 assert.equal(
1054 element._computeTotalCommentCounts(0, element._changeComments!),
1055 '1 draft'
1056 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001057 draftStub.restore();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001058 draftStub = sinon
1059 .stub(element._changeComments!, 'computeDraftCount')
1060 .returns(0);
1061 assert.equal(
1062 element._computeTotalCommentCounts(0, element._changeComments!),
1063 ''
1064 );
1065 assert.equal(
1066 element._computeTotalCommentCounts(1, element._changeComments!),
1067 '1 unresolved'
1068 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001069 draftStub.restore();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001070 draftStub = sinon
1071 .stub(element._changeComments!, 'computeDraftCount')
1072 .returns(2);
1073 assert.equal(
1074 element._computeTotalCommentCounts(1, element._changeComments!),
1075 '1 unresolved, 2 drafts'
1076 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001077 draftStub.restore();
1078 });
1079 });
1080
1081 suite('thread list and change log tabs', () => {
1082 setup(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001083 element._changeNum = TEST_NUMERIC_CHANGE_ID;
Kasper Nilsson9c1a3db2018-10-19 15:11:07 -07001084 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001085 basePatchNum: ParentPatchSetNum,
1086 patchNum: 1 as PatchSetNum,
Kasper Nilsson9c1a3db2018-10-19 15:11:07 -07001087 };
Becky Siegel9b03dd22017-10-26 14:57:32 -07001088 element._change = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001089 ...createChange(),
Becky Siegel9b03dd22017-10-26 14:57:32 -07001090 revisions: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001091 rev2: createRevision(2),
1092 rev1: createRevision(1),
1093 rev13: createRevision(13),
1094 rev3: createRevision(3),
Kasper Nilssonf0743732016-10-18 13:01:10 -07001095 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001096 current_revision: 'rev3' as CommitId,
1097 status: ChangeStatus.NEW,
Kasper Nilssonf0743732016-10-18 13:01:10 -07001098 labels: {
1099 test: {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001100 all: [],
Kasper Nilssonf0743732016-10-18 13:01:10 -07001101 default_value: 0,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001102 values: {},
Kasper Nilssonf0743732016-10-18 13:01:10 -07001103 approved: {},
1104 },
1105 },
1106 };
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001107 sinon.stub(element.$.relatedChanges, 'reload');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001108 sinon.stub(element, '_reload').returns(Promise.resolve([]));
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001109 sinon.spy(element, '_paramsChanged');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001110 element.params = createAppElementChangeViewParams();
Kasper Nilsson34a5d892018-04-11 11:10:53 -07001111 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001112 });
1113
1114 suite('Findings comment tab', () => {
1115 setup(done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001116 element._changeNum = TEST_NUMERIC_CHANGE_ID;
Kasper Nilssonbbd28672018-08-01 10:23:23 -07001117 element._change = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001118 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001119 revisions: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001120 rev2: createRevision(2),
1121 rev1: createRevision(1),
1122 rev13: createRevision(13),
1123 rev3: createRevision(3),
1124 rev4: createRevision(4),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001125 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001126 current_revision: 'rev4' as CommitId,
Kasper Nilssonbbd28672018-08-01 10:23:23 -07001127 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001128 element._commentThreads = THREADS;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001129 const paperTabs = element.shadowRoot!.querySelector('#primaryTabs')!;
1130 tap(paperTabs.querySelectorAll('paper-tab')[3]);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001131 flush(() => {
1132 done();
1133 });
Kasper Nilssonbbd28672018-08-01 10:23:23 -07001134 });
Milutin Kristofic7a86db12019-08-07 15:26:13 +02001135
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001136 test('robot comments count per patchset', () => {
1137 const count = element._robotCommentCountPerPatchSet(THREADS);
1138 const expectedCount = {
1139 2: 1,
1140 3: 1,
1141 4: 2,
1142 };
1143 assert.deepEqual(count, expectedCount);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001144 assert.equal(
1145 element._computeText(createRevision(2), THREADS),
1146 'Patchset 2 (1 finding)'
1147 );
1148 assert.equal(
1149 element._computeText(createRevision(4), THREADS),
1150 'Patchset 4 (2 findings)'
1151 );
1152 assert.equal(
1153 element._computeText(createRevision(5), THREADS),
1154 'Patchset 5'
1155 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001156 });
Milutin Kristofic7a86db12019-08-07 15:26:13 +02001157
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001158 test('only robot comments are rendered', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001159 assert.equal(element._robotCommentThreads!.length, 2);
1160 assert.equal(
1161 (element._robotCommentThreads![0].comments[0] as UIRobot).robot_id,
1162 'rc1'
1163 );
1164 assert.equal(
1165 (element._robotCommentThreads![1].comments[0] as UIRobot).robot_id,
1166 'rc2'
1167 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001168 });
1169
1170 test('changing patchsets resets robot comments', done => {
1171 element.set('_change.current_revision', 'rev3');
1172 flush(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001173 assert.equal(element._robotCommentThreads!.length, 1);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001174 done();
1175 });
1176 });
1177
1178 test('Show more button is hidden', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001179 assert.isNull(element.shadowRoot!.querySelector('.show-robot-comments'));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001180 });
1181
1182 suite('robot comments show more button', () => {
1183 setup(done => {
1184 const arr = [];
1185 for (let i = 0; i <= 30; i++) {
1186 arr.push(...THREADS);
1187 }
1188 element._commentThreads = arr;
Milutin Kristofic7a86db12019-08-07 15:26:13 +02001189 flush(() => {
Milutin Kristofic7a86db12019-08-07 15:26:13 +02001190 done();
1191 });
1192 });
1193
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001194 test('Show more button is rendered', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001195 assert.isOk(element.shadowRoot!.querySelector('.show-robot-comments'));
1196 assert.equal(
1197 element._robotCommentThreads!.length,
1198 ROBOT_COMMENTS_LIMIT
1199 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001200 });
1201
1202 test('Clicking show more button renders all comments', done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001203 tap(element.shadowRoot!.querySelector('.show-robot-comments')!);
Milutin Kristofic7a86db12019-08-07 15:26:13 +02001204 flush(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001205 assert.equal(element._robotCommentThreads!.length, 62);
Milutin Kristofic7a86db12019-08-07 15:26:13 +02001206 done();
1207 });
1208 });
1209 });
Andrew Bonventre547b8ab2015-12-01 01:02:00 -05001210 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001211
1212 test('reply button is not visible when logged out', () => {
1213 assert.equal(getComputedStyle(element.$.replyBtn).display, 'none');
1214 element._loggedIn = true;
1215 assert.notEqual(getComputedStyle(element.$.replyBtn).display, 'none');
1216 });
1217
1218 test('download tap calls _handleOpenDownloadDialog', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001219 const openDialogStub = sinon.stub(element, '_handleOpenDownloadDialog');
Tao Zhou0a3c9862020-04-08 14:45:37 +02001220 element.$.actions.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001221 new CustomEvent('download-tap', {
1222 composed: true,
1223 bubbles: true,
1224 })
1225 );
1226 assert.isTrue(openDialogStub.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001227 });
1228
1229 test('fetches the server config on attached', done => {
1230 flush(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001231 assert.equal(
1232 element._serverConfig!.user.anonymous_coward_name,
1233 'test coward name'
1234 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001235 done();
1236 });
1237 });
1238
1239 test('_changeStatuses', () => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001240 element._loading = false;
1241 element._change = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001242 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001243 revisions: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001244 rev2: createRevision(2),
1245 rev1: createRevision(1),
1246 rev13: createRevision(13),
1247 rev3: createRevision(3),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001248 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001249 current_revision: 'rev3' as CommitId,
Dmitrii Filippov3bf68892020-07-12 00:19:10 +02001250 status: ChangeStatus.MERGED,
1251 work_in_progress: true,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001252 labels: {
1253 test: {
1254 all: [],
1255 default_value: 0,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001256 values: {},
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001257 approved: {},
1258 },
1259 },
1260 };
1261 element._mergeable = true;
1262 const expectedStatuses = ['Merged', 'WIP'];
1263 assert.deepEqual(element._changeStatuses, expectedStatuses);
1264 assert.equal(element._changeStatus, expectedStatuses.join(', '));
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02001265 flush();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001266 const statusChips = element.shadowRoot!.querySelectorAll(
1267 'gr-change-status'
1268 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001269 assert.equal(statusChips.length, 2);
1270 });
1271
1272 test('diff preferences open when open-diff-prefs is fired', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001273 const overlayOpenStub = sinon.stub(element.$.fileList, 'openDiffPrefs');
Tao Zhou0a3c9862020-04-08 14:45:37 +02001274 element.$.fileListHeader.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001275 new CustomEvent('open-diff-prefs', {
1276 composed: true,
1277 bubbles: true,
1278 })
1279 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001280 assert.isTrue(overlayOpenStub.called);
1281 });
1282
1283 test('_prepareCommitMsgForLinkify', () => {
1284 let commitMessage = 'R=test@google.com';
1285 let result = element._prepareCommitMsgForLinkify(commitMessage);
1286 assert.equal(result, 'R=\u200Btest@google.com');
1287
1288 commitMessage = 'R=test@google.com\nR=test@google.com';
1289 result = element._prepareCommitMsgForLinkify(commitMessage);
1290 assert.equal(result, 'R=\u200Btest@google.com\nR=\u200Btest@google.com');
1291
1292 commitMessage = 'CC=test@google.com';
1293 result = element._prepareCommitMsgForLinkify(commitMessage);
1294 assert.equal(result, 'CC=\u200Btest@google.com');
David Ostrovskya2401c12020-05-03 19:29:26 +02001295 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001296
1297 test('_isSubmitEnabled', () => {
1298 assert.isFalse(element._isSubmitEnabled({}));
1299 assert.isFalse(element._isSubmitEnabled({submit: {}}));
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001300 assert.isTrue(element._isSubmitEnabled({submit: {enabled: true}}));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001301 });
1302
1303 test('_reload is called when an approved label is removed', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001304 const vote: ApprovalInfo = {
1305 ...createApproval(),
1306 _account_id: 1 as AccountId,
1307 name: 'bojack',
1308 value: 1,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001309 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001310 element._changeNum = TEST_NUMERIC_CHANGE_ID;
1311 element._patchRange = {
1312 basePatchNum: ParentPatchSetNum,
1313 patchNum: 1 as PatchSetNum,
1314 };
1315 const change = {
1316 ...createChange(),
1317 owner: createAccountWithIdNameAndEmail(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001318 revisions: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001319 rev2: createRevision(2),
1320 rev1: createRevision(1),
1321 rev13: createRevision(13),
1322 rev3: createRevision(3),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001323 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001324 current_revision: 'rev3' as CommitId,
1325 status: ChangeStatus.NEW,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001326 labels: {
1327 test: {
1328 all: [vote],
1329 default_value: 0,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001330 values: {},
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001331 approved: {},
1332 },
1333 },
1334 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001335 element._change = change;
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02001336 flush();
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001337 const reloadStub = sinon.stub(element, '_reload');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001338 element.splice('_change.labels.test.all', 0, 1);
1339 assert.isFalse(reloadStub.called);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001340 change.labels.test.all.push(vote);
1341 change.labels.test.all.push(vote);
1342 change.labels.test.approved = vote;
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02001343 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001344 element.splice('_change.labels.test.all', 0, 2);
1345 assert.isTrue(reloadStub.called);
1346 assert.isTrue(reloadStub.calledOnce);
1347 });
1348
1349 test('reply button has updated count when there are drafts', () => {
1350 const getLabel = element._computeReplyButtonLabel;
1351
1352 assert.equal(getLabel(null, false), 'Reply');
Ben Rohlfs706d72b2020-05-28 14:56:55 +02001353 assert.equal(getLabel(null, true), 'Start Review');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001354
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001355 const changeRecord: ElementPropertyDeepChange<
1356 GrChangeView,
1357 '_diffDrafts'
1358 > = {base: undefined, path: '', value: undefined};
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001359 assert.equal(getLabel(changeRecord, false), 'Reply');
1360
1361 changeRecord.base = {};
1362 assert.equal(getLabel(changeRecord, false), 'Reply');
1363
1364 changeRecord.base = {
1365 'file1.txt': [{}],
1366 'file2.txt': [{}, {}],
1367 };
1368 assert.equal(getLabel(changeRecord, false), 'Reply (3)');
Tao Zhou709c0822020-07-08 09:47:09 +02001369 assert.equal(getLabel(changeRecord, true), 'Start Review (3)');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001370 });
1371
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001372 test('comment events properly update diff drafts', () => {
1373 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001374 basePatchNum: ParentPatchSetNum,
1375 patchNum: 2 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001376 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001377 const draft: DraftInfo = {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001378 __draft: true,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001379 id: 'id1' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001380 path: '/foo/bar.txt',
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001381 message: 'hello',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001382 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001383 element._handleCommentSave(new CustomEvent('', {detail: {comment: draft}}));
1384 draft.patch_set = 2 as PatchSetNum;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001385 assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001386 draft.patch_set = undefined;
1387 draft.message = 'hello, there';
1388 element._handleCommentSave(new CustomEvent('', {detail: {comment: draft}}));
1389 draft.patch_set = 2 as PatchSetNum;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001390 assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001391 const draft2: DraftInfo = {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001392 __draft: true,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001393 id: 'id2' as UrlEncodedCommentId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001394 path: '/foo/bar.txt',
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001395 message: 'hola',
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001396 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001397 element._handleCommentSave(
1398 new CustomEvent('', {detail: {comment: draft2}})
1399 );
1400 draft2.patch_set = 2 as PatchSetNum;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001401 assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft, draft2]});
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001402 draft.patch_set = undefined;
1403 element._handleCommentDiscard(
1404 new CustomEvent('', {detail: {comment: draft}})
1405 );
1406 draft.patch_set = 2 as PatchSetNum;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001407 assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft2]});
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001408 element._handleCommentDiscard(
1409 new CustomEvent('', {detail: {comment: draft2}})
1410 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001411 assert.deepEqual(element._diffDrafts, {});
1412 });
1413
1414 test('change num change', () => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01001415 const change = {
1416 ...createChange(),
1417 labels: {},
1418 } as ParsedChangeInfo;
1419 stubRestApi('getChangeDetail').returns(Promise.resolve(change));
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001420 element._changeNum = undefined;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001421 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001422 basePatchNum: ParentPatchSetNum,
1423 patchNum: 2 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001424 };
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01001425 element._change = change;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001426 element.viewState.changeNum = null;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001427 element.viewState.diffMode = DiffViewMode.UNIFIED;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001428 assert.equal(element.viewState.numFilesShown, 200);
1429 assert.equal(element._numFilesShown, 200);
1430 element._numFilesShown = 150;
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02001431 flush();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001432 assert.equal(element.viewState.diffMode, DiffViewMode.UNIFIED);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001433 assert.equal(element.viewState.numFilesShown, 150);
1434
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001435 element._changeNum = 1 as NumericChangeId;
1436 element.params = {
1437 ...createAppElementChangeViewParams(),
1438 changeNum: 1 as NumericChangeId,
1439 };
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02001440 flush();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001441 assert.equal(element.viewState.diffMode, DiffViewMode.UNIFIED);
1442 assert.equal(element.viewState.changeNum, 1);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001443
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001444 element._changeNum = 2 as NumericChangeId;
1445 element.params = {
1446 ...createAppElementChangeViewParams(),
1447 changeNum: 2 as NumericChangeId,
1448 };
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02001449 flush();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001450 assert.equal(element.viewState.diffMode, DiffViewMode.UNIFIED);
1451 assert.equal(element.viewState.changeNum, 2);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001452 assert.equal(element.viewState.numFilesShown, 200);
1453 assert.equal(element._numFilesShown, 200);
1454 });
1455
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001456 test('_setDiffViewMode is called with reset when new change is loaded', () => {
1457 const setDiffViewModeStub = sinon.stub(element, '_setDiffViewMode');
1458 element.viewState = {changeNum: 1 as NumericChangeId};
1459 element._changeNum = 2 as NumericChangeId;
1460 element._resetFileListViewState();
1461 assert.isTrue(setDiffViewModeStub.calledWithExactly(true));
1462 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001463
1464 test('diffViewMode is propagated from file list header', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001465 element.viewState = {diffMode: DiffViewMode.UNIFIED};
1466 element.$.fileListHeader.diffViewMode = DiffViewMode.SIDE_BY_SIDE;
1467 assert.equal(element.viewState.diffMode, DiffViewMode.SIDE_BY_SIDE);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001468 });
1469
1470 test('diffMode defaults to side by side without preferences', done => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01001471 stubRestApi('getPreferences').returns(Promise.resolve(createPreferences()));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001472 // No user prefs or diff view mode set.
1473
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001474 element._setDiffViewMode()!.then(() => {
1475 assert.equal(element.viewState.diffMode, DiffViewMode.SIDE_BY_SIDE);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001476 done();
1477 });
1478 });
1479
1480 test('diffMode defaults to preference when not already set', done => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01001481 stubRestApi('getPreferences').returns(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001482 Promise.resolve({
1483 ...createPreferences(),
1484 default_diff_view: DiffViewMode.UNIFIED,
1485 })
1486 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001487
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001488 element._setDiffViewMode()!.then(() => {
1489 assert.equal(element.viewState.diffMode, DiffViewMode.UNIFIED);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001490 done();
1491 });
1492 });
1493
1494 test('existing diffMode overrides preference', done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001495 element.viewState.diffMode = DiffViewMode.SIDE_BY_SIDE;
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01001496 stubRestApi('getPreferences').returns(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001497 Promise.resolve({
1498 ...createPreferences(),
1499 default_diff_view: DiffViewMode.UNIFIED,
1500 })
1501 );
1502 element._setDiffViewMode()!.then(() => {
1503 assert.equal(element.viewState.diffMode, DiffViewMode.SIDE_BY_SIDE);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001504 done();
1505 });
1506 });
1507
1508 test('don’t reload entire page when patchRange changes', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001509 const reloadStub = sinon
1510 .stub(element, '_reload')
1511 .callsFake(() => Promise.resolve([]));
1512 const reloadPatchDependentStub = sinon
1513 .stub(element, '_reloadPatchNumDependentResources')
Dhruv Srivastava09a1b5a2021-01-20 09:28:15 +01001514 .callsFake(() => Promise.resolve([undefined, undefined, undefined]));
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001515 const relatedClearSpy = sinon.spy(element.$.relatedChanges, 'clear');
1516 const collapseStub = sinon.stub(element.$.fileList, 'collapseAllDiffs');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001517
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001518 const value: AppElementChangeViewParams = {
1519 ...createAppElementChangeViewParams(),
1520 view: GerritView.CHANGE,
1521 patchNum: 1 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001522 };
1523 element._paramsChanged(value);
1524 assert.isTrue(reloadStub.calledOnce);
1525 assert.isTrue(relatedClearSpy.calledOnce);
1526
1527 element._initialLoadComplete = true;
1528
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001529 value.basePatchNum = 1 as PatchSetNum;
1530 value.patchNum = 2 as PatchSetNum;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001531 element._paramsChanged(value);
1532 assert.isFalse(reloadStub.calledTwice);
1533 assert.isTrue(reloadPatchDependentStub.calledOnce);
1534 assert.isTrue(relatedClearSpy.calledOnce);
1535 assert.isTrue(collapseStub.calledTwice);
1536 });
1537
Dhruv Srivastava09a1b5a2021-01-20 09:28:15 +01001538 test('reload ported comments when patchNum changes', () => {
1539 sinon.stub(element, '_reload').callsFake(() => Promise.resolve([]));
1540 sinon.stub(element, '_getCommitInfo');
1541 sinon.stub(element.$.fileList, 'reload');
1542 const reloadPortedCommentsStub = sinon.stub(
1543 element.$.commentAPI,
1544 'reloadPortedComments'
1545 );
1546 sinon.spy(element.$.relatedChanges, 'clear');
1547 sinon.stub(element.$.fileList, 'collapseAllDiffs');
1548
1549 const value: AppElementChangeViewParams = {
1550 ...createAppElementChangeViewParams(),
1551 view: GerritView.CHANGE,
1552 patchNum: 1 as PatchSetNum,
1553 };
1554 element._paramsChanged(value);
1555
1556 element._initialLoadComplete = true;
1557
1558 value.basePatchNum = 1 as PatchSetNum;
1559 value.patchNum = 2 as PatchSetNum;
1560 element._paramsChanged(value);
1561 assert.isTrue(reloadPortedCommentsStub.calledOnce);
1562 });
1563
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001564 test('reload entire page when patchRange doesnt change', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001565 const reloadStub = sinon
1566 .stub(element, '_reload')
1567 .callsFake(() => Promise.resolve([]));
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001568 const collapseStub = sinon.stub(element.$.fileList, 'collapseAllDiffs');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001569 const value: AppElementChangeViewParams = createAppElementChangeViewParams();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001570 element._paramsChanged(value);
1571 assert.isTrue(reloadStub.calledOnce);
1572 element._initialLoadComplete = true;
1573 element._paramsChanged(value);
1574 assert.isTrue(reloadStub.calledTwice);
1575 assert.isTrue(collapseStub.calledTwice);
1576 });
1577
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001578 test('related changes are not updated after other action', done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001579 sinon.stub(element, '_reload').callsFake(() => Promise.resolve([]));
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001580 sinon.stub(element.$.relatedChanges, 'reload');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001581 element._reload(true).then(() => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001582 assert.isFalse(navigateToChangeStub.called);
1583 done();
1584 });
1585 });
1586
1587 test('_computeMergedCommitInfo', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001588 const dummyRevs: {[revisionId: string]: RevisionInfo} = {
1589 1: createRevision(1),
1590 2: createRevision(2),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001591 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001592 assert.deepEqual(
1593 element._computeMergedCommitInfo('0' as CommitId, dummyRevs),
1594 {}
1595 );
1596 assert.deepEqual(
1597 element._computeMergedCommitInfo('1' as CommitId, dummyRevs),
1598 dummyRevs[1].commit
1599 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001600
1601 // Regression test for issue 5337.
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001602 const commit = element._computeMergedCommitInfo('2' as CommitId, dummyRevs);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001603 assert.notDeepEqual(commit, dummyRevs[2]);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001604 assert.deepEqual(commit, dummyRevs[2].commit);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001605 });
1606
1607 test('_computeCopyTextForTitle', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001608 const change: ChangeInfo = {
1609 ...createChange(),
1610 _number: 123 as NumericChangeId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001611 subject: 'test subject',
1612 revisions: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001613 rev1: createRevision(1),
1614 rev3: createRevision(3),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001615 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001616 current_revision: 'rev3' as CommitId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001617 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001618 sinon.stub(GerritNav, 'getUrlForChange').returns('/change/123');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001619 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001620 element._computeCopyTextForTitle(change),
1621 `123: test subject | http://${location.host}/change/123`
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001622 );
1623 });
1624
1625 test('get latest revision', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001626 let change: ChangeInfo = {
1627 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001628 revisions: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001629 rev1: createRevision(1),
1630 rev3: createRevision(3),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001631 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001632 current_revision: 'rev3' as CommitId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001633 };
1634 assert.equal(element._getLatestRevisionSHA(change), 'rev3');
1635 change = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001636 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001637 revisions: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001638 rev1: createRevision(1),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001639 },
1640 };
1641 assert.equal(element._getLatestRevisionSHA(change), 'rev1');
1642 });
1643
1644 test('show commit message edit button', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001645 const change = createChange();
1646 const mergedChanged: ChangeInfo = {
1647 ...createChange(),
Dmitrii Filippov4e4522e2020-05-06 12:50:49 +02001648 status: ChangeStatus.MERGED,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001649 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001650 assert.isTrue(element._computeHideEditCommitMessage(false, false, change));
1651 assert.isTrue(element._computeHideEditCommitMessage(true, true, change));
1652 assert.isTrue(element._computeHideEditCommitMessage(false, true, change));
1653 assert.isFalse(element._computeHideEditCommitMessage(true, false, change));
1654 assert.isTrue(
1655 element._computeHideEditCommitMessage(true, false, mergedChanged)
1656 );
1657 assert.isTrue(
1658 element._computeHideEditCommitMessage(true, false, change, true)
1659 );
1660 assert.isFalse(
1661 element._computeHideEditCommitMessage(true, false, change, false)
1662 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001663 });
1664
1665 test('_handleCommitMessageSave trims trailing whitespace', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001666 element._change = createChange();
1667 // Response code is 500, because we want to avoid window reloading
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01001668 const putStub = stubRestApi('putChangeCommitMessage').returns(
1669 Promise.resolve(new Response(null, {status: 500}))
1670 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001671
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001672 const mockEvent = (content: string) => {
1673 return new CustomEvent('', {detail: {content}});
1674 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001675
1676 element._handleCommitMessageSave(mockEvent('test \n test '));
1677 assert.equal(putStub.lastCall.args[1], 'test\n test');
1678
1679 element._handleCommitMessageSave(mockEvent(' test\ntest'));
1680 assert.equal(putStub.lastCall.args[1], ' test\ntest');
1681
1682 element._handleCommitMessageSave(mockEvent('\n\n\n\n\n\n\n\n'));
1683 assert.equal(putStub.lastCall.args[1], '\n\n\n\n\n\n\n\n');
1684 });
1685
1686 test('_computeChangeIdCommitMessageError', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001687 let commitMessage = 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483';
1688 let change: ChangeInfo = {
1689 ...createChange(),
1690 change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483' as ChangeId,
1691 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001692 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001693 element._computeChangeIdCommitMessageError(commitMessage, change),
1694 null
1695 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001696
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001697 change = {
1698 ...createChange(),
1699 change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484' as ChangeId,
1700 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001701 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001702 element._computeChangeIdCommitMessageError(commitMessage, change),
1703 'mismatch'
1704 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001705
1706 commitMessage = 'This is the greatest change.';
1707 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001708 element._computeChangeIdCommitMessageError(commitMessage, change),
1709 'missing'
1710 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001711 });
1712
1713 test('multiple change Ids in commit message picks last', () => {
1714 const commitMessage = [
1715 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
1716 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
1717 ].join('\n');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001718 let change: ChangeInfo = {
1719 ...createChange(),
1720 change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483' as ChangeId,
1721 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001722 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001723 element._computeChangeIdCommitMessageError(commitMessage, change),
1724 null
1725 );
1726 change = {
1727 ...createChange(),
1728 change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484' as ChangeId,
1729 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001730 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001731 element._computeChangeIdCommitMessageError(commitMessage, change),
1732 'mismatch'
1733 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001734 });
1735
1736 test('does not count change Id that starts mid line', () => {
1737 const commitMessage = [
1738 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
1739 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
1740 ].join(' and ');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001741 let change: ChangeInfo = {
1742 ...createChange(),
1743 change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484' as ChangeId,
1744 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001745 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001746 element._computeChangeIdCommitMessageError(commitMessage, change),
1747 null
1748 );
1749 change = {
1750 ...createChange(),
1751 change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483' as ChangeId,
1752 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001753 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001754 element._computeChangeIdCommitMessageError(commitMessage, change),
1755 'mismatch'
1756 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001757 });
1758
1759 test('_computeTitleAttributeWarning', () => {
1760 let changeIdCommitMessageError = 'missing';
1761 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001762 element._computeTitleAttributeWarning(changeIdCommitMessageError),
1763 'No Change-Id in commit message'
1764 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001765
1766 changeIdCommitMessageError = 'mismatch';
1767 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001768 element._computeTitleAttributeWarning(changeIdCommitMessageError),
1769 'Change-Id mismatch'
1770 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001771 });
1772
1773 test('_computeChangeIdClass', () => {
1774 let changeIdCommitMessageError = 'missing';
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001775 assert.equal(element._computeChangeIdClass(changeIdCommitMessageError), '');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001776
1777 changeIdCommitMessageError = 'mismatch';
1778 assert.equal(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001779 element._computeChangeIdClass(changeIdCommitMessageError),
1780 'warning'
1781 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001782 });
1783
1784 test('topic is coalesced to null', done => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001785 sinon.stub(element, '_changeChanged');
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01001786 stubRestApi('getChangeDetail').returns(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001787 Promise.resolve({
1788 ...createChange(),
1789 labels: {},
1790 current_revision: 'foo' as CommitId,
1791 revisions: {foo: createRevision()},
1792 })
1793 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001794
1795 element._getChangeDetail().then(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001796 assert.isNull(element._change!.topic);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001797 done();
1798 });
1799 });
1800
1801 test('commit sha is populated from getChangeDetail', done => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001802 sinon.stub(element, '_changeChanged');
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01001803 stubRestApi('getChangeDetail').callsFake(() =>
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001804 Promise.resolve({
1805 ...createChange(),
1806 labels: {},
1807 current_revision: 'foo' as CommitId,
1808 revisions: {foo: createRevision()},
1809 })
1810 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001811
1812 element._getChangeDetail().then(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001813 assert.equal('foo', element._commitInfo!.commit);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001814 done();
1815 });
1816 });
1817
1818 test('edit is added to change', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001819 sinon.stub(element, '_changeChanged');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001820 const changeRevision = createRevision();
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01001821 stubRestApi('getChangeDetail').callsFake(() =>
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001822 Promise.resolve({
1823 ...createChange(),
1824 labels: {},
1825 current_revision: 'foo' as CommitId,
1826 revisions: {foo: {...changeRevision}},
1827 })
1828 );
1829 const editCommit: CommitInfo = {
1830 ...createCommit(),
1831 commit: 'bar' as CommitId,
1832 };
1833 sinon.stub(element, '_getEdit').callsFake(() =>
1834 Promise.resolve({
1835 base_patch_set_number: 1 as PatchSetNum,
1836 commit: {...editCommit},
1837 base_revision: 'abc',
1838 ref: 'some/ref' as GitRef,
1839 })
1840 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001841 element._patchRange = {};
1842
1843 return element._getChangeDetail().then(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001844 const revs = element._change!.revisions!;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001845 assert.equal(Object.keys(revs).length, 2);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001846 assert.deepEqual(revs['foo'], changeRevision);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001847 assert.deepEqual(revs['bar'], {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001848 ...createEditRevision(),
1849 commit: editCommit,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001850 fetch: undefined,
1851 });
1852 });
1853 });
1854
1855 test('_getBasePatchNum', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001856 const _change: ChangeInfo = {
1857 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001858 revisions: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001859 '98da160735fb81604b4c40e93c368f380539dd0e': createRevision(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001860 },
1861 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001862 const _patchRange: ChangeViewPatchRange = {
1863 basePatchNum: ParentPatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001864 };
1865 assert.equal(element._getBasePatchNum(_change, _patchRange), 'PARENT');
1866
1867 element._prefs = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001868 ...createPreferences(),
1869 default_base_for_merges: DefaultBase.FIRST_PARENT,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001870 };
1871
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001872 const _change2: ChangeInfo = {
1873 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001874 revisions: {
1875 '98da160735fb81604b4c40e93c368f380539dd0e': {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001876 ...createRevision(1),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001877 commit: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001878 ...createCommit(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001879 parents: [
1880 {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001881 commit: '6e12bdf1176eb4ab24d8491ba3b6d0704409cde8' as CommitId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001882 subject: 'test',
1883 },
1884 {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001885 commit: '22f7db4754b5d9816fc581f3d9a6c0ef8429c841' as CommitId,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001886 subject: 'test3',
1887 },
1888 ],
1889 },
1890 },
1891 },
1892 };
1893 assert.equal(element._getBasePatchNum(_change2, _patchRange), -1);
1894
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001895 _patchRange.patchNum = 1 as PatchSetNum;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001896 assert.equal(element._getBasePatchNum(_change2, _patchRange), 'PARENT');
1897 });
1898
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001899 test('_openReplyDialog called with `ANY` when coming from tap event', done => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001900 flush(() => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001901 const openStub = sinon.stub(element, '_openReplyDialog');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001902 tap(element.$.replyBtn);
1903 assert(
1904 openStub.lastCall.calledWithExactly(
1905 element.$.replyDialog.FocusTarget.ANY
1906 ),
1907 '_openReplyDialog should have been passed ANY'
1908 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001909 assert.equal(openStub.callCount, 1);
1910 done();
1911 });
1912 });
1913
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001914 test(
1915 '_openReplyDialog called with `BODY` when coming from message reply' +
1916 'event',
1917 done => {
1918 flush(() => {
1919 const openStub = sinon.stub(element, '_openReplyDialog');
1920 element.messagesList!.dispatchEvent(
1921 new CustomEvent('reply', {
1922 detail: {message: {message: 'text'}},
1923 composed: true,
1924 bubbles: true,
1925 })
1926 );
1927 assert(
1928 openStub.lastCall.calledWithExactly(
1929 element.$.replyDialog.FocusTarget.BODY
1930 ),
1931 '_openReplyDialog should have been passed BODY'
1932 );
1933 assert.equal(openStub.callCount, 1);
1934 done();
1935 });
1936 }
1937 );
1938
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001939 test('reply dialog focus can be controlled', () => {
1940 const FocusTarget = element.$.replyDialog.FocusTarget;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001941 const openStub = sinon.stub(element, '_openReplyDialog');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001942
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001943 const e = new CustomEvent('show-reply-dialog', {
1944 detail: {value: {ccsOnly: false}},
1945 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001946 element._handleShowReplyDialog(e);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001947 assert(
1948 openStub.lastCall.calledWithExactly(FocusTarget.REVIEWERS),
1949 '_openReplyDialog should have been passed REVIEWERS'
1950 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001951 assert.equal(openStub.callCount, 1);
1952
1953 e.detail.value = {ccsOnly: true};
1954 element._handleShowReplyDialog(e);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001955 assert(
1956 openStub.lastCall.calledWithExactly(FocusTarget.CCS),
1957 '_openReplyDialog should have been passed CCS'
1958 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001959 assert.equal(openStub.callCount, 2);
1960 });
1961
1962 test('getUrlParameter functionality', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001963 const locationStub = sinon.stub(element, '_getLocationSearch');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001964
1965 locationStub.returns('?test');
1966 assert.equal(element._getUrlParameter('test'), 'test');
1967 locationStub.returns('?test2=12&test=3');
1968 assert.equal(element._getUrlParameter('test'), 'test');
1969 locationStub.returns('');
1970 assert.isNull(element._getUrlParameter('test'));
1971 locationStub.returns('?');
1972 assert.isNull(element._getUrlParameter('test'));
1973 locationStub.returns('?test2');
1974 assert.isNull(element._getUrlParameter('test'));
1975 });
1976
1977 test('revert dialog opened with revert param', done => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01001978 stubRestApi('getLoggedIn').returns(Promise.resolve(true));
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001979 const awaitPluginsLoadedStub = sinon
1980 .stub(getPluginLoader(), 'awaitPluginsLoaded')
1981 .callsFake(() => Promise.resolve());
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001982
1983 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001984 basePatchNum: ParentPatchSetNum,
1985 patchNum: 2 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001986 };
1987 element._change = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001988 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001989 revisions: {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001990 rev1: createRevision(1),
1991 rev2: createRevision(2),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001992 },
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001993 current_revision: 'rev1' as CommitId,
Dmitrii Filippov4e4522e2020-05-06 12:50:49 +02001994 status: ChangeStatus.MERGED,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001995 labels: {},
1996 actions: {},
1997 };
1998
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01001999 sinon.stub(element, '_getUrlParameter').callsFake(param => {
2000 assert.equal(param, 'revert');
2001 return param;
2002 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002003
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002004 sinon.stub(element.$.actions, 'showRevertDialog').callsFake(done);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002005
2006 element._maybeShowRevertDialog();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002007 assert.isTrue(awaitPluginsLoadedStub.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002008 });
2009
2010 suite('scroll related tests', () => {
2011 test('document scrolling calls function to set scroll height', done => {
2012 const originalHeight = document.body.scrollHeight;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002013 const scrollStub = sinon.stub(element, '_handleScroll').callsFake(() => {
2014 assert.isTrue(scrollStub.called);
2015 document.body.style.height = `${originalHeight}px`;
2016 scrollStub.restore();
2017 done();
2018 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002019 document.body.style.height = '10000px';
2020 element._handleScroll();
2021 });
2022
2023 test('scrollTop is set correctly', () => {
2024 element.viewState = {scrollTop: TEST_SCROLL_TOP_PX};
2025
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002026 sinon.stub(element, '_reload').callsFake(() => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002027 // When element is reloaded, ensure that the history
2028 // state has the scrollTop set earlier. This will then
2029 // be reset.
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002030 assert.isTrue(element.viewState.scrollTop === TEST_SCROLL_TOP_PX);
2031 return Promise.resolve([]);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002032 });
2033
2034 // simulate reloading component, which is done when route
2035 // changes to match a regex of change view type.
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002036 element._paramsChanged({...createAppElementChangeViewParams()});
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002037 });
2038
2039 test('scrollTop is reset when new change is loaded', () => {
2040 element._resetFileListViewState();
2041 assert.equal(element.viewState.scrollTop, 0);
2042 });
2043 });
2044
2045 suite('reply dialog tests', () => {
2046 setup(() => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002047 sinon.stub(element.$.replyDialog, '_draftChanged');
Dmitrii Filippov0695d402020-10-22 16:57:57 +02002048 element._change = {
2049 ...createChange(),
2050 revisions: createRevisions(1),
2051 messages: createChangeMessages(1),
2052 };
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +02002053 element._change.labels = {};
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002054 stubRestApi('getChangeDetail').callsFake(() =>
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002055 Promise.resolve({
2056 ...createChange(),
2057 // element has latest info
2058 revisions: {rev1: createRevision()},
2059 messages: createChangeMessages(1),
2060 current_revision: 'rev1' as CommitId,
2061 })
2062 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002063 });
2064
Tao Zhouda7463c2020-07-14 11:17:20 +02002065 test('show reply dialog on open-reply-dialog event', done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002066 const openReplyDialogStub = sinon.stub(element, '_openReplyDialog');
Tao Zhouda7463c2020-07-14 11:17:20 +02002067 element.dispatchEvent(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002068 new CustomEvent('open-reply-dialog', {
2069 composed: true,
2070 bubbles: true,
2071 detail: {},
2072 })
2073 );
Tao Zhouda7463c2020-07-14 11:17:20 +02002074 flush(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002075 assert.isTrue(openReplyDialogStub.calledOnce);
Tao Zhouda7463c2020-07-14 11:17:20 +02002076 done();
2077 });
2078 });
2079
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002080 test('reply from comment adds quote text', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002081 const e = new CustomEvent('', {
2082 detail: {message: {message: 'quote text'}},
2083 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002084 element._handleMessageReply(e);
2085 assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
2086 });
2087
2088 test('reply from comment replaces quote text', () => {
2089 element.$.replyDialog.draft = '> old quote text\n\n some draft text';
2090 element.$.replyDialog.quote = '> old quote text\n\n';
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002091 const e = new CustomEvent('', {
2092 detail: {message: {message: 'quote text'}},
2093 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002094 element._handleMessageReply(e);
2095 assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
2096 });
2097
2098 test('reply from same comment preserves quote text', () => {
2099 element.$.replyDialog.draft = '> quote text\n\n some draft text';
2100 element.$.replyDialog.quote = '> quote text\n\n';
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002101 const e = new CustomEvent('', {
2102 detail: {message: {message: 'quote text'}},
2103 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002104 element._handleMessageReply(e);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002105 assert.equal(
2106 element.$.replyDialog.draft,
2107 '> quote text\n\n some draft text'
2108 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002109 assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
2110 });
2111
2112 test('reply from top of page contains previous draft', () => {
2113 const div = document.createElement('div');
2114 element.$.replyDialog.draft = '> quote text\n\n some draft text';
2115 element.$.replyDialog.quote = '> quote text\n\n';
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002116 const e = ({
2117 target: div,
2118 preventDefault: sinon.spy(),
2119 } as unknown) as MouseEvent;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002120 element._handleReplyTap(e);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002121 assert.equal(
2122 element.$.replyDialog.draft,
2123 '> quote text\n\n some draft text'
2124 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002125 assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
2126 });
2127 });
2128
Milutin Kristoficbec88f12020-10-13 16:53:28 +02002129 test('reply button is disabled until server config is loaded', done => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002130 assert.isTrue(element._replyDisabled);
Milutin Kristoficbec88f12020-10-13 16:53:28 +02002131 // fetches the server config on attached
2132 flush(() => {
2133 assert.isFalse(element._replyDisabled);
2134 done();
2135 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002136 });
2137
2138 suite('commit message expand/collapse', () => {
2139 setup(() => {
Dmitrii Filippov0695d402020-10-22 16:57:57 +02002140 element._change = {
2141 ...createChange(),
2142 revisions: createRevisions(1),
2143 messages: createChangeMessages(1),
2144 };
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +02002145 element._change.labels = {};
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002146 stubRestApi('getChangeDetail').callsFake(() =>
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002147 Promise.resolve({
2148 ...createChange(),
2149 // new patchset was uploaded
2150 revisions: createRevisions(2),
2151 current_revision: getCurrentRevision(2),
2152 messages: createChangeMessages(1),
2153 })
2154 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002155 });
2156
2157 test('commitCollapseToggle hidden for short commit message', () => {
2158 element._latestCommitMessage = '';
2159 assert.isTrue(element.$.commitCollapseToggle.hasAttribute('hidden'));
2160 });
2161
2162 test('commitCollapseToggle shown for long commit message', () => {
2163 element._latestCommitMessage = _.times(31, String).join('\n');
2164 assert.isFalse(element.$.commitCollapseToggle.hasAttribute('hidden'));
2165 });
2166
2167 test('commitCollapseToggle functions', () => {
2168 element._latestCommitMessage = _.times(35, String).join('\n');
2169 assert.isTrue(element._commitCollapsed);
2170 assert.isTrue(element._commitCollapsible);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002171 assert.isTrue(element.$.commitMessageEditor.hasAttribute('collapsed'));
2172 tap(element.$.commitCollapseToggleButton);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002173 assert.isFalse(element._commitCollapsed);
2174 assert.isTrue(element._commitCollapsible);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002175 assert.isFalse(element.$.commitMessageEditor.hasAttribute('collapsed'));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002176 });
2177 });
2178
2179 suite('related changes expand/collapse', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002180 let updateHeightSpy: SinonSpyMember<typeof element._updateRelatedChangeMaxHeight>;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002181 setup(() => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002182 updateHeightSpy = sinon.spy(element, '_updateRelatedChangeMaxHeight');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002183 });
2184
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002185 test('relatedChangesToggle shown height greater than changeInfo height', () => {
2186 assert.isFalse(
2187 element.$.relatedChangesToggle.classList.contains('showToggle')
2188 );
2189 sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
2190 sinon.stub(element, '_getScrollHeight').callsFake(() => 60);
2191 sinon.stub(element, '_getLineHeight').callsFake(() => 5);
2192 sinon.stub(window, 'matchMedia').callsFake(() => {
2193 return {matches: true} as MediaQueryList;
2194 });
2195 element.$.relatedChanges.dispatchEvent(
2196 new CustomEvent('new-section-loaded')
2197 );
2198 assert.isTrue(
2199 element.$.relatedChangesToggle.classList.contains('showToggle')
2200 );
2201 assert.equal(updateHeightSpy.callCount, 1);
2202 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002203
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002204 test('relatedChangesToggle hidden height less than changeInfo height', () => {
2205 assert.isFalse(
2206 element.$.relatedChangesToggle.classList.contains('showToggle')
2207 );
2208 sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
2209 sinon.stub(element, '_getScrollHeight').callsFake(() => 40);
2210 sinon.stub(element, '_getLineHeight').callsFake(() => 5);
2211 sinon.stub(window, 'matchMedia').callsFake(() => {
2212 return {matches: true} as MediaQueryList;
2213 });
2214 element.$.relatedChanges.dispatchEvent(
2215 new CustomEvent('new-section-loaded')
2216 );
2217 assert.isFalse(
2218 element.$.relatedChangesToggle.classList.contains('showToggle')
2219 );
2220 assert.equal(updateHeightSpy.callCount, 1);
2221 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002222
2223 test('relatedChangesToggle functions', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002224 sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002225 sinon.stub(window, 'matchMedia').callsFake(() => {
2226 return {matches: false} as MediaQueryList;
2227 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002228 assert.isTrue(element._relatedChangesCollapsed);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002229 assert.isTrue(element.$.relatedChanges.classList.contains('collapsed'));
2230 tap(element.$.relatedChangesToggleButton);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002231 assert.isFalse(element._relatedChangesCollapsed);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002232 assert.isFalse(element.$.relatedChanges.classList.contains('collapsed'));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002233 });
2234
2235 test('_updateRelatedChangeMaxHeight without commit toggle', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002236 sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
2237 sinon.stub(element, '_getLineHeight').callsFake(() => 12);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002238 sinon.stub(window, 'matchMedia').callsFake(() => {
2239 return {matches: false} as MediaQueryList;
2240 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002241
2242 // 50 (existing height) - 30 (extra height) = 20 (adjusted height).
2243 // 20 (max existing height) % 12 (line height) = 6 (remainder).
2244 // 20 (adjusted height) - 8 (remainder) = 12 (max height to set).
2245
2246 element._updateRelatedChangeMaxHeight();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002247 assert.equal(getCustomCssValue('--relation-chain-max-height'), '12px');
2248 assert.equal(getCustomCssValue('--related-change-btn-top-padding'), '');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002249 });
2250
2251 test('_updateRelatedChangeMaxHeight with commit toggle', () => {
2252 element._latestCommitMessage = _.times(31, String).join('\n');
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002253 sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
2254 sinon.stub(element, '_getLineHeight').callsFake(() => 12);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002255 sinon.stub(window, 'matchMedia').callsFake(() => {
2256 return {matches: false} as MediaQueryList;
2257 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002258
2259 // 50 (existing height) % 12 (line height) = 2 (remainder).
2260 // 50 (existing height) - 2 (remainder) = 48 (max height to set).
2261
2262 element._updateRelatedChangeMaxHeight();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002263 assert.equal(getCustomCssValue('--relation-chain-max-height'), '48px');
2264 assert.equal(
2265 getCustomCssValue('--related-change-btn-top-padding'),
2266 '2px'
2267 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002268 });
2269
2270 test('_updateRelatedChangeMaxHeight in small screen mode', () => {
2271 element._latestCommitMessage = _.times(31, String).join('\n');
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002272 sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
2273 sinon.stub(element, '_getLineHeight').callsFake(() => 12);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002274 sinon.stub(window, 'matchMedia').callsFake(() => {
2275 return {matches: true} as MediaQueryList;
2276 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002277
2278 element._updateRelatedChangeMaxHeight();
2279
2280 // 400 (new height) % 12 (line height) = 4 (remainder).
2281 // 400 (new height) - 4 (remainder) = 396.
2282
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002283 assert.equal(getCustomCssValue('--relation-chain-max-height'), '396px');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002284 });
2285
2286 test('_updateRelatedChangeMaxHeight in medium screen mode', () => {
2287 element._latestCommitMessage = _.times(31, String).join('\n');
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002288 sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
2289 sinon.stub(element, '_getLineHeight').callsFake(() => 12);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002290 const matchMediaStub = sinon.stub(window, 'matchMedia').callsFake(() => {
2291 if (matchMediaStub.lastCall.args[0] === '(max-width: 75em)') {
2292 return {matches: true} as MediaQueryList;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002293 } else {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002294 return {matches: false} as MediaQueryList;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002295 }
2296 });
2297
2298 // 100 (new height) % 12 (line height) = 4 (remainder).
2299 // 100 (new height) - 4 (remainder) = 96.
2300 element._updateRelatedChangeMaxHeight();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002301 assert.equal(getCustomCssValue('--relation-chain-max-height'), '96px');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002302 });
2303
2304 suite('update checks', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002305 let startUpdateCheckTimerSpy: SinonSpyMember<typeof element._startUpdateCheckTimer>;
2306 let asyncStub: SinonStubbedMember<typeof element.async>;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002307 setup(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002308 startUpdateCheckTimerSpy = sinon.spy(element, '_startUpdateCheckTimer');
2309 asyncStub = sinon.stub(element, 'async').callsFake(f => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002310 // Only fire the async callback one time.
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002311 if (asyncStub.callCount > 1) {
2312 return 1;
2313 }
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002314 f.call(element);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002315 return 1;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002316 });
Dmitrii Filippov0695d402020-10-22 16:57:57 +02002317 element._change = {
2318 ...createChange(),
2319 revisions: createRevisions(1),
2320 messages: createChangeMessages(1),
2321 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002322 });
2323
2324 test('_startUpdateCheckTimer negative delay', () => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002325 const getChangeDetailStub = stubRestApi('getChangeDetail').returns(
2326 Promise.resolve({
2327 ...createChange(),
2328 // element has latest info
2329 revisions: {rev1: createRevision()},
2330 messages: createChangeMessages(1),
2331 current_revision: 'rev1' as CommitId,
2332 })
2333 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002334
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002335 element._serverConfig = {
2336 ...createServerInfo(),
2337 change: {...createChangeConfig(), update_delay: -1},
2338 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002339
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002340 assert.isTrue(startUpdateCheckTimerSpy.called);
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +02002341 assert.isFalse(getChangeDetailStub.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002342 });
2343
Ben Rohlfs67614c72020-09-17 08:18:04 +02002344 test('_startUpdateCheckTimer up-to-date', async () => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002345 const getChangeDetailStub = stubRestApi('getChangeDetail').callsFake(
2346 () =>
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002347 Promise.resolve({
2348 ...createChange(),
2349 // element has latest info
2350 revisions: {rev1: createRevision()},
2351 messages: createChangeMessages(1),
2352 current_revision: 'rev1' as CommitId,
2353 })
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002354 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002355
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002356 element._serverConfig = {
2357 ...createServerInfo(),
2358 change: {...createChangeConfig(), update_delay: 12345},
2359 };
Ben Rohlfs67614c72020-09-17 08:18:04 +02002360 await flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002361
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002362 assert.equal(startUpdateCheckTimerSpy.callCount, 2);
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +02002363 assert.isTrue(getChangeDetailStub.called);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002364 assert.equal(asyncStub.lastCall.args[1], 12345 * 1000);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002365 });
2366
2367 test('_startUpdateCheckTimer out-of-date shows an alert', done => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002368 stubRestApi('getChangeDetail').callsFake(() =>
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002369 Promise.resolve({
2370 ...createChange(),
2371 // new patchset was uploaded
2372 revisions: createRevisions(2),
2373 current_revision: getCurrentRevision(2),
2374 messages: createChangeMessages(1),
2375 })
2376 );
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +02002377
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002378 element.addEventListener('show-alert', e => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002379 assert.equal(e.detail.message, 'A newer patch set has been uploaded');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002380 done();
2381 });
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002382 element._serverConfig = {
2383 ...createServerInfo(),
2384 change: {...createChangeConfig(), update_delay: 12345},
2385 };
Ben Rohlfs67614c72020-09-17 08:18:04 +02002386
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002387 assert.equal(startUpdateCheckTimerSpy.callCount, 1);
Ben Rohlfs67614c72020-09-17 08:18:04 +02002388 });
2389
2390 test('_startUpdateCheckTimer respects _loading', async () => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002391 stubRestApi('getChangeDetail').callsFake(() =>
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002392 Promise.resolve({
2393 ...createChange(),
2394 // new patchset was uploaded
2395 revisions: createRevisions(2),
2396 current_revision: getCurrentRevision(2),
2397 messages: createChangeMessages(1),
2398 })
2399 );
Ben Rohlfs67614c72020-09-17 08:18:04 +02002400
2401 element._loading = true;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002402 element._serverConfig = {
2403 ...createServerInfo(),
2404 change: {...createChangeConfig(), update_delay: 12345},
2405 };
Ben Rohlfs67614c72020-09-17 08:18:04 +02002406 await flush();
2407
2408 // No toast, instead a second call to _startUpdateCheckTimer().
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002409 assert.equal(startUpdateCheckTimerSpy.callCount, 2);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002410 });
2411
2412 test('_startUpdateCheckTimer new status shows an alert', done => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002413 stubRestApi('getChangeDetail').callsFake(() =>
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002414 Promise.resolve({
2415 ...createChange(),
2416 // element has latest info
2417 revisions: {rev1: createRevision()},
2418 messages: createChangeMessages(1),
2419 current_revision: 'rev1' as CommitId,
2420 status: ChangeStatus.MERGED,
2421 })
2422 );
Dmitrii Filippov77e5f7f2020-07-10 18:39:45 +02002423
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002424 element.addEventListener('show-alert', e => {
2425 assert.equal(e.detail.message, 'This change has been merged');
2426 done();
2427 });
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002428 element._serverConfig = {
2429 ...createServerInfo(),
2430 change: {...createChangeConfig(), update_delay: 12345},
2431 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002432 });
2433
2434 test('_startUpdateCheckTimer new messages shows an alert', done => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002435 stubRestApi('getChangeDetail').callsFake(() =>
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002436 Promise.resolve({
2437 ...createChange(),
2438 revisions: {rev1: createRevision()},
2439 // element has new message
2440 messages: createChangeMessages(2),
2441 current_revision: 'rev1' as CommitId,
2442 })
2443 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002444 element.addEventListener('show-alert', e => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002445 assert.equal(
2446 e.detail.message,
2447 'There are new messages on this change'
2448 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002449 done();
2450 });
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002451 element._serverConfig = {
2452 ...createServerInfo(),
2453 change: {...createChangeConfig(), update_delay: 12345},
2454 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002455 });
2456 });
2457
2458 test('canStartReview computation', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002459 const change1: ChangeInfo = createChange();
2460 const change2: ChangeInfo = {
2461 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002462 actions: {
2463 ready: {
2464 enabled: true,
2465 },
2466 },
2467 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002468 const change3: ChangeInfo = {
2469 ...createChange(),
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002470 actions: {
2471 ready: {
2472 label: 'Ready for Review',
2473 },
2474 },
2475 };
2476 assert.isFalse(element._computeCanStartReview(change1));
2477 assert.isTrue(element._computeCanStartReview(change2));
2478 assert.isFalse(element._computeCanStartReview(change3));
2479 });
2480 });
2481
2482 test('header class computation', () => {
2483 assert.equal(element._computeHeaderClass(), 'header');
2484 assert.equal(element._computeHeaderClass(true), 'header editMode');
2485 });
2486
2487 test('_maybeScrollToMessage', done => {
2488 flush(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002489 const scrollStub = sinon.stub(element.messagesList!, 'scrollToMessage');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002490
2491 element._maybeScrollToMessage('');
2492 assert.isFalse(scrollStub.called);
2493 element._maybeScrollToMessage('message');
2494 assert.isFalse(scrollStub.called);
2495 element._maybeScrollToMessage('#message-TEST');
2496 assert.isTrue(scrollStub.called);
2497 assert.equal(scrollStub.lastCall.args[0], 'TEST');
2498 done();
2499 });
2500 });
2501
2502 test('topic update reloads related changes', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002503 const reloadStub = sinon.stub(element.$.relatedChanges, 'reload');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002504 element.dispatchEvent(new CustomEvent('topic-changed'));
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002505 assert.isTrue(reloadStub.calledOnce);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002506 });
2507
2508 test('_computeEditMode', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002509 const callCompute = (
2510 range: PatchRange,
2511 params: AppElementChangeViewParams
2512 ) =>
2513 element._computeEditMode(
2514 {base: range, path: '', value: range},
2515 {base: params, path: '', value: params}
2516 );
2517 assert.isTrue(
2518 callCompute(
2519 {basePatchNum: ParentPatchSetNum, patchNum: 1 as PatchSetNum},
2520 {...createAppElementChangeViewParams(), edit: true}
2521 )
2522 );
2523 assert.isFalse(
2524 callCompute(
2525 {basePatchNum: ParentPatchSetNum, patchNum: 1 as PatchSetNum},
2526 createAppElementChangeViewParams()
2527 )
2528 );
2529 assert.isFalse(
2530 callCompute(
2531 {basePatchNum: EditPatchSetNum, patchNum: 1 as PatchSetNum},
2532 createAppElementChangeViewParams()
2533 )
2534 );
2535 assert.isTrue(
2536 callCompute(
2537 {basePatchNum: 1 as PatchSetNum, patchNum: EditPatchSetNum},
2538 createAppElementChangeViewParams()
2539 )
2540 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002541 });
2542
2543 test('_processEdit', () => {
2544 element._patchRange = {};
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002545 const change: ParsedChangeInfo = {
2546 ...createChange(),
2547 current_revision: 'foo' as CommitId,
2548 revisions: {
2549 foo: {...createRevision(), actions: {cherrypick: {enabled: true}}},
2550 },
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002551 };
2552 let mockChange;
2553
2554 // With no edit, mockChange should be unmodified.
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002555 element._processEdit((mockChange = _.cloneDeep(change)), false);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002556 assert.deepEqual(mockChange, change);
2557
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002558 const editCommit: CommitInfo = {
2559 ...createCommit(),
2560 commit: 'bar' as CommitId,
2561 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002562 // When edit is not based on the latest PS, current_revision should be
2563 // unmodified.
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002564 const edit: EditInfo = {
2565 ref: 'ref/test/abc' as GitRef,
2566 base_revision: 'abc',
2567 base_patch_set_number: 1 as PatchSetNum,
2568 commit: {...editCommit},
2569 fetch: {},
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002570 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002571 element._processEdit((mockChange = _.cloneDeep(change)), edit);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002572 assert.notDeepEqual(mockChange, change);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002573 assert.equal(mockChange.revisions.bar._number, EditPatchSetNum);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002574 assert.equal(mockChange.current_revision, change.current_revision);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002575 assert.deepEqual(mockChange.revisions.bar.commit, editCommit);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002576 assert.notOk(mockChange.revisions.bar.actions);
2577
2578 edit.base_revision = 'foo';
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002579 element._processEdit((mockChange = _.cloneDeep(change)), edit);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002580 assert.notDeepEqual(mockChange, change);
2581 assert.equal(mockChange.current_revision, 'bar');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002582 assert.deepEqual(
2583 mockChange.revisions.bar.actions,
2584 mockChange.revisions.foo.actions
2585 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002586
2587 // If _patchRange.patchNum is defined, do not load edit.
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002588 element._patchRange.patchNum = 5 as PatchSetNum;
2589 change.current_revision = 'baz' as CommitId;
2590 element._processEdit((mockChange = _.cloneDeep(change)), edit);
2591 assert.equal(element._patchRange.patchNum, 5 as PatchSetNum);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002592 assert.notOk(mockChange.revisions.bar.actions);
2593 });
2594
2595 test('file-action-tap handling', () => {
2596 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002597 basePatchNum: ParentPatchSetNum,
2598 patchNum: 1 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002599 };
Milutin Kristoficbec88f12020-10-13 16:53:28 +02002600 element._change = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002601 ...createChange(),
Milutin Kristoficbec88f12020-10-13 16:53:28 +02002602 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002603 const fileList = element.$.fileList;
2604 const Actions = GrEditConstants.Actions;
Milutin Kristofic21b0dc92020-05-18 22:44:11 +02002605 element.$.fileListHeader.editMode = true;
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02002606 flush();
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002607 const controls = element.$.fileListHeader.shadowRoot!.querySelector(
2608 '#editControls'
2609 ) as GrEditControls;
2610 const openDeleteDialogStub = sinon.stub(controls, 'openDeleteDialog');
2611 const openRenameDialogStub = sinon.stub(controls, 'openRenameDialog');
2612 const openRestoreDialogStub = sinon.stub(controls, 'openRestoreDialog');
2613 const getEditUrlForDiffStub = sinon.stub(GerritNav, 'getEditUrlForDiff');
2614 const navigateToRelativeUrlStub = sinon.stub(
2615 GerritNav,
2616 'navigateToRelativeUrl'
2617 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002618
2619 // Delete
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002620 fileList.dispatchEvent(
2621 new CustomEvent('file-action-tap', {
2622 detail: {action: Actions.DELETE.id, path: 'foo'},
2623 bubbles: true,
2624 composed: true,
2625 })
2626 );
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02002627 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002628
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002629 assert.isTrue(openDeleteDialogStub.called);
2630 assert.equal(openDeleteDialogStub.lastCall.args[0], 'foo');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002631
2632 // Restore
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002633 fileList.dispatchEvent(
2634 new CustomEvent('file-action-tap', {
2635 detail: {action: Actions.RESTORE.id, path: 'foo'},
2636 bubbles: true,
2637 composed: true,
2638 })
2639 );
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02002640 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002641
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002642 assert.isTrue(openRestoreDialogStub.called);
2643 assert.equal(openRestoreDialogStub.lastCall.args[0], 'foo');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002644
2645 // Rename
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002646 fileList.dispatchEvent(
2647 new CustomEvent('file-action-tap', {
2648 detail: {action: Actions.RENAME.id, path: 'foo'},
2649 bubbles: true,
2650 composed: true,
2651 })
2652 );
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02002653 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002654
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002655 assert.isTrue(openRenameDialogStub.called);
2656 assert.equal(openRenameDialogStub.lastCall.args[0], 'foo');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002657
2658 // Open
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002659 fileList.dispatchEvent(
2660 new CustomEvent('file-action-tap', {
2661 detail: {action: Actions.OPEN.id, path: 'foo'},
2662 bubbles: true,
2663 composed: true,
2664 })
2665 );
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02002666 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002667
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002668 assert.isTrue(getEditUrlForDiffStub.called);
2669 assert.equal(getEditUrlForDiffStub.lastCall.args[1], 'foo');
2670 assert.equal(getEditUrlForDiffStub.lastCall.args[2], 1 as PatchSetNum);
2671 assert.isTrue(navigateToRelativeUrlStub.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002672 });
2673
2674 test('_selectedRevision updates when patchNum is changed', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002675 const revision1: RevisionInfo = createRevision(1);
2676 const revision2: RevisionInfo = createRevision(2);
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002677 stubRestApi('getChangeDetail').returns(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002678 Promise.resolve({
2679 ...createChange(),
2680 revisions: {
2681 aaa: revision1,
2682 bbb: revision2,
2683 },
2684 labels: {},
2685 actions: {},
2686 current_revision: 'bbb' as CommitId,
2687 })
2688 );
2689 sinon.stub(element, '_getEdit').returns(Promise.resolve(false));
2690 sinon
2691 .stub(element, '_getPreferences')
2692 .returns(Promise.resolve(createPreferences()));
2693 element._patchRange = {patchNum: 2 as PatchSetNum};
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002694 return element._getChangeDetail().then(() => {
2695 assert.strictEqual(element._selectedRevision, revision2);
2696
2697 element.set('_patchRange.patchNum', '1');
2698 assert.strictEqual(element._selectedRevision, revision1);
2699 });
2700 });
2701
2702 test('_selectedRevision is assigned when patchNum is edit', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002703 const revision1 = createRevision(1);
2704 const revision2 = createRevision(2);
2705 const revision3 = createEditRevision();
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002706 stubRestApi('getChangeDetail').returns(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002707 Promise.resolve({
2708 ...createChange(),
2709 revisions: {
2710 aaa: revision1,
2711 bbb: revision2,
2712 ccc: revision3,
2713 },
2714 labels: {},
2715 actions: {},
2716 current_revision: 'ccc' as CommitId,
2717 })
2718 );
2719 sinon.stub(element, '_getEdit').returns(Promise.resolve(undefined));
2720 sinon
2721 .stub(element, '_getPreferences')
2722 .returns(Promise.resolve(createPreferences()));
2723 element._patchRange = {patchNum: EditPatchSetNum};
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002724 return element._getChangeDetail().then(() => {
2725 assert.strictEqual(element._selectedRevision, revision3);
2726 });
2727 });
2728
2729 test('_sendShowChangeEvent', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002730 const change = {...createChange(), labels: {}};
2731 element._change = {...change};
2732 element._patchRange = {patchNum: 4 as PatchSetNum};
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002733 element._mergeable = true;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002734 const showStub = sinon.stub(element.$.jsAPI, 'handleEvent');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002735 element._sendShowChangeEvent();
2736 assert.isTrue(showStub.calledOnce);
Ben Rohlfsa47355d2020-08-30 15:56:13 +02002737 assert.equal(showStub.lastCall.args[0], EventType.SHOW_CHANGE);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002738 assert.deepEqual(showStub.lastCall.args[1], {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002739 change,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002740 patchNum: 4,
2741 info: {mergeable: true},
2742 });
2743 });
2744
2745 suite('_handleEditTap', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002746 let fireEdit: () => void;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002747
2748 setup(() => {
2749 fireEdit = () => {
2750 element.$.actions.dispatchEvent(new CustomEvent('edit-tap'));
2751 };
2752 navigateToChangeStub.restore();
2753
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002754 element._change = {
2755 ...createChange(),
2756 revisions: {rev1: createRevision()},
2757 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002758 });
2759
2760 test('edit exists in revisions', done => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002761 sinon.stub(GerritNav, 'navigateToChange').callsFake((...args) => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002762 assert.equal(args.length, 2);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002763 assert.equal(args[1], EditPatchSetNum); // patchNum
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002764 done();
2765 });
2766
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002767 element.set('_change.revisions.rev2', {
2768 _number: SPECIAL_PATCH_SET_NUM.EDIT,
2769 });
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02002770 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002771
2772 fireEdit();
2773 });
2774
2775 test('no edit exists in revisions, non-latest patchset', done => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002776 sinon.stub(GerritNav, 'navigateToChange').callsFake((...args) => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002777 assert.equal(args.length, 4);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002778 assert.equal(args[1], 1 as PatchSetNum); // patchNum
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002779 assert.equal(args[3], true); // opt_isEdit
2780 done();
2781 });
2782
2783 element.set('_change.revisions.rev2', {_number: 2});
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002784 element._patchRange = {patchNum: 1 as PatchSetNum};
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02002785 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002786
2787 fireEdit();
2788 });
2789
2790 test('no edit exists in revisions, latest patchset', done => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002791 sinon.stub(GerritNav, 'navigateToChange').callsFake((...args) => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002792 assert.equal(args.length, 4);
2793 // No patch should be specified when patchNum == latest.
2794 assert.isNotOk(args[1]); // patchNum
2795 assert.equal(args[3], true); // opt_isEdit
2796 done();
2797 });
2798
2799 element.set('_change.revisions.rev2', {_number: 2});
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002800 element._patchRange = {patchNum: 2 as PatchSetNum};
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02002801 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002802
2803 fireEdit();
2804 });
2805 });
2806
2807 test('_handleStopEditTap', done => {
Milutin Kristoficbec88f12020-10-13 16:53:28 +02002808 element._change = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002809 ...createChange(),
Milutin Kristoficbec88f12020-10-13 16:53:28 +02002810 };
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002811 sinon.stub(element.$.metadata, '_computeLabelNames');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002812 navigateToChangeStub.restore();
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002813 sinon.stub(GerritNav, 'navigateToChange').callsFake((...args) => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002814 assert.equal(args.length, 2);
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002815 assert.equal(args[1], 1 as PatchSetNum); // patchNum
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002816 done();
2817 });
2818
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002819 element._patchRange = {patchNum: 1 as PatchSetNum};
2820 element.$.actions.dispatchEvent(
2821 new CustomEvent('stop-edit-tap', {bubbles: false})
2822 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002823 });
2824
2825 suite('plugin endpoints', () => {
2826 test('endpoint params', done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002827 element._change = {...createChange(), labels: {}};
2828 element._selectedRevision = createRevision();
2829 let hookEl: HTMLElement;
2830 let plugin: PluginApi;
Dmitrii Filippov5f25dc02020-04-07 18:49:00 +02002831 pluginApi.install(
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002832 p => {
2833 plugin = p;
2834 plugin
2835 .hook('change-view-integration')
2836 .getLastAttached()
2837 .then(el => (hookEl = el));
2838 },
2839 '0.1',
2840 'http://some/plugins/url.html'
2841 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002842 flush(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002843 assert.strictEqual((hookEl as any).plugin, plugin);
2844 assert.strictEqual((hookEl as any).change, element._change);
2845 assert.strictEqual((hookEl as any).revision, element._selectedRevision);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002846 done();
2847 });
2848 });
2849 });
2850
2851 suite('_getMergeability', () => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002852 let getMergeableStub: SinonStubbedMember<RestApiService['getMergeable']>;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002853 setup(() => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002854 element._change = {...createChange(), labels: {}};
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002855 getMergeableStub = stubRestApi('getMergeable').returns(
2856 Promise.resolve({...createMergeable(), mergeable: true})
2857 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002858 });
2859
2860 test('merged change', () => {
2861 element._mergeable = null;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002862 element._change!.status = ChangeStatus.MERGED;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002863 return element._getMergeability().then(() => {
2864 assert.isFalse(element._mergeable);
2865 assert.isFalse(getMergeableStub.called);
2866 });
2867 });
2868
2869 test('abandoned change', () => {
2870 element._mergeable = null;
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002871 element._change!.status = ChangeStatus.ABANDONED;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002872 return element._getMergeability().then(() => {
2873 assert.isFalse(element._mergeable);
2874 assert.isFalse(getMergeableStub.called);
2875 });
2876 });
2877
2878 test('open change', () => {
2879 element._mergeable = null;
2880 return element._getMergeability().then(() => {
2881 assert.isTrue(element._mergeable);
2882 assert.isTrue(getMergeableStub.called);
2883 });
2884 });
2885 });
2886
2887 test('_paramsChanged sets in projectLookup', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002888 sinon.stub(element.$.relatedChanges, 'reload');
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002889 sinon.stub(element, '_reload').returns(Promise.resolve([]));
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002890 const setStub = stubRestApi('setInProjectLookup');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002891 element._paramsChanged({
Dmitrii Filippoveb8b2692020-04-06 18:02:35 +02002892 view: GerritNav.View.CHANGE,
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002893 changeNum: 101 as NumericChangeId,
2894 project: TEST_PROJECT_NAME,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002895 });
2896 assert.isTrue(setStub.calledOnce);
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002897 assert.isTrue(setStub.calledWith(101 as never, TEST_PROJECT_NAME as never));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002898 });
2899
2900 test('_handleToggleStar called when star is tapped', () => {
2901 element._change = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002902 ...createChange(),
2903 owner: {_account_id: 1 as AccountId},
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002904 starred: false,
2905 };
2906 element._loggedIn = true;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002907 const stub = sinon.stub(element, '_handleToggleStar');
Ben Rohlfsd47eeb92020-09-25 10:29:48 +02002908 flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002909
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002910 tap(element.$.changeStar.shadowRoot!.querySelector('button')!);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002911 assert.isTrue(stub.called);
2912 });
2913
2914 suite('gr-reporting tests', () => {
2915 setup(() => {
2916 element._patchRange = {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002917 basePatchNum: ParentPatchSetNum,
2918 patchNum: 1 as PatchSetNum,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002919 };
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002920 sinon.stub(element, '_getChangeDetail').returns(Promise.resolve(false));
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02002921 sinon.stub(element, '_getProjectConfig').returns(Promise.resolve());
2922 sinon.stub(element, '_reloadComments').returns(Promise.resolve());
2923 sinon.stub(element, '_getMergeability').returns(Promise.resolve());
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002924 sinon.stub(element, '_getLatestCommitMessage').returns(Promise.resolve());
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002925 sinon
2926 .stub(element, '_reloadPatchNumDependentResources')
Dhruv Srivastava09a1b5a2021-01-20 09:28:15 +01002927 .returns(Promise.resolve([undefined, undefined, undefined]));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002928 });
2929
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002930 test("don't report changeDisplayed on reply", done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002931 const changeDisplayStub = sinon.stub(
2932 element.reporting,
2933 'changeDisplayed'
2934 );
2935 const changeFullyLoadedStub = sinon.stub(
2936 element.reporting,
2937 'changeFullyLoaded'
2938 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002939 element._handleReplySent();
2940 flush(() => {
2941 assert.isFalse(changeDisplayStub.called);
2942 assert.isFalse(changeFullyLoadedStub.called);
2943 done();
2944 });
2945 });
2946
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +01002947 test('report changeDisplayed on _paramsChanged', done => {
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002948 const changeDisplayStub = sinon.stub(
2949 element.reporting,
2950 'changeDisplayed'
2951 );
2952 const changeFullyLoadedStub = sinon.stub(
2953 element.reporting,
2954 'changeFullyLoaded'
2955 );
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002956 element._paramsChanged({
Dmitrii Filippov78448cd2020-10-26 17:39:11 +01002957 ...createAppElementChangeViewParams(),
2958 changeNum: 101 as NumericChangeId,
2959 project: TEST_PROJECT_NAME,
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01002960 });
2961 flush(() => {
2962 assert.isTrue(changeDisplayStub.called);
2963 assert.isTrue(changeFullyLoadedStub.called);
2964 done();
2965 });
2966 });
2967 });
2968});