diff options
author | Dmitrii Filippov <dmfilippov@google.com> | 2021-04-01 18:02:27 +0200 |
---|---|---|
committer | Paladox none <thomasmulhall410@yahoo.com> | 2021-04-17 14:22:40 +0000 |
commit | b2d7c2aadb0cdcead1f0a5a097a07daddcb77592 (patch) | |
tree | 48efa606348cc463c5c535f178d37d2b37aab0cf | |
parent | 5c0c08071eeeb6bc229daa2c404ded9ed304ed45 (diff) |
Do not reload page after clicking Cancel in apply-fix dialog
Change-Id: I5830caac655df9d3dc7058dc9674ba727685012b
(cherry picked from commit 131bf7a080f0f2772a846591979b7d3dcab964bf)
8 files changed, 449 insertions, 299 deletions
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts index 155c77bce1..eadcc3054e 100644 --- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts +++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts @@ -155,6 +155,7 @@ import { ThreadListModifiedEvent, TabState, EventType, + CloseFixPreviewEvent, } from '../../../types/events'; import {GrButton} from '../../shared/gr-button/gr-button'; import {GrMessagesList} from '../gr-messages-list/gr-messages-list'; @@ -676,7 +677,7 @@ export class GrChangeView extends KeyboardShortcutMixin(PolymerElement) { this._handleCommitMessageCancel() ); this.addEventListener('open-fix-preview', e => this._onOpenFixPreview(e)); - this.addEventListener('close-fix-preview', () => this._onCloseFixPreview()); + this.addEventListener('close-fix-preview', e => this._onCloseFixPreview(e)); window.addEventListener('scroll', this.handleScroll); document.addEventListener('visibilitychange', this.handleVisibilityChange); @@ -742,8 +743,8 @@ export class GrChangeView extends KeyboardShortcutMixin(PolymerElement) { this.$.applyFixDialog.open(e); } - _onCloseFixPreview() { - this._reload(); + _onCloseFixPreview(e: CloseFixPreviewEvent) { + if (e.detail.fixApplied) this._reload(); } _handleToggleDiffMode(e: CustomKeyboardEvent) { diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts index 716d142fb2..0bf9f1c770 100644 --- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts +++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts @@ -37,12 +37,14 @@ import {GrOverlay} from '../../shared/gr-overlay/gr-overlay'; import {isRobot} from '../../../utils/comment-util'; import {OpenFixPreviewEvent} from '../../../types/events'; import {appContext} from '../../../services/app-context'; -import {fireEvent} from '../../../utils/event-util'; +import {fireCloseFixPreview, fireEvent} from '../../../utils/event-util'; import {ParsedChangeInfo} from '../../../types/types'; +import {GrButton} from '../../shared/gr-button/gr-button'; export interface GrApplyFixDialog { $: { applyFixOverlay: GrOverlay; + nextFix: GrButton; }; } @@ -168,7 +170,7 @@ export class GrApplyFixDialog extends PolymerElement { } }) .catch(err => { - this._close(); + this._close(false); throw err; }); } @@ -186,7 +188,7 @@ export class GrApplyFixDialog extends PolymerElement { if (e) { e.stopPropagation(); } - this._close(); + this._close(false); } addOneTo(_selectedFixIdx: number) { @@ -225,12 +227,12 @@ export class GrApplyFixDialog extends PolymerElement { return _selectedFixIdx === fixSuggestions.length - 1; } - _close() { + _close(fixApplied: boolean) { this._currentFix = undefined; this._currentPreviews = []; this._isApplyFixLoading = false; - fireEvent(this, 'close-fix-preview'); + fireCloseFixPreview(this, fixApplied); this.$.applyFixOverlay.close(); } @@ -282,7 +284,7 @@ export class GrApplyFixDialog extends PolymerElement { EditPatchSetNum, patchNum as BasePatchSetNum ); - this._close(); + this._close(true); } this._isApplyFixLoading = false; }); diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.js b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.js deleted file mode 100644 index d78961cfa0..0000000000 --- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.js +++ /dev/null @@ -1,272 +0,0 @@ -/** - * @license - * Copyright (C) 2019 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. - */ - -import '../../../test/common-test-setup-karma.js'; -import './gr-apply-fix-dialog.js'; -import {GerritNav} from '../../core/gr-navigation/gr-navigation.js'; -import {stubRestApi} from '../../../test/test-utils.js'; - -const basicFixture = fixtureFromElement('gr-apply-fix-dialog'); - -suite('gr-apply-fix-dialog tests', () => { - let element; - - const ROBOT_COMMENT_WITH_TWO_FIXES = { - robot_id: 'robot_1', - fix_suggestions: [{fix_id: 'fix_1'}, {fix_id: 'fix_2'}], - }; - - const ROBOT_COMMENT_WITH_ONE_FIX = { - robot_id: 'robot_1', - fix_suggestions: [{fix_id: 'fix_1'}], - }; - - setup(() => { - element = basicFixture.instantiate(); - element.changeNum = '1'; - element._patchNum = 2; - element.change = { - _number: '1', - project: 'project', - revisions: { - abcd: {_number: 1}, - efgh: {_number: 2}, - }, - current_revision: 'efgh', - }; - element.prefs = { - font_size: 12, - line_length: 100, - tab_size: 4, - }; - }); - - suite('dialog open', () => { - setup(() => { - stubRestApi('getRobotCommentFixPreview') - .returns(Promise.resolve({ - f1: { - meta_a: {}, - meta_b: {}, - content: [ - { - ab: ['loqlwkqll'], - }, - { - b: ['qwqqsqw'], - }, - { - ab: ['qwqqsqw', 'qweqeqweqeq', 'qweqweq'], - }, - ], - }, - f2: { - meta_a: {}, - meta_b: {}, - content: [ - { - ab: ['eqweqweqwex'], - }, - { - b: ['zassdasd'], - }, - { - ab: ['zassdasd', 'dasdasda', 'asdasdad'], - }, - ], - }, - })); - sinon.stub(element.$.applyFixOverlay, 'open') - .returns(Promise.resolve()); - }); - - test('dialog opens fetch and sets previews', done => { - element.open({detail: {patchNum: 2, - comment: ROBOT_COMMENT_WITH_TWO_FIXES}}) - .then(() => { - assert.equal(element._currentFix.fix_id, 'fix_1'); - assert.equal(element._currentPreviews.length, 2); - assert.equal(element._robotId, 'robot_1'); - const button = element.shadowRoot.querySelector( - '#applyFixDialog').shadowRoot.querySelector('#confirm'); - assert.isFalse(button.hasAttribute('disabled')); - assert.equal(button.getAttribute('title'), ''); - done(); - }); - }); - - test('tooltip is hidden if apply fix is loading', done => { - element.open({detail: {patchNum: 2, - comment: ROBOT_COMMENT_WITH_TWO_FIXES}}) - .then(() => { - element._isApplyFixLoading = true; - const button = element.shadowRoot.querySelector( - '#applyFixDialog').shadowRoot.querySelector('#confirm'); - assert.isTrue(button.hasAttribute('disabled')); - assert.equal(button.getAttribute('title'), ''); - done(); - }); - }); - - test('apply fix button is disabled on older patchset', done => { - element.change = { - _number: '1', - project: 'project', - revisions: { - abcd: {_number: 1}, - efgh: {_number: 2}, - }, - current_revision: 'abcd', - }; - element.open({detail: {patchNum: 2, - comment: ROBOT_COMMENT_WITH_ONE_FIX}}) - .then(() => { - flush(() => { - const button = element.shadowRoot.querySelector( - '#applyFixDialog').shadowRoot.querySelector('#confirm'); - assert.isTrue(button.hasAttribute('disabled')); - assert.equal(button.getAttribute('title'), - 'Fix can only be applied to the latest patchset'); - done(); - }); - }); - }); - }); - - test('next button state updated when suggestions changed', done => { - stubRestApi('getRobotCommentFixPreview').returns(Promise.resolve({})); - sinon.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve()); - - element.open({detail: {patchNum: 2, comment: ROBOT_COMMENT_WITH_ONE_FIX}}) - .then(() => assert.isTrue(element.$.nextFix.disabled)) - .then(() => - element.open({detail: {patchNum: 2, - comment: ROBOT_COMMENT_WITH_TWO_FIXES}})) - .then(() => { - assert.isFalse(element.$.nextFix.disabled); - done(); - }); - }); - - test('preview endpoint throws error should reset dialog', async () => { - stubRestApi('getRobotCommentFixPreview').returns( - Promise.reject(new Error('backend error'))); - element.open({detail: {patchNum: 2, - comment: ROBOT_COMMENT_WITH_TWO_FIXES}}); - await flush(); - assert.equal(element._currentFix, undefined); - }); - - test('apply fix button should call apply ' + - 'and navigate to change view', () => { - const stub = stubRestApi('applyFixSuggestion').returns( - Promise.resolve({ok: true})); - sinon.stub(GerritNav, 'navigateToChange'); - element._currentFix = {fix_id: '123'}; - - return element._handleApplyFix().then(() => { - assert.isTrue(stub.calledWithExactly('1', 2, '123')); - assert.isTrue(GerritNav.navigateToChange.calledWithExactly({ - _number: '1', - project: 'project', - revisions: { - abcd: {_number: 1}, - efgh: {_number: 2}, - }, - current_revision: 'efgh', - }, 'edit', 2)); - - // reset gr-apply-fix-dialog and close - assert.equal(element._currentFix, undefined); - assert.equal(element._currentPreviews.length, 0); - }); - }); - - test('should not navigate to change view if incorect reponse', done => { - const stub = stubRestApi('applyFixSuggestion').returns(Promise.resolve({})); - sinon.stub(GerritNav, 'navigateToChange'); - element._currentFix = {fix_id: '123'}; - - element._handleApplyFix().then(() => { - assert.isTrue(stub.calledWithExactly('1', 2, '123')); - assert.isTrue(GerritNav.navigateToChange.notCalled); - - assert.equal(element._isApplyFixLoading, false); - done(); - }); - }); - - test('select fix forward and back of multiple suggested fixes', done => { - stubRestApi('getRobotCommentFixPreview') - .returns(Promise.resolve({ - f1: { - meta_a: {}, - meta_b: {}, - content: [ - { - ab: ['loqlwkqll'], - }, - { - b: ['qwqqsqw'], - }, - { - ab: ['qwqqsqw', 'qweqeqweqeq', 'qweqweq'], - }, - ], - }, - f2: { - meta_a: {}, - meta_b: {}, - content: [ - { - ab: ['eqweqweqwex'], - }, - { - b: ['zassdasd'], - }, - { - ab: ['zassdasd', 'dasdasda', 'asdasdad'], - }, - ], - }, - })); - sinon.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve()); - - element.open({detail: {patchNum: 2, comment: ROBOT_COMMENT_WITH_TWO_FIXES}}) - .then(() => { - element._onNextFixClick(); - assert.equal(element._currentFix.fix_id, 'fix_2'); - element._onPrevFixClick(); - assert.equal(element._currentFix.fix_id, 'fix_1'); - done(); - }); - }); - - test('server-error should throw for failed apply call', async () => { - stubRestApi('applyFixSuggestion').returns( - Promise.reject(new Error('backend error'))); - sinon.stub(GerritNav, 'navigateToChange'); - element._currentFix = {fix_id: '123'}; - let expectedError; - await element._handleApplyFix().catch(e => { - expectedError = e; - }); - assert.isOk(expectedError); - assert.isFalse(GerritNav.navigateToChange.called); - }); -}); - diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts new file mode 100644 index 0000000000..d3d7615834 --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts @@ -0,0 +1,376 @@ +/** + * @license + * Copyright (C) 2019 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. + */ + +import '../../../test/common-test-setup-karma'; +import './gr-apply-fix-dialog'; +import {GerritNav} from '../../core/gr-navigation/gr-navigation'; +import {queryAndAssert, stubRestApi} from '../../../test/test-utils'; +import {GrApplyFixDialog} from './gr-apply-fix-dialog'; +import { + BasePatchSetNum, + EditPatchSetNum, + PatchSetNum, + RobotId, + RobotRunId, + Timestamp, + UrlEncodedCommentId, +} from '../../../types/common'; +import { + createFixSuggestionInfo, + createParsedChange, + createRevisions, + getCurrentRevision, +} from '../../../test/test-data-generators'; +import {createDefaultDiffPrefs} from '../../../constants/constants'; +import {DiffInfo} from '../../../types/diff'; +import {UIRobot} from '../../../utils/comment-util'; +import { + CloseFixPreviewEventDetail, + EventType, + OpenFixPreviewEventDetail, +} from '../../../types/events'; +import {GrButton} from '../../shared/gr-button/gr-button'; + +const basicFixture = fixtureFromElement('gr-apply-fix-dialog'); + +suite('gr-apply-fix-dialog tests', () => { + let element: GrApplyFixDialog; + + const ROBOT_COMMENT_WITH_TWO_FIXES: UIRobot = { + id: '1' as UrlEncodedCommentId, + updated: '2018-02-08 18:49:18.000000000' as Timestamp, + robot_id: 'robot_1' as RobotId, + robot_run_id: 'run_1' as RobotRunId, + properties: {}, + fix_suggestions: [ + createFixSuggestionInfo('fix_1'), + createFixSuggestionInfo('fix_2'), + ], + }; + + const ROBOT_COMMENT_WITH_ONE_FIX: UIRobot = { + id: '2' as UrlEncodedCommentId, + updated: '2018-02-08 18:49:18.000000000' as Timestamp, + robot_id: 'robot_1' as RobotId, + robot_run_id: 'run_1' as RobotRunId, + properties: {}, + fix_suggestions: [createFixSuggestionInfo('fix_1')], + }; + + function getConfirmButton(): GrButton { + return queryAndAssert( + queryAndAssert(element, '#applyFixDialog'), + '#confirm' + ); + } + + setup(() => { + element = basicFixture.instantiate(); + const change = { + ...createParsedChange(), + revisions: createRevisions(2), + current_revision: getCurrentRevision(1), + }; + element.changeNum = change._number; + element._patchNum = change.revisions[change.current_revision]._number; + element.change = change; + element.prefs = { + ...createDefaultDiffPrefs(), + font_size: 12, + line_length: 100, + tab_size: 4, + }; + }); + + suite('dialog open', () => { + setup(() => { + const diffInfo1: DiffInfo = { + meta_a: { + name: 'f1', + content_type: 'text', + lines: 10, + }, + meta_b: { + name: 'f1', + content_type: 'text', + lines: 12, + }, + content: [ + { + ab: ['loqlwkqll'], + }, + { + b: ['qwqqsqw'], + }, + { + ab: ['qwqqsqw', 'qweqeqweqeq', 'qweqweq'], + }, + ], + change_type: 'MODIFIED', + intraline_status: 'OK', + }; + + const diffInfo2: DiffInfo = { + meta_a: { + name: 'f2', + content_type: 'text', + lines: 10, + }, + meta_b: { + name: 'f2', + content_type: 'text', + lines: 12, + }, + content: [ + { + ab: ['eqweqweqwex'], + }, + { + b: ['zassdasd'], + }, + { + ab: ['zassdasd', 'dasdasda', 'asdasdad'], + }, + ], + change_type: 'MODIFIED', + intraline_status: 'OK', + }; + + stubRestApi('getRobotCommentFixPreview').returns( + Promise.resolve({ + f1: diffInfo1, + f2: diffInfo2, + }) + ); + sinon.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve()); + }); + + test('dialog opens fetch and sets previews', async () => { + await element.open( + new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, { + detail: { + patchNum: 2 as PatchSetNum, + comment: ROBOT_COMMENT_WITH_TWO_FIXES, + }, + }) + ); + assert.equal(element._currentFix!.fix_id, 'fix_1'); + assert.equal(element._currentPreviews.length, 2); + assert.equal(element._robotId, 'robot_1' as RobotId); + const button = getConfirmButton(); + assert.isFalse(button.hasAttribute('disabled')); + assert.equal(button.getAttribute('title'), ''); + }); + + test('tooltip is hidden if apply fix is loading', async () => { + await element.open( + new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, { + detail: { + patchNum: 2 as PatchSetNum, + comment: ROBOT_COMMENT_WITH_TWO_FIXES, + }, + }) + ); + element._isApplyFixLoading = true; + const button = getConfirmButton(); + assert.isTrue(button.hasAttribute('disabled')); + assert.equal(button.getAttribute('title'), ''); + }); + + test('apply fix button is disabled on older patchset', async () => { + element.change = element.change = { + ...createParsedChange(), + revisions: createRevisions(2), + current_revision: getCurrentRevision(0), + }; + await element.open( + new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, { + detail: { + patchNum: 2 as PatchSetNum, + comment: ROBOT_COMMENT_WITH_ONE_FIX, + }, + }) + ); + await flush(); + const button = getConfirmButton(); + assert.isTrue(button.hasAttribute('disabled')); + assert.equal( + button.getAttribute('title'), + 'Fix can only be applied to the latest patchset' + ); + }); + }); + + test('next button state updated when suggestions changed', async () => { + stubRestApi('getRobotCommentFixPreview').returns(Promise.resolve({})); + sinon.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve()); + + await element.open( + new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, { + detail: { + patchNum: 2 as PatchSetNum, + comment: ROBOT_COMMENT_WITH_ONE_FIX, + }, + }) + ); + assert.isTrue(element.$.nextFix.disabled); + await element.open( + new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, { + detail: { + patchNum: 2 as PatchSetNum, + comment: ROBOT_COMMENT_WITH_TWO_FIXES, + }, + }) + ); + assert.isFalse(element.$.nextFix.disabled); + }); + + test('preview endpoint throws error should reset dialog', async () => { + stubRestApi('getRobotCommentFixPreview').returns( + Promise.reject(new Error('backend error')) + ); + element.open( + new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, { + detail: { + patchNum: 2 as PatchSetNum, + comment: ROBOT_COMMENT_WITH_TWO_FIXES, + }, + }) + ); + await flush(); + assert.equal(element._currentFix, undefined); + }); + + test('apply fix button should call apply, navigate to change view and fire close', async () => { + const applyFixSuggestionStub = stubRestApi('applyFixSuggestion').returns( + Promise.resolve(new Response(null, {status: 200})) + ); + const navigateToChangeStub = sinon.stub(GerritNav, 'navigateToChange'); + element._currentFix = createFixSuggestionInfo('123'); + + const closeFixPreviewEventSpy = sinon.spy(); + // Element is recreated after each test, removeEventListener isn't required + element.addEventListener( + EventType.CLOSE_FIX_PREVIEW, + closeFixPreviewEventSpy + ); + await element._handleApplyFix(new CustomEvent('confirm')); + + sinon.assert.calledOnceWithExactly( + applyFixSuggestionStub, + element.change!._number, + 2 as PatchSetNum, + '123' + ); + sinon.assert.calledWithExactly( + navigateToChangeStub, + element.change!, + EditPatchSetNum, + element.change!.revisions[2]._number as BasePatchSetNum + ); + + sinon.assert.calledOnceWithExactly( + closeFixPreviewEventSpy, + new CustomEvent<CloseFixPreviewEventDetail>(EventType.CLOSE_FIX_PREVIEW, { + detail: { + fixApplied: true, + }, + }) + ); + + // reset gr-apply-fix-dialog and close + assert.equal(element._currentFix, undefined); + assert.equal(element._currentPreviews.length, 0); + }); + + test('should not navigate to change view if incorect reponse', async () => { + const applyFixSuggestionStub = stubRestApi('applyFixSuggestion').returns( + Promise.resolve(new Response(null, {status: 500})) + ); + const navigateToChangeStub = sinon.stub(GerritNav, 'navigateToChange'); + element._currentFix = createFixSuggestionInfo('fix_123'); + + await element._handleApplyFix(new CustomEvent('confirm')); + sinon.assert.calledWithExactly( + applyFixSuggestionStub, + element.change!._number, + 2 as PatchSetNum, + 'fix_123' + ); + assert.isTrue(navigateToChangeStub.notCalled); + + assert.equal(element._isApplyFixLoading, false); + }); + + test('select fix forward and back of multiple suggested fixes', async () => { + sinon.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve()); + + await element.open( + new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, { + detail: { + patchNum: 2 as PatchSetNum, + comment: ROBOT_COMMENT_WITH_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('server-error should throw for failed apply call', async () => { + stubRestApi('applyFixSuggestion').returns( + Promise.reject(new Error('backend error')) + ); + const navigateToChangeStub = sinon.stub(GerritNav, 'navigateToChange'); + element._currentFix = createFixSuggestionInfo('fix_123'); + + const closeFixPreviewEventSpy = sinon.spy(); + // Element is recreated after each test, removeEventListener isn't required + element.addEventListener( + EventType.CLOSE_FIX_PREVIEW, + closeFixPreviewEventSpy + ); + + let expectedError; + await element._handleApplyFix(new CustomEvent('click')).catch(e => { + expectedError = e; + }); + assert.isOk(expectedError); + assert.isFalse(navigateToChangeStub.called); + sinon.assert.notCalled(closeFixPreviewEventSpy); + }); + + test('onCancel fires close with correct parameters', () => { + const closeFixPreviewEventSpy = sinon.spy(); + // Element is recreated after each test, removeEventListener isn't required + element.addEventListener( + EventType.CLOSE_FIX_PREVIEW, + closeFixPreviewEventSpy + ); + element.onCancel(new CustomEvent('cancel')); + sinon.assert.calledOnceWithExactly( + closeFixPreviewEventSpy, + new CustomEvent<CloseFixPreviewEventDetail>(EventType.CLOSE_FIX_PREVIEW, { + detail: { + fixApplied: false, + }, + }) + ); + }); +}); diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts index 24a7d7862b..874f572aba 100644 --- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts +++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts @@ -72,6 +72,7 @@ export interface DiffContextExpandedEventDetail { declare global { interface HTMLElementEventMap { 'diff-context-expanded': CustomEvent<DiffContextExpandedEventDetail>; + 'content-load-needed': CustomEvent<ContentLoadNeededEventDetail>; } } @@ -511,14 +512,14 @@ export abstract class GrDiffBuilder { end_line: lastRange.right.end_line, }, }; - fire<ContentLoadNeededEventDetail>(button, 'content-load-needed', { + fire(button, 'content-load-needed', { lineRange, }); }); } else { button.addEventListener('click', e => { e.stopPropagation(); - fire<DiffContextExpandedEventDetail>(button, 'diff-context-expanded', { + fire(button, 'diff-context-expanded', { groups, section, numLines, diff --git a/polygerrit-ui/app/test/test-data-generators.ts b/polygerrit-ui/app/test/test-data-generators.ts index 3bfe743fbf..778e58da7d 100644 --- a/polygerrit-ui/app/test/test-data-generators.ts +++ b/polygerrit-ui/app/test/test-data-generators.ts @@ -65,6 +65,8 @@ import { RelatedChangeAndCommitInfo, SubmittedTogetherInfo, RelatedChangesInfo, + FixSuggestionInfo, + FixId, } from '../types/common'; import { AccountsVisibility, @@ -614,3 +616,11 @@ export function createSubmittedTogetherInfo(): SubmittedTogetherInfo { non_visible_changes: 0, }; } + +export function createFixSuggestionInfo(fixId = 'fix_1'): FixSuggestionInfo { + return { + fix_id: fixId as FixId, + description: `Fix ${fixId}`, + replacements: [], + }; +} diff --git a/polygerrit-ui/app/types/events.ts b/polygerrit-ui/app/types/events.ts index 11155c1463..7bde788b36 100644 --- a/polygerrit-ui/app/types/events.ts +++ b/polygerrit-ui/app/types/events.ts @@ -32,6 +32,7 @@ export enum EventType { MOVED_LINK_CLICKED = 'moved-link-clicked', NETWORK_ERROR = 'network-error', OPEN_FIX_PREVIEW = 'open-fix-preview', + CLOSE_FIX_PREVIEW = 'close-fix-preview', PAGE_ERROR = 'page-error', RELOAD = 'reload', REPLY = 'reply', @@ -54,6 +55,7 @@ declare global { 'iron-announce': IronAnnounceEvent; 'moved-link-clicked': MovedLinkClickedEvent; 'open-fix-preview': OpenFixPreviewEvent; + 'close-fix-preview': CloseFixPreviewEvent; /* prettier-ignore */ 'reload': ReloadEvent; /* prettier-ignore */ @@ -133,6 +135,11 @@ export interface OpenFixPreviewEventDetail { } export type OpenFixPreviewEvent = CustomEvent<OpenFixPreviewEventDetail>; +export interface CloseFixPreviewEventDetail { + fixApplied: boolean; +} +export type CloseFixPreviewEvent = CustomEvent<CloseFixPreviewEventDetail>; + export interface PageErrorEventDetail { response?: Response; } diff --git a/polygerrit-ui/app/utils/event-util.ts b/polygerrit-ui/app/utils/event-util.ts index 080955ff2f..da075f17c1 100644 --- a/polygerrit-ui/app/utils/event-util.ts +++ b/polygerrit-ui/app/utils/event-util.ts @@ -20,15 +20,8 @@ import {FetchRequest} from '../types/types'; import { DialogChangeEventDetail, EventType, - IronAnnounceEventDetail, - NetworkErrorEventDetail, - PageErrorEventDetail, - ServerErrorEventDetail, - ShowAlertEventDetail, SwitchTabEventDetail, TabState, - ThreadListModifiedDetail, - TitleChangeEventDetail, } from '../types/events'; export function fireEvent(target: EventTarget, type: string) { @@ -40,6 +33,34 @@ export function fireEvent(target: EventTarget, type: string) { ); } +type HTMLElementEventDetailType< + K extends keyof HTMLElementEventMap +> = HTMLElementEventMap[K] extends CustomEvent<infer DT> + ? unknown extends DT + ? never + : DT + : never; + +type DocumentEventDetailType< + K extends keyof DocumentEventMap +> = DocumentEventMap[K] extends CustomEvent<infer DT> + ? unknown extends DT + ? never + : DT + : never; + +export function fire<K extends keyof DocumentEventMap>( + target: Document, + type: K, + detail: DocumentEventDetailType<K> +): void; + +export function fire<K extends keyof HTMLElementEventMap>( + target: EventTarget, + type: K, + detail: HTMLElementEventDetailType<K> +): void; + export function fire<T>(target: EventTarget, type: string, detail: T) { target.dispatchEvent( new CustomEvent<T>(type, { @@ -51,27 +72,27 @@ export function fire<T>(target: EventTarget, type: string, detail: T) { } export function fireAlert(target: EventTarget, message: string) { - fire<ShowAlertEventDetail>(target, EventType.SHOW_ALERT, {message}); + fire(target, EventType.SHOW_ALERT, {message}); } export function firePageError(response?: Response | null) { if (response === null) response = undefined; - fire<PageErrorEventDetail>(document, EventType.PAGE_ERROR, {response}); + fire(document, EventType.PAGE_ERROR, {response}); } export function fireServerError(response: Response, request?: FetchRequest) { - fire<ServerErrorEventDetail>(document, EventType.SERVER_ERROR, { + fire(document, EventType.SERVER_ERROR, { response, request, }); } export function fireNetworkError(error: Error) { - fire<NetworkErrorEventDetail>(document, EventType.NETWORK_ERROR, {error}); + fire(document, EventType.NETWORK_ERROR, {error}); } export function fireTitleChange(target: EventTarget, title: string) { - fire<TitleChangeEventDetail>(target, EventType.TITLE_CHANGE, {title}); + fire(target, EventType.TITLE_CHANGE, {title}); } // TODO(milutin) - remove once new gr-dialog will do it out of the box @@ -80,11 +101,11 @@ export function fireDialogChange( target: EventTarget, detail: DialogChangeEventDetail ) { - fire<DialogChangeEventDetail>(target, EventType.DIALOG_CHANGE, detail); + fire(target, EventType.DIALOG_CHANGE, detail); } export function fireIronAnnounce(target: EventTarget, text: string) { - fire<IronAnnounceEventDetail>(target, EventType.IRON_ANNOUNCE, {text}); + fire(target, EventType.IRON_ANNOUNCE, {text}); } export function fireThreadListModifiedEvent( @@ -92,7 +113,7 @@ export function fireThreadListModifiedEvent( rootId: UrlEncodedCommentId, path: string ) { - fire<ThreadListModifiedDetail>(target, EventType.THREAD_LIST_MODIFIED, { + fire(target, EventType.THREAD_LIST_MODIFIED, { rootId, path, }); @@ -105,7 +126,11 @@ export function fireShowPrimaryTab( tabState?: TabState ) { const detail: SwitchTabEventDetail = {tab, scrollIntoView, tabState}; - fire<SwitchTabEventDetail>(target, EventType.SHOW_PRIMARY_TAB, detail); + fire(target, EventType.SHOW_PRIMARY_TAB, detail); +} + +export function fireCloseFixPreview(target: EventTarget, fixApplied: boolean) { + fire(target, EventType.CLOSE_FIX_PREVIEW, {fixApplied}); } export function waitForEventOnce<K extends keyof HTMLElementEventMap>( |