| <!DOCTYPE html> |
| <!-- |
| @license |
| Copyright (C) 2018 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-lite.min.js"></script> |
| <script src="../../../bower_components/web-component-tester/browser.js"></script> |
| <link rel="import" href="../../../test/common-test-setup.html"/> |
| |
| <link rel="import" href="gr-diff-host.html"> |
| |
| <script>void(0);</script> |
| |
| <test-fixture id="basic"> |
| <template> |
| <gr-diff-host></gr-diff-host> |
| </template> |
| </test-fixture> |
| |
| <script> |
| suite('gr-diff-host tests', () => { |
| let element; |
| let sandbox; |
| let getLoggedIn; |
| |
| setup(() => { |
| sandbox = sinon.sandbox.create(); |
| getLoggedIn = false; |
| stub('gr-rest-api-interface', { |
| async getLoggedIn() { return getLoggedIn; }, |
| }); |
| element = fixture('basic'); |
| // For reasons beyond me, fixture reuses elements, cleans out some |
| // stuff but not that list. |
| element._threadEls = []; |
| }); |
| |
| teardown(() => { |
| sandbox.restore(); |
| }); |
| |
| test('thread-discard handling', () => { |
| const threads = [ |
| {comments: [{id: 4711}]}, |
| {comments: [{id: 42}]}, |
| ]; |
| element._parentIndex = 1; |
| element.changeNum = '2'; |
| element.path = 'some/path'; |
| element.projectName = 'Some project'; |
| const threadEls = threads.map( |
| thread => element._createThreadElement(thread)); |
| assert.equal(threadEls.length, 2); |
| assert.equal(threadEls[0].rootId, 4711); |
| assert.equal(threadEls[1].rootId, 42); |
| for (const threadEl of threadEls) { |
| Polymer.dom(element).appendChild(threadEl); |
| } |
| |
| threadEls[0].dispatchEvent( |
| new CustomEvent('thread-discard', {detail: {rootId: 4711}})); |
| const attachedThreads = element.queryAllEffectiveChildren( |
| 'gr-diff-comment-thread'); |
| assert.equal(attachedThreads.length, 1); |
| assert.equal(attachedThreads[0].rootId, 42); |
| }); |
| |
| test('reload() cancels before network resolves', () => { |
| const cancelStub = sandbox.stub(element.$.diff, 'cancel'); |
| |
| // Stub the network calls into requests that never resolve. |
| sandbox.stub(element, '_getDiff', () => new Promise(() => {})); |
| |
| element.reload(); |
| assert.isTrue(cancelStub.called); |
| }); |
| |
| suite('not logged in', () => { |
| setup(() => { |
| getLoggedIn = false; |
| element = fixture('basic'); |
| }); |
| |
| test('reload() loads files weblinks', () => { |
| const weblinksStub = sandbox.stub(Gerrit.Nav, '_generateWeblinks') |
| .returns({name: 'stubb', url: '#s'}); |
| sandbox.stub(element.$.restAPI, 'getDiff').returns(Promise.resolve({ |
| content: [], |
| })); |
| element.projectName = 'test-project'; |
| element.path = 'test-path'; |
| element.commitRange = {baseCommit: 'test-base', commit: 'test-commit'}; |
| element.patchRange = {}; |
| return element.reload().then(() => { |
| assert.isTrue(weblinksStub.calledTwice); |
| assert.isTrue(weblinksStub.firstCall.calledWith({ |
| commit: 'test-base', |
| file: 'test-path', |
| options: { |
| weblinks: undefined, |
| }, |
| repo: 'test-project', |
| type: Gerrit.Nav.WeblinkType.FILE})); |
| assert.isTrue(weblinksStub.secondCall.calledWith({ |
| commit: 'test-commit', |
| file: 'test-path', |
| options: { |
| weblinks: undefined, |
| }, |
| repo: 'test-project', |
| type: Gerrit.Nav.WeblinkType.FILE})); |
| assert.deepEqual(element.filesWeblinks, { |
| meta_a: [{name: 'stubb', url: '#s'}], |
| meta_b: [{name: 'stubb', url: '#s'}], |
| }); |
| }); |
| }); |
| |
| test('_getDiff handles null diff responses', done => { |
| stub('gr-rest-api-interface', { |
| getDiff() { return Promise.resolve(null); }, |
| }); |
| element.changeNum = 123; |
| element.patchRange = {basePatchNum: 1, patchNum: 2}; |
| element.path = 'file.txt'; |
| element._getDiff().then(done); |
| }); |
| |
| test('reload resolves on error', () => { |
| const onErrStub = sandbox.stub(element, '_handleGetDiffError'); |
| const error = {ok: false, status: 500}; |
| sandbox.stub(element.$.restAPI, 'getDiff', |
| (changeNum, basePatchNum, patchNum, path, onErr) => { |
| onErr(error); |
| }); |
| return element.reload().then(() => { |
| assert.isTrue(onErrStub.calledOnce); |
| }); |
| }); |
| |
| suite('_handleGetDiffError', () => { |
| let serverErrorStub; |
| let pageErrorStub; |
| |
| setup(() => { |
| serverErrorStub = sinon.stub(); |
| element.addEventListener('server-error', serverErrorStub); |
| pageErrorStub = sinon.stub(); |
| element.addEventListener('page-error', pageErrorStub); |
| }); |
| |
| test('page error on HTTP-409', () => { |
| element._handleGetDiffError({status: 409}); |
| assert.isTrue(serverErrorStub.calledOnce); |
| assert.isFalse(pageErrorStub.called); |
| assert.isNotOk(element._errorMessage); |
| }); |
| |
| test('server error on non-HTTP-409', () => { |
| element._handleGetDiffError({status: 500}); |
| assert.isFalse(serverErrorStub.called); |
| assert.isTrue(pageErrorStub.calledOnce); |
| assert.isNotOk(element._errorMessage); |
| }); |
| |
| test('error message if showLoadFailure', () => { |
| element.showLoadFailure = true; |
| element._handleGetDiffError({status: 500, statusText: 'Failure!'}); |
| assert.isFalse(serverErrorStub.called); |
| assert.isFalse(pageErrorStub.called); |
| assert.equal(element._errorMessage, |
| 'Encountered error when loading the diff: 500 Failure!'); |
| }); |
| }); |
| |
| suite('image diffs', () => { |
| let mockFile1; |
| let mockFile2; |
| setup(() => { |
| mockFile1 = { |
| body: 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' + |
| 'wsAAAAAAAAAAAAAAAAA/w==', |
| type: 'image/bmp', |
| }; |
| mockFile2 = { |
| body: 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' + |
| 'wsAAAAAAAAAAAAA/////w==', |
| type: 'image/bmp', |
| }; |
| sandbox.stub(element.$.restAPI, |
| 'getB64FileContents', |
| (changeId, patchNum, path, opt_parentIndex) => { |
| return Promise.resolve(opt_parentIndex === 1 ? mockFile1 : |
| mockFile2); |
| }); |
| |
| element.patchRange = {basePatchNum: 'PARENT', patchNum: 1}; |
| element.comments = { |
| left: [], |
| right: [], |
| meta: {patchRange: element.patchRange}, |
| }; |
| }); |
| |
| test('renders image diffs with same file name', done => { |
| const 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, |
| }; |
| sandbox.stub(element.$.restAPI, 'getDiff') |
| .returns(Promise.resolve(mockDiff)); |
| |
| const rendered = () => { |
| // Recognizes that it should be an image diff. |
| assert.isTrue(element.isImageDiff); |
| assert.instanceOf( |
| element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage); |
| |
| // Left image rendered with the parent commit's version of the file. |
| const leftImage = |
| element.$.diff.$.diffTable.querySelector('td.left img'); |
| const leftLabel = |
| element.$.diff.$.diffTable.querySelector('td.left label'); |
| const leftLabelContent = leftLabel.querySelector('.label'); |
| const leftLabelName = leftLabel.querySelector('.name'); |
| |
| const rightImage = |
| element.$.diff.$.diffTable.querySelector('td.right img'); |
| const rightLabel = element.$.diff.$.diffTable.querySelector( |
| 'td.right label'); |
| const rightLabelContent = rightLabel.querySelector('.label'); |
| const rightLabelName = rightLabel.querySelector('.name'); |
| |
| assert.isNotOk(rightLabelName); |
| assert.isNotOk(leftLabelName); |
| |
| let leftLoaded = false; |
| let rightLoaded = false; |
| |
| leftImage.addEventListener('load', () => { |
| assert.isOk(leftImage); |
| assert.equal(leftImage.getAttribute('src'), |
| 'data:image/bmp;base64, ' + mockFile1.body); |
| assert.equal(leftLabelContent.textContent, '1×1 image/bmp'); |
| leftLoaded = true; |
| if (rightLoaded) { |
| element.removeEventListener('render', rendered); |
| done(); |
| } |
| }); |
| |
| rightImage.addEventListener('load', () => { |
| assert.isOk(rightImage); |
| assert.equal(rightImage.getAttribute('src'), |
| 'data:image/bmp;base64, ' + mockFile2.body); |
| assert.equal(rightLabelContent.textContent, '1×1 image/bmp'); |
| |
| rightLoaded = true; |
| if (leftLoaded) { |
| element.removeEventListener('render', rendered); |
| done(); |
| } |
| }); |
| }; |
| |
| element.addEventListener('render', rendered); |
| |
| element.$.restAPI.getDiffPreferences().then(prefs => { |
| element.prefs = prefs; |
| element.reload(); |
| }); |
| }); |
| |
| test('renders image diffs with a different file name', done => { |
| const mockDiff = { |
| meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66}, |
| meta_b: {name: 'carrot2.jpg', content_type: 'image/jpeg', |
| lines: 560}, |
| intraline_status: 'OK', |
| change_type: 'MODIFIED', |
| diff_header: [ |
| 'diff --git a/carrot.jpg b/carrot2.jpg', |
| 'index 2adc47d..f9c2f2c 100644', |
| '--- a/carrot.jpg', |
| '+++ b/carrot2.jpg', |
| 'Binary files differ', |
| ], |
| content: [{skip: 66}], |
| binary: true, |
| }; |
| sandbox.stub(element.$.restAPI, 'getDiff') |
| .returns(Promise.resolve(mockDiff)); |
| |
| const rendered = () => { |
| // Recognizes that it should be an image diff. |
| assert.isTrue(element.isImageDiff); |
| assert.instanceOf( |
| element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage); |
| |
| // Left image rendered with the parent commit's version of the file. |
| const leftImage = |
| element.$.diff.$.diffTable.querySelector('td.left img'); |
| const leftLabel = |
| element.$.diff.$.diffTable.querySelector('td.left label'); |
| const leftLabelContent = leftLabel.querySelector('.label'); |
| const leftLabelName = leftLabel.querySelector('.name'); |
| |
| const rightImage = |
| element.$.diff.$.diffTable.querySelector('td.right img'); |
| const rightLabel = element.$.diff.$.diffTable.querySelector( |
| 'td.right label'); |
| const rightLabelContent = rightLabel.querySelector('.label'); |
| const rightLabelName = rightLabel.querySelector('.name'); |
| |
| assert.isOk(rightLabelName); |
| assert.isOk(leftLabelName); |
| assert.equal(leftLabelName.textContent, mockDiff.meta_a.name); |
| assert.equal(rightLabelName.textContent, mockDiff.meta_b.name); |
| |
| let leftLoaded = false; |
| let rightLoaded = false; |
| |
| leftImage.addEventListener('load', () => { |
| assert.isOk(leftImage); |
| assert.equal(leftImage.getAttribute('src'), |
| 'data:image/bmp;base64, ' + mockFile1.body); |
| assert.equal(leftLabelContent.textContent, '1×1 image/bmp'); |
| leftLoaded = true; |
| if (rightLoaded) { |
| element.removeEventListener('render', rendered); |
| done(); |
| } |
| }); |
| |
| rightImage.addEventListener('load', () => { |
| assert.isOk(rightImage); |
| assert.equal(rightImage.getAttribute('src'), |
| 'data:image/bmp;base64, ' + mockFile2.body); |
| assert.equal(rightLabelContent.textContent, '1×1 image/bmp'); |
| |
| rightLoaded = true; |
| if (leftLoaded) { |
| element.removeEventListener('render', rendered); |
| done(); |
| } |
| }); |
| }; |
| |
| element.addEventListener('render', rendered); |
| |
| element.$.restAPI.getDiffPreferences().then(prefs => { |
| element.prefs = prefs; |
| element.reload(); |
| }); |
| }); |
| |
| test('renders added image', done => { |
| const mockDiff = { |
| meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg', |
| lines: 560}, |
| intraline_status: 'OK', |
| change_type: 'ADDED', |
| diff_header: [ |
| 'diff --git a/carrot.jpg b/carrot.jpg', |
| 'index 0000000..f9c2f2c 100644', |
| '--- /dev/null', |
| '+++ b/carrot.jpg', |
| 'Binary files differ', |
| ], |
| content: [{skip: 66}], |
| binary: true, |
| }; |
| sandbox.stub(element.$.restAPI, 'getDiff') |
| .returns(Promise.resolve(mockDiff)); |
| |
| element.addEventListener('render', () => { |
| // Recognizes that it should be an image diff. |
| assert.isTrue(element.isImageDiff); |
| assert.instanceOf( |
| element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage); |
| |
| const leftImage = |
| element.$.diff.$.diffTable.querySelector('td.left img'); |
| const rightImage = |
| element.$.diff.$.diffTable.querySelector('td.right img'); |
| |
| assert.isNotOk(leftImage); |
| assert.isOk(rightImage); |
| done(); |
| }); |
| |
| element.$.restAPI.getDiffPreferences().then(prefs => { |
| element.prefs = prefs; |
| element.reload(); |
| }); |
| }); |
| |
| test('renders removed image', done => { |
| const mockDiff = { |
| meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', |
| lines: 560}, |
| intraline_status: 'OK', |
| change_type: 'DELETED', |
| diff_header: [ |
| 'diff --git a/carrot.jpg b/carrot.jpg', |
| 'index f9c2f2c..0000000 100644', |
| '--- a/carrot.jpg', |
| '+++ /dev/null', |
| 'Binary files differ', |
| ], |
| content: [{skip: 66}], |
| binary: true, |
| }; |
| sandbox.stub(element.$.restAPI, 'getDiff') |
| .returns(Promise.resolve(mockDiff)); |
| |
| element.addEventListener('render', () => { |
| // Recognizes that it should be an image diff. |
| assert.isTrue(element.isImageDiff); |
| assert.instanceOf( |
| element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage); |
| |
| const leftImage = |
| element.$.diff.$.diffTable.querySelector('td.left img'); |
| const rightImage = |
| element.$.diff.$.diffTable.querySelector('td.right img'); |
| |
| assert.isOk(leftImage); |
| assert.isNotOk(rightImage); |
| done(); |
| }); |
| |
| element.$.restAPI.getDiffPreferences().then(prefs => { |
| element.prefs = prefs; |
| element.reload(); |
| }); |
| }); |
| |
| test('does not render disallowed image type', done => { |
| const mockDiff = { |
| meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg-evil', |
| lines: 560}, |
| intraline_status: 'OK', |
| change_type: 'DELETED', |
| diff_header: [ |
| 'diff --git a/carrot.jpg b/carrot.jpg', |
| 'index f9c2f2c..0000000 100644', |
| '--- a/carrot.jpg', |
| '+++ /dev/null', |
| 'Binary files differ', |
| ], |
| content: [{skip: 66}], |
| binary: true, |
| }; |
| mockFile1.type = 'image/jpeg-evil'; |
| |
| sandbox.stub(element.$.restAPI, 'getDiff') |
| .returns(Promise.resolve(mockDiff)); |
| |
| element.addEventListener('render', () => { |
| // Recognizes that it should be an image diff. |
| assert.isTrue(element.isImageDiff); |
| assert.instanceOf( |
| element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage); |
| const leftImage = |
| element.$.diff.$.diffTable.querySelector('td.left img'); |
| assert.isNotOk(leftImage); |
| done(); |
| }); |
| |
| element.$.restAPI.getDiffPreferences().then(prefs => { |
| element.prefs = prefs; |
| element.reload(); |
| }); |
| }); |
| }); |
| }); |
| |
| test('delegates cancel()', () => { |
| const stub = sandbox.stub(element.$.diff, 'cancel'); |
| element.reload(); |
| assert.isTrue(stub.calledOnce); |
| assert.equal(stub.lastCall.args.length, 0); |
| }); |
| |
| test('delegates getCursorStops()', () => { |
| const returnValue = [document.createElement('b')]; |
| const stub = sandbox.stub(element.$.diff, 'getCursorStops') |
| .returns(returnValue); |
| assert.equal(element.getCursorStops(), returnValue); |
| assert.isTrue(stub.calledOnce); |
| assert.equal(stub.lastCall.args.length, 0); |
| }); |
| |
| test('delegates isRangeSelected()', () => { |
| const returnValue = true; |
| const stub = sandbox.stub(element.$.diff, 'isRangeSelected') |
| .returns(returnValue); |
| assert.equal(element.isRangeSelected(), returnValue); |
| assert.isTrue(stub.calledOnce); |
| assert.equal(stub.lastCall.args.length, 0); |
| }); |
| |
| test('delegates toggleLeftDiff()', () => { |
| const stub = sandbox.stub(element.$.diff, 'toggleLeftDiff'); |
| element.toggleLeftDiff(); |
| assert.isTrue(stub.calledOnce); |
| assert.equal(stub.lastCall.args.length, 0); |
| }); |
| |
| suite('blame', () => { |
| setup(() => { |
| element = fixture('basic'); |
| }); |
| |
| test('clearBlame', () => { |
| element._blame = []; |
| const setBlameSpy = sandbox.spy(element.$.diff.$.diffBuilder, 'setBlame'); |
| element.clearBlame(); |
| assert.isNull(element._blame); |
| assert.isTrue(setBlameSpy.calledWithExactly(null)); |
| assert.equal(element.isBlameLoaded, false); |
| }); |
| |
| test('loadBlame', () => { |
| const mockBlame = [{id: 'commit id', ranges: [{start: 1, end: 2}]}]; |
| const showAlertStub = sinon.stub(); |
| element.addEventListener('show-alert', showAlertStub); |
| const getBlameStub = sandbox.stub(element.$.restAPI, 'getBlame') |
| .returns(Promise.resolve(mockBlame)); |
| element.changeNum = 42; |
| element.patchRange = {patchNum: 5, basePatchNum: 4}; |
| element.path = 'foo/bar.baz'; |
| return element.loadBlame().then(() => { |
| assert.isTrue(getBlameStub.calledWithExactly( |
| 42, 5, 'foo/bar.baz', true)); |
| assert.isFalse(showAlertStub.called); |
| assert.equal(element._blame, mockBlame); |
| assert.equal(element.isBlameLoaded, true); |
| }); |
| }); |
| |
| test('loadBlame empty', () => { |
| const mockBlame = []; |
| const showAlertStub = sinon.stub(); |
| element.addEventListener('show-alert', showAlertStub); |
| sandbox.stub(element.$.restAPI, 'getBlame') |
| .returns(Promise.resolve(mockBlame)); |
| element.changeNum = 42; |
| element.patchRange = {patchNum: 5, basePatchNum: 4}; |
| element.path = 'foo/bar.baz'; |
| return element.loadBlame() |
| .then(() => { |
| assert.isTrue(false, 'Promise should not resolve'); |
| }) |
| .catch(() => { |
| assert.isTrue(showAlertStub.calledOnce); |
| assert.isNull(element._blame); |
| assert.equal(element.isBlameLoaded, false); |
| }); |
| }); |
| }); |
| |
| test('getThreadEls() returns _threadEls', () => { |
| const returnValue = [document.createElement('b')]; |
| element._threadEls = returnValue; |
| assert.equal(element.getThreadEls(), returnValue); |
| }); |
| |
| test('delegates addDraftAtLine(el)', () => { |
| const param0 = document.createElement('b'); |
| const stub = sandbox.stub(element.$.diff, 'addDraftAtLine'); |
| element.addDraftAtLine(param0); |
| assert.isTrue(stub.calledOnce); |
| assert.equal(stub.lastCall.args.length, 1); |
| assert.equal(stub.lastCall.args[0], param0); |
| }); |
| |
| test('delegates clearDiffContent()', () => { |
| const stub = sandbox.stub(element.$.diff, 'clearDiffContent'); |
| element.clearDiffContent(); |
| assert.isTrue(stub.calledOnce); |
| assert.equal(stub.lastCall.args.length, 0); |
| }); |
| |
| test('delegates expandAllContext()', () => { |
| const stub = sandbox.stub(element.$.diff, 'expandAllContext'); |
| element.expandAllContext(); |
| assert.isTrue(stub.calledOnce); |
| assert.equal(stub.lastCall.args.length, 0); |
| }); |
| |
| test('passes in changeNum', () => { |
| const value = '12345'; |
| element.changeNum = value; |
| assert.equal(element.$.diff.changeNum, value); |
| }); |
| |
| test('passes in noAutoRender', () => { |
| const value = true; |
| element.noAutoRender = value; |
| assert.equal(element.$.diff.noAutoRender, value); |
| }); |
| |
| test('passes in patchRange', () => { |
| const value = {patchNum: 'foo', basePatchNum: 'bar'}; |
| element.patchRange = value; |
| assert.equal(element.$.diff.patchRange, value); |
| }); |
| |
| test('passes in path', () => { |
| const value = 'some/file/path'; |
| element.path = value; |
| assert.equal(element.$.diff.path, value); |
| }); |
| |
| test('passes in prefs', () => { |
| const value = {}; |
| element.prefs = value; |
| assert.equal(element.$.diff.prefs, value); |
| }); |
| |
| test('passes in changeNum', () => { |
| const value = '12345'; |
| element.changeNum = value; |
| assert.equal(element.$.diff.changeNum, value); |
| }); |
| |
| test('passes in projectName', () => { |
| const value = 'Gerrit'; |
| element.projectName = value; |
| assert.equal(element.$.diff.projectName, value); |
| }); |
| |
| test('passes in displayLine', () => { |
| const value = true; |
| element.displayLine = value; |
| assert.equal(element.$.diff.displayLine, value); |
| }); |
| |
| test('passes in commitRange', () => { |
| const value = {}; |
| element.commitRange = value; |
| assert.equal(element.$.diff.commitRange, value); |
| }); |
| |
| test('passes in hidden', () => { |
| const value = true; |
| element.hidden = value; |
| assert.equal(element.$.diff.hidden, value); |
| assert.isNotNull(element.getAttribute('hidden')); |
| }); |
| |
| test('passes in noRenderOnPrefsChange', () => { |
| const value = true; |
| element.noRenderOnPrefsChange = value; |
| assert.equal(element.$.diff.noRenderOnPrefsChange, value); |
| }); |
| |
| test('passes in comments', () => { |
| const value = {left: [], right: []}; |
| element.comments = value; |
| assert.equal(element.$.diff.comments, value); |
| }); |
| |
| test('passes in lineWrapping', () => { |
| const value = true; |
| element.lineWrapping = value; |
| assert.equal(element.$.diff.lineWrapping, value); |
| }); |
| |
| test('passes in viewMode', () => { |
| const value = 'SIDE_BY_SIDE'; |
| element.viewMode = value; |
| assert.equal(element.$.diff.viewMode, value); |
| }); |
| |
| test('passes in lineOfInterest', () => { |
| const value = {number: 123, leftSide: true}; |
| element.lineOfInterest = value; |
| assert.equal(element.$.diff.lineOfInterest, value); |
| }); |
| |
| suite('_reportDiff', () => { |
| let reportStub; |
| |
| setup(() => { |
| element = fixture('basic'); |
| element.patchRange = {basePatchNum: 1}; |
| reportStub = sandbox.stub(element.$.reporting, 'reportInteraction'); |
| }); |
| |
| test('null and content-less', () => { |
| element._reportDiff(null); |
| assert.isFalse(reportStub.called); |
| |
| element._reportDiff({}); |
| assert.isFalse(reportStub.called); |
| }); |
| |
| test('diff w/ no delta', () => { |
| const diff = { |
| content: [ |
| {ab: ['foo', 'bar']}, |
| {ab: ['baz', 'foo']}, |
| ], |
| }; |
| element._reportDiff(diff); |
| assert.isTrue(reportStub.calledOnce); |
| assert.equal(reportStub.lastCall.args[0], 'rebase-percent-zero'); |
| assert.isUndefined(reportStub.lastCall.args[1]); |
| }); |
| |
| test('diff w/ no rebase delta', () => { |
| const diff = { |
| content: [ |
| {ab: ['foo', 'bar']}, |
| {a: ['baz', 'foo']}, |
| {ab: ['foo', 'bar']}, |
| {a: ['baz', 'foo'], b: ['bar', 'baz']}, |
| {ab: ['foo', 'bar']}, |
| {b: ['baz', 'foo']}, |
| {ab: ['foo', 'bar']}, |
| ], |
| }; |
| element._reportDiff(diff); |
| assert.isTrue(reportStub.calledOnce); |
| assert.equal(reportStub.lastCall.args[0], 'rebase-percent-zero'); |
| assert.isUndefined(reportStub.lastCall.args[1]); |
| }); |
| |
| test('diff w/ some rebase delta', () => { |
| const diff = { |
| content: [ |
| {ab: ['foo', 'bar']}, |
| {a: ['baz', 'foo'], due_to_rebase: true}, |
| {ab: ['foo', 'bar']}, |
| {a: ['baz', 'foo'], b: ['bar', 'baz']}, |
| {ab: ['foo', 'bar']}, |
| {b: ['baz', 'foo'], due_to_rebase: true}, |
| {ab: ['foo', 'bar']}, |
| {a: ['baz', 'foo']}, |
| ], |
| }; |
| element._reportDiff(diff); |
| assert.isTrue(reportStub.calledOnce); |
| assert.equal(reportStub.lastCall.args[0], 'rebase-percent-nonzero'); |
| assert.strictEqual(reportStub.lastCall.args[1], 50); |
| }); |
| |
| test('diff w/ all rebase delta', () => { |
| const diff = {content: [{ |
| a: ['foo', 'bar'], |
| b: ['baz', 'foo'], |
| due_to_rebase: true, |
| }]}; |
| element._reportDiff(diff); |
| assert.isTrue(reportStub.calledOnce); |
| assert.equal(reportStub.lastCall.args[0], 'rebase-percent-nonzero'); |
| assert.strictEqual(reportStub.lastCall.args[1], 100); |
| }); |
| |
| test('diff against parent event', () => { |
| element.patchRange.basePatchNum = 'PARENT'; |
| const diff = {content: [{ |
| a: ['foo', 'bar'], |
| b: ['baz', 'foo'], |
| }]}; |
| element._reportDiff(diff); |
| assert.isTrue(reportStub.calledOnce); |
| assert.equal(reportStub.lastCall.args[0], 'diff-against-parent'); |
| assert.isUndefined(reportStub.lastCall.args[1]); |
| }); |
| }); |
| |
| test('_createThreads', () => { |
| const comments = [ |
| { |
| id: 'sallys_confession', |
| message: 'i like you, jack', |
| updated: '2015-12-23 15:00:20.396000000', |
| line: 1, |
| __commentSide: 'left', |
| }, { |
| id: 'jacks_reply', |
| message: 'i like you, too', |
| updated: '2015-12-24 15:01:20.396000000', |
| __commentSide: 'left', |
| line: 1, |
| in_reply_to: 'sallys_confession', |
| }, |
| { |
| id: 'new_draft', |
| message: 'i do not like either of you', |
| __commentSide: 'left', |
| __draft: true, |
| updated: '2015-12-20 15:01:20.396000000', |
| }, |
| ]; |
| |
| const actualThreads = element._createThreads(comments); |
| |
| assert.equal(actualThreads.length, 2); |
| |
| assert.equal( |
| actualThreads[0].start_datetime, '2015-12-23 15:00:20.396000000'); |
| assert.equal(actualThreads[0].commentSide, 'left'); |
| assert.equal(actualThreads[0].comments.length, 2); |
| assert.deepEqual(actualThreads[0].comments[0], comments[0]); |
| assert.deepEqual(actualThreads[0].comments[1], comments[1]); |
| assert.equal(actualThreads[0].patchNum, undefined); |
| assert.equal(actualThreads[0].rootId, 'sallys_confession'); |
| assert.equal(actualThreads[0].lineNum, 1); |
| |
| assert.equal( |
| actualThreads[1].start_datetime, '2015-12-20 15:01:20.396000000'); |
| assert.equal(actualThreads[1].commentSide, 'left'); |
| assert.equal(actualThreads[1].comments.length, 1); |
| assert.deepEqual(actualThreads[1].comments[0], comments[2]); |
| assert.equal(actualThreads[1].patchNum, undefined); |
| assert.equal(actualThreads[1].rootId, 'new_draft'); |
| assert.equal(actualThreads[1].lineNum, undefined); |
| }); |
| |
| test('_createThreads inherits patchNum and range', () => { |
| const comments = [{ |
| id: 'betsys_confession', |
| message: 'i like you, jack', |
| updated: '2015-12-24 15:00:10.396000000', |
| range: { |
| start_line: 1, |
| start_character: 1, |
| end_line: 1, |
| end_character: 2, |
| }, |
| patch_set: 5, |
| __commentSide: 'left', |
| line: 1, |
| }]; |
| |
| expectedThreads = [ |
| { |
| start_datetime: '2015-12-24 15:00:10.396000000', |
| commentSide: 'left', |
| comments: [{ |
| id: 'betsys_confession', |
| message: 'i like you, jack', |
| updated: '2015-12-24 15:00:10.396000000', |
| range: { |
| start_line: 1, |
| start_character: 1, |
| end_line: 1, |
| end_character: 2, |
| }, |
| patch_set: 5, |
| __commentSide: 'left', |
| line: 1, |
| }], |
| patchNum: 5, |
| rootId: 'betsys_confession', |
| range: { |
| start_line: 1, |
| start_character: 1, |
| end_line: 1, |
| end_character: 2, |
| }, |
| lineNum: 1, |
| isOnParent: false, |
| }, |
| ]; |
| |
| assert.deepEqual( |
| element._createThreads(comments), |
| expectedThreads); |
| }); |
| |
| test('_createThreads does not thread unrelated comments at same location', |
| () => { |
| const comments = [ |
| { |
| id: 'sallys_confession', |
| message: 'i like you, jack', |
| updated: '2015-12-23 15:00:20.396000000', |
| __commentSide: 'left', |
| }, { |
| id: 'jacks_reply', |
| message: 'i like you, too', |
| updated: '2015-12-24 15:01:20.396000000', |
| __commentSide: 'left', |
| }, |
| ]; |
| assert.equal(element._createThreads(comments).length, 2); |
| }); |
| |
| test('_createThreads derives isOnParent using side from first comment', |
| () => { |
| const comments = [ |
| { |
| id: 'sallys_confession', |
| message: 'i like you, jack', |
| updated: '2015-12-23 15:00:20.396000000', |
| // line: 1, |
| // __commentSide: 'left', |
| }, { |
| id: 'jacks_reply', |
| message: 'i like you, too', |
| updated: '2015-12-24 15:01:20.396000000', |
| // __commentSide: 'left', |
| // line: 1, |
| in_reply_to: 'sallys_confession', |
| }, |
| ]; |
| |
| assert.equal(element._createThreads(comments)[0].isOnParent, false); |
| |
| comments[0].side = 'REVISION'; |
| assert.equal(element._createThreads(comments)[0].isOnParent, false); |
| |
| comments[0].side = 'PARENT'; |
| assert.equal(element._createThreads(comments)[0].isOnParent, true); |
| }); |
| |
| test('_getOrCreateThread', () => { |
| const commentSide = 'left'; |
| |
| assert.isOk(element._getOrCreateThread('2', 3, |
| commentSide, undefined, false)); |
| |
| let threads = Polymer.dom(element.$.diff) |
| .queryDistributedElements('gr-diff-comment-thread'); |
| |
| assert.equal(threads.length, 1); |
| assert.equal(threads[0].commentSide, commentSide); |
| assert.equal(threads[0].range, undefined); |
| assert.equal(threads[0].isOnParent, false); |
| assert.equal(threads[0].patchNum, 2); |
| |
| |
| // Try to fetch a thread with a different range. |
| range = { |
| start_line: 1, |
| start_character: 1, |
| end_line: 1, |
| end_character: 3, |
| }; |
| |
| assert.isOk(element._getOrCreateThread( |
| '3', 1, commentSide, range, true)); |
| |
| threads = Polymer.dom(element.$.diff) |
| .queryDistributedElements('gr-diff-comment-thread'); |
| |
| assert.equal(threads.length, 2); |
| assert.equal(threads[1].commentSide, commentSide); |
| assert.equal(threads[1].range, range); |
| assert.equal(threads[1].isOnParent, true); |
| assert.equal(threads[1].patchNum, 3); |
| }); |
| |
| suite('_translateChunksToIgnore', () => { |
| let content; |
| |
| setup(() => { |
| content = [ |
| {ab: ['one', 'two']}, |
| {a: ['three'], b: ['different three']}, |
| {b: ['four']}, |
| {ab: ['five', 'six']}, |
| {a: ['seven']}, |
| {ab: ['eight', 'nine']}, |
| ]; |
| }); |
| |
| test('does nothing to unmarked diff', () => { |
| assert.deepEqual(element._translateChunksToIgnore({content}), |
| {content}); |
| }); |
| |
| test('merges marked delta chunk', () => { |
| content[1].common = true; |
| assert.deepEqual(element._translateChunksToIgnore({content}), { |
| content: [ |
| {ab: ['one', 'two', 'different three']}, |
| {b: ['four']}, |
| {ab: ['five', 'six']}, |
| {a: ['seven']}, |
| {ab: ['eight', 'nine']}, |
| ], |
| }); |
| }); |
| |
| test('merges marked addition chunk', () => { |
| content[2].common = true; |
| assert.deepEqual(element._translateChunksToIgnore({content}), { |
| content: [ |
| {ab: ['one', 'two']}, |
| {a: ['three'], b: ['different three']}, |
| {ab: ['four', 'five', 'six']}, |
| {a: ['seven']}, |
| {ab: ['eight', 'nine']}, |
| ], |
| }); |
| }); |
| |
| test('merges multiple marked delta', () => { |
| content[1].common = true; |
| content[2].common = true; |
| assert.deepEqual(element._translateChunksToIgnore({content}), { |
| content: [ |
| {ab: ['one', 'two', 'different three', 'four', 'five', 'six']}, |
| {a: ['seven']}, |
| {ab: ['eight', 'nine']}, |
| ], |
| }); |
| }); |
| |
| test('marked deletion chunks are omitted', () => { |
| content[4].common = true; |
| assert.deepEqual(element._translateChunksToIgnore({content}), { |
| content: [ |
| {ab: ['one', 'two']}, |
| {a: ['three'], b: ['different three']}, |
| {b: ['four']}, |
| {ab: ['five', 'six', 'eight', 'nine']}, |
| ], |
| }); |
| }); |
| |
| test('marked deltas can start shared chunks', () => { |
| content[0] = {a: ['one'], b: ['two'], common: true}; |
| assert.deepEqual(element._translateChunksToIgnore({content}), { |
| content: [ |
| {ab: ['two']}, |
| {a: ['three'], b: ['different three']}, |
| {b: ['four']}, |
| {ab: ['five', 'six']}, |
| {a: ['seven']}, |
| {ab: ['eight', 'nine']}, |
| ], |
| }); |
| }); |
| }); |
| }); |
| </script> |