mirror of
https://github.com/gitlabhq/gitlabhq.git
synced 2025-08-16 17:13:01 +00:00
Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
@ -7,7 +7,6 @@ import { resetServiceWorkersPublicPath } from '../lib/utils/webpack';
|
||||
import MergeRequest from '../merge_request';
|
||||
import discussionCounter from '../notes/components/discussion_counter.vue';
|
||||
import initDiscussionFilters from '../notes/discussion_filters';
|
||||
import initSortDiscussions from '../notes/sort_discussions';
|
||||
import initNotesApp from './init_notes';
|
||||
|
||||
export default function initMrNotes() {
|
||||
@ -52,6 +51,5 @@ export default function initMrNotes() {
|
||||
}
|
||||
|
||||
initDiscussionFilters(store);
|
||||
initSortDiscussions(store);
|
||||
});
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { getLocationHash, doesHashExistInUrl } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import Tracking from '~/tracking';
|
||||
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
|
||||
import {
|
||||
DISCUSSION_FILTERS_DEFAULT_VALUE,
|
||||
HISTORY_ONLY_FILTER_VALUE,
|
||||
@ -9,15 +12,25 @@ import {
|
||||
DISCUSSION_TAB_LABEL,
|
||||
DISCUSSION_FILTER_TYPES,
|
||||
NOTE_UNDERSCORE,
|
||||
ASC,
|
||||
DESC,
|
||||
} from '../constants';
|
||||
import notesEventHub from '../event_hub';
|
||||
|
||||
const SORT_OPTIONS = [
|
||||
{ key: DESC, text: __('Newest first'), cls: 'js-newest-first' },
|
||||
{ key: ASC, text: __('Oldest first'), cls: 'js-oldest-first' },
|
||||
];
|
||||
|
||||
export default {
|
||||
SORT_OPTIONS,
|
||||
components: {
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownDivider,
|
||||
LocalStorageSync,
|
||||
},
|
||||
mixins: [Tracking.mixin()],
|
||||
props: {
|
||||
filters: {
|
||||
type: Array,
|
||||
@ -39,11 +52,24 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['getNotesDataByProp', 'timelineEnabled', 'isLoading']),
|
||||
...mapGetters([
|
||||
'getNotesDataByProp',
|
||||
'timelineEnabled',
|
||||
'isLoading',
|
||||
'sortDirection',
|
||||
'persistSortOrder',
|
||||
'noteableType',
|
||||
]),
|
||||
currentFilter() {
|
||||
if (!this.currentValue) return this.filters[0];
|
||||
return this.filters.find((filter) => filter.value === this.currentValue);
|
||||
},
|
||||
selectedSortOption() {
|
||||
return SORT_OPTIONS.find(({ key }) => this.sortDirection === key);
|
||||
},
|
||||
sortStorageKey() {
|
||||
return `sort_direction_${this.noteableType.toLowerCase()}`;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (window.mrTabs) {
|
||||
@ -69,6 +95,7 @@ export default {
|
||||
'setCommentsDisabled',
|
||||
'setTargetNoteHash',
|
||||
'setTimelineView',
|
||||
'setDiscussionSortDirection',
|
||||
]),
|
||||
selectFilter(value, persistFilter = true) {
|
||||
const filter = parseInt(value, 10);
|
||||
@ -108,31 +135,73 @@ export default {
|
||||
}
|
||||
return DISCUSSION_FILTER_TYPES.HISTORY;
|
||||
},
|
||||
fetchSortedDiscussions(direction) {
|
||||
if (this.isSortDropdownItemActive(direction)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setDiscussionSortDirection({ direction });
|
||||
this.track('change_discussion_sort_direction', { property: direction });
|
||||
},
|
||||
isSortDropdownItemActive(sortDir) {
|
||||
return sortDir === this.sortDirection;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-dropdown
|
||||
<div
|
||||
v-if="displayFilters"
|
||||
id="discussion-filter-dropdown"
|
||||
class="full-width-mobile discussion-filter-container js-discussion-filter-container"
|
||||
data-qa-selector="discussion_filter_dropdown"
|
||||
:text="currentFilter.title"
|
||||
:disabled="isLoading"
|
||||
id="discussion-preferences"
|
||||
data-testid="discussion-preferences"
|
||||
class="gl-display-inline-block gl-vertical-align-bottom full-width-mobile"
|
||||
>
|
||||
<div v-for="filter in filters" :key="filter.value" class="dropdown-item-wrapper">
|
||||
<gl-dropdown-item
|
||||
:is-check-item="true"
|
||||
:is-checked="filter.value === currentValue"
|
||||
:class="{ 'is-active': filter.value === currentValue }"
|
||||
:data-filter-type="filterType(filter.value)"
|
||||
data-qa-selector="filter_menu_item"
|
||||
@click.prevent="selectFilter(filter.value)"
|
||||
<local-storage-sync
|
||||
:value="sortDirection"
|
||||
:storage-key="sortStorageKey"
|
||||
:persist="persistSortOrder"
|
||||
as-string
|
||||
@input="setDiscussionSortDirection({ direction: $event })"
|
||||
/>
|
||||
<gl-dropdown
|
||||
id="discussion-preferences-dropdown"
|
||||
class="full-width-mobile"
|
||||
data-qa-selector="discussion_preferences_dropdown"
|
||||
text="Sort or filter"
|
||||
:disabled="isLoading"
|
||||
right
|
||||
>
|
||||
<div id="discussion-sort">
|
||||
<gl-dropdown-item
|
||||
v-for="{ text, key, cls } in $options.SORT_OPTIONS"
|
||||
:key="text"
|
||||
:class="cls"
|
||||
:is-check-item="true"
|
||||
:is-checked="isSortDropdownItemActive(key)"
|
||||
@click="fetchSortedDiscussions(key)"
|
||||
>
|
||||
{{ text }}
|
||||
</gl-dropdown-item>
|
||||
</div>
|
||||
<gl-dropdown-divider />
|
||||
<div
|
||||
id="discussion-filter"
|
||||
class="discussion-filter-container js-discussion-filter-container"
|
||||
>
|
||||
{{ filter.title }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-divider v-if="filter.value === defaultValue" />
|
||||
</div>
|
||||
</gl-dropdown>
|
||||
<gl-dropdown-item
|
||||
v-for="filter in filters"
|
||||
:key="filter.value"
|
||||
:is-check-item="true"
|
||||
:is-checked="filter.value === currentValue"
|
||||
:class="{ 'is-active': filter.value === currentValue }"
|
||||
:data-filter-type="filterType(filter.value)"
|
||||
data-qa-selector="filter_menu_item"
|
||||
@click.prevent="selectFilter(filter.value)"
|
||||
>
|
||||
{{ filter.title }}
|
||||
</gl-dropdown-item>
|
||||
</div>
|
||||
</gl-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,76 +0,0 @@
|
||||
<script>
|
||||
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { __ } from '~/locale';
|
||||
import Tracking from '~/tracking';
|
||||
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
|
||||
import { ASC, DESC } from '../constants';
|
||||
|
||||
const SORT_OPTIONS = [
|
||||
{ key: DESC, text: __('Newest first'), cls: 'js-newest-first' },
|
||||
{ key: ASC, text: __('Oldest first'), cls: 'js-oldest-first' },
|
||||
];
|
||||
|
||||
export default {
|
||||
SORT_OPTIONS,
|
||||
components: {
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
LocalStorageSync,
|
||||
},
|
||||
mixins: [Tracking.mixin()],
|
||||
computed: {
|
||||
...mapGetters(['sortDirection', 'persistSortOrder', 'noteableType']),
|
||||
selectedOption() {
|
||||
return SORT_OPTIONS.find(({ key }) => this.sortDirection === key);
|
||||
},
|
||||
dropdownText() {
|
||||
return this.selectedOption.text;
|
||||
},
|
||||
storageKey() {
|
||||
return `sort_direction_${this.noteableType.toLowerCase()}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['setDiscussionSortDirection']),
|
||||
fetchSortedDiscussions(direction) {
|
||||
if (this.isDropdownItemActive(direction)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setDiscussionSortDirection({ direction });
|
||||
this.track('change_discussion_sort_direction', { property: direction });
|
||||
},
|
||||
isDropdownItemActive(sortDir) {
|
||||
return sortDir === this.sortDirection;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
data-testid="sort-discussion-filter"
|
||||
class="gl-mr-3 gl-display-inline-block gl-vertical-align-bottom full-width-mobile"
|
||||
>
|
||||
<local-storage-sync
|
||||
:value="sortDirection"
|
||||
:storage-key="storageKey"
|
||||
:persist="persistSortOrder"
|
||||
as-string
|
||||
@input="setDiscussionSortDirection({ direction: $event })"
|
||||
/>
|
||||
<gl-dropdown :text="dropdownText" class="js-dropdown-text full-width-mobile">
|
||||
<gl-dropdown-item
|
||||
v-for="{ text, key, cls } in $options.SORT_OPTIONS"
|
||||
:key="key"
|
||||
:class="cls"
|
||||
:is-check-item="true"
|
||||
:is-checked="isDropdownItemActive(key)"
|
||||
@click="fetchSortedDiscussions(key)"
|
||||
>
|
||||
{{ text }}
|
||||
</gl-dropdown-item>
|
||||
</gl-dropdown>
|
||||
</div>
|
||||
</template>
|
@ -53,7 +53,6 @@ export default {
|
||||
:selected="timelineEnabled"
|
||||
:title="tooltip"
|
||||
:aria-label="tooltip"
|
||||
class="gl-mr-3"
|
||||
@click="toggleTimeline"
|
||||
/>
|
||||
</template>
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Vue from 'vue';
|
||||
import notesApp from './components/notes_app.vue';
|
||||
import initDiscussionFilters from './discussion_filters';
|
||||
import initSortDiscussions from './sort_discussions';
|
||||
import { store } from './stores';
|
||||
import initTimelineToggle from './timeline';
|
||||
|
||||
@ -61,6 +60,5 @@ export default () => {
|
||||
});
|
||||
|
||||
initDiscussionFilters(store);
|
||||
initSortDiscussions(store);
|
||||
initTimelineToggle(store);
|
||||
};
|
||||
|
@ -1,17 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import SortDiscussion from './components/sort_discussion.vue';
|
||||
|
||||
export default (store) => {
|
||||
const el = document.getElementById('js-vue-sort-issue-discussions');
|
||||
|
||||
if (!el) return null;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'SortDiscussionRoot',
|
||||
store,
|
||||
render(createElement) {
|
||||
return createElement(SortDiscussion);
|
||||
},
|
||||
});
|
||||
};
|
@ -8,7 +8,6 @@ module AcceptsPendingInvitations
|
||||
|
||||
if user.pending_invitations.load.any?
|
||||
user.accept_pending_invitations!
|
||||
clear_stored_location_for(user: user)
|
||||
after_pending_invitations_hook
|
||||
end
|
||||
end
|
||||
@ -16,10 +15,4 @@ module AcceptsPendingInvitations
|
||||
def after_pending_invitations_hook
|
||||
# no-op
|
||||
end
|
||||
|
||||
def clear_stored_location_for(user:)
|
||||
session_key = stored_location_key_for(user)
|
||||
|
||||
session.delete(session_key)
|
||||
end
|
||||
end
|
||||
|
@ -4,8 +4,7 @@
|
||||
.row.gl-m-0.gl-justify-content-space-between
|
||||
.js-noteable-awards
|
||||
= render 'award_emoji/awards_block', awardable: issuable, inline: true, api_awards_path: api_awards_path
|
||||
.new-branch-col.gl-my-2.gl-font-size-0
|
||||
.new-branch-col.gl-display-flex.gl-my-2.gl-font-size-0.gl-gap-3
|
||||
= render_if_exists "projects/issues/timeline_toggle", issuable: issuable
|
||||
#js-vue-sort-issue-discussions
|
||||
#js-vue-discussion-filter{ data: { default_filter: current_user&.notes_filter_for(issuable), notes_filters: UserPreference.notes_filters.to_json } }
|
||||
= render 'new_branch' if show_new_branch_button?
|
||||
|
@ -301,8 +301,7 @@ test:
|
||||
|
||||
If your project uses [pip](https://pip.pypa.io/en/stable/) to install
|
||||
Python dependencies, the following example defines `cache` globally so that
|
||||
all jobs inherit it. Python libraries are installed in a virtual environment under `venv/`.
|
||||
pip's cache is defined under `.cache/pip/` and both are cached per-branch:
|
||||
all jobs inherit it. pip's cache is defined under `.cache/pip/` and is cached per-branch:
|
||||
|
||||
```yaml
|
||||
#
|
||||
@ -317,13 +316,9 @@ variables:
|
||||
|
||||
# Pip's cache doesn't store the python packages
|
||||
# https://pip.pypa.io/en/stable/reference/pip_install/#caching
|
||||
#
|
||||
# If you want to also cache the installed packages, you have to install
|
||||
# them in a virtualenv and cache it as well.
|
||||
cache:
|
||||
paths:
|
||||
- .cache/pip
|
||||
- venv/
|
||||
|
||||
before_script:
|
||||
- python -V # Print out python version for debugging
|
||||
|
@ -34329,9 +34329,15 @@ msgstr ""
|
||||
msgid "Saving project."
|
||||
msgstr ""
|
||||
|
||||
msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
|
||||
msgstr ""
|
||||
|
||||
msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} for the %{branches} branch(es)"
|
||||
msgstr ""
|
||||
|
||||
msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
|
||||
msgstr ""
|
||||
|
||||
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
|
||||
msgstr ""
|
||||
|
||||
@ -34347,6 +34353,9 @@ msgstr ""
|
||||
msgid "ScanExecutionPolicy|Select branches"
|
||||
msgstr ""
|
||||
|
||||
msgid "ScanExecutionPolicy|branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
|
||||
msgstr ""
|
||||
|
||||
@ -46258,6 +46267,9 @@ msgstr ""
|
||||
msgid "created by"
|
||||
msgstr ""
|
||||
|
||||
msgid "daily"
|
||||
msgstr ""
|
||||
|
||||
msgid "data"
|
||||
msgstr ""
|
||||
|
||||
@ -47574,6 +47586,9 @@ msgstr ""
|
||||
msgid "was scheduled to merge after pipeline succeeds by"
|
||||
msgstr ""
|
||||
|
||||
msgid "weekly"
|
||||
msgstr ""
|
||||
|
||||
msgid "wiki page"
|
||||
msgstr ""
|
||||
|
||||
|
@ -28,7 +28,7 @@ module QA
|
||||
end
|
||||
|
||||
base.view 'app/assets/javascripts/notes/components/discussion_filter.vue' do
|
||||
element :discussion_filter_dropdown, required: true
|
||||
element :discussion_preferences_dropdown, required: true
|
||||
element :filter_menu_item
|
||||
end
|
||||
|
||||
@ -169,7 +169,7 @@ module QA
|
||||
def select_filter_with_text(text)
|
||||
retry_on_exception do
|
||||
click_element(:title_content)
|
||||
click_element :discussion_filter_dropdown
|
||||
click_element :discussion_preferences_dropdown
|
||||
find_element(:filter_menu_item, text: text).click
|
||||
|
||||
wait_for_requests
|
||||
|
@ -16,7 +16,9 @@ RSpec.describe 'Comment sort direction' do
|
||||
it 'saves sort order' do
|
||||
# open dropdown, and select 'Newest first'
|
||||
page.within('.issuable-details') do
|
||||
find('#discussion-preferences-dropdown').click
|
||||
click_button('Oldest first')
|
||||
find('#discussion-preferences-dropdown').click
|
||||
click_button('Newest first')
|
||||
end
|
||||
|
||||
|
@ -20,7 +20,7 @@ RSpec.describe 'User opens link to comment', :js do
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(page.find('#discussion-filter-dropdown')).to have_content('Show all activity')
|
||||
expect(find('#discussion-preferences-dropdown')).to have_content('Sort or filter')
|
||||
expect(page).not_to have_content('Something went wrong while fetching comments')
|
||||
|
||||
# Auto-switching to show all notes shouldn't be persisted
|
||||
|
@ -8,7 +8,14 @@ import createEventHub from '~/helpers/event_hub_factory';
|
||||
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import DiscussionFilter from '~/notes/components/discussion_filter.vue';
|
||||
import { DISCUSSION_FILTERS_DEFAULT_VALUE, DISCUSSION_FILTER_TYPES } from '~/notes/constants';
|
||||
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
|
||||
import Tracking from '~/tracking';
|
||||
import {
|
||||
DISCUSSION_FILTERS_DEFAULT_VALUE,
|
||||
DISCUSSION_FILTER_TYPES,
|
||||
ASC,
|
||||
DESC,
|
||||
} from '~/notes/constants';
|
||||
import notesModule from '~/notes/stores/modules';
|
||||
|
||||
import { discussionFiltersMock, discussionMock } from '../mock_data';
|
||||
@ -28,6 +35,8 @@ describe('DiscussionFilter component', () => {
|
||||
const findFilter = (filterType) =>
|
||||
wrapper.find(`.dropdown-item[data-filter-type="${filterType}"]`);
|
||||
|
||||
const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
|
||||
|
||||
const mountComponent = () => {
|
||||
const discussions = [
|
||||
{
|
||||
@ -68,6 +77,7 @@ describe('DiscussionFilter component', () => {
|
||||
mock.onGet(DISCUSSION_PATH).reply(200, '');
|
||||
window.mrTabs = undefined;
|
||||
wrapper = mountComponent();
|
||||
jest.spyOn(Tracking, 'event');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -75,6 +85,65 @@ describe('DiscussionFilter component', () => {
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
describe('default', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(store, 'dispatch').mockImplementation();
|
||||
});
|
||||
|
||||
it('has local storage sync with the correct props', () => {
|
||||
expect(findLocalStorageSync().props('asString')).toBe(true);
|
||||
});
|
||||
|
||||
it('calls setDiscussionSortDirection when update is emitted', () => {
|
||||
findLocalStorageSync().vm.$emit('input', ASC);
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', { direction: ASC });
|
||||
});
|
||||
});
|
||||
|
||||
describe('when asc', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(store, 'dispatch').mockImplementation();
|
||||
});
|
||||
|
||||
describe('when the dropdown is clicked', () => {
|
||||
it('calls the right actions', () => {
|
||||
wrapper.find('.js-newest-first').vm.$emit('click');
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', {
|
||||
direction: DESC,
|
||||
});
|
||||
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'change_discussion_sort_direction', {
|
||||
property: DESC,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when desc', () => {
|
||||
beforeEach(() => {
|
||||
store.state.discussionSortOrder = DESC;
|
||||
jest.spyOn(store, 'dispatch').mockImplementation();
|
||||
});
|
||||
|
||||
describe('when the dropdown item is clicked', () => {
|
||||
it('calls the right actions', () => {
|
||||
wrapper.find('.js-oldest-first').vm.$emit('click');
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', {
|
||||
direction: ASC,
|
||||
});
|
||||
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'change_discussion_sort_direction', {
|
||||
property: ASC,
|
||||
});
|
||||
});
|
||||
|
||||
it('sets is-checked to true on the active button in the dropdown', () => {
|
||||
expect(wrapper.find('.js-newest-first').props('isChecked')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the all filters', () => {
|
||||
expect(wrapper.findAll('.discussion-filter-container .dropdown-item').length).toBe(
|
||||
discussionFiltersMock.length,
|
||||
@ -82,7 +151,7 @@ describe('DiscussionFilter component', () => {
|
||||
});
|
||||
|
||||
it('renders the default selected item', () => {
|
||||
expect(wrapper.find('#discussion-filter-dropdown .dropdown-item').text().trim()).toBe(
|
||||
expect(wrapper.find('.discussion-filter-container .dropdown-item').text().trim()).toBe(
|
||||
discussionFiltersMock[0].title,
|
||||
);
|
||||
});
|
||||
@ -127,14 +196,6 @@ describe('DiscussionFilter component', () => {
|
||||
expect(wrapper.vm.$store.state.commentsDisabled).toBe(false);
|
||||
});
|
||||
|
||||
it('renders a dropdown divider for the default filter', () => {
|
||||
const defaultFilter = wrapper.findAll(
|
||||
`.discussion-filter-container .dropdown-item-wrapper > *`,
|
||||
);
|
||||
|
||||
expect(defaultFilter.at(1).classes('gl-new-dropdown-divider')).toBe(true);
|
||||
});
|
||||
|
||||
describe('Merge request tabs', () => {
|
||||
eventHub = createEventHub();
|
||||
|
||||
|
@ -1,102 +0,0 @@
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import SortDiscussion from '~/notes/components/sort_discussion.vue';
|
||||
import { ASC, DESC } from '~/notes/constants';
|
||||
import createStore from '~/notes/stores';
|
||||
import Tracking from '~/tracking';
|
||||
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
describe('Sort Discussion component', () => {
|
||||
let wrapper;
|
||||
let store;
|
||||
|
||||
const createComponent = () => {
|
||||
jest.spyOn(store, 'dispatch').mockImplementation();
|
||||
|
||||
wrapper = shallowMount(SortDiscussion, {
|
||||
store,
|
||||
});
|
||||
};
|
||||
|
||||
const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
|
||||
|
||||
beforeEach(() => {
|
||||
store = createStore();
|
||||
jest.spyOn(Tracking, 'event');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
});
|
||||
|
||||
describe('default', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('has local storage sync with the correct props', () => {
|
||||
expect(findLocalStorageSync().props('asString')).toBe(true);
|
||||
});
|
||||
|
||||
it('calls setDiscussionSortDirection when update is emitted', () => {
|
||||
findLocalStorageSync().vm.$emit('input', ASC);
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', { direction: ASC });
|
||||
});
|
||||
});
|
||||
|
||||
describe('when asc', () => {
|
||||
describe('when the dropdown is clicked', () => {
|
||||
it('calls the right actions', () => {
|
||||
createComponent();
|
||||
|
||||
wrapper.find('.js-newest-first').vm.$emit('click');
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', {
|
||||
direction: DESC,
|
||||
});
|
||||
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'change_discussion_sort_direction', {
|
||||
property: DESC,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('shows the "Oldest First" as the dropdown', () => {
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.find('.js-dropdown-text').props('text')).toBe('Oldest first');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when desc', () => {
|
||||
beforeEach(() => {
|
||||
store.state.discussionSortOrder = DESC;
|
||||
createComponent();
|
||||
});
|
||||
|
||||
describe('when the dropdown item is clicked', () => {
|
||||
it('calls the right actions', () => {
|
||||
wrapper.find('.js-oldest-first').vm.$emit('click');
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', {
|
||||
direction: ASC,
|
||||
});
|
||||
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'change_discussion_sort_direction', {
|
||||
property: ASC,
|
||||
});
|
||||
});
|
||||
|
||||
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').props('text')).toBe('Newest first');
|
||||
});
|
||||
});
|
||||
});
|
@ -4,7 +4,6 @@ require 'spec_helper'
|
||||
|
||||
RSpec.describe GitlabSchema.types['Project'] do
|
||||
include GraphqlHelpers
|
||||
include Ci::TemplateHelpers
|
||||
|
||||
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Project) }
|
||||
|
||||
|
@ -3,8 +3,6 @@
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Security::CiConfiguration::SastParserService do
|
||||
include Ci::TemplateHelpers
|
||||
|
||||
describe '#configuration' do
|
||||
include_context 'read ci configuration for sast enabled project'
|
||||
|
||||
|
@ -2,10 +2,6 @@
|
||||
|
||||
module Ci
|
||||
module TemplateHelpers
|
||||
def secure_analyzers_prefix
|
||||
'registry.gitlab.com/security-products'
|
||||
end
|
||||
|
||||
def template_registry_host
|
||||
'registry.gitlab.com'
|
||||
end
|
||||
|
Reference in New Issue
Block a user