summaryrefslogtreecommitdiff
path: root/spec/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/issues_list/components/issues_list_app_spec.js2
-rw-r--r--spec/frontend/issues_list/mock_data.js40
-rw-r--r--spec/frontend/issues_list/utils_spec.js8
-rw-r--r--spec/frontend/vue_mr_widget/mr_widget_options_spec.js5
-rw-r--r--spec/frontend/vue_mr_widget/test_extension.js1
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js9
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js78
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.',
+ });
+ });
+});