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:
Diffstat (limited to 'spec/frontend/notes')
-rw-r--r--spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap8
-rw-r--r--spec/frontend/notes/components/comment_form_spec.js29
-rw-r--r--spec/frontend/notes/components/diff_discussion_header_spec.js2
-rw-r--r--spec/frontend/notes/components/discussion_actions_spec.js2
-rw-r--r--spec/frontend/notes/components/note_header_spec.js99
-rw-r--r--spec/frontend/notes/components/noteable_note_spec.js2
-rw-r--r--spec/frontend/notes/components/notes_activity_header_spec.js67
-rw-r--r--spec/frontend/notes/components/notes_app_spec.js31
-rw-r--r--spec/frontend/notes/mixins/discussion_navigation_spec.js141
-rw-r--r--spec/frontend/notes/mock_data.js17
-rw-r--r--spec/frontend/notes/utils/get_notes_filter_data_spec.js44
11 files changed, 216 insertions, 226 deletions
diff --git a/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap b/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap
index 5f4b3e04a79..bc29903d4bf 100644
--- a/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap
+++ b/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap
@@ -3,15 +3,15 @@
exports[`note_app when sort direction is asc shows skeleton notes after the loaded discussions 1`] = `
"<ul id=\\"notes-list\\" class=\\"notes main-notes-list timeline\\">
<noteable-discussion-stub discussion=\\"[object Object]\\" renderdifffile=\\"true\\" helppagepath=\\"\\" isoverviewtab=\\"true\\"></noteable-discussion-stub>
- <skeleton-loading-container-stub></skeleton-loading-container-stub>
- <discussion-filter-note-stub style=\\"display: none;\\"></discussion-filter-note-stub>
+ <skeleton-loading-container-stub class=\\"note-skeleton\\"></skeleton-loading-container-stub>
+ <!---->
</ul>"
`;
exports[`note_app when sort direction is desc shows skeleton notes before the loaded discussions 1`] = `
"<ul id=\\"notes-list\\" class=\\"notes main-notes-list timeline\\">
- <skeleton-loading-container-stub></skeleton-loading-container-stub>
+ <skeleton-loading-container-stub class=\\"note-skeleton\\"></skeleton-loading-container-stub>
<noteable-discussion-stub discussion=\\"[object Object]\\" renderdifffile=\\"true\\" helppagepath=\\"\\" isoverviewtab=\\"true\\"></noteable-discussion-stub>
- <discussion-filter-note-stub style=\\"display: none;\\"></discussion-filter-note-stub>
+ <!---->
</ul>"
`;
diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js
index 55e4ef42e37..701ff492702 100644
--- a/spec/frontend/notes/components/comment_form_spec.js
+++ b/spec/frontend/notes/components/comment_form_spec.js
@@ -7,7 +7,7 @@ import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import batchComments from '~/batch_comments/stores/modules/batch_comments';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import CommentForm from '~/notes/components/comment_form.vue';
import CommentTypeDropdown from '~/notes/components/comment_type_dropdown.vue';
@@ -71,11 +71,19 @@ describe('issue_comment_form component', () => {
};
const notableDataMockCanUpdateIssuable = createNotableDataMock({
- current_user: { can_update: true, can_create_note: true },
+ current_user: { can_update: true, can_create_note: true, can_create_confidential_note: true },
});
const notableDataMockCannotUpdateIssuable = createNotableDataMock({
- current_user: { can_update: false, can_create_note: true },
+ current_user: {
+ can_update: false,
+ can_create_note: false,
+ can_create_confidential_note: false,
+ },
+ });
+
+ const notableDataMockCannotCreateConfidentialNote = createNotableDataMock({
+ current_user: { can_update: false, can_create_note: true, can_create_confidential_note: false },
});
const mountComponent = ({
@@ -490,7 +498,7 @@ describe('issue_comment_form component', () => {
await nextTick();
await nextTick();
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: `Something went wrong while closing the ${type}. Please try again later.`,
});
});
@@ -526,7 +534,7 @@ describe('issue_comment_form component', () => {
await nextTick();
await nextTick();
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: `Something went wrong while reopening the ${type}. Please try again later.`,
});
});
@@ -562,6 +570,17 @@ describe('issue_comment_form component', () => {
expect(checkbox.element.checked).toBe(false);
});
+ it('should not render checkbox if user is not at least a reporter', () => {
+ mountComponent({
+ mountFunction: mount,
+ initialData: { note: 'confidential note' },
+ noteableData: { ...notableDataMockCannotCreateConfidentialNote },
+ });
+
+ const checkbox = findConfidentialNoteCheckbox();
+ expect(checkbox.exists()).toBe(false);
+ });
+
it.each`
noteableType | rendered | message
${'Issue'} | ${true} | ${'render'}
diff --git a/spec/frontend/notes/components/diff_discussion_header_spec.js b/spec/frontend/notes/components/diff_discussion_header_spec.js
index 5800f68b114..bb44563b87a 100644
--- a/spec/frontend/notes/components/diff_discussion_header_spec.js
+++ b/spec/frontend/notes/components/diff_discussion_header_spec.js
@@ -42,7 +42,7 @@ describe('diff_discussion_header component', () => {
expect(props).toMatchObject({
src: firstNoteAuthor.avatar_url,
alt: firstNoteAuthor.name,
- size: { default: 24, md: 32 },
+ size: 32,
});
});
});
diff --git a/spec/frontend/notes/components/discussion_actions_spec.js b/spec/frontend/notes/components/discussion_actions_spec.js
index d16c13d6fd3..e414ada1854 100644
--- a/spec/frontend/notes/components/discussion_actions_spec.js
+++ b/spec/frontend/notes/components/discussion_actions_spec.js
@@ -81,7 +81,7 @@ describe('DiscussionActions', () => {
});
});
- it(shouldRender ? 'renders resolve buttons' : 'does not render resolve buttons', () => {
+ it(`${shouldRender ? 'renders' : 'does not render'} resolve buttons`, () => {
expect(wrapper.findComponent(ResolveDiscussionButton).exists()).toBe(shouldRender);
expect(wrapper.findComponent(ResolveWithIssueButton).exists()).toBe(shouldRender);
});
diff --git a/spec/frontend/notes/components/note_header_spec.js b/spec/frontend/notes/components/note_header_spec.js
index 76177229cff..b870cda2a24 100644
--- a/spec/frontend/notes/components/note_header_spec.js
+++ b/spec/frontend/notes/components/note_header_spec.js
@@ -1,10 +1,7 @@
-import { GlSprintf } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import NoteHeader from '~/notes/components/note_header.vue';
-import { AVAILABILITY_STATUS } from '~/set_status_modal/constants';
-import UserNameWithStatus from '~/sidebar/components/assignees/user_name_with_status.vue';
Vue.use(Vuex);
@@ -23,7 +20,6 @@ describe('NoteHeader component', () => {
const findTimestamp = () => wrapper.findComponent({ ref: 'noteTimestamp' });
const findInternalNoteIndicator = () => wrapper.findByTestId('internalNoteIndicator');
const findSpinner = () => wrapper.findComponent({ ref: 'spinner' });
- const findAuthorStatus = () => wrapper.findComponent({ ref: 'authorStatus' });
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>"';
@@ -37,22 +33,14 @@ describe('NoteHeader component', () => {
username: 'root',
show_status: true,
status_tooltip_html: statusHtml,
- availability: '',
};
- const createComponent = (props, userAttributes = false) => {
+ const createComponent = (props) => {
wrapper = shallowMountExtended(NoteHeader, {
store: new Vuex.Store({
actions,
}),
propsData: { ...props },
- stubs: { GlSprintf, UserNameWithStatus },
- provide: {
- glFeatures: {
- removeUserAttributesProjects: userAttributes,
- removeUserAttributesGroups: userAttributes,
- },
- },
});
};
@@ -61,26 +49,6 @@ describe('NoteHeader component', () => {
wrapper = null;
});
- describe('when removeUserAttributesProjects feature flag is enabled', () => {
- it('does not render busy status', () => {
- createComponent({ author: { ...author, availability: AVAILABILITY_STATUS.BUSY } }, true);
-
- expect(wrapper.find('.note-header-info').text()).not.toContain('(Busy)');
- });
-
- it('does not render author status', () => {
- createComponent({ author }, true);
-
- expect(findAuthorStatus().exists()).toBe(false);
- });
-
- it('does not render username', () => {
- createComponent({ author }, true);
-
- expect(wrapper.find('.note-header-info').text()).not.toContain('@');
- });
- });
-
it('does not render discussion actions when includeToggle is false', () => {
createComponent({
includeToggle: false,
@@ -145,39 +113,6 @@ describe('NoteHeader component', () => {
expect(wrapper.find('.js-user-link').exists()).toBe(true);
});
-
- it('renders busy status if author availability is set', () => {
- createComponent({ author: { ...author, availability: AVAILABILITY_STATUS.BUSY } });
-
- expect(wrapper.find('.js-user-link').text()).toContain('(Busy)');
- });
-
- it('renders author status', () => {
- createComponent({ author });
-
- expect(findAuthorStatus().exists()).toBe(true);
- });
-
- it('does not render author status if show_status=false', () => {
- createComponent({
- author: { ...author, status: { availability: AVAILABILITY_STATUS.BUSY }, show_status: false },
- });
-
- expect(findAuthorStatus().exists()).toBe(false);
- });
-
- it('does not render author status if status_tooltip_html=null', () => {
- createComponent({
- author: {
- ...author,
- status: { availability: AVAILABILITY_STATUS.BUSY },
- status_tooltip_html: null,
- },
- });
-
- expect(findAuthorStatus().exists()).toBe(false);
- });
-
it('renders deleted user text if author is not passed as a prop', () => {
createComponent();
@@ -270,24 +205,6 @@ describe('NoteHeader component', () => {
});
});
- describe('when author status tooltip is opened', () => {
- it('removes `title` attribute from emoji to prevent duplicate tooltips', () => {
- createComponent({
- author: {
- ...author,
- status_tooltip_html: statusHtml,
- },
- });
-
- return nextTick().then(() => {
- const authorStatus = findAuthorStatus();
- authorStatus.trigger('mouseenter');
-
- expect(authorStatus.find('gl-emoji').attributes('title')).toBeUndefined();
- });
- });
- });
-
describe('when author username link is hovered', () => {
it('toggles hover specific CSS classes on author name link', async () => {
createComponent({ author });
@@ -327,4 +244,18 @@ describe('NoteHeader component', () => {
);
});
});
+
+ 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('@');
+ });
+ });
});
diff --git a/spec/frontend/notes/components/noteable_note_spec.js b/spec/frontend/notes/components/noteable_note_spec.js
index b044d40cbe4..3d7195752d3 100644
--- a/spec/frontend/notes/components/noteable_note_spec.js
+++ b/spec/frontend/notes/components/noteable_note_spec.js
@@ -214,7 +214,7 @@ describe('issue_note', () => {
expect(avatarProps.src).toBe(author.avatar_url);
expect(avatarProps.entityName).toBe(author.username);
expect(avatarProps.alt).toBe(author.name);
- expect(avatarProps.size).toEqual({ default: 24, md: 32 });
+ expect(avatarProps.size).toEqual(32);
});
it('should render note header content', () => {
diff --git a/spec/frontend/notes/components/notes_activity_header_spec.js b/spec/frontend/notes/components/notes_activity_header_spec.js
new file mode 100644
index 00000000000..5b3165bf401
--- /dev/null
+++ b/spec/frontend/notes/components/notes_activity_header_spec.js
@@ -0,0 +1,67 @@
+import { shallowMount } from '@vue/test-utils';
+import { __ } from '~/locale';
+import NotesActivityHeader from '~/notes/components/notes_activity_header.vue';
+import DiscussionFilter from '~/notes/components/discussion_filter.vue';
+import TimelineToggle from '~/notes/components/timeline_toggle.vue';
+import createStore from '~/notes/stores';
+import waitForPromises from 'helpers/wait_for_promises';
+import { notesFilters } from '../mock_data';
+
+describe('~/notes/components/notes_activity_header.vue', () => {
+ let wrapper;
+
+ const findTitle = () => wrapper.find('h2');
+
+ const createComponent = ({ props = {}, ...options } = {}) => {
+ wrapper = shallowMount(NotesActivityHeader, {
+ propsData: {
+ notesFilters,
+ ...props,
+ },
+ // why: Rendering async timeline toggle requires store
+ store: createStore(),
+ ...options,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('default', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders title', () => {
+ expect(findTitle().text()).toBe(__('Activity'));
+ });
+
+ it('renders discussion filter', () => {
+ expect(wrapper.findComponent(DiscussionFilter).props()).toEqual({
+ filters: notesFilters,
+ selectedValue: 0,
+ });
+ });
+
+ it('does not render timeline toggle', () => {
+ expect(wrapper.findComponent(TimelineToggle).exists()).toBe(false);
+ });
+ });
+
+ it('with notesFilterValue prop, passes to discussion filter', () => {
+ createComponent({ props: { notesFilterValue: 1 } });
+
+ expect(wrapper.findComponent(DiscussionFilter).props('selectedValue')).toBe(1);
+ });
+
+ it('with showTimelineViewToggle injected, renders timeline toggle asynchronously', async () => {
+ createComponent({ provide: { showTimelineViewToggle: () => true } });
+
+ expect(wrapper.findComponent(TimelineToggle).exists()).toBe(false);
+
+ await waitForPromises();
+
+ expect(wrapper.findComponent(TimelineToggle).exists()).toBe(true);
+ });
+});
diff --git a/spec/frontend/notes/components/notes_app_spec.js b/spec/frontend/notes/components/notes_app_spec.js
index d4cb07d97dc..9051fcab97f 100644
--- a/spec/frontend/notes/components/notes_app_spec.js
+++ b/spec/frontend/notes/components/notes_app_spec.js
@@ -11,6 +11,7 @@ import axios from '~/lib/utils/axios_utils';
import * as urlUtility from '~/lib/utils/url_utility';
import CommentForm from '~/notes/components/comment_form.vue';
import NotesApp from '~/notes/components/notes_app.vue';
+import NotesActivityHeader from '~/notes/components/notes_activity_header.vue';
import * as constants from '~/notes/constants';
import createStore from '~/notes/stores';
import '~/behaviors/markdown/render_gfm';
@@ -20,11 +21,14 @@ import * as mockData from '../mock_data';
const TYPE_COMMENT_FORM = 'comment-form';
const TYPE_NOTES_LIST = 'notes-list';
+const TEST_NOTES_FILTER_VALUE = 1;
const propsData = {
noteableData: mockData.noteableDataMock,
notesData: mockData.notesDataMock,
userData: mockData.userDataMock,
+ notesFilters: mockData.notesFilters,
+ notesFilterValue: TEST_NOTES_FILTER_VALUE,
};
describe('note_app', () => {
@@ -47,7 +51,7 @@ describe('note_app', () => {
axiosMock = new AxiosMockAdapter(axios);
store = createStore();
- mountComponent = () => {
+ mountComponent = ({ props = {} } = {}) => {
return mount(
{
components: {
@@ -58,7 +62,10 @@ describe('note_app', () => {
</div>`,
},
{
- propsData,
+ propsData: {
+ ...propsData,
+ ...props,
+ },
store,
},
);
@@ -144,6 +151,13 @@ describe('note_app', () => {
it('updates discussions badge', () => {
expect(document.querySelector('.js-discussions-count').textContent).toEqual('2');
});
+
+ it('should render notes activity header', () => {
+ expect(wrapper.findComponent(NotesActivityHeader).props()).toEqual({
+ notesFilterValue: TEST_NOTES_FILTER_VALUE,
+ notesFilters: mockData.notesFilters,
+ });
+ });
});
describe('render with comments disabled', () => {
@@ -151,8 +165,15 @@ describe('note_app', () => {
setHTMLFixture('<div class="js-discussions-count"></div>');
axiosMock.onAny().reply(mockData.getIndividualNoteResponse);
- store.state.commentsDisabled = true;
- wrapper = mountComponent();
+ wrapper = mountComponent({
+ // why: In this integration test, previously we manually set store.state.commentsDisabled
+ // This stopped working when we added `<discussion-filter>` into the component tree.
+ // Let's lean into the integration scope and use a prop that "disables comments".
+ props: {
+ notesFilterValue: constants.HISTORY_ONLY_FILTER_VALUE,
+ },
+ });
+
return waitForPromises();
});
@@ -358,7 +379,7 @@ describe('note_app', () => {
it('should listen hashchange event', () => {
const notesApp = wrapper.findComponent(NotesApp);
const hash = 'some dummy hash';
- jest.spyOn(urlUtility, 'getLocationHash').mockReturnValueOnce(hash);
+ jest.spyOn(urlUtility, 'getLocationHash').mockReturnValue(hash);
const setTargetNoteHash = jest.spyOn(notesApp.vm, 'setTargetNoteHash');
window.dispatchEvent(new Event('hashchange'), hash);
diff --git a/spec/frontend/notes/mixins/discussion_navigation_spec.js b/spec/frontend/notes/mixins/discussion_navigation_spec.js
index 1b4e8026d84..45625d0a23f 100644
--- a/spec/frontend/notes/mixins/discussion_navigation_spec.js
+++ b/spec/frontend/notes/mixins/discussion_navigation_spec.js
@@ -4,7 +4,6 @@ import Vuex from 'vuex';
import { setHTMLFixture } from 'helpers/fixtures';
import createEventHub from '~/helpers/event_hub_factory';
import * as utils from '~/lib/utils/common_utils';
-import eventHub from '~/notes/event_hub';
import discussionNavigation from '~/notes/mixins/discussion_navigation';
import notesModule from '~/notes/stores/modules';
@@ -35,13 +34,15 @@ describe('Discussion navigation mixin', () => {
beforeEach(() => {
setHTMLFixture(
- [...'abcde']
+ `<div class="notes">
+ ${[...'abcde']
.map(
(id) =>
`<ul class="notes" data-discussion-id="${id}"></ul>
<div class="discussion" data-discussion-id="${id}"></div>`,
)
- .join(''),
+ .join('')}
+ </div>`,
);
jest.spyOn(utils, 'scrollToElementWithContext');
@@ -58,7 +59,7 @@ describe('Discussion navigation mixin', () => {
},
diffs: {
namespaced: true,
- actions: { scrollToFile },
+ actions: { scrollToFile, disableVirtualScroller: () => {} },
state: { diffFiles: [] },
},
},
@@ -73,9 +74,6 @@ describe('Discussion navigation mixin', () => {
jest.clearAllMocks();
});
- const findDiscussion = (selector, id) =>
- document.querySelector(`${selector}[data-discussion-id="${id}"]`);
-
describe('jumpToFirstUnresolvedDiscussion method', () => {
let vm;
@@ -110,14 +108,14 @@ describe('Discussion navigation mixin', () => {
});
describe.each`
- fn | args | currentId | expected
- ${'jumpToNextDiscussion'} | ${[]} | ${null} | ${'a'}
- ${'jumpToNextDiscussion'} | ${[]} | ${'a'} | ${'c'}
- ${'jumpToNextDiscussion'} | ${[]} | ${'e'} | ${'a'}
- ${'jumpToPreviousDiscussion'} | ${[]} | ${null} | ${'e'}
- ${'jumpToPreviousDiscussion'} | ${[]} | ${'e'} | ${'c'}
- ${'jumpToPreviousDiscussion'} | ${[]} | ${'c'} | ${'a'}
- `('$fn (args = $args, currentId = $currentId)', ({ fn, args, currentId, expected }) => {
+ fn | args | currentId
+ ${'jumpToNextDiscussion'} | ${[]} | ${null}
+ ${'jumpToNextDiscussion'} | ${[]} | ${'a'}
+ ${'jumpToNextDiscussion'} | ${[]} | ${'e'}
+ ${'jumpToPreviousDiscussion'} | ${[]} | ${null}
+ ${'jumpToPreviousDiscussion'} | ${[]} | ${'e'}
+ ${'jumpToPreviousDiscussion'} | ${[]} | ${'c'}
+ `('$fn (args = $args, currentId = $currentId)', ({ fn, args, currentId }) => {
beforeEach(() => {
store.state.notes.currentDiscussionId = currentId;
});
@@ -130,125 +128,18 @@ describe('Discussion navigation mixin', () => {
await nextTick();
});
- it('expands discussion', () => {
- expect(expandDiscussion).toHaveBeenCalled();
- });
-
- it('scrolls to element', () => {
- expect(utils.scrollToElement).toHaveBeenCalled();
- });
- });
-
- describe('on `diffs` active tab', () => {
- beforeEach(async () => {
- window.mrTabs.currentAction = 'diffs';
- wrapper.vm[fn](...args);
-
+ it('expands discussion', async () => {
await nextTick();
- });
- it('sets current discussion', () => {
- expect(store.state.notes.currentDiscussionId).toEqual(expected);
- });
-
- it('expands discussion', () => {
expect(expandDiscussion).toHaveBeenCalled();
});
- it('scrolls when scrollToDiscussion is emitted', () => {
- expect(utils.scrollToElementWithContext).not.toHaveBeenCalled();
-
- eventHub.$emit('scrollToDiscussion');
-
- expect(utils.scrollToElementWithContext).toHaveBeenCalledWith(
- findDiscussion('ul.notes', expected),
- { behavior: 'auto', offset: 0 },
- );
- });
- });
-
- describe('on `other` active tab', () => {
- beforeEach(async () => {
- window.mrTabs.currentAction = 'other';
- wrapper.vm[fn](...args);
-
+ it('scrolls to element', async () => {
await nextTick();
- });
- it('sets current discussion', () => {
- expect(store.state.notes.currentDiscussionId).toEqual(expected);
- });
-
- it('does not expand discussion yet', () => {
- expect(expandDiscussion).not.toHaveBeenCalled();
- });
-
- it('shows mrTabs', () => {
- expect(window.mrTabs.tabShown).toHaveBeenCalledWith('show');
- });
-
- describe('when tab is changed', () => {
- beforeEach(() => {
- window.mrTabs.eventHub.$emit('MergeRequestTabChange');
-
- jest.runAllTimers();
- });
-
- it('expands discussion', () => {
- expect(expandDiscussion).toHaveBeenCalledWith(expect.anything(), {
- discussionId: expected,
- });
- });
-
- it('scrolls to discussion', () => {
- expect(utils.scrollToElement).toHaveBeenCalledWith(
- findDiscussion('div.discussion', expected),
- { behavior: 'auto', offset: 0 },
- );
- });
+ expect(utils.scrollToElement).toHaveBeenCalled();
});
});
});
-
- describe('virtual scrolling feature', () => {
- beforeEach(() => {
- jest.spyOn(store, 'dispatch');
-
- store.state.notes.currentDiscussionId = 'a';
- window.location.hash = 'test';
- });
-
- afterEach(() => {
- window.gon = {};
- window.location.hash = '';
- });
-
- it('resets location hash', async () => {
- wrapper.vm.jumpToNextDiscussion();
-
- await nextTick();
-
- expect(window.location.hash).toBe('');
- });
-
- it.each`
- tabValue
- ${'diffs'}
- ${'other'}
- `(
- 'calls scrollToFile with setHash as $hashValue when the tab is $tabValue',
- async ({ tabValue }) => {
- window.mrTabs.currentAction = tabValue;
-
- wrapper.vm.jumpToNextDiscussion();
-
- await nextTick();
-
- expect(store.dispatch).toHaveBeenCalledWith('diffs/scrollToFile', {
- path: 'test.js',
- });
- },
- );
- });
});
});
diff --git a/spec/frontend/notes/mock_data.js b/spec/frontend/notes/mock_data.js
index 9fa7166474a..286f2adc1d8 100644
--- a/spec/frontend/notes/mock_data.js
+++ b/spec/frontend/notes/mock_data.js
@@ -1,4 +1,5 @@
// Copied to ee/spec/frontend/notes/mock_data.js
+import { __ } from '~/locale';
export const notesDataMock = {
discussionsPath: '/gitlab-org/gitlab-foss/issues/26/discussions.json',
@@ -35,6 +36,7 @@ export const noteableDataMock = {
can_create_note: true,
can_update: true,
can_award_emoji: true,
+ can_create_confidential_note: true,
},
description: '',
due_date: null,
@@ -1292,3 +1294,18 @@ export const draftDiffDiscussion = {
file_path: 'lib/foo.rb',
isDraft: true,
};
+
+export const notesFilters = [
+ {
+ title: __('Show all activity'),
+ value: 0,
+ },
+ {
+ title: __('Show comments only'),
+ value: 1,
+ },
+ {
+ title: __('Show history only'),
+ value: 2,
+ },
+];
diff --git a/spec/frontend/notes/utils/get_notes_filter_data_spec.js b/spec/frontend/notes/utils/get_notes_filter_data_spec.js
new file mode 100644
index 00000000000..c3a8d3bc619
--- /dev/null
+++ b/spec/frontend/notes/utils/get_notes_filter_data_spec.js
@@ -0,0 +1,44 @@
+import { getNotesFilterData } from '~/notes/utils/get_notes_filter_data';
+import { notesFilters } from '../mock_data';
+
+// what: This is the format we expect the element attribute to be in
+// why: For readability, we make this clear by hardcoding the indecise instead of using `reduce`.
+const TEST_NOTES_FILTERS_ATTR = {
+ [notesFilters[0].title]: notesFilters[0].value,
+ [notesFilters[1].title]: notesFilters[1].value,
+ [notesFilters[2].title]: notesFilters[2].value,
+};
+
+describe('~/notes/utils/get_notes_filter_data', () => {
+ it.each([
+ {
+ desc: 'empty',
+ attributes: {},
+ expectation: {
+ notesFilters: [],
+ notesFilterValue: undefined,
+ },
+ },
+ {
+ desc: 'valid attributes',
+ attributes: {
+ 'data-notes-filters': JSON.stringify(TEST_NOTES_FILTERS_ATTR),
+ 'data-notes-filter-value': '1',
+ },
+ expectation: {
+ notesFilters,
+ notesFilterValue: 1,
+ },
+ },
+ ])('with $desc, parses data from element attributes', ({ attributes, expectation }) => {
+ const el = document.createElement('div');
+
+ Object.entries(attributes).forEach(([key, value]) => {
+ el.setAttribute(key, value);
+ });
+
+ const actual = getNotesFilterData(el);
+
+ expect(actual).toStrictEqual(expectation);
+ });
+});