debian-mirror-gitlab/spec/frontend/notes/components/note_header_spec.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

279 lines
8.5 KiB
JavaScript
Raw Normal View History

2022-04-04 11:22:00 +05:30
import Vue, { nextTick } from 'vue';
2020-03-13 15:44:24 +05:30
import Vuex from 'vuex';
2022-05-07 20:08:51 +05:30
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
2020-03-13 15:44:24 +05:30
import NoteHeader from '~/notes/components/note_header.vue';
2022-04-04 11:22:00 +05:30
Vue.use(Vuex);
2020-03-13 15:44:24 +05:30
const actions = {
setTargetNoteHash: jest.fn(),
};
describe('NoteHeader component', () => {
let wrapper;
2022-08-27 11:52:29 +05:30
const findActionsWrapper = () => wrapper.findComponent({ ref: 'discussionActions' });
2022-05-07 20:08:51 +05:30
const findToggleThreadButton = () => wrapper.findByTestId('thread-toggle');
2022-08-27 11:52:29 +05:30
const findChevronIcon = () => wrapper.findComponent({ ref: 'chevronIcon' });
const findActionText = () => wrapper.findComponent({ ref: 'actionText' });
const findTimestampLink = () => wrapper.findComponent({ ref: 'noteTimestampLink' });
const findTimestamp = () => wrapper.findComponent({ ref: 'noteTimestamp' });
2023-01-13 00:05:48 +05:30
const findInternalNoteIndicator = () => wrapper.findByTestId('internal-note-indicator');
2023-07-09 08:55:56 +05:30
const findAuthorName = () => wrapper.findByTestId('author-name');
2022-08-27 11:52:29 +05:30
const findSpinner = () => wrapper.findComponent({ ref: 'spinner' });
2023-07-09 08:55:56 +05:30
const authorUsernameLink = () => wrapper.findComponent({ ref: 'authorUsernameLink' });
2021-02-22 17:27:13 +05:30
const statusHtml =
'"<span class="user-status-emoji has-tooltip" title="foo bar" data-html="true" data-placement="top"><gl-emoji title="basketball and hoop" data-name="basketball" data-unicode-version="6.0">🏀</gl-emoji></span>"';
2020-04-22 19:07:51 +05:30
const author = {
avatar_url: null,
id: 1,
name: 'Root',
path: '/root',
state: 'active',
username: 'root',
2021-02-22 17:27:13 +05:30
show_status: true,
status_tooltip_html: statusHtml,
2020-04-22 19:07:51 +05:30
};
2020-03-13 15:44:24 +05:30
2023-07-09 08:55:56 +05:30
const supportBotAuthor = {
avatar_url: null,
id: 1,
name: 'Gitlab Support Bot',
path: '/support-bot',
state: 'active',
username: 'support-bot',
show_status: true,
status_tooltip_html: statusHtml,
};
2022-11-25 23:54:43 +05:30
const createComponent = (props) => {
2022-05-07 20:08:51 +05:30
wrapper = shallowMountExtended(NoteHeader, {
2020-03-13 15:44:24 +05:30
store: new Vuex.Store({
actions,
}),
2020-04-22 19:07:51 +05:30
propsData: { ...props },
2020-03-13 15:44:24 +05:30
});
};
it('does not render discussion actions when includeToggle is false', () => {
createComponent({
includeToggle: false,
});
expect(findActionsWrapper().exists()).toBe(false);
});
describe('when includes a toggle', () => {
it('renders discussion actions', () => {
createComponent({
includeToggle: true,
});
expect(findActionsWrapper().exists()).toBe(true);
});
it('emits toggleHandler event on button click', () => {
createComponent({
includeToggle: true,
});
wrapper.find('.note-action-button').trigger('click');
expect(wrapper.emitted('toggleHandler')).toBeDefined();
expect(wrapper.emitted('toggleHandler')).toHaveLength(1);
});
it('has chevron-up icon if expanded prop is true', () => {
createComponent({
includeToggle: true,
expanded: true,
});
2021-01-29 00:20:46 +05:30
expect(findChevronIcon().props('name')).toBe('chevron-up');
2020-03-13 15:44:24 +05:30
});
it('has chevron-down icon if expanded prop is false', () => {
createComponent({
includeToggle: true,
expanded: false,
});
2021-01-29 00:20:46 +05:30
expect(findChevronIcon().props('name')).toBe('chevron-down');
2020-03-13 15:44:24 +05:30
});
2022-05-07 20:08:51 +05:30
it.each`
text | expanded
${NoteHeader.i18n.showThread} | ${false}
${NoteHeader.i18n.hideThread} | ${true}
`('toggle button has text $text is expanded is $expanded', ({ text, expanded }) => {
createComponent({
includeToggle: true,
expanded,
});
expect(findToggleThreadButton().text()).toBe(text);
});
2020-03-13 15:44:24 +05:30
});
it('renders an author link if author is passed to props', () => {
2020-04-22 19:07:51 +05:30
createComponent({ author });
2020-03-13 15:44:24 +05:30
expect(wrapper.find('.js-user-link').exists()).toBe(true);
});
it('renders deleted user text if author is not passed as a prop', () => {
createComponent();
expect(wrapper.text()).toContain('A deleted user');
});
2023-07-09 08:55:56 +05:30
it('renders participant email when author is a support-bot', () => {
createComponent({
author: supportBotAuthor,
emailParticipant: 'email@example.com',
});
expect(findAuthorName().text()).toBe('email@example.com');
expect(authorUsernameLink().exists()).toBe(false);
});
2020-03-13 15:44:24 +05:30
it('does not render created at information if createdAt is not passed as a prop', () => {
createComponent();
expect(findActionText().exists()).toBe(false);
2020-04-22 19:07:51 +05:30
expect(findTimestampLink().exists()).toBe(false);
2020-03-13 15:44:24 +05:30
});
describe('when createdAt is passed as a prop', () => {
it('renders action text and a timestamp', () => {
createComponent({
createdAt: '2017-08-02T10:51:58.559Z',
2020-04-22 19:07:51 +05:30
noteId: 123,
2020-03-13 15:44:24 +05:30
});
expect(findActionText().exists()).toBe(true);
2020-04-22 19:07:51 +05:30
expect(findTimestampLink().exists()).toBe(true);
2020-03-13 15:44:24 +05:30
});
it('renders correct actionText if passed', () => {
createComponent({
createdAt: '2017-08-02T10:51:58.559Z',
actionText: 'Test action text',
});
expect(findActionText().text()).toBe('Test action text');
});
it('calls an action when timestamp is clicked', () => {
createComponent({
createdAt: '2017-08-02T10:51:58.559Z',
2020-04-22 19:07:51 +05:30
noteId: 123,
2020-03-13 15:44:24 +05:30
});
2020-04-22 19:07:51 +05:30
findTimestampLink().trigger('click');
2020-03-13 15:44:24 +05:30
expect(actions.setTargetNoteHash).toHaveBeenCalled();
});
});
2020-04-22 19:07:51 +05:30
describe('loading spinner', () => {
it('shows spinner when showSpinner is true', () => {
createComponent();
expect(findSpinner().exists()).toBe(true);
});
it('does not show spinner when showSpinner is false', () => {
createComponent({ showSpinner: false });
expect(findSpinner().exists()).toBe(false);
});
});
describe('timestamp', () => {
it('shows timestamp as a link if a noteId was provided', () => {
createComponent({ createdAt: new Date().toISOString(), noteId: 123 });
expect(findTimestampLink().exists()).toBe(true);
expect(findTimestamp().exists()).toBe(false);
});
it('shows timestamp as plain text if a noteId was not provided', () => {
createComponent({ createdAt: new Date().toISOString() });
expect(findTimestampLink().exists()).toBe(false);
expect(findTimestamp().exists()).toBe(true);
});
});
2020-05-24 23:13:21 +05:30
describe('author username link', () => {
it('proxies `mouseenter` event to author name link', () => {
createComponent({ author });
const dispatchEvent = jest.spyOn(wrapper.vm.$refs.authorNameLink, 'dispatchEvent');
2022-08-27 11:52:29 +05:30
wrapper.findComponent({ ref: 'authorUsernameLink' }).trigger('mouseenter');
2020-05-24 23:13:21 +05:30
expect(dispatchEvent).toHaveBeenCalledWith(new Event('mouseenter'));
});
it('proxies `mouseleave` event to author name link', () => {
createComponent({ author });
const dispatchEvent = jest.spyOn(wrapper.vm.$refs.authorNameLink, 'dispatchEvent');
2022-08-27 11:52:29 +05:30
wrapper.findComponent({ ref: 'authorUsernameLink' }).trigger('mouseleave');
2020-05-24 23:13:21 +05:30
expect(dispatchEvent).toHaveBeenCalledWith(new Event('mouseleave'));
});
});
describe('when author username link is hovered', () => {
2022-06-21 17:19:12 +05:30
it('toggles hover specific CSS classes on author name link', async () => {
2020-05-24 23:13:21 +05:30
createComponent({ author });
2022-08-27 11:52:29 +05:30
const authorNameLink = wrapper.findComponent({ ref: 'authorNameLink' });
2020-05-24 23:13:21 +05:30
2023-07-09 08:55:56 +05:30
authorUsernameLink().trigger('mouseenter');
2020-05-24 23:13:21 +05:30
2022-06-21 17:19:12 +05:30
await nextTick();
expect(authorNameLink.classes()).toContain('hover');
expect(authorNameLink.classes()).toContain('text-underline');
2020-05-24 23:13:21 +05:30
2023-07-09 08:55:56 +05:30
authorUsernameLink().trigger('mouseleave');
2020-05-24 23:13:21 +05:30
2022-06-21 17:19:12 +05:30
await nextTick();
expect(authorNameLink.classes()).not.toContain('hover');
expect(authorNameLink.classes()).not.toContain('text-underline');
2020-05-24 23:13:21 +05:30
});
});
2022-07-23 23:45:48 +05:30
describe('with internal note badge', () => {
2020-05-24 23:13:21 +05:30
it.each`
status | condition
${true} | ${'shows'}
${false} | ${'hides'}
2022-07-23 23:45:48 +05:30
`('$condition badge when isInternalNote is $status', ({ status }) => {
createComponent({ isInternalNote: status });
expect(findInternalNoteIndicator().exists()).toBe(status);
2020-05-24 23:13:21 +05:30
});
2022-06-21 17:19:12 +05:30
2022-07-23 23:45:48 +05:30
it('shows internal note badge tooltip for project context', () => {
createComponent({ isInternalNote: true, noteableType: 'issue' });
2022-06-21 17:19:12 +05:30
2022-07-23 23:45:48 +05:30
expect(findInternalNoteIndicator().attributes('title')).toBe(
2022-07-16 23:28:13 +05:30
'This internal note will always remain confidential',
2022-06-21 17:19:12 +05:30
);
});
2020-05-24 23:13:21 +05:30
});
2022-11-25 23:54:43 +05:30
it('does render username', () => {
createComponent({ author }, true);
expect(wrapper.find('.note-header-info').text()).toContain('@');
});
describe('with system note', () => {
it('does not render username', () => {
createComponent({ author, isSystemNote: true }, true);
expect(wrapper.find('.note-header-info').text()).not.toContain('@');
});
});
2020-03-13 15:44:24 +05:30
});