blob: 59b3d41ead474a0f39de0350820c88146aa387aa [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (C) 2015 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-change-view</title>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="../../../bower_components/web-component-tester/browser.js"></script>
<script src="../../../bower_components/page/page.js"></script>
<link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
<link rel="import" href="gr-change-view.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-change-view></gr-change-view>
</template>
</test-fixture>
<script>
suite('gr-change-view tests', function() {
var element;
var sandbox;
var showStub;
var TEST_SCROLL_TOP_PX = 100;
setup(function() {
sandbox = sinon.sandbox.create();
showStub = sandbox.stub(page, 'show');
stub('gr-rest-api-interface', {
getConfig: function() { return Promise.resolve({}); },
getAccount: function() { return Promise.resolve(null); },
});
element = fixture('basic');
});
teardown(function(done) {
flush(function() {
sandbox.restore();
done();
});
});
suite('keyboard shortcuts', function() {
test('S should toggle the CL star', function() {
var starStub = sandbox.stub(element.$.changeStar, 'toggleStar');
MockInteractions.pressAndReleaseKeyOn(element, 83, null, 's');
assert(starStub.called);
});
test('U should navigate to / if no backPage set', function() {
MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
assert(showStub.lastCall.calledWithExactly('/'));
});
test('U should navigate to backPage if set', function() {
element.backPage = '/dashboard/self';
MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
assert(showStub.lastCall.calledWithExactly('/dashboard/self'));
});
test('A fires an error event when not logged in', function(done) {
sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(false));
var loggedInErrorSpy = sandbox.spy();
element.addEventListener('show-auth-required', loggedInErrorSpy);
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
flush(function() {
assert.isFalse(element.$.replyOverlay.opened);
assert.isTrue(loggedInErrorSpy.called);
done();
});
});
test('shift A does not open reply overlay', function(done) {
sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
flush(function() {
assert.isFalse(element.$.replyOverlay.opened);
done();
});
});
test('A toggles overlay when logged in', function(done) {
sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
flush(function() {
assert.isTrue(element.$.replyOverlay.opened);
element.$.replyOverlay.close();
assert.isFalse(element.$.replyOverlay.opened);
done();
});
});
test('X should expand all messages', function() {
var handleExpand =
sandbox.stub(element.$.messageList, 'handleExpandCollapse');
MockInteractions.pressAndReleaseKeyOn(element, 88, null, 'x');
assert(handleExpand.calledWith(true));
});
test('Z should collapse all messages', function() {
var handleExpand =
sandbox.stub(element.$.messageList, 'handleExpandCollapse');
MockInteractions.pressAndReleaseKeyOn(element, 90, null, 'z');
assert(handleExpand.calledWith(false));
});
test('shift + R should fetch and navigate to the latest patch set',
function(done) {
element._changeNum = '42';
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 1,
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
_number: 42,
revisions: {
rev1: {_number: 1},
},
current_revision: 'rev1',
status: 'NEW',
labels: {},
actions: {},
};
sandbox.stub(element.$.actions, 'reload');
showStub.restore();
showStub = sandbox.stub(page, 'show', function(arg) {
assert.equal(arg, '/c/42');
done();
});
MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
});
test('d should open download overlay', function() {
var stub = sandbox.stub(element.$.downloadOverlay, 'open');
MockInteractions.pressAndReleaseKeyOn(element, 68, null, 'd');
assert.isTrue(stub.called);
});
});
test('_computeDescriptionReadOnly', function() {
assert.equal(element._computeDescriptionReadOnly(false,
{owner: {_account_id: 1}}, {_account_id: 1}), true);
assert.equal(element._computeDescriptionReadOnly(true,
{owner: {_account_id: 0}}, {_account_id: 1}), true);
assert.equal(element._computeDescriptionReadOnly(true,
{owner: {_account_id: 1}}, {_account_id: 1}), false);
});
test('_computeDescriptionPlaceholder', function() {
assert.equal(element._computeDescriptionPlaceholder(true),
'No patch set description');
assert.equal(element._computeDescriptionPlaceholder(false),
'Add a patch set description');
});
test('_computePatchSetDisabled', function() {
var basePatchNum = 'PARENT';
var patchNum = 1;
assert.equal(element._computePatchSetDisabled(patchNum, basePatchNum),
false);
basePatchNum = 1;
assert.equal(element._computePatchSetDisabled(patchNum, basePatchNum),
true);
patchNum = 2;
assert.equal(element._computePatchSetDisabled(patchNum, basePatchNum),
false);
});
test('_prepareCommitMsgForLinkify', function() {
var commitMessage = 'R=test@google.com';
var result = element._prepareCommitMsgForLinkify(commitMessage);
assert.equal(result, 'R=\u200Btest@google.com');
commitMessage = 'R=test@google.com\nR=test@google.com';
var result = element._prepareCommitMsgForLinkify(commitMessage);
assert.equal(result, 'R=\u200Btest@google.com\nR=\u200Btest@google.com');
}),
test('_handleDescriptionChanged', function() {
var putDescStub = sandbox.stub(element.$.restAPI, 'setDescription')
.returns(Promise.resolve({ok: true}));
sandbox.stub(element, '_computeDescriptionReadOnly');
element._changeNum = '42';
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 1,
};
element._selectedPatchNum = '1';
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
rev1: {_number: 1, description: 'test', commit: {commit: 'rev1'}},
},
current_revision: 'rev1',
status: 'NEW',
labels: {},
actions: {},
owner: {_account_id: 1},
};
element._account = {_account_id: 1};
element._loggedIn = true;
flushAsynchronousOperations();
var label = element.$.descriptionLabel;
assert.equal(label.value, 'test');
label.editing = true;
label._inputText = 'test2';
label._save();
flushAsynchronousOperations();
assert.isTrue(putDescStub.called);
assert.equal(putDescStub.args[0][2], 'test2');
});
test('_updateRebaseAction', function() {
var currentRevisionActions = {
cherrypick: {
enabled: true,
label: 'Cherry Pick',
method: 'POST',
title: 'cherrypick'
},
rebase: {
enabled: true,
label: 'Rebase',
method: 'POST',
title: 'Rebase onto tip of branch or parent change'
},
};
// Rebase enabled should always end up true.
// When rebase is enabled initially, rebaseOnCurrent should be set to
// true.
assert.equal(element._updateRebaseAction(currentRevisionActions),
currentRevisionActions);
assert.isTrue(currentRevisionActions.rebase.enabled);
assert.isTrue(currentRevisionActions.rebase.rebaseOnCurrent);
delete currentRevisionActions.rebase.enabled;
// When rebase is not enabled initially, rebaseOnCurrent should be set to
// false.
assert.equal(element._updateRebaseAction(currentRevisionActions),
currentRevisionActions);
assert.isTrue(currentRevisionActions.rebase.enabled);
assert.isFalse(currentRevisionActions.rebase.rebaseOnCurrent);
});
test('_reload is called when an approved label is removed', function() {
var vote = {_account_id: 1, name: 'bojack', value: 1};
element._changeNum = '42';
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 1,
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
rev2: {_number: 2},
rev1: {_number: 1},
rev13: {_number: 13},
rev3: {_number: 3},
},
current_revision: 'rev3',
status: 'NEW',
labels: {
test: {
all: [vote],
default_value: 0,
values: [],
approved: {},
},
},
};
flushAsynchronousOperations();
var reloadStub = sandbox.stub(element, '_reload');
element.splice('_change.labels.test.all', 0, 1);
assert.isFalse(reloadStub.called);
element._change.labels.test.all.push(vote);
element._change.labels.test.all.push(vote);
element._change.labels.test.approved = vote;
flushAsynchronousOperations();
element.splice('_change.labels.test.all', 0, 2);
assert.isTrue(reloadStub.called);
assert.isTrue(reloadStub.calledOnce);
});
test('reply button has updated count when there are drafts', function() {
var replyButton = element.$$('gr-button.reply');
assert.ok(replyButton);
assert.equal(replyButton.textContent, 'Reply');
element._diffDrafts = null;
assert.equal(replyButton.textContent, 'Reply');
element._diffDrafts = {};
assert.equal(replyButton.textContent, 'Reply');
element._diffDrafts = {
'file1.txt': [{}],
'file2.txt': [{}, {}],
};
assert.equal(replyButton.textContent, 'Reply (3)');
});
test('comment events properly update diff drafts', function() {
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 2,
};
var draft = {
__draft: true,
id: 'id1',
path: '/foo/bar.txt',
text: 'hello',
};
element._handleCommentSave({target: {comment: draft}});
draft.patch_set = 2;
assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
draft.patch_set = null;
draft.text = 'hello, there';
element._handleCommentSave({target: {comment: draft}});
draft.patch_set = 2;
assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
var draft2 = {
__draft: true,
id: 'id2',
path: '/foo/bar.txt',
text: 'hola',
};
element._handleCommentSave({target: {comment: draft2}});
draft2.patch_set = 2;
assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft, draft2]});
draft.patch_set = null;
element._handleCommentDiscard({target: {comment: draft}});
draft.patch_set = 2;
assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft2]});
element._handleCommentDiscard({target: {comment: draft2}});
assert.deepEqual(element._diffDrafts, {});
});
test('change num change', function() {
element._changeNum = null;
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 2,
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
labels: {},
};
element.viewState.changeNum = null;
element.viewState.diffMode = 'UNIFIED';
assert.equal(element.viewState.numFilesShown, 200);
assert.equal(element._numFilesShown, 200);
element._numFilesShown = 150;
flushAsynchronousOperations();
assert.equal(element.viewState.diffMode, 'UNIFIED');
assert.equal(element.viewState.numFilesShown, 150);
element._changeNum = '1';
element.params = {changeNum: '1'};
element._change.newProp = '1';
flushAsynchronousOperations();
assert.equal(element.viewState.diffMode, 'UNIFIED');
assert.equal(element.viewState.changeNum, '1');
element._changeNum = '2';
element.params = {changeNum: '2'};
element._change.newProp = '2';
flushAsynchronousOperations();
assert.isNull(element.viewState.diffMode);
assert.equal(element.viewState.changeNum, '2');
assert.equal(element.viewState.numFilesShown, 200);
assert.equal(element._numFilesShown, 200);
});
test('patch num change', function(done) {
element._changeNum = '42';
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 2,
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
rev2: {_number: 2},
rev1: {_number: 1},
rev13: {_number: 13},
rev3: {_number: 3},
},
current_revision: 'rev3',
status: 'NEW',
labels: {},
};
element.viewState.diffMode = 'UNIFIED';
flushAsynchronousOperations();
var selectEl = element.$$('.patchInfo-header select');
assert.ok(selectEl);
var optionEls = Polymer.dom(element.root).querySelectorAll(
'.patchInfo-header option');
assert.equal(optionEls.length, 4);
var select = element.$$('.patchInfo-header #patchSetSelect').bindValue;
assert.notEqual(select, 1);
assert.equal(select, 2);
assert.notEqual(select, 3);
assert.equal(optionEls[3].value, 13);
var numEvents = 0;
selectEl.addEventListener('change', function(e) {
assert.equal(element.viewState.diffMode, 'UNIFIED');
numEvents++;
if (numEvents == 1) {
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
'Should navigate to /c/42/1');
selectEl.value = '3';
element.fire('change', {}, {node: selectEl});
} else if (numEvents == 2) {
assert(showStub.lastCall.calledWithExactly('/c/42/3'),
'Should navigate to /c/42/3');
done();
}
});
selectEl.value = '1';
element.fire('change', {}, {node: selectEl});
});
test('patch num change with missing current_revision', function(done) {
element._changeNum = '42';
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 2,
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
rev2: {_number: 2},
rev1: {_number: 1},
rev13: {_number: 13},
rev3: {_number: 3},
},
status: 'NEW',
labels: {},
};
flushAsynchronousOperations();
var selectEl = element.$$('.patchInfo-header select');
assert.ok(selectEl);
var optionEls = Polymer.dom(element.root).querySelectorAll(
'.patchInfo-header option');
assert.equal(optionEls.length, 4);
assert.notEqual(
element.$$('.patchInfo-header #patchSetSelect').bindValue, 1);
assert.equal(
element.$$('.patchInfo-header #patchSetSelect').bindValue, 2);
assert.notEqual(
element.$$('.patchInfo-header #patchSetSelect').bindValue, 3);
assert.equal(optionEls[3].value, 13);
var numEvents = 0;
selectEl.addEventListener('change', function(e) {
numEvents++;
if (numEvents == 1) {
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
'Should navigate to /c/42/1');
selectEl.value = '3';
element.fire('change', {}, {node: selectEl});
} else if (numEvents == 2) {
assert(showStub.lastCall.calledWithExactly('/c/42/3'),
'Should navigate to /c/42/3');
done();
}
});
selectEl.value = '1';
element.fire('change', {}, {node: selectEl});
});
test('don’t reload entire page when patchRange changes', function() {
var reloadStub = sandbox.stub(element, '_reload',
function() { return Promise.resolve(); });
var reloadPatchDependentStub = sandbox.stub(element,
'_reloadPatchNumDependentResources',
function() { return Promise.resolve(); });
var relatedClearSpy = sandbox.spy(element.$.relatedChanges, 'clear');
var value = {
view: 'gr-change-view',
patchNum: '1',
};
element._paramsChanged(value);
assert.isTrue(reloadStub.calledOnce);
assert.isTrue(relatedClearSpy.calledOnce);
element._initialLoadComplete = true;
value.basePatchNum = '1';
value.patchNum = '2';
element._paramsChanged(value);
assert.isFalse(reloadStub.calledTwice);
assert.isTrue(reloadPatchDependentStub.calledOnce);
assert.isTrue(relatedClearSpy.calledOnce);
});
test('reload entire page when patchRange doesnt change', function() {
var reloadStub = sandbox.stub(element, '_reload',
function() { return Promise.resolve(); });
var value = {
view: 'gr-change-view',
};
element._paramsChanged(value);
assert.isTrue(reloadStub.calledOnce);
element._initialLoadComplete = true;
element._paramsChanged(value);
assert.isTrue(reloadStub.calledTwice);
});
test('include base patch when not parent', function() {
element._changeNum = '42';
element._patchRange = {
basePatchNum: '2',
patchNum: '3',
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
rev2: {_number: 2},
rev1: {_number: 1},
rev13: {_number: 13},
rev3: {_number: 3},
},
status: 'NEW',
labels: {},
};
element._changePatchNum(13);
assert(showStub.lastCall.calledWithExactly('/c/42/2..13'));
element._patchRange.basePatchNum = 'PARENT';
element._changePatchNum(3);
assert(showStub.lastCall.calledWithExactly('/c/42/3'));
});
test('related changes are updated and new patch selected after rebase',
function(done) {
element._changeNum = '42';
sandbox.stub(element, 'computeLatestPatchNum', function() {
return 1;
});
sandbox.stub(element, '_reload',
function() { return Promise.resolve(); });
var e = {detail: {action: 'rebase'}};
element._handleReloadChange(e).then(function() {
assert.isTrue(showStub.lastCall.calledWithExactly('/c/42'));
done();
});
});
test('related changes are not updated after other action', function(done) {
sandbox.stub(element, '_reload',
function() { return Promise.resolve(); });
sandbox.stub(element, '_updateSelected');
sandbox.stub(element.$.relatedChanges, 'reload');
var e = {detail: {action: 'abandon'}};
element._handleReloadChange(e).then(function() {
assert.isFalse(showStub.called);
done();
});
});
test('change status new', function() {
element._changeNum = '1';
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 1,
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
rev1: {_number: 1},
},
current_revision: 'rev1',
status: 'NEW',
labels: {},
};
var status = element._computeChangeStatus(element._change, '1');
assert.equal(status, '');
});
test('change status draft', function() {
element._changeNum = '1';
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 1,
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
rev1: {_number: 1},
},
current_revision: 'rev1',
status: 'DRAFT',
labels: {},
};
var status = element._computeChangeStatus(element._change, '1');
assert.equal(status, 'Draft');
});
test('change status merged', function() {
element._changeNum = '1';
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 1,
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
rev1: {_number: 1},
},
current_revision: 'rev1',
status: element.ChangeStatus.MERGED,
labels: {},
};
var status = element._computeChangeStatus(element._change, '1');
assert.equal(status, 'Merged');
});
test('revision status draft', function() {
element._changeNum = '1';
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 1,
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
rev1: {_number: 1},
rev2: {
_number: 2,
draft: true,
},
},
current_revision: 'rev1',
status: 'NEW',
labels: {},
};
var status = element._computeChangeStatus(element._change, '2');
assert.equal(status, 'Draft');
});
test('_computeMergedCommitInfo', function() {
var dummyRevs = {
1: {commit: {commit: 1}},
2: {commit: {}},
};
assert.deepEqual(element._computeMergedCommitInfo(0, dummyRevs), {});
assert.deepEqual(element._computeMergedCommitInfo(1, dummyRevs),
dummyRevs[1].commit);
// Regression test for issue 5337.
var commit = element._computeMergedCommitInfo(2, dummyRevs);
assert.notDeepEqual(commit, dummyRevs[2]);
assert.deepEqual(commit, {commit: 2});
});
test('get latest revision', function() {
var change = {
revisions: {
rev1: {_number: 1},
rev3: {_number: 3},
},
current_revision: 'rev3',
};
assert.equal(element._getLatestRevisionSHA(change), 'rev3');
change = {
revisions: {
rev1: {_number: 1},
},
};
assert.equal(element._getLatestRevisionSHA(change), 'rev1');
});
test('show commit message edit button', function() {
var _change = {
status: element.ChangeStatus.MERGED,
};
assert.isTrue(element._computeHideEditCommitMessage(false, false, {}));
assert.isTrue(element._computeHideEditCommitMessage(true, true, {}));
assert.isTrue(element._computeHideEditCommitMessage(false, true, {}));
assert.isFalse(element._computeHideEditCommitMessage(true, false, {}));
assert.isTrue(element._computeHideEditCommitMessage(true, false,
_change));
});
test('_computeChangeIdCommitMessageError', function() {
var commitMessage =
'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483';
var change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
assert.equal(
element._computeChangeIdCommitMessageError(commitMessage, change),
null);
change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
assert.equal(
element._computeChangeIdCommitMessageError(commitMessage, change),
'mismatch');
commitMessage = 'This is the greatest change.';
assert.equal(
element._computeChangeIdCommitMessageError(commitMessage, change),
'missing');
});
test('multiple change Ids in commit message picks last', function() {
var commitMessage = [
'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
].join('\n');
var change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
assert.equal(
element._computeChangeIdCommitMessageError(commitMessage, change),
null);
change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
assert.equal(
element._computeChangeIdCommitMessageError(commitMessage, change),
'mismatch');
});
test('does not count change Id that starts mid line', function() {
var commitMessage = [
'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
].join(' and ');
var change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
assert.equal(
element._computeChangeIdCommitMessageError(commitMessage, change),
null);
change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
assert.equal(
element._computeChangeIdCommitMessageError(commitMessage, change),
'mismatch');
});
test('_computeTitleAttributeWarning', function() {
var changeIdCommitMessageError = 'missing';
assert.equal(
element._computeTitleAttributeWarning(changeIdCommitMessageError),
'No Change-Id in commit message');
var changeIdCommitMessageError = 'mismatch';
assert.equal(
element._computeTitleAttributeWarning(changeIdCommitMessageError),
'Change-Id mismatch');
});
test('_computeChangeIdClass', function() {
var changeIdCommitMessageError = 'missing';
assert.equal(
element._computeChangeIdClass(changeIdCommitMessageError), '');
var changeIdCommitMessageError = 'mismatch';
assert.equal(
element._computeChangeIdClass(changeIdCommitMessageError), 'warning');
});
test('topic is coalesced to null', function(done) {
sandbox.stub(element, '_changeChanged');
sandbox.stub(element.$.restAPI, 'getChangeDetail', function() {
return Promise.resolve({
id: '123456789',
labels: {},
current_revision: 'foo',
revisions: {foo: {commit: {}}},
});
});
element._getChangeDetail().then(function() {
assert.isNull(element._change.topic);
done();
});
});
test('commit sha is populated from getChangeDetail', function(done) {
sandbox.stub(element, '_changeChanged');
sandbox.stub(element.$.restAPI, 'getChangeDetail', function() {
return Promise.resolve({
id: '123456789',
labels: {},
current_revision: 'foo',
revisions: {foo: {commit: {}}},
});
});
element._getChangeDetail().then(function() {
assert.equal('foo', element._commitInfo.commit);
done();
});
});
test('reply dialog focus can be controlled', function() {
var FocusTarget = element.$.replyDialog.FocusTarget;
var openStub = sandbox.stub(element, '_openReplyDialog');
var e = {detail: {}};
element._handleShowReplyDialog(e);
assert(openStub.lastCall.calledWithExactly(FocusTarget.REVIEWERS),
'_openReplyDialog should have been passed REVIEWERS');
e.detail.value = {ccsOnly: true};
element._handleShowReplyDialog(e);
assert(openStub.lastCall.calledWithExactly(FocusTarget.CCS),
'_openReplyDialog should have been passed CCS');
});
test('class is applied to file list on old patch set', function() {
var allPatchSets = [{num: 1}, {num: 2}, {num: 4}];
assert.equal(element._computePatchInfoClass('1', allPatchSets),
'patchInfo--oldPatchSet');
assert.equal(element._computePatchInfoClass('2', allPatchSets),
'patchInfo--oldPatchSet');
assert.equal(element._computePatchInfoClass('4', allPatchSets), '');
});
test('getUrlParameter functionality', function() {
var locationStub = sandbox.stub(element, '_getLocationSearch');
locationStub.returns('?test');
assert.equal(element._getUrlParameter('test'), 'test');
locationStub.returns('?test2=12&test=3');
assert.equal(element._getUrlParameter('test'), 'test');
locationStub.returns('');
assert.isNull(element._getUrlParameter('test'));
locationStub.returns('?');
assert.isNull(element._getUrlParameter('test'));
locationStub.returns('?test2');
assert.isNull(element._getUrlParameter('test'));
});
test('revert dialog opened with revert param', function(done) {
sandbox.stub(element.$.restAPI, 'getLoggedIn', function() {
return Promise.resolve(true);
});
sandbox.stub(Gerrit, 'awaitPluginsLoaded', function() {
return Promise.resolve();
});
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 2,
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
rev1: {_number: 1},
},
current_revision: 'rev1',
status: element.ChangeStatus.MERGED,
labels: {},
actions: {},
};
var urlParamStub = sandbox.stub(element, '_getUrlParameter',
function(param) {
assert.equal(param, 'revert');
return param;
});
var revertDialogStub = sandbox.stub(element.$.actions, 'showRevertDialog',
done);
element._maybeShowRevertDialog();
assert.isTrue(Gerrit.awaitPluginsLoaded.called);
});
suite('scroll related tests', function() {
test('document scrolling calls function to set scroll height',
function(done) {
var originalHeight = document.body.scrollHeight;
var scrollStub = sandbox.stub(element, '_handleScroll',
function() {
assert.isTrue(scrollStub.called);
document.body.style.height =
originalHeight + 'px';
scrollStub.restore();
done();
});
document.body.style.height = '10000px';
document.body.scrollTop = TEST_SCROLL_TOP_PX;
element._handleScroll();
});
test('history is loaded correctly', function() {
history.replaceState(
{
scrollTop: 100,
path: location.pathname,
},
location.pathname);
var reloadStub = sandbox.stub(element, '_reload',
function() {
// When element is reloaded, ensure that the history
// state has the scrollTop set earlier. This will then
// be reset.
assert.isTrue(history.state.scrollTop == 100);
return Promise.resolve({});
});
// simulate reloading component, which is done when route
// changes to match a regex of change view type.
element._paramsChanged({view: 'gr-change-view'});
});
});
suite('reply dialog tests', function() {
setup(function() {
sandbox.stub(element.$.replyDialog, '_draftChanged');
});
test('reply from comment adds quote text', function() {
var e = {detail: {message: {message: 'quote text'}}};
element._handleMessageReply(e);
assert.equal(element.$.replyDialog.draft, '> quote text\n\n');
assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
});
test('reply from comment replaces quote text', function() {
element.$.replyDialog.draft = '> old quote text\n\n some draft text';
element.$.replyDialog.quote = '> old quote text\n\n';
var e = {detail: {message: {message: 'quote text'}}};
element._handleMessageReply(e);
assert.equal(element.$.replyDialog.draft, '> quote text\n\n');
assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
});
test('reply from same comment preserves quote text', function() {
element.$.replyDialog.draft = '> quote text\n\n some draft text';
element.$.replyDialog.quote = '> quote text\n\n';
var e = {detail: {message: {message: 'quote text'}}};
element._handleMessageReply(e);
assert.equal(element.$.replyDialog.draft,
'> quote text\n\n some draft text');
assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
});
test('reply from top of page contains previous draft', function() {
var div = document.createElement('div');
element.$.replyDialog.draft = '> quote text\n\n some draft text';
element.$.replyDialog.quote = '> quote text\n\n';
var e = {target: div, preventDefault: sandbox.spy()};
element._handleReplyTap(e);
assert.equal(element.$.replyDialog.draft,
'> quote text\n\n some draft text');
assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
});
});
test('reply button is disabled until server config is loaded', function() {
assert.isTrue(element._replyDisabled);
element.serverConfig = {};
assert.isFalse(element._replyDisabled);
});
suite('commit message expand/collapse', function() {
test('commitCollapseToggle hidden for short commit message', function() {
element._latestCommitMessage = '';
assert.isTrue(element.$.commitCollapseToggle.hasAttribute('hidden'));
});
test('commitCollapseToggle shown for long commit message', function() {
element._latestCommitMessage = _.times(31, String).join('\n');
assert.isFalse(element.$.commitCollapseToggle.hasAttribute('hidden'));
});
test('commitCollapseToggle functions', function() {
element._latestCommitMessage = _.times(31, String).join('\n');
assert.isTrue(element._commitCollapsed);
assert.isTrue(
element.$.commitMessage.classList.contains('collapsed'));
MockInteractions.tap(element.$.commitCollapseToggleButton);
assert.isFalse(element._commitCollapsed);
assert.isFalse(
element.$.commitMessage.classList.contains('collapsed'));
});
});
suite('related changes expand/collapse', function() {
var updateHeightSpy;
setup(function() {
updateHeightSpy = sandbox.spy(element, '_updateRelatedChangeMaxHeight');
});
test('relatedChangesToggle shown height greater than changeInfo height',
function() {
assert.isTrue(element.$.relatedChangesToggle.hasAttribute('hidden'));
sandbox.stub(element, '_getOffsetHeight', function() {
return 50;
});
sandbox.stub(element, '_getScrollHeight', function() {
return 60;
});
element._relatedChangesLoading = false;
assert.isFalse(element.$.relatedChangesToggle.hasAttribute('hidden'));
assert.equal(updateHeightSpy.callCount, 1);
});
test('relatedChangesToggle hidden height less than changeInfo height',
function() {
assert.isTrue(element.$.relatedChangesToggle.hasAttribute('hidden'));
sandbox.stub(element, '_getOffsetHeight', function() {
return 50;
});
sandbox.stub(element, '_getScrollHeight', function() {
return 40;
});
element._relatedChangesLoading = false;
assert.isTrue(element.$.relatedChangesToggle.hasAttribute('hidden'));
assert.equal(updateHeightSpy.callCount, 1);
});
test('relatedChangesToggle functions', function() {
sandbox.stub(element, '_getOffsetHeight', function() {
return 50;
});
sandbox.stub(element, '_getScrollHeight', function() {
return 60;
});
element._relatedChangesLoading = false;
assert.isTrue(element._relatedChangesCollapsed);
assert.isTrue(
element.$.relatedChanges.classList.contains('collapsed'));
MockInteractions.tap(element.$.relatedChangesToggleButton);
assert.isFalse(element._relatedChangesCollapsed);
assert.isFalse(
element.$.relatedChanges.classList.contains('collapsed'));
});
test('_updateRelatedChangeMaxHeight without commit toggle', function() {
sandbox.stub(element, '_getOffsetHeight', function() {
return 50;
});
sandbox.stub(element, '_getLineHeight', function() {
return 12;
});
// 50 (existing height) - 24 (extra height) = 26 (adjusted height).
// 50 (existing height) % 12 (line height) = 2 (remainder).
// 26 (adjusted height) - 2 (remainder) = 24 (max height to set).
element._updateRelatedChangeMaxHeight();
assert.equal(element.customStyle['--relation-chain-max-height'],
'24px');
assert.equal(element.customStyle['--related-change-btn-top-padding'],
undefined);
});
test('_updateRelatedChangeMaxHeight with commit toggle', function() {
element._latestCommitMessage = _.times(31, String).join('\n');
sandbox.stub(element, '_getOffsetHeight', function() {
return 50;
});
sandbox.stub(element, '_getLineHeight', function() {
return 12;
});
// 50 (existing height) % 12 (line height) = 2 (remainder).
// 50 (existing height) - 2 (remainder) = 48 (max height to set).
element._updateRelatedChangeMaxHeight();
assert.equal(element.customStyle['--relation-chain-max-height'],
'48px');
assert.equal(element.customStyle['--related-change-btn-top-padding'],
'2px');
});
suite('update checks', function() {
setup(function() {
sandbox.spy(element, '_startUpdateCheckTimer');
sandbox.stub(element, 'async', function(f) {
// Only fire the async callback one time.
if (element.async.callCount > 1) { return; }
f.call(element);
});
});
test('_startUpdateCheckTimer negative delay', function() {
sandbox.stub(element, 'fetchIsLatestKnown');
element.serverConfig = {change: {update_delay: -1}};
assert.isTrue(element._startUpdateCheckTimer.called);
assert.isFalse(element.fetchIsLatestKnown.called);
});
test('_startUpdateCheckTimer up-to-date', function() {
sandbox.stub(element, 'fetchIsLatestKnown',
function() { return Promise.resolve(true); });
element.serverConfig = {change: {update_delay: 12345}};
assert.isTrue(element._startUpdateCheckTimer.called);
assert.isTrue(element.fetchIsLatestKnown.called);
assert.equal(element.async.lastCall.args[1], 12345 * 1000);
});
test('_startUpdateCheckTimer out-of-date shows an alert',
function(done) {
sandbox.stub(element, 'fetchIsLatestKnown',
function() { return Promise.resolve(false); });
element.addEventListener('show-alert', function() {
done();
});
element.serverConfig = {change: {update_delay: 12345}};
});
});
});
});
</script>