debian-mirror-gitlab/spec/frontend/snippets/components/snippet_header_spec.js

265 lines
7 KiB
JavaScript
Raw Normal View History

2020-01-01 13:55:28 +05:30
import { GlButton, GlModal } from '@gitlab/ui';
2020-10-24 23:57:45 +05:30
import { mount } from '@vue/test-utils';
2021-03-11 19:13:27 +05:30
import { ApolloMutation } from 'vue-apollo';
2020-10-24 23:57:45 +05:30
import waitForPromises from 'helpers/wait_for_promises';
2021-03-11 19:13:27 +05:30
import { Blob, BinaryBlob } from 'jest/blob/components/mock_data';
2020-11-24 15:15:51 +05:30
import { differenceInMilliseconds } from '~/lib/utils/datetime_utility';
2021-03-11 19:13:27 +05:30
import SnippetHeader from '~/snippets/components/snippet_header.vue';
import DeleteSnippetMutation from '~/snippets/mutations/deleteSnippet.mutation.graphql';
2020-01-01 13:55:28 +05:30
describe('Snippet header component', () => {
let wrapper;
2020-10-24 23:57:45 +05:30
let snippet;
let mutationTypes;
let mutationVariables;
let errorMsg;
let err;
2020-11-24 15:15:51 +05:30
const originalRelativeUrlRoot = gon.relative_url_root;
2020-01-01 13:55:28 +05:30
2021-03-08 18:12:59 +05:30
const GlEmoji = { template: '<img/>' };
2020-01-01 13:55:28 +05:30
function createComponent({
loading = false,
permissions = {},
mutationRes = mutationTypes.RESOLVE,
2020-05-24 23:13:21 +05:30
snippetProps = {},
2020-01-01 13:55:28 +05:30
} = {}) {
2020-05-24 23:13:21 +05:30
const defaultProps = Object.assign(snippet, snippetProps);
2020-01-01 13:55:28 +05:30
if (permissions) {
2020-05-24 23:13:21 +05:30
Object.assign(defaultProps.userPermissions, {
2020-01-01 13:55:28 +05:30
...permissions,
});
}
const $apollo = {
queries: {
canCreateSnippet: {
loading,
},
},
mutate: mutationRes,
};
2020-10-24 23:57:45 +05:30
wrapper = mount(SnippetHeader, {
2020-01-01 13:55:28 +05:30
mocks: { $apollo },
propsData: {
2020-05-24 23:13:21 +05:30
snippet: {
...defaultProps,
},
2020-01-01 13:55:28 +05:30
},
stubs: {
ApolloMutation,
2021-03-08 18:12:59 +05:30
GlEmoji,
2020-01-01 13:55:28 +05:30
},
});
}
2021-03-08 18:12:59 +05:30
const findAuthorEmoji = () => wrapper.find(GlEmoji);
const findAuthoredMessage = () => wrapper.find('[data-testid="authored-message"]').text();
const buttonCount = () => wrapper.findAll(GlButton).length;
2020-10-24 23:57:45 +05:30
beforeEach(() => {
2020-11-24 15:15:51 +05:30
gon.relative_url_root = '/foo/';
2020-10-24 23:57:45 +05:30
snippet = {
id: 'gid://gitlab/PersonalSnippet/50',
title: 'The property of Thor',
visibilityLevel: 'private',
webUrl: 'http://personal.dev.null/42',
userPermissions: {
adminSnippet: true,
updateSnippet: true,
reportSnippet: false,
},
project: null,
author: {
name: 'Thor Odinson',
2021-03-08 18:12:59 +05:30
status: null,
2020-10-24 23:57:45 +05:30
},
blobs: [Blob],
2020-11-24 15:15:51 +05:30
createdAt: new Date(differenceInMilliseconds(32 * 24 * 3600 * 1000)).toISOString(),
2020-10-24 23:57:45 +05:30
};
mutationVariables = {
mutation: DeleteSnippetMutation,
variables: {
id: snippet.id,
},
};
errorMsg = 'Foo bar';
err = { message: errorMsg };
mutationTypes = {
RESOLVE: jest.fn(() => Promise.resolve({ data: { destroySnippet: { errors: [] } } })),
REJECT: jest.fn(() => Promise.reject(err)),
};
});
2020-01-01 13:55:28 +05:30
afterEach(() => {
wrapper.destroy();
2020-11-24 15:15:51 +05:30
gon.relative_url_root = originalRelativeUrlRoot;
2020-01-01 13:55:28 +05:30
});
it('renders itself', () => {
createComponent();
expect(wrapper.find('.detail-page-header').exists()).toBe(true);
});
2020-10-24 23:57:45 +05:30
it('renders a message showing snippet creation date and author', () => {
createComponent();
2021-03-08 18:12:59 +05:30
const text = findAuthoredMessage();
2020-10-24 23:57:45 +05:30
expect(text).toContain('Authored 1 month ago by');
expect(text).toContain('Thor Odinson');
});
2021-03-08 18:12:59 +05:30
describe('author status', () => {
it('is rendered when it is set', () => {
snippet.author.status = {
message: 'At work',
emoji: 'hammer',
};
createComponent();
expect(findAuthorEmoji().attributes('title')).toBe(snippet.author.status.message);
expect(findAuthorEmoji().attributes('data-name')).toBe(snippet.author.status.emoji);
});
it('is not rendered when the user has no status', () => {
createComponent();
expect(findAuthorEmoji().exists()).toBe(false);
});
});
2020-10-24 23:57:45 +05:30
it('renders a message showing only snippet creation date if author is null', () => {
snippet.author = null;
createComponent();
2021-03-08 18:12:59 +05:30
const text = findAuthoredMessage();
2020-10-24 23:57:45 +05:30
expect(text).toBe('Authored 1 month ago');
});
2020-01-01 13:55:28 +05:30
it('renders action buttons based on permissions', () => {
createComponent({
permissions: {
adminSnippet: false,
updateSnippet: false,
},
});
2021-03-08 18:12:59 +05:30
expect(buttonCount()).toEqual(0);
2020-01-01 13:55:28 +05:30
createComponent({
permissions: {
adminSnippet: true,
updateSnippet: false,
},
});
2021-03-08 18:12:59 +05:30
expect(buttonCount()).toEqual(1);
2020-01-01 13:55:28 +05:30
createComponent({
permissions: {
adminSnippet: true,
updateSnippet: true,
},
});
2021-03-08 18:12:59 +05:30
expect(buttonCount()).toEqual(2);
2020-01-01 13:55:28 +05:30
createComponent({
permissions: {
adminSnippet: true,
updateSnippet: true,
},
});
wrapper.setData({
canCreateSnippet: true,
});
return wrapper.vm.$nextTick().then(() => {
2021-03-08 18:12:59 +05:30
expect(buttonCount()).toEqual(3);
2020-01-01 13:55:28 +05:30
});
});
it('renders modal for deletion of a snippet', () => {
createComponent();
expect(wrapper.find(GlModal).exists()).toBe(true);
});
2020-07-28 23:09:34 +05:30
it.each`
blobs | isDisabled | condition
${[Blob]} | ${false} | ${'no binary'}
${[Blob, BinaryBlob]} | ${true} | ${'several blobs. incl. a binary'}
${[BinaryBlob]} | ${true} | ${'binary'}
`('renders Edit button when snippet contains $condition file', ({ blobs, isDisabled }) => {
2020-05-24 23:13:21 +05:30
createComponent({
snippetProps: {
2020-07-28 23:09:34 +05:30
blobs,
2020-05-24 23:13:21 +05:30
},
});
2020-07-28 23:09:34 +05:30
expect(wrapper.find('[href*="edit"]').props('disabled')).toBe(isDisabled);
2020-05-24 23:13:21 +05:30
});
2020-01-01 13:55:28 +05:30
describe('Delete mutation', () => {
const { location } = window;
beforeEach(() => {
delete window.location;
window.location = {
pathname: '',
};
});
afterEach(() => {
window.location = location;
});
it('dispatches a mutation to delete the snippet with correct variables', () => {
createComponent();
wrapper.vm.deleteSnippet();
expect(mutationTypes.RESOLVE).toHaveBeenCalledWith(mutationVariables);
});
2020-10-24 23:57:45 +05:30
it('sets error message if mutation fails', async () => {
2020-01-01 13:55:28 +05:30
createComponent({ mutationRes: mutationTypes.REJECT });
expect(Boolean(wrapper.vm.errorMessage)).toBe(false);
wrapper.vm.deleteSnippet();
2020-10-24 23:57:45 +05:30
await waitForPromises();
expect(wrapper.vm.errorMessage).toEqual(errorMsg);
2020-01-01 13:55:28 +05:30
});
2020-05-24 23:13:21 +05:30
describe('in case of successful mutation, closes modal and redirects to correct listing', () => {
const createDeleteSnippet = (snippetProps = {}) => {
createComponent({
snippetProps,
});
wrapper.vm.closeDeleteModal = jest.fn();
2020-01-01 13:55:28 +05:30
2020-05-24 23:13:21 +05:30
wrapper.vm.deleteSnippet();
return wrapper.vm.$nextTick();
};
it('redirects to dashboard/snippets for personal snippet', () => {
return createDeleteSnippet().then(() => {
expect(wrapper.vm.closeDeleteModal).toHaveBeenCalled();
2020-11-24 15:15:51 +05:30
expect(window.location.pathname).toBe(`${gon.relative_url_root}dashboard/snippets`);
2020-05-24 23:13:21 +05:30
});
});
it('redirects to project snippets for project snippet', () => {
const fullPath = 'foo/bar';
return createDeleteSnippet({
project: {
fullPath,
},
}).then(() => {
expect(wrapper.vm.closeDeleteModal).toHaveBeenCalled();
2020-10-24 23:57:45 +05:30
expect(window.location.pathname).toBe(`${fullPath}/-/snippets`);
2020-05-24 23:13:21 +05:30
});
2020-01-01 13:55:28 +05:30
});
});
});
});