1227 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			1227 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html>
 | 
						|
<!--
 | 
						|
Copyright (C) 2015 The Android Open Source Project
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
-->
 | 
						|
 | 
						|
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 | 
						|
<title>gr-file-list</title>
 | 
						|
 | 
						|
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
 | 
						|
<script src="../../../bower_components/web-component-tester/browser.js"></script>
 | 
						|
<script src="../../../bower_components/page/page.js"></script>
 | 
						|
<script src="../../../scripts/util.js"></script>
 | 
						|
 | 
						|
<link rel="import" href="../../shared/gr-rest-api-interface/mock-diff-response_test.html">
 | 
						|
<link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
 | 
						|
<link rel="import" href="gr-file-list.html">
 | 
						|
 | 
						|
<script>void(0);</script>
 | 
						|
 | 
						|
<test-fixture id="basic">
 | 
						|
  <template>
 | 
						|
    <gr-file-list></gr-file-list>
 | 
						|
  </template>
 | 
						|
</test-fixture>
 | 
						|
 | 
						|
<test-fixture id="blank">
 | 
						|
  <template>
 | 
						|
    <div></div>
 | 
						|
  </template>
 | 
						|
</test-fixture>
 | 
						|
 | 
						|
<script>
 | 
						|
  suite('gr-file-list tests', () => {
 | 
						|
    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(); },
 | 
						|
      });
 | 
						|
      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.$.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 showStub = sandbox.stub(page, 'show');
 | 
						|
        assert.equal(element.$.fileCursor.index, 2);
 | 
						|
        assert.equal(element.selectedIndex, 2);
 | 
						|
        MockInteractions.pressAndReleaseKeyOn(element, 13, null, 'enter');
 | 
						|
        assert(showStub.lastCall.calledWith('/c/42/2/myfile.txt'),
 | 
						|
            'Should navigate to /c/42/2/myfile.txt');
 | 
						|
        // k with a modifier should not move the cursor.
 | 
						|
        MockInteractions.pressAndReleaseKeyOn(element, 75, 'shift', 'k');
 | 
						|
        assert.equal(element.$.fileCursor.index, 2);
 | 
						|
 | 
						|
        MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
 | 
						|
        assert.equal(element.$.fileCursor.index, 1);
 | 
						|
        assert.equal(element.selectedIndex, 1);
 | 
						|
        MockInteractions.pressAndReleaseKeyOn(element, 79, null, 'o');
 | 
						|
        assert(showStub.lastCall.calledWith('/c/42/2/file_added_in_rev2.txt'),
 | 
						|
            'Should navigate to /c/42/2/file_added_in_rev2.txt');
 | 
						|
 | 
						|
        MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
 | 
						|
        MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
 | 
						|
        MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
 | 
						|
        assert.equal(element.$.fileCursor.index, 0);
 | 
						|
        assert.equal(element.selectedIndex, 0);
 | 
						|
      });
 | 
						|
 | 
						|
      test('i key shows/hides selected inline diff', () => {
 | 
						|
        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);
 | 
						|
        }
 | 
						|
      });
 | 
						|
 | 
						|
      suite('_handleEnterKey', () => {
 | 
						|
        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._handleEnterKey(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('noop when anchor focused', () => {
 | 
						|
          const e = new CustomEvent('fake-keyboard-event',
 | 
						|
              {detail: {keyboardEvent: {target: document.createElement('a')}}});
 | 
						|
          sinon.stub(e, 'preventDefault');
 | 
						|
          element._handleEnterKey(e);
 | 
						|
          assert.isFalse(e.preventDefault.called);
 | 
						|
        });
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    test('comment filtering', () => {
 | 
						|
      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('patch range string', () => {
 | 
						|
      assert.equal(
 | 
						|
          element._patchRangeStr({basePatchNum: 'PARENT', patchNum: '1'}),
 | 
						|
          '1');
 | 
						|
      assert.equal(
 | 
						|
          element._patchRangeStr({basePatchNum: '1', patchNum: '3'}),
 | 
						|
          '1..3');
 | 
						|
    });
 | 
						|
 | 
						|
    test('diff against dropdown', done => {
 | 
						|
      const showStub = sandbox.stub(page, 'show');
 | 
						|
      element.changeNum = '42';
 | 
						|
      element.patchRange = {
 | 
						|
        basePatchNum: 'PARENT',
 | 
						|
        patchNum: '3',
 | 
						|
      };
 | 
						|
      element.change = {
 | 
						|
        revisions: {
 | 
						|
          rev1: {_number: 1},
 | 
						|
          rev2: {_number: 2},
 | 
						|
          rev3: {_number: 3},
 | 
						|
        },
 | 
						|
      };
 | 
						|
      flush(() => {
 | 
						|
        const selectEl = element.$.patchChange;
 | 
						|
        assert.equal(selectEl.value, 'PARENT');
 | 
						|
        assert.isTrue(element.$$('option[value="3"]').hasAttribute('disabled'));
 | 
						|
        selectEl.addEventListener('change', () => {
 | 
						|
          assert.equal(selectEl.value, '2');
 | 
						|
          assert(showStub.lastCall.calledWithExactly('/c/42/2..3'),
 | 
						|
              'Should navigate to /c/42/2..3');
 | 
						|
          showStub.restore();
 | 
						|
          done();
 | 
						|
        });
 | 
						|
        selectEl.value = '2';
 | 
						|
        element.fire('change', {}, {node: selectEl});
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    test('checkbox shows/hides diff inline', () => {
 | 
						|
      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('path should be properly escaped', () => {
 | 
						|
      element._files = [
 | 
						|
        {__path: 'foo bar/my+file.txt%'},
 | 
						|
      ];
 | 
						|
      element.changeNum = '42';
 | 
						|
      element.patchRange = {
 | 
						|
        basePatchNum: 'PARENT',
 | 
						|
        patchNum: '2',
 | 
						|
      };
 | 
						|
      flushAsynchronousOperations();
 | 
						|
      // Slashes should be preserved, and spaces should be translated to `+`.
 | 
						|
      // @see Issue 4255 regarding double-encoding.
 | 
						|
      // @see Issue 4577 regarding more readable URLs.
 | 
						|
      assert.equal(
 | 
						|
          element.$$('a').getAttribute('href'),
 | 
						|
          '/c/42/2/foo+bar/my%252Bfile.txt%2525');
 | 
						|
    });
 | 
						|
 | 
						|
    test('diff mode correctly toggles the diffs', () => {
 | 
						|
      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.value, 'SIDE_BY_SIDE');
 | 
						|
 | 
						|
      // Receive the overriding preference.
 | 
						|
      resolvePrefs({default_diff_view: 'UNIFIED'});
 | 
						|
      flushAsynchronousOperations();
 | 
						|
      assert.equal(select.value, 'SIDE_BY_SIDE');
 | 
						|
      document.getElementById('blank').restore();
 | 
						|
    });
 | 
						|
 | 
						|
    test('show/hide diffs disabled for large amounts of files', 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();
 | 
						|
          });
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  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(); },
 | 
						|
      });
 | 
						|
      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(() => {
 | 
						|
        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 showStub = sandbox.stub(page, 'show');
 | 
						|
      // Noop when there are no files.
 | 
						|
      element._openSelectedFile();
 | 
						|
      assert.isFalse(showStub.called);
 | 
						|
 | 
						|
      element.set('_files', _files);
 | 
						|
      flushAsynchronousOperations();
 | 
						|
       // Navigates when a file is selected.
 | 
						|
      element._openSelectedFile();
 | 
						|
      assert.isTrue(showStub.called);
 | 
						|
    });
 | 
						|
  });
 | 
						|
</script>
 |