blob: 1d35430c0ec929bc7e45529d6b04c9b531b29b40 [file] [log] [blame]
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import * as sinon from 'sinon';
import '../../../test/common-test-setup';
import './gr-apply-fix-dialog';
import {
NavigationService,
navigationToken,
} from '../../core/gr-navigation/gr-navigation';
import {queryAndAssert, stubRestApi} from '../../../test/test-utils';
import {GrApplyFixDialog} from './gr-apply-fix-dialog';
import {PatchSetNum, PatchSetNumber} from '../../../types/common';
import {
createFixSuggestionInfo,
createParsedChange,
createRange,
createRevisions,
getCurrentRevision,
} from '../../../test/test-data-generators';
import {createDefaultDiffPrefs} from '../../../constants/constants';
import {OpenFixPreviewEventDetail} from '../../../types/events';
import {GrButton} from '../../shared/gr-button/gr-button';
import {assert, fixture, html} from '@open-wc/testing';
import {SinonStubbedMember} from 'sinon';
import {testResolver} from '../../../test/common-test-setup';
import {PROVIDED_FIX_ID} from '../../../utils/comment-util';
suite('gr-apply-fix-dialog tests', () => {
let element: GrApplyFixDialog;
let setUrlStub: SinonStubbedMember<NavigationService['setUrl']>;
const TWO_FIXES: OpenFixPreviewEventDetail = {
patchNum: 2 as PatchSetNum,
fixSuggestions: [
createFixSuggestionInfo('fix_1'),
createFixSuggestionInfo('fix_2'),
],
onCloseFixPreviewCallbacks: [],
};
const ONE_FIX: OpenFixPreviewEventDetail = {
patchNum: 2 as PatchSetNum,
fixSuggestions: [createFixSuggestionInfo('fix_1')],
onCloseFixPreviewCallbacks: [],
};
function getConfirmButton(): GrButton {
return queryAndAssert(
queryAndAssert(element, '#applyFixDialog'),
'#confirm'
);
}
async function open(detail: OpenFixPreviewEventDetail) {
element.open(
new CustomEvent<OpenFixPreviewEventDetail>('open-fix-preview', {
detail,
})
);
await element.updateComplete;
}
setup(async () => {
setUrlStub = sinon.stub(testResolver(navigationToken), 'setUrl');
element = await fixture<GrApplyFixDialog>(
html`<gr-apply-fix-dialog></gr-apply-fix-dialog>`
);
const change = {
...createParsedChange(),
revisions: createRevisions(2),
current_revision: getCurrentRevision(1),
};
element.changeNum = change._number;
element.patchNum = change.revisions[change.current_revision]._number;
element.latestPatchNum = change.revisions[change.current_revision]
._number as PatchSetNumber;
element.change = change;
element.diffPrefs = {
...createDefaultDiffPrefs(),
font_size: 12,
line_length: 100,
tab_size: 4,
};
await element.updateComplete;
});
suite('dialog open', () => {
setup(() => {
sinon.stub(element.applyFixModal!, 'showModal');
});
test('dialog opens fetch and sets previews', async () => {
await open(TWO_FIXES);
assert.equal(element.currentFix!.fix_id, 'fix_1');
assert.equal(element.currentPreviews.length, 0);
const button = getConfirmButton();
assert.isFalse(button.hasAttribute('disabled'));
assert.equal(button.getAttribute('title'), '');
});
test('tooltip is hidden if apply fix is loading', async () => {
element.isApplyFixLoading = true;
await open(TWO_FIXES);
const button = getConfirmButton();
assert.isTrue(button.hasAttribute('disabled'));
assert.equal(button.getAttribute('title'), 'Fix is still loading ...');
});
});
test('renders', async () => {
await open(TWO_FIXES);
assert.shadowDom.equal(
element,
/* HTML */ `
<dialog id="applyFixModal" tabindex="-1" open="">
<gr-dialog id="applyFixDialog" role="dialog" loading="">
<div slot="header">Fix fix_1</div>
<div slot="main"></div>
<div class="fix-picker" slot="footer">
<span>Suggested fix 1 of 2</span>
<gr-button
aria-disabled="true"
disabled=""
id="prevFix"
role="button"
tabindex="-1"
>
<gr-icon icon="chevron_left"></gr-icon>
</gr-button>
<gr-button
aria-disabled="false"
id="nextFix"
role="button"
tabindex="0"
>
<gr-icon icon="chevron_right"></gr-icon>
</gr-button>
</div>
</gr-dialog>
</dialog>
`,
{ignoreAttributes: ['style']}
);
});
test('next button state updated when suggestions changed', async () => {
await open(ONE_FIX);
await element.updateComplete;
assert.notOk(element.nextFix);
element.applyFixModal?.close();
await open(TWO_FIXES);
assert.ok(element.nextFix);
assert.notOk(element.nextFix.disabled);
});
test('select fix forward and back of multiple suggested fixes', async () => {
sinon.stub(element.applyFixModal!, 'showModal');
await open(TWO_FIXES);
element.onNextFixClick(new CustomEvent('click'));
assert.equal(element.currentFix!.fix_id, 'fix_2');
element.onPrevFixClick(new CustomEvent('click'));
assert.equal(element.currentFix!.fix_id, 'fix_1');
});
test('onCancel fires close with correct parameters', () => {
const closeFixPreviewEventSpy = sinon.spy();
element.onCloseFixPreviewCallbacks.push(closeFixPreviewEventSpy);
element.onCancel(new CustomEvent('cancel'));
sinon.assert.calledOnceWithExactly(closeFixPreviewEventSpy, false);
});
test('applies second fix with PROVIDED_FIX_ID', async () => {
const applyFixSuggestionStub = stubRestApi('applyFixSuggestion').returns(
Promise.resolve(new Response(null, {status: 200}))
);
const fixes: OpenFixPreviewEventDetail = {
patchNum: 2 as PatchSetNum,
fixSuggestions: [
{
...createFixSuggestionInfo('fix_1'),
fix_id: PROVIDED_FIX_ID,
replacements: [
{
path: 'file1.txt',
replacement: 'new content',
range: createRange(),
},
],
},
{
...createFixSuggestionInfo('fix_2'),
fix_id: PROVIDED_FIX_ID,
replacements: [
{
path: 'file2.txt',
replacement: 'other content',
range: createRange(),
},
],
},
],
onCloseFixPreviewCallbacks: [],
};
await open(fixes);
element.onNextFixClick(new CustomEvent('click'));
await element.updateComplete;
await element.handleApplyFix(new CustomEvent('confirm'));
sinon.assert.calledOnceWithExactly(
applyFixSuggestionStub,
element.change!._number,
2 as PatchSetNum,
[{path: 'file2.txt', replacement: 'other content', range: createRange()}],
element.latestPatchNum
);
assert.isTrue(setUrlStub.called);
assert.equal(
setUrlStub.lastCall.firstArg,
'/c/test-project/+/42/2..edit?forceReload=true'
);
});
});