1322 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			1322 lines
		
	
	
		
			44 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>
 | |
| <link rel="import" href="../../../test/common-test-setup.html"/>
 | |
| <script src="../../../bower_components/page/page.js"></script>
 | |
| <script src="../../../scripts/util.js"></script>
 | |
| 
 | |
| <link rel="import" href="../../shared/gr-rest-api-interface/mock-diff-response_test.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', () => {
 | |
|     let element;
 | |
|     let sandbox;
 | |
|     let saveStub;
 | |
| 
 | |
|     setup(() => {
 | |
|       sandbox = sinon.sandbox.create();
 | |
|       stub('gr-rest-api-interface', {
 | |
|         getLoggedIn() { return Promise.resolve(true); },
 | |
|         getPreferences() { return Promise.resolve({}); },
 | |
|         fetchJSON() { return Promise.resolve({}); },
 | |
|       });
 | |
|       stub('gr-date-formatter', {
 | |
|         _loadTimeFormat() { return Promise.resolve(''); },
 | |
|       });
 | |
|       stub('gr-diff', {
 | |
|         reload() { return Promise.resolve(); },
 | |
|       });
 | |
|       stub('gr-comment-api', {
 | |
|         loadAll() { return Promise.resolve(); },
 | |
|         getPaths() { return {}; },
 | |
|         getCommentsForPath() { return {meta: {}, left: [], right: []}; },
 | |
|       });
 | |
| 
 | |
|       element = fixture('basic');
 | |
|       element.numFilesShown = 200;
 | |
|       saveStub = sandbox.stub(element, '_saveReviewedState',
 | |
|           () => { return Promise.resolve(); });
 | |
|     });
 | |
| 
 | |
|     teardown(() => {
 | |
|       sandbox.restore();
 | |
|     });
 | |
| 
 | |
|     test('correct number of files are shown', () => {
 | |
|       element._files = _.times(500, i => {
 | |
|         return {__path: '/file' + i, lines_inserted: 9};
 | |
|       });
 | |
|       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',
 | |
|         });
 | |
| 
 | |
|         getChangeFilesStub.restore();
 | |
