| /** | |
| * @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); | |
| }); | |
| }); |