
One notable thing that I intentionally did was name the event coming from the dropdown more simply. This makes it easier to add a handler within the html like `on-send` instead of `on-gr-reply-dropdown-send`. After a bit of thought I think we should simplify all event names for this purpose. Feature: Issue 3649 Change-Id: I2460db54b5d85243988c22f572c00043c5597210
354 lines
12 KiB
HTML
354 lines
12 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-view</title>
|
|
|
|
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
|
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
|
<script src="../../bower_components/page/page.js"></script>
|
|
<script src="../scripts/changes.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-view.html">
|
|
|
|
<test-fixture id="basic">
|
|
<template>
|
|
<gr-diff-view ruler-width="0"></gr-diff-view>
|
|
</template>
|
|
</test-fixture>
|
|
|
|
<test-fixture id="comments">
|
|
<template>
|
|
<gr-diff-view></gr-diff-view>
|
|
</template>
|
|
</test-fixture>
|
|
|
|
<test-fixture id="manylines">
|
|
<template>
|
|
<gr-diff-view></gr-diff-view>
|
|
</template>
|
|
</test-fixture>
|
|
|
|
<script>
|
|
// Original diff:
|
|
// Left side (side A):
|
|
// 1: if i < 5 { // "comments" &= \'fun\' && true
|
|
// 2: println("i is less than five")
|
|
// 3: }
|
|
// 4:
|
|
// 5:
|
|
// 6: // Comment
|
|
// 7: foo
|
|
// 8: bar
|
|
// 9: Bad news: combustible lemons failed.
|
|
//
|
|
// Right side (side B):
|
|
// 1: if i < 5 { // "comments" &= \'fun\' && true
|
|
// 2: println("i is less than five")
|
|
// 3: }
|
|
// 4:
|
|
// 5:
|
|
// 6: // Comment
|
|
// 7: baz
|
|
// 8: Bad news: combustible lemons failed.
|
|
//
|
|
var diffContent = [
|
|
{
|
|
ab: [
|
|
'if i < 5 { // "comments" &= \'fun\' && true',
|
|
' println("i is less than five")',
|
|
'}',
|
|
'',
|
|
'',
|
|
'// Comment'
|
|
]
|
|
},
|
|
{
|
|
a: [
|
|
'foo',
|
|
'bar'
|
|
],
|
|
b: [
|
|
'baz',
|
|
]
|
|
},
|
|
{
|
|
ab: [
|
|
'Bad news: combustible lemons failed.'
|
|
]
|
|
}
|
|
];
|
|
|
|
suite('<gr-diff-view>', function() {
|
|
var element;
|
|
|
|
setup(function() {
|
|
element = fixture('basic');
|
|
element._renderDiff({content: diffContent}, [], [], [], []);
|
|
flushAsynchronousOperations();
|
|
});
|
|
|
|
test('ab content is the same for left and right sides', function() {
|
|
for (var i = 0; i < diffContent[0].ab.length; i++) {
|
|
var leftEls = Polymer.dom(element.root).querySelectorAll(
|
|
'#leftDiffContent .content[data-line-num="' + (i + 1) + '"]');
|
|
assert.equal(leftEls.length, 1);
|
|
var rightEls = Polymer.dom(element.root).querySelectorAll(
|
|
'#rightDiffContent .content[data-line-num="' + (i + 1) + '"]');
|
|
assert.equal(rightEls.length, 1);
|
|
assert.equal(leftEls[0].textContent, rightEls[0].textContent);
|
|
}
|
|
});
|
|
|
|
test('all line number and content elements have same (non-zero) height',
|
|
function() {
|
|
var els = Polymer.dom(element.root).querySelectorAll('.lineNum, .content');
|
|
assert.isAbove(els.length, 0);
|
|
var offsetHeight = els.length > 0 && els[0].offsetHeight;
|
|
assert.isAbove(offsetHeight, 0);
|
|
for (var i = 0; i < els.length; i++) {
|
|
assert.equal(offsetHeight, els[i].offsetHeight);
|
|
}
|
|
});
|
|
|
|
test('content is properly escaped', function() {
|
|
var firstLineEls = Polymer.dom(element.root).querySelectorAll(
|
|
'#leftDiffContent .content[data-line-num="1"], ' +
|
|
'#rightDiffContent .content[data-line-num="1"]');
|
|
assert.equal(2, firstLineEls.length);
|
|
for (var i = 0; i < firstLineEls.length; i++) {
|
|
assert.equal(firstLineEls[i].innerHTML,
|
|
'if i < 5 { // "comments" &= \'fun\' && true');
|
|
}
|
|
});
|
|
|
|
test('content and line numbers are correct for a/b edit', function() {
|
|
assert.equal(element.$$(
|
|
'#leftDiffContent .content[data-line-num="7"]').textContent, 'foo');
|
|
assert.equal(element.$$(
|
|
'#leftDiffContent .content[data-line-num="8"]').textContent, 'bar');
|
|
assert.equal(element.$$(
|
|
'#rightDiffContent .content[data-line-num="7"]').textContent, 'baz');
|
|
assert.equal(element.$$(
|
|
'#leftDiffContent .content[data-line-num="9"]').textContent,
|
|
element.$$(
|
|
'#rightDiffContent .content[data-line-num="8"]').textContent);
|
|
});
|
|
|
|
test('ruler width changes are applied correctly', function() {
|
|
assert.equal(element.rulerWidth, 0);
|
|
assert.equal(Polymer.dom(element.root).querySelectorAll('.ruler').length,
|
|
0);
|
|
element.rulerWidth = 80;
|
|
flushAsynchronousOperations();
|
|
var els = Polymer.dom(element.root).querySelectorAll('.ruler');
|
|
assert.isAbove(els.length, 0);
|
|
for (var i = 0; i < els.length; i++) {
|
|
assert.equal(els[i].style.left, '80ch');
|
|
}
|
|
element.rulerWidth = 0;
|
|
flushAsynchronousOperations();
|
|
assert.equal(Polymer.dom(element.root).querySelectorAll('.ruler').length,
|
|
0);
|
|
element.rulerWidth = 100;
|
|
flushAsynchronousOperations();
|
|
els = Polymer.dom(element.root).querySelectorAll('.ruler');
|
|
assert.isAbove(els.length, 0);
|
|
for (var i = 0; i < els.length; i++) {
|
|
assert.equal(els[i].style.left, '100ch');
|
|
}
|
|
});
|
|
});
|
|
|
|
suite('comments and drafts', function() {
|
|
var element;
|
|
|
|
setup(function(done) {
|
|
element = fixture('comments');
|
|
element._patchNum = 1;
|
|
element._renderDiff({content: diffContent}, [], [
|
|
{
|
|
id: 'file_comment',
|
|
message: 'this is a file comment about the meaninglessness of life',
|
|
author: {
|
|
name: 'GLaDOS'
|
|
}
|
|
},
|
|
{
|
|
id: 'all_the_lemons',
|
|
line: 8,
|
|
message: 'MAKE LIFE TAKE THE LEMONS BACK',
|
|
author: {
|
|
name: 'Cave Johnson',
|
|
}
|
|
}
|
|
], [], []);
|
|
|
|
// On WebKit and Gecko, flushAsynchronousOperations isn't enough to allow
|
|
// the thread filler elements to properly render. Spin the runloop.
|
|
element.async(function() {
|
|
done();
|
|
}, 1);
|
|
});
|
|
|
|
test('comment threads are rendered correctly', function() {
|
|
var threadEls = Polymer.dom(element.root).querySelectorAll(
|
|
'gr-diff-comment-thread[data-thread-id="thread-1-8"]');
|
|
assert.equal(threadEls.length, 1);
|
|
var fillerEls = Polymer.dom(element.root).querySelectorAll(
|
|
'.js-threadFiller[data-thread-id="thread-1-8"]');
|
|
assert.equal(fillerEls.length, 3);
|
|
|
|
threadEls = Polymer.dom(element.root).querySelectorAll(
|
|
'gr-diff-comment-thread[data-thread-id="thread-1-FILE"]');
|
|
assert.equal(threadEls.length, 1);
|
|
fillerEls = Polymer.dom(element.root).querySelectorAll(
|
|
'.js-threadFiller[data-thread-id="thread-1-FILE"]');
|
|
assert.equal(fillerEls.length, 3);
|
|
});
|
|
|
|
test('tapping a line with an existing thread', function() {
|
|
var threadEls = Polymer.dom(element.root).querySelectorAll(
|
|
'gr-diff-comment-thread[data-line-num="8"][data-patch-num="1"]');
|
|
assert.equal(threadEls.length, 1);
|
|
var lineEl = element.$$(
|
|
'.lineNum[data-line-num="8"][data-patch-num="1"]');
|
|
assert.ok(lineEl);
|
|
MockInteractions.tap(lineEl);
|
|
threadEls = Polymer.dom(element.root).querySelectorAll(
|
|
'gr-diff-comment-thread[data-line-num="8"][data-patch-num="1"]');
|
|
assert.equal(threadEls.length, 1);
|
|
});
|
|
|
|
test('creating a draft', function() {
|
|
var threadEls = Polymer.dom(element.root).querySelectorAll(
|
|
'gr-diff-comment-thread[data-line-num="5"][data-patch-num="1"]');
|
|
assert.equal(threadEls.length, 0);
|
|
var lineEl = element.$$(
|
|
'.lineNum[data-line-num="5"][data-patch-num="1"]');
|
|
assert.ok(lineEl);
|
|
MockInteractions.tap(lineEl);
|
|
threadEls = Polymer.dom(element.root).querySelectorAll(
|
|
'gr-diff-comment-thread[data-line-num="5"][data-patch-num="1"]');
|
|
assert.equal(threadEls.length, 1);
|
|
});
|
|
});
|
|
|
|
suite('long diffs', function() {
|
|
var element;
|
|
|
|
setup(function() {
|
|
element = fixture('manylines');
|
|
var longDiffContent = [{ ab: [] }];
|
|
for (var i = 0; i < 300; i++) {
|
|
longDiffContent[0].ab.push('');
|
|
}
|
|
element._renderDiff({content: longDiffContent}, [], [], [], []);
|
|
});
|
|
|
|
function isVisibleInWindow(el) {
|
|
var rect = el.getBoundingClientRect();
|
|
return rect.top >= 0 && rect.left >= 0 &&
|
|
rect.bottom <= window.innerHeight && rect.right <= window.innerWidth;
|
|
}
|
|
|
|
test('jump to line', function() {
|
|
window.scrollTo(0, 0);
|
|
element._jumpToLine(-12849);
|
|
assert.equal(window.scrollY, 0);
|
|
element._jumpToLine('sup');
|
|
assert.equal(window.scrollY, 0);
|
|
// Use the left line numbers in this case because the viewport may be too
|
|
// thin for the right line number element to be visible. Since the content
|
|
// is the same for both sides, it should not make a difference.
|
|
var lineEl =
|
|
element.$$('.diffNumbers.left .lineNum[data-line-num="150"]');
|
|
assert.isFalse(isVisibleInWindow(lineEl),
|
|
'element should not be visible');
|
|
element._jumpToLine(150);
|
|
assert.isAbove(window.scrollY, 0);
|
|
assert.isTrue(isVisibleInWindow(lineEl), 'element should be visible');
|
|
});
|
|
|
|
test('keyboard shortcuts', function() {
|
|
element._changeNum = '42';
|
|
element._patchNum = '10';
|
|
element._fileList = ['chell.go', 'glados.txt', 'wheatley.md'];
|
|
element._path = 'glados.txt';
|
|
|
|
var showStub = sinon.stub(page, 'show');
|
|
MockInteractions.pressAndReleaseKeyOn(element, 85); // 'u'
|
|
assert(showStub.lastCall.calledWithExactly('/c/42'),
|
|
'Should navigate to /c/42');
|
|
|
|
pressAndReleaseKeyIdentifierOn(element, '\U+005D'); // ']'
|
|
assert(showStub.lastCall.calledWithExactly('/c/42/10/wheatley.md'),
|
|
'Should navigate to /c/42/10/wheatley.md');
|
|
element._path = 'wheatley.md';
|
|
|
|
pressAndReleaseKeyIdentifierOn(element, '\U+005B'); // '['
|
|
assert(showStub.lastCall.calledWithExactly('/c/42/10/glados.txt'),
|
|
'Should navigate to /c/42/10/glados.txt');
|
|
element._path = 'glados.txt';
|
|
|
|
pressAndReleaseKeyIdentifierOn(element, '\U+005B'); // '['
|
|
assert(showStub.lastCall.calledWithExactly('/c/42/10/chell.go'),
|
|
'Should navigate to /c/42/10/chell.go');
|
|
element._path = 'chell.go';
|
|
|
|
pressAndReleaseKeyIdentifierOn(element, '\U+005B'); // '['
|
|
assert(showStub.lastCall.calledWithExactly('/c/42'),
|
|
'Should navigate to /c/42');
|
|
|
|
showStub.restore();
|
|
|
|
// https://github.com/PolymerElements/iron-test-helpers/issues/33
|
|
function keyboardEventFor(type, keyIdentifier) {
|
|
var event = new CustomEvent(type, {
|
|
bubbles: true,
|
|
cancelable: true
|
|
});
|
|
|
|
event.keyIdentifier = keyIdentifier;
|
|
|
|
return event;
|
|
}
|
|
|
|
function keyEventOn(target, type, keyIdentifier) {
|
|
target.dispatchEvent(keyboardEventFor(type, keyIdentifier));
|
|
}
|
|
|
|
function keyDownOn(target, keyIdentifier) {
|
|
keyEventOn(target, 'keydown', keyIdentifier);
|
|
}
|
|
|
|
function keyUpOn(target, keyIdentifier) {
|
|
keyEventOn(target, 'keyup', keyIdentifier);
|
|
}
|
|
|
|
function pressAndReleaseKeyIdentifierOn(target, keyIdentifier) {
|
|
keyDownOn(target, keyIdentifier);
|
|
Polymer.Base.async(function() {
|
|
keyUpOn(target, keyIdentifier);
|
|
}, 1);
|
|
}
|
|
});
|
|
});
|
|
</script>
|