blob: aaaded24989e203695746845210328aa042dd17a [file] [log] [blame]
<!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/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="../elements/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;
setup(function() {
element = fixture('basic');
element.changeNum = 42;
element.path = 'sieve.go';
element.prefs = {
context: 10,
tab_size: 8,
};
server = sinon.fakeServer.create();
server.respondWith(
'GET',
/\/changes\/42\/revisions\/(1|2)\/files\/sieve\.go\/diff(.*)/,
[
200,
{ 'Content-Type': 'application/json' },
')]}\'\n' +
JSON.stringify({
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.',
]
},
]
}),
]
);
server.respondWith(
'GET',
'/changes/42/revisions/1/comments',
[
200,
{ 'Content-Type': 'application/json' },
')]}\'\n' +
JSON.stringify({
'/COMMIT_MSG': [],
'sieve.go': [
{
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',
},
{
author: {
_account_id: 1000000,
name: 'Andrew Bonventre',
email: 'andybons@gmail.com',
},
id: '9af53d3f_bf1cd76b',
line: 1,
side: 'PARENT',
message: 'how did this work in the first place?',
updated: '2015-12-10 00:08:42.255000000',
},
],
}),
]
);
server.respondWith(
'GET',
'/changes/42/revisions/2/comments',
[
200,
{ 'Content-Type': 'application/json' },
')]}\'\n' +
JSON.stringify({
'/COMMIT_MSG': [],
'sieve.go': [
{
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: 1010008,
name: 'Dave Borowitz',
email: 'dborowitz@google.com',
},
id: '001a2067_f6b1b1c8',
in_reply_to: '9af53d3f_bf1cd76b',
line: 1,
side: 'PARENT',
message: 'Yeah not sure how this worked either?',
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.respondWith(
'PUT',
'/accounts/self/preferences.diff',
[
200,
{ 'Content-Type': 'application/json' },
')]}\'\n' +
JSON.stringify({ context: 25 }),
]
);
});
teardown(function() {
server.restore();
});
test('comments with parent', function(done) {
element.patchRange = {
basePatchNum: 'PARENT',
patchNum: 1,
};
element.reload();
server.respond();
element._diffRequestsPromise.then(function() {
assert.equal(element._baseComments.length, 1);
assert.equal(element._comments.length, 1);
assert.equal(element._baseDrafts.length, 0);
assert.equal(element._drafts.length, 0);
done();
});
});
test('comments between two patches', function(done) {
element.patchRange = {
basePatchNum: 1,
patchNum: 2,
};
element.reload();
server.respond();
element._diffRequestsPromise.then(function() {
assert.equal(element._baseComments.length, 1);
assert.equal(element._comments.length, 2);
assert.equal(element._baseDrafts.length, 0);
assert.equal(element._drafts.length, 0);
done();
});
});
test('comment rendering', function(done) {
element.prefs.context = -1;
element._loggedIn = true;
element.patchRange = {
basePatchNum: 1,
patchNum: 2,
};
element.reload();
server.respond();
// Allow events to fire and the threads to render.
element.async(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);
element.async(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});
}, 1);
}, 1);
}),
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>