summaryrefslogtreecommitdiffstats
path: root/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
diff options
context:
space:
mode:
Diffstat (limited to 'polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html')
-rw-r--r--polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html1277
1 files changed, 893 insertions, 384 deletions
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index a5fd521ffe..a44196588a 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -1,5 +1,6 @@
<!DOCTYPE html>
<!--
+@license
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +23,7 @@ limitations under the License.
<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="../../diff/gr-comment-api/gr-comment-api.html">
<script src="../../../scripts/util.js"></script>
<link rel="import" href="../../shared/gr-rest-api-interface/mock-diff-response_test.html">
@@ -29,43 +31,89 @@ limitations under the License.
<script>void(0);</script>
+<dom-module id="comment-api-mock">
+ <template>
+ <gr-file-list id="fileList"
+ change-comments="[[_changeComments]]"
+ on-reload-drafts="_reloadDraftsWithCallback"></gr-file-list>
+ <gr-comment-api id="commentAPI"></gr-comment-api>
+ </template>
+ <script src="../../diff/gr-comment-api/gr-comment-api-mock.js"></script>
+</dom-module>
+
<test-fixture id="basic">
<template>
- <gr-file-list></gr-file-list>
+ <comment-api-mock></comment-api-mock>
</template>
</test-fixture>
<script>
suite('gr-file-list tests', () => {
+ const kb = window.Gerrit.KeyboardShortcutBinder;
+ kb.bindShortcut(kb.Shortcut.LEFT_PANE, 'shift+left');
+ kb.bindShortcut(kb.Shortcut.RIGHT_PANE, 'shift+right');
+ kb.bindShortcut(kb.Shortcut.TOGGLE_INLINE_DIFF, 'i:keyup');
+ kb.bindShortcut(kb.Shortcut.TOGGLE_ALL_INLINE_DIFFS, 'shift+i:keyup');
+ kb.bindShortcut(kb.Shortcut.CURSOR_NEXT_FILE, 'j', 'down');
+ kb.bindShortcut(kb.Shortcut.CURSOR_PREV_FILE, 'k', 'up');
+ kb.bindShortcut(kb.Shortcut.NEXT_LINE, 'j', 'down');
+ kb.bindShortcut(kb.Shortcut.PREV_LINE, 'k', 'up');
+ kb.bindShortcut(kb.Shortcut.NEW_COMMENT, 'c');
+ kb.bindShortcut(kb.Shortcut.OPEN_LAST_FILE, '[');
+ kb.bindShortcut(kb.Shortcut.OPEN_FIRST_FILE, ']');
+ kb.bindShortcut(kb.Shortcut.OPEN_FILE, 'o');
+ kb.bindShortcut(kb.Shortcut.NEXT_CHUNK, 'n');
+ kb.bindShortcut(kb.Shortcut.PREV_CHUNK, 'p');
+ kb.bindShortcut(kb.Shortcut.TOGGLE_FILE_REVIEWED, 'r');
+ kb.bindShortcut(kb.Shortcut.TOGGLE_LEFT_PANE, 'shift+a');
+
let element;
+ let commentApiWrapper;
let sandbox;
let saveStub;
- let loadCommentStub;
+ let loadCommentSpy;
- setup(() => {
+ setup(done => {
sandbox = sinon.sandbox.create();
stub('gr-rest-api-interface', {
getLoggedIn() { return Promise.resolve(true); },
getPreferences() { return Promise.resolve({}); },
- fetchJSON() { return Promise.resolve({}); },
+ getDiffPreferences() { return Promise.resolve({}); },
+ getDiffComments() { return Promise.resolve({}); },
+ getDiffRobotComments() { return Promise.resolve({}); },
+ getDiffDrafts() { return Promise.resolve({}); },
+ getAccountCapabilities() { return Promise.resolve({}); },
});
stub('gr-date-formatter', {
_loadTimeFormat() { return Promise.resolve(''); },
});
- stub('gr-diff', {
+ stub('gr-diff-host', {
reload() { return Promise.resolve(); },
});
- stub('gr-comment-api', {
- getPaths() { return {}; },
- getCommentsForPath() { return {meta: {}, left: [], right: []}; },
- });
- element = fixture('basic');
+ // Element must be wrapped in an element with direct access to the
+ // comment API.
+ commentApiWrapper = fixture('basic');
+ element = commentApiWrapper.$.fileList;
+ loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
+
+ // Stub methods on the changeComments object after changeComments has
+ // been initalized.
+ commentApiWrapper.loadComments().then(() => {
+ sandbox.stub(element.changeComments, 'getPaths').returns({});
+ sandbox.stub(element.changeComments, 'getCommentsBySideForPath')
+ .returns({meta: {}, left: [], right: []});
+ done();
+ });
+ element._loading = false;
+ element.diffPrefs = {};
element.numFilesShown = 200;
+ element.patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: '2',
+ };
saveStub = sandbox.stub(element, '_saveReviewedState',
() => { return Promise.resolve(); });
- loadCommentStub = sandbox.stub(element.$.commentAPI, 'loadAll',
- () => { return Promise.resolve(); });
});
teardown(() => {
@@ -73,109 +121,64 @@ limitations under the License.
});
test('correct number of files are shown', () => {
- element._files = _.times(500, i => {
- return {__path: '/file' + i, lines_inserted: 9};
- });
+ element.fileListIncrement = 300;
+ element._filesByPath = _.range(500)
+ .reduce((_filesByPath, i) => {
+ _filesByPath['/file' + i] = {lines_inserted: 9};
+ return _filesByPath;
+ }, {});
+
flushAsynchronousOperations();
assert.equal(
Polymer.dom(element.root).querySelectorAll('.file-row').length,
element.numFilesShown);
- });
-
- test('get file list', done => {
- const getChangeFilesStub = sandbox.stub(element.$.restAPI, 'getChangeFiles',
- () => {
- return Promise.resolve({
- '/COMMIT_MSG': {lines_inserted: 9},
- 'tags.html': {lines_deleted: 123},
- 'about.txt': {},
- });
- });
-
- element._getFiles().then(files => {
- const filenames = files.map(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',
- });
+ const controlRow = element.$$('.controlRow');
+ assert.isFalse(controlRow.classList.contains('invisible'));
+ assert.equal(element.$.incrementButton.textContent.trim(),
+ 'Show 300 more');
+ assert.equal(element.$.showAllButton.textContent.trim(),
+ 'Show all 500 files');
+
+ MockInteractions.tap(element.$.showAllButton);
+ flushAsynchronousOperations();
- getChangeFilesStub.restore();
- done();
- });
+ assert.equal(element.numFilesShown, 500);
+ assert.equal(element._shownFiles.length, 500);
+ assert.isTrue(controlRow.classList.contains('invisible'));
});
- test('get file list with change edit', done => {
- element.editLoaded = true;
-
- sandbox.stub(element.$.restAPI,
- 'getChangeEditFiles', () => {
- return Promise.resolve({
- commit: {},
- files: {
- '/COMMIT_MSG': {
- lines_inserted: 9,
- },
- 'tags.html': {
- lines_deleted: 123,
- },
- 'about.txt': {},
- },
- });
- });
-
- element._getFiles().then(files => {
- const filenames = files.map(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',
- });
-
- done();
- });
+ test('rendering each row calls the _reportRenderedRow method', () => {
+ const renderedStub = sandbox.stub(element, '_reportRenderedRow');
+ element._filesByPath = _.range(10)
+ .reduce((_filesByPath, i) => {
+ _filesByPath['/file' + i] = {lines_inserted: 9};
+ return _filesByPath;
+ }, {});
+ flushAsynchronousOperations();
+ assert.equal(
+ Polymer.dom(element.root).querySelectorAll('.file-row').length, 10);
+ assert.equal(renderedStub.callCount, 10);
});
test('calculate totals for patch number', () => {
- element._files = [
- {__path: '/COMMIT_MSG', lines_inserted: 9},
- {
- __path: 'file_added_in_rev2.txt',
+ element._filesByPath = {
+ '/COMMIT_MSG': {
+ lines_inserted: 9,
+ },
+ 'file_added_in_rev2.txt': {
lines_inserted: 1,
lines_deleted: 1,
size_delta: 10,
size: 100,
},
- {
- __path: 'myfile.txt',
+ 'myfile.txt': {
lines_inserted: 1,
lines_deleted: 1,
size_delta: 10,
size: 100,
},
- ];
+ };
+
assert.deepEqual(element._patchChange, {
inserted: 2,
deleted: 2,
@@ -187,11 +190,20 @@ limitations under the License.
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},
- ];
+ element._filesByPath = {
+ 'file_added_in_rev2.txt': {
+ lines_inserted: 1,
+ lines_deleted: 1,
+ },
+ '/COMMIT_MSG': {
+ lines_inserted: 9,
+ },
+ 'myfile.txt': {
+ lines_inserted: 1,
+ lines_deleted: 1,
+ },
+ };
+
assert.deepEqual(element._patchChange, {
inserted: 2,
deleted: 2,
@@ -203,10 +215,17 @@ limitations under the License.
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},
- ];
+ element._filesByPath = {
+ 'file_added_in_rev2.txt': {
+ lines_inserted: 1,
+ lines_deleted: 1,
+ },
+ 'myfile.txt': {
+ lines_inserted: 1,
+ lines_deleted: 1,
+ },
+ };
+
assert.deepEqual(element._patchChange, {
inserted: 2,
deleted: 2,
@@ -218,10 +237,10 @@ limitations under the License.
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},
- ];
+ element._filesByPath = {
+ 'file_added_in_rev2.txt': {lines_inserted: 1},
+ 'myfile.txt': {lines_deleted: 1},
+ };
assert.deepEqual(element._patchChange, {
inserted: 1,
deleted: 1,
@@ -234,11 +253,11 @@ limitations under the License.
});
test('binary only files', () => {
- 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},
- ];
+ element._filesByPath = {
+ '/COMMIT_MSG': {lines_inserted: 9},
+ 'file_binary_1': {binary: true, size_delta: 10, size: 100},
+ 'file_binary_2': {binary: true, size_delta: -5, size: 120},
+ };
assert.deepEqual(element._patchChange, {
inserted: 0,
deleted: 0,
@@ -251,13 +270,13 @@ limitations under the License.
});
test('binary and regular files', () => {
- 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},
- ];
+ element._filesByPath = {
+ '/COMMIT_MSG': {lines_inserted: 9},
+ 'file_binary_1': {binary: true, size_delta: 10, size: 100},
+ 'file_binary_2': {binary: true, size_delta: -5, size: 120},
+ 'myfile.txt': {lines_deleted: 5, size_delta: -10, size: 100},
+ 'myfile2.txt': {lines_inserted: 10},
+ };
assert.deepEqual(element._patchChange, {
inserted: 10,
deleted: 5,
@@ -325,13 +344,229 @@ limitations under the License.
}
});
+ test('comment filtering', () => {
+ element.changeComments._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,
+ },
+ ],
+ };
+ element.changeComments._drafts = {
+ '/COMMIT_MSG': [
+ {
+ patch_set: 1,
+ message: 'hi',
+ updated: '2017-02-15 16:40:49',
+ id: '5',
+ unresolved: true,
+ },
+ {
+ patch_set: 1,
+ message: 'fyi',
+ updated: '2017-02-15 16:40:49',
+ id: '6',
+ unresolved: false,
+ },
+ ],
+ 'unresolved.file': [
+ {
+ patch_set: 1,
+ message: 'hi',
+ updated: '2017-02-11 16:40:49',
+ id: '4',
+ unresolved: false,
+ },
+ ],
+ };
+
+ const parentTo1 = {
+ basePatchNum: 'PARENT',
+ patchNum: '1',
+ };
+
+ const parentTo2 = {
+ basePatchNum: 'PARENT',
+ patchNum: '2',
+ };
+
+ const _1To2 = {
+ basePatchNum: '1',
+ patchNum: '2',
+ };
+
+ assert.equal(
+ element._computeCommentsString(element.changeComments, parentTo1,
+ '/COMMIT_MSG', 'comment'), '2 comments (1 unresolved)');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, _1To2,
+ '/COMMIT_MSG', 'comment'), '3 comments (1 unresolved)');
+ assert.equal(
+ element._computeCommentsStringMobile(element.changeComments, parentTo1
+ , '/COMMIT_MSG'), '2c');
+ assert.equal(
+ element._computeCommentsStringMobile(element.changeComments, _1To2
+ , '/COMMIT_MSG'), '3c');
+ assert.equal(
+ element._computeDraftsString(element.changeComments, parentTo1,
+ 'unresolved.file'), '1 draft');
+ assert.equal(
+ element._computeDraftsString(element.changeComments, _1To2,
+ 'unresolved.file'), '1 draft');
+ assert.equal(
+ element._computeDraftsStringMobile(element.changeComments, parentTo1,
+ 'unresolved.file'), '1d');
+ assert.equal(
+ element._computeDraftsStringMobile(element.changeComments, _1To2,
+ 'unresolved.file'), '1d');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, parentTo1,
+ 'myfile.txt', 'comment'), '1 comment');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, _1To2,
+ 'myfile.txt', 'comment'), '3 comments');
+ assert.equal(
+ element._computeCommentsStringMobile(element.changeComments, parentTo1,
+ 'myfile.txt'), '1c');
+ assert.equal(
+ element._computeCommentsStringMobile(element.changeComments, _1To2,
+ 'myfile.txt'), '3c');
+ assert.equal(
+ element._computeDraftsString(element.changeComments, parentTo1,
+ 'myfile.txt'), '');
+ assert.equal(
+ element._computeDraftsString(element.changeComments, _1To2,
+ 'myfile.txt'), '');
+ assert.equal(
+ element._computeDraftsStringMobile(element.changeComments, parentTo1,
+ 'myfile.txt'), '');
+ assert.equal(
+ element._computeDraftsStringMobile(element.changeComments, _1To2,
+ 'myfile.txt'), '');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, parentTo1,
+ 'file_added_in_rev2.txt', 'comment'), '');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, _1To2,
+ 'file_added_in_rev2.txt', 'comment'), '');
+ assert.equal(
+ element._computeCommentsStringMobile(element.changeComments, parentTo1,
+ 'file_added_in_rev2.txt'), '');
+ assert.equal(
+ element._computeCommentsStringMobile(element.changeComments, _1To2,
+ 'file_added_in_rev2.txt'), '');
+ assert.equal(
+ element._computeDraftsString(element.changeComments, parentTo1,
+ 'file_added_in_rev2.txt'), '');
+ assert.equal(
+ element._computeDraftsString(element.changeComments, _1To2,
+ 'file_added_in_rev2.txt'), '');
+ assert.equal(
+ element._computeDraftsStringMobile(element.changeComments, parentTo1,
+ 'file_added_in_rev2.txt'), '');
+ assert.equal(
+ element._computeDraftsStringMobile(element.changeComments, _1To2,
+ 'file_added_in_rev2.txt'), '');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, parentTo2,
+ '/COMMIT_MSG', 'comment'), '1 comment');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, _1To2,
+ '/COMMIT_MSG', 'comment'), '3 comments (1 unresolved)');
+ assert.equal(
+ element._computeCommentsStringMobile(element.changeComments, parentTo2,
+ '/COMMIT_MSG'), '1c');
+ assert.equal(
+ element._computeCommentsStringMobile(element.changeComments, _1To2,
+ '/COMMIT_MSG'), '3c');
+ assert.equal(
+ element._computeDraftsString(element.changeComments, parentTo1,
+ '/COMMIT_MSG'), '2 drafts');
+ assert.equal(
+ element._computeDraftsString(element.changeComments, _1To2,
+ '/COMMIT_MSG'), '2 drafts');
+ assert.equal(
+ element._computeDraftsStringMobile(element.changeComments, parentTo1,
+ '/COMMIT_MSG'), '2d');
+ assert.equal(
+ element._computeDraftsStringMobile(element.changeComments, _1To2,
+ '/COMMIT_MSG'), '2d');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, parentTo2,
+ 'myfile.txt', 'comment'), '2 comments');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, _1To2,
+ 'myfile.txt', 'comment'), '3 comments');
+ assert.equal(
+ element._computeCommentsStringMobile(element.changeComments, parentTo2,
+ 'myfile.txt'), '2c');
+ assert.equal(
+ element._computeCommentsStringMobile(element.changeComments, _1To2,
+ 'myfile.txt'), '3c');
+ assert.equal(
+ element._computeDraftsStringMobile(element.changeComments, parentTo2,
+ 'myfile.txt'), '');
+ assert.equal(
+ element._computeDraftsStringMobile(element.changeComments, _1To2,
+ 'myfile.txt'), '');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, parentTo2,
+ 'file_added_in_rev2.txt', 'comment'), '');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, _1To2,
+ 'file_added_in_rev2.txt', 'comment'), '');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, parentTo2,
+ 'unresolved.file', 'comment'), '3 comments (1 unresolved)');
+ assert.equal(
+ element._computeCommentsString(element.changeComments, _1To2,
+ 'unresolved.file', 'comment'), '3 comments (1 unresolved)');
+ });
+
+ test('_reviewedTitle', () => {
+ assert.equal(
+ element._reviewedTitle(true), 'Mark as not reviewed (shortcut: r)');
+
+ assert.equal(
+ element._reviewedTitle(false), 'Mark as reviewed (shortcut: r)');
+ });
+
suite('keyboard shortcuts', () => {
setup(() => {
- element._files = [
- {__path: '/COMMIT_MSG'},
- {__path: 'file_added_in_rev2.txt'},
- {__path: 'myfile.txt'},
- ];
+ element._filesByPath = {
+ '/COMMIT_MSG': {},
+ 'file_added_in_rev2.txt': {},
+ 'myfile.txt': {},
+ };
element.changeNum = '42';
element.patchRange = {
basePatchNum: 'PARENT',
@@ -403,6 +638,10 @@ limitations under the License.
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
assert.equal(element.$.fileCursor.index, 0);
assert.equal(element.selectedIndex, 0);
+
+ sandbox.stub(element, '_addDraftAtTarget');
+ MockInteractions.pressAndReleaseKeyOn(element, 67, null, 'c');
+ assert.isTrue(element._addDraftAtTarget.called);
});
test('i key shows/hides selected inline diff', () => {
@@ -411,24 +650,24 @@ limitations under the License.
const files = Polymer.dom(element.root).querySelectorAll('.file-row');
element.$.fileCursor.stops = files;
element.$.fileCursor.setCursorAtIndex(0);
- MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
+ MockInteractions.keyUpOn(element, 73, null, 'i');
flushAsynchronousOperations();
assert.include(element._expandedFilePaths, element.diffs[0].path);
- MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
+ MockInteractions.keyUpOn(element, 73, null, 'i');
flushAsynchronousOperations();
assert.notInclude(element._expandedFilePaths, element.diffs[0].path);
element.$.fileCursor.setCursorAtIndex(1);
- MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
+ MockInteractions.keyUpOn(element, 73, null, 'i');
flushAsynchronousOperations();
assert.include(element._expandedFilePaths, element.diffs[1].path);
- MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'i');
+ MockInteractions.keyUpOn(element, 73, 'shift', 'i');
flushAsynchronousOperations();
for (const index in element.diffs) {
if (!element.diffs.hasOwnProperty(index)) { continue; }
assert.include(element._expandedFilePaths, element.diffs[index].path);
}
- MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'i');
+ MockInteractions.keyUpOn(element, 73, 'shift', 'i');
flushAsynchronousOperations();
for (const index in element.diffs) {
if (!element.diffs.hasOwnProperty(index)) { continue; }
@@ -438,21 +677,24 @@ limitations under the License.
});
test('r key toggles reviewed flag', () => {
+ const reducer = (accum, file) => file.isReviewed ? ++accum : accum;
+ const getNumReviewed = () => element._files.reduce(reducer, 0);
flushAsynchronousOperations();
// Default state should be unreviewed.
- assert.equal(element._reviewed.length, 0);
+ assert.equal(getNumReviewed(), 0);
// Press the review key to toggle it (set the flag).
MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
- assert.equal(element._reviewed.length, 1);
+ flushAsynchronousOperations();
+ assert.equal(getNumReviewed(), 1);
// Press the review key to toggle it (clear the flag).
MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
- assert.equal(element._reviewed.length, 0);
+ assert.equal(getNumReviewed(), 0);
});
- suite('_handleOKey', () => {
+ suite('_handleOpenFile', () => {
let interact;
setup(() => {
@@ -470,7 +712,7 @@ limitations under the License.
const e = new CustomEvent('fake-keyboard-event', opt_payload);
sinon.stub(e, 'preventDefault');
- element._handleOKey(e);
+ element._handleOpenFile(e);
assert.isTrue(e.preventDefault.called);
const result = {};
if (openCursorStub.called) {
@@ -494,10 +736,6 @@ limitations under the License.
test('open from diff cursor', () => {
element._showInlineDiffs = true;
assert.deepEqual(interact(), {opened_cursor: true});
-
- // "Show diffs" mode overrides userPrefs.expand_inline_diffs
- element._userPrefs = {expand_inline_diffs: true};
- assert.deepEqual(interact(), {opened_cursor: true});
});
test('expand when user prefers', () => {
@@ -505,123 +743,28 @@ limitations under the License.
assert.deepEqual(interact(), {opened_selected: true});
element._userPrefs = {};
assert.deepEqual(interact(), {opened_selected: true});
- element._userPrefs.expand_inline_diffs = true;
- assert.deepEqual(interact(), {expanded: true});
});
});
- });
- test('comment filtering', () => {
- const 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,
- },
- ],
- };
- const 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.computeUnresolvedNum(comments, [], 2, 'myfile.txt'), 0);
- assert.equal(
- element._computeUnresolvedString(comments, [], 2, 'unresolved.file'),
- '(1 unresolved)');
- assert.equal(
- element.computeUnresolvedNum(comments, [], 2, 'unresolved.file'), 1);
- assert.equal(
- element._computeUnresolvedString(comments, drafts, 2,
- 'unresolved.file'), '');
+ test('shift+left/shift+right', () => {
+ const moveLeftStub = sandbox.stub(element.$.diffCursor, 'moveLeft');
+ const moveRightStub = sandbox.stub(element.$.diffCursor, 'moveRight');
+
+ let noDiffsExpanded = true;
+ sandbox.stub(element, '_noDiffsExpanded', () => noDiffsExpanded);
+
+ MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'left');
+ assert.isFalse(moveLeftStub.called);
+ MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'right');
+ assert.isFalse(moveRightStub.called);
+
+ noDiffsExpanded = false;
+
+ MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'left');
+ assert.isTrue(moveLeftStub.called);
+ MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'right');
+ assert.isTrue(moveRightStub.called);
+ });
});
test('computed properties', () => {
@@ -635,12 +778,12 @@ limitations under the License.
});
test('file review status', () => {
- element._files = [
- {__path: '/COMMIT_MSG'},
- {__path: 'file_added_in_rev2.txt'},
- {__path: 'myfile.txt'},
- ];
element._reviewed = ['/COMMIT_MSG', 'myfile.txt'];
+ element._filesByPath = {
+ '/COMMIT_MSG': {},
+ 'file_added_in_rev2.txt': {},
+ 'myfile.txt': {},
+ };
element._loggedIn = true;
element.changeNum = '42';
element.patchRange = {
@@ -680,12 +823,80 @@ limitations under the License.
assert.isTrue(tapSpy.lastCall.args[0].defaultPrevented);
});
+ test('_computeFileStatusLabel', () => {
+ assert.equal(element._computeFileStatusLabel('A'), 'Added');
+ assert.equal(element._computeFileStatusLabel('M'), 'Modified');
+ });
+
+ test('_handleFileListTap', () => {
+ element._filesByPath = {
+ '/COMMIT_MSG': {},
+ 'f1.txt': {},
+ 'f2.txt': {},
+ };
+ element.changeNum = '42';
+ element.patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: '2',
+ };
+
+ const tapSpy = sandbox.spy(element, '_handleFileListTap');
+ const reviewStub = sandbox.stub(element, '_reviewFile');
+ const toggleExpandSpy = sandbox.spy(element, '_togglePathExpanded');
+
+ const row = Polymer.dom(element.root)
+ .querySelector('.row[data-path="f1.txt"]');
+
+ // Click on the expand button, resulting in _togglePathExpanded being
+ // called and not resulting in a call to _reviewFile.
+ row.querySelector('div.show-hide').click();
+ assert.isTrue(tapSpy.calledOnce);
+ assert.isTrue(toggleExpandSpy.calledOnce);
+ assert.isFalse(reviewStub.called);
+
+ // Click inside the diff. This should result in no additional calls to
+ // _togglePathExpanded or _reviewFile.
+ Polymer.dom(element.root).querySelector('gr-diff-host').click();
+ assert.isTrue(tapSpy.calledTwice);
+ assert.isTrue(toggleExpandSpy.calledOnce);
+ assert.isFalse(reviewStub.called);
+
+ // Click the reviewed checkbox, resulting in a call to _reviewFile, but
+ // no additional call to _togglePathExpanded.
+ row.querySelector('.markReviewed').click();
+ assert.isTrue(tapSpy.calledThrice);
+ assert.isTrue(toggleExpandSpy.calledOnce);
+ assert.isTrue(reviewStub.calledOnce);
+ });
+
+ test('_handleFileListTap editMode', () => {
+ element._filesByPath = {
+ '/COMMIT_MSG': {},
+ 'f1.txt': {},
+ 'f2.txt': {},
+ };
+ element.changeNum = '42';
+ element.patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: '2',
+ };
+ element.editMode = true;
+ flushAsynchronousOperations();
+ const tapSpy = sandbox.spy(element, '_handleFileListTap');
+ const toggleExpandSpy = sandbox.spy(element, '_togglePathExpanded');
+
+ // Tap the edit controls. Should be ignored by _handleFileListTap.
+ MockInteractions.tap(element.$$('.editFileControls'));
+ assert.isTrue(tapSpy.calledOnce);
+ assert.isFalse(toggleExpandSpy.called);
+ });
+
test('patch set from revisions', () => {
const expected = [
- {num: 1, desc: 'test'},
- {num: 2, desc: 'test'},
- {num: 3, desc: 'test'},
{num: 4, desc: 'test'},
+ {num: 3, desc: 'test'},
+ {num: 2, desc: 'test'},
+ {num: 1, desc: 'test'},
];
const patchNums = element.computeAllPatchSets({
revisions: {
@@ -702,9 +913,9 @@ limitations under the License.
});
test('checkbox shows/hides diff inline', () => {
- element._files = [
- {__path: 'myfile.txt'},
- ];
+ element._filesByPath = {
+ 'myfile.txt': {},
+ };
element.changeNum = '42';
element.patchRange = {
basePatchNum: 'PARENT',
@@ -727,9 +938,9 @@ limitations under the License.
});
test('diff mode correctly toggles the diffs', () => {
- element._files = [
- {__path: 'myfile.txt'},
- ];
+ element._filesByPath = {
+ 'myfile.txt': {},
+ };
element.changeNum = '42';
element.patchRange = {
basePatchNum: 'PARENT',
@@ -752,18 +963,17 @@ limitations under the License.
assert.isTrue(element._updateDiffPreferences.called);
});
-
test('expanded attribute not set on path when not expanded', () => {
- element._files = [
- {__path: '/COMMIT_MSG'},
- ];
+ element._filesByPath = {
+ '/COMMIT_MSG': {},
+ };
assert.isNotOk(element.$$('.expanded'));
});
- test('expand_inline_diffs user preference', () => {
- element._files = [
- {__path: '/COMMIT_MSG'},
- ];
+ test('tapping row ignores links', () => {
+ element._filesByPath = {
+ '/COMMIT_MSG': {},
+ };
element.changeNum = '42';
element.patchRange = {
basePatchNum: 'PARENT',
@@ -772,7 +982,7 @@ limitations under the License.
sandbox.stub(element, '_expandedPathsChanged');
flushAsynchronousOperations();
const commitMsgFile = Polymer.dom(element.root)
- .querySelectorAll('.row:not(.header) a')[0];
+ .querySelectorAll('.row:not(.header) a.pathLink')[0];
// Remove href attribute so the app doesn't route to a diff view
commitMsgFile.removeAttribute('href');
@@ -782,50 +992,53 @@ limitations under the License.
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'));
+ assert.notEqual(getComputedStyle(element.$$('.show-hide')).display,
+ 'none');
});
test('_togglePathExpanded', () => {
const path = 'path/to/my/file.txt';
- element.files = [{__path: path}];
- const renderStub = sandbox.stub(element, '_renderInOrder')
- .returns(Promise.resolve());
+ element._filesByPath = {[path]: {}};
+ const renderSpy = sandbox.spy(element, '_renderInOrder');
+ const collapseStub = sandbox.stub(element, '_clearCollapsedDiffs');
+ assert.equal(element.$$('iron-icon').icon, 'gr-icons:expand-more');
assert.equal(element._expandedFilePaths.length, 0);
element._togglePathExpanded(path);
flushAsynchronousOperations();
+ assert.equal(collapseStub.lastCall.args[0].length, 0);
+ assert.equal(element.$$('iron-icon').icon, 'gr-icons:expand-less');
- assert.equal(renderStub.callCount, 1);
+ assert.equal(renderSpy.callCount, 1);
assert.include(element._expandedFilePaths, path);
element._togglePathExpanded(path);
flushAsynchronousOperations();
- assert.equal(renderStub.callCount, 2);
+ assert.equal(element.$$('iron-icon').icon, 'gr-icons:expand-more');
+ assert.equal(renderSpy.callCount, 1);
assert.notInclude(element._expandedFilePaths, path);
+ assert.equal(collapseStub.lastCall.args[0].length, 1);
});
- test('collapseAllDiffs', () => {
- sandbox.stub(element, '_renderInOrder')
- .returns(Promise.resolve());
+ test('expandAllDiffs and collapseAllDiffs', () => {
+ const collapseStub = sandbox.stub(element, '_clearCollapsedDiffs');
const cursorUpdateStub = sandbox.stub(element.$.diffCursor,
'handleDiffUpdate');
const path = 'path/to/my/file.txt';
- element.files = [{__path: path}];
- element._expandedFilePaths = [path];
- element._showInlineDiffs = true;
+ element._filesByPath = {[path]: {}};
+ element.expandAllDiffs();
+ flushAsynchronousOperations();
+ assert.isTrue(element._showInlineDiffs);
+ assert.isTrue(cursorUpdateStub.calledOnce);
+ assert.equal(collapseStub.lastCall.args[0].length, 0);
element.collapseAllDiffs();
flushAsynchronousOperations();
assert.equal(element._expandedFilePaths.length, 0);
assert.isFalse(element._showInlineDiffs);
- assert.isTrue(cursorUpdateStub.calledOnce);
+ assert.isTrue(cursorUpdateStub.calledTwice);
+ assert.equal(collapseStub.lastCall.args[0].length, 1);
});
test('_expandedPathsChanged', done => {
@@ -836,6 +1049,9 @@ limitations under the License.
reload() {
done();
},
+ cancel() {},
+ getCursorStops() { return []; },
+ addEventListener(eventName, callback) { callback(new Event(eventName)); },
}];
sinon.stub(element, 'diffs', {
get() { return diffs; },
@@ -843,39 +1059,40 @@ limitations under the License.
element.push('_expandedFilePaths', path);
});
- suite('_handleFileListTap', () => {
- function testForModifier(modifier) {
- const e = {preventDefault() {}};
- e.detail = {sourceEvent: {}};
- e.target = {
- dataset: {path: '/test'},
- classList: element.classList,
- };
-
- e.detail.sourceEvent[modifier] = true;
-
- const 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', () => {
- testForModifier('metaKey');
- });
+ test('_clearCollapsedDiffs', () => {
+ const diff = {
+ cancel: sinon.stub(),
+ clearDiffContent: sinon.stub(),
+ };
+ element._clearCollapsedDiffs([diff]);
+ assert.isTrue(diff.cancel.calledOnce);
+ assert.isTrue(diff.clearDiffContent.calledOnce);
+ });
- test('_handleFileListTap ctrl', () => {
- testForModifier('ctrlKey');
- });
+ test('filesExpanded value updates to correct enum', () => {
+ element._filesByPath = {
+ 'foo.bar': {},
+ 'baz.bar': {},
+ };
+ flushAsynchronousOperations();
+ assert.equal(element.filesExpanded,
+ GrFileListConstants.FilesExpandedState.NONE);
+ element.push('_expandedFilePaths', 'baz.bar');
+ flushAsynchronousOperations();
+ assert.equal(element.filesExpanded,
+ GrFileListConstants.FilesExpandedState.SOME);
+ element.push('_expandedFilePaths', 'foo.bar');
+ flushAsynchronousOperations();
+ assert.equal(element.filesExpanded,
+ GrFileListConstants.FilesExpandedState.ALL);
+ element.collapseAllDiffs();
+ flushAsynchronousOperations();
+ assert.equal(element.filesExpanded,
+ GrFileListConstants.FilesExpandedState.NONE);
+ element.expandAllDiffs();
+ flushAsynchronousOperations();
+ assert.equal(element.filesExpanded,
+ GrFileListConstants.FilesExpandedState.ALL);
});
test('_renderInOrder', done => {
@@ -903,13 +1120,13 @@ limitations under the License.
element._renderInOrder(['p2', 'p1', 'p0'], diffs, 3)
.then(() => {
assert.isFalse(reviewStub.called);
- assert.isTrue(loadCommentStub.called);
+ assert.isTrue(loadCommentSpy.called);
done();
});
});
test('_renderInOrder logged in', done => {
- element._isLoggedIn = true;
+ element._loggedIn = true;
const reviewStub = sandbox.stub(element, '_reviewFile');
let callCount = 0;
const diffs = [{
@@ -941,10 +1158,30 @@ limitations under the License.
});
});
+ test('_renderInOrder respects diffPrefs.manual_review', () => {
+ element._loggedIn = true;
+ element.diffPrefs = {manual_review: true};
+ const reviewStub = sandbox.stub(element, '_reviewFile');
+ const diffs = [{
+ path: 'p',
+ reload() { return Promise.resolve(); },
+ }];
+
+ return element._renderInOrder(['p'], diffs, 1).then(() => {
+ assert.isFalse(reviewStub.called);
+ delete element.diffPrefs.manual_review;
+ return element._renderInOrder(['p'], diffs, 1).then(() => {
+ assert.isTrue(reviewStub.called);
+ assert.isTrue(reviewStub.calledWithExactly('p', true));
+ });
+ });
+ });
+
test('_loadingChanged fired from reload in debouncer', done => {
+ sandbox.stub(element, '_getReviewedFiles').returns(Promise.resolve([]));
element.changeNum = 123;
element.patchRange = {patchNum: 12};
- element._files = [{__path: 'foo.bar'}];
+ element._filesByPath = {'foo.bar': {}};
element.reload().then(() => {
assert.isFalse(element._loading);
@@ -959,6 +1196,7 @@ limitations under the License.
});
test('_loadingChanged does not set class when there are no files', () => {
+ sandbox.stub(element, '_getReviewedFiles').returns(Promise.resolve([]));
element.changeNum = 123;
element.patchRange = {patchNum: 12};
element.reload();
@@ -971,7 +1209,8 @@ limitations under the License.
const urlStub = sandbox.stub(element, '_computeDiffURL');
element.change = {_number: 123};
element.patchRange = {patchNum: undefined, basePatchNum: 'PARENT'};
- element._files = [{__path: 'foo/bar.cpp'}];
+ element._filesByPath = {'foo/bar.cpp': {}};
+ element.editMode = false;
flush(() => {
assert.isFalse(urlStub.called);
element.set('patchRange.patchNum', 4);
@@ -981,18 +1220,178 @@ limitations under the License.
});
});
});
+
+ suite('size bars', () => {
+ test('_computeSizeBarLayout', () => {
+ assert.isUndefined(element._computeSizeBarLayout(null));
+ assert.isUndefined(element._computeSizeBarLayout({}));
+ assert.deepEqual(element._computeSizeBarLayout({base: []}), {
+ maxInserted: 0,
+ maxDeleted: 0,
+ maxAdditionWidth: 0,
+ maxDeletionWidth: 0,
+ deletionOffset: 0,
+ });
+
+ const files = [
+ {__path: '/COMMIT_MSG', lines_inserted: 10000},
+ {__path: 'foo', lines_inserted: 4, lines_deleted: 10},
+ {__path: 'bar', lines_inserted: 5, lines_deleted: 8},
+ ];
+ const layout = element._computeSizeBarLayout({base: files});
+ assert.equal(layout.maxInserted, 5);
+ assert.equal(layout.maxDeleted, 10);
+ });
+
+ test('_computeBarAdditionWidth', () => {
+ const file = {
+ __path: 'foo/bar.baz',
+ lines_inserted: 5,
+ lines_deleted: 0,
+ };
+ const stats = {
+ maxInserted: 10,
+ maxDeleted: 0,
+ maxAdditionWidth: 60,
+ maxDeletionWidth: 0,
+ deletionOffset: 60,
+ };
+
+ // Uses half the space when file is half the largest addition and there
+ // are no deletions.
+ assert.equal(element._computeBarAdditionWidth(file, stats), 30);
+
+ // If there are no insetions, there is no width.
+ stats.maxInserted = 0;
+ assert.equal(element._computeBarAdditionWidth(file, stats), 0);
+
+ // If the insertions is not present on the file, there is no width.
+ stats.maxInserted = 10;
+ file.lines_inserted = undefined;
+ assert.equal(element._computeBarAdditionWidth(file, stats), 0);
+
+ // If the file is a commit message, returns zero.
+ file.lines_inserted = 5;
+ file.__path = '/COMMIT_MSG';
+ assert.equal(element._computeBarAdditionWidth(file, stats), 0);
+
+ // Width bottoms-out at the minimum width.
+ file.__path = 'stuff.txt';
+ file.lines_inserted = 1;
+ stats.maxInserted = 1000000;
+ assert.equal(element._computeBarAdditionWidth(file, stats), 1.5);
+ });
+
+ test('_computeBarAdditionX', () => {
+ const file = {
+ __path: 'foo/bar.baz',
+ lines_inserted: 5,
+ lines_deleted: 0,
+ };
+ const stats = {
+ maxInserted: 10,
+ maxDeleted: 0,
+ maxAdditionWidth: 60,
+ maxDeletionWidth: 0,
+ deletionOffset: 60,
+ };
+ assert.equal(element._computeBarAdditionX(file, stats), 30);
+ });
+
+ test('_computeBarDeletionWidth', () => {
+ const file = {
+ __path: 'foo/bar.baz',
+ lines_inserted: 0,
+ lines_deleted: 5,
+ };
+ const stats = {
+ maxInserted: 10,
+ maxDeleted: 10,
+ maxAdditionWidth: 30,
+ maxDeletionWidth: 30,
+ deletionOffset: 31,
+ };
+
+ // Uses a quarter the space when file is half the largest deletions and
+ // there are equal additions.
+ assert.equal(element._computeBarDeletionWidth(file, stats), 15);
+
+ // If there are no deletions, there is no width.
+ stats.maxDeleted = 0;
+ assert.equal(element._computeBarDeletionWidth(file, stats), 0);
+
+ // If the deletions is not present on the file, there is no width.
+ stats.maxDeleted = 10;
+ file.lines_deleted = undefined;
+ assert.equal(element._computeBarDeletionWidth(file, stats), 0);
+
+ // If the file is a commit message, returns zero.
+ file.lines_deleted = 5;
+ file.__path = '/COMMIT_MSG';
+ assert.equal(element._computeBarDeletionWidth(file, stats), 0);
+
+ // Width bottoms-out at the minimum width.
+ file.__path = 'stuff.txt';
+ file.lines_deleted = 1;
+ stats.maxDeleted = 1000000;
+ assert.equal(element._computeBarDeletionWidth(file, stats), 1.5);
+ });
+
+ test('_computeSizeBarsClass', () => {
+ assert.equal(element._computeSizeBarsClass(false, 'foo/bar.baz'),
+ 'sizeBars desktop hide');
+ assert.equal(element._computeSizeBarsClass(true, '/COMMIT_MSG'),
+ 'sizeBars desktop invisible');
+ assert.equal(element._computeSizeBarsClass(true, 'foo/bar.baz'),
+ 'sizeBars desktop ');
+ });
+ });
});
suite('gr-file-list inline diff tests', () => {
let element;
let sandbox;
+ const commitMsgComments = [
+ {
+ patch_set: 2,
+ id: 'ecf0b9fa_fe1a5f62',
+ line: 20,
+ updated: '2018-02-08 18:49:18.000000000',
+ message: 'another comment',
+ unresolved: true,
+ },
+ {
+ patch_set: 2,
+ id: '503008e2_0ab203ee',
+ line: 10,
+ updated: '2018-02-14 22:07:43.000000000',
+ message: 'response',
+ unresolved: true,
+ },
+ {
+ patch_set: 2,
+ id: 'cc788d2c_cb1d728c',
+ line: 20,
+ in_reply_to: 'ecf0b9fa_fe1a5f62',
+ updated: '2018-02-13 22:07:43.000000000',
+ message: 'a comments',
+ unresolved: true,
+ },
+ ];
+
const setupDiff = function(diff) {
const mock = document.createElement('mock-diff-response');
- diff._diff = mock.diffResponse;
diff.comments = {
- left: [],
+ left: diff.path === '/COMMIT_MSG' ? commitMsgComments : [],
right: [],
+ meta: {
+ changeNum: 1,
+ patchRange: {
+ basePatchNum: 'PARENT',
+ patchNum: 2,
+ },
+ },
};
diff.prefs = {
context: 10,
@@ -1010,12 +1409,12 @@ limitations under the License.
theme: 'DEFAULT',
ignore_whitespace: 'IGNORE_NONE',
};
- diff._renderDiffTable();
+ diff._diff = mock.diffResponse;
};
const renderAndGetNewDiffs = function(index) {
const diffs =
- Polymer.dom(element.root).querySelectorAll('gr-diff');
+ Polymer.dom(element.root).querySelectorAll('gr-diff-host');
for (let i = index; i < diffs.length; i++) {
setupDiff(diffs[i]);
@@ -1026,43 +1425,56 @@ limitations under the License.
return diffs;
};
- setup(() => {
+ setup(done => {
sandbox = sinon.sandbox.create();
stub('gr-rest-api-interface', {
getLoggedIn() { return Promise.resolve(true); },
getPreferences() { return Promise.resolve({}); },
+ getDiffComments() { return Promise.resolve({}); },
+ getDiffRobotComments() { return Promise.resolve({}); },
+ getDiffDrafts() { return Promise.resolve({}); },
});
stub('gr-date-formatter', {
_loadTimeFormat() { return Promise.resolve(''); },
});
- stub('gr-diff', {
+ stub('gr-diff-host', {
reload() { return Promise.resolve(); },
});
- stub('gr-comment-api', {
- loadAll() { return Promise.resolve(); },
- getPaths() { return {}; },
- getCommentsForPath() { return {meta: {}, left: [], right: []}; },
+
+ // Element must be wrapped in an element with direct access to the
+ // comment API.
+ commentApiWrapper = fixture('basic');
+ element = commentApiWrapper.$.fileList;
+ loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
+ element.diffPrefs = {};
+ sandbox.stub(element, '_reviewFile');
+
+ // Stub methods on the changeComments object after changeComments has
+ // been initalized.
+ commentApiWrapper.loadComments().then(() => {
+ sandbox.stub(element.changeComments, 'getPaths').returns({});
+ sandbox.stub(element.changeComments, 'getCommentsBySideForPath')
+ .returns({meta: {}, left: [], right: []});
+ done();
});
- element = fixture('basic');
+ element._loading = false;
element.numFilesShown = 75;
element.selectedIndex = 0;
- element._files = [
- {__path: '/COMMIT_MSG', lines_inserted: 9},
- {
- __path: 'file_added_in_rev2.txt',
+ element._filesByPath = {
+ '/COMMIT_MSG': {lines_inserted: 9},
+ 'file_added_in_rev2.txt': {
lines_inserted: 1,
lines_deleted: 1,
size_delta: 10,
size: 100,
},
- {
- __path: 'myfile.txt',
+ 'myfile.txt': {
lines_inserted: 1,
lines_deleted: 1,
size_delta: 10,
size: 100,
},
- ];
+ };
element._reviewed = ['/COMMIT_MSG', 'myfile.txt'];
element._loggedIn = true;
element.changeNum = '42';
@@ -1081,7 +1493,7 @@ limitations under the License.
});
test('cursor with individually opened files', () => {
- MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
+ MockInteractions.keyUpOn(element, 73, null, 'i');
flushAsynchronousOperations();
let diffs = renderAndGetNewDiffs(0);
const diffStops = diffs[0].getCursorStops();
@@ -1107,7 +1519,7 @@ limitations under the License.
// The file cusor is now at 1.
assert.equal(element.$.fileCursor.index, 1);
- MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
+ MockInteractions.keyUpOn(element, 73, null, 'i');
flushAsynchronousOperations();
diffs = renderAndGetNewDiffs(1);
@@ -1122,7 +1534,7 @@ limitations under the License.
});
test('cursor with toggle all files', () => {
- MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'i');
+ MockInteractions.keyUpOn(element, 73, 'shift', 'i');
flushAsynchronousOperations();
const diffs = renderAndGetNewDiffs(0);
@@ -1156,9 +1568,10 @@ limitations under the License.
let nextCommentStub;
let nextChunkStub;
let fileRows;
+
setup(() => {
sandbox.stub(element, '_renderInOrder').returns(Promise.resolve());
- nKeySpy = sandbox.spy(element, '_handleNKey');
+ nKeySpy = sandbox.spy(element, '_handleNextChunk');
nextCommentStub = sandbox.stub(element.$.diffCursor,
'moveToNextCommentThread');
nextChunkStub = sandbox.stub(element.$.diffCursor,
@@ -1166,9 +1579,11 @@ limitations under the License.
fileRows =
Polymer.dom(element.root).querySelectorAll('.row:not(.header)');
});
- test('n key with all files expanded and no shift key', () => {
- MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, null, 'i');
+
+ test('n key with some files expanded and no shift key', () => {
+ MockInteractions.keyUpOn(fileRows[0], 73, null, 'i');
flushAsynchronousOperations();
+ assert.equal(nextChunkStub.callCount, 1);
// Handle N key should return before calling diff cursor functions.
MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
@@ -1176,25 +1591,26 @@ limitations under the License.
assert.isFalse(nextCommentStub.called);
// This is also called in diffCursor.moveToFirstChunk.
- assert.equal(nextChunkStub.callCount, 1);
- assert.isFalse(!!element._showInlineDiffs);
+ assert.equal(nextChunkStub.callCount, 2);
+ assert.equal(element.filesExpanded, 'some');
});
- test('n key with all files expanded and shift key', () => {
- MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, null, 'i');
+ test('n key with some files expanded and shift key', () => {
+ MockInteractions.keyUpOn(fileRows[0], 73, null, 'i');
flushAsynchronousOperations();
+ assert.equal(nextChunkStub.callCount, 1);
MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
assert.isTrue(nKeySpy.called);
- assert.isFalse(nextCommentStub.called);
+ assert.isTrue(nextCommentStub.called);
// This is also called in diffCursor.moveToFirstChunk.
assert.equal(nextChunkStub.callCount, 1);
- assert.isFalse(!!element._showInlineDiffs);
+ assert.equal(element.filesExpanded, 'some');
});
test('n key without all files expanded and shift key', () => {
- MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, 'shift', 'i');
+ MockInteractions.keyUpOn(fileRows[0], 73, 'shift', 'i');
flushAsynchronousOperations();
MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
@@ -1207,7 +1623,7 @@ limitations under the License.
});
test('n key without all files expanded and no shift key', () => {
- MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, 'shift', 'i');
+ MockInteractions.keyUpOn(fileRows[0], 73, 'shift', 'i');
flushAsynchronousOperations();
MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
@@ -1221,14 +1637,14 @@ limitations under the License.
});
test('_openSelectedFile behavior', () => {
- const _files = element._files;
- element.set('_files', []);
+ const _filesByPath = element._filesByPath;
+ element.set('_filesByPath', {});
const navStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
// Noop when there are no files.
element._openSelectedFile();
assert.isFalse(navStub.called);
- element.set('_files', _files);
+ element.set('_filesByPath', _filesByPath);
flushAsynchronousOperations();
// Navigates when a file is selected.
element._openSelectedFile();
@@ -1242,11 +1658,11 @@ limitations under the License.
const mockEvent = {preventDefault() {}};
element._displayLine = false;
- element._handleDownKey(mockEvent);
+ element._handleCursorNext(mockEvent);
assert.isTrue(element._displayLine);
element._displayLine = false;
- element._handleUpKey(mockEvent);
+ element._handleCursorPrev(mockEvent);
assert.isTrue(element._displayLine);
element._displayLine = true;
@@ -1254,42 +1670,135 @@ limitations under the License.
assert.isFalse(element._displayLine);
});
- suite('editLoaded behavior', () => {
- const isVisible = el => {
- assert.ok(el);
- return getComputedStyle(el).getPropertyValue('display') !== 'none';
- };
-
+ suite('editMode behavior', () => {
test('reviewed checkbox', () => {
- const alertStub = sandbox.stub();
+ element._reviewFile.restore();
const saveReviewStub = sandbox.stub(element, '_saveReviewedState');
- element.addEventListener('show-alert', alertStub);
- element.editLoaded = false;
- // Reviewed checkbox should be shown.
- assert.isTrue(isVisible(element.$$('.reviewed')));
+ element.editMode = false;
MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
- assert.isFalse(alertStub.called);
assert.isTrue(saveReviewStub.calledOnce);
- element.editLoaded = true;
+ element.editMode = true;
flushAsynchronousOperations();
- assert.isFalse(isVisible(element.$$('.reviewed')));
MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
- assert.isTrue(alertStub.called);
assert.isTrue(saveReviewStub.calledOnce);
});
test('_getReviewedFiles does not call API', () => {
const apiSpy = sandbox.spy(element.$.restAPI, 'getReviewedFiles');
- element.editLoaded = true;
+ element.editMode = true;
return element._getReviewedFiles().then(files => {
assert.equal(files.length, 0);
assert.isFalse(apiSpy.called);
});
});
});
+
+ test('editing actions', () => {
+ // Edit controls are guarded behind a dom-if initially and not rendered.
+ assert.isNotOk(Polymer.dom(element.root)
+ .querySelector('gr-edit-file-controls'));
+
+ element.editMode = true;
+ flushAsynchronousOperations();
+
+ // Commit message should not have edit controls.
+ const editControls =
+ Polymer.dom(element.root).querySelectorAll('.row:not(.header)')
+ .map(row => row.querySelector('gr-edit-file-controls'));
+ assert.isTrue(editControls[0].classList.contains('invisible'));
+ });
+
+ test('reloadCommentsForThreadWithRootId', () => {
+ const commentStub =
+ sandbox.stub(element.changeComments, 'getCommentsForThread');
+ const commentStubRes1 = [
+ {
+ patch_set: 2,
+ id: 'ecf0b9fa_fe1a5f62',
+ line: 20,
+ updated: '2018-02-08 18:49:18.000000000',
+ message: 'another comment',
+ unresolved: true,
+ },
+ {
+ patch_set: 2,
+ id: '503008e2_0ab203ee',
+ line: 10,
+ updated: '2018-02-14 22:07:43.000000000',
+ message: 'response',
+ unresolved: true,
+ },
+ {
+ patch_set: 2,
+ id: '503008e2_0ab203ef',
+ line: 20,
+ in_reply_to: 'ecf0b9fa_fe1a5f62',
+ updated: '2018-02-15 22:07:43.000000000',
+ message: 'a third comment in the thread',
+ unresolved: true,
+ },
+ ];
+ const commentStubRes2 = [
+ {
+ patch_set: 2,
+ id: 'ecf0b9fa_fe1a5f62',
+ line: 20,
+ updated: '2018-02-08 18:49:18.000000000',
+ message: 'edited text',
+ unresolved: false,
+ },
+ ];
+ commentStub.withArgs('cc788d2c_cb1d728c').returns(
+ commentStubRes1);
+ commentStub.withArgs('ecf0b9fa_fe1a5f62').returns(
+ commentStubRes2);
+ // Expand the commit message diff
+ MockInteractions.keyUpOn(element, 73, 'shift', 'i');
+ const diffs = renderAndGetNewDiffs(0);
+ flushAsynchronousOperations();
+
+ // Two comment threads sould be generated
+ const commentThreadEls = diffs[0].getThreadEls();
+ assert(commentThreadEls[0].comments.length, 2);
+ assert(commentThreadEls[1].comments.length, 1);
+ assert.isTrue(commentThreadEls[1].comments[0].unresolved);
+ assert.equal(commentThreadEls[1].comments[0].message, 'another comment');
+
+ // Reload comments from the first comment thread, which should have a new
+ // reply.
+ element.reloadCommentsForThreadWithRootId('cc788d2c_cb1d728c',
+ '/COMMIT_MSG');
+ assert(commentThreadEls[0].comments.length, 3);
+
+
+ // Reload comments from the first comment thread, which should have a
+ // an updated message and a toggled resolve state.
+ element.reloadCommentsForThreadWithRootId('ecf0b9fa_fe1a5f62',
+ '/COMMIT_MSG');
+ assert(commentThreadEls[1].comments.length, 1);
+ assert.isFalse(commentThreadEls[1].comments[0].unresolved);
+ assert.equal(commentThreadEls[1].comments[0].message, 'edited text');
+
+ const commentStubCount = commentStub.callCount;
+ const getThreadsSpy = sandbox.spy(diffs[0], 'getThreadEls');
+
+ // Should not be getting threadss when the file is not expanded.
+ element.reloadCommentsForThreadWithRootId('ecf0b9fa_fe1a5f62',
+ 'other/file');
+ assert.isFalse(getThreadsSpy.called);
+ assert.equal(commentStubCount, commentStub.callCount);
+
+ // Should be query selecting diffs when the file is expanded.
+ // Should not be fetching change comments when the rootId is not found
+ // to match.
+ element.reloadCommentsForThreadWithRootId('acf0b9fa_fe1a5f62',
+ '/COMMIT_MSG');
+ assert.isTrue(getThreadsSpy.called);
+ assert.equal(commentStubCount, commentStub.callCount);
+ });
});
a11ySuite('basic');
</script>