blob: 6facdcaeffae35b1c69f247990f5163825f3836e [file] [log] [blame]
Dmitrii Filippov06117e82020-06-25 13:26:55 +02001/**
2 * @license
3 * Copyright (C) 2018 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 */
Ole Rehmsene5de55e2018-08-23 16:52:57 +020017
Dmitrii Filippov06117e82020-06-25 13:26:55 +020018import '../../../test/common-test-setup-karma.js';
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010019import './gr-diff-host.js';
Chris Poucet1ffbbd12021-10-05 18:33:36 +000020
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010021import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
Chris Poucet1ffbbd12021-10-05 18:33:36 +000022import {createDefaultDiffPrefs, Side} from '../../../constants/constants.js';
Dhruv Srivastava89fd52f2021-08-03 11:05:01 +020023import {_testOnly_resetState} from '../../../services/comments/comments-model.js';
Chris Poucet1ffbbd12021-10-05 18:33:36 +000024import {createChange, createComment, createCommentThread} from '../../../test/test-data-generators.js';
25import {addListenerForTest, mockPromise, stubRestApi} from '../../../test/test-utils.js';
26import {EditPatchSetNum, ParentPatchSetNum} from '../../../types/common.js';
27import {CoverageType} from '../../../types/types.js';
28import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
29import {GrDiffBuilderImage} from '../gr-diff-builder/gr-diff-builder-image.js';
Dmitrii Filippov9fcdcb72020-04-07 13:26:52 +020030
Dmitrii Filippov06117e82020-06-25 13:26:55 +020031const basicFixture = fixtureFromElement('gr-diff-host');
32
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010033suite('gr-diff-host tests', () => {
34 let element;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +020035
Ole Rehmsen4637b802021-02-04 13:28:16 +010036 let loggedIn;
Ole Rehmsene5de55e2018-08-23 16:52:57 +020037
Ole Rehmsen4637b802021-02-04 13:28:16 +010038 setup(async () => {
39 loggedIn = false;
40 stubRestApi('getLoggedIn').callsFake(() => Promise.resolve(loggedIn));
Dmitrii Filippov06117e82020-06-25 13:26:55 +020041 element = basicFixture.instantiate();
Ben Rohlfs1d487062020-09-26 11:26:03 +020042 element.changeNum = 123;
43 element.path = 'some/path';
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +020044 sinon.stub(element.reporting, 'time');
45 sinon.stub(element.reporting, 'timeEnd');
Dhruv Srivastava89fd52f2021-08-03 11:05:01 +020046 _testOnly_resetState();
Ole Rehmsen4637b802021-02-04 13:28:16 +010047 await flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010048 });
49
50 suite('plugin layers', () => {
51 const pluginLayers = [{annotate: () => {}}, {annotate: () => {}}];
Ole Rehmsene5de55e2018-08-23 16:52:57 +020052 setup(() => {
Dmitrii Filippov06117e82020-06-25 13:26:55 +020053 element = basicFixture.instantiate();
Ben Rohlfs70cbedc2021-02-03 23:03:21 +010054 sinon.stub(element.jsAPI, 'getDiffLayers').returns(pluginLayers);
Ben Rohlfs1d487062020-09-26 11:26:03 +020055 element.changeNum = 123;
56 element.path = 'some/path';
Ole Rehmsene5de55e2018-08-23 16:52:57 +020057 });
Ben Rohlfs2b7159d2021-02-01 16:04:36 +010058 test('plugin layers requested', async () => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010059 element.patchRange = {};
Dmitrii Filippov0695d402020-10-22 16:57:57 +020060 element.change = createChange();
Ben Rohlfs2b7159d2021-02-01 16:04:36 +010061 stubRestApi('getDiff').returns(Promise.resolve({content: []}));
62 await element.reload();
Ben Rohlfs70cbedc2021-02-03 23:03:21 +010063 assert(element.jsAPI.getDiffLayers.called);
Ole Rehmsene5de55e2018-08-23 16:52:57 +020064 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010065 });
Ole Rehmsene5de55e2018-08-23 16:52:57 +020066
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010067 suite('render reporting', () => {
Chris Pouceta2e173e2021-08-31 01:04:04 +000068 test('starts total and content timer on render-start', () => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010069 element.dispatchEvent(
70 new CustomEvent('render-start', {bubbles: true, composed: true}));
Milutin Kristoficda88b332020-03-24 10:19:12 +010071 assert.isTrue(element.reporting.time.calledWithExactly(
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010072 'Diff Total Render'));
Milutin Kristoficda88b332020-03-24 10:19:12 +010073 assert.isTrue(element.reporting.time.calledWithExactly(
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010074 'Diff Content Render'));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010075 });
76
77 test('ends content timer on render-content', () => {
78 element.dispatchEvent(
79 new CustomEvent('render-content', {bubbles: true, composed: true}));
Milutin Kristoficda88b332020-03-24 10:19:12 +010080 assert.isTrue(element.reporting.timeEnd.calledWithExactly(
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010081 'Diff Content Render'));
82 });
83
Oleb0368262020-10-12 16:50:24 +020084 test('ends total and syntax timer after syntax layer', async () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +020085 sinon.stub(element.reporting, 'diffViewContentDisplayed');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010086 let notifySyntaxProcessed;
Dhruv Srivastava92ca4ef2021-03-08 13:38:01 +010087 sinon.stub(element.syntaxLayer, 'process').returns(
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +010088 new Promise(resolve => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010089 notifySyntaxProcessed = resolve;
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +010090 })
91 );
92 stubRestApi('getDiff').returns(Promise.resolve({content: []}));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010093 element.patchRange = {};
Dmitrii Filippov0695d402020-10-22 16:57:57 +020094 element.change = createChange();
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +010095 element.prefs = createDefaultDiffPrefs();
96 element.reload(true);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +010097 // Multiple cascading microtasks are scheduled.
Oleb0368262020-10-12 16:50:24 +020098 await flush();
99 notifySyntaxProcessed();
100 // Multiple cascading microtasks are scheduled.
101 await flush();
102 assert.isTrue(element.reporting.timeEnd.calledWithExactly(
103 'Diff Total Render'));
104 assert.isTrue(element.reporting.timeEnd.calledWithExactly(
105 'Diff Syntax Render'));
106 assert.isTrue(element.reporting.diffViewContentDisplayed.called);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100107 });
Mayank Kumar41b0f952019-10-03 18:04:08 -0700108
Oleb0368262020-10-12 16:50:24 +0200109 test('ends total timer w/ no syntax layer processing', async () => {
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +0100110 stubRestApi('getDiff').returns(Promise.resolve({content: []}));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100111 element.patchRange = {};
Dmitrii Filippov0695d402020-10-22 16:57:57 +0200112 element.change = createChange();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100113 element.reload();
114 // Multiple cascading microtasks are scheduled.
Oleb0368262020-10-12 16:50:24 +0200115 await flush();
Ben Rohlfsf92d3b52021-03-10 23:13:03 +0100116 await flush();
Oleb0368262020-10-12 16:50:24 +0200117 // Reporting can be called with other parameters (ex. PluginsLoaded),
118 // but only 'Diff Total Render' is important in this test.
119 assert.equal(
120 element.reporting.timeEnd.getCalls()
121 .filter(call => call.calledWithExactly('Diff Total Render'))
122 .length,
123 1);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100124 });
125
Oleb0368262020-10-12 16:50:24 +0200126 test('completes reload promise after syntax layer processing', async () => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100127 let notifySyntaxProcessed;
Dhruv Srivastava92ca4ef2021-03-08 13:38:01 +0100128 sinon.stub(element.syntaxLayer, 'process').returns(new Promise(
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100129 resolve => {
130 notifySyntaxProcessed = resolve;
131 }));
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +0100132 stubRestApi('getDiff').returns(
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100133 Promise.resolve({content: []}));
134 element.patchRange = {};
Dmitrii Filippov0695d402020-10-22 16:57:57 +0200135 element.change = createChange();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100136 let reloadComplete = false;
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +0100137 element.prefs = createDefaultDiffPrefs();
138 element.reload().then(() => {
139 reloadComplete = true;
140 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100141 // Multiple cascading microtasks are scheduled.
Oleb0368262020-10-12 16:50:24 +0200142 await flush();
143 assert.isFalse(reloadComplete);
144 notifySyntaxProcessed();
145 // Assert after the notification task is processed.
146 await flush();
147 assert.isTrue(reloadComplete);
Ole Rehmsen578f9212019-04-11 23:58:56 +0200148 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100149 });
Ole Rehmsen578f9212019-04-11 23:58:56 +0200150
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100151 test('reload() cancels before network resolves', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200152 const cancelStub = sinon.stub(element.$.diff, 'cancel');
Ole Rehmsenb1a79672018-08-27 22:43:38 +0200153
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100154 // Stub the network calls into requests that never resolve.
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200155 sinon.stub(element, '_getDiff').callsFake(() => new Promise(() => {}));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100156 element.patchRange = {};
Dmitrii Filippov0695d402020-10-22 16:57:57 +0200157 element.change = createChange();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100158
Olee3ea65d2020-10-13 14:59:08 +0200159 // Needs to be set to something first for it to cancel.
160 element.diff = {
161 content: [{
162 a: ['foo'],
163 }],
164 };
165
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100166 element.reload();
167 assert.isTrue(cancelStub.called);
168 });
169
Frank Bordend7c299f2021-05-05 14:18:09 +0200170 test('reload() loads files weblinks', async () => {
Ole Rehmsen4637b802021-02-04 13:28:16 +0100171 element.change = createChange();
172 const weblinksStub = sinon.stub(GerritNav, '_generateWeblinks')
173 .returns({name: 'stubb', url: '#s'});
174 stubRestApi('getDiff').returns(Promise.resolve({
175 content: [],
176 }));
177 element.projectName = 'test-project';
178 element.path = 'test-path';
179 element.commitRange = {baseCommit: 'test-base', commit: 'test-commit'};
180 element.patchRange = {};
Frank Bordend7c299f2021-05-05 14:18:09 +0200181
182 await element.reload();
183
184 assert.equal(weblinksStub.callCount, 3);
185 assert.deepEqual(weblinksStub.firstCall.args[0], {
186 commit: 'test-base',
187 file: 'test-path',
188 options: {
189 weblinks: undefined,
190 },
191 repo: 'test-project',
192 type: GerritNav.WeblinkType.EDIT});
193 assert.deepEqual(element.editWeblinks, [{
194 name: 'stubb', url: '#s',
195 }]);
196 assert.deepEqual(weblinksStub.secondCall.args[0], {
197 commit: 'test-base',
198 file: 'test-path',
199 options: {
200 weblinks: undefined,
201 },
202 repo: 'test-project',
203 type: GerritNav.WeblinkType.FILE});
204 assert.deepEqual(weblinksStub.thirdCall.args[0], {
205 commit: 'test-commit',
206 file: 'test-path',
207 options: {
208 weblinks: undefined,
209 },
210 repo: 'test-project',
211 type: GerritNav.WeblinkType.FILE});
212 assert.deepEqual(element.filesWeblinks, {
213 meta_a: [{name: 'stubb', url: '#s'}],
214 meta_b: [{name: 'stubb', url: '#s'}],
Ole Rehmsenb1a79672018-08-27 22:43:38 +0200215 });
Ole Rehmsen4637b802021-02-04 13:28:16 +0100216 });
Ole Rehmsenb1a79672018-08-27 22:43:38 +0200217
Chris Pouceta2e173e2021-08-31 01:04:04 +0000218 test('prefetch getDiff', async () => {
Ole Rehmsen4637b802021-02-04 13:28:16 +0100219 const diffRestApiStub = stubRestApi('getDiff')
220 .returns(Promise.resolve({content: []}));
221 element.changeNum = 123;
222 element.patchRange = {basePatchNum: 1, patchNum: 2};
223 element.path = 'file.txt';
224 element.prefetchDiff();
Chris Pouceta2e173e2021-08-31 01:04:04 +0000225 await element._getDiff();
226 assert.isTrue(diffRestApiStub.calledOnce);
Ole Rehmsen4637b802021-02-04 13:28:16 +0100227 });
228
Chris Pouceta2e173e2021-08-31 01:04:04 +0000229 test('_getDiff handles null diff responses', async () => {
Ole Rehmsen4637b802021-02-04 13:28:16 +0100230 stubRestApi('getDiff').returns(Promise.resolve(null));
231 element.changeNum = 123;
232 element.patchRange = {basePatchNum: 1, patchNum: 2};
233 element.path = 'file.txt';
Chris Pouceta2e173e2021-08-31 01:04:04 +0000234 await element._getDiff();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100235 });
236
237 test('reload resolves on error', () => {
238 const onErrStub = sinon.stub(element, '_handleGetDiffError');
239 const error = new Response(null, {ok: false, status: 500});
240 stubRestApi('getDiff').callsFake(
241 (changeNum, basePatchNum, patchNum, path, whitespace, onErr) => {
242 onErr(error);
243 });
244 element.patchRange = {};
245 return element.reload().then(() => {
246 assert.isTrue(onErrStub.calledOnce);
247 });
248 });
249
250 suite('_handleGetDiffError', () => {
251 let serverErrorStub;
252 let pageErrorStub;
253
254 setup(() => {
255 serverErrorStub = sinon.stub();
256 addListenerForTest(document, 'server-error', serverErrorStub);
257 pageErrorStub = sinon.stub();
258 addListenerForTest(document, 'page-error', pageErrorStub);
259 });
260
261 test('page error on HTTP-409', () => {
262 element._handleGetDiffError({status: 409});
263 assert.isTrue(serverErrorStub.calledOnce);
264 assert.isFalse(pageErrorStub.called);
265 assert.isNotOk(element._errorMessage);
266 });
267
268 test('server error on non-HTTP-409', () => {
269 element._handleGetDiffError({
270 status: 500,
271 text: () => Promise.resolve(''),
272 });
273 assert.isFalse(serverErrorStub.called);
274 assert.isTrue(pageErrorStub.calledOnce);
275 assert.isNotOk(element._errorMessage);
276 });
277
278 test('error message if showLoadFailure', () => {
279 element.showLoadFailure = true;
280 element._handleGetDiffError({status: 500, statusText: 'Failure!'});
281 assert.isFalse(serverErrorStub.called);
282 assert.isFalse(pageErrorStub.called);
283 assert.equal(element._errorMessage,
284 'Encountered error when loading the diff: 500 Failure!');
285 });
286 });
287
288 suite('image diffs', () => {
289 let mockFile1;
290 let mockFile2;
291 setup(() => {
292 mockFile1 = {
293 body: 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
294 'wsAAAAAAAAAAAAAAAAA/w==',
295 type: 'image/bmp',
296 };
297 mockFile2 = {
298 body: 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
299 'wsAAAAAAAAAAAAA/////w==',
300 type: 'image/bmp',
301 };
302
303 element.patchRange = {basePatchNum: 'PARENT', patchNum: 1};
304 element.change = createChange();
305 element.comments = {
306 left: [],
307 right: [],
308 meta: {patchRange: element.patchRange},
309 };
310 });
311
Chris Pouceta2e173e2021-08-31 01:04:04 +0000312 test('renders image diffs with same file name', async () => {
Ole Rehmsen4637b802021-02-04 13:28:16 +0100313 const mockDiff = {
314 meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
315 meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg',
316 lines: 560},
317 intraline_status: 'OK',
318 change_type: 'MODIFIED',
319 diff_header: [
320 'diff --git a/carrot.jpg b/carrot.jpg',
321 'index 2adc47d..f9c2f2c 100644',
322 '--- a/carrot.jpg',
323 '+++ b/carrot.jpg',
324 'Binary files differ',
325 ],
326 content: [{skip: 66}],
327 binary: true,
328 };
329 stubRestApi('getDiff').returns(Promise.resolve(mockDiff));
330 stubRestApi('getImagesForDiff').returns(Promise.resolve({
331 baseImage: {
332 ...mockFile1,
333 _expectedType: 'image/jpeg',
334 _name: 'carrot.jpg',
335 },
336 revisionImage: {
337 ...mockFile2,
338 _expectedType: 'image/jpeg',
339 _name: 'carrot.jpg',
340 },
341 }));
342
Chris Pouceta2e173e2021-08-31 01:04:04 +0000343 const promise = mockPromise();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100344 const rendered = () => {
345 // Recognizes that it should be an image diff.
346 assert.isTrue(element.isImageDiff);
347 assert.instanceOf(
348 element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
349
350 // Left image rendered with the parent commit's version of the file.
351 const leftImage =
352 element.$.diff.$.diffTable.querySelector('td.left img');
353 const leftLabel =
354 element.$.diff.$.diffTable.querySelector('td.left label');
355 const leftLabelContent = leftLabel.querySelector('.label');
356 const leftLabelName = leftLabel.querySelector('.name');
357
358 const rightImage =
359 element.$.diff.$.diffTable.querySelector('td.right img');
360 const rightLabel = element.$.diff.$.diffTable.querySelector(
361 'td.right label');
362 const rightLabelContent = rightLabel.querySelector('.label');
363 const rightLabelName = rightLabel.querySelector('.name');
364
365 assert.isNotOk(rightLabelName);
366 assert.isNotOk(leftLabelName);
367
368 let leftLoaded = false;
369 let rightLoaded = false;
370
371 leftImage.addEventListener('load', () => {
372 assert.isOk(leftImage);
373 assert.equal(leftImage.getAttribute('src'),
Hermann Looseff98f432021-03-30 15:26:25 +0200374 'data:image/bmp;base64,' + mockFile1.body);
Ole Rehmsen4637b802021-02-04 13:28:16 +0100375 assert.equal(leftLabelContent.textContent, '1×1 image/bmp');
376 leftLoaded = true;
377 if (rightLoaded) {
378 element.removeEventListener('render', rendered);
Chris Pouceta2e173e2021-08-31 01:04:04 +0000379 promise.resolve();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100380 }
381 });
382
383 rightImage.addEventListener('load', () => {
384 assert.isOk(rightImage);
385 assert.equal(rightImage.getAttribute('src'),
Hermann Looseff98f432021-03-30 15:26:25 +0200386 'data:image/bmp;base64,' + mockFile2.body);
Ole Rehmsen4637b802021-02-04 13:28:16 +0100387 assert.equal(rightLabelContent.textContent, '1×1 image/bmp');
388
389 rightLoaded = true;
390 if (leftLoaded) {
391 element.removeEventListener('render', rendered);
Chris Pouceta2e173e2021-08-31 01:04:04 +0000392 promise.resolve();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100393 }
394 });
395 };
396
397 element.addEventListener('render', rendered);
398 element.prefs = createDefaultDiffPrefs();
399 element.reload();
Chris Pouceta2e173e2021-08-31 01:04:04 +0000400 await promise;
Ole Rehmsen4637b802021-02-04 13:28:16 +0100401 });
402
Chris Pouceta2e173e2021-08-31 01:04:04 +0000403 test('renders image diffs with a different file name', async () => {
Ole Rehmsen4637b802021-02-04 13:28:16 +0100404 const mockDiff = {
405 meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
406 meta_b: {name: 'carrot2.jpg', content_type: 'image/jpeg',
407 lines: 560},
408 intraline_status: 'OK',
409 change_type: 'MODIFIED',
410 diff_header: [
411 'diff --git a/carrot.jpg b/carrot2.jpg',
412 'index 2adc47d..f9c2f2c 100644',
413 '--- a/carrot.jpg',
414 '+++ b/carrot2.jpg',
415 'Binary files differ',
416 ],
417 content: [{skip: 66}],
418 binary: true,
419 };
420 stubRestApi('getDiff').returns(Promise.resolve(mockDiff));
421 stubRestApi('getImagesForDiff').returns(Promise.resolve({
422 baseImage: {
423 ...mockFile1,
424 _expectedType: 'image/jpeg',
425 _name: 'carrot.jpg',
426 },
427 revisionImage: {
428 ...mockFile2,
429 _expectedType: 'image/jpeg',
430 _name: 'carrot2.jpg',
431 },
432 }));
433
Chris Pouceta2e173e2021-08-31 01:04:04 +0000434 const promise = mockPromise();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100435 const rendered = () => {
436 // Recognizes that it should be an image diff.
437 assert.isTrue(element.isImageDiff);
438 assert.instanceOf(
439 element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
440
441 // Left image rendered with the parent commit's version of the file.
442 const leftImage =
443 element.$.diff.$.diffTable.querySelector('td.left img');
444 const leftLabel =
445 element.$.diff.$.diffTable.querySelector('td.left label');
446 const leftLabelContent = leftLabel.querySelector('.label');
447 const leftLabelName = leftLabel.querySelector('.name');
448
449 const rightImage =
450 element.$.diff.$.diffTable.querySelector('td.right img');
451 const rightLabel = element.$.diff.$.diffTable.querySelector(
452 'td.right label');
453 const rightLabelContent = rightLabel.querySelector('.label');
454 const rightLabelName = rightLabel.querySelector('.name');
455
456 assert.isOk(rightLabelName);
457 assert.isOk(leftLabelName);
458 assert.equal(leftLabelName.textContent, mockDiff.meta_a.name);
459 assert.equal(rightLabelName.textContent, mockDiff.meta_b.name);
460
461 let leftLoaded = false;
462 let rightLoaded = false;
463
464 leftImage.addEventListener('load', () => {
465 assert.isOk(leftImage);
466 assert.equal(leftImage.getAttribute('src'),
Hermann Looseff98f432021-03-30 15:26:25 +0200467 'data:image/bmp;base64,' + mockFile1.body);
Ole Rehmsen4637b802021-02-04 13:28:16 +0100468 assert.equal(leftLabelContent.textContent, '1×1 image/bmp');
469 leftLoaded = true;
470 if (rightLoaded) {
471 element.removeEventListener('render', rendered);
Chris Pouceta2e173e2021-08-31 01:04:04 +0000472 promise.resolve();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100473 }
474 });
475
476 rightImage.addEventListener('load', () => {
477 assert.isOk(rightImage);
478 assert.equal(rightImage.getAttribute('src'),
Hermann Looseff98f432021-03-30 15:26:25 +0200479 'data:image/bmp;base64,' + mockFile2.body);
Ole Rehmsen4637b802021-02-04 13:28:16 +0100480 assert.equal(rightLabelContent.textContent, '1×1 image/bmp');
481
482 rightLoaded = true;
483 if (leftLoaded) {
484 element.removeEventListener('render', rendered);
Chris Pouceta2e173e2021-08-31 01:04:04 +0000485 promise.resolve();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100486 }
487 });
488 };
489
490 element.addEventListener('render', rendered);
491 element.prefs = createDefaultDiffPrefs();
492 element.reload();
Chris Pouceta2e173e2021-08-31 01:04:04 +0000493 await promise;
Ole Rehmsen4637b802021-02-04 13:28:16 +0100494 });
495
Chris Pouceta2e173e2021-08-31 01:04:04 +0000496 test('renders added image', async () => {
Ole Rehmsen4637b802021-02-04 13:28:16 +0100497 const mockDiff = {
498 meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg',
499 lines: 560},
500 intraline_status: 'OK',
501 change_type: 'ADDED',
502 diff_header: [
503 'diff --git a/carrot.jpg b/carrot.jpg',
504 'index 0000000..f9c2f2c 100644',
505 '--- /dev/null',
506 '+++ b/carrot.jpg',
507 'Binary files differ',
508 ],
509 content: [{skip: 66}],
510 binary: true,
511 };
512 stubRestApi('getDiff').returns(Promise.resolve(mockDiff));
513 stubRestApi('getImagesForDiff').returns(Promise.resolve({
514 baseImage: null,
515 revisionImage: {
516 ...mockFile2,
517 _expectedType: 'image/jpeg',
518 _name: 'carrot2.jpg',
519 },
520 }));
521
Chris Pouceta2e173e2021-08-31 01:04:04 +0000522 const promise = mockPromise();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100523 element.addEventListener('render', () => {
524 // Recognizes that it should be an image diff.
525 assert.isTrue(element.isImageDiff);
526 assert.instanceOf(
527 element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
528
529 const leftImage =
530 element.$.diff.$.diffTable.querySelector('td.left img');
531 const rightImage =
532 element.$.diff.$.diffTable.querySelector('td.right img');
533
534 assert.isNotOk(leftImage);
535 assert.isOk(rightImage);
Chris Pouceta2e173e2021-08-31 01:04:04 +0000536 promise.resolve();
Milutin Kristofic890bee02020-06-10 17:12:00 +0200537 });
Ole Rehmsen4637b802021-02-04 13:28:16 +0100538
539 element.prefs = createDefaultDiffPrefs();
540 element.reload();
Chris Pouceta2e173e2021-08-31 01:04:04 +0000541 await promise;
Milutin Kristofic890bee02020-06-10 17:12:00 +0200542 });
543
Chris Pouceta2e173e2021-08-31 01:04:04 +0000544 test('renders removed image', async () => {
Ole Rehmsen4637b802021-02-04 13:28:16 +0100545 const mockDiff = {
546 meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg',
547 lines: 560},
548 intraline_status: 'OK',
549 change_type: 'DELETED',
550 diff_header: [
551 'diff --git a/carrot.jpg b/carrot.jpg',
552 'index f9c2f2c..0000000 100644',
553 '--- a/carrot.jpg',
554 '+++ /dev/null',
555 'Binary files differ',
556 ],
557 content: [{skip: 66}],
558 binary: true,
559 };
560 stubRestApi('getDiff').returns(Promise.resolve(mockDiff));
561 stubRestApi('getImagesForDiff').returns(Promise.resolve({
562 baseImage: {
563 ...mockFile1,
564 _expectedType: 'image/jpeg',
565 _name: 'carrot.jpg',
566 },
567 revisionImage: null,
568 }));
569
Chris Pouceta2e173e2021-08-31 01:04:04 +0000570 const promise = mockPromise();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100571 element.addEventListener('render', () => {
572 // Recognizes that it should be an image diff.
573 assert.isTrue(element.isImageDiff);
574 assert.instanceOf(
575 element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
576
577 const leftImage =
578 element.$.diff.$.diffTable.querySelector('td.left img');
579 const rightImage =
580 element.$.diff.$.diffTable.querySelector('td.right img');
581
582 assert.isOk(leftImage);
583 assert.isNotOk(rightImage);
Chris Pouceta2e173e2021-08-31 01:04:04 +0000584 promise.resolve();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100585 });
586
587 element.prefs = createDefaultDiffPrefs();
588 element.reload();
Chris Pouceta2e173e2021-08-31 01:04:04 +0000589 await promise;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100590 });
591
Chris Pouceta2e173e2021-08-31 01:04:04 +0000592 test('does not render disallowed image type', async () => {
Ole Rehmsen4637b802021-02-04 13:28:16 +0100593 const mockDiff = {
594 meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg-evil',
595 lines: 560},
596 intraline_status: 'OK',
597 change_type: 'DELETED',
598 diff_header: [
599 'diff --git a/carrot.jpg b/carrot.jpg',
600 'index f9c2f2c..0000000 100644',
601 '--- a/carrot.jpg',
602 '+++ /dev/null',
603 'Binary files differ',
604 ],
605 content: [{skip: 66}],
606 binary: true,
607 };
608 mockFile1.type = 'image/jpeg-evil';
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100609
Ole Rehmsen4637b802021-02-04 13:28:16 +0100610 stubRestApi('getDiff').returns(Promise.resolve(mockDiff));
611 stubRestApi('getImagesForDiff').returns(Promise.resolve({
612 baseImage: {
613 ...mockFile1,
614 _expectedType: 'image/jpeg',
615 _name: 'carrot.jpg',
616 },
617 revisionImage: null,
618 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100619
Chris Pouceta2e173e2021-08-31 01:04:04 +0000620 const promise = mockPromise();
Ole Rehmsen4637b802021-02-04 13:28:16 +0100621 element.addEventListener('render', () => {
622 // Recognizes that it should be an image diff.
623 assert.isTrue(element.isImageDiff);
624 assert.instanceOf(
625 element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
626 const leftImage =
627 element.$.diff.$.diffTable.querySelector('td.left img');
628 assert.isNotOk(leftImage);
Chris Pouceta2e173e2021-08-31 01:04:04 +0000629 promise.resolve();
Ben Rohlfsea4cb7e2020-12-03 16:00:00 +0100630 });
631
Ole Rehmsen4637b802021-02-04 13:28:16 +0100632 element.prefs = createDefaultDiffPrefs();
633 element.reload();
Chris Pouceta2e173e2021-08-31 01:04:04 +0000634 await promise;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100635 });
636 });
637
Ole Rehmsenef0d17b2021-02-04 14:42:46 +0100638 test('cannot create comments when not logged in', () => {
639 element.patchRange = {
640 basePatchNum: 'PARENT',
641 patchNum: 2,
642 };
643 const showAuthRequireSpy = sinon.spy();
644 element.addEventListener('show-auth-required', showAuthRequireSpy);
645
646 element.dispatchEvent(new CustomEvent('create-comment', {
647 detail: {
648 lineNum: 3,
649 side: Side.LEFT,
650 path: '/p',
651 },
652 }));
653
654 const threads = dom(element.$.diff)
655 .queryDistributedElements('gr-comment-thread');
656
657 assert.equal(threads.length, 0);
658
659 assert.isTrue(showAuthRequireSpy.called);
660 });
661
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100662 test('delegates cancel()', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200663 const stub = sinon.stub(element.$.diff, 'cancel');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100664 element.patchRange = {};
Olee3ea65d2020-10-13 14:59:08 +0200665 element.cancel();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100666 assert.isTrue(stub.calledOnce);
667 assert.equal(stub.lastCall.args.length, 0);
668 });
669
670 test('delegates getCursorStops()', () => {
671 const returnValue = [document.createElement('b')];
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200672 const stub = sinon.stub(element.$.diff, 'getCursorStops')
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100673 .returns(returnValue);
674 assert.equal(element.getCursorStops(), returnValue);
675 assert.isTrue(stub.calledOnce);
676 assert.equal(stub.lastCall.args.length, 0);
677 });
678
679 test('delegates isRangeSelected()', () => {
680 const returnValue = true;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200681 const stub = sinon.stub(element.$.diff, 'isRangeSelected')
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100682 .returns(returnValue);
683 assert.equal(element.isRangeSelected(), returnValue);
684 assert.isTrue(stub.calledOnce);
685 assert.equal(stub.lastCall.args.length, 0);
686 });
687
688 test('delegates toggleLeftDiff()', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200689 const stub = sinon.stub(element.$.diff, 'toggleLeftDiff');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100690 element.toggleLeftDiff();
691 assert.isTrue(stub.calledOnce);
692 assert.equal(stub.lastCall.args.length, 0);
693 });
694
695 suite('blame', () => {
Ole Rehmsen4637b802021-02-04 13:28:16 +0100696 setup(async () => {
Dmitrii Filippov06117e82020-06-25 13:26:55 +0200697 element = basicFixture.instantiate();
Ben Rohlfs1d487062020-09-26 11:26:03 +0200698 element.changeNum = 123;
699 element.path = 'some/path';
Ole Rehmsen4637b802021-02-04 13:28:16 +0100700 await flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100701 });
702
703 test('clearBlame', () => {
704 element._blame = [];
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200705 const setBlameSpy = sinon.spy(element.$.diff.$.diffBuilder, 'setBlame');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100706 element.clearBlame();
707 assert.isNull(element._blame);
708 assert.isTrue(setBlameSpy.calledWithExactly(null));
709 assert.equal(element.isBlameLoaded, false);
710 });
711
712 test('loadBlame', () => {
713 const mockBlame = [{id: 'commit id', ranges: [{start: 1, end: 2}]}];
714 const showAlertStub = sinon.stub();
715 element.addEventListener('show-alert', showAlertStub);
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +0100716 const getBlameStub = stubRestApi('getBlame')
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100717 .returns(Promise.resolve(mockBlame));
718 element.changeNum = 42;
719 element.patchRange = {patchNum: 5, basePatchNum: 4};
720 element.path = 'foo/bar.baz';
721 return element.loadBlame().then(() => {
722 assert.isTrue(getBlameStub.calledWithExactly(
723 42, 5, 'foo/bar.baz', true));
724 assert.isFalse(showAlertStub.called);
725 assert.equal(element._blame, mockBlame);
726 assert.equal(element.isBlameLoaded, true);
Ole Rehmsenb1a79672018-08-27 22:43:38 +0200727 });
Ole Rehmsene5de55e2018-08-23 16:52:57 +0200728 });
Wyatt Allenefc81212018-08-20 16:40:48 -0700729
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100730 test('loadBlame empty', () => {
731 const mockBlame = [];
732 const showAlertStub = sinon.stub();
733 element.addEventListener('show-alert', showAlertStub);
Ben Rohlfs3a6ff7e2021-01-18 14:08:39 +0100734 stubRestApi('getBlame')
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100735 .returns(Promise.resolve(mockBlame));
736 element.changeNum = 42;
737 element.patchRange = {patchNum: 5, basePatchNum: 4};
738 element.path = 'foo/bar.baz';
739 return element.loadBlame()
740 .then(() => {
741 assert.isTrue(false, 'Promise should not resolve');
742 })
743 .catch(() => {
744 assert.isTrue(showAlertStub.calledOnce);
745 assert.isNull(element._blame);
746 assert.equal(element.isBlameLoaded, false);
747 });
748 });
749 });
750
751 test('getThreadEls() returns .comment-threads', () => {
752 const threadEl = document.createElement('div');
753 threadEl.className = 'comment-thread';
Tao Zhou93a4ed72020-08-21 09:52:02 +0200754 element.$.diff.appendChild(threadEl);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100755 assert.deepEqual(element.getThreadEls(), [threadEl]);
756 });
757
758 test('delegates addDraftAtLine(el)', () => {
759 const param0 = document.createElement('b');
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200760 const stub = sinon.stub(element.$.diff, 'addDraftAtLine');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100761 element.addDraftAtLine(param0);
762 assert.isTrue(stub.calledOnce);
763 assert.equal(stub.lastCall.args.length, 1);
764 assert.equal(stub.lastCall.args[0], param0);
765 });
766
767 test('delegates clearDiffContent()', () => {
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200768 const stub = sinon.stub(element.$.diff, 'clearDiffContent');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100769 element.clearDiffContent();
770 assert.isTrue(stub.calledOnce);
771 assert.equal(stub.lastCall.args.length, 0);
772 });
773
Frank Borden401c2b62021-02-11 17:14:10 -0800774 test('delegates toggleAllContext()', () => {
775 const stub = sinon.stub(element.$.diff, 'toggleAllContext');
776 element.toggleAllContext();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100777 assert.isTrue(stub.calledOnce);
778 assert.equal(stub.lastCall.args.length, 0);
779 });
780
781 test('passes in changeNum', () => {
Ben Rohlfs1d487062020-09-26 11:26:03 +0200782 element.changeNum = 12345;
783 assert.equal(element.$.diff.changeNum, 12345);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100784 });
785
786 test('passes in noAutoRender', () => {
787 const value = true;
788 element.noAutoRender = value;
789 assert.equal(element.$.diff.noAutoRender, value);
790 });
791
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100792 test('passes in path', () => {
793 const value = 'some/file/path';
794 element.path = value;
795 assert.equal(element.$.diff.path, value);
796 });
797
798 test('passes in prefs', () => {
799 const value = {};
800 element.prefs = value;
801 assert.equal(element.$.diff.prefs, value);
802 });
803
804 test('passes in changeNum', () => {
Ben Rohlfs1d487062020-09-26 11:26:03 +0200805 element.changeNum = 12345;
806 assert.equal(element.$.diff.changeNum, 12345);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100807 });
808
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100809 test('passes in displayLine', () => {
810 const value = true;
811 element.displayLine = value;
812 assert.equal(element.$.diff.displayLine, value);
813 });
814
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100815 test('passes in hidden', () => {
816 const value = true;
817 element.hidden = value;
818 assert.equal(element.$.diff.hidden, value);
819 assert.isNotNull(element.getAttribute('hidden'));
820 });
821
822 test('passes in noRenderOnPrefsChange', () => {
823 const value = true;
824 element.noRenderOnPrefsChange = value;
825 assert.equal(element.$.diff.noRenderOnPrefsChange, value);
826 });
827
828 test('passes in lineWrapping', () => {
829 const value = true;
830 element.lineWrapping = value;
831 assert.equal(element.$.diff.lineWrapping, value);
832 });
833
834 test('passes in viewMode', () => {
835 const value = 'SIDE_BY_SIDE';
836 element.viewMode = value;
837 assert.equal(element.$.diff.viewMode, value);
838 });
839
840 test('passes in lineOfInterest', () => {
841 const value = {number: 123, leftSide: true};
842 element.lineOfInterest = value;
843 assert.equal(element.$.diff.lineOfInterest, value);
844 });
845
846 suite('_reportDiff', () => {
847 let reportStub;
848
Ole Rehmsen4637b802021-02-04 13:28:16 +0100849 setup(async () => {
Dmitrii Filippov06117e82020-06-25 13:26:55 +0200850 element = basicFixture.instantiate();
Ben Rohlfs1d487062020-09-26 11:26:03 +0200851 element.changeNum = 123;
Tao Zhoue0d7c652020-05-04 11:32:05 +0200852 element.path = 'file.txt';
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100853 element.patchRange = {basePatchNum: 1};
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +0200854 reportStub = sinon.stub(element.reporting, 'reportInteraction');
Ole Rehmsen4637b802021-02-04 13:28:16 +0100855 await flush();
Dhruv Srivastavab84bf912020-02-03 19:05:59 +0100856 });
857
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100858 test('null and content-less', () => {
859 element._reportDiff(null);
860 assert.isFalse(reportStub.called);
Ole Rehmsen8c8ce2d2018-10-12 16:20:57 +0200861
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100862 element._reportDiff({});
863 assert.isFalse(reportStub.called);
Ole Rehmsen8c8ce2d2018-10-12 16:20:57 +0200864 });
865
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100866 test('diff w/ no delta', () => {
867 const diff = {
868 content: [
869 {ab: ['foo', 'bar']},
870 {ab: ['baz', 'foo']},
871 ],
872 };
873 element._reportDiff(diff);
874 assert.isTrue(reportStub.calledOnce);
875 assert.equal(reportStub.lastCall.args[0], 'rebase-percent-zero');
876 assert.isUndefined(reportStub.lastCall.args[1]);
877 });
878
879 test('diff w/ no rebase delta', () => {
880 const diff = {
881 content: [
882 {ab: ['foo', 'bar']},
883 {a: ['baz', 'foo']},
884 {ab: ['foo', 'bar']},
885 {a: ['baz', 'foo'], b: ['bar', 'baz']},
886 {ab: ['foo', 'bar']},
887 {b: ['baz', 'foo']},
888 {ab: ['foo', 'bar']},
889 ],
890 };
891 element._reportDiff(diff);
892 assert.isTrue(reportStub.calledOnce);
893 assert.equal(reportStub.lastCall.args[0], 'rebase-percent-zero');
894 assert.isUndefined(reportStub.lastCall.args[1]);
895 });
896
897 test('diff w/ some rebase delta', () => {
898 const diff = {
899 content: [
900 {ab: ['foo', 'bar']},
901 {a: ['baz', 'foo'], due_to_rebase: true},
902 {ab: ['foo', 'bar']},
903 {a: ['baz', 'foo'], b: ['bar', 'baz']},
904 {ab: ['foo', 'bar']},
905 {b: ['baz', 'foo'], due_to_rebase: true},
906 {ab: ['foo', 'bar']},
907 {a: ['baz', 'foo']},
908 ],
909 };
910 element._reportDiff(diff);
911 assert.isTrue(reportStub.calledOnce);
912 assert.isTrue(reportStub.calledWith(
913 'rebase-percent-nonzero',
914 {percentRebaseDelta: 50}
915 ));
916 });
917
918 test('diff w/ all rebase delta', () => {
919 const diff = {content: [{
920 a: ['foo', 'bar'],
921 b: ['baz', 'foo'],
922 due_to_rebase: true,
923 }]};
924 element._reportDiff(diff);
925 assert.isTrue(reportStub.calledOnce);
926 assert.isTrue(reportStub.calledWith(
927 'rebase-percent-nonzero',
928 {percentRebaseDelta: 100}
929 ));
930 });
931
932 test('diff against parent event', () => {
933 element.patchRange.basePatchNum = 'PARENT';
934 const diff = {content: [{
935 a: ['foo', 'bar'],
936 b: ['baz', 'foo'],
937 }]};
938 element._reportDiff(diff);
939 assert.isTrue(reportStub.calledOnce);
940 assert.equal(reportStub.lastCall.args[0], 'diff-against-parent');
941 assert.isUndefined(reportStub.lastCall.args[1]);
942 });
943 });
944
Ole Rehmsene5653b32021-01-29 13:30:34 +0100945 suite('create-comment', () => {
Ole Rehmsenef0d17b2021-02-04 14:42:46 +0100946 setup(async () => {
947 loggedIn = true;
Ben Rohlfs5f520da2021-03-10 14:58:43 +0100948 element.connectedCallback();
Ole Rehmsenef0d17b2021-02-04 14:42:46 +0100949 await flush();
950 });
951
Ole Rehmsene5653b32021-01-29 13:30:34 +0100952 test('creates comments if they do not exist yet', () => {
953 const diffSide = Side.LEFT;
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +0100954 element.patchRange = {
955 basePatchNum: 'PARENT',
956 patchNum: 2,
957 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100958
Ole Rehmsene5653b32021-01-29 13:30:34 +0100959 element.dispatchEvent(new CustomEvent('create-comment', {
960 detail: {
Ole Rehmsene5653b32021-01-29 13:30:34 +0100961 lineNum: 3,
962 side: diffSide,
Ole Rehmsene5653b32021-01-29 13:30:34 +0100963 path: '/p',
964 },
965 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100966
Ole Rehmsene5653b32021-01-29 13:30:34 +0100967 let threads = dom(element.$.diff)
968 .queryDistributedElements('gr-comment-thread');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100969
Ole Rehmsene5653b32021-01-29 13:30:34 +0100970 assert.equal(threads.length, 1);
971 assert.equal(threads[0].diffSide, diffSide);
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +0100972 assert.isTrue(threads[0].isOnParent);
Ole Rehmsene5653b32021-01-29 13:30:34 +0100973 assert.equal(threads[0].range, undefined);
974 assert.equal(threads[0].patchNum, 2);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100975
Ole Rehmsene5653b32021-01-29 13:30:34 +0100976 // Try to fetch a thread with a different range.
977 const range = {
978 start_line: 1,
979 start_character: 1,
980 end_line: 1,
981 end_character: 3,
982 };
Ole Rehmsenfa242852021-01-29 11:02:25 +0100983 element.patchRange = {
984 basePatchNum: 'PARENT',
985 patchNum: 3,
986 };
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100987
Ole Rehmsene5653b32021-01-29 13:30:34 +0100988 element.dispatchEvent(new CustomEvent('create-comment', {
989 detail: {
Ole Rehmsene5653b32021-01-29 13:30:34 +0100990 lineNum: 1,
991 side: diffSide,
Ole Rehmsene5653b32021-01-29 13:30:34 +0100992 path: '/p',
993 range,
994 },
995 }));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100996
Ole Rehmsene5653b32021-01-29 13:30:34 +0100997 threads = dom(element.$.diff)
998 .queryDistributedElements('gr-comment-thread');
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100999
Ole Rehmsene5653b32021-01-29 13:30:34 +01001000 assert.equal(threads.length, 2);
1001 assert.equal(threads[1].diffSide, diffSide);
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +01001002 assert.isTrue(threads[0].isOnParent);
Ole Rehmsene5653b32021-01-29 13:30:34 +01001003 assert.equal(threads[1].range, range);
1004 assert.equal(threads[1].patchNum, 3);
1005 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001006
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +01001007 test('should not be on parent if on the right', () => {
1008 element.patchRange = {
1009 basePatchNum: 2,
1010 patchNum: 3,
1011 };
1012
1013 element.dispatchEvent(new CustomEvent('create-comment', {
1014 detail: {
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +01001015 side: Side.RIGHT,
1016 },
1017 }));
1018
1019 const thread = dom(element.$.diff)
1020 .queryDistributedElements('gr-comment-thread')[0];
1021
1022 assert.isFalse(thread.isOnParent);
1023 });
1024
1025 test('should be on parent if right and base is PARENT', () => {
1026 element.patchRange = {
1027 basePatchNum: 'PARENT',
1028 patchNum: 3,
1029 };
1030
1031 element.dispatchEvent(new CustomEvent('create-comment', {
1032 detail: {
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +01001033 side: Side.LEFT,
1034 },
1035 }));
1036
1037 const thread = dom(element.$.diff)
1038 .queryDistributedElements('gr-comment-thread')[0];
1039
1040 assert.isTrue(thread.isOnParent);
1041 });
1042
1043 test('should be on parent if right and base negative', () => {
1044 element.patchRange = {
1045 basePatchNum: -2, // merge parents have negative numbers
1046 patchNum: 3,
1047 };
1048
1049 element.dispatchEvent(new CustomEvent('create-comment', {
1050 detail: {
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +01001051 side: Side.LEFT,
1052 },
1053 }));
1054
1055 const thread = dom(element.$.diff)
1056 .queryDistributedElements('gr-comment-thread')[0];
1057
1058 assert.isTrue(thread.isOnParent);
1059 });
1060
1061 test('should not be on parent otherwise', () => {
1062 element.patchRange = {
1063 basePatchNum: 2, // merge parents have negative numbers
1064 patchNum: 3,
1065 };
1066
1067 element.dispatchEvent(new CustomEvent('create-comment', {
1068 detail: {
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +01001069 side: Side.LEFT,
1070 },
1071 }));
1072
1073 const thread = dom(element.$.diff)
1074 .queryDistributedElements('gr-comment-thread')[0];
1075
1076 assert.isFalse(thread.isOnParent);
1077 });
1078
Ole Rehmsene5653b32021-01-29 13:30:34 +01001079 test('thread should use old file path if first created ' +
1080 'on patch set (left) before renaming', () => {
1081 const diffSide = Side.LEFT;
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +01001082 element.patchRange = {
1083 basePatchNum: 2,
1084 patchNum: 3,
1085 };
Ole Rehmsene5653b32021-01-29 13:30:34 +01001086 element.file = {basePath: 'file_renamed.txt', path: element.path};
Tao Zhoue0d7c652020-05-04 11:32:05 +02001087
Ole Rehmsene5653b32021-01-29 13:30:34 +01001088 element.dispatchEvent(new CustomEvent('create-comment', {
1089 detail: {
Ole Rehmsene5653b32021-01-29 13:30:34 +01001090 side: diffSide,
Ole Rehmsene5653b32021-01-29 13:30:34 +01001091 path: '/p',
1092 },
1093 }));
Tao Zhoue0d7c652020-05-04 11:32:05 +02001094
Ole Rehmsene5653b32021-01-29 13:30:34 +01001095 const threads = dom(element.$.diff)
1096 .queryDistributedElements('gr-comment-thread');
Tao Zhoue0d7c652020-05-04 11:32:05 +02001097
Ole Rehmsene5653b32021-01-29 13:30:34 +01001098 assert.equal(threads.length, 1);
1099 assert.equal(threads[0].diffSide, diffSide);
1100 assert.equal(threads[0].path, element.file.basePath);
1101 });
Tao Zhoue0d7c652020-05-04 11:32:05 +02001102
Ole Rehmsene5653b32021-01-29 13:30:34 +01001103 test('thread should use new file path if first created' +
1104 'on patch set (right) after renaming', () => {
1105 const diffSide = Side.RIGHT;
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +01001106 element.patchRange = {
1107 basePatchNum: 2,
1108 patchNum: 3,
1109 };
Ole Rehmsene5653b32021-01-29 13:30:34 +01001110 element.file = {basePath: 'file_renamed.txt', path: element.path};
Tao Zhoue0d7c652020-05-04 11:32:05 +02001111
Ole Rehmsene5653b32021-01-29 13:30:34 +01001112 element.dispatchEvent(new CustomEvent('create-comment', {
1113 detail: {
Ole Rehmsene5653b32021-01-29 13:30:34 +01001114 side: diffSide,
Ole Rehmsene5653b32021-01-29 13:30:34 +01001115 path: '/p',
1116 },
1117 }));
Tao Zhoue0d7c652020-05-04 11:32:05 +02001118
Ole Rehmsene5653b32021-01-29 13:30:34 +01001119 const threads = dom(element.$.diff)
1120 .queryDistributedElements('gr-comment-thread');
Tao Zhoue0d7c652020-05-04 11:32:05 +02001121
Ole Rehmsene5653b32021-01-29 13:30:34 +01001122 assert.equal(threads.length, 1);
1123 assert.equal(threads[0].diffSide, diffSide);
1124 assert.equal(threads[0].path, element.file.path);
1125 });
Tao Zhoue0d7c652020-05-04 11:32:05 +02001126
Dhruv Srivastava3b90e052021-10-05 12:11:05 +01001127 test('multiple threads created on the same range', () => {
1128 element.patchRange = {
1129 basePatchNum: 2,
1130 patchNum: 3,
1131 };
1132 element.file = {basePath: 'file_renamed.txt', path: element.path};
1133
1134 const comment = createComment();
1135 comment.range = {
1136 start_line: 1,
1137 start_character: 1,
1138 end_line: 2,
1139 end_character: 2,
1140 };
1141 const thread = createCommentThread([comment]);
1142 element.threads = [thread];
1143
1144 let threads = dom(element.$.diff)
1145 .queryDistributedElements('gr-comment-thread');
1146
1147 assert.equal(threads.length, 1);
Dhruv Srivastava3b90e052021-10-05 12:11:05 +01001148 element.threads= [...element.threads, thread];
1149
1150 threads = dom(element.$.diff)
1151 .queryDistributedElements('gr-comment-thread');
Dhruv Srivastava3ba43512021-10-07 17:04:11 +01001152 // Threads have same rootId so element is reused
1153 assert.equal(threads.length, 1);
1154
1155 const newThread = {...thread};
1156 newThread.rootId = 'differentRootId';
1157 element.threads= [...element.threads, newThread];
1158 threads = dom(element.$.diff)
1159 .queryDistributedElements('gr-comment-thread');
1160 // New thread has a different rootId
Dhruv Srivastava3b90e052021-10-05 12:11:05 +01001161 assert.equal(threads.length, 2);
1162 });
1163
Ole Rehmsene5653b32021-01-29 13:30:34 +01001164 test('thread should use new file path if first created' +
1165 'on patch set (left) but is base', () => {
1166 const diffSide = Side.LEFT;
Ole Rehmsen2a1c47f2021-01-29 10:52:12 +01001167 element.patchRange = {
1168 basePatchNum: 'PARENT',
1169 patchNum: 3,
1170 };
Ole Rehmsene5653b32021-01-29 13:30:34 +01001171 element.file = {basePath: 'file_renamed.txt', path: element.path};
Tao Zhoue0d7c652020-05-04 11:32:05 +02001172
Ole Rehmsene5653b32021-01-29 13:30:34 +01001173 element.dispatchEvent(new CustomEvent('create-comment', {
1174 detail: {
Ole Rehmsene5653b32021-01-29 13:30:34 +01001175 side: diffSide,
Ole Rehmsene5653b32021-01-29 13:30:34 +01001176 path: '/p',
Ole Rehmsene5653b32021-01-29 13:30:34 +01001177 },
1178 }));
Tao Zhoue0d7c652020-05-04 11:32:05 +02001179
Chris Poucet1ffbbd12021-10-05 18:33:36 +00001180 const threads =
1181 dom(element.$.diff).queryDistributedElements('gr-comment-thread');
Tao Zhoue0d7c652020-05-04 11:32:05 +02001182
Ole Rehmsene5653b32021-01-29 13:30:34 +01001183 assert.equal(threads.length, 1);
1184 assert.equal(threads[0].diffSide, diffSide);
1185 assert.equal(threads[0].path, element.file.path);
1186 });
Ole Rehmsenef0d17b2021-02-04 14:42:46 +01001187
1188 test('cannot create thread on an edit', () => {
1189 const alertSpy = sinon.spy();
1190 element.addEventListener('show-alert', alertSpy);
1191
1192 const diffSide = Side.LEFT;
1193 element.patchRange = {
1194 basePatchNum: EditPatchSetNum,
1195 patchNum: 3,
1196 };
1197 element.dispatchEvent(new CustomEvent('create-comment', {
1198 detail: {
1199 side: diffSide,
1200 path: '/p',
1201 },
1202 }));
1203
Chris Poucet1ffbbd12021-10-05 18:33:36 +00001204 const threads =
1205 dom(element.$.diff).queryDistributedElements('gr-comment-thread');
Ole Rehmsenef0d17b2021-02-04 14:42:46 +01001206 assert.equal(threads.length, 0);
1207 assert.isTrue(alertSpy.called);
1208 });
1209
1210 test('cannot create thread on an edit base', () => {
1211 const alertSpy = sinon.spy();
1212 element.addEventListener('show-alert', alertSpy);
1213
1214 const diffSide = Side.LEFT;
1215 element.patchRange = {
1216 basePatchNum: ParentPatchSetNum,
1217 patchNum: EditPatchSetNum,
1218 };
1219 element.dispatchEvent(new CustomEvent('create-comment', {
1220 detail: {
1221 side: diffSide,
1222 path: '/p',
1223 },
1224 }));
1225
1226 const threads = dom(element.$.diff)
1227 .queryDistributedElements('gr-comment-thread');
1228 assert.equal(threads.length, 0);
1229 assert.isTrue(alertSpy.called);
1230 });
Tao Zhoue0d7c652020-05-04 11:32:05 +02001231 });
1232
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001233 test('_filterThreadElsForLocation with no threads', () => {
1234 const line = {beforeNumber: 3, afterNumber: 5};
1235
1236 const threads = [];
1237 assert.deepEqual(element._filterThreadElsForLocation(threads, line), []);
1238 assert.deepEqual(element._filterThreadElsForLocation(threads, line,
Ben Rohlfs1d487062020-09-26 11:26:03 +02001239 Side.LEFT), []);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001240 assert.deepEqual(element._filterThreadElsForLocation(threads, line,
Ben Rohlfs1d487062020-09-26 11:26:03 +02001241 Side.RIGHT), []);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001242 });
1243
1244 test('_filterThreadElsForLocation for line comments', () => {
1245 const line = {beforeNumber: 3, afterNumber: 5};
1246
1247 const l3 = document.createElement('div');
1248 l3.setAttribute('line-num', 3);
Dhruv Srivastavab223df22020-12-08 17:48:59 +01001249 l3.setAttribute('diff-side', Side.LEFT);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001250
1251 const l5 = document.createElement('div');
1252 l5.setAttribute('line-num', 5);
Dhruv Srivastavab223df22020-12-08 17:48:59 +01001253 l5.setAttribute('diff-side', Side.LEFT);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001254
1255 const r3 = document.createElement('div');
1256 r3.setAttribute('line-num', 3);
Dhruv Srivastavab223df22020-12-08 17:48:59 +01001257 r3.setAttribute('diff-side', Side.RIGHT);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001258
1259 const r5 = document.createElement('div');
1260 r5.setAttribute('line-num', 5);
Dhruv Srivastavab223df22020-12-08 17:48:59 +01001261 r5.setAttribute('diff-side', Side.RIGHT);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001262
1263 const threadEls = [l3, l5, r3, r5];
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001264 assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
Ben Rohlfs1d487062020-09-26 11:26:03 +02001265 Side.LEFT), [l3]);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001266 assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
Ben Rohlfs1d487062020-09-26 11:26:03 +02001267 Side.RIGHT), [r5]);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001268 });
1269
1270 test('_filterThreadElsForLocation for file comments', () => {
1271 const line = {beforeNumber: 'FILE', afterNumber: 'FILE'};
1272
1273 const l = document.createElement('div');
Dhruv Srivastavab223df22020-12-08 17:48:59 +01001274 l.setAttribute('diff-side', Side.LEFT);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001275 l.setAttribute('line-num', 'FILE');
1276
1277 const r = document.createElement('div');
Dhruv Srivastavab223df22020-12-08 17:48:59 +01001278 r.setAttribute('diff-side', Side.RIGHT);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001279 r.setAttribute('line-num', 'FILE');
1280
1281 const threadEls = [l, r];
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001282 assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
Ben Rohlfs1d487062020-09-26 11:26:03 +02001283 Side.LEFT), [l]);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001284 assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
Ben Rohlfs1d487062020-09-26 11:26:03 +02001285 Side.RIGHT), [r]);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001286 });
1287
1288 suite('syntax layer with syntax_highlighting on', () => {
1289 setup(() => {
1290 const prefs = {
1291 line_length: 10,
1292 show_tabs: true,
1293 tab_size: 4,
1294 context: -1,
1295 syntax_highlighting: true,
1296 };
1297 element.patchRange = {};
1298 element.prefs = prefs;
Ben Rohlfs1d487062020-09-26 11:26:03 +02001299 element.changeNum = 123;
Dmitrii Filippov0695d402020-10-22 16:57:57 +02001300 element.change = createChange();
Ben Rohlfs1d487062020-09-26 11:26:03 +02001301 element.path = 'some/path';
Tao Zhou3dba39e2019-12-13 15:14:31 +01001302 });
Hermann Loose234616a2020-02-11 16:54:27 +01001303
Ben Rohlfs2b7159d2021-02-01 16:04:36 +01001304 test('gr-diff-host provides syntax highlighting layer', async () => {
1305 stubRestApi('getDiff').returns(Promise.resolve({content: []}));
1306 await element.reload();
Chris Poucetaf465c12021-10-27 17:19:36 +02001307 assert.equal(element.$.diff.layers[1], element.syntaxLayer);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001308 });
Hermann Loose234616a2020-02-11 16:54:27 +01001309
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001310 test('rendering normal-sized diff does not disable syntax', () => {
1311 element.diff = {
1312 content: [{
1313 a: ['foo'],
1314 }],
1315 };
Dhruv Srivastava92ca4ef2021-03-08 13:38:01 +01001316 assert.isTrue(element.syntaxLayer.enabled);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001317 });
Hermann Loose234616a2020-02-11 16:54:27 +01001318
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001319 test('rendering large diff disables syntax', () => {
1320 // Before it renders, set the first diff line to 500 '*' characters.
1321 element.diff = {
1322 content: [{
1323 a: [new Array(501).join('*')],
1324 }],
1325 };
Dhruv Srivastava92ca4ef2021-03-08 13:38:01 +01001326 assert.isFalse(element.syntaxLayer.enabled);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001327 });
Hermann Loose234616a2020-02-11 16:54:27 +01001328
Oleb0368262020-10-12 16:50:24 +02001329 test('starts syntax layer processing on render event', async () => {
Dhruv Srivastava92ca4ef2021-03-08 13:38:01 +01001330 sinon.stub(element.syntaxLayer, 'process')
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001331 .returns(Promise.resolve());
Ben Rohlfs2b7159d2021-02-01 16:04:36 +01001332 stubRestApi('getDiff').returns(Promise.resolve({content: []}));
1333 await element.reload();
Oleb0368262020-10-12 16:50:24 +02001334 element.dispatchEvent(
1335 new CustomEvent('render', {bubbles: true, composed: true}));
Dhruv Srivastava92ca4ef2021-03-08 13:38:01 +01001336 assert.isTrue(element.syntaxLayer.process.called);
Hermann Loose234616a2020-02-11 16:54:27 +01001337 });
Ole Rehmsene5de55e2018-08-23 16:52:57 +02001338 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001339
David Ostrovskya2401c12020-05-03 19:29:26 +02001340 suite('syntax layer with syntax_highlighting off', () => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001341 setup(() => {
1342 const prefs = {
1343 line_length: 10,
1344 show_tabs: true,
1345 tab_size: 4,
1346 context: -1,
1347 };
1348 element.diff = {
1349 content: [{
1350 a: ['foo'],
1351 }],
1352 };
1353 element.patchRange = {};
Dmitrii Filippov0695d402020-10-22 16:57:57 +02001354 element.change = createChange();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001355 element.prefs = prefs;
1356 });
1357
Ben Rohlfs2b7159d2021-02-01 16:04:36 +01001358 test('gr-diff-host provides syntax highlighting layer', async () => {
1359 stubRestApi('getDiff').returns(Promise.resolve({content: []}));
1360 await element.reload();
Chris Poucetaf465c12021-10-27 17:19:36 +02001361 assert.equal(element.$.diff.layers[1], element.syntaxLayer);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001362 });
1363
1364 test('syntax layer should be disabled', () => {
Dhruv Srivastava92ca4ef2021-03-08 13:38:01 +01001365 assert.isFalse(element.syntaxLayer.enabled);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001366 });
1367
1368 test('still disabled for large diff', () => {
1369 // Before it renders, set the first diff line to 500 '*' characters.
1370 element.diff = {
1371 content: [{
1372 a: [new Array(501).join('*')],
1373 }],
1374 };
Dhruv Srivastava92ca4ef2021-03-08 13:38:01 +01001375 assert.isFalse(element.syntaxLayer.enabled);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001376 });
1377 });
1378
1379 suite('coverage layer', () => {
1380 let notifyStub;
Malgorzata Salawa4acc5752020-12-08 13:55:49 +01001381 let coverageProviderStub;
1382 const exampleRanges = [
1383 {
Dhruv Srivastavab223df22020-12-08 17:48:59 +01001384 type: CoverageType.COVERED,
1385 side: Side.RIGHT,
Malgorzata Salawa4acc5752020-12-08 13:55:49 +01001386 code_range: {
1387 start_line: 1,
1388 end_line: 2,
1389 },
1390 },
1391 {
Dhruv Srivastavab223df22020-12-08 17:48:59 +01001392 type: CoverageType.NOT_COVERED,
1393 side: Side.RIGHT,
Malgorzata Salawa4acc5752020-12-08 13:55:49 +01001394 code_range: {
1395 start_line: 3,
1396 end_line: 4,
1397 },
1398 },
1399 ];
1400
Ole Rehmsen4637b802021-02-04 13:28:16 +01001401 setup(async () => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001402 notifyStub = sinon.stub();
Malgorzata Salawa4acc5752020-12-08 13:55:49 +01001403 coverageProviderStub = sinon.stub().returns(
1404 Promise.resolve(exampleRanges));
1405
Ben Rohlfs70cbedc2021-02-03 23:03:21 +01001406 element = basicFixture.instantiate();
1407 sinon.stub(element.jsAPI, 'getCoverageAnnotationApis').returns(
1408 Promise.resolve([{
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001409 notify: notifyStub,
1410 getCoverageProvider() {
Malgorzata Salawa4acc5752020-12-08 13:55:49 +01001411 return coverageProviderStub;
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001412 },
Ben Rohlfs70cbedc2021-02-03 23:03:21 +01001413 }]));
Ben Rohlfs1d487062020-09-26 11:26:03 +02001414 element.changeNum = 123;
Dmitrii Filippov0695d402020-10-22 16:57:57 +02001415 element.change = createChange();
Ben Rohlfs1d487062020-09-26 11:26:03 +02001416 element.path = 'some/path';
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001417 const prefs = {
1418 line_length: 10,
1419 show_tabs: true,
1420 tab_size: 4,
1421 context: -1,
1422 };
1423 element.diff = {
1424 content: [{
1425 a: ['foo'],
1426 }],
1427 };
1428 element.patchRange = {};
1429 element.prefs = prefs;
Ben Rohlfs2b7159d2021-02-01 16:04:36 +01001430 stubRestApi('getDiff').returns(Promise.resolve(element.diff));
Ole Rehmsen4637b802021-02-04 13:28:16 +01001431 await flush();
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001432 });
1433
Ben Rohlfs2b7159d2021-02-01 16:04:36 +01001434 test('getCoverageAnnotationApis should be called', async () => {
1435 await element.reload();
Ben Rohlfs70cbedc2021-02-03 23:03:21 +01001436 assert.isTrue(element.jsAPI.getCoverageAnnotationApis.calledOnce);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001437 });
1438
Ben Rohlfs2b7159d2021-02-01 16:04:36 +01001439 test('coverageRangeChanged should be called', async () => {
1440 await element.reload();
1441 assert.equal(notifyStub.callCount, 2);
1442 assert.isTrue(notifyStub.calledWithExactly(
1443 'some/path', 1, 2, Side.RIGHT));
1444 assert.isTrue(notifyStub.calledWithExactly(
1445 'some/path', 3, 4, Side.RIGHT));
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001446 });
Malgorzata Salawa4acc5752020-12-08 13:55:49 +01001447
Ben Rohlfs2b7159d2021-02-01 16:04:36 +01001448 test('provider is called with appropriate params', async () => {
Malgorzata Salawa4acc5752020-12-08 13:55:49 +01001449 element.patchRange.basePatchNum = 1;
1450 element.patchRange.patchNum = 3;
1451
Ben Rohlfs2b7159d2021-02-01 16:04:36 +01001452 await element.reload();
1453 assert.isTrue(coverageProviderStub.calledWithExactly(
1454 123, 'some/path', 1, 3, element.change));
Malgorzata Salawa4acc5752020-12-08 13:55:49 +01001455 });
1456
1457 test('provider is called with appropriate params - special patchset values',
Ben Rohlfs2b7159d2021-02-01 16:04:36 +01001458 async () => {
Malgorzata Salawa4acc5752020-12-08 13:55:49 +01001459 element.patchRange.basePatchNum = 'PARENT';
1460 element.patchRange.patchNum = 'invalid';
1461
Ben Rohlfs2b7159d2021-02-01 16:04:36 +01001462 await element.reload();
1463 assert.isTrue(coverageProviderStub.calledWithExactly(
1464 123, 'some/path', undefined, undefined, element.change));
Malgorzata Salawa4acc5752020-12-08 13:55:49 +01001465 });
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001466 });
1467
1468 suite('trailing newlines', () => {
1469 setup(() => {
1470 });
1471
1472 suite('_lastChunkForSide', () => {
1473 test('deltas', () => {
1474 const diff = {content: [
1475 {a: ['foo', 'bar'], b: ['baz']},
1476 {ab: ['foo', 'bar', 'baz']},
1477 {b: ['foo']},
1478 ]};
1479 assert.equal(element._lastChunkForSide(diff, false), diff.content[2]);
1480 assert.equal(element._lastChunkForSide(diff, true), diff.content[1]);
1481
1482 diff.content.push({a: ['foo'], b: ['bar']});
1483 assert.equal(element._lastChunkForSide(diff, false), diff.content[3]);
1484 assert.equal(element._lastChunkForSide(diff, true), diff.content[3]);
1485 });
1486
1487 test('addition with a undefined', () => {
1488 const diff = {content: [
1489 {b: ['foo', 'bar', 'baz']},
1490 ]};
1491 assert.equal(element._lastChunkForSide(diff, false), diff.content[0]);
1492 assert.isNull(element._lastChunkForSide(diff, true));
1493 });
1494
1495 test('addition with a empty', () => {
1496 const diff = {content: [
1497 {a: [], b: ['foo', 'bar', 'baz']},
1498 ]};
1499 assert.equal(element._lastChunkForSide(diff, false), diff.content[0]);
1500 assert.isNull(element._lastChunkForSide(diff, true));
1501 });
1502
1503 test('deletion with b undefined', () => {
1504 const diff = {content: [
1505 {a: ['foo', 'bar', 'baz']},
1506 ]};
1507 assert.isNull(element._lastChunkForSide(diff, false));
1508 assert.equal(element._lastChunkForSide(diff, true), diff.content[0]);
1509 });
1510
1511 test('deletion with b empty', () => {
1512 const diff = {content: [
1513 {a: ['foo', 'bar', 'baz'], b: []},
1514 ]};
1515 assert.isNull(element._lastChunkForSide(diff, false));
1516 assert.equal(element._lastChunkForSide(diff, true), diff.content[0]);
1517 });
1518
1519 test('empty', () => {
1520 const diff = {content: []};
1521 assert.isNull(element._lastChunkForSide(diff, false));
1522 assert.isNull(element._lastChunkForSide(diff, true));
1523 });
1524 });
1525
1526 suite('_hasTrailingNewlines', () => {
1527 test('shared no trailing', () => {
1528 const diff = undefined;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001529 sinon.stub(element, '_lastChunkForSide')
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001530 .returns({ab: ['foo', 'bar']});
1531 assert.isFalse(element._hasTrailingNewlines(diff, false));
1532 assert.isFalse(element._hasTrailingNewlines(diff, true));
1533 });
1534
1535 test('delta trailing in right', () => {
1536 const diff = undefined;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001537 sinon.stub(element, '_lastChunkForSide')
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001538 .returns({a: ['foo', 'bar'], b: ['baz', '']});
1539 assert.isTrue(element._hasTrailingNewlines(diff, false));
1540 assert.isFalse(element._hasTrailingNewlines(diff, true));
1541 });
1542
1543 test('addition', () => {
1544 const diff = undefined;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001545 sinon.stub(element, '_lastChunkForSide').callsFake((diff, leftSide) => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001546 if (leftSide) { return null; }
1547 return {b: ['foo', '']};
1548 });
1549 assert.isTrue(element._hasTrailingNewlines(diff, false));
1550 assert.isNull(element._hasTrailingNewlines(diff, true));
1551 });
1552
1553 test('deletion', () => {
1554 const diff = undefined;
Dmitrii Filippov7d4f2f32020-06-28 23:14:26 +02001555 sinon.stub(element, '_lastChunkForSide').callsFake((diff, leftSide) => {
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +01001556 if (!leftSide) { return null; }
1557 return {a: ['foo']};
1558 });
1559 assert.isNull(element._hasTrailingNewlines(diff, false));
1560 assert.isFalse(element._hasTrailingNewlines(diff, true));
1561 });
1562 });
1563 });
1564});
Dmitrii Filippov06117e82020-06-25 13:26:55 +02001565