gitlab-org--gitlab-foss/spec/frontend/pipeline_wizard/components/commit_spec.js

283 lines
9.8 KiB
JavaScript
Raw Normal View History

import { GlButton, GlFormGroup } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { __, s__, sprintf } from '~/locale';
import { mountExtended } from 'jest/__helpers__/vue_test_utils_helper';
import CommitStep, { i18n } from '~/pipeline_wizard/components/commit.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import createCommitMutation from '~/pipeline_wizard/queries/create_commit.graphql';
import getFileMetadataQuery from '~/pipeline_wizard/queries/get_file_meta.graphql';
import RefSelector from '~/ref/components/ref_selector.vue';
import flushPromises from 'helpers/flush_promises';
import {
createCommitMutationErrorResult,
createCommitMutationResult,
fileQueryErrorResult,
fileQueryResult,
fileQueryEmptyResult,
} from '../mock/query_responses';
Vue.use(VueApollo);
const COMMIT_MESSAGE_ADD_FILE = s__('PipelineWizardDefaultCommitMessage|Add %{filename}');
const COMMIT_MESSAGE_UPDATE_FILE = s__('PipelineWizardDefaultCommitMessage|Update %{filename}');
describe('Pipeline Wizard - Commit Page', () => {
const createCommitMutationHandler = jest.fn();
const $toast = {
show: jest.fn(),
};
let wrapper;
const getMockApollo = (scenario = {}) => {
return createMockApollo([
[
createCommitMutation,
createCommitMutationHandler.mockResolvedValue(
scenario.commitHasError ? createCommitMutationErrorResult : createCommitMutationResult,
),
],
[
getFileMetadataQuery,
(vars) => {
if (scenario.fileResultByRef) return scenario.fileResultByRef[vars.ref];
if (scenario.hasError) return fileQueryErrorResult;
return scenario.fileExists ? fileQueryResult : fileQueryEmptyResult;
},
],
]);
};
const createComponent = (props = {}, mockApollo = getMockApollo()) => {
wrapper = mountExtended(CommitStep, {
apolloProvider: mockApollo,
propsData: {
projectPath: 'some/path',
defaultBranch: 'main',
filename: 'newFile.yml',
...props,
},
mocks: { $toast },
stubs: {
RefSelector: true,
GlFormGroup,
},
});
};
function getButtonWithLabel(label) {
return wrapper.findAllComponents(GlButton).filter((n) => n.text().match(label));
}
describe('ui setup', () => {
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('shows a commit message input with the correct label', () => {
expect(wrapper.findByTestId('commit_message').exists()).toBe(true);
expect(wrapper.find('label[for="commit_message"]').text()).toBe(i18n.commitMessageLabel);
});
it('shows a branch selector with the correct label', () => {
expect(wrapper.findByTestId('branch').exists()).toBe(true);
expect(wrapper.find('label[for="branch"]').text()).toBe(i18n.branchSelectorLabel);
});
it('shows a commit button', () => {
expect(getButtonWithLabel(i18n.commitButtonLabel).exists()).toBe(true);
});
it('shows a back button', () => {
expect(getButtonWithLabel(__('Back')).exists()).toBe(true);
});
it('does not show a next button', () => {
expect(getButtonWithLabel(__('Next')).exists()).toBe(false);
});
});
describe('loading the remote file', () => {
const projectPath = 'foo/bar';
const filename = 'foo.yml';
it('does not show a load error if call is successful', async () => {
createComponent({ projectPath, filename });
await flushPromises();
expect(wrapper.findByTestId('load-error').exists()).not.toBe(true);
});
it('shows a load error if call returns an unexpected error', async () => {
const branch = 'foo';
createComponent(
{ defaultBranch: branch, projectPath, filename },
createMockApollo([[getFileMetadataQuery, () => fileQueryErrorResult]]),
);
await flushPromises();
expect(wrapper.findByTestId('load-error').exists()).toBe(true);
expect(wrapper.findByTestId('load-error').text()).toBe(i18n.errors.loadError);
});
afterEach(() => {
wrapper.destroy();
});
});
describe('commit result handling', () => {
describe('successful commit', () => {
beforeEach(async () => {
createComponent();
await flushPromises();
await getButtonWithLabel(__('Commit')).trigger('click');
await flushPromises();
});
it('will not show an error', async () => {
expect(wrapper.findByTestId('commit-error').exists()).not.toBe(true);
});
it('will show a toast message', () => {
expect($toast.show).toHaveBeenCalledWith(
s__('PipelineWizard|The file has been committed.'),
);
});
it('emits a done event', () => {
expect(wrapper.emitted().done.length).toBe(1);
});
afterEach(() => {
wrapper.destroy();
jest.clearAllMocks();
});
});
describe('failed commit', () => {
beforeEach(async () => {
createComponent({}, getMockApollo({ commitHasError: true }));
await flushPromises();
await getButtonWithLabel(__('Commit')).trigger('click');
await flushPromises();
});
it('will show an error', async () => {
expect(wrapper.findByTestId('commit-error').exists()).toBe(true);
expect(wrapper.findByTestId('commit-error').text()).toBe(i18n.errors.commitError);
});
it('will not show a toast message', () => {
expect($toast.show).not.toHaveBeenCalledWith(i18n.commitSuccessMessage);
});
it('will not emit a done event', () => {
expect(wrapper.emitted().done?.length).toBeFalsy();
});
afterEach(() => {
wrapper.destroy();
jest.clearAllMocks();
});
});
});
describe('modelling different input combinations', () => {
const projectPath = 'some/path';
const defaultBranch = 'foo';
const fileContent = 'foo: bar';
describe.each`
filename | fileExistsOnDefaultBranch | fileExistsOnInputtedBranch | fileLoadError | commitMessageInputValue | branchInputValue | expectedCommitBranch | expectedCommitMessage | expectedAction
${'foo.yml'} | ${false} | ${undefined} | ${false} | ${'foo'} | ${undefined} | ${defaultBranch} | ${'foo'} | ${'CREATE'}
${'foo.yml'} | ${true} | ${undefined} | ${false} | ${'foo'} | ${undefined} | ${defaultBranch} | ${'foo'} | ${'UPDATE'}
${'foo.yml'} | ${false} | ${true} | ${false} | ${'foo'} | ${'dev'} | ${'dev'} | ${'foo'} | ${'UPDATE'}
${'foo.yml'} | ${false} | ${undefined} | ${false} | ${null} | ${undefined} | ${defaultBranch} | ${COMMIT_MESSAGE_ADD_FILE} | ${'CREATE'}
${'foo.yml'} | ${true} | ${undefined} | ${false} | ${null} | ${undefined} | ${defaultBranch} | ${COMMIT_MESSAGE_UPDATE_FILE} | ${'UPDATE'}
${'foo.yml'} | ${false} | ${true} | ${false} | ${null} | ${'dev'} | ${'dev'} | ${COMMIT_MESSAGE_UPDATE_FILE} | ${'UPDATE'}
`(
'Test with fileExistsOnDefaultBranch=$fileExistsOnDefaultBranch, fileExistsOnInputtedBranch=$fileExistsOnInputtedBranch, commitMessageInputValue=$commitMessageInputValue, branchInputValue=$branchInputValue, commitReturnsError=$commitReturnsError',
({
filename,
fileExistsOnDefaultBranch,
fileExistsOnInputtedBranch,
commitMessageInputValue,
branchInputValue,
expectedCommitBranch,
expectedCommitMessage,
expectedAction,
}) => {
let consoleSpy;
beforeAll(async () => {
createComponent(
{
filename,
defaultBranch,
projectPath,
fileContent,
},
getMockApollo({
fileResultByRef: {
[defaultBranch]: fileExistsOnDefaultBranch ? fileQueryResult : fileQueryEmptyResult,
[branchInputValue]: fileExistsOnInputtedBranch
? fileQueryResult
: fileQueryEmptyResult,
},
}),
);
await flushPromises();
consoleSpy = jest.spyOn(console, 'error');
await wrapper
.findByTestId('commit_message')
.get('textarea')
.setValue(commitMessageInputValue);
if (branchInputValue) {
await wrapper.getComponent(RefSelector).vm.$emit('input', branchInputValue);
}
await Vue.nextTick();
await flushPromises();
});
afterAll(() => {
wrapper.destroy();
});
it('sets up without error', async () => {
expect(consoleSpy).not.toHaveBeenCalled();
});
it('does not show a load error', async () => {
expect(wrapper.findByTestId('load-error').exists()).not.toBe(true);
});
it('sends the expected commit mutation', async () => {
await getButtonWithLabel(__('Commit')).trigger('click');
expect(createCommitMutationHandler).toHaveBeenCalledWith({
input: {
actions: [
{
action: expectedAction,
content: fileContent,
filePath: `/${filename}`,
},
],
branch: expectedCommitBranch,
message: sprintf(expectedCommitMessage, { filename }),
projectPath,
},
});
});
},
);
});
});