Previously, if a user viewed more files or expanded all files, navigated to a diff view, and back to the file list, it would not preserve the state that it was left in. Because the Polymer elements are recreated when the change view reloads, the number of files shown property is reset to the default value. This change adds an attribute in _viewState.changeView to store the number of files shown. It preserves the state of the change view when navigating to pages of a different type (ex: diff) and then back to the change view. When a new change view is rendered (with a different change number), the default files shown is reset. Bug: Issue 5877 Change-Id: I36f9bc64b7d64a23a41c195b2e8188daf47d063f
931 lines
32 KiB
HTML
931 lines
32 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-file-list</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>
|
|
<script src="../../../scripts/util.js"></script>
|
|
|
|
<link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
|
|
<link rel="import" href="gr-file-list.html">
|
|
|
|
<script>void(0);</script>
|
|
|
|
<test-fixture id="basic">
|
|
<template>
|
|
<gr-file-list></gr-file-list>
|
|
</template>
|
|
</test-fixture>
|
|
|
|
<test-fixture id="blank">
|
|
<template>
|
|
<div></div>
|
|
</template>
|
|
</test-fixture>
|
|
|
|
<script>
|
|
suite('gr-file-list tests', function() {
|
|
var element;
|
|
var sandbox;
|
|
var saveStub;
|
|
|
|
setup(function() {
|
|
sandbox = sinon.sandbox.create();
|
|
stub('gr-rest-api-interface', {
|
|
getLoggedIn: function() { return Promise.resolve(true); },
|
|
getPreferences: function() { return Promise.resolve({}); },
|
|
fetchJSON: function() { return Promise.resolve({}); },
|
|
});
|
|
stub('gr-date-formatter', {
|
|
_loadTimeFormat: function() { return Promise.resolve(''); },
|
|
});
|
|
stub('gr-diff', {
|
|
reload: function() { return Promise.resolve(); },
|
|
});
|
|
element = fixture('basic');
|
|
element.numFilesShown = 75;
|
|
saveStub = sandbox.stub(element, '_saveReviewedState',
|
|
function() { return Promise.resolve(); });
|
|
});
|
|
|
|
teardown(function() {
|
|
sandbox.restore();
|
|
});
|
|
|
|
test('get file list', function(done) {
|
|
var getChangeFilesStub = sandbox.stub(element.$.restAPI, 'getChangeFiles',
|
|
function() {
|
|
return Promise.resolve({
|
|
'/COMMIT_MSG': {lines_inserted: 9},
|
|
'tags.html': {lines_deleted: 123},
|
|
'about.txt': {},
|
|
});
|
|
});
|
|
|
|
element._getFiles().then(function(files) {
|
|
var filenames = files.map(function(f) { return f.__path; });
|
|
assert.deepEqual(filenames, ['/COMMIT_MSG', 'about.txt', 'tags.html']);
|
|
assert.deepEqual(files[0], {
|
|
lines_inserted: 9,
|
|
lines_deleted: 0,
|
|
__path: '/COMMIT_MSG',
|
|
});
|
|
assert.deepEqual(files[1], {
|
|
lines_inserted: 0,
|
|
lines_deleted: 0,
|
|
__path: 'about.txt',
|
|
});
|
|
assert.deepEqual(files[2], {
|
|
lines_inserted: 0,
|
|
lines_deleted: 123,
|
|
__path: 'tags.html',
|
|
});
|
|
|
|
getChangeFilesStub.restore();
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('calculate totals for patch number', function() {
|
|
element._files = [
|
|
{__path: '/COMMIT_MSG', lines_inserted: 9},
|
|
{
|
|
__path: 'file_added_in_rev2.txt',
|
|
lines_inserted: 1,
|
|
lines_deleted: 1,
|
|
size_delta: 10,
|
|
size: 100,
|
|
},
|
|
{
|
|
__path: 'myfile.txt',
|
|
lines_inserted: 1,
|
|
lines_deleted: 1,
|
|
size_delta: 10,
|
|
size: 100,
|
|
},
|
|
];
|
|
assert.deepEqual(element._patchChange, {
|
|
inserted: 2,
|
|
deleted: 2,
|
|
size_delta_inserted: 0,
|
|
size_delta_deleted: 0,
|
|
total_size: 0,
|
|
});
|
|
assert.isTrue(element._hideBinaryChangeTotals);
|
|
assert.isFalse(element._hideChangeTotals);
|
|
|
|
// Test with a commit message that isn't the first file.
|
|
element._files = [
|
|
{__path: 'file_added_in_rev2.txt', lines_inserted: 1, lines_deleted: 1},
|
|
{__path: '/COMMIT_MSG', lines_inserted: 9},
|
|
{__path: 'myfile.txt', lines_inserted: 1, lines_deleted: 1},
|
|
];
|
|
assert.deepEqual(element._patchChange, {
|
|
inserted: 2,
|
|
deleted: 2,
|
|
size_delta_inserted: 0,
|
|
size_delta_deleted: 0,
|
|
total_size: 0,
|
|
});
|
|
assert.isTrue(element._hideBinaryChangeTotals);
|
|
assert.isFalse(element._hideChangeTotals);
|
|
|
|
// Test with no commit message.
|
|
element._files = [
|
|
{__path: 'file_added_in_rev2.txt', lines_inserted: 1, lines_deleted: 1},
|
|
{__path: 'myfile.txt', lines_inserted: 1, lines_deleted: 1},
|
|
];
|
|
assert.deepEqual(element._patchChange, {
|
|
inserted: 2,
|
|
deleted: 2,
|
|
size_delta_inserted: 0,
|
|
size_delta_deleted: 0,
|
|
total_size: 0,
|
|
});
|
|
assert.isTrue(element._hideBinaryChangeTotals);
|
|
assert.isFalse(element._hideChangeTotals);
|
|
|
|
// Test with files missing either lines_inserted or lines_deleted.
|
|
element._files = [
|
|
{__path: 'file_added_in_rev2.txt', lines_inserted: 1},
|
|
{__path: 'myfile.txt', lines_deleted: 1},
|
|
];
|
|
assert.deepEqual(element._patchChange, {
|
|
inserted: 1,
|
|
deleted: 1,
|
|
size_delta_inserted: 0,
|
|
size_delta_deleted: 0,
|
|
total_size: 0,
|
|
});
|
|
assert.isTrue(element._hideBinaryChangeTotals);
|
|
assert.isFalse(element._hideChangeTotals);
|
|
});
|
|
|
|
test('binary only files', function() {
|
|
element._files = [
|
|
{__path: '/COMMIT_MSG', lines_inserted: 9},
|
|
{__path: 'file_binary', binary: true, size_delta: 10, size: 100},
|
|
{__path: 'file_binary', binary: true, size_delta: -5, size: 120},
|
|
];
|
|
assert.deepEqual(element._patchChange, {
|
|
inserted: 0,
|
|
deleted: 0,
|
|
size_delta_inserted: 10,
|
|
size_delta_deleted: -5,
|
|
total_size: 220,
|
|
});
|
|
assert.isFalse(element._hideBinaryChangeTotals);
|
|
assert.isTrue(element._hideChangeTotals);
|
|
});
|
|
|
|
test('binary and regular files', function() {
|
|
element._files = [
|
|
{__path: '/COMMIT_MSG', lines_inserted: 9},
|
|
{__path: 'file_binary', binary: true, size_delta: 10, size: 100},
|
|
{__path: 'file_binary', binary: true, size_delta: -5, size: 120},
|
|
{__path: 'myfile.txt', lines_deleted: 5, size_delta: -10, size: 100},
|
|
{__path: 'myfile2.txt', lines_inserted: 10},
|
|
];
|
|
assert.deepEqual(element._patchChange, {
|
|
inserted: 10,
|
|
deleted: 5,
|
|
size_delta_inserted: 10,
|
|
size_delta_deleted: -5,
|
|
total_size: 220,
|
|
});
|
|
assert.isFalse(element._hideBinaryChangeTotals);
|
|
assert.isFalse(element._hideChangeTotals);
|
|
});
|
|
|
|
test('_formatBytes function', function() {
|
|
var table = {
|
|
64: '+64 B',
|
|
1023: '+1023 B',
|
|
1024: '+1 KiB',
|
|
4096: '+4 KiB',
|
|
1073741824: '+1 GiB',
|
|
'-64': '-64 B',
|
|
'-1023': '-1023 B',
|
|
'-1024': '-1 KiB',
|
|
'-4096': '-4 KiB',
|
|
'-1073741824': '-1 GiB',
|
|
0: '+/-0 B',
|
|
};
|
|
|
|
for (var bytes in table) {
|
|
if (table.hasOwnProperty(bytes)) {
|
|
assert.equal(element._formatBytes(bytes), table[bytes]);
|
|
}
|
|
}
|
|
});
|
|
|
|
test('_formatPercentage function', function() {
|
|
var table = [
|
|
{ size: 100,
|
|
delta: 100,
|
|
display: '',
|
|
},
|
|
{ size: 195060,
|
|
delta: 64,
|
|
display: '(+0%)',
|
|
},
|
|
{ size: 195060,
|
|
delta: -64,
|
|
display: '(-0%)',
|
|
},
|
|
{ size: 394892,
|
|
delta: -7128,
|
|
display: '(-2%)',
|
|
},
|
|
{ size: 90,
|
|
delta: -10,
|
|
display: '(-10%)',
|
|
},
|
|
{ size: 110,
|
|
delta: 10,
|
|
display: '(+10%)',
|
|
},
|
|
];
|
|
|
|
table.forEach(function(item) {
|
|
assert.equal(element._formatPercentage(
|
|
item.size, item.delta), item.display);
|
|
});
|
|
});
|
|
|
|
suite('keyboard shortcuts', function() {
|
|
setup(function() {
|
|
element._files = [
|
|
{__path: '/COMMIT_MSG'},
|
|
{__path: 'file_added_in_rev2.txt'},
|
|
{__path: 'myfile.txt'},
|
|
];
|
|
element.changeNum = '42';
|
|
element.patchRange = {
|
|
basePatchNum: 'PARENT',
|
|
patchNum: '2',
|
|
};
|
|
element.$.fileCursor.setCursorAtIndex(0);
|
|
});
|
|
|
|
test('toggle left diff via shortcut', function() {
|
|
var toggleLeftDiffStub = sandbox.stub();
|
|
// Property getter cannot be stubbed w/ sandbox due to a bug in Sinon.
|
|
// https://github.com/sinonjs/sinon/issues/781
|
|
var diffsStub = sinon.stub(element, 'diffs', {
|
|
get: function() {
|
|
return [{toggleLeftDiff: toggleLeftDiffStub}];
|
|
},
|
|
});
|
|
MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
|
|
assert.isTrue(toggleLeftDiffStub.calledOnce);
|
|
diffsStub.restore();
|
|
});
|
|
|
|
test('keyboard shortcuts', function() {
|
|
flushAsynchronousOperations();
|
|
|
|
var items = Polymer.dom(element.root).querySelectorAll('.file-row');
|
|
element.$.fileCursor.stops = items;
|
|
element.$.fileCursor.setCursorAtIndex(0);
|
|
assert.equal(items.length, 3);
|
|
assert.isTrue(items[0].classList.contains('selected'));
|
|
assert.isFalse(items[1].classList.contains('selected'));
|
|
assert.isFalse(items[2].classList.contains('selected'));
|
|
// j with a modifier should not move the cursor.
|
|
MockInteractions.pressAndReleaseKeyOn(element, 74, 'shift', 'j');
|
|
assert.equal(element.$.fileCursor.index, 0);
|
|
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
|
|
assert.equal(element.$.fileCursor.index, 1);
|
|
assert.equal(element.selectedIndex, 1);
|
|
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
|
|
|
|
var showStub = sandbox.stub(page, 'show');
|
|
assert.equal(element.$.fileCursor.index, 2);
|
|
assert.equal(element.selectedIndex, 2);
|
|
MockInteractions.pressAndReleaseKeyOn(element, 13, null, 'enter');
|
|
assert(showStub.lastCall.calledWith('/c/42/2/myfile.txt'),
|
|
'Should navigate to /c/42/2/myfile.txt');
|
|
// k with a modifier should not move the cursor.
|
|
MockInteractions.pressAndReleaseKeyOn(element, 75, 'shift', 'k');
|
|
assert.equal(element.$.fileCursor.index, 2);
|
|
|
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
|
assert.equal(element.$.fileCursor.index, 1);
|
|
assert.equal(element.selectedIndex, 1);
|
|
MockInteractions.pressAndReleaseKeyOn(element, 79, null, 'o');
|
|
assert(showStub.lastCall.calledWith('/c/42/2/file_added_in_rev2.txt'),
|
|
'Should navigate to /c/42/2/file_added_in_rev2.txt');
|
|
|
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
|
assert.equal(element.$.fileCursor.index, 0);
|
|
assert.equal(element.selectedIndex, 0);
|
|
});
|
|
|
|
test('i key shows/hides selected inline diff', function() {
|
|
sandbox.stub(element, '_expandedPathsChanged');
|
|
flushAsynchronousOperations();
|
|
var files = Polymer.dom(element.root).querySelectorAll('.file-row');
|
|
element.$.fileCursor.stops = files;
|
|
element.$.fileCursor.setCursorAtIndex(0);
|
|
MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
|
|
flushAsynchronousOperations();
|
|
assert.include(element._expandedFilePaths, element.diffs[0].path);
|
|
MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
|
|
flushAsynchronousOperations();
|
|
assert.notInclude(element._expandedFilePaths, element.diffs[0].path);
|
|
element.$.fileCursor.setCursorAtIndex(1);
|
|
MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
|
|
flushAsynchronousOperations();
|
|
assert.include(element._expandedFilePaths, element.diffs[1].path);
|
|
|
|
MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'i');
|
|
flushAsynchronousOperations();
|
|
for (var index in element.diffs) {
|
|
assert.include(element._expandedFilePaths, element.diffs[index].path);
|
|
}
|
|
MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'i');
|
|
flushAsynchronousOperations();
|
|
for (var index in element.diffs) {
|
|
assert.notInclude(element._expandedFilePaths,
|
|
element.diffs[index].path);
|
|
}
|
|
});
|
|
|
|
test('_handleEnterKey navigates', function() {
|
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
|
sandbox.stub(element, 'modifierPressed').returns(false);
|
|
var expandStub = sandbox.stub(element, '_openCursorFile');
|
|
var navStub = sandbox.stub(element, '_openSelectedFile');
|
|
var e = new CustomEvent('fake-keyboard-event');
|
|
sinon.stub(e, 'preventDefault');
|
|
element._showInlineDiffs = false;
|
|
element._handleEnterKey(e);
|
|
assert.isTrue(e.preventDefault.called);
|
|
assert.isTrue(navStub.called);
|
|
assert.isFalse(expandStub.called);
|
|
});
|
|
|
|
test('_handleEnterKey expands', function() {
|
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
|
sandbox.stub(element, 'modifierPressed').returns(false);
|
|
var expandStub = sandbox.stub(element, '_openCursorFile');
|
|
var navStub = sandbox.stub(element, '_openSelectedFile');
|
|
var e = new CustomEvent('fake-keyboard-event');
|
|
sinon.stub(e, 'preventDefault');
|
|
element._showInlineDiffs = true;
|
|
element._handleEnterKey(e);
|
|
assert.isTrue(e.preventDefault.called);
|
|
assert.isFalse(navStub.called);
|
|
assert.isTrue(expandStub.called);
|
|
});
|
|
|
|
test('_handleEnterKey noop when anchor focused', function() {
|
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
|
sandbox.stub(element, 'modifierPressed').returns(false);
|
|
var e = new CustomEvent('fake-keyboard-event',
|
|
{detail: {keyboardEvent: {target: document.createElement('a')}}});
|
|
sinon.stub(e, 'preventDefault');
|
|
element._handleEnterKey(e);
|
|
assert.isFalse(e.preventDefault.called);
|
|
});
|
|
});
|
|
|
|
test('comment filtering', function() {
|
|
var comments = {
|
|
'/COMMIT_MSG': [
|
|
{patch_set: 1, message: 'Done', updated: '2017-02-08 16:40:49'},
|
|
{patch_set: 1, message: 'oh hay', updated: '2017-02-09 16:40:49'},
|
|
{patch_set: 2, message: 'hello', updated: '2017-02-10 16:40:49'},
|
|
],
|
|
'myfile.txt': [
|
|
{patch_set: 1, message: 'good news!', updated: '2017-02-08 16:40:49'},
|
|
{patch_set: 2, message: 'wat!?', updated: '2017-02-09 16:40:49'},
|
|
{patch_set: 2, message: 'hi', updated: '2017-02-10 16:40:49'},
|
|
],
|
|
'unresolved.file': [
|
|
{
|
|
patch_set: 2,
|
|
message: 'wat!?',
|
|
updated: '2017-02-09 16:40:49',
|
|
id: '1',
|
|
unresolved: true,
|
|
},
|
|
{
|
|
patch_set: 2,
|
|
message: 'hi',
|
|
updated: '2017-02-10 16:40:49',
|
|
id: '2',
|
|
in_reply_to: '1',
|
|
unresolved: false,
|
|
},
|
|
{
|
|
patch_set: 2,
|
|
message: 'good news!',
|
|
updated: '2017-02-08 16:40:49',
|
|
id: '3',
|
|
unresolved: true,
|
|
},
|
|
],
|
|
};
|
|
var drafts = {
|
|
'unresolved.file': [
|
|
{
|
|
patch_set: 2,
|
|
message: 'hi',
|
|
updated: '2017-02-11 16:40:49',
|
|
id: '4',
|
|
in_reply_to: '3',
|
|
unresolved: false,
|
|
},
|
|
],
|
|
};
|
|
assert.equal(
|
|
element._computeCountString(comments, '1', '/COMMIT_MSG', 'comment'),
|
|
'2 comments');
|
|
assert.equal(
|
|
element._computeCommentsStringMobile(comments, '1', '/COMMIT_MSG'),
|
|
'2c');
|
|
assert.equal(
|
|
element._computeDraftsStringMobile(comments, '1', '/COMMIT_MSG'),
|
|
'2d');
|
|
assert.equal(
|
|
element._computeCountString(comments, '1', 'myfile.txt', 'comment'),
|
|
'1 comment');
|
|
assert.equal(
|
|
element._computeCommentsStringMobile(comments, '1', 'myfile.txt'),
|
|
'1c');
|
|
assert.equal(
|
|
element._computeDraftsStringMobile(comments, '1', 'myfile.txt'),
|
|
'1d');
|
|
assert.equal(
|
|
element._computeCountString(comments, '1',
|
|
'file_added_in_rev2.txt', 'comment'), '');
|
|
assert.equal(
|
|
element._computeCommentsStringMobile(comments, '1',
|
|
'file_added_in_rev2.txt'), '');
|
|
assert.equal(
|
|
element._computeDraftsStringMobile(comments, '1',
|
|
'file_added_in_rev2.txt'), '');
|
|
assert.equal(
|
|
element._computeCountString(comments, '2', '/COMMIT_MSG', 'comment'),
|
|
'1 comment');
|
|
assert.equal(
|
|
element._computeCommentsStringMobile(comments, '2', '/COMMIT_MSG'),
|
|
'1c');
|
|
assert.equal(
|
|
element._computeDraftsStringMobile(comments, '2', '/COMMIT_MSG'),
|
|
'1d');
|
|
assert.equal(
|
|
element._computeCountString(comments, '2', 'myfile.txt', 'comment'),
|
|
'2 comments');
|
|
assert.equal(
|
|
element._computeCommentsStringMobile(comments, '2', 'myfile.txt'),
|
|
'2c');
|
|
assert.equal(
|
|
element._computeDraftsStringMobile(comments, '2', 'myfile.txt'),
|
|
'2d');
|
|
assert.equal(
|
|
element._computeCountString(comments, '2',
|
|
'file_added_in_rev2.txt', 'comment'), '');
|
|
assert.equal(element._computeCountString(comments, '2',
|
|
'unresolved.file', 'comment'), '3 comments');
|
|
assert.equal(
|
|
element._computeUnresolvedString(comments, [], 2, 'myfile.txt'), '');
|
|
assert.equal(
|
|
element._computeUnresolvedString(comments, [], 2, 'unresolved.file'),
|
|
'(1 unresolved)');
|
|
assert.equal(
|
|
element._computeUnresolvedString(comments, drafts, 2,
|
|
'unresolved.file'), '');
|
|
});
|
|
|
|
test('computed properties', function() {
|
|
assert.equal(element._computeFileStatus('A'), 'A');
|
|
assert.equal(element._computeFileStatus(undefined), 'M');
|
|
assert.equal(element._computeFileStatus(null), 'M');
|
|
|
|
assert.equal(element._computeFileDisplayName('/foo/bar/baz'),
|
|
'/foo/bar/baz');
|
|
assert.equal(element._computeFileDisplayName('/COMMIT_MSG'),
|
|
'Commit message');
|
|
|
|
assert.equal(element._computeClass('clazz', '/foo/bar/baz'), 'clazz');
|
|
assert.equal(element._computeClass('clazz', '/COMMIT_MSG'),
|
|
'clazz invisible');
|
|
assert.equal(element._computeExpandInlineClass(
|
|
{expand_inline_diffs: true}), 'expandInline');
|
|
assert.equal(element._computeExpandInlineClass(
|
|
{expand_inline_diffs: false}), '');
|
|
});
|
|
|
|
test('file review status', function() {
|
|
element._files = [
|
|
{__path: '/COMMIT_MSG'},
|
|
{__path: 'file_added_in_rev2.txt'},
|
|
{__path: 'myfile.txt'},
|
|
];
|
|
element._reviewed = ['/COMMIT_MSG', 'myfile.txt'];
|
|
element._loggedIn = true;
|
|
element.changeNum = '42';
|
|
element.patchRange = {
|
|
basePatchNum: 'PARENT',
|
|
patchNum: '2',
|
|
};
|
|
element.$.fileCursor.setCursorAtIndex(0);
|
|
|
|
flushAsynchronousOperations();
|
|
var fileRows =
|
|
Polymer.dom(element.root).querySelectorAll('.row:not(.header)');
|
|
var commitMsg = fileRows[0].querySelector(
|
|
'input.reviewed[type="checkbox"]');
|
|
var fileAdded = fileRows[1].querySelector(
|
|
'input.reviewed[type="checkbox"]');
|
|
var myFile = fileRows[2].querySelector(
|
|
'input.reviewed[type="checkbox"]');
|
|
|
|
assert.isTrue(commitMsg.checked);
|
|
assert.isFalse(fileAdded.checked);
|
|
assert.isTrue(myFile.checked);
|
|
|
|
MockInteractions.tap(commitMsg);
|
|
assert.isTrue(saveStub.lastCall.calledWithExactly('/COMMIT_MSG', false));
|
|
MockInteractions.tap(commitMsg);
|
|
assert.isTrue(saveStub.lastCall.calledWithExactly('/COMMIT_MSG', true));
|
|
});
|
|
|
|
test('patch set from revisions', function() {
|
|
var expected = [
|
|
{num: 1, desc: 'test'},
|
|
{num: 2, desc: 'test'},
|
|
{num: 3, desc: 'test'},
|
|
{num: 4, desc: 'test'},
|
|
];
|
|
var patchNums = element._computePatchSets({
|
|
base: {
|
|
rev3: {_number: 3, description: 'test'},
|
|
rev1: {_number: 1, description: 'test'},
|
|
rev4: {_number: 4, description: 'test'},
|
|
rev2: {_number: 2, description: 'test'},
|
|
},
|
|
});
|
|
assert.equal(patchNums.length, expected.length);
|
|
for (var i = 0; i < expected.length; i++) {
|
|
assert.deepEqual(patchNums[i], expected[i]);
|
|
}
|
|
});
|
|
|
|
test('patch range string', function() {
|
|
assert.equal(
|
|
element._patchRangeStr({basePatchNum: 'PARENT', patchNum: '1'}),
|
|
'1');
|
|
assert.equal(
|
|
element._patchRangeStr({basePatchNum: '1', patchNum: '3'}),
|
|
'1..3');
|
|
});
|
|
|
|
test('diff against dropdown', function(done) {
|
|
var showStub = sandbox.stub(page, 'show');
|
|
element.changeNum = '42';
|
|
element.patchRange = {
|
|
basePatchNum: 'PARENT',
|
|
patchNum: '3',
|
|
};
|
|
element.revisions = {
|
|
rev1: {_number: 1},
|
|
rev2: {_number: 2},
|
|
rev3: {_number: 3},
|
|
};
|
|
flush(function() {
|
|
var selectEl = element.$.patchChange;
|
|
assert.equal(selectEl.value, 'PARENT');
|
|
assert.isTrue(element.$$('option[value="3"]').hasAttribute('disabled'));
|
|
selectEl.addEventListener('change', function() {
|
|
assert.equal(selectEl.value, '2');
|
|
assert(showStub.lastCall.calledWithExactly('/c/42/2..3'),
|
|
'Should navigate to /c/42/2..3');
|
|
showStub.restore();
|
|
done();
|
|
});
|
|
selectEl.value = '2';
|
|
element.fire('change', {}, {node: selectEl});
|
|
});
|
|
});
|
|
|
|
test('checkbox shows/hides diff inline', function() {
|
|
element._files = [
|
|
{__path: 'myfile.txt'},
|
|
];
|
|
element.changeNum = '42';
|
|
element.patchRange = {
|
|
basePatchNum: 'PARENT',
|
|
patchNum: '2',
|
|
};
|
|
element.$.fileCursor.setCursorAtIndex(0);
|
|
sandbox.stub(element, '_expandedPathsChanged');
|
|
flushAsynchronousOperations();
|
|
var fileRows =
|
|
Polymer.dom(element.root).querySelectorAll('.row:not(.header)');
|
|
// Because the label surrounds the input, the tap event is triggered
|
|
// there first.
|
|
var showHideLabel = fileRows[0].querySelector('label.show-hide');
|
|
var showHideCheck = fileRows[0].querySelector(
|
|
'input.show-hide[type="checkbox"]');
|
|
assert.isNotOk(showHideCheck.checked);
|
|
MockInteractions.tap(showHideLabel);
|
|
assert.isOk(showHideCheck.checked);
|
|
assert.notEqual(element._expandedFilePaths.indexOf('myfile.txt'), -1);
|
|
});
|
|
|
|
test('path should be properly escaped', function() {
|
|
element._files = [
|
|
{__path: 'foo bar/my+file.txt%'},
|
|
];
|
|
element.changeNum = '42';
|
|
element.patchRange = {
|
|
basePatchNum: 'PARENT',
|
|
patchNum: '2',
|
|
};
|
|
flushAsynchronousOperations();
|
|
// Slashes should be preserved, and spaces should be translated to `+`.
|
|
// @see Issue 4255 regarding double-encoding.
|
|
// @see Issue 4577 regarding more readable URLs.
|
|
assert.equal(
|
|
element.$$('a').getAttribute('href'),
|
|
'/c/42/2/foo+bar/my%252Bfile.txt%2525');
|
|
});
|
|
|
|
test('diff mode correctly toggles the diffs', function() {
|
|
element._files = [
|
|
{__path: 'myfile.txt'},
|
|
];
|
|
element.changeNum = '42';
|
|
element.patchRange = {
|
|
basePatchNum: 'PARENT',
|
|
patchNum: '2',
|
|
};
|
|
element.$.fileCursor.setCursorAtIndex(0);
|
|
flushAsynchronousOperations();
|
|
|
|
// Tap on a file to generate the diff.
|
|
var row = Polymer.dom(element.root)
|
|
.querySelectorAll('.row:not(.header) label.show-hide')[0];
|
|
|
|
MockInteractions.tap(row);
|
|
flushAsynchronousOperations();
|
|
var diffDisplay = element.diffs[0];
|
|
element._userPrefs = {default_diff_view: 'SIDE_BY_SIDE'};
|
|
assert.equal(element.diffViewMode, 'SIDE_BY_SIDE');
|
|
assert.equal(diffDisplay.viewMode, 'SIDE_BY_SIDE');
|
|
element.set('diffViewMode', 'UNIFIED_DIFF');
|
|
assert.equal(diffDisplay.viewMode, 'UNIFIED_DIFF');
|
|
});
|
|
|
|
test('diff mode selector initializes from preferences', function() {
|
|
var resolvePrefs;
|
|
var prefsPromise = new Promise(function(resolve) {
|
|
resolvePrefs = resolve;
|
|
});
|
|
sandbox.stub(element, '_getPreferences').returns(prefsPromise);
|
|
|
|
// Attach a new gr-file-list so we can intercept the preferences fetch.
|
|
var view = document.createElement('gr-file-list');
|
|
var select = view.$.modeSelect;
|
|
fixture('blank').appendChild(view);
|
|
flushAsynchronousOperations();
|
|
|
|
// At this point the diff mode doesn't yet have the user's preference.
|
|
assert.equal(select.value, 'SIDE_BY_SIDE');
|
|
|
|
// Receive the overriding preference.
|
|
resolvePrefs({default_diff_view: 'UNIFIED'});
|
|
flushAsynchronousOperations();
|
|
assert.equal(select.value, 'SIDE_BY_SIDE');
|
|
document.getElementById('blank').restore();
|
|
});
|
|
|
|
test('show/hide diffs disabled for large amounts of files', function(done) {
|
|
var computeSpy = sandbox.spy(element, '_fileListActionsVisible');
|
|
element._files = [];
|
|
element.changeNum = '42';
|
|
element.patchRange = {
|
|
basePatchNum: 'PARENT',
|
|
patchNum: '2',
|
|
};
|
|
element.$.fileCursor.setCursorAtIndex(0);
|
|
flush(function() {
|
|
assert.isTrue(computeSpy.lastCall.returnValue);
|
|
var arr = [];
|
|
_.times(element._maxFilesForBulkActions + 1, function() {
|
|
arr.push({__path: 'myfile.txt'});
|
|
});
|
|
element._files = arr;
|
|
element.numFilesShown = arr.length;
|
|
assert.isFalse(computeSpy.lastCall.returnValue);
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('expanded attribute not set on path when not expanded', function() {
|
|
element._files = [
|
|
{__path: '/COMMIT_MSG'},
|
|
];
|
|
assert.isNotOk(element.$$('.expanded'));
|
|
});
|
|
|
|
test('_getDiffViewMode', function() {
|
|
// No user prefs or diff view mode set.
|
|
assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
|
|
// User prefs but no diff view mode set.
|
|
element.diffViewMode = null;
|
|
element._userPrefs = {default_diff_view: 'UNIFIED_DIFF'};
|
|
assert.equal(
|
|
element._getDiffViewMode(null, element._userPrefs), 'UNIFIED_DIFF');
|
|
// User prefs and diff view mode set.
|
|
element.diffViewMode = 'SIDE_BY_SIDE';
|
|
assert.equal(element._getDiffViewMode(
|
|
element.diffViewMode, element._userPrefs), 'SIDE_BY_SIDE');
|
|
});
|
|
test('expand_inline_diffs user preference', function() {
|
|
element._files = [
|
|
{__path: '/COMMIT_MSG'},
|
|
];
|
|
element.changeNum = '42';
|
|
element.patchRange = {
|
|
basePatchNum: 'PARENT',
|
|
patchNum: '2',
|
|
};
|
|
sandbox.stub(element, '_expandedPathsChanged');
|
|
flushAsynchronousOperations();
|
|
var commitMsgFile = Polymer.dom(element.root)
|
|
.querySelectorAll('.row:not(.header) a')[0];
|
|
|
|
// Remove href attribute so the app doesn't route to a diff view
|
|
commitMsgFile.removeAttribute('href');
|
|
var togglePathSpy = sandbox.spy(element, '_togglePathExpanded');
|
|
|
|
MockInteractions.tap(commitMsgFile);
|
|
flushAsynchronousOperations();
|
|
assert(togglePathSpy.notCalled, 'file is opened as diff view');
|
|
assert.isNotOk(element.$$('.expanded'));
|
|
|
|
element._userPrefs = {expand_inline_diffs: true};
|
|
flushAsynchronousOperations();
|
|
MockInteractions.tap(commitMsgFile);
|
|
flushAsynchronousOperations();
|
|
assert(togglePathSpy.calledOnce, 'file is expanded');
|
|
assert.isOk(element.$$('.expanded'));
|
|
});
|
|
|
|
test('_togglePathExpanded', function() {
|
|
var path = 'path/to/my/file.txt';
|
|
element.files = [{__path: path}];
|
|
var renderStub = sandbox.stub(element, '_renderInOrder')
|
|
.returns(Promise.resolve());
|
|
|
|
assert.equal(element._expandedFilePaths.length, 0);
|
|
element._togglePathExpanded(path);
|
|
flushAsynchronousOperations();
|
|
|
|
assert.equal(renderStub.callCount, 1);
|
|
assert.include(element._expandedFilePaths, path);
|
|
element._togglePathExpanded(path);
|
|
flushAsynchronousOperations();
|
|
|
|
assert.equal(renderStub.callCount, 2);
|
|
assert.notInclude(element._expandedFilePaths, path);
|
|
});
|
|
|
|
test('_expandedPathsChanged', function(done) {
|
|
sandbox.stub(element, '_reviewFile');
|
|
var path = 'path/to/my/file.txt';
|
|
var diffs = [{
|
|
path: path,
|
|
reload: function() {
|
|
done();
|
|
},
|
|
}];
|
|
var diffsStub = sinon.stub(element, 'diffs', {
|
|
get: function() { return diffs; },
|
|
});
|
|
element.push('_expandedFilePaths', path);
|
|
});
|
|
|
|
suite('_handleFileListTap', function() {
|
|
function testForModifier(modifier) {
|
|
var e = {preventDefault: function() {}};
|
|
e.detail = {sourceEvent: {}};
|
|
e.target = {
|
|
dataset: {path: '/test'},
|
|
classList: element.classList,
|
|
};
|
|
|
|
e.detail.sourceEvent[modifier] = true;
|
|
|
|
var togglePathStub = sandbox.stub(element, '_togglePathExpanded');
|
|
element._userPrefs = { expand_inline_diffs: true };
|
|
|
|
element._handleFileListTap(e);
|
|
assert.isFalse(togglePathStub.called);
|
|
|
|
e.detail.sourceEvent[modifier] = false;
|
|
element._handleFileListTap(e);
|
|
assert.equal(togglePathStub.callCount, 1);
|
|
|
|
element._userPrefs = { expand_inline_diffs: false };
|
|
element._handleFileListTap(e);
|
|
assert.equal(togglePathStub.callCount, 1);
|
|
}
|
|
|
|
test('_handleFileListTap meta', function() {
|
|
testForModifier('metaKey');
|
|
});
|
|
|
|
test('_handleFileListTap ctrl', function() {
|
|
testForModifier('ctrlKey');
|
|
});
|
|
});
|
|
|
|
test('_renderInOrder', function(done) {
|
|
var reviewStub = sandbox.stub(element, '_reviewFile');
|
|
var callCount = 0;
|
|
var diffs = [{
|
|
path: 'p0',
|
|
reload: function() {
|
|
assert.equal(callCount++, 2);
|
|
return Promise.resolve();
|
|
},
|
|
}, {
|
|
path: 'p1',
|
|
reload: function() {
|
|
assert.equal(callCount++, 1);
|
|
return Promise.resolve();
|
|
},
|
|
}, {
|
|
path: 'p2',
|
|
reload: function() {
|
|
assert.equal(callCount++, 0);
|
|
return Promise.resolve();
|
|
},
|
|
}];
|
|
element._renderInOrder(['p2', 'p1', 'p0'], diffs, 3)
|
|
.then(function() {
|
|
assert.isFalse(reviewStub.called);
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('_renderInOrder logged in', function(done) {
|
|
element._isLoggedIn = true;
|
|
var reviewStub = sandbox.stub(element, '_reviewFile');
|
|
var callCount = 0;
|
|
var diffs = [{
|
|
path: 'p0',
|
|
reload: function() {
|
|
assert.equal(reviewStub.callCount, 2);
|
|
assert.equal(callCount++, 2);
|
|
return Promise.resolve();
|
|
},
|
|
}, {
|
|
path: 'p1',
|
|
reload: function() {
|
|
assert.equal(reviewStub.callCount, 1);
|
|
assert.equal(callCount++, 1);
|
|
return Promise.resolve();
|
|
},
|
|
}, {
|
|
path: 'p2',
|
|
reload: function() {
|
|
assert.equal(reviewStub.callCount, 0);
|
|
assert.equal(callCount++, 0);
|
|
return Promise.resolve();
|
|
},
|
|
}];
|
|
element._renderInOrder(['p2', 'p1', 'p0'], diffs, 3)
|
|
.then(function() {
|
|
assert.equal(reviewStub.callCount, 3);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
</script>
|