Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-10-21 10:08:36 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-10-21 10:08:36 +0300
commit48aff82709769b098321c738f3444b9bdaa694c6 (patch)
treee00c7c43e2d9b603a5a6af576b1685e400410dee /spec/frontend/issuable_show
parent879f5329ee916a948223f8f43d77fba4da6cd028 (diff)
Add latest changes from gitlab-org/gitlab@13-5-stable-eev13.5.0-rc42
Diffstat (limited to 'spec/frontend/issuable_show')
-rw-r--r--spec/frontend/issuable_show/components/issuable_body_spec.js140
-rw-r--r--spec/frontend/issuable_show/components/issuable_description_spec.js41
-rw-r--r--spec/frontend/issuable_show/components/issuable_edit_form_spec.js122
-rw-r--r--spec/frontend/issuable_show/components/issuable_header_spec.js132
-rw-r--r--spec/frontend/issuable_show/components/issuable_show_root_spec.js123
-rw-r--r--spec/frontend/issuable_show/components/issuable_title_spec.js100
-rw-r--r--spec/frontend/issuable_show/mock_data.js34
7 files changed, 692 insertions, 0 deletions
diff --git a/spec/frontend/issuable_show/components/issuable_body_spec.js b/spec/frontend/issuable_show/components/issuable_body_spec.js
new file mode 100644
index 00000000000..0e4475e8103
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_body_spec.js
@@ -0,0 +1,140 @@
+import { shallowMount } from '@vue/test-utils';
+
+import IssuableBody from '~/issuable_show/components/issuable_body.vue';
+
+import IssuableTitle from '~/issuable_show/components/issuable_title.vue';
+import IssuableDescription from '~/issuable_show/components/issuable_description.vue';
+import IssuableEditForm from '~/issuable_show/components/issuable_edit_form.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+import { mockIssuableShowProps, mockIssuable } from '../mock_data';
+
+jest.mock('~/autosave');
+
+const issuableBodyProps = {
+ ...mockIssuableShowProps,
+ issuable: mockIssuable,
+};
+
+const createComponent = (propsData = issuableBodyProps) =>
+ shallowMount(IssuableBody, {
+ propsData,
+ stubs: {
+ IssuableTitle,
+ IssuableDescription,
+ IssuableEditForm,
+ TimeAgoTooltip,
+ },
+ slots: {
+ 'status-badge': 'Open',
+ 'edit-form-actions': `
+ <button class="js-save">Save changes</button>
+ <button class="js-cancel">Cancel</button>
+ `,
+ },
+ });
+
+describe('IssuableBody', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('computed', () => {
+ describe('isUpdated', () => {
+ it.each`
+ updatedAt | returnValue
+ ${mockIssuable.updatedAt} | ${true}
+ ${null} | ${false}
+ ${''} | ${false}
+ `(
+ 'returns $returnValue when value of `updateAt` prop is `$updatedAt`',
+ async ({ updatedAt, returnValue }) => {
+ wrapper.setProps({
+ issuable: {
+ ...mockIssuable,
+ updatedAt,
+ },
+ });
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.vm.isUpdated).toBe(returnValue);
+ },
+ );
+ });
+
+ describe('updatedBy', () => {
+ it('returns value of `issuable.updatedBy`', () => {
+ expect(wrapper.vm.updatedBy).toBe(mockIssuable.updatedBy);
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('renders issuable-title component', () => {
+ const titleEl = wrapper.find(IssuableTitle);
+
+ expect(titleEl.exists()).toBe(true);
+ expect(titleEl.props()).toMatchObject({
+ issuable: issuableBodyProps.issuable,
+ statusBadgeClass: issuableBodyProps.statusBadgeClass,
+ statusIcon: issuableBodyProps.statusIcon,
+ enableEdit: issuableBodyProps.enableEdit,
+ });
+ });
+
+ it('renders issuable-description component', () => {
+ const descriptionEl = wrapper.find(IssuableDescription);
+
+ expect(descriptionEl.exists()).toBe(true);
+ expect(descriptionEl.props('issuable')).toEqual(issuableBodyProps.issuable);
+ });
+
+ it('renders issuable edit info', () => {
+ const editedEl = wrapper.find('small');
+ const sanitizedText = editedEl
+ .text()
+ .replace(/\n/g, ' ')
+ .replace(/\s+/g, ' ');
+
+ expect(sanitizedText).toContain('Edited');
+ expect(sanitizedText).toContain('ago');
+ expect(sanitizedText).toContain(`by ${mockIssuable.updatedBy.name}`);
+ });
+
+ it('renders issuable-edit-form when `editFormVisible` prop is true', async () => {
+ wrapper.setProps({
+ editFormVisible: true,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ const editFormEl = wrapper.find(IssuableEditForm);
+ expect(editFormEl.exists()).toBe(true);
+ expect(editFormEl.props()).toMatchObject({
+ issuable: issuableBodyProps.issuable,
+ enableAutocomplete: issuableBodyProps.enableAutocomplete,
+ descriptionPreviewPath: issuableBodyProps.descriptionPreviewPath,
+ descriptionHelpPath: issuableBodyProps.descriptionHelpPath,
+ });
+ expect(editFormEl.find('button.js-save').exists()).toBe(true);
+ expect(editFormEl.find('button.js-cancel').exists()).toBe(true);
+ });
+
+ describe('events', () => {
+ it('component emits `edit-issuable` event bubbled via issuable-title', () => {
+ const issuableTitle = wrapper.find(IssuableTitle);
+
+ issuableTitle.vm.$emit('edit-issuable');
+
+ expect(wrapper.emitted('edit-issuable')).toBeTruthy();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/components/issuable_description_spec.js b/spec/frontend/issuable_show/components/issuable_description_spec.js
new file mode 100644
index 00000000000..1dd8348b098
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_description_spec.js
@@ -0,0 +1,41 @@
+import $ from 'jquery';
+import { shallowMount } from '@vue/test-utils';
+
+import IssuableDescription from '~/issuable_show/components/issuable_description.vue';
+
+import { mockIssuable } from '../mock_data';
+
+const createComponent = (issuable = mockIssuable) =>
+ shallowMount(IssuableDescription, {
+ propsData: { issuable },
+ });
+
+describe('IssuableDescription', () => {
+ let renderGFMSpy;
+ let wrapper;
+
+ beforeEach(() => {
+ renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('mounted', () => {
+ it('calls `renderGFM`', () => {
+ expect(renderGFMSpy).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('methods', () => {
+ describe('renderGFM', () => {
+ it('calls `renderGFM` on container element', () => {
+ wrapper.vm.renderGFM();
+
+ expect(renderGFMSpy).toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/components/issuable_edit_form_spec.js b/spec/frontend/issuable_show/components/issuable_edit_form_spec.js
new file mode 100644
index 00000000000..352e66cdffe
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_edit_form_spec.js
@@ -0,0 +1,122 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlFormInput } from '@gitlab/ui';
+import MarkdownField from '~/vue_shared/components/markdown/field.vue';
+
+import IssuableEditForm from '~/issuable_show/components/issuable_edit_form.vue';
+import IssuableEventHub from '~/issuable_show/event_hub';
+
+import { mockIssuableShowProps, mockIssuable } from '../mock_data';
+
+const issuableEditFormProps = {
+ issuable: mockIssuable,
+ ...mockIssuableShowProps,
+};
+
+const createComponent = ({ propsData = issuableEditFormProps } = {}) =>
+ shallowMount(IssuableEditForm, {
+ propsData,
+ stubs: {
+ MarkdownField,
+ },
+ slots: {
+ 'edit-form-actions': `
+ <button class="js-save">Save changes</button>
+ <button class="js-cancel">Cancel</button>
+ `,
+ },
+ });
+
+describe('IssuableEditForm', () => {
+ let wrapper;
+ const assertEvent = eventSpy => {
+ expect(eventSpy).toHaveBeenNthCalledWith(1, 'update.issuable', expect.any(Function));
+ expect(eventSpy).toHaveBeenNthCalledWith(2, 'close.form', expect.any(Function));
+ };
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('created', () => {
+ it('binds `update.issuable` and `close.form` event listeners', () => {
+ const eventOnSpy = jest.spyOn(IssuableEventHub, '$on');
+ const wrapperTemp = createComponent();
+
+ assertEvent(eventOnSpy);
+
+ wrapperTemp.destroy();
+ });
+ });
+
+ describe('beforeDestroy', () => {
+ it('unbinds `update.issuable` and `close.form` event listeners', () => {
+ const wrapperTemp = createComponent();
+ const eventOffSpy = jest.spyOn(IssuableEventHub, '$off');
+
+ wrapperTemp.destroy();
+
+ assertEvent(eventOffSpy);
+ });
+ });
+
+ describe('methods', () => {
+ describe('initAutosave', () => {
+ it('initializes `autosaveTitle` and `autosaveDescription` props', () => {
+ expect(wrapper.vm.autosaveTitle).toBeDefined();
+ expect(wrapper.vm.autosaveDescription).toBeDefined();
+ });
+ });
+
+ describe('resetAutosave', () => {
+ it('calls `reset` on `autosaveTitle` and `autosaveDescription` props', () => {
+ jest.spyOn(wrapper.vm.autosaveTitle, 'reset').mockImplementation(jest.fn);
+ jest.spyOn(wrapper.vm.autosaveDescription, 'reset').mockImplementation(jest.fn);
+
+ wrapper.vm.resetAutosave();
+
+ expect(wrapper.vm.autosaveTitle.reset).toHaveBeenCalled();
+ expect(wrapper.vm.autosaveDescription.reset).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('renders title input field', () => {
+ const titleInputEl = wrapper.find('[data-testid="title"]');
+
+ expect(titleInputEl.exists()).toBe(true);
+ expect(titleInputEl.find(GlFormInput).attributes()).toMatchObject({
+ 'aria-label': 'Title',
+ placeholder: 'Title',
+ });
+ });
+
+ it('renders description textarea field', () => {
+ const descriptionEl = wrapper.find('[data-testid="description"]');
+
+ expect(descriptionEl.exists()).toBe(true);
+ expect(descriptionEl.find(MarkdownField).props()).toMatchObject({
+ markdownPreviewPath: issuableEditFormProps.descriptionPreviewPath,
+ markdownDocsPath: issuableEditFormProps.descriptionHelpPath,
+ enableAutocomplete: issuableEditFormProps.enableAutocomplete,
+ textareaValue: mockIssuable.description,
+ });
+ expect(descriptionEl.find('textarea').attributes()).toMatchObject({
+ 'data-supports-quick-actions': 'true',
+ 'aria-label': 'Description',
+ placeholder: 'Write a comment or drag your files hereā€¦',
+ });
+ });
+
+ it('renders form actions', () => {
+ const actionsEl = wrapper.find('[data-testid="actions"]');
+
+ expect(actionsEl.find('button.js-save').exists()).toBe(true);
+ expect(actionsEl.find('button.js-cancel').exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/components/issuable_header_spec.js b/spec/frontend/issuable_show/components/issuable_header_spec.js
new file mode 100644
index 00000000000..fad8ec8a891
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_header_spec.js
@@ -0,0 +1,132 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon, GlAvatarLabeled } from '@gitlab/ui';
+
+import IssuableHeader from '~/issuable_show/components/issuable_header.vue';
+
+import { mockIssuableShowProps, mockIssuable } from '../mock_data';
+
+const issuableHeaderProps = {
+ ...mockIssuable,
+ ...mockIssuableShowProps,
+};
+
+const createComponent = (propsData = issuableHeaderProps) =>
+ shallowMount(IssuableHeader, {
+ propsData,
+ slots: {
+ 'status-badge': 'Open',
+ 'header-actions': `
+ <button class="js-close">Close issuable</button>
+ <a class="js-new" href="/gitlab-org/gitlab-shell/-/issues/new">New issuable</a>
+ `,
+ },
+ });
+
+describe('IssuableHeader', () => {
+ let wrapper;
+ const findByTestId = testId => wrapper.find(`[data-testid="${testId}"]`);
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('computed', () => {
+ describe('authorId', () => {
+ it('returns numeric ID from GraphQL ID of `author` prop', () => {
+ expect(wrapper.vm.authorId).toBe(1);
+ });
+ });
+ });
+
+ describe('handleRightSidebarToggleClick', () => {
+ beforeEach(() => {
+ setFixtures('<button class="js-toggle-right-sidebar-button">Collapse sidebar</button>');
+ });
+
+ it('dispatches `click` event on sidebar toggle button', () => {
+ wrapper.vm.toggleSidebarButtonEl = document.querySelector('.js-toggle-right-sidebar-button');
+ jest.spyOn(wrapper.vm.toggleSidebarButtonEl, 'dispatchEvent').mockImplementation(jest.fn);
+
+ wrapper.vm.handleRightSidebarToggleClick();
+
+ expect(wrapper.vm.toggleSidebarButtonEl.dispatchEvent).toHaveBeenCalledWith(
+ expect.objectContaining({
+ type: 'click',
+ }),
+ );
+ });
+ });
+
+ describe('template', () => {
+ it('renders issuable status icon and text', () => {
+ const statusBoxEl = findByTestId('status');
+
+ expect(statusBoxEl.exists()).toBe(true);
+ expect(statusBoxEl.find(GlIcon).props('name')).toBe(mockIssuableShowProps.statusIcon);
+ expect(statusBoxEl.text()).toContain('Open');
+ });
+
+ it('renders blocked icon when issuable is blocked', async () => {
+ wrapper.setProps({
+ blocked: true,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ const blockedEl = findByTestId('blocked');
+
+ expect(blockedEl.exists()).toBe(true);
+ expect(blockedEl.find(GlIcon).props('name')).toBe('lock');
+ });
+
+ it('renders confidential icon when issuable is confidential', async () => {
+ wrapper.setProps({
+ confidential: true,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ const confidentialEl = findByTestId('confidential');
+
+ expect(confidentialEl.exists()).toBe(true);
+ expect(confidentialEl.find(GlIcon).props('name')).toBe('eye-slash');
+ });
+
+ it('renders issuable author avatar', () => {
+ const { username, name, webUrl, avatarUrl } = mockIssuable.author;
+ const avatarElAttrs = {
+ 'data-user-id': '1',
+ 'data-username': username,
+ 'data-name': name,
+ href: webUrl,
+ target: '_blank',
+ };
+ const avatarEl = findByTestId('avatar');
+ expect(avatarEl.exists()).toBe(true);
+ expect(avatarEl.attributes()).toMatchObject(avatarElAttrs);
+ expect(avatarEl.find(GlAvatarLabeled).attributes()).toMatchObject({
+ size: '24',
+ src: avatarUrl,
+ label: name,
+ });
+ });
+
+ it('renders sidebar toggle button', () => {
+ const toggleButtonEl = findByTestId('sidebar-toggle');
+
+ expect(toggleButtonEl.exists()).toBe(true);
+ expect(toggleButtonEl.props('icon')).toBe('chevron-double-lg-left');
+ });
+
+ it('renders header actions', () => {
+ const actionsEl = findByTestId('header-actions');
+
+ expect(actionsEl.find('button.js-close').exists()).toBe(true);
+ expect(actionsEl.find('a.js-new').exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/components/issuable_show_root_spec.js b/spec/frontend/issuable_show/components/issuable_show_root_spec.js
new file mode 100644
index 00000000000..112e4ccd340
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_show_root_spec.js
@@ -0,0 +1,123 @@
+import { shallowMount } from '@vue/test-utils';
+
+import IssuableShowRoot from '~/issuable_show/components/issuable_show_root.vue';
+
+import IssuableHeader from '~/issuable_show/components/issuable_header.vue';
+import IssuableBody from '~/issuable_show/components/issuable_body.vue';
+import IssuableSidebar from '~/issuable_sidebar/components/issuable_sidebar_root.vue';
+
+import { mockIssuableShowProps, mockIssuable } from '../mock_data';
+
+const createComponent = (propsData = mockIssuableShowProps) =>
+ shallowMount(IssuableShowRoot, {
+ propsData,
+ stubs: {
+ IssuableHeader,
+ IssuableBody,
+ IssuableSidebar,
+ },
+ slots: {
+ 'status-badge': 'Open',
+ 'header-actions': `
+ <button class="js-close">Close issuable</button>
+ <a class="js-new" href="/gitlab-org/gitlab-shell/-/issues/new">New issuable</a>
+ `,
+ 'edit-form-actions': `
+ <button class="js-save">Save changes</button>
+ <button class="js-cancel">Cancel</button>
+ `,
+ 'right-sidebar-items': `
+ <div class="js-todo">
+ To Do <button class="js-add-todo">Add a To Do</button>
+ </div>
+ `,
+ },
+ });
+
+describe('IssuableShowRoot', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('template', () => {
+ const {
+ statusBadgeClass,
+ statusIcon,
+ enableEdit,
+ enableAutocomplete,
+ editFormVisible,
+ descriptionPreviewPath,
+ descriptionHelpPath,
+ } = mockIssuableShowProps;
+ const { blocked, confidential, createdAt, author } = mockIssuable;
+
+ it('renders component container element with class `issuable-show-container`', () => {
+ expect(wrapper.classes()).toContain('issuable-show-container');
+ });
+
+ it('renders issuable-header component', () => {
+ const issuableHeader = wrapper.find(IssuableHeader);
+
+ expect(issuableHeader.exists()).toBe(true);
+ expect(issuableHeader.props()).toMatchObject({
+ statusBadgeClass,
+ statusIcon,
+ blocked,
+ confidential,
+ createdAt,
+ author,
+ });
+ expect(issuableHeader.find('.issuable-status-box').text()).toContain('Open');
+ expect(issuableHeader.find('.detail-page-header-actions button.js-close').exists()).toBe(
+ true,
+ );
+ expect(issuableHeader.find('.detail-page-header-actions a.js-new').exists()).toBe(true);
+ });
+
+ it('renders issuable-body component', () => {
+ const issuableBody = wrapper.find(IssuableBody);
+
+ expect(issuableBody.exists()).toBe(true);
+ expect(issuableBody.props()).toMatchObject({
+ issuable: mockIssuable,
+ statusBadgeClass,
+ statusIcon,
+ enableEdit,
+ enableAutocomplete,
+ editFormVisible,
+ descriptionPreviewPath,
+ descriptionHelpPath,
+ });
+ });
+
+ it('renders issuable-sidebar component', () => {
+ const issuableSidebar = wrapper.find(IssuableSidebar);
+
+ expect(issuableSidebar.exists()).toBe(true);
+ });
+
+ describe('events', () => {
+ it('component emits `edit-issuable` event bubbled via issuable-body', () => {
+ const issuableBody = wrapper.find(IssuableBody);
+
+ issuableBody.vm.$emit('edit-issuable');
+
+ expect(wrapper.emitted('edit-issuable')).toBeTruthy();
+ });
+
+ it('component emits `sidebar-toggle` event bubbled via issuable-sidebar', () => {
+ const issuableSidebar = wrapper.find(IssuableSidebar);
+
+ issuableSidebar.vm.$emit('sidebar-toggle', true);
+
+ expect(wrapper.emitted('sidebar-toggle')).toBeTruthy();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/components/issuable_title_spec.js b/spec/frontend/issuable_show/components/issuable_title_spec.js
new file mode 100644
index 00000000000..e8621c763b3
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_title_spec.js
@@ -0,0 +1,100 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon, GlButton, GlIntersectionObserver } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+
+import IssuableTitle from '~/issuable_show/components/issuable_title.vue';
+
+import { mockIssuableShowProps, mockIssuable } from '../mock_data';
+
+const issuableTitleProps = {
+ issuable: mockIssuable,
+ ...mockIssuableShowProps,
+};
+
+const createComponent = (propsData = issuableTitleProps) =>
+ shallowMount(IssuableTitle, {
+ propsData,
+ stubs: {
+ transition: true,
+ },
+ slots: {
+ 'status-badge': 'Open',
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+
+describe('IssuableTitle', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('methods', () => {
+ describe('handleTitleAppear', () => {
+ it('sets value of `stickyTitleVisible` prop to false', () => {
+ wrapper.find(GlIntersectionObserver).vm.$emit('appear');
+
+ expect(wrapper.vm.stickyTitleVisible).toBe(false);
+ });
+ });
+
+ describe('handleTitleDisappear', () => {
+ it('sets value of `stickyTitleVisible` prop to true', () => {
+ wrapper.find(GlIntersectionObserver).vm.$emit('disappear');
+
+ expect(wrapper.vm.stickyTitleVisible).toBe(true);
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('renders issuable title', async () => {
+ const wrapperWithTitle = createComponent({
+ ...mockIssuableShowProps,
+ issuable: {
+ ...mockIssuable,
+ titleHtml: '<b>Sample</b> title',
+ },
+ });
+
+ await wrapperWithTitle.vm.$nextTick();
+ const titleEl = wrapperWithTitle.find('h2');
+
+ expect(titleEl.exists()).toBe(true);
+ expect(titleEl.html()).toBe('<h2 dir="auto" class="title qa-title"><b>Sample</b> title</h2>');
+
+ wrapperWithTitle.destroy();
+ });
+
+ it('renders edit button', () => {
+ const editButtonEl = wrapper.find(GlButton);
+ const tooltip = getBinding(editButtonEl.element, 'gl-tooltip');
+
+ expect(editButtonEl.exists()).toBe(true);
+ expect(editButtonEl.props('icon')).toBe('pencil');
+ expect(editButtonEl.attributes('title')).toBe('Edit title and description');
+ expect(tooltip).toBeDefined();
+ });
+
+ it('renders sticky header when `stickyTitleVisible` prop is true', async () => {
+ wrapper.setData({
+ stickyTitleVisible: true,
+ });
+
+ await wrapper.vm.$nextTick();
+ const stickyHeaderEl = wrapper.find('[data-testid="header"]');
+
+ expect(stickyHeaderEl.exists()).toBe(true);
+ expect(stickyHeaderEl.find(GlIcon).props('name')).toBe(issuableTitleProps.statusIcon);
+ expect(stickyHeaderEl.text()).toContain('Open');
+ expect(stickyHeaderEl.text()).toContain(issuableTitleProps.issuable.title);
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/mock_data.js b/spec/frontend/issuable_show/mock_data.js
new file mode 100644
index 00000000000..14e5febdc6b
--- /dev/null
+++ b/spec/frontend/issuable_show/mock_data.js
@@ -0,0 +1,34 @@
+import { mockIssuable as issuable } from '../issuable_list/mock_data';
+
+export const mockIssuable = {
+ ...issuable,
+ id: 'gid://gitlab/Issue/30',
+ title: 'Sample title',
+ titleHtml: 'Sample title',
+ description: '# Summary',
+ descriptionHtml:
+ '<h1 data-sourcepos="1:1-1:25" dir="auto">&#x000A;<a id="user-content-magnoque-it-lurida-deus" class="anchor" href="#magnoque-it-lurida-deus" aria-hidden="true"></a>Summary</h1>',
+ state: 'opened',
+ blocked: false,
+ confidential: false,
+ updatedBy: issuable.author,
+ currentUserTodos: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Todo/489',
+ state: 'done',
+ },
+ ],
+ },
+};
+
+export const mockIssuableShowProps = {
+ issuable: mockIssuable,
+ descriptionHelpPath: '/help/user/markdown',
+ descriptionPreviewPath: '/gitlab-org/gitlab-shell/preview_markdown',
+ editFormVisible: false,
+ enableAutocomplete: true,
+ enableEdit: true,
+ statusBadgeClass: 'status-box-open',
+ statusIcon: 'issue-open-m',
+};