| <!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="../../../test/fake-app.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; |
| var server; |
| var getDiffStub; |
| var getCommentsStub; |
| |
| setup(function() { |
| element = fixture('basic'); |
| element.changeNum = 42; |
| element.path = 'sieve.go'; |
| element.prefs = { |
| context: 10, |
| tab_size: 8, |
| }; |
| |
| getDiffStub = sinon.stub(element.$.restAPI, 'getDiff', function() { |
| return Promise.resolve({ |
| change_type: 'MODIFIED', |
| content: [ |
| { |
| ab: [ |
| '<!DOCTYPE html>', |
| '<meta charset="utf-8">', |
| '<title>My great page</title>', |
| '<style>', |
| ' *,', |
| ' *:before,', |
| ' *:after {', |
| ' box-sizing: border-box;', |
| ' }', |
| '</style>', |
| '<header>', |
| ] |
| }, |
| { |
| a: [ |
| ' Welcome ', |
| ' to the wooorld of tomorrow!', |
| ], |
| b: [ |
| ' Hello, world!', |
| ], |
| }, |
| { |
| ab: [ |
| '</header>', |
| '<body>', |
| 'Leela: This is the only place the ship can’t hear us, so ', |
| 'everyone pretend to shower.', |
| 'Fry: Same as every day. Got it.', |
| ] |
| }, |
| ] |
| }); |
| }); |
| |
| getCommentsStub = sinon.stub(element.$.restAPI, 'getDiffComments', |
| function() { |
| return Promise.resolve({ |
| baseComments: [ |
| { |
| author: { |
| _account_id: 1000000, |
| name: 'Andrew Bonventre', |
| email: 'andybons@gmail.com', |
| }, |
| id: '9af53d3f_5f2b8b82', |
| line: 1, |
| message: 'this isn’t quite right', |
| updated: '2015-12-10 02:50:21.627000000', |
| } |
| ], |
| comments: [ |
| { |
| author: { |
| _account_id: 1010008, |
| name: 'Dave Borowitz', |
| email: 'dborowitz@google.com', |
| }, |
| id: '001a2067_f30f3048', |
| line: 12, |
| message: 'What on earth are you thinking, here?', |
| updated: '2015-12-12 02:51:37.973000000', |
| }, |
| { |
| author: { |
| _account_id: 1000000, |
| name: 'Andrew Bonventre', |
| email: 'andybons@gmail.com', |
| }, |
| id: 'a0407443_30dfe8fb', |
| in_reply_to: '001a2067_f30f3048', |
| line: 12, |
| message: '¯\\_(ツ)_/¯', |
| updated: '2015-12-12 18:50:21.627000000', |
| }, |
| ], |
| }); |
| } |
| ); |
| |
| server = sinon.fakeServer.create(); |
| server.respondWith( |
| 'PUT', |
| '/accounts/self/preferences.diff', |
| [ |
| 200, |
| {'Content-Type': 'application/json'}, |
| ')]}\'\n' + |
| JSON.stringify({context: 25}), |
| ] |
| ); |
| |
| }); |
| |
| teardown(function() { |
| getDiffStub.restore(); |
| getCommentsStub.restore(); |
| server.restore(); |
| }); |
| |
| test('comment rendering', function(done) { |
| element.prefs.context = -1; |
| element._loggedIn = true; |
| element.patchRange = { |
| basePatchNum: 1, |
| patchNum: 2, |
| }; |
| |
| element.reload().then(function() { |
| flush(function() { |
| var leftThreadEls = |
| Polymer.dom(element.$.leftDiff.root).querySelectorAll( |
| 'gr-diff-comment-thread'); |
| assert.equal(leftThreadEls.length, 1); |
| assert.equal(leftThreadEls[0].comments.length, 1); |
| |
| var rightThreadEls = |
| Polymer.dom(element.$.rightDiff.root).querySelectorAll( |
| 'gr-diff-comment-thread'); |
| assert.equal(rightThreadEls.length, 1); |
| assert.equal(rightThreadEls[0].comments.length, 2); |
| |
| var index = leftThreadEls[0].getAttribute('data-index'); |
| var leftFillerEls = |
| Polymer.dom(element.$.leftDiff.root).querySelectorAll( |
| '.commentThread.filler[data-index="' + index + '"]'); |
| assert.equal(leftFillerEls.length, 1); |
| var rightFillerEls = |
| Polymer.dom(element.$.rightDiff.root).querySelectorAll( |
| '[data-index="' + index + '"]'); |
| assert.equal(rightFillerEls.length, 2); |
| |
| for (var i = 0; i < rightFillerEls.length; i++) { |
| assert.isTrue(rightFillerEls[i].classList.contains('filler')); |
| } |
| var originalHeight = rightFillerEls[0].offsetHeight; |
| assert.equal(rightFillerEls[1].offsetHeight, originalHeight); |
| assert.equal(leftThreadEls[0].offsetHeight, originalHeight); |
| assert.equal(leftFillerEls[0].offsetHeight, originalHeight); |
| |
| // Create a comment on the opposite side of the first comment. |
| var rightLineEL = element.$.rightDiff.$$( |
| '.lineNum[data-index="' + (index - 1) + '"]'); |
| assert.ok(rightLineEL); |
| MockInteractions.tap(rightLineEL); |
| flush(function() { |
| var newThreadEls = |
| Polymer.dom(element.$.rightDiff.root).querySelectorAll( |
| '[data-index="' + index + '"]'); |
| assert.equal(newThreadEls.length, 2); |
| for (var i = 0; i < newThreadEls.length; i++) { |
| assert.isTrue( |
| newThreadEls[i].classList.contains('commentThread') || |
| newThreadEls[i].tagName == 'GR-DIFF-COMMENT-THREAD'); |
| } |
| var newHeight = newThreadEls[0].offsetHeight; |
| assert.equal(newThreadEls[1].offsetHeight, newHeight); |
| assert.equal(leftFillerEls[0].offsetHeight, newHeight); |
| assert.equal(leftThreadEls[0].offsetHeight, newHeight); |
| |
| // The editing mode height of the right comment will be greater than |
| // the non-editing mode height of the left comment. |
| assert.isAbove(newHeight, originalHeight); |
| |
| // Discard the right thread and ensure the left comment heights are |
| // back to their original values. |
| newThreadEls[1].addEventListener('discard', function() { |
| rightFillerEls = |
| Polymer.dom(element.$.rightDiff.root).querySelectorAll( |
| '[data-index="' + index + '"]'); |
| assert.equal(rightFillerEls.length, 2); |
| |
| for (var i = 0; i < rightFillerEls.length; i++) { |
| assert.isTrue(rightFillerEls[i].classList.contains('filler')); |
| } |
| var originalHeight = rightFillerEls[0].offsetHeight; |
| assert.equal(rightFillerEls[1].offsetHeight, originalHeight); |
| assert.equal(leftThreadEls[0].offsetHeight, originalHeight); |
| assert.equal(leftFillerEls[0].offsetHeight, originalHeight); |
| done(); |
| }); |
| var commentEl = newThreadEls[1].$$('gr-diff-comment'); |
| commentEl.fire('discard', null, {bubbles: false}); |
| }); |
| }); |
| }); |
| server.respond(); |
| }); |
| |
| test('intraline normalization', function() { |
| // The content and highlights are in the format returned by the Gerrit |
| // REST API. |
| var content = [ |
| ' <section class="summary">', |
| ' <gr-linked-text content="' + |
| '[[_computeCurrentRevisionMessage(change)]]"></gr-linked-text>', |
| ' </section>', |
| ]; |
| var highlights = [ |
| [31, 34], [42, 26] |
| ]; |
| var results = element._normalizeIntralineHighlights(content, highlights); |
| assert.deepEqual(results, [ |
| { |
| contentIndex: 0, |
| startIndex: 31, |
| }, |
| { |
| contentIndex: 1, |
| startIndex: 0, |
| endIndex: 33, |
| }, |
| { |
| contentIndex: 1, |
| startIndex: 75, |
| }, |
| { |
| contentIndex: 2, |
| startIndex: 0, |
| endIndex: 6, |
| } |
| ]); |
| |
| content = [ |
| ' this._path = value.path;', |
| '', |
| ' // When navigating away from the page, there is a possibility that the', |
| ' // patch number is no longer a part of the URL (say when navigating to', |
| ' // the top-level change info view) and therefore undefined in `params`.', |
| ' if (!this._patchRange.patchNum) {', |
| ]; |
| highlights = [ |
| [14, 17], |
| [11, 70], |
| [12, 67], |
| [12, 67], |
| [14, 29], |
| ]; |
| results = element._normalizeIntralineHighlights(content, highlights); |
| assert.deepEqual(results, [ |
| { |
| contentIndex: 0, |
| startIndex: 14, |
| endIndex: 31, |
| }, |
| { |
| contentIndex: 2, |
| startIndex: 8, |
| endIndex: 78, |
| }, |
| { |
| contentIndex: 3, |
| startIndex: 11, |
| endIndex: 78, |
| }, |
| { |
| contentIndex: 4, |
| startIndex: 11, |
| endIndex: 78, |
| }, |
| { |
| contentIndex: 5, |
| startIndex: 12, |
| endIndex: 41, |
| } |
| ]); |
| }); |
| |
| test('context', function() { |
| element.prefs.context = 3; |
| element._diffResponse = { |
| content: [ |
| { |
| ab: [ |
| '<!DOCTYPE html>', |
| '<meta charset="utf-8">', |
| '<title>My great page</title>', |
| '<style>', |
| ' *,', |
| ' *:before,', |
| ' *:after {', |
| ' box-sizing: border-box;', |
| ' }', |
| '</style>', |
| '<header>', |
| ] |
| }, |
| { |
| a: [ |
| ' Welcome ', |
| ' to the wooorld of tomorrow!', |
| ], |
| b: [ |
| ' Hello, world!', |
| ], |
| }, |
| { |
| ab: [ |
| '</header>', |
| '<body>', |
| 'Leela: This is the only place the ship can’t hear us, so ', |
| 'everyone pretend to shower.', |
| 'Fry: Same as every day. Got it.', |
| ] |
| }, |
| ] |
| }; |
| element._processContent(); |
| |
| // First eight lines should be hidden on both sides. |
| for (var i = 0; i < 8; i++) { |
| assert.isTrue(element._diff.leftSide[i].hidden); |
| assert.isTrue(element._diff.rightSide[i].hidden); |
| } |
| // A context control should be at index 8 on both sides. |
| var leftContext = element._diff.leftSide[8]; |
| var rightContext = element._diff.rightSide[8]; |
| assert.deepEqual(leftContext, rightContext); |
| assert.equal(leftContext.numLines, 8); |
| assert.equal(leftContext.start, 0); |
| assert.equal(leftContext.end, 8); |
| |
| // Line indices 9-16 should be shown. |
| for (var i = 9; i <= 16; i++) { |
| // notOk (falsy) because the `hidden` attribute may not be present. |
| assert.notOk(element._diff.leftSide[i].hidden); |
| assert.notOk(element._diff.rightSide[i].hidden); |
| } |
| |
| // Lines at indices 17 and 18 should be hidden. |
| assert.isTrue(element._diff.leftSide[17].hidden); |
| assert.isTrue(element._diff.rightSide[17].hidden); |
| assert.isTrue(element._diff.leftSide[18].hidden); |
| assert.isTrue(element._diff.rightSide[18].hidden); |
| |
| // Context control at index 19. |
| leftContext = element._diff.leftSide[19]; |
| rightContext = element._diff.rightSide[19]; |
| assert.deepEqual(leftContext, rightContext); |
| assert.equal(leftContext.numLines, 2); |
| assert.equal(leftContext.start, 17); |
| assert.equal(leftContext.end, 19); |
| }); |
| |
| test('save prefs', function(done) { |
| element._loggedIn = false; |
| |
| element.prefs = { |
| tab_size: 4, |
| context: 50, |
| }; |
| element.fire('save', {}, {node: element.$$('gr-diff-preferences')}); |
| assert.isTrue(element._diffPreferencesPromise == null); |
| |
| element._loggedIn = true; |
| element.fire('save', {}, {node: element.$$('gr-diff-preferences')}); |
| server.respond(); |
| |
| element._diffPreferencesPromise.then(function(req) { |
| assert.equal(req.xhr.requestBody, JSON.stringify(element.prefs)); |
| done(); |
| }); |
| }); |
| |
| test('visible line length', function() { |
| assert.equal(element._visibleLineLength('A'.repeat(5)), 5); |
| assert.equal( |
| element._visibleLineLength('A'.repeat(5) + '\t' + 'A'.repeat(5)), 18); |
| }); |
| |
| test('break up common diff chunks', function() { |
| element._groupedBaseComments = { |
| 1: {}, |
| }; |
| element._groupedComments = { |
| 10: {}, |
| }; |
| var ctx = { |
| left: {lineNum: 0}, |
| right: {lineNum: 0}, |
| }; |
| var content = [ |
| { |
| ab: [ |
| '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.', |
| ] |
| } |
| ]; |
| var result = element._breakUpCommonChunksWithComments(ctx, content); |
| assert.deepEqual(result, [ |
| { |
| __noHighlight: true, |
| a: ['Copyright (C) 2015 The Android Open Source Project'], |
| b: ['Copyright (C) 2015 The Android Open Source Project'], |
| }, |
| { |
| ab: [ |
| '', |
| '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, ', |
| ] |
| }, |
| { |
| __noHighlight: true, |
| a: ['software distributed under the License is distributed on an '], |
| b: ['software distributed under the License is distributed on an '] |
| }, |
| { |
| ab: [ |
| '"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.', |
| ] |
| } |
| ]); |
| }); |
| }); |
| |
| </script> |