gitlab-ce/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js

238 lines
7.4 KiB
JavaScript

import { GlAlert, GlFormInput, GlForm, GlLink } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue';
import issueSetTitleMutation from '~/boards/graphql/issue_set_title.mutation.graphql';
import * as cacheUpdates from '~/boards/graphql/cache_updates';
import updateEpicTitleMutation from '~/sidebar/queries/update_epic_title.mutation.graphql';
import { updateIssueTitleResponse, updateEpicTitleResponse } from '../../mock_data';
Vue.use(VueApollo);
const TEST_TITLE = 'New item title';
const TEST_ISSUE_A = {
id: 'gid://gitlab/Issue/1',
iid: 8,
title: 'Issue 1',
referencePath: 'h/b#1',
webUrl: 'webUrl',
};
const TEST_ISSUE_B = {
id: 'gid://gitlab/Issue/2',
iid: 9,
title: 'Issue 2',
referencePath: 'h/b#2',
webUrl: 'webUrl',
};
describe('BoardSidebarTitle', () => {
let wrapper;
let mockApollo;
const issueSetTitleMutationHandlerSuccess = jest.fn().mockResolvedValue(updateIssueTitleResponse);
const issueSetTitleMutationHandlerFailure = jest.fn().mockRejectedValue(new Error('error'));
const updateEpicTitleMutationHandlerSuccess = jest
.fn()
.mockResolvedValue(updateEpicTitleResponse);
beforeEach(() => {
cacheUpdates.setError = jest.fn();
});
afterEach(() => {
localStorage.clear();
});
const createWrapper = ({
item = TEST_ISSUE_A,
provide = {},
issueSetTitleMutationHandler = issueSetTitleMutationHandlerSuccess,
} = {}) => {
mockApollo = createMockApollo([
[issueSetTitleMutation, issueSetTitleMutationHandler],
[updateEpicTitleMutation, updateEpicTitleMutationHandlerSuccess],
]);
wrapper = shallowMountExtended(BoardSidebarTitle, {
apolloProvider: mockApollo,
provide: {
canUpdate: true,
fullPath: 'gitlab-org',
issuableType: 'issue',
isEpicBoard: false,
...provide,
},
propsData: {
activeItem: item,
},
stubs: {
'board-editable-item': BoardEditableItem,
},
});
};
const findForm = () => wrapper.findComponent(GlForm);
const findAlert = () => wrapper.findComponent(GlAlert);
const findFormInput = () => wrapper.findComponent(GlFormInput);
const findGlLink = () => wrapper.findComponent(GlLink);
const findEditableItem = () => wrapper.findComponent(BoardEditableItem);
const findCancelButton = () => wrapper.findByTestId('cancel-button');
const findTitle = () => wrapper.findByTestId('item-title');
const findCollapsed = () => wrapper.findByTestId('collapsed-content');
it('renders title and reference', () => {
createWrapper();
expect(findTitle().text()).toContain(TEST_ISSUE_A.title);
expect(findCollapsed().text()).toContain(TEST_ISSUE_A.referencePath);
});
it('does not render alert', () => {
createWrapper();
expect(findAlert().exists()).toBe(false);
});
it('links title to the corresponding issue', () => {
createWrapper();
expect(findGlLink().attributes('href')).toBe('webUrl');
});
describe('when new title is submitted', () => {
beforeEach(async () => {
createWrapper();
findFormInput().vm.$emit('input', TEST_TITLE);
findForm().vm.$emit('submit', { preventDefault: () => {} });
await nextTick();
});
it('collapses sidebar and renders new title', async () => {
await waitForPromises();
expect(findCollapsed().isVisible()).toBe(true);
});
it('renders correct title', async () => {
createWrapper({ item: { ...TEST_ISSUE_A, title: TEST_TITLE } });
await waitForPromises();
expect(findTitle().text()).toContain(TEST_TITLE);
});
});
it.each`
issuableType | isEpicBoard | queryHandler | notCalledHandler
${'issue'} | ${false} | ${issueSetTitleMutationHandlerSuccess} | ${updateEpicTitleMutationHandlerSuccess}
${'epic'} | ${true} | ${updateEpicTitleMutationHandlerSuccess} | ${issueSetTitleMutationHandlerSuccess}
`(
'updates $issuableType title',
async ({ issuableType, isEpicBoard, queryHandler, notCalledHandler }) => {
createWrapper({
provide: {
issuableType,
isEpicBoard,
},
});
await nextTick();
findFormInput().vm.$emit('input', TEST_TITLE);
findForm().vm.$emit('submit', { preventDefault: () => {} });
await nextTick();
expect(queryHandler).toHaveBeenCalled();
expect(notCalledHandler).not.toHaveBeenCalled();
},
);
describe('when submitting and invalid title', () => {
beforeEach(async () => {
createWrapper();
findFormInput().vm.$emit('input', '');
findForm().vm.$emit('submit', { preventDefault: () => {} });
await nextTick();
});
it('does not update title', () => {
expect(issueSetTitleMutationHandlerSuccess).not.toHaveBeenCalled();
});
});
describe('when abandoning the form without saving', () => {
beforeEach(async () => {
createWrapper();
wrapper.vm.$refs.sidebarItem.expand();
findFormInput().vm.$emit('input', TEST_TITLE);
findEditableItem().vm.$emit('off-click');
await nextTick();
});
it('does not collapses sidebar and shows alert', () => {
expect(findCollapsed().isVisible()).toBe(false);
expect(findAlert().exists()).toBe(true);
expect(localStorage.getItem(`${TEST_ISSUE_A.id}/item-title-pending-changes`)).toBe(
TEST_TITLE,
);
});
});
describe('when accessing the form with pending changes', () => {
beforeAll(() => {
localStorage.setItem(`${TEST_ISSUE_A.id}/item-title-pending-changes`, TEST_TITLE);
createWrapper();
});
it('sets title, expands item and shows alert', () => {
expect(findFormInput().attributes('value')).toBe(TEST_TITLE);
expect(findCollapsed().isVisible()).toBe(false);
expect(findAlert().exists()).toBe(true);
});
});
describe('when cancel button is clicked', () => {
beforeEach(async () => {
createWrapper({ item: TEST_ISSUE_B });
findFormInput().vm.$emit('input', TEST_TITLE);
findCancelButton().vm.$emit('click');
await nextTick();
});
it('collapses sidebar and render former title', () => {
expect(issueSetTitleMutationHandlerSuccess).not.toHaveBeenCalled();
expect(findCollapsed().isVisible()).toBe(true);
expect(findTitle().text()).toBe(TEST_ISSUE_B.title);
});
});
describe('when the mutation fails', () => {
beforeEach(async () => {
createWrapper({
item: TEST_ISSUE_B,
issueSetTitleMutationHandler: issueSetTitleMutationHandlerFailure,
});
findFormInput().vm.$emit('input', 'Invalid title');
findForm().vm.$emit('submit', { preventDefault: () => {} });
await nextTick();
});
it('collapses sidebar and renders former item title', async () => {
expect(findCollapsed().isVisible()).toBe(true);
expect(findTitle().text()).toContain(TEST_ISSUE_B.title);
await waitForPromises();
expect(cacheUpdates.setError).toHaveBeenCalledWith(
expect.objectContaining({ message: 'An error occurred when updating the title' }),
);
});
});
});