Files
gerrit/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
Ole Rehmsen 9b94616a54 Move comment and thread elements to shared
Even before the refactorings, the comment and thread elements were also used
from views outside of diff/. Now they are now completely independent from
gr-diff and descendants, and can move into their own folder and drop the -diff
from their name.

The dependency left from diff/gr-diff-host onto comment[-thread], makes sense
since gr-diff-host is the Gerrit wrapper for gr-diff with gr-comment[-thread].

Change-Id: I5076428da980198989edc605e5edc0e4d66529dd
2018-11-19 23:30:20 +01:00

1307 lines
44 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!--
@license
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-diff</title>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="../../../bower_components/web-component-tester/browser.js"></script>
<link rel="import" href="../../../test/common-test-setup.html"/>
<link rel="import" href="gr-diff-host.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-diff-host></gr-diff-host>
</template>
</test-fixture>
<script>
suite('gr-diff-host tests', () => {
let element;
let sandbox;
let getLoggedIn;
setup(() => {
sandbox = sinon.sandbox.create();
getLoggedIn = false;
stub('gr-rest-api-interface', {
async getLoggedIn() { return getLoggedIn; },
});
element = fixture('basic');
});
teardown(() => {
sandbox.restore();
});
suite('handle comment-update', () => {
setup(() => {
sandbox.stub(element, '_commentsChanged');
element.comments = {
meta: {
changeNum: '42',
patchRange: {
basePatchNum: 'PARENT',
patchNum: 3,
},
path: '/path/to/foo',
projectConfig: {foo: 'bar'},
},
left: [
{id: 'bc1', side: 'PARENT', __commentSide: 'left'},
{id: 'bc2', side: 'PARENT', __commentSide: 'left'},
{id: 'bd1', __draft: true, side: 'PARENT', __commentSide: 'left'},
{id: 'bd2', __draft: true, side: 'PARENT', __commentSide: 'left'},
],
right: [
{id: 'c1', __commentSide: 'right'},
{id: 'c2', __commentSide: 'right'},
{id: 'd1', __draft: true, __commentSide: 'right'},
{id: 'd2', __draft: true, __commentSide: 'right'},
],
};
});
test('creating a draft', () => {
const comment = {__draft: true, __draftID: 'tempID', side: 'PARENT',
__commentSide: 'left'};
element.fire('comment-update', {comment});
assert.include(element.comments.left, comment);
});
test('discarding a draft', () => {
const draftID = 'tempID';
const id = 'savedID';
const comment = {
__draft: true,
__draftID: draftID,
side: 'PARENT',
__commentSide: 'left',
};
const diffCommentsModifiedStub = sandbox.stub();
element.addEventListener('diff-comments-modified',
diffCommentsModifiedStub);
element.comments.left.push(comment);
comment.id = id;
element.fire('comment-discard', {comment});
const drafts = element.comments.left.filter(item => {
return item.__draftID === draftID;
});
assert.equal(drafts.length, 0);
assert.isTrue(diffCommentsModifiedStub.called);
});
test('saving a draft', () => {
const draftID = 'tempID';
const id = 'savedID';
const comment = {
__draft: true,
__draftID: draftID,
side: 'PARENT',
__commentSide: 'left',
};
const diffCommentsModifiedStub = sandbox.stub();
element.addEventListener('diff-comments-modified',
diffCommentsModifiedStub);
element.comments.left.push(comment);
comment.id = id;
element.fire('comment-save', {comment});
const drafts = element.comments.left.filter(item => {
return item.__draftID === draftID;
});
assert.equal(drafts.length, 1);
assert.equal(drafts[0].id, id);
assert.isTrue(diffCommentsModifiedStub.called);
});
});
test('remove comment', () => {
sandbox.stub(element, '_commentsChanged');
element.comments = {
meta: {
changeNum: '42',
patchRange: {
basePatchNum: 'PARENT',
patchNum: 3,
},
path: '/path/to/foo',
projectConfig: {foo: 'bar'},
},
left: [
{id: 'bc1', side: 'PARENT', __commentSide: 'left'},
{id: 'bc2', side: 'PARENT', __commentSide: 'left'},
{id: 'bd1', __draft: true, side: 'PARENT', __commentSide: 'left'},
{id: 'bd2', __draft: true, side: 'PARENT', __commentSide: 'left'},
],
right: [
{id: 'c1', __commentSide: 'right'},
{id: 'c2', __commentSide: 'right'},
{id: 'd1', __draft: true, __commentSide: 'right'},
{id: 'd2', __draft: true, __commentSide: 'right'},
],
};
element._removeComment({});
// Using JSON.stringify because Safari 9.1 (11601.5.17.1) doesnt seem
// to believe that one object deepEquals another even when they do :-/.
assert.equal(JSON.stringify(element.comments), JSON.stringify({
meta: {
changeNum: '42',
patchRange: {
basePatchNum: 'PARENT',
patchNum: 3,
},
path: '/path/to/foo',
projectConfig: {foo: 'bar'},
},
left: [
{id: 'bc1', side: 'PARENT', __commentSide: 'left'},
{id: 'bc2', side: 'PARENT', __commentSide: 'left'},
{id: 'bd1', __draft: true, side: 'PARENT', __commentSide: 'left'},
{id: 'bd2', __draft: true, side: 'PARENT', __commentSide: 'left'},
],
right: [
{id: 'c1', __commentSide: 'right'},
{id: 'c2', __commentSide: 'right'},
{id: 'd1', __draft: true, __commentSide: 'right'},
{id: 'd2', __draft: true, __commentSide: 'right'},
],
}));
element._removeComment({id: 'bc2', side: 'PARENT',
__commentSide: 'left'});
assert.deepEqual(element.comments, {
meta: {
changeNum: '42',
patchRange: {
basePatchNum: 'PARENT',
patchNum: 3,
},
path: '/path/to/foo',
projectConfig: {foo: 'bar'},
},
left: [
{id: 'bc1', side: 'PARENT', __commentSide: 'left'},
{id: 'bd1', __draft: true, side: 'PARENT', __commentSide: 'left'},
{id: 'bd2', __draft: true, side: 'PARENT', __commentSide: 'left'},
],
right: [
{id: 'c1', __commentSide: 'right'},
{id: 'c2', __commentSide: 'right'},
{id: 'd1', __draft: true, __commentSide: 'right'},
{id: 'd2', __draft: true, __commentSide: 'right'},
],
});
element._removeComment({id: 'd2', __commentSide: 'right'});
assert.deepEqual(element.comments, {
meta: {
changeNum: '42',
patchRange: {
basePatchNum: 'PARENT',
patchNum: 3,
},
path: '/path/to/foo',
projectConfig: {foo: 'bar'},
},
left: [
{id: 'bc1', side: 'PARENT', __commentSide: 'left'},
{id: 'bd1', __draft: true, side: 'PARENT', __commentSide: 'left'},
{id: 'bd2', __draft: true, side: 'PARENT', __commentSide: 'left'},
],
right: [
{id: 'c1', __commentSide: 'right'},
{id: 'c2', __commentSide: 'right'},
{id: 'd1', __draft: true, __commentSide: 'right'},
],
});
});
test('thread-discard handling', () => {
const threads = [
{comments: [{id: 4711}]},
{comments: [{id: 42}]},
];
element._parentIndex = 1;
element.changeNum = '2';
element.path = 'some/path';
element.projectName = 'Some project';
const threadEls = threads.map(
thread => element._createThreadElement(thread));
assert.equal(threadEls.length, 2);
assert.equal(threadEls[0].rootId, 4711);
assert.equal(threadEls[1].rootId, 42);
for (const threadEl of threadEls) {
Polymer.dom(element).appendChild(threadEl);
}
threadEls[0].dispatchEvent(
new CustomEvent('thread-discard', {detail: {rootId: 4711}}));
const attachedThreads = element.queryAllEffectiveChildren(
'gr-comment-thread');
assert.equal(attachedThreads.length, 1);
assert.equal(attachedThreads[0].rootId, 42);
});
test('reload() cancels before network resolves', () => {
const cancelStub = sandbox.stub(element.$.diff, 'cancel');
// Stub the network calls into requests that never resolve.
sandbox.stub(element, '_getDiff', () => new Promise(() => {}));
element.reload();
assert.isTrue(cancelStub.called);
});
suite('not logged in', () => {
setup(() => {
getLoggedIn = false;
element = fixture('basic');
});
test('reload() loads files weblinks', () => {
const weblinksStub = sandbox.stub(Gerrit.Nav, '_generateWeblinks')
.returns({name: 'stubb', url: '#s'});
sandbox.stub(element.$.restAPI, 'getDiff').returns(Promise.resolve({
content: [],
}));
element.projectName = 'test-project';
element.path = 'test-path';
element.commitRange = {baseCommit: 'test-base', commit: 'test-commit'};
element.patchRange = {};
return element.reload().then(() => {
assert.isTrue(weblinksStub.calledTwice);
assert.isTrue(weblinksStub.firstCall.calledWith({
commit: 'test-base',
file: 'test-path',
options: {
weblinks: undefined,
},
repo: 'test-project',
type: Gerrit.Nav.WeblinkType.FILE}));
assert.isTrue(weblinksStub.secondCall.calledWith({
commit: 'test-commit',
file: 'test-path',
options: {
weblinks: undefined,
},
repo: 'test-project',
type: Gerrit.Nav.WeblinkType.FILE}));
assert.deepEqual(element.filesWeblinks, {
meta_a: [{name: 'stubb', url: '#s'}],
meta_b: [{name: 'stubb', url: '#s'}],
});
});
});
test('_getDiff handles null diff responses', done => {
stub('gr-rest-api-interface', {
getDiff() { return Promise.resolve(null); },
});
element.changeNum = 123;
element.patchRange = {basePatchNum: 1, patchNum: 2};
element.path = 'file.txt';
element._getDiff().then(done);
});
test('reload resolves on error', () => {
const onErrStub = sandbox.stub(element, '_handleGetDiffError');
const error = {ok: false, status: 500};
sandbox.stub(element.$.restAPI, 'getDiff',
(changeNum, basePatchNum, patchNum, path, onErr) => {
onErr(error);
});
return element.reload().then(() => {
assert.isTrue(onErrStub.calledOnce);
});
});
suite('_handleGetDiffError', () => {
let serverErrorStub;
let pageErrorStub;
setup(() => {
serverErrorStub = sinon.stub();
element.addEventListener('server-error', serverErrorStub);
pageErrorStub = sinon.stub();
element.addEventListener('page-error', pageErrorStub);
});
test('page error on HTTP-409', () => {
element._handleGetDiffError({status: 409});
assert.isTrue(serverErrorStub.calledOnce);
assert.isFalse(pageErrorStub.called);
assert.isNotOk(element._errorMessage);
});
test('server error on non-HTTP-409', () => {
element._handleGetDiffError({status: 500});
assert.isFalse(serverErrorStub.called);
assert.isTrue(pageErrorStub.calledOnce);
assert.isNotOk(element._errorMessage);
});
test('error message if showLoadFailure', () => {
element.showLoadFailure = true;
element._handleGetDiffError({status: 500, statusText: 'Failure!'});
assert.isFalse(serverErrorStub.called);
assert.isFalse(pageErrorStub.called);
assert.equal(element._errorMessage,
'Encountered error when loading the diff: 500 Failure!');
});
});
suite('image diffs', () => {
let mockFile1;
let mockFile2;
setup(() => {
mockFile1 = {
body: 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
'wsAAAAAAAAAAAAAAAAA/w==',
type: 'image/bmp',
};
mockFile2 = {
body: 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
'wsAAAAAAAAAAAAA/////w==',
type: 'image/bmp',
};
sandbox.stub(element.$.restAPI,
'getB64FileContents',
(changeId, patchNum, path, opt_parentIndex) => {
return Promise.resolve(opt_parentIndex === 1 ? mockFile1 :
mockFile2);
});
element.patchRange = {basePatchNum: 'PARENT', patchNum: 1};
element.comments = {
left: [],
right: [],
meta: {patchRange: element.patchRange},
};
});
test('renders image diffs with same file name', done => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg',
lines: 560},
intraline_status: 'OK',
change_type: 'MODIFIED',
diff_header: [
'diff --git a/carrot.jpg b/carrot.jpg',
'index 2adc47d..f9c2f2c 100644',
'--- a/carrot.jpg',
'+++ b/carrot.jpg',
'Binary files differ',
],
content: [{skip: 66}],
binary: true,
};
sandbox.stub(element.$.restAPI, 'getDiff')
.returns(Promise.resolve(mockDiff));
const rendered = () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
// Left image rendered with the parent commit's version of the file.
const leftImage =
element.$.diff.$.diffTable.querySelector('td.left img');
const leftLabel =
element.$.diff.$.diffTable.querySelector('td.left label');
const leftLabelContent = leftLabel.querySelector('.label');
const leftLabelName = leftLabel.querySelector('.name');
const rightImage =
element.$.diff.$.diffTable.querySelector('td.right img');
const rightLabel = element.$.diff.$.diffTable.querySelector(
'td.right label');
const rightLabelContent = rightLabel.querySelector('.label');
const rightLabelName = rightLabel.querySelector('.name');
assert.isNotOk(rightLabelName);
assert.isNotOk(leftLabelName);
let leftLoaded = false;
let rightLoaded = false;
leftImage.addEventListener('load', () => {
assert.isOk(leftImage);
assert.equal(leftImage.getAttribute('src'),
'data:image/bmp;base64, ' + mockFile1.body);
assert.equal(leftLabelContent.textContent, '1×1 image/bmp');
leftLoaded = true;
if (rightLoaded) {
element.removeEventListener('render', rendered);
done();
}
});
rightImage.addEventListener('load', () => {
assert.isOk(rightImage);
assert.equal(rightImage.getAttribute('src'),
'data:image/bmp;base64, ' + mockFile2.body);
assert.equal(rightLabelContent.textContent, '1×1 image/bmp');
rightLoaded = true;
if (leftLoaded) {
element.removeEventListener('render', rendered);
done();
}
});
};
element.addEventListener('render', rendered);
element.$.restAPI.getDiffPreferences().then(prefs => {
element.prefs = prefs;
element.reload();
});
});
test('renders image diffs with a different file name', done => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
meta_b: {name: 'carrot2.jpg', content_type: 'image/jpeg',
lines: 560},
intraline_status: 'OK',
change_type: 'MODIFIED',
diff_header: [
'diff --git a/carrot.jpg b/carrot2.jpg',
'index 2adc47d..f9c2f2c 100644',
'--- a/carrot.jpg',
'+++ b/carrot2.jpg',
'Binary files differ',
],
content: [{skip: 66}],
binary: true,
};
sandbox.stub(element.$.restAPI, 'getDiff')
.returns(Promise.resolve(mockDiff));
const rendered = () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
// Left image rendered with the parent commit's version of the file.
const leftImage =
element.$.diff.$.diffTable.querySelector('td.left img');
const leftLabel =
element.$.diff.$.diffTable.querySelector('td.left label');
const leftLabelContent = leftLabel.querySelector('.label');
const leftLabelName = leftLabel.querySelector('.name');
const rightImage =
element.$.diff.$.diffTable.querySelector('td.right img');
const rightLabel = element.$.diff.$.diffTable.querySelector(
'td.right label');
const rightLabelContent = rightLabel.querySelector('.label');
const rightLabelName = rightLabel.querySelector('.name');
assert.isOk(rightLabelName);
assert.isOk(leftLabelName);
assert.equal(leftLabelName.textContent, mockDiff.meta_a.name);
assert.equal(rightLabelName.textContent, mockDiff.meta_b.name);
let leftLoaded = false;
let rightLoaded = false;
leftImage.addEventListener('load', () => {
assert.isOk(leftImage);
assert.equal(leftImage.getAttribute('src'),
'data:image/bmp;base64, ' + mockFile1.body);
assert.equal(leftLabelContent.textContent, '1×1 image/bmp');
leftLoaded = true;
if (rightLoaded) {
element.removeEventListener('render', rendered);
done();
}
});
rightImage.addEventListener('load', () => {
assert.isOk(rightImage);
assert.equal(rightImage.getAttribute('src'),
'data:image/bmp;base64, ' + mockFile2.body);
assert.equal(rightLabelContent.textContent, '1×1 image/bmp');
rightLoaded = true;
if (leftLoaded) {
element.removeEventListener('render', rendered);
done();
}
});
};
element.addEventListener('render', rendered);
element.$.restAPI.getDiffPreferences().then(prefs => {
element.prefs = prefs;
element.reload();
});
});
test('renders added image', done => {
const mockDiff = {
meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg',
lines: 560},
intraline_status: 'OK',
change_type: 'ADDED',
diff_header: [
'diff --git a/carrot.jpg b/carrot.jpg',
'index 0000000..f9c2f2c 100644',
'--- /dev/null',
'+++ b/carrot.jpg',
'Binary files differ',
],
content: [{skip: 66}],
binary: true,
};
sandbox.stub(element.$.restAPI, 'getDiff')
.returns(Promise.resolve(mockDiff));
element.addEventListener('render', () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
const leftImage =
element.$.diff.$.diffTable.querySelector('td.left img');
const rightImage =
element.$.diff.$.diffTable.querySelector('td.right img');
assert.isNotOk(leftImage);
assert.isOk(rightImage);
done();
});
element.$.restAPI.getDiffPreferences().then(prefs => {
element.prefs = prefs;
element.reload();
});
});
test('renders removed image', done => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg',
lines: 560},
intraline_status: 'OK',
change_type: 'DELETED',
diff_header: [
'diff --git a/carrot.jpg b/carrot.jpg',
'index f9c2f2c..0000000 100644',
'--- a/carrot.jpg',
'+++ /dev/null',
'Binary files differ',
],
content: [{skip: 66}],
binary: true,
};
sandbox.stub(element.$.restAPI, 'getDiff')
.returns(Promise.resolve(mockDiff));
element.addEventListener('render', () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
const leftImage =
element.$.diff.$.diffTable.querySelector('td.left img');
const rightImage =
element.$.diff.$.diffTable.querySelector('td.right img');
assert.isOk(leftImage);
assert.isNotOk(rightImage);
done();
});
element.$.restAPI.getDiffPreferences().then(prefs => {
element.prefs = prefs;
element.reload();
});
});
test('does not render disallowed image type', done => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg-evil',
lines: 560},
intraline_status: 'OK',
change_type: 'DELETED',
diff_header: [
'diff --git a/carrot.jpg b/carrot.jpg',
'index f9c2f2c..0000000 100644',
'--- a/carrot.jpg',
'+++ /dev/null',
'Binary files differ',
],
content: [{skip: 66}],
binary: true,
};
mockFile1.type = 'image/jpeg-evil';
sandbox.stub(element.$.restAPI, 'getDiff')
.returns(Promise.resolve(mockDiff));
element.addEventListener('render', () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
const leftImage =
element.$.diff.$.diffTable.querySelector('td.left img');
assert.isNotOk(leftImage);
done();
});
element.$.restAPI.getDiffPreferences().then(prefs => {
element.prefs = prefs;
element.reload();
});
});
});
});
test('delegates cancel()', () => {
const stub = sandbox.stub(element.$.diff, 'cancel');
element.reload();
assert.isTrue(stub.calledOnce);
assert.equal(stub.lastCall.args.length, 0);
});
test('delegates getCursorStops()', () => {
const returnValue = [document.createElement('b')];
const stub = sandbox.stub(element.$.diff, 'getCursorStops')
.returns(returnValue);
assert.equal(element.getCursorStops(), returnValue);
assert.isTrue(stub.calledOnce);
assert.equal(stub.lastCall.args.length, 0);
});
test('delegates isRangeSelected()', () => {
const returnValue = true;
const stub = sandbox.stub(element.$.diff, 'isRangeSelected')
.returns(returnValue);
assert.equal(element.isRangeSelected(), returnValue);
assert.isTrue(stub.calledOnce);
assert.equal(stub.lastCall.args.length, 0);
});
test('delegates toggleLeftDiff()', () => {
const stub = sandbox.stub(element.$.diff, 'toggleLeftDiff');
element.toggleLeftDiff();
assert.isTrue(stub.calledOnce);
assert.equal(stub.lastCall.args.length, 0);
});
suite('blame', () => {
setup(() => {
element = fixture('basic');
});
test('clearBlame', () => {
element._blame = [];
const setBlameSpy = sandbox.spy(element.$.diff.$.diffBuilder, 'setBlame');
element.clearBlame();
assert.isNull(element._blame);
assert.isTrue(setBlameSpy.calledWithExactly(null));
assert.equal(element.isBlameLoaded, false);
});
test('loadBlame', () => {
const mockBlame = [{id: 'commit id', ranges: [{start: 1, end: 2}]}];
const showAlertStub = sinon.stub();
element.addEventListener('show-alert', showAlertStub);
const getBlameStub = sandbox.stub(element.$.restAPI, 'getBlame')
.returns(Promise.resolve(mockBlame));
element.changeNum = 42;
element.patchRange = {patchNum: 5, basePatchNum: 4};
element.path = 'foo/bar.baz';
return element.loadBlame().then(() => {
assert.isTrue(getBlameStub.calledWithExactly(
42, 5, 'foo/bar.baz', true));
assert.isFalse(showAlertStub.called);
assert.equal(element._blame, mockBlame);
assert.equal(element.isBlameLoaded, true);
});
});
test('loadBlame empty', () => {
const mockBlame = [];
const showAlertStub = sinon.stub();
element.addEventListener('show-alert', showAlertStub);
sandbox.stub(element.$.restAPI, 'getBlame')
.returns(Promise.resolve(mockBlame));
element.changeNum = 42;
element.patchRange = {patchNum: 5, basePatchNum: 4};
element.path = 'foo/bar.baz';
return element.loadBlame()
.then(() => {
assert.isTrue(false, 'Promise should not resolve');
})
.catch(() => {
assert.isTrue(showAlertStub.calledOnce);
assert.isNull(element._blame);
assert.equal(element.isBlameLoaded, false);
});
});
});
test('getThreadEls() returns .comment-threads', () => {
const threadEl = document.createElement('div');
threadEl.className = 'comment-thread';
Polymer.dom(element.$.diff).appendChild(threadEl);
assert.deepEqual(element.getThreadEls(), [threadEl]);
});
test('delegates addDraftAtLine(el)', () => {
const param0 = document.createElement('b');
const stub = sandbox.stub(element.$.diff, 'addDraftAtLine');
element.addDraftAtLine(param0);
assert.isTrue(stub.calledOnce);
assert.equal(stub.lastCall.args.length, 1);
assert.equal(stub.lastCall.args[0], param0);
});
test('delegates clearDiffContent()', () => {
const stub = sandbox.stub(element.$.diff, 'clearDiffContent');
element.clearDiffContent();
assert.isTrue(stub.calledOnce);
assert.equal(stub.lastCall.args.length, 0);
});
test('delegates expandAllContext()', () => {
const stub = sandbox.stub(element.$.diff, 'expandAllContext');
element.expandAllContext();
assert.isTrue(stub.calledOnce);
assert.equal(stub.lastCall.args.length, 0);
});
test('passes in changeNum', () => {
const value = '12345';
element.changeNum = value;
assert.equal(element.$.diff.changeNum, value);
});
test('passes in noAutoRender', () => {
const value = true;
element.noAutoRender = value;
assert.equal(element.$.diff.noAutoRender, value);
});
test('passes in patchRange', () => {
const value = {patchNum: 'foo', basePatchNum: 'bar'};
element.patchRange = value;
assert.equal(element.$.diff.patchRange, value);
});
test('passes in path', () => {
const value = 'some/file/path';
element.path = value;
assert.equal(element.$.diff.path, value);
});
test('passes in prefs', () => {
const value = {};
element.prefs = value;
assert.equal(element.$.diff.prefs, value);
});
test('passes in changeNum', () => {
const value = '12345';
element.changeNum = value;
assert.equal(element.$.diff.changeNum, value);
});
test('passes in projectName', () => {
const value = 'Gerrit';
element.projectName = value;
assert.equal(element.$.diff.projectName, value);
});
test('passes in displayLine', () => {
const value = true;
element.displayLine = value;
assert.equal(element.$.diff.displayLine, value);
});
test('passes in commitRange', () => {
const value = {};
element.commitRange = value;
assert.equal(element.$.diff.commitRange, value);
});
test('passes in hidden', () => {
const value = true;
element.hidden = value;
assert.equal(element.$.diff.hidden, value);
assert.isNotNull(element.getAttribute('hidden'));
});
test('passes in noRenderOnPrefsChange', () => {
const value = true;
element.noRenderOnPrefsChange = value;
assert.equal(element.$.diff.noRenderOnPrefsChange, value);
});
test('passes in lineWrapping', () => {
const value = true;
element.lineWrapping = value;
assert.equal(element.$.diff.lineWrapping, value);
});
test('passes in viewMode', () => {
const value = 'SIDE_BY_SIDE';
element.viewMode = value;
assert.equal(element.$.diff.viewMode, value);
});
test('passes in lineOfInterest', () => {
const value = {number: 123, leftSide: true};
element.lineOfInterest = value;
assert.equal(element.$.diff.lineOfInterest, value);
});
suite('_reportDiff', () => {
let reportStub;
setup(() => {
element = fixture('basic');
element.patchRange = {basePatchNum: 1};
reportStub = sandbox.stub(element.$.reporting, 'reportInteraction');
});
test('null and content-less', () => {
element._reportDiff(null);
assert.isFalse(reportStub.called);
element._reportDiff({});
assert.isFalse(reportStub.called);
});
test('diff w/ no delta', () => {
const diff = {
content: [
{ab: ['foo', 'bar']},
{ab: ['baz', 'foo']},
],
};
element._reportDiff(diff);
assert.isTrue(reportStub.calledOnce);
assert.equal(reportStub.lastCall.args[0], 'rebase-percent-zero');
assert.isUndefined(reportStub.lastCall.args[1]);
});
test('diff w/ no rebase delta', () => {
const diff = {
content: [
{ab: ['foo', 'bar']},
{a: ['baz', 'foo']},
{ab: ['foo', 'bar']},
{a: ['baz', 'foo'], b: ['bar', 'baz']},
{ab: ['foo', 'bar']},
{b: ['baz', 'foo']},
{ab: ['foo', 'bar']},
],
};
element._reportDiff(diff);
assert.isTrue(reportStub.calledOnce);
assert.equal(reportStub.lastCall.args[0], 'rebase-percent-zero');
assert.isUndefined(reportStub.lastCall.args[1]);
});
test('diff w/ some rebase delta', () => {
const diff = {
content: [
{ab: ['foo', 'bar']},
{a: ['baz', 'foo'], due_to_rebase: true},
{ab: ['foo', 'bar']},
{a: ['baz', 'foo'], b: ['bar', 'baz']},
{ab: ['foo', 'bar']},
{b: ['baz', 'foo'], due_to_rebase: true},
{ab: ['foo', 'bar']},
{a: ['baz', 'foo']},
],
};
element._reportDiff(diff);
assert.isTrue(reportStub.calledOnce);
assert.equal(reportStub.lastCall.args[0], 'rebase-percent-nonzero');
assert.strictEqual(reportStub.lastCall.args[1], 50);
});
test('diff w/ all rebase delta', () => {
const diff = {content: [{
a: ['foo', 'bar'],
b: ['baz', 'foo'],
due_to_rebase: true,
}]};
element._reportDiff(diff);
assert.isTrue(reportStub.calledOnce);
assert.equal(reportStub.lastCall.args[0], 'rebase-percent-nonzero');
assert.strictEqual(reportStub.lastCall.args[1], 100);
});
test('diff against parent event', () => {
element.patchRange.basePatchNum = 'PARENT';
const diff = {content: [{
a: ['foo', 'bar'],
b: ['baz', 'foo'],
}]};
element._reportDiff(diff);
assert.isTrue(reportStub.calledOnce);
assert.equal(reportStub.lastCall.args[0], 'diff-against-parent');
assert.isUndefined(reportStub.lastCall.args[1]);
});
});
test('_createThreads', () => {
const comments = [
{
id: 'sallys_confession',
message: 'i like you, jack',
updated: '2015-12-23 15:00:20.396000000',
line: 1,
__commentSide: 'left',
}, {
id: 'jacks_reply',
message: 'i like you, too',
updated: '2015-12-24 15:01:20.396000000',
__commentSide: 'left',
line: 1,
in_reply_to: 'sallys_confession',
},
{
id: 'new_draft',
message: 'i do not like either of you',
__commentSide: 'left',
__draft: true,
updated: '2015-12-20 15:01:20.396000000',
},
];
const actualThreads = element._createThreads(comments);
assert.equal(actualThreads.length, 2);
assert.equal(
actualThreads[0].start_datetime, '2015-12-23 15:00:20.396000000');
assert.equal(actualThreads[0].commentSide, 'left');
assert.equal(actualThreads[0].comments.length, 2);
assert.deepEqual(actualThreads[0].comments[0], comments[0]);
assert.deepEqual(actualThreads[0].comments[1], comments[1]);
assert.equal(actualThreads[0].patchNum, undefined);
assert.equal(actualThreads[0].rootId, 'sallys_confession');
assert.equal(actualThreads[0].lineNum, 1);
assert.equal(
actualThreads[1].start_datetime, '2015-12-20 15:01:20.396000000');
assert.equal(actualThreads[1].commentSide, 'left');
assert.equal(actualThreads[1].comments.length, 1);
assert.deepEqual(actualThreads[1].comments[0], comments[2]);
assert.equal(actualThreads[1].patchNum, undefined);
assert.equal(actualThreads[1].rootId, 'new_draft');
assert.equal(actualThreads[1].lineNum, undefined);
});
test('_createThreads inherits patchNum and range', () => {
const comments = [{
id: 'betsys_confession',
message: 'i like you, jack',
updated: '2015-12-24 15:00:10.396000000',
range: {
start_line: 1,
start_character: 1,
end_line: 1,
end_character: 2,
},
patch_set: 5,
__commentSide: 'left',
line: 1,
}];
expectedThreads = [
{
start_datetime: '2015-12-24 15:00:10.396000000',
commentSide: 'left',
comments: [{
id: 'betsys_confession',
message: 'i like you, jack',
updated: '2015-12-24 15:00:10.396000000',
range: {
start_line: 1,
start_character: 1,
end_line: 1,
end_character: 2,
},
patch_set: 5,
__commentSide: 'left',
line: 1,
}],
patchNum: 5,
rootId: 'betsys_confession',
range: {
start_line: 1,
start_character: 1,
end_line: 1,
end_character: 2,
},
lineNum: 1,
isOnParent: false,
},
];
assert.deepEqual(
element._createThreads(comments),
expectedThreads);
});
test('_createThreads does not thread unrelated comments at same location',
() => {
const comments = [
{
id: 'sallys_confession',
message: 'i like you, jack',
updated: '2015-12-23 15:00:20.396000000',
__commentSide: 'left',
}, {
id: 'jacks_reply',
message: 'i like you, too',
updated: '2015-12-24 15:01:20.396000000',
__commentSide: 'left',
},
];
assert.equal(element._createThreads(comments).length, 2);
});
test('_createThreads derives isOnParent using side from first comment',
() => {
const comments = [
{
id: 'sallys_confession',
message: 'i like you, jack',
updated: '2015-12-23 15:00:20.396000000',
// line: 1,
// __commentSide: 'left',
}, {
id: 'jacks_reply',
message: 'i like you, too',
updated: '2015-12-24 15:01:20.396000000',
// __commentSide: 'left',
// line: 1,
in_reply_to: 'sallys_confession',
},
];
assert.equal(element._createThreads(comments)[0].isOnParent, false);
comments[0].side = 'REVISION';
assert.equal(element._createThreads(comments)[0].isOnParent, false);
comments[0].side = 'PARENT';
assert.equal(element._createThreads(comments)[0].isOnParent, true);
});
test('_getOrCreateThread', () => {
const commentSide = 'left';
assert.isOk(element._getOrCreateThread('2', 3,
commentSide, undefined, false));
let threads = Polymer.dom(element.$.diff)
.queryDistributedElements('gr-comment-thread');
assert.equal(threads.length, 1);
assert.equal(threads[0].commentSide, commentSide);
assert.equal(threads[0].range, undefined);
assert.equal(threads[0].isOnParent, false);
assert.equal(threads[0].patchNum, 2);
// Try to fetch a thread with a different range.
range = {
start_line: 1,
start_character: 1,
end_line: 1,
end_character: 3,
};
assert.isOk(element._getOrCreateThread(
'3', 1, commentSide, range, true));
threads = Polymer.dom(element.$.diff)
.queryDistributedElements('gr-comment-thread');
assert.equal(threads.length, 2);
assert.equal(threads[1].commentSide, commentSide);
assert.equal(threads[1].range, range);
assert.equal(threads[1].isOnParent, true);
assert.equal(threads[1].patchNum, 3);
});
test('_filterThreadElsForLocation with no threads', () => {
const line = {beforeNumber: 3, afterNumber: 5};
const threads = [];
assert.deepEqual(element._filterThreadElsForLocation(threads, line), []);
assert.deepEqual(element._filterThreadElsForLocation(threads, line,
Gerrit.DiffSide.LEFT), []);
assert.deepEqual(element._filterThreadElsForLocation(threads, line,
Gerrit.DiffSide.RIGHT), []);
});
test('_filterThreadElsForLocation for line comments', () => {
const line = {beforeNumber: 3, afterNumber: 5};
const l3 = document.createElement('div');
l3.setAttribute('line-num', 3);
l3.setAttribute('comment-side', 'left');
const l5 = document.createElement('div');
l5.setAttribute('line-num', 5);
l5.setAttribute('comment-side', 'left');
const r3 = document.createElement('div');
r3.setAttribute('line-num', 3);
r3.setAttribute('comment-side', 'right');
const r5 = document.createElement('div');
r5.setAttribute('line-num', 5);
r5.setAttribute('comment-side', 'right');
const threadEls = [l3, l5, r3, r5];
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line),
[l3, r5]);
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
Gerrit.DiffSide.LEFT), [l3]);
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
Gerrit.DiffSide.RIGHT), [r5]);
});
test('_filterThreadElsForLocation for file comments', () => {
const line = {beforeNumber: 'FILE', afterNumber: 'FILE'};
const l = document.createElement('div');
l.setAttribute('comment-side', 'left');
const r = document.createElement('div');
r.setAttribute('comment-side', 'right');
const threadEls = [l, r];
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line),
[l, r]);
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
Gerrit.DiffSide.BOTH), [l, r]);
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
Gerrit.DiffSide.LEFT), [l]);
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
Gerrit.DiffSide.RIGHT), [r]);
});
suite('_translateChunksToIgnore', () => {
let content;
setup(() => {
content = [
{ab: ['one', 'two']},
{a: ['three'], b: ['different three']},
{b: ['four']},
{ab: ['five', 'six']},
{a: ['seven']},
{ab: ['eight', 'nine']},
];
});
test('does nothing to unmarked diff', () => {
assert.deepEqual(element._translateChunksToIgnore({content}),
{content});
});
test('merges marked delta chunk', () => {
content[1].common = true;
assert.deepEqual(element._translateChunksToIgnore({content}), {
content: [
{ab: ['one', 'two', 'different three']},
{b: ['four']},
{ab: ['five', 'six']},
{a: ['seven']},
{ab: ['eight', 'nine']},
],
});
});
test('merges marked addition chunk', () => {
content[2].common = true;
assert.deepEqual(element._translateChunksToIgnore({content}), {
content: [
{ab: ['one', 'two']},
{a: ['three'], b: ['different three']},
{ab: ['four', 'five', 'six']},
{a: ['seven']},
{ab: ['eight', 'nine']},
],
});
});
test('merges multiple marked delta', () => {
content[1].common = true;
content[2].common = true;
assert.deepEqual(element._translateChunksToIgnore({content}), {
content: [
{ab: ['one', 'two', 'different three', 'four', 'five', 'six']},
{a: ['seven']},
{ab: ['eight', 'nine']},
],
});
});
test('marked deletion chunks are omitted', () => {
content[4].common = true;
assert.deepEqual(element._translateChunksToIgnore({content}), {
content: [
{ab: ['one', 'two']},
{a: ['three'], b: ['different three']},
{b: ['four']},
{ab: ['five', 'six', 'eight', 'nine']},
],
});
});
test('marked deltas can start shared chunks', () => {
content[0] = {a: ['one'], b: ['two'], common: true};
assert.deepEqual(element._translateChunksToIgnore({content}), {
content: [
{ab: ['two']},
{a: ['three'], b: ['different three']},
{b: ['four']},
{ab: ['five', 'six']},
{a: ['seven']},
{ab: ['eight', 'nine']},
],
});
});
});
});
</script>