summaryrefslogtreecommitdiff
path: root/spec/frontend/notes
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/notes')
-rw-r--r--spec/frontend/notes/components/discussion_counter_spec.js28
-rw-r--r--spec/frontend/notes/components/discussion_filter_spec.js38
-rw-r--r--spec/frontend/notes/components/notes_app_spec.js17
-rw-r--r--spec/frontend/notes/components/sort_discussion_spec.js22
-rw-r--r--spec/frontend/notes/components/timeline_toggle_spec.js117
-rw-r--r--spec/frontend/notes/stores/actions_spec.js9
-rw-r--r--spec/frontend/notes/stores/getters_spec.js13
-rw-r--r--spec/frontend/notes/stores/mutation_spec.js3
8 files changed, 205 insertions, 42 deletions
diff --git a/spec/frontend/notes/components/discussion_counter_spec.js b/spec/frontend/notes/components/discussion_counter_spec.js
index affd6c1d1d2..d82590c7e9e 100644
--- a/spec/frontend/notes/components/discussion_counter_spec.js
+++ b/spec/frontend/notes/components/discussion_counter_spec.js
@@ -1,6 +1,6 @@
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
-import { GlIcon } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import notesModule from '~/notes/stores/modules';
import DiscussionCounter from '~/notes/components/discussion_counter.vue';
import { noteableDataMock, discussionMock, notesDataMock, userDataMock } from '../mock_data';
@@ -9,6 +9,7 @@ import * as types from '~/notes/stores/mutation_types';
describe('DiscussionCounter component', () => {
let store;
let wrapper;
+ let setExpandDiscussionsFn;
const localVue = createLocalVue();
localVue.use(Vuex);
@@ -16,6 +17,7 @@ describe('DiscussionCounter component', () => {
beforeEach(() => {
window.mrTabs = {};
const { state, getters, mutations, actions } = notesModule();
+ setExpandDiscussionsFn = jest.fn().mockImplementation(actions.setExpandDiscussions);
store = new Vuex.Store({
state: {
@@ -24,7 +26,10 @@ describe('DiscussionCounter component', () => {
},
getters,
mutations,
- actions,
+ actions: {
+ ...actions,
+ setExpandDiscussions: setExpandDiscussionsFn,
+ },
});
store.dispatch('setNoteableData', {
...noteableDataMock,
@@ -84,7 +89,7 @@ describe('DiscussionCounter component', () => {
wrapper = shallowMount(DiscussionCounter, { store, localVue });
expect(wrapper.find(`.is-active`).exists()).toBe(isActive);
- expect(wrapper.findAll('[role="group"').length).toBe(groupLength);
+ expect(wrapper.findAll(GlButton)).toHaveLength(groupLength);
});
});
@@ -103,23 +108,22 @@ describe('DiscussionCounter component', () => {
it('calls button handler when clicked', () => {
updateStoreWithExpanded(true);
- wrapper.setMethods({ handleExpandDiscussions: jest.fn() });
- toggleAllButton.trigger('click');
+ toggleAllButton.vm.$emit('click');
- expect(wrapper.vm.handleExpandDiscussions).toHaveBeenCalledTimes(1);
+ expect(setExpandDiscussionsFn).toHaveBeenCalledTimes(1);
});
it('collapses all discussions if expanded', () => {
updateStoreWithExpanded(true);
expect(wrapper.vm.allExpanded).toBe(true);
- expect(toggleAllButton.find(GlIcon).props().name).toBe('angle-up');
+ expect(toggleAllButton.props('icon')).toBe('angle-up');
- toggleAllButton.trigger('click');
+ toggleAllButton.vm.$emit('click');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.allExpanded).toBe(false);
- expect(toggleAllButton.find(GlIcon).props().name).toBe('angle-down');
+ expect(toggleAllButton.props('icon')).toBe('angle-down');
});
});
@@ -127,13 +131,13 @@ describe('DiscussionCounter component', () => {
updateStoreWithExpanded(false);
expect(wrapper.vm.allExpanded).toBe(false);
- expect(toggleAllButton.find(GlIcon).props().name).toBe('angle-down');
+ expect(toggleAllButton.props('icon')).toBe('angle-down');
- toggleAllButton.trigger('click');
+ toggleAllButton.vm.$emit('click');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.allExpanded).toBe(true);
- expect(toggleAllButton.find(GlIcon).props().name).toBe('angle-up');
+ expect(toggleAllButton.props('icon')).toBe('angle-up');
});
});
});
diff --git a/spec/frontend/notes/components/discussion_filter_spec.js b/spec/frontend/notes/components/discussion_filter_spec.js
index 91ff796b9de..9f3655c53b9 100644
--- a/spec/frontend/notes/components/discussion_filter_spec.js
+++ b/spec/frontend/notes/components/discussion_filter_spec.js
@@ -25,6 +25,8 @@ describe('DiscussionFilter component', () => {
const filterDiscussion = jest.fn();
+ const findFilter = filterType => wrapper.find(`.dropdown-item[data-filter-type="${filterType}"]`);
+
const mountComponent = () => {
const discussions = [
{
@@ -74,22 +76,22 @@ describe('DiscussionFilter component', () => {
});
it('renders the all filters', () => {
- expect(wrapper.findAll('.dropdown-menu li').length).toBe(discussionFiltersMock.length);
+ expect(wrapper.findAll('.discussion-filter-container .dropdown-item').length).toBe(
+ discussionFiltersMock.length,
+ );
});
it('renders the default selected item', () => {
expect(
wrapper
- .find('#discussion-filter-dropdown')
+ .find('#discussion-filter-dropdown .dropdown-item')
.text()
.trim(),
).toBe(discussionFiltersMock[0].title);
});
it('updates to the selected item', () => {
- const filterItem = wrapper.find(
- `.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.HISTORY}"] button`,
- );
+ const filterItem = findFilter(DISCUSSION_FILTER_TYPES.ALL);
filterItem.trigger('click');
@@ -97,37 +99,37 @@ describe('DiscussionFilter component', () => {
});
it('only updates when selected filter changes', () => {
- wrapper
- .find(`.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.ALL}"] button`)
- .trigger('click');
+ findFilter(DISCUSSION_FILTER_TYPES.ALL).trigger('click');
expect(filterDiscussion).not.toHaveBeenCalled();
});
+ it('disables timeline view if it was enabled', () => {
+ store.state.isTimelineEnabled = true;
+
+ findFilter(DISCUSSION_FILTER_TYPES.HISTORY).trigger('click');
+
+ expect(wrapper.vm.$store.state.isTimelineEnabled).toBe(false);
+ });
+
it('disables commenting when "Show history only" filter is applied', () => {
- const filterItem = wrapper.find(
- `.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.HISTORY}"] button`,
- );
- filterItem.trigger('click');
+ findFilter(DISCUSSION_FILTER_TYPES.HISTORY).trigger('click');
expect(wrapper.vm.$store.state.commentsDisabled).toBe(true);
});
it('enables commenting when "Show history only" filter is not applied', () => {
- const filterItem = wrapper.find(
- `.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.ALL}"] button`,
- );
- filterItem.trigger('click');
+ findFilter(DISCUSSION_FILTER_TYPES.ALL).trigger('click');
expect(wrapper.vm.$store.state.commentsDisabled).toBe(false);
});
it('renders a dropdown divider for the default filter', () => {
const defaultFilter = wrapper.findAll(
- `.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.ALL}"] > *`,
+ `.discussion-filter-container .dropdown-item-wrapper > *`,
);
- expect(defaultFilter.at(defaultFilter.length - 1).classes('dropdown-divider')).toBe(true);
+ expect(defaultFilter.at(1).classes('gl-new-dropdown-divider')).toBe(true);
});
describe('Merge request tabs', () => {
diff --git a/spec/frontend/notes/components/notes_app_spec.js b/spec/frontend/notes/components/notes_app_spec.js
index c6034639a4a..e905a12919e 100644
--- a/spec/frontend/notes/components/notes_app_spec.js
+++ b/spec/frontend/notes/components/notes_app_spec.js
@@ -174,6 +174,23 @@ describe('note_app', () => {
});
});
+ describe('timeline view', () => {
+ beforeEach(() => {
+ setFixtures('<div class="js-discussions-count"></div>');
+
+ axiosMock.onAny().reply(mockData.getIndividualNoteResponse);
+ store.state.commentsDisabled = false;
+ store.state.isTimelineEnabled = true;
+
+ wrapper = mountComponent();
+ return waitForDiscussionsRequest();
+ });
+
+ it('should not render comments form', () => {
+ expect(wrapper.find('.js-main-target-form').exists()).toBe(false);
+ });
+ });
+
describe('while fetching data', () => {
beforeEach(() => {
setFixtures('<div class="js-discussions-count"></div>');
diff --git a/spec/frontend/notes/components/sort_discussion_spec.js b/spec/frontend/notes/components/sort_discussion_spec.js
index 575f1057db2..739e247735d 100644
--- a/spec/frontend/notes/components/sort_discussion_spec.js
+++ b/spec/frontend/notes/components/sort_discussion_spec.js
@@ -46,7 +46,7 @@ describe('Sort Discussion component', () => {
it('calls setDiscussionSortDirection when update is emitted', () => {
findLocalStorageSync().vm.$emit('input', ASC);
- expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', ASC);
+ expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', { direction: ASC });
});
});
@@ -55,9 +55,11 @@ describe('Sort Discussion component', () => {
it('calls the right actions', () => {
createComponent();
- wrapper.find('.js-newest-first').trigger('click');
+ wrapper.find('.js-newest-first').vm.$emit('click');
- expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', DESC);
+ expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', {
+ direction: DESC,
+ });
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'change_discussion_sort_direction', {
property: DESC,
});
@@ -67,7 +69,7 @@ describe('Sort Discussion component', () => {
it('shows the "Oldest First" as the dropdown', () => {
createComponent();
- expect(wrapper.find('.js-dropdown-text').text()).toBe('Oldest first');
+ expect(wrapper.find('.js-dropdown-text').props('text')).toBe('Oldest first');
});
});
@@ -79,21 +81,23 @@ describe('Sort Discussion component', () => {
describe('when the dropdown item is clicked', () => {
it('calls the right actions', () => {
- wrapper.find('.js-oldest-first').trigger('click');
+ wrapper.find('.js-oldest-first').vm.$emit('click');
- expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', ASC);
+ expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', {
+ direction: ASC,
+ });
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'change_discussion_sort_direction', {
property: ASC,
});
});
- it('applies the active class to the correct button in the dropdown', () => {
- expect(wrapper.find('.js-newest-first').classes()).toContain('is-active');
+ it('sets is-checked to true on the active button in the dropdown', () => {
+ expect(wrapper.find('.js-newest-first').props('isChecked')).toBe(true);
});
});
it('shows the "Newest First" as the dropdown', () => {
- expect(wrapper.find('.js-dropdown-text').text()).toBe('Newest first');
+ expect(wrapper.find('.js-dropdown-text').props('text')).toBe('Newest first');
});
});
});
diff --git a/spec/frontend/notes/components/timeline_toggle_spec.js b/spec/frontend/notes/components/timeline_toggle_spec.js
new file mode 100644
index 00000000000..b8df6fc7996
--- /dev/null
+++ b/spec/frontend/notes/components/timeline_toggle_spec.js
@@ -0,0 +1,117 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
+import Vuex from 'vuex';
+import TimelineToggle, {
+ timelineEnabledTooltip,
+ timelineDisabledTooltip,
+} from '~/notes/components/timeline_toggle.vue';
+import createStore from '~/notes/stores';
+import { ASC, DESC } from '~/notes/constants';
+import { trackToggleTimelineView } from '~/notes/utils';
+import Tracking from '~/tracking';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Timeline toggle', () => {
+ let wrapper;
+ let store;
+ const mockEvent = { currentTarget: { blur: jest.fn() } };
+
+ const createComponent = () => {
+ jest.spyOn(store, 'dispatch').mockImplementation();
+ jest.spyOn(Tracking, 'event').mockImplementation();
+
+ wrapper = shallowMount(TimelineToggle, {
+ localVue,
+ store,
+ });
+ };
+
+ const findGlButton = () => wrapper.find(GlButton);
+
+ beforeEach(() => {
+ store = createStore();
+ createComponent();
+ });
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ store.dispatch.mockReset();
+ mockEvent.currentTarget.blur.mockReset();
+ Tracking.event.mockReset();
+ });
+
+ describe('ON state', () => {
+ it('should update timeline flag in the store', () => {
+ store.state.isTimelineEnabled = false;
+ findGlButton().vm.$emit('click', mockEvent);
+ expect(store.dispatch).toHaveBeenCalledWith('setTimelineView', true);
+ });
+
+ it('should set sort direction to DESC if not set', () => {
+ store.state.isTimelineEnabled = true;
+ store.state.sortDirection = ASC;
+ findGlButton().vm.$emit('click', mockEvent);
+ expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', {
+ direction: DESC,
+ persist: false,
+ });
+ });
+
+ it('should set correct UI state', async () => {
+ store.state.isTimelineEnabled = true;
+ findGlButton().vm.$emit('click', mockEvent);
+ await wrapper.vm.$nextTick();
+ expect(findGlButton().attributes('title')).toBe(timelineEnabledTooltip);
+ expect(findGlButton().attributes('selected')).toBe('true');
+ expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
+ });
+
+ it('should track Snowplow event', async () => {
+ store.state.isTimelineEnabled = true;
+ await wrapper.vm.$nextTick();
+
+ findGlButton().trigger('click');
+
+ const { category, action, label, property, value } = trackToggleTimelineView(true);
+ expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property, value });
+ });
+ });
+
+ describe('OFF state', () => {
+ it('should update timeline flag in the store', () => {
+ store.state.isTimelineEnabled = true;
+ findGlButton().vm.$emit('click', mockEvent);
+ expect(store.dispatch).toHaveBeenCalledWith('setTimelineView', false);
+ });
+
+ it('should NOT update sort direction', () => {
+ store.state.isTimelineEnabled = false;
+ findGlButton().vm.$emit('click', mockEvent);
+ expect(store.dispatch).not.toHaveBeenCalledWith();
+ });
+
+ it('should set correct UI state', async () => {
+ store.state.isTimelineEnabled = false;
+ findGlButton().vm.$emit('click', mockEvent);
+ await wrapper.vm.$nextTick();
+ expect(findGlButton().attributes('title')).toBe(timelineDisabledTooltip);
+ expect(findGlButton().attributes('selected')).toBe(undefined);
+ expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
+ });
+
+ it('should track Snowplow event', async () => {
+ store.state.isTimelineEnabled = false;
+ await wrapper.vm.$nextTick();
+
+ findGlButton().trigger('click');
+
+ const { category, action, label, property, value } = trackToggleTimelineView(false);
+ expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property, value });
+ });
+ });
+});
diff --git a/spec/frontend/notes/stores/actions_spec.js b/spec/frontend/notes/stores/actions_spec.js
index 4681f3aa429..920959f41e7 100644
--- a/spec/frontend/notes/stores/actions_spec.js
+++ b/spec/frontend/notes/stores/actions_spec.js
@@ -1144,9 +1144,14 @@ describe('Actions Notes Store', () => {
it('calls the correct mutation with the correct args', done => {
testAction(
actions.setDiscussionSortDirection,
- notesConstants.DESC,
+ { direction: notesConstants.DESC, persist: false },
{},
- [{ type: mutationTypes.SET_DISCUSSIONS_SORT, payload: notesConstants.DESC }],
+ [
+ {
+ type: mutationTypes.SET_DISCUSSIONS_SORT,
+ payload: { direction: notesConstants.DESC, persist: false },
+ },
+ ],
[],
done,
);
diff --git a/spec/frontend/notes/stores/getters_spec.js b/spec/frontend/notes/stores/getters_spec.js
index a07aa45d812..1a369caee49 100644
--- a/spec/frontend/notes/stores/getters_spec.js
+++ b/spec/frontend/notes/stores/getters_spec.js
@@ -6,6 +6,7 @@ import {
noteableDataMock,
individualNote,
collapseNotesMock,
+ discussionMock,
discussion1,
discussion2,
discussion3,
@@ -65,6 +66,18 @@ describe('Getters Notes Store', () => {
it('should return all discussions in the store', () => {
expect(getters.discussions(state)).toEqual([individualNote]);
});
+
+ it('should transform discussion to individual notes in timeline view', () => {
+ state.discussions = [discussionMock];
+ state.isTimelineEnabled = true;
+
+ expect(getters.discussions(state).length).toEqual(discussionMock.notes.length);
+ getters.discussions(state).forEach(discussion => {
+ expect(discussion.individual_note).toBe(true);
+ expect(discussion.id).toBe(discussion.notes[0].id);
+ expect(discussion.created_at).toBe(discussion.notes[0].created_at);
+ });
+ });
});
describe('resolvedDiscussionsById', () => {
diff --git a/spec/frontend/notes/stores/mutation_spec.js b/spec/frontend/notes/stores/mutation_spec.js
index b953bffc4fe..2618c3a53b8 100644
--- a/spec/frontend/notes/stores/mutation_spec.js
+++ b/spec/frontend/notes/stores/mutation_spec.js
@@ -680,9 +680,10 @@ describe('Notes Store mutations', () => {
});
it('sets sort order', () => {
- mutations.SET_DISCUSSIONS_SORT(state, DESC);
+ mutations.SET_DISCUSSIONS_SORT(state, { direction: DESC, persist: false });
expect(state.discussionSortOrder).toBe(DESC);
+ expect(state.persistSortOrder).toBe(false);
});
});