Kasper Nilsson a7f7f3bf47 Remove two-way databinding from patch range select
Two-way databinding was causing some cyclical UI updating, resulting in
an incorrect redirect URL. Instead of binding to the patchNum and
basePatchNum in both directions, the patch-range-select fires an event
when it notices a change in the selected patchsets.

Bug: Issue 7336, Issue 7315, Issue 7316
Change-Id: Ifdf476dcf4fa1353d0b280d7e6dd25e4ef40865a
2017-10-03 12:41:30 +00:00

337 lines
9.4 KiB
HTML

<!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-patch-range-select</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"/>
<script src="../../../bower_components/page/page.js"></script>
<link rel="import" href="gr-patch-range-select.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-patch-range-select auto></gr-patch-range-select>
</template>
</test-fixture>
<script>
suite('gr-patch-range-select tests', () => {
let element;
let sandbox;
setup(() => {
element = fixture('basic');
sandbox = sinon.sandbox.create();
});
teardown(() => sandbox.restore());
test('enabled/disabled options', () => {
const patchRange = {
basePatchNum: 'PARENT',
patchNum: '3',
};
const sortedRevisions = [
{_number: 1},
{_number: 2},
{_number: element.EDIT_NAME, basePatchNum: 2},
{_number: 3},
];
for (const patchNum of ['1', '2', '3']) {
assert.isFalse(element._computeRightDisabled(patchNum,
patchRange.basePatchNum, sortedRevisions));
}
for (const patchNum of ['PARENT', '1', '2']) {
assert.isFalse(element._computeLeftDisabled(patchNum,
patchRange.patchNum, sortedRevisions));
}
assert.isTrue(element._computeLeftDisabled('3', patchRange.patchNum));
patchRange.basePatchNum = element.EDIT_NAME;
assert.isTrue(element._computeLeftDisabled('3', patchRange.patchNum,
sortedRevisions));
assert.isTrue(element._computeRightDisabled('1', patchRange.basePatchNum,
sortedRevisions));
assert.isTrue(element._computeRightDisabled('2', patchRange.basePatchNum,
sortedRevisions));
assert.isFalse(element._computeRightDisabled('3', patchRange.basePatchNum,
sortedRevisions));
assert.isTrue(element._computeRightDisabled(element.EDIT_NAME,
patchRange.basePatchNum, sortedRevisions));
});
test('_computeBaseDropdownContent', () => {
element.comments = {};
const availablePatches = [
{num: 1},
{num: 2},
{num: 3},
{num: 'edit'},
];
const revisions = [
{
commit: {},
_number: 2,
description: 'description',
},
{commit: {}},
{commit: {}},
{commit: {}},
];
const patchNum = 1;
const sortedRevisions = [
{_number: 1},
{_number: 2},
{_number: element.EDIT_NAME, basePatchNum: 2},
{_number: 3},
];
const expectedResult = [
{
text: 'Base',
value: 'PARENT',
},
{
disabled: true,
triggerText: 'Patchset 1',
text: 'Patchset 1',
mobileText: '1',
bottomText: '',
value: 1,
},
{
disabled: true,
triggerText: 'Patchset 2',
text: 'Patchset 2',
mobileText: '2 description',
bottomText: 'description',
value: 2,
},
{
disabled: true,
triggerText: 'Patchset 3',
text: 'Patchset 3',
mobileText: '3',
bottomText: '',
value: 3,
},
{
disabled: true,
triggerText: 'Patchset edit',
text: 'Patchset edit',
mobileText: 'edit',
bottomText: '',
value: 'edit',
},
];
assert.deepEqual(element._computeBaseDropdownContent(availablePatches,
patchNum, sortedRevisions, revisions), expectedResult);
});
test('_computeBaseDropdownContent called when patchNum updates', () => {
element.revisions = [
{commit: {}},
{commit: {}},
{commit: {}},
{commit: {}},
];
element.availablePatches = [
{num: 1},
{num: 2},
{num: 3},
{num: 'edit'},
];
element.patchNum = 2;
element.basePatchNum = 'PARENT';
flushAsynchronousOperations();
sandbox.stub(element, '_computeBaseDropdownContent');
// Should be recomputed for each available patch
element.set('patchNum', 1);
assert.equal(element._computeBaseDropdownContent.callCount, 1);
});
test('_computePatchDropdownContent called when basePatchNum updates', () => {
element.revisions = [
{commit: {}},
{commit: {}},
{commit: {}},
{commit: {}},
];
element.availablePatches = [
{num: 1},
{num: 2},
{num: 3},
{num: 'edit'},
];
element.patchNum = 2;
element.basePatchNum = 'PARENT';
flushAsynchronousOperations();
// Should be recomputed for each available patch
sandbox.stub(element, '_computePatchDropdownContent');
element.set('basePatchNum', 1);
assert.equal(element._computePatchDropdownContent.callCount, 1);
});
test('_computePatchDropdownContent', () => {
element.comments = {};
const availablePatches = [
{num: 1},
{num: 2},
{num: 3},
{num: 'edit'},
];
const revisions = [
{
commit: {},
_number: 2,
description: 'description',
},
{commit: {}},
{commit: {}},
{commit: {}},
];
const basePatchNum = 1;
const sortedRevisions = [
{_number: 1},
{_number: 2},
{_number: element.EDIT_NAME, basePatchNum: 2},
{_number: 3},
];
const expectedResult = [
{
disabled: true,
triggerText: 'Patchset 1',
text: 'Patchset 1',
mobileText: '1',
bottomText: '',
value: 1,
},
{
disabled: false,
triggerText: 'Patchset 2',
text: 'Patchset 2',
mobileText: '2 description',
bottomText: 'description',
value: 2,
},
{
disabled: false,
triggerText: 'Patchset 3',
text: 'Patchset 3',
mobileText: '3',
bottomText: '',
value: 3,
},
{
disabled: false,
triggerText: 'Patchset edit',
text: 'Patchset edit',
mobileText: 'edit',
bottomText: '',
value: 'edit',
},
];
assert.deepEqual(element._computePatchDropdownContent(availablePatches,
basePatchNum, sortedRevisions, revisions), expectedResult);
});
test('filesWeblinks', () => {
element.filesWeblinks = {
meta_a: [
{
name: 'foo',
url: 'f.oo',
},
],
meta_b: [
{
name: 'bar',
url: 'ba.r',
},
],
};
flushAsynchronousOperations();
const domApi = Polymer.dom(element.root);
assert.equal(
domApi.querySelector('a[href="f.oo"]').textContent, 'foo');
assert.equal(
domApi.querySelector('a[href="ba.r"]').textContent, 'bar');
});
test('_computePatchSetCommentsString', () => {
// Test string with unresolved comments.
comments = {
foo: [{
id: '27dcee4d_f7b77cfa',
message: 'test',
patch_set: 1,
unresolved: true,
}],
bar: [{
id: '27dcee4d_f7b77cfa',
message: 'test',
patch_set: 1,
},
{
id: '27dcee4d_f7b77cfa',
message: 'test',
patch_set: 1,
}],
abc: [],
};
assert.equal(element._computePatchSetCommentsString(comments, 1),
' (3 comments, 1 unresolved)');
// Test string with no unresolved comments.
delete comments['foo'];
assert.equal(element._computePatchSetCommentsString(comments, 1),
' (2 comments)');
// Test string with no comments.
delete comments['bar'];
assert.equal(element._computePatchSetCommentsString(comments, 1), '');
});
test('patch-range-change fires', () => {
const handler = sandbox.stub();
element.basePatchNum = 1;
element.patchNum = 3;
element.addEventListener('patch-range-change', handler);
element.$.basePatchDropdown._handleValueChange(2, [{value: 2}]);
assert.isTrue(handler.calledOnce);
assert.deepEqual(handler.lastCall.args[0].detail,
{basePatchNum: 2, patchNum: 3});
// BasePatchNum should not have changed, due to one-way data binding.
element.$.patchNumDropdown._handleValueChange('edit', [{value: 'edit'}]);
assert.deepEqual(handler.lastCall.args[0].detail,
{basePatchNum: 1, patchNum: 'edit'});
});
});
</script>