517 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			517 lines
		
	
	
		
			17 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-diff</title>
 | ||
| 
 | ||
| <script src="../../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
 | ||
| <script src="../../../bower_components/web-component-tester/browser.js"></script>
 | ||
| <script src="../../../scripts/util.js"></script>
 | ||
| 
 | ||
| <link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
 | ||
| <link rel="import" href="gr-diff.html">
 | ||
| 
 | ||
| <test-fixture id="basic">
 | ||
|   <template>
 | ||
|     <gr-diff></gr-diff>
 | ||
|   </template>
 | ||
| </test-fixture>
 | ||
| 
 | ||
| <script>
 | ||
|   suite('gr-diff tests', function() {
 | ||
|     var element;
 | ||
| 
 | ||
|     suite('not logged in', function() {
 | ||
|       setup(function() {
 | ||
|         stub('gr-rest-api-interface', {
 | ||
|           getLoggedIn: function() { return Promise.resolve(false); },
 | ||
|         });
 | ||
|         element = fixture('basic');
 | ||
|       });
 | ||
| 
 | ||
|       test('toggleLeftDiff', function() {
 | ||
|         element.toggleLeftDiff();
 | ||
|         assert.isTrue(element.classList.contains('no-left'));
 | ||
|         element.toggleLeftDiff();
 | ||
|         assert.isFalse(element.classList.contains('no-left'));
 | ||
|       });
 | ||
| 
 | ||
|       test('view does not start with displayLine classList', function() {
 | ||
|         assert.isFalse(
 | ||
|             element.$$('.diffContainer').classList.contains('displayLine'));
 | ||
|       });
 | ||
| 
 | ||
|       test('displayLine class added called when displayLine is true',
 | ||
|           function() {
 | ||
|         var spy = sinon.spy(element, '_computeContainerClass');
 | ||
|         element.displayLine = true;
 | ||
|         assert.isTrue(spy.called);
 | ||
|         assert.isTrue(
 | ||
|             element.$$('.diffContainer').classList.contains('displayLine'));
 | ||
|         spy.restore();
 | ||
|       });
 | ||
| 
 | ||
|       test('get drafts', function(done) {
 | ||
|         element.patchRange = {basePatchNum: 0, patchNum: 0};
 | ||
| 
 | ||
|         var getDraftsStub = sinon.stub(element.$.restAPI, 'getDiffDrafts');
 | ||
|         element._getDiffDrafts().then(function(result) {
 | ||
|           assert.deepEqual(result, {baseComments: [], comments: []});
 | ||
|           sinon.assert.notCalled(getDraftsStub);
 | ||
|           getDraftsStub.restore();
 | ||
|           done();
 | ||
|         });
 | ||
|       });
 | ||
| 
 | ||
|       test('loads files weblinks', function(done) {
 | ||
|         var diffStub = sinon.stub(element.$.restAPI, 'getDiff').returns(
 | ||
|             Promise.resolve({
 | ||
|               meta_a: {
 | ||
|                 web_links: 'foo',
 | ||
|               },
 | ||
|               meta_b: {
 | ||
|                 web_links: 'bar',
 | ||
|               },
 | ||
|             }));
 | ||
|         element.patchRange = {};
 | ||
|         element._getDiff().then(function() {
 | ||
|           assert.deepEqual(element.filesWeblinks, {
 | ||
|             meta_a: 'foo',
 | ||
|             meta_b: 'bar',
 | ||
|           });
 | ||
|           done();
 | ||
|         });
 | ||
|         diffStub.restore();
 | ||
|       });
 | ||
| 
 | ||
|       test('remove comment', function() {
 | ||
|         element._comments = {
 | ||
|           meta: {
 | ||
|             changeNum: '42',
 | ||
|             patchRange: {
 | ||
|               basePatchNum: 'PARENT',
 | ||
|               patchNum: 3,
 | ||
|             },
 | ||
|             path: '/path/to/foo',
 | ||
|             projectConfig: {foo: 'bar'},
 | ||
|           },
 | ||
|           left: [
 | ||
|             {id: 'bc1', side: 'PARENT'},
 | ||
|             {id: 'bc2', side: 'PARENT'},
 | ||
|             {id: 'bd1', __draft: true, side: 'PARENT'},
 | ||
|             {id: 'bd2', __draft: true, side: 'PARENT'},
 | ||
|           ],
 | ||
|           right: [
 | ||
|             {id: 'c1'},
 | ||
|             {id: 'c2'},
 | ||
|             {id: 'd1', __draft: true},
 | ||
|             {id: 'd2', __draft: true},
 | ||
|           ],
 | ||
|         };
 | ||
| 
 | ||
|         element._removeComment({});
 | ||
|         // Using JSON.stringify because Safari 9.1 (11601.5.17.1) doesn’t seem
 | ||
|         // to believe that one object deepEquals another even when they do :-/.
 | ||
|         assert.equal(JSON.stringify(element._comments), JSON.stringify({
 | ||
|           meta: {
 | ||
|             changeNum: '42',
 | ||
|             patchRange: {
 | ||
|               basePatchNum: 'PARENT',
 | ||
|               patchNum: 3,
 | ||
|             },
 | ||
|             path: '/path/to/foo',
 | ||
|             projectConfig: {foo: 'bar'},
 | ||
|           },
 | ||
|           left: [
 | ||
|             {id: 'bc1', side: 'PARENT'},
 | ||
|             {id: 'bc2', side: 'PARENT'},
 | ||
|             {id: 'bd1', __draft: true, side: 'PARENT'},
 | ||
|             {id: 'bd2', __draft: true, side: 'PARENT'},
 | ||
|           ],
 | ||
|           right: [
 | ||
|             {id: 'c1'},
 | ||
|             {id: 'c2'},
 | ||
|             {id: 'd1', __draft: true},
 | ||
|             {id: 'd2', __draft: true},
 | ||
|           ],
 | ||
|         }));
 | ||
| 
 | ||
|         element._removeComment({id: 'bc2', side: 'PARENT'});
 | ||
|         assert.equal(JSON.stringify(element._comments), JSON.stringify({
 | ||
|           meta: {
 | ||
|             changeNum: '42',
 | ||
|             patchRange: {
 | ||
|               basePatchNum: 'PARENT',
 | ||
|               patchNum: 3,
 | ||
|             },
 | ||
|             path: '/path/to/foo',
 | ||
|             projectConfig: {foo: 'bar'},
 | ||
|           },
 | ||
|           left: [
 | ||
|             {id: 'bc1', side: 'PARENT'},
 | ||
|             {id: 'bd1', __draft: true, side: 'PARENT'},
 | ||
|             {id: 'bd2', __draft: true, side: 'PARENT'},
 | ||
|           ],
 | ||
|           right: [
 | ||
|             {id: 'c1'},
 | ||
|             {id: 'c2'},
 | ||
|             {id: 'd1', __draft: true},
 | ||
|             {id: 'd2', __draft: true},
 | ||
|           ],
 | ||
|         }));
 | ||
| 
 | ||
|         element._removeComment({id: 'd2'});
 | ||
|         assert.deepEqual(JSON.stringify(element._comments), JSON.stringify({
 | ||
|           meta: {
 | ||
|             changeNum: '42',
 | ||
|             patchRange: {
 | ||
|               basePatchNum: 'PARENT',
 | ||
|               patchNum: 3,
 | ||
|             },
 | ||
|             path: '/path/to/foo',
 | ||
|             projectConfig: {foo: 'bar'},
 | ||
|           },
 | ||
|           left: [
 | ||
|             {id: 'bc1', side: 'PARENT'},
 | ||
|             {id: 'bd1', __draft: true, side: 'PARENT'},
 | ||
|             {id: 'bd2', __draft: true, side: 'PARENT'},
 | ||
|           ],
 | ||
|           right: [
 | ||
|             {id: 'c1'},
 | ||
|             {id: 'c2'},
 | ||
|             {id: 'd1', __draft: true},
 | ||
|           ],
 | ||
|         }));
 | ||
|       });
 | ||
| 
 | ||
|       test('renders image diffs', function(done) {
 | ||
|         var mockDiff = {
 | ||
|           meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
 | ||
|           meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
 | ||
|           intraline_status: 'OK',
 | ||
|           change_type: 'MODIFIED',
 | ||
|           diff_header: [
 | ||
|             'diff --git a/carrot.jpg b/carrot.jpg',
 | ||
|             'index 2adc47d..f9c2f2c 100644',
 | ||
|             '--- a/carrot.jpg',
 | ||
|             '+++ b/carrot.jpg',
 | ||
|             'Binary files differ',
 | ||
|           ],
 | ||
|           content: [{skip: 66}],
 | ||
|           binary: true,
 | ||
|         };
 | ||
|         var mockFile1 = {
 | ||
|           body: 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAEwsA' +
 | ||
|               'AAAAAAAAAAAAAAAA/w==',
 | ||
|           type: 'image/bmp',
 | ||
|         };
 | ||
|         var mockFile2 = {
 | ||
|           body: 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAEwsA' +
 | ||
|               'AAAAAAAAAAAA/////w==',
 | ||
|           type: 'image/bmp'
 | ||
|         };
 | ||
|         var mockCommit = {
 | ||
|           commit: '9a1a1d10baece5efbba10bc4ccf808a67a50ac0a',
 | ||
|           parents: [{
 | ||
|             commit: '7338aa9adfe57909f1fdaf88975cdea467d3382f',
 | ||
|             subject: 'Added a carrot',
 | ||
|           }],
 | ||
|           author: {
 | ||
|             name: 'Wyatt Allen',
 | ||
|             email: 'wyatta@google.com',
 | ||
|             date: '2016-05-23 21:44:51.000000000',
 | ||
|             tz: -420,
 | ||
|           },
 | ||
|           committer: {
 | ||
|             name: 'Wyatt Allen',
 | ||
|             email: 'wyatta@google.com',
 | ||
|             date: '2016-05-25 00:25:41.000000000',
 | ||
|             tz: -420,
 | ||
|           },
 | ||
|           subject: 'Updated the carrot',
 | ||
|           message: 'Updated the carrot\n\nChange-Id: Iabcd123\n',
 | ||
|         };
 | ||
|         var mockComments = {baseComments: [], comments: []};
 | ||
| 
 | ||
|         var stubs = [];
 | ||
|         stubs.push(sinon.stub(element, '_getDiff',
 | ||
|             function() { return Promise.resolve(mockDiff); }));
 | ||
|         stubs.push(sinon.stub(element.$.restAPI, 'getCommitInfo',
 | ||
|             function() { return Promise.resolve(mockCommit); }));
 | ||
|         stubs.push(sinon.stub(element.$.restAPI,
 | ||
|             'getCommitFileContents',
 | ||
|             function() { return Promise.resolve(mockFile1); }));
 | ||
|         stubs.push(sinon.stub(element.$.restAPI,
 | ||
|             'getChangeFileContents',
 | ||
|             function() { return Promise.resolve(mockFile2); }));
 | ||
|         stubs.push(sinon.stub(element.$.restAPI, '_getDiffComments',
 | ||
|             function() { return Promise.resolve(mockComments); }));
 | ||
|         stubs.push(sinon.stub(element.$.restAPI, 'getDiffDrafts',
 | ||
|             function() { return Promise.resolve(mockComments); }));
 | ||
| 
 | ||
|         element.patchRange = {basePatchNum: 'PARENT', patchNum: 1};
 | ||
| 
 | ||
|         var rendered = function() {
 | ||
|           // Recognizes that it should be an image diff.
 | ||
|           assert.isTrue(element.isImageDiff);
 | ||
|           assert.instanceOf(element.$.diffBuilder._builder, GrDiffBuilderImage);
 | ||
| 
 | ||
|           // Left image rendered with the parent commit's version of the file.
 | ||
|           var leftInmage = element.$.diffTable.querySelector('td.left img');
 | ||
|           assert.isOk(leftInmage);
 | ||
|           assert.equal(leftInmage.getAttribute('src'),
 | ||
|               'data:image/bmp;base64, ' + mockFile1.body);
 | ||
| 
 | ||
|           // Right image rendered with this change's revision of the image.
 | ||
|           var rightInmage = element.$.diffTable.querySelector('td.right img');
 | ||
|           assert.isOk(rightInmage);
 | ||
|           assert.equal(rightInmage.getAttribute('src'),
 | ||
|               'data:image/bmp;base64, ' + mockFile2.body);
 | ||
| 
 | ||
|           // Cleanup.
 | ||
|           element.removeEventListener('render', rendered);
 | ||
|           stubs.forEach(function(stub) { stub.restore(); });
 | ||
| 
 | ||
|           done();
 | ||
|         };
 | ||
| 
 | ||
|         element.addEventListener('render', rendered);
 | ||
| 
 | ||
|         element.$.restAPI.getDiffPreferences().then(function(prefs) {
 | ||
|           element.prefs = prefs;
 | ||
|           element.reload();
 | ||
|         });
 | ||
|       });
 | ||
| 
 | ||
|       test('_handleTap lineNum', function(done) {
 | ||
|         var addDraftStub = sinon.stub(element, 'addDraftAtLine');
 | ||
|         var el = document.createElement('div');
 | ||
|         el.className = 'lineNum';
 | ||
|         el.addEventListener('click', function(e) {
 | ||
|           element._handleTap(e);
 | ||
|           assert.isTrue(addDraftStub.called);
 | ||
|           assert.equal(addDraftStub.lastCall.args[0], el);
 | ||
|           done();
 | ||
|         });
 | ||
|         el.click();
 | ||
|       });
 | ||
| 
 | ||
|       test('_handleTap context', function(done) {
 | ||
|         var showContextStub = sinon.stub(element.$.diffBuilder, 'showContext');
 | ||
|         var el = document.createElement('div');
 | ||
|         el.className = 'showContext';
 | ||
|         el.addEventListener('click', function(e) {
 | ||
|           element._handleTap(e);
 | ||
|           assert.isTrue(showContextStub.called);
 | ||
|           done();
 | ||
|         });
 | ||
|         el.click();
 | ||
|       });
 | ||
| 
 | ||
|       test('_handleTap content', function(done) {
 | ||
|         var content = document.createElement('div');
 | ||
|         var lineEl = document.createElement('div');
 | ||
| 
 | ||
|         var selectStub = sinon.stub(element, '_selectLine');
 | ||
|         var getLineStub = sinon.stub(element.$.diffBuilder, 'getLineElByChild',
 | ||
|             function() { return lineEl; });
 | ||
| 
 | ||
|         content.className = 'content';
 | ||
|         content.addEventListener('click', function(e) {
 | ||
|           element._handleTap(e);
 | ||
|           assert.isTrue(selectStub.called);
 | ||
|           assert.equal(selectStub.lastCall.args[0], lineEl);
 | ||
|           selectStub.restore();
 | ||
|           getLineStub.restore();
 | ||
|           done();
 | ||
|         });
 | ||
|         content.click();
 | ||
|       });
 | ||
| 
 | ||
|       test('_getDiff handles null diff responses', function(done) {
 | ||
|         stub('gr-rest-api-interface', {
 | ||
|           getDiff: function() { return Promise.resolve(null); },
 | ||
|         });
 | ||
|         element.changeNum = 123;
 | ||
|         element.patchRange = {basePatchNum: 1, patchNum: 2};
 | ||
|         element.path = 'file.txt';
 | ||
|         element._getDiff().then(done);
 | ||
|       });
 | ||
|     });
 | ||
| 
 | ||
|     suite('logged in', function() {
 | ||
|       setup(function() {
 | ||
|         stub('gr-rest-api-interface', {
 | ||
|           getLoggedIn: function() { return Promise.resolve(true); },
 | ||
|           getPreferences: function() {
 | ||
|             return Promise.resolve({time_format: 'HHMM_12'});
 | ||
|           },
 | ||
|         });
 | ||
|         element = fixture('basic');
 | ||
|       });
 | ||
| 
 | ||
|       test('get drafts', function(done) {
 | ||
|         element.patchRange = {basePatchNum: 0, patchNum: 0};
 | ||
|         var draftsResponse = {
 | ||
|           baseComments: [{id: 'foo'}],
 | ||
|           comments: [{id: 'bar'}],
 | ||
|         };
 | ||
|         var getDraftsStub = sinon.stub(element.$.restAPI, 'getDiffDrafts',
 | ||
|             function() { return Promise.resolve(draftsResponse); });
 | ||
|         element._getDiffDrafts().then(function(result) {
 | ||
|           assert.deepEqual(result, draftsResponse);
 | ||
|           getDraftsStub.restore();
 | ||
|           done();
 | ||
|         });
 | ||
|       });
 | ||
| 
 | ||
|       test('get comments and drafts', function(done) {
 | ||
|         var comments = {
 | ||
|           baseComments: [
 | ||
|             {id: 'bc1'},
 | ||
|             {id: 'bc2'},
 | ||
|           ],
 | ||
|           comments: [
 | ||
|             {id: 'c1'},
 | ||
|             {id: 'c2'},
 | ||
|           ],
 | ||
|         };
 | ||
|         var diffCommentsStub = sinon.stub(element, '_getDiffComments',
 | ||
|             function() { return Promise.resolve(comments); });
 | ||
| 
 | ||
|         var drafts = {
 | ||
|           baseComments: [
 | ||
|             {id: 'bd1'},
 | ||
|             {id: 'bd2'},
 | ||
|           ],
 | ||
|           comments: [
 | ||
|             {id: 'd1'},
 | ||
|             {id: 'd2'},
 | ||
|           ],
 | ||
|         };
 | ||
|         var diffDraftsStub = sinon.stub(element, '_getDiffDrafts',
 | ||
|             function() { return Promise.resolve(drafts); });
 | ||
| 
 | ||
|         element.changeNum = '42';
 | ||
|         element.patchRange = {
 | ||
|           basePatchNum: 'PARENT',
 | ||
|           patchNum: 3,
 | ||
|         };
 | ||
|         element.path = '/path/to/foo';
 | ||
|         element.projectConfig = {foo: 'bar'};
 | ||
| 
 | ||
|         element._getDiffCommentsAndDrafts().then(function(result) {
 | ||
|           assert.deepEqual(result, {
 | ||
|             meta: {
 | ||
|               changeNum: '42',
 | ||
|               patchRange: {
 | ||
|                 basePatchNum: 'PARENT',
 | ||
|                 patchNum: 3,
 | ||
|               },
 | ||
|               path: '/path/to/foo',
 | ||
|               projectConfig: {foo: 'bar'},
 | ||
|             },
 | ||
|             left: [
 | ||
|               {id: 'bc1'},
 | ||
|               {id: 'bc2'},
 | ||
|               {id: 'bd1', __draft: true},
 | ||
|               {id: 'bd2', __draft: true},
 | ||
|             ],
 | ||
|             right: [
 | ||
|               {id: 'c1'},
 | ||
|               {id: 'c2'},
 | ||
|               {id: 'd1', __draft: true},
 | ||
|               {id: 'd2', __draft: true},
 | ||
|             ],
 | ||
|           });
 | ||
| 
 | ||
|           diffCommentsStub.restore();
 | ||
|           diffDraftsStub.restore();
 | ||
|           done();
 | ||
|         });
 | ||
|       });
 | ||
| 
 | ||
|       suite('handle comment-update', function() {
 | ||
| 
 | ||
|         setup(function() {
 | ||
|           element._comments = {
 | ||
|             meta: {
 | ||
|               changeNum: '42',
 | ||
|               patchRange: {
 | ||
|                 basePatchNum: 'PARENT',
 | ||
|                 patchNum: 3,
 | ||
|               },
 | ||
|               path: '/path/to/foo',
 | ||
|               projectConfig: {foo: 'bar'},
 | ||
|             },
 | ||
|             left: [
 | ||
|               {id: 'bc1', side: 'PARENT'},
 | ||
|               {id: 'bc2', side: 'PARENT'},
 | ||
|               {id: 'bd1', __draft: true, side: 'PARENT'},
 | ||
|               {id: 'bd2', __draft: true, side: 'PARENT'},
 | ||
|             ],
 | ||
|             right: [
 | ||
|               {id: 'c1'},
 | ||
|               {id: 'c2'},
 | ||
|               {id: 'd1', __draft: true},
 | ||
|               {id: 'd2', __draft: true},
 | ||
|             ],
 | ||
|           };
 | ||
|         });
 | ||
| 
 | ||
|         test('creating a draft', function() {
 | ||
|           var comment = {__draft: true, __draftID: 'tempID', side: 'PARENT'};
 | ||
|           element.fire('comment-update', {comment: comment});
 | ||
|           assert.include(element._comments.left, comment);
 | ||
|         });
 | ||
| 
 | ||
|         test('saving a draft', function() {
 | ||
|           var draftID = 'tempID';
 | ||
|           var id = 'savedID';
 | ||
|           element._comments.left.push(
 | ||
|               {__draft: true, __draftID: draftID, side: 'PARENT'});
 | ||
|           element.fire('comment-update', {comment:
 | ||
|               {id: id, __draft: true, __draftID: draftID, side: 'PARENT'},
 | ||
|           });
 | ||
|           var drafts = element._comments.left.filter(function(item) {
 | ||
|             return item.__draftID === draftID;
 | ||
|           });
 | ||
|           assert.equal(drafts.length, 1);
 | ||
|           assert.equal(drafts[0].id, id);
 | ||
|         });
 | ||
| 
 | ||
|         test('_handleShowDiff reloads when expanded is made true',
 | ||
|             function(done) {
 | ||
|           element.expanded = false;
 | ||
|           element.changeNum = element._comments.meta.changeNum;
 | ||
|           element.patchRange = element._comments.meta.patchRange;
 | ||
|           element.path = element._comments.meta.path;
 | ||
| 
 | ||
|           var stub = sinon.stub(element, 'reload', function() {
 | ||
|             assert.isTrue(stub.called);
 | ||
|             stub.restore();
 | ||
|             done();
 | ||
|           });
 | ||
|           var spy = sinon.spy(element, '_handleShowDiff');
 | ||
|           element.set('expanded', true);
 | ||
|           assert.isTrue(spy.called);
 | ||
|         });
 | ||
|       });
 | ||
|     });
 | ||
|   });
 | ||
| </script>
 | 
