Commit 46e62a8d authored by Frédéric Caplette's avatar Frédéric Caplette Committed by Nicolò Maria Mezzopera

Improve error messages experience in pipeline editor

parent d148084e
......@@ -247,10 +247,14 @@ export default {
await this.$apollo.queries.initialCiFileContent.refetch();
},
reportFailure(type, reasons = []) {
window.scrollTo({ top: 0, behavior: 'smooth' });
this.showFailure = true;
this.failureType = type;
this.failureReasons = reasons;
const isCurrentFailure = this.failureType === type && this.failureReasons[0] === reasons[0];
if (!isCurrentFailure) {
this.showFailure = true;
this.failureType = type;
this.failureReasons = reasons;
window.scrollTo({ top: 0, behavior: 'smooth' });
}
},
reportSuccess(type) {
window.scrollTo({ top: 0, behavior: 'smooth' });
......
......@@ -8,7 +8,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue';
import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue';
import PipelineEditorMessages from '~/pipeline_editor/components/ui/pipeline_editor_messages.vue';
import { COMMIT_SUCCESS, COMMIT_FAILURE } from '~/pipeline_editor/constants';
import { COMMIT_SUCCESS, COMMIT_FAILURE, LOAD_FAILURE_UNKNOWN } from '~/pipeline_editor/constants';
import getBlobContent from '~/pipeline_editor/graphql/queries/blob_content.graphql';
import getCiConfigData from '~/pipeline_editor/graphql/queries/ci_config.graphql';
import getTemplate from '~/pipeline_editor/graphql/queries/get_starter_template.query.graphql';
......@@ -412,6 +412,94 @@ describe('Pipeline editor app component', () => {
});
});
describe('when multiple errors occurs in a row', () => {
const updateFailureMessage = 'The GitLab CI configuration could not be updated.';
const unknownFailureMessage = 'The CI configuration was not loaded, please try again.';
const unknownReasons = ['Commit failed'];
const alertErrorMessage = `${updateFailureMessage} ${unknownReasons[0]}`;
const emitError = (type = COMMIT_FAILURE, reasons = unknownReasons) =>
findEditorHome().vm.$emit('showError', {
type,
reasons,
});
beforeEach(async () => {
mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
mockCiConfigData.mockResolvedValue(mockCiConfigQueryResponse);
mockLatestCommitShaQuery.mockResolvedValue(mockCommitShaResults);
window.scrollTo = jest.fn();
await createComponentWithApollo({ stubs: { PipelineEditorMessages } });
await emitError();
});
it('shows an error message for the first error', () => {
expect(findAlert().text()).toMatchInterpolatedText(alertErrorMessage);
});
it('scrolls to the top of the page to bring attention to the error message', () => {
expect(window.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' });
expect(window.scrollTo).toHaveBeenCalledTimes(1);
});
it('does not scroll to the top of the page if the same error occur multiple times in a row', async () => {
await emitError();
expect(window.scrollTo).toHaveBeenCalledTimes(1);
expect(findAlert().text()).toMatchInterpolatedText(alertErrorMessage);
});
it('scrolls to the top if the error is different', async () => {
await emitError(LOAD_FAILURE_UNKNOWN, []);
expect(findAlert().text()).toMatchInterpolatedText(unknownFailureMessage);
expect(window.scrollTo).toHaveBeenCalledTimes(2);
});
describe('when a user dismiss the alert', () => {
beforeEach(async () => {
await findAlert().vm.$emit('dismiss');
});
it('shows an error if the type is the same, but the reason is different', async () => {
const newReason = 'Something broke';
await emitError(COMMIT_FAILURE, [newReason]);
expect(window.scrollTo).toHaveBeenCalledTimes(2);
expect(findAlert().text()).toMatchInterpolatedText(`${updateFailureMessage} ${newReason}`);
});
it('does not show an error or scroll if a new error with the same type occurs', async () => {
await emitError();
expect(window.scrollTo).toHaveBeenCalledTimes(1);
expect(findAlert().exists()).toBe(false);
});
it('it shows an error and scroll when a new type is emitted', async () => {
await emitError(LOAD_FAILURE_UNKNOWN, []);
expect(window.scrollTo).toHaveBeenCalledTimes(2);
expect(findAlert().text()).toMatchInterpolatedText(unknownFailureMessage);
});
it('it shows an error and scroll if a previously shown type happen again', async () => {
await emitError(LOAD_FAILURE_UNKNOWN, []);
expect(window.scrollTo).toHaveBeenCalledTimes(2);
expect(findAlert().text()).toMatchInterpolatedText(unknownFailureMessage);
await emitError();
expect(window.scrollTo).toHaveBeenCalledTimes(3);
expect(findAlert().text()).toMatchInterpolatedText(alertErrorMessage);
});
});
});
describe('when add_new_config_file query param is present', () => {
const originalLocation = window.location.href;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment