blob: 23bd6ef833cbb26bc2d7b350788a1fa9c8b7158a [file]
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import '../../../test/common-test-setup';
import {LitElement} from 'lit';
import './gr-diff-row';
import {GrDiffRow} from './gr-diff-row';
import {assert, fixture, html} from '@open-wc/testing';
import {GrDiffLine} from '../gr-diff/gr-diff-line';
import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
import {DiffViewMode, GrDiffLineType, Side} from '../../../api/diff';
import {diffModelToken} from '../gr-diff-model/gr-diff-model';
import {testResolver} from '../../../test/common-test-setup';
interface GrDiffRowPrivate {
layersApplied: boolean;
updateLayers(side: Side): Promise<void>;
}
suite('gr-diff-row test', () => {
let element: GrDiffRow;
setup(async () => {
element = await fixture<GrDiffRow>(html`<gr-diff-row></gr-diff-row>`);
element.addTableWrapperForTesting = true;
await element.updateComplete;
});
test('both', async () => {
const line = new GrDiffLine(GrDiffLineType.BOTH, 1, 1);
line.text = 'lorem ipsum';
element.left = line;
element.right = line;
await element.updateComplete;
assert.lightDom.equal(
element,
/* HTML */ `
<table>
<tbody>
<tr
aria-labelledby="left-button-1 left-content-1 right-button-1 right-content-1"
class="diff-row side-by-side"
left-type="both"
right-type="both"
tabindex="-1"
>
<td class="left lineNum" data-value="1">
<button
aria-label="1 unmodified"
class="left lineNumButton"
data-value="1"
id="left-button-1"
tabindex="-1"
>
1
</button>
</td>
<td class="both content left no-intraline-info">
<div
class="contentText"
data-side="left"
id="left-content-1"
>
<gr-diff-text data-side="left"> lorem ipsum </gr-diff-text>
</div>
</div>
</td>
<td class="lineNum right" data-value="1">
<button
aria-label="1 unmodified"
class="lineNumButton right"
data-value="1"
id="right-button-1"
tabindex="-1"
>
1
</button>
</td>
<td class="both content no-intraline-info right">
<div
class="contentText"
data-side="right"
id="right-content-1"
>
<gr-diff-text data-side="right"> lorem ipsum </gr-diff-text>
</div>
</td>
</tr>
<slot name="post-left-line-1"></slot>
<slot name="post-right-line-1"></slot>
</tbody>
</table>
`
);
});
test('both unified', async () => {
const line = new GrDiffLine(GrDiffLineType.BOTH, 1, 1);
line.text = 'lorem ipsum';
element.left = line;
element.right = line;
const diffModel = testResolver(diffModelToken);
diffModel.updateState({renderPrefs: {view_mode: DiffViewMode.UNIFIED}});
element.unifiedDiff = true;
await element.updateComplete;
assert.lightDom.equal(
element,
/* HTML */ `
<table>
<tbody>
<tr
aria-labelledby="left-button-1 right-button-1 right-content-1"
class="both diff-row unified"
tabindex="-1"
>
<td class="left lineNum" data-value="1">
<button
aria-label="1 unmodified"
class="left lineNumButton"
data-value="1"
id="left-button-1"
tabindex="-1"
>
1
</button>
</td>
<td class="lineNum right" data-value="1">
<button
aria-label="1 unmodified"
class="lineNumButton right"
data-value="1"
id="right-button-1"
tabindex="-1"
>
1
</button>
</td>
<td class="both content no-intraline-info right">
<div class="contentText" data-side="right" id="right-content-1">
<gr-diff-text data-side="right"> lorem ipsum </gr-diff-text>
</div>
</td>
</tr>
<slot name="post-left-line-1"></slot>
<slot name="post-right-line-1"></slot>
</tbody>
</table>
`
);
});
test('add', async () => {
const line = new GrDiffLine(GrDiffLineType.ADD, 0, 1);
line.text = 'lorem ipsum';
element.left = new GrDiffLine(GrDiffLineType.BLANK);
element.right = line;
await element.updateComplete;
assert.lightDom.equal(
element,
/* HTML */ `
<table>
<tbody>
<tr
aria-labelledby="right-button-1 right-content-1"
class="diff-row side-by-side"
left-type="blank"
right-type="add"
tabindex="-1"
>
<td class="blankLineNum left"></td>
<td class="blank left no-intraline-info">
<div class="contentText" data-side="left">
<gr-diff-text data-side="left"></gr-diff-text>
</div>
</td>
<td class="lineNum right" data-value="1">
<button
aria-label="1 added"
class="lineNumButton right"
data-value="1"
id="right-button-1"
tabindex="-1"
>
1
</button>
</td>
<td class="add content no-intraline-info right">
<div class="contentText" data-side="right" id="right-content-1">
<gr-diff-text data-side="right"> lorem ipsum </gr-diff-text>
</div>
</td>
<slot name="post-right-line-1"></slot>
</tr>
</tbody>
</table>
`
);
});
test('remove', async () => {
const line = new GrDiffLine(GrDiffLineType.REMOVE, 1, 0);
line.text = 'lorem ipsum';
element.left = line;
element.right = new GrDiffLine(GrDiffLineType.BLANK);
await element.updateComplete;
assert.lightDom.equal(
element,
/* HTML */ `
<table>
<tbody>
<tr
aria-labelledby="left-button-1 left-content-1"
class="diff-row side-by-side"
left-type="remove"
right-type="blank"
tabindex="-1"
>
<td class="left lineNum" data-value="1">
<button
aria-label="1 removed"
class="left lineNumButton"
data-value="1"
id="left-button-1"
tabindex="-1"
>
1
</button>
</td>
<td class="content left no-intraline-info remove">
<div class="contentText" data-side="left" id="left-content-1">
<gr-diff-text data-side="left"> lorem ipsum </gr-diff-text>
</div>
</td>
<td class="blankLineNum right"></td>
<td class="blank no-intraline-info right">
<div class="contentText" data-side="right">
<gr-diff-text data-side="right"></gr-diff-text>
</div>
</td>
</tr>
<slot name="post-left-line-1"></slot>
</tbody>
</table>
`
);
});
test('renders revert button when showRevertButton is true', async () => {
const line = new GrDiffLine(GrDiffLineType.REMOVE, 1, 0);
line.text = 'lorem ipsum';
element.left = line;
element.right = new GrDiffLine(GrDiffLineType.BLANK);
element.showRevertButton = true;
await element.updateComplete;
const revertBtn = element.querySelector('.revert-btn');
assert.isNotNull(revertBtn);
});
test('does not render revert button when showRevertButton is false', async () => {
const line = new GrDiffLine(GrDiffLineType.REMOVE, 1, 0);
line.text = 'lorem ipsum';
element.left = line;
element.right = new GrDiffLine(GrDiffLineType.BLANK);
element.showRevertButton = false;
await element.updateComplete;
const revertBtn = element.querySelector('.revert-btn');
assert.isNull(revertBtn);
});
test('fires revert-delta event on button click', async () => {
const line = new GrDiffLine(GrDiffLineType.REMOVE, 1, 0);
line.text = 'lorem ipsum';
const group = new GrDiffGroup({
type: GrDiffGroupType.DELTA,
lines: [line],
});
element.left = line;
element.right = new GrDiffLine(GrDiffLineType.BLANK);
element.group = group;
element.showRevertButton = true;
await element.updateComplete;
let eventDetail: {group: GrDiffGroup; onComplete?: () => void} | undefined;
element.addEventListener('revert-delta', (e: CustomEvent) => {
eventDetail = e.detail;
});
const revertBtn = element.querySelector<HTMLButtonElement>('.revert-btn')!;
assert.isNotNull(revertBtn);
revertBtn.click();
await element.updateComplete;
assert.isDefined(eventDetail);
assert.equal(eventDetail?.group, group);
assert.isTrue(revertBtn.classList.contains('loading'));
assert.isNotNull(revertBtn.querySelector('.loadingSpin'));
assert.isNull(revertBtn.querySelector('gr-icon'));
eventDetail?.onComplete?.();
await element.updateComplete;
assert.isFalse(revertBtn.classList.contains('loading'));
assert.isNull(revertBtn.querySelector('.loadingSpin'));
assert.isNotNull(revertBtn.querySelector('gr-icon'));
});
test('updateLayers aborts when DOM element references change during await', async () => {
const line = new GrDiffLine(GrDiffLineType.BOTH, 1, 1);
line.text = 'lorem ipsum';
element.left = line;
element.right = line;
let annotateCalled = false;
element.layers = [
{
annotate() {
annotateCalled = true;
},
},
];
await element.updateComplete;
await new Promise(resolve => setTimeout(resolve, 0));
annotateCalled = false;
// Create a mock content element with a controllable updateComplete promise
let resolveUpdate: () => void;
const updatePromise = new Promise<boolean>(r => {
resolveUpdate = () => r(true);
});
const oldContentEl = {
updateComplete: updatePromise,
} as unknown as LitElement;
element.contentLeftRef = {value: oldContentEl};
const privElement = element as unknown as GrDiffRowPrivate;
privElement.layersApplied = false;
const updateLayersPromise = privElement.updateLayers(Side.LEFT);
// Swap the ref while updateLayers is awaiting updateComplete
element.contentLeftRef = {
value: document.createElement('div') as unknown as LitElement,
};
resolveUpdate!();
await updateLayersPromise;
assert.isFalse(annotateCalled);
assert.isFalse(privElement.layersApplied);
});
});