diff options
Diffstat (limited to 'spec/frontend')
7 files changed, 130 insertions, 13 deletions
diff --git a/spec/frontend/issues_list/components/issues_list_app_spec.js b/spec/frontend/issues_list/components/issues_list_app_spec.js index 6b443062f12..3f52c7b4afe 100644 --- a/spec/frontend/issues_list/components/issues_list_app_spec.js +++ b/spec/frontend/issues_list/components/issues_list_app_spec.js @@ -37,6 +37,7 @@ import { TOKEN_TYPE_LABEL, TOKEN_TYPE_MILESTONE, TOKEN_TYPE_MY_REACTION, + TOKEN_TYPE_RELEASE, TOKEN_TYPE_TYPE, TOKEN_TYPE_WEIGHT, urlSortParams, @@ -581,6 +582,7 @@ describe('IssuesListApp component', () => { { type: TOKEN_TYPE_MILESTONE }, { type: TOKEN_TYPE_LABEL }, { type: TOKEN_TYPE_TYPE }, + { type: TOKEN_TYPE_RELEASE }, { type: TOKEN_TYPE_MY_REACTION }, { type: TOKEN_TYPE_CONFIDENTIAL }, { type: TOKEN_TYPE_ITERATION }, diff --git a/spec/frontend/issues_list/mock_data.js b/spec/frontend/issues_list/mock_data.js index c62050c3563..25664cc2842 100644 --- a/spec/frontend/issues_list/mock_data.js +++ b/spec/frontend/issues_list/mock_data.js @@ -95,12 +95,18 @@ export const locationSearch = [ 'assignee_username[]=lisa', 'not[assignee_username][]=patty', 'not[assignee_username][]=selma', + 'milestone_title=season+3', 'milestone_title=season+4', 'not[milestone_title]=season+20', + 'not[milestone_title]=season+30', 'label_name[]=cartoon', 'label_name[]=tv', 'not[label_name][]=live action', 'not[label_name][]=drama', + 'release_tag=v3', + 'release_tag=v4', + 'not[release_tag]=v20', + 'not[release_tag]=v30', 'type[]=issue', 'type[]=feature', 'not[type][]=bug', @@ -109,7 +115,9 @@ export const locationSearch = [ 'not[my_reaction_emoji]=thumbsdown', 'confidential=yes', 'iteration_id=4', + 'iteration_id=12', 'not[iteration_id]=20', + 'not[iteration_id]=42', 'epic_id=12', 'not[epic_id]=34', 'weight=1', @@ -122,6 +130,7 @@ export const locationSearchWithSpecialValues = [ 'my_reaction_emoji=None', 'iteration_id=Current', 'label_name[]=None', + 'release_tag=None', 'milestone_title=Upcoming', 'epic_id=None', 'weight=None', @@ -134,12 +143,18 @@ export const filteredTokens = [ { type: 'assignee_username', value: { data: 'lisa', operator: OPERATOR_IS } }, { type: 'assignee_username', value: { data: 'patty', operator: OPERATOR_IS_NOT } }, { type: 'assignee_username', value: { data: 'selma', operator: OPERATOR_IS_NOT } }, + { type: 'milestone', value: { data: 'season 3', operator: OPERATOR_IS } }, { type: 'milestone', value: { data: 'season 4', operator: OPERATOR_IS } }, { type: 'milestone', value: { data: 'season 20', operator: OPERATOR_IS_NOT } }, + { type: 'milestone', value: { data: 'season 30', operator: OPERATOR_IS_NOT } }, { type: 'labels', value: { data: 'cartoon', operator: OPERATOR_IS } }, { type: 'labels', value: { data: 'tv', operator: OPERATOR_IS } }, { type: 'labels', value: { data: 'live action', operator: OPERATOR_IS_NOT } }, { type: 'labels', value: { data: 'drama', operator: OPERATOR_IS_NOT } }, + { type: 'release', value: { data: 'v3', operator: OPERATOR_IS } }, + { type: 'release', value: { data: 'v4', operator: OPERATOR_IS } }, + { type: 'release', value: { data: 'v20', operator: OPERATOR_IS_NOT } }, + { type: 'release', value: { data: 'v30', operator: OPERATOR_IS_NOT } }, { type: 'type', value: { data: 'issue', operator: OPERATOR_IS } }, { type: 'type', value: { data: 'feature', operator: OPERATOR_IS } }, { type: 'type', value: { data: 'bug', operator: OPERATOR_IS_NOT } }, @@ -148,7 +163,9 @@ export const filteredTokens = [ { type: 'my_reaction_emoji', value: { data: 'thumbsdown', operator: OPERATOR_IS_NOT } }, { type: 'confidential', value: { data: 'yes', operator: OPERATOR_IS } }, { type: 'iteration', value: { data: '4', operator: OPERATOR_IS } }, + { type: 'iteration', value: { data: '12', operator: OPERATOR_IS } }, { type: 'iteration', value: { data: '20', operator: OPERATOR_IS_NOT } }, + { type: 'iteration', value: { data: '42', operator: OPERATOR_IS_NOT } }, { type: 'epic_id', value: { data: '12', operator: OPERATOR_IS } }, { type: 'epic_id', value: { data: '34', operator: OPERATOR_IS_NOT } }, { type: 'weight', value: { data: '1', operator: OPERATOR_IS } }, @@ -163,6 +180,7 @@ export const filteredTokensWithSpecialValues = [ { type: 'my_reaction_emoji', value: { data: 'None', operator: OPERATOR_IS } }, { type: 'iteration', value: { data: 'Current', operator: OPERATOR_IS } }, { type: 'labels', value: { data: 'None', operator: OPERATOR_IS } }, + { type: 'release', value: { data: 'None', operator: OPERATOR_IS } }, { type: 'milestone', value: { data: 'Upcoming', operator: OPERATOR_IS } }, { type: 'epic_id', value: { data: 'None', operator: OPERATOR_IS } }, { type: 'weight', value: { data: 'None', operator: OPERATOR_IS } }, @@ -171,22 +189,24 @@ export const filteredTokensWithSpecialValues = [ export const apiParams = { authorUsername: 'homer', assigneeUsernames: ['bart', 'lisa'], - milestoneTitle: 'season 4', + milestoneTitle: ['season 3', 'season 4'], labelName: ['cartoon', 'tv'], + releaseTag: ['v3', 'v4'], types: ['ISSUE', 'FEATURE'], myReactionEmoji: 'thumbsup', confidential: true, - iterationId: '4', + iterationId: ['4', '12'], epicId: '12', weight: '1', not: { authorUsername: 'marge', assigneeUsernames: ['patty', 'selma'], - milestoneTitle: 'season 20', + milestoneTitle: ['season 20', 'season 30'], labelName: ['live action', 'drama'], + releaseTag: ['v20', 'v30'], types: ['BUG', 'INCIDENT'], myReactionEmoji: 'thumbsdown', - iterationId: '20', + iterationId: ['20', '42'], epicId: '34', weight: '3', }, @@ -197,6 +217,7 @@ export const apiParamsWithSpecialValues = { assigneeUsernames: 'bart', labelName: 'None', myReactionEmoji: 'None', + releaseTagWildcardId: 'NONE', iterationWildcardId: 'CURRENT', milestoneWildcardId: 'UPCOMING', epicId: 'None', @@ -208,17 +229,19 @@ export const urlParams = { 'not[author_username]': 'marge', 'assignee_username[]': ['bart', 'lisa'], 'not[assignee_username][]': ['patty', 'selma'], - milestone_title: 'season 4', - 'not[milestone_title]': 'season 20', + milestone_title: ['season 3', 'season 4'], + 'not[milestone_title]': ['season 20', 'season 30'], 'label_name[]': ['cartoon', 'tv'], 'not[label_name][]': ['live action', 'drama'], + release_tag: ['v3', 'v4'], + 'not[release_tag]': ['v20', 'v30'], 'type[]': ['issue', 'feature'], 'not[type][]': ['bug', 'incident'], my_reaction_emoji: 'thumbsup', 'not[my_reaction_emoji]': 'thumbsdown', confidential: 'yes', - iteration_id: '4', - 'not[iteration_id]': '20', + iteration_id: ['4', '12'], + 'not[iteration_id]': ['20', '42'], epic_id: '12', 'not[epic_id]': '34', weight: '1', @@ -229,6 +252,7 @@ export const urlParamsWithSpecialValues = { assignee_id: '123', 'assignee_username[]': 'bart', 'label_name[]': 'None', + release_tag: 'None', my_reaction_emoji: 'None', iteration_id: 'Current', milestone_title: 'Upcoming', diff --git a/spec/frontend/issues_list/utils_spec.js b/spec/frontend/issues_list/utils_spec.js index 458776d9ec5..8e1d70db92d 100644 --- a/spec/frontend/issues_list/utils_spec.js +++ b/spec/frontend/issues_list/utils_spec.js @@ -58,10 +58,10 @@ describe('getDueDateValue', () => { describe('getSortOptions', () => { describe.each` hasIssueWeightsFeature | hasBlockedIssuesFeature | length | containsWeight | containsBlocking - ${false} | ${false} | ${8} | ${false} | ${false} - ${true} | ${false} | ${9} | ${true} | ${false} - ${false} | ${true} | ${9} | ${false} | ${true} - ${true} | ${true} | ${10} | ${true} | ${true} + ${false} | ${false} | ${9} | ${false} | ${false} + ${true} | ${false} | ${10} | ${true} | ${false} + ${false} | ${true} | ${10} | ${false} | ${true} + ${true} | ${true} | ${11} | ${true} | ${true} `( 'when hasIssueWeightsFeature=$hasIssueWeightsFeature and hasBlockedIssuesFeature=$hasBlockedIssuesFeature', ({ diff --git a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js index 19892539a8f..844e7330679 100644 --- a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js +++ b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js @@ -1,4 +1,4 @@ -import { GlBadge, GlLink, GlIcon, GlDropdown } from '@gitlab/ui'; +import { GlBadge, GlLink, GlIcon, GlButton, GlDropdown } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; import Vue, { nextTick } from 'vue'; @@ -947,6 +947,9 @@ describe('MrWidgetOptions', () => { // Renders a link in the row expect(collapsedSection.find(GlLink).exists()).toBe(true); expect(collapsedSection.find(GlLink).text()).toBe('GitLab.com'); + + expect(collapsedSection.find(GlButton).exists()).toBe(true); + expect(collapsedSection.find(GlButton).text()).toBe('Full report'); }); }); }); diff --git a/spec/frontend/vue_mr_widget/test_extension.js b/spec/frontend/vue_mr_widget/test_extension.js index 51bc44a7063..65c1bd8473b 100644 --- a/spec/frontend/vue_mr_widget/test_extension.js +++ b/spec/frontend/vue_mr_widget/test_extension.js @@ -31,6 +31,7 @@ export default { href: 'https://gitlab.com', text: 'GitLab.com', }, + actions: [{ text: 'Full report', href: 'https://gitlab.com', target: '_blank' }], }, ]); }, diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js index c2462d90a63..74cf6985b99 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js @@ -9,6 +9,7 @@ import EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_t import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue'; import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue'; import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue'; +import ReleaseToken from '~/vue_shared/components/filtered_search_bar/tokens/release_token.vue'; import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue'; export const mockAuthor1 = { @@ -132,6 +133,14 @@ export const mockMilestoneToken = { fetchMilestones: () => Promise.resolve({ data: mockMilestones }), }; +export const mockReleaseToken = { + type: 'release', + icon: 'rocket', + title: 'Release', + token: ReleaseToken, + fetchReleases: () => Promise.resolve(), +}; + export const mockEpicToken = { type: 'epic_iid', icon: 'clock', diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js new file mode 100644 index 00000000000..b804ff97b82 --- /dev/null +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js @@ -0,0 +1,78 @@ +import { GlFilteredSearchToken, GlFilteredSearchTokenSegment } from '@gitlab/ui'; +import { mount } from '@vue/test-utils'; +import waitForPromises from 'helpers/wait_for_promises'; +import createFlash from '~/flash'; +import ReleaseToken from '~/vue_shared/components/filtered_search_bar/tokens/release_token.vue'; +import { mockReleaseToken } from '../mock_data'; + +jest.mock('~/flash'); + +describe('ReleaseToken', () => { + const id = 123; + let wrapper; + + const createComponent = ({ config = mockReleaseToken, value = { data: '' } } = {}) => + mount(ReleaseToken, { + propsData: { + active: false, + config, + value, + }, + provide: { + portalName: 'fake target', + alignSuggestions: function fakeAlignSuggestions() {}, + suggestionsListClass: () => 'custom-class', + }, + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders release value', async () => { + wrapper = createComponent({ value: { data: id } }); + await wrapper.vm.$nextTick(); + + const tokenSegments = wrapper.findAllComponents(GlFilteredSearchTokenSegment); + + expect(tokenSegments).toHaveLength(3); // `Release` `=` `v1` + expect(tokenSegments.at(2).text()).toBe(id.toString()); + }); + + it('fetches initial values', () => { + const fetchReleasesSpy = jest.fn().mockResolvedValue(); + + wrapper = createComponent({ + config: { ...mockReleaseToken, fetchReleases: fetchReleasesSpy }, + value: { data: id }, + }); + + expect(fetchReleasesSpy).toHaveBeenCalledWith(id); + }); + + it('fetches releases on user input', () => { + const search = 'hello'; + const fetchReleasesSpy = jest.fn().mockResolvedValue(); + + wrapper = createComponent({ + config: { ...mockReleaseToken, fetchReleases: fetchReleasesSpy }, + }); + + wrapper.findComponent(GlFilteredSearchToken).vm.$emit('input', { data: search }); + + expect(fetchReleasesSpy).toHaveBeenCalledWith(search); + }); + + it('renders error message when request fails', async () => { + const fetchReleasesSpy = jest.fn().mockRejectedValue(); + + wrapper = createComponent({ + config: { ...mockReleaseToken, fetchReleases: fetchReleasesSpy }, + }); + await waitForPromises(); + + expect(createFlash).toHaveBeenCalledWith({ + message: 'There was a problem fetching releases.', + }); + }); +}); |