|         done();
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     test('calculate totals for patch number', () => {
 | |
|       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', () => {
 | |
|       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', () => {
 | |
|       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', () => {
 | |
|       const 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 (const bytes in table) {
 | |
|         if (table.hasOwnProperty(bytes)) {
 | |
|           assert.equal(element._formatBytes(bytes), table[bytes]);
 | |
|         }
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('_formatPercentage function', () => {
 | |
|       const 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%)',
 | |
|         },
 | |
|       ];
 | |
| 
 | |
|       for (const item of table) {
 | |
|         assert.equal(element._formatPercentage(
 | |
|             item.size, item.delta), item.display);
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     suite('keyboard shortcuts', () => {
 | |
|       setup(() => {
 | |
|         element._files = [
 | |
|           {__path: '/COMMIT_MSG'},
 | |
|           {__path: 'file_added_in_rev2.txt'},
 | |
|           {__path: 'myfile.txt'},
 | |
|         ];
 | |
|         element.changeNum = '42';
 | |
|         element.patchRange = {
 | |
|           basePatchNum: 'PARENT',
 | |
|           patchNum: '2',
 | |
|         };
 | |
|         element.change = {_number: 42};
 | |
|         element.$.fileCursor.setCursorAtIndex(0);
 | |
|       });
 | |
| 
 | |
|       test('toggle left diff via shortcut', () => {
 | |
|         const toggleLeftDiffStub = sandbox.stub();
 | |
|         // Property getter cannot be stubbed w/ sandbox due to a bug in Sinon.
 | |
|         // https://github.com/sinonjs/sinon/issues/781
 | |
|         const diffsStub = sinon.stub(element, 'diffs', {
 | |
|           get() {
 | |
|             return [{toggleLeftDiff: toggleLeftDiffStub}];
 | |
|           },
 | |
|         });
 | |
|         MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
 | |
|         assert.isTrue(toggleLeftDiffStub.calledOnce);
 | |
|         diffsStub.restore();
 | |
|       });
 | |
| 
 | |
|       test('keyboard shortcuts', () => {
 | |
|         flushAsynchronousOperations();
 | |
| 
 | |
|         const 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');
 | |
| 
 | |
|         const navStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
 | |
|         assert.equal(element.$.fileCursor.index, 2);
 | |
|         assert.equal(element.selectedIndex, 2);
 | |
| 
 | |
|         // 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(navStub.lastCall.calledWith(element.change,
 | |
|             'file_added_in_rev2.txt', '2'),
 | |
|             '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', () => {
 | |
|         sandbox.stub(element, '_expandedPathsChanged');
 | |
|         flushAsynchronousOperations();
 | |
|         const 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 (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');
 | |
|         flushAsynchronousOperations();
 | |
|         for (const index in element.diffs) {
 | |
|           if (!element.diffs.hasOwnProperty(index)) { continue; }
 | |
|           assert.notInclude(element._expandedFilePaths,
 | |
|               element.diffs[index].path);
 | |
|         }
 | |
|       });
 | |
| 
 | |
|       test('r key toggles reviewed flag', () => {
 | |
|         flushAsynchronousOperations();
 | |
| 
 | |
|         // Default state should be unreviewed.
 | |
|         assert.equal(element._reviewed.length, 0);
 | |
| 
 | |
|         // Press the review key to toggle it (set the flag).
 | |
|         MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
 | |
|         assert.equal(element._reviewed.length, 1);
 | |
| 
 | |
|         // Press the review key to toggle it (clear the flag).
 | |
|         MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
 | |
|         assert.equal(element._reviewed.length, 0);
 | |
|       });
 | |
| 
 | |
|       suite('_handleOKey', () => {
 | |
|         let interact;
 | |
| 
 | |
|         setup(() => {
 | |
|           sandbox.stub(element, 'shouldSuppressKeyboardShortcut')
 | |
|               .returns(false);
 | |
|           sandbox.stub(element, 'modifierPressed').returns(false);
 | |
|           const openCursorStub = sandbox.stub(element, '_openCursorFile');
 | |
|           const openSelectedStub = sandbox.stub(element, '_openSelectedFile');
 | |
|           const expandStub = sandbox.stub(element, '_togglePathExpanded');
 | |
| 
 | |
|           interact = function(opt_payload) {
 | |
|             openCursorStub.reset();
 | |
|             openSelectedStub.reset();
 | |
|             expandStub.reset();
 | |
| 
 | |
|             const e = new CustomEvent('fake-keyboard-event', opt_payload);
 | |
|             sinon.stub(e, 'preventDefault');
 | |
|             element._handleOKey(e);
 | |
|             assert.isTrue(e.preventDefault.called);
 | |
|             const result = {};
 | |
|             if (openCursorStub.called) {
 | |
|               result.opened_cursor = true;
 | |
|             }
 | |
|             if (openSelectedStub.called) {
 | |
|               result.opened_selected = true;
 | |
|             }
 | |
|             if (expandStub.called) {
 | |
|               result.expanded = true;
 | |
|             }
 | |
|             return result;
 | |
|           };
 | |
|         });
 | |
| 
 | |
|         test('open from selected file', () => {
 | |
|           element._showInlineDiffs = false;
 | |
|           assert.deepEqual(interact(), {opened_selected: true});
 | |
|         });
 | |
| 
 | |
|         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', () => {
 | |
|           element._showInlineDiffs = false;
 | |
|           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('computed properties', () => {
 | |
|       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', () => {
 | |
|       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();
 | |
|       const fileRows =
 | |
|           Polymer.dom(element.root).querySelectorAll('.row:not(.header)');
 | |
|       const commitMsg = fileRows[0].querySelector(
 | |
|           'input.reviewed[type="checkbox"]');
 | |
|       const fileAdded = fileRows[1].querySelector(
 | |
|           'input.reviewed[type="checkbox"]');
 | |
|       const 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', () => {
 | |
|       const expected = [
 | |
|         {num: 1, desc: 'test'},
 | |
|         {num: 2, desc: 'test'},
 | |
|         {num: 3, desc: 'test'},
 | |
|         {num: 4, desc: 'test'},
 | |
|       ];
 | |
|       const patchNums = element.computeAllPatchSets({
 | |
|         revisions: {
 | |
|           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 (let i = 0; i < expected.length; i++) {
 | |
|         assert.deepEqual(patchNums[i], expected[i]);
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('diff against dropdown', done => {
 | |
|       const navStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
 | |
|       element.changeNum = '42';
 | |
|       element.patchRange = {
 | |
|         basePatchNum: 'PARENT',
 | |
|         patchNum: '3',
 | |
|       };
 | |
|       element.change = {
 | |
|         revisions: {
 | |
|           rev1: {_number: 1},
 | |
|           rev2: {_number: 2},
 | |
|           rev3: {_number: 'edit', basePatchNum: 2},
 | |
|           rev4: {_number: 3},
 | |
|         },
 | |
|       };
 | |
|       element.revisions = [
 | |
|         {_number: 1},
 | |
|         {_number: 2},
 | |
|         {_number: 'edit', basePatchNum: 2},
 | |
|         {_number: 3},
 | |
|       ];
 | |
| 
 | |
|       flush(() => {
 | |
|         const selectEl = element.$.patchChange;
 | |
|         assert.equal(selectEl.nativeSelect.value, 'PARENT');
 | |
|         assert.isTrue(element.$$('option[value="3"]').hasAttribute('disabled'));
 | |
|         selectEl.addEventListener('change', () => {
 | |
|           assert.equal(selectEl.nativeSelect.value, 'edit');
 | |
|           assert(navStub.lastCall.calledWithExactly(element.change, '3', 'edit'),
 | |
|               'Should navigate to /c/42/edit..3');
 | |
|           navStub.restore();
 | |
|           done();
 | |
|         });
 | |
|         selectEl.nativeSelect.value = 'edit';
 | |
|         element.fire('change', {}, {node: selectEl.nativeSelect});
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     test('checkbox shows/hides diff inline', () => {
 | |
|       element._files = [
 | |
|         {__path: 'myfile.txt'},
 | |
|       ];
 | |
|       element.changeNum = '42';
 | |
|       element.patchRange = {
 | |
|         basePatchNum: 'PARENT',
 | |
|         patchNum: '2',
 | |
|       };
 | |
|       element.$.fileCursor.setCursorAtIndex(0);
 | |
|       sandbox.stub(element, '_expandedPathsChanged');
 | |
|       flushAsynchronousOperations();
 | |
|       const fileRows =
 | |
|           Polymer.dom(element.root).querySelectorAll('.row:not(.header)');
 | |
|       // Because the label surrounds the input, the tap event is triggered
 | |
|       // there first.
 | |
|       const showHideLabel = fileRows[0].querySelector('label.show-hide');
 | |
|       const 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('diff mode correctly toggles the diffs', () => {
 | |
|       element._files = [
 | |
|         {__path: 'myfile.txt'},
 | |
|       ];
 | |
|       element.changeNum = '42';
 | |
|       element.patchRange = {
 | |
|         basePatchNum: 'PARENT',
 | |
|         patchNum: '2',
 | |
|       };
 | |
|       sandbox.spy(element, '_updateDiffPreferences');
 | |
|       element.$.fileCursor.setCursorAtIndex(0);
 | |
|       flushAsynchronousOperations();
 | |
| 
 | |
|       // Tap on a file to generate the diff.
 | |
|       const row = Polymer.dom(element.root)
 | |
|           .querySelectorAll('.row:not(.header) label.show-hide')[0];
 | |
| 
 | |
|       MockInteractions.tap(row);
 | |
|       flushAsynchronousOperations();
 | |
|       const 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');
 | |
|       assert.isTrue(element._updateDiffPreferences.called);
 | |
|     });
 | |
| 
 | |
|     test('diff mode selector initializes from preferences', () => {
 | |
|       let resolvePrefs;
 | |
|       const prefsPromise = new Promise(resolve => {
 | |
|         resolvePrefs = resolve;
 | |
|       });
 | |
|       sandbox.stub(element, '_getPreferences').returns(prefsPromise);
 | |
| 
 | |
|       // Attach a new gr-file-list so we can intercept the preferences fetch.
 | |
|       const view = document.createElement('gr-file-list');
 | |
|       const 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.nativeSelect.value, 'SIDE_BY_SIDE');
 | |
| 
 | |
|       // Receive the overriding preference.
 | |
|       resolvePrefs({default_diff_view: 'UNIFIED'});
 | |
|       flushAsynchronousOperations();
 | |
|       assert.equal(select.nativeSelect.value, 'SIDE_BY_SIDE');
 | |
|       document.getElementById('blank').restore();
 | |
|     });
 | |
| 
 | |
|     test('show/hide diffs disabled for large amounts of files', done => {
 | |
|       const computeSpy = sandbox.spy(element, '_fileListActionsVisible');
 | |
|       element._files = [];
 | |
|       element.changeNum = '42';
 | |
|       element.patchRange = {
 | |
|         basePatchNum: 'PARENT',
 | |
|         patchNum: '2',
 | |
|       };
 | |
|       element.$.fileCursor.setCursorAtIndex(0);
 | |
|       flush(() => {
 | |
|         assert.isTrue(computeSpy.lastCall.returnValue);
 | |
|         const arr = [];
 | |
|         _.times(element._maxFilesForBulkActions + 1, () => {
 | |
|           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', () => {
 | |
|       element._files = [
 | |
|         {__path: '/COMMIT_MSG'},
 | |
|       ];
 | |
|       assert.isNotOk(element.$$('.expanded'));
 | |
|     });
 | |
| 
 | |
|     test('_getDiffViewMode', () => {
 | |
|       // 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', () => {
 | |
|       element._files = [
 | |
|         {__path: '/COMMIT_MSG'},
 | |
|       ];
 | |
|       element.changeNum = '42';
 | |
|       element.patchRange = {
 | |
|         basePatchNum: 'PARENT',
 | |
|         patchNum: '2',
 | |
|       };
 | |
|       sandbox.stub(element, '_expandedPathsChanged');
 | |
|       flushAsynchronousOperations();
 | |
|       const 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');
 | |
|       const 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', () => {
 | |
|       const path = 'path/to/my/file.txt';
 | |
|       element.files = [{__path: path}];
 | |
|       const 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', done => {
 | |
|       sandbox.stub(element, '_reviewFile');
 | |
|       const path = 'path/to/my/file.txt';
 | |
|       const diffs = [{
 | |
|         path,
 | |
|         reload() {
 | |
|           done();
 | |
|         },
 | |
|       }];
 | |
|       sinon.stub(element, 'diffs', {
 | |
|         get() { return diffs; },
 | |
|       });
 | |
|       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('_handleFileListTap ctrl', () => {
 | |
|         testForModifier('ctrlKey');
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     test('_renderInOrder', done => {
 | |
|       const reviewStub = sandbox.stub(element, '_reviewFile');
 | |
|       let callCount = 0;
 | |
|       const diffs = [{
 | |
|         path: 'p0',
 | |
|         reload() {
 | |
|           assert.equal(callCount++, 2);
 | |
|           return Promise.resolve();
 | |
|         },
 | |
|       }, {
 | |
|         path: 'p1',
 | |
|         reload() {
 | |
|           assert.equal(callCount++, 1);
 | |
|           return Promise.resolve();
 | |
|         },
 | |
|       }, {
 | |
|         path: 'p2',
 | |
|         reload() {
 | |
|           assert.equal(callCount++, 0);
 | |
|           return Promise.resolve();
 | |
|         },
 | |
|       }];
 | |
|       element._renderInOrder(['p2', 'p1', 'p0'], diffs, 3)
 | |
|           .then(() => {
 | |
|             assert.isFalse(reviewStub.called);
 | |
|             done();
 | |
|           });
 | |
|     });
 | |
| 
 | |
|     test('_renderInOrder logged in', done => {
 | |
|       element._isLoggedIn = true;
 | |
|       const reviewStub = sandbox.stub(element, '_reviewFile');
 | |
|       let callCount = 0;
 | |
|       const diffs = [{
 | |
|         path: 'p0',
 | |
|         reload() {
 | |
|           assert.equal(reviewStub.callCount, 2);
 | |
|           assert.equal(callCount++, 2);
 | |
|           return Promise.resolve();
 | |
|         },
 | |
|       }, {
 | |
|         path: 'p1',
 | |
|         reload() {
 | |
|           assert.equal(reviewStub.callCount, 1);
 | |
|           assert.equal(callCount++, 1);
 | |
|           return Promise.resolve();
 | |
|         },
 | |
|       }, {
 | |
|         path: 'p2',
 | |
|         reload() {
 | |
|           assert.equal(reviewStub.callCount, 0);
 | |
|           assert.equal(callCount++, 0);
 | |
|           return Promise.resolve();
 | |
|         },
 | |
|       }];
 | |
|       element._renderInOrder(['p2', 'p1', 'p0'], diffs, 3)
 | |
|           .then(() => {
 | |
|             assert.equal(reviewStub.callCount, 3);
 | |
|             done();
 | |
|           });
 | |
|     });
 | |
| 
 | |
|     test('_loadingChanged fired from reload in debouncer', done => {
 | |
|       element.changeNum = 123;
 | |
|       element.patchRange = {patchNum: 12};
 | |
|       element._files = [{__path: 'foo.bar'}];
 | |
| 
 | |
|       element.reload().then(() => {
 | |
|         assert.isFalse(element._loading);
 | |
|         element.flushDebouncer('loading-change');
 | |
|         assert.isFalse(element.classList.contains('loading'));
 | |
|         done();
 | |
|       });
 | |
|       assert.isTrue(element._loading);
 | |
|       assert.isFalse(element.classList.contains('loading'));
 | |
|       element.flushDebouncer('loading-change');
 | |
|       assert.isTrue(element.classList.contains('loading'));
 | |
|     });
 | |
| 
 | |
|     test('_loadingChanged does not set class when there are no files', () => {
 | |
|       element.changeNum = 123;
 | |
|       element.patchRange = {patchNum: 12};
 | |
|       element.reload();
 | |
|       assert.isTrue(element._loading);
 | |
|       element.flushDebouncer('loading-change');
 | |
|       assert.isFalse(element.classList.contains('loading'));
 | |
|     });
 | |
| 
 | |
|     test('no execute _computeDiffURL before patchNum is knwon', done => {
 | |
|       const urlStub = sandbox.stub(element, '_computeDiffURL');
 | |
|       element.change = {_number: 123};
 | |
|       element.patchRange = {patchNum: undefined, basePatchNum: 'PARENT'};
 | |
|       element._files = [{__path: 'foo/bar.cpp'}];
 | |
|       flush(() => {
 | |
|         assert.isFalse(urlStub.called);
 | |
|         element.set('patchRange.patchNum', 4);
 | |
|         flush(() => {
 | |
|           assert.isTrue(urlStub.called);
 | |
|           done();
 | |
|         });
 | |
|       });
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   suite('gr-file-list inline diff tests', () => {
 | |
|     let element;
 | |
|     let sandbox;
 | |
| 
 | |
|     const setupDiff = function(diff) {
 | |
|       const mock = document.createElement('mock-diff-response');
 | |
|       diff._diff = mock.diffResponse;
 | |
|       diff.comments = {
 | |
|         left: [],
 | |
|         right: [],
 | |
|       };
 | |
|       diff.prefs = {
 | |
|         context: 10,
 | |
|         tab_size: 8,
 | |
|         font_size: 12,
 | |
|         line_length: 100,
 | |
|         cursor_blink_rate: 0,
 | |
|         line_wrapping: false,
 | |
|         intraline_difference: true,
 | |
|         show_line_endings: true,
 | |
|         show_tabs: true,
 | |
|         show_whitespace_errors: true,
 | |
|         syntax_highlighting: true,
 | |
|         auto_hide_diff_table_header: true,
 | |
|         theme: 'DEFAULT',
 | |
|         ignore_whitespace: 'IGNORE_NONE',
 | |
|       };
 | |
|       diff._renderDiffTable();
 | |
|     };
 | |
| 
 | |
|     const renderAndGetNewDiffs = function(index) {
 | |
|       const diffs =
 | |
|           Polymer.dom(element.root).querySelectorAll('gr-diff');
 | |
| 
 | |
|       for (let i = index; i < diffs.length; i++) {
 | |
|         setupDiff(diffs[i]);
 | |
|       }
 | |
| 
 | |
|       element._updateDiffCursor();
 | |
|       element.$.diffCursor.handleDiffUpdate();
 | |
|       return diffs;
 | |
|     };
 | |
| 
 | |
|     setup(() => {
 | |
|       sandbox = sinon.sandbox.create();
 | |
|       stub('gr-rest-api-interface', {
 | |
|         getLoggedIn() { return Promise.resolve(true); },
 | |
|         getPreferences() { return Promise.resolve({}); },
 | |
|       });
 | |
|       stub('gr-date-formatter', {
 | |
|         _loadTimeFormat() { return Promise.resolve(''); },
 | |
|       });
 | |
|       stub('gr-diff', {
 | |
|         reload() { return Promise.resolve(); },
 | |
|       });
 | |
|       stub('gr-comment-api', {
 | |
|         loadAll() { return Promise.resolve(); },
 | |
|         getPaths() { return {}; },
 | |
|         getCommentsForPath() { return {meta: {}, left: [], right: []}; },
 | |
|       });
 | |
|       element = fixture('basic');
 | |
|       element.numFilesShown = 75;
 | |
|       element.selectedIndex = 0;
 | |
|       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,
 | |
|         },
 | |
|       ];
 | |
|       element._reviewed = ['/COMMIT_MSG', 'myfile.txt'];
 | |
|       element._loggedIn = true;
 | |
|       element.changeNum = '42';
 | |
|       element.patchRange = {
 | |
|         basePatchNum: 'PARENT',
 | |
|         patchNum: '2',
 | |
|       };
 | |
|       sandbox.stub(window, 'fetch', () => {
 | |
|         return Promise.resolve();
 | |
|       });
 | |
|       flushAsynchronousOperations();
 | |
|     });
 | |
| 
 | |
|     teardown(() => {
 | |
|       sandbox.restore();
 | |
|     });
 | |
| 
 | |
|     test('cursor with individually opened files', () => {
 | |
|       MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
 | |
|       flushAsynchronousOperations();
 | |
|       let diffs = renderAndGetNewDiffs(0);
 | |
|       const diffStops = diffs[0].getCursorStops();
 | |
| 
 | |
|       // 1 diff should be rendered.
 | |
|       assert.equal(diffs.length, 1);
 | |
| 
 | |
|       // No line number is selected.
 | |
|       assert.isFalse(diffStops[10].classList.contains('target-row'));
 | |
| 
 | |
|       // Tapping content on a line selects the line number.
 | |
|       MockInteractions.tap(Polymer.dom(
 | |
|           diffStops[10]).querySelectorAll('.contentText')[0]);
 | |
|       flushAsynchronousOperations();
 | |
|       assert.isTrue(diffStops[10].classList.contains('target-row'));
 | |
| 
 | |
|       // Keyboard shortcuts are still moving the file cursor, not the diff
 | |
|       // cursor.
 | |
|       MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
 | |
|       flushAsynchronousOperations();
 | |
|       assert.isTrue(diffStops[10].classList.contains('target-row'));
 | |
|       assert.isFalse(diffStops[11].classList.contains('target-row'));
 | |
| 
 | |
|       // The file cusor is now at 1.
 | |
|       assert.equal(element.$.fileCursor.index, 1);
 | |
|       MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
 | |
|       flushAsynchronousOperations();
 | |
| 
 | |
|       diffs = renderAndGetNewDiffs(1);
 | |
|       // Two diffs should be rendered.
 | |
|       assert.equal(diffs.length, 2);
 | |
|       const diffStopsFirst = diffs[0].getCursorStops();
 | |
|       const diffStopsSecond = diffs[1].getCursorStops();
 | |
| 
 | |
|       // The line on the first diff is stil selected
 | |
|       assert.isTrue(diffStopsFirst[10].classList.contains('target-row'));
 | |
|       assert.isFalse(diffStopsSecond[10].classList.contains('target-row'));
 | |
|     });
 | |
| 
 | |
|     test('cursor with toggle all files', () => {
 | |
|       MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'i');
 | |
|       flushAsynchronousOperations();
 | |
| 
 | |
|       const diffs = renderAndGetNewDiffs(0);
 | |
|       const diffStops = diffs[0].getCursorStops();
 | |
| 
 | |
|       // 1 diff should be rendered.
 | |
|       assert.equal(diffs.length, 3);
 | |
| 
 | |
|       // No line number is selected.
 | |
|       assert.isFalse(diffStops[10].classList.contains('target-row'));
 | |
| 
 | |
|       // Tapping content on a line selects the line number.
 | |
|       MockInteractions.tap(Polymer.dom(
 | |
|           diffStops[10]).querySelectorAll('.contentText')[0]);
 | |
|       flushAsynchronousOperations();
 | |
|       assert.isTrue(diffStops[10].classList.contains('target-row'));
 | |
| 
 | |
|       // Keyboard shortcuts are still moving the file cursor, not the diff
 | |
|       // cursor.
 | |
|       MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
 | |
|       flushAsynchronousOperations();
 | |
|       assert.isFalse(diffStops[10].classList.contains('target-row'));
 | |
|       assert.isTrue(diffStops[11].classList.contains('target-row'));
 | |
| 
 | |
|       // The file cusor is still at 0.
 | |
|       assert.equal(element.$.fileCursor.index, 0);
 | |
|     });
 | |
| 
 | |
|     suite('n key presses', () => {
 | |
|       let nKeySpy;
 | |
|       let nextCommentStub;
 | |
|       let nextChunkStub;
 | |
|       let fileRows;
 | |
|       setup(() => {
 | |
|         sandbox.stub(element, '_renderInOrder').returns(Promise.resolve());
 | |
|         nKeySpy = sandbox.spy(element, '_handleNKey');
 | |
|         nextCommentStub = sandbox.stub(element.$.diffCursor,
 | |
|             'moveToNextCommentThread');
 | |
|         nextChunkStub = sandbox.stub(element.$.diffCursor,
 | |
|             'moveToNextChunk');
 | |
|         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');
 | |
|         flushAsynchronousOperations();
 | |
| 
 | |
|         // Handle N key should return before calling diff cursor functions.
 | |
|         MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
 | |
|         assert.isTrue(nKeySpy.called);
 | |
|         assert.isFalse(nextCommentStub.called);
 | |
| 
 | |
|         // This is also called in diffCursor.moveToFirstChunk.
 | |
|         assert.equal(nextChunkStub.callCount, 1);
 | |
|         assert.isFalse(!!element._showInlineDiffs);
 | |
|       });
 | |
| 
 | |
|       test('n key with all files expanded and shift key', () => {
 | |
|         MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, null, 'i');
 | |
|         flushAsynchronousOperations();
 | |
| 
 | |
|         MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
 | |
|         assert.isTrue(nKeySpy.called);
 | |
|         assert.isFalse(nextCommentStub.called);
 | |
| 
 | |
|         // This is also called in diffCursor.moveToFirstChunk.
 | |
|         assert.equal(nextChunkStub.callCount, 1);
 | |
|         assert.isFalse(!!element._showInlineDiffs);
 | |
|       });
 | |
| 
 | |
|       test('n key without all files expanded and shift key', () => {
 | |
|         MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, 'shift', 'i');
 | |
|         flushAsynchronousOperations();
 | |
| 
 | |
|         MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
 | |
|         assert.isTrue(nKeySpy.called);
 | |
|         assert.isFalse(nextCommentStub.called);
 | |
| 
 | |
|         // This is also called in diffCursor.moveToFirstChunk.
 | |
|         assert.equal(nextChunkStub.callCount, 2);
 | |
|         assert.isTrue(element._showInlineDiffs);
 | |
|       });
 | |
| 
 | |
|       test('n key without all files expanded and no shift key', () => {
 | |
|         MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, 'shift', 'i');
 | |
|         flushAsynchronousOperations();
 | |
| 
 | |
|         MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
 | |
|         assert.isTrue(nKeySpy.called);
 | |
|         assert.isTrue(nextCommentStub.called);
 | |
| 
 | |
|         // This is also called in diffCursor.moveToFirstChunk.
 | |
|         assert.equal(nextChunkStub.callCount, 1);
 | |
|         assert.isTrue(element._showInlineDiffs);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     test('_openSelectedFile behavior', () => {
 | |
|       const _files = element._files;
 | |
|       element.set('_files', []);
 | |
|       const navStub = sandbox.stub(Gerrit.Nav, 'navigateToDiff');
 | |
|       // Noop when there are no files.
 | |
|       element._openSelectedFile();
 | |
|       assert.isFalse(navStub.called);
 | |
| 
 | |
|       element.set('_files', _files);
 | |
|       flushAsynchronousOperations();
 | |
|        // Navigates when a file is selected.
 | |
|       element._openSelectedFile();
 | |
|       assert.isTrue(navStub.called);
 | |
|     });
 | |
| 
 | |
|     test('_displayLine', () => {
 | |
|       sandbox.stub(element, 'shouldSuppressKeyboardShortcut', () => false);
 | |
|       sandbox.stub(element, 'modifierPressed', () => false);
 | |
|       element._showInlineDiffs = true;
 | |
|       const mockEvent = {preventDefault() {}};
 | |
| 
 | |
|       element._displayLine = false;
 | |
|       element._handleDownKey(mockEvent);
 | |
|       assert.isTrue(element._displayLine);
 | |
| 
 | |
|       element._displayLine = false;
 | |
|       element._handleUpKey(mockEvent);
 | |
|       assert.isTrue(element._displayLine);
 | |
| 
 | |
|       element._displayLine = true;
 | |
|       element._handleEscKey(mockEvent);
 | |
|       assert.isFalse(element._displayLine);
 | |
|     });
 | |
| 
 | |
|     suite('editLoaded behavior', () => {
 | |
|       const isVisible = el => {
 | |
|         assert.ok(el);
 | |
|         return getComputedStyle(el).getPropertyValue('display') !== 'none';
 | |
|       };
 | |
| 
 | |
|       test('reviewed checkbox', () => {
 | |
|         const alertStub = sandbox.stub();
 | |
|         element.addEventListener('show-alert', alertStub);
 | |
|         element.editLoaded = false;
 | |
|         // Reviewed checkbox should be shown.
 | |
|         assert.isTrue(isVisible(element.$$('.reviewed')));
 | |
|         MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
 | |
|         assert.isFalse(alertStub.called);
 | |
| 
 | |
|         element.editLoaded = true;
 | |
|         flushAsynchronousOperations();
 | |
| 
 | |
|         assert.isFalse(isVisible(element.$$('.reviewed')));
 | |
|         MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
 | |
|         assert.isTrue(alertStub.called);
 | |
|       });
 | |
| 
 | |
|       test('_getReviewedFiles does not call API', () => {
 | |
|         const apiSpy = sandbox.spy(element.$.restAPI, 'getReviewedFiles');
 | |
|         element.editLoaded = true;
 | |
|         return element._getReviewedFiles().then(files => {
 | |
|           assert.equal(files.length, 0);
 | |
|           assert.isFalse(apiSpy.called);
 | |
|         });
 | |
|       });
 | |
|     });
 | |
|   });
 | |
|   a11ySuite('basic');
 | |
| </script>
 | 
