summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitrii Filippov <dmfilippov@google.com>2021-04-01 18:02:27 +0200
committerPaladox none <thomasmulhall410@yahoo.com>2021-04-17 14:22:40 +0000
commitb2d7c2aadb0cdcead1f0a5a097a07daddcb77592 (patch)
tree48efa606348cc463c5c535f178d37d2b37aab0cf
parent5c0c08071eeeb6bc229daa2c404ded9ed304ed45 (diff)
Do not reload page after clicking Cancel in apply-fix dialog
Change-Id: I5830caac655df9d3dc7058dc9674ba727685012b (cherry picked from commit 131bf7a080f0f2772a846591979b7d3dcab964bf)
-rw-r--r--polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts7
-rw-r--r--polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts14
-rw-r--r--polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.js272
-rw-r--r--polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts376
-rw-r--r--polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts5
-rw-r--r--polygerrit-ui/app/test/test-data-generators.ts10
-rw-r--r--polygerrit-ui/app/types/events.ts7
-rw-r--r--polygerrit-ui/app/utils/event-util.ts57
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>(