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
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-03-14 21:08:55 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-14 21:08:55 +0300
commit3828d19ab2d68dd6cafa6f08221e1eee572671e7 (patch)
treeafd36fcf20499d876493bf24bd9f0ee926454547 /spec
parent3e764061b3209d4deee2a55851d5d564a9f19d8b (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/contextual_sidebar_spec.rb69
-rw-r--r--spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb10
-rw-r--r--spec/features/dashboard/groups_list_spec.rb7
-rw-r--r--spec/features/dashboard/projects_spec.rb6
-rw-r--r--spec/features/dashboard/snippets_spec.rb7
-rw-r--r--spec/features/explore/navbar_spec.rb13
-rw-r--r--spec/features/nav/top_nav_responsive_spec.rb7
-rw-r--r--spec/features/snippets/show_spec.rb5
-rw-r--r--spec/finders/abuse_reports_finder_spec.rb31
-rw-r--r--spec/frontend/boards/components/board_form_spec.js6
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js14
-rw-r--r--spec/frontend/clusters/agents/components/revoke_token_button_spec.js2
-rw-r--r--spec/frontend/clusters_list/components/delete_agent_button_spec.js2
-rw-r--r--spec/frontend/environments/canary_update_modal_spec.js2
-rw-r--r--spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js4
-rw-r--r--spec/frontend/ide/components/new_dropdown/modal_spec.js8
-rw-r--r--spec/frontend/invite_members/components/invite_members_trigger_spec.js19
-rw-r--r--spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js12
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js2
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js2
-rw-r--r--spec/frontend/pages/profiles/password_prompt/password_prompt_modal_spec.js3
-rw-r--r--spec/frontend/repository/components/delete_blob_modal_spec.js4
-rw-r--r--spec/frontend/repository/components/new_directory_modal_spec.js2
-rw-r--r--spec/frontend/repository/components/tree_content_spec.js38
-rw-r--r--spec/frontend/repository/components/upload_blob_modal_spec.js6
-rw-r--r--spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js4
-rw-r--r--spec/frontend/super_sidebar/components/user_bar_spec.js6
-rw-r--r--spec/frontend/super_sidebar/mock_data.js1
-rw-r--r--spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js2
-rw-r--r--spec/helpers/explore_helper_spec.rb2
-rw-r--r--spec/helpers/nav/top_nav_helper_spec.rb52
-rw-r--r--spec/lib/gitlab/gitaly_client/repository_service_spec.rb17
-rw-r--r--spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb55
-rw-r--r--spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb52
-rw-r--r--spec/models/abuse_report_spec.rb11
-rw-r--r--spec/requests/api/graphql/mutations/work_items/create_spec.rb54
-rw-r--r--spec/services/work_items/parent_links/create_service_spec.rb34
-rw-r--r--spec/services/work_items/widgets/hierarchy_service/create_service_spec.rb31
-rw-r--r--spec/support/shared_contexts/navbar_structure_context.rb27
39 files changed, 278 insertions, 351 deletions
diff --git a/spec/features/contextual_sidebar_spec.rb b/spec/features/contextual_sidebar_spec.rb
index 2b671d4b3f1..132c8eb7192 100644
--- a/spec/features/contextual_sidebar_spec.rb
+++ b/spec/features/contextual_sidebar_spec.rb
@@ -39,74 +39,5 @@ RSpec.describe 'Contextual sidebar', :js, feature_category: :remote_development
expect(page).to have_selector('.is-showing-fly-out')
end
end
-
- context 'with invite_members_in_side_nav experiment', :experiment do
- it 'allows opening of modal for the candidate experience' do
- stub_experiments(invite_members_in_side_nav: :candidate)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: project.group)
- .on_next_instance
-
- visit project_path(project)
-
- page.within '[data-test-id="side-nav-invite-members"' do
- find('[data-test-id="invite-members-button"').click
- end
-
- expect(page).to have_content("You're inviting members to the")
- end
-
- it 'does not have invite members link in side nav for the control experience' do
- stub_experiments(invite_members_in_side_nav: :control)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: project.group)
- .on_next_instance
-
- visit project_path(project)
-
- expect(page).not_to have_css('[data-test-id="side-nav-invite-members"')
- end
- end
- end
-
- context 'when context is a group' do
- let_it_be(:user) { create(:user) }
- let_it_be(:group) do
- create(:group).tap do |g|
- g.add_owner(user)
- end
- end
-
- before do
- sign_in(user)
- end
-
- context 'with invite_members_in_side_nav experiment', :experiment do
- it 'allows opening of modal for the candidate experience' do
- stub_experiments(invite_members_in_side_nav: :candidate)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: group)
- .on_next_instance
-
- visit group_path(group)
-
- page.within '[data-test-id="side-nav-invite-members"' do
- find('[data-test-id="invite-members-button"').click
- end
-
- expect(page).to have_content("You're inviting members to the")
- end
-
- it 'does not have invite members link in side nav for the control experience' do
- stub_experiments(invite_members_in_side_nav: :control)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: group)
- .on_next_instance
-
- visit group_path(group)
-
- expect(page).not_to have_css('[data-test-id="side-nav-invite-members"')
- end
- end
end
end
diff --git a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
index f5b02a87758..a5d6ba58ffa 100644
--- a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
+++ b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
@@ -21,9 +21,8 @@ RSpec.describe 'The group dashboard', :js, feature_category: :subgroups do
within_top_nav do
expect(page).to have_button('Projects')
expect(page).to have_button('Groups')
- expect(page).to have_link('Activity')
- expect(page).to have_link('Milestones')
- expect(page).to have_link('Snippets')
+ expect(page).to have_link('Your work')
+ expect(page).to have_link('Explore')
end
end
@@ -36,9 +35,8 @@ RSpec.describe 'The group dashboard', :js, feature_category: :subgroups do
within_top_nav do
expect(page).to have_button('Projects')
expect(page).to have_button('Groups')
- expect(page).not_to have_link('Activity')
- expect(page).not_to have_link('Milestones')
- expect(page).to have_link('Snippets')
+ expect(page).to have_link('Your work')
+ expect(page).to have_link('Explore')
end
end
end
diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb
index a45e0a58ed6..1fb393e1769 100644
--- a/spec/features/dashboard/groups_list_spec.rb
+++ b/spec/features/dashboard/groups_list_spec.rb
@@ -230,4 +230,11 @@ RSpec.describe 'Dashboard Groups page', :js, feature_category: :subgroups do
expect(page).not_to have_content(another_group.name)
end
end
+
+ it 'links to the "Explore groups" page' do
+ sign_in(user)
+ visit dashboard_groups_path
+
+ expect(page).to have_link("Explore groups", href: explore_groups_path)
+ end
end
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 099a7b14cd8..eafc41c0f40 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -20,6 +20,12 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do
it_behaves_like "a dashboard page with sidebar", :dashboard_projects_path, :projects
+ it 'links to the "Explore projects" page' do
+ visit dashboard_projects_path
+
+ expect(page).to have_link("Explore projects", href: explore_projects_path)
+ end
+
context 'when user has access to the project' do
it 'shows role badge' do
visit dashboard_projects_path
diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb
index ba40290d866..f4234b433f8 100644
--- a/spec/features/dashboard/snippets_spec.rb
+++ b/spec/features/dashboard/snippets_spec.rb
@@ -7,6 +7,13 @@ RSpec.describe 'Dashboard snippets', feature_category: :source_code_management d
it_behaves_like 'a dashboard page with sidebar', :dashboard_snippets_path, :snippets
+ it 'links to the "Explore snippets" page' do
+ sign_in(user)
+ visit dashboard_snippets_path
+
+ expect(page).to have_link("Explore snippets", href: explore_snippets_path)
+ end
+
context 'when the project has snippets' do
let(:project) { create(:project, :public, creator: user) }
let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.first_owner, project: project) }
diff --git a/spec/features/explore/navbar_spec.rb b/spec/features/explore/navbar_spec.rb
new file mode 100644
index 00000000000..8f281abe6a7
--- /dev/null
+++ b/spec/features/explore/navbar_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe '"Explore" navbar', feature_category: :navigation do
+ include_context '"Explore" navbar structure'
+
+ it_behaves_like 'verified navigation bar' do
+ before do
+ visit explore_projects_path
+ end
+ end
+end
diff --git a/spec/features/nav/top_nav_responsive_spec.rb b/spec/features/nav/top_nav_responsive_spec.rb
index f1862a3b9b2..9ac63c26ba0 100644
--- a/spec/features/nav/top_nav_responsive_spec.rb
+++ b/spec/features/nav/top_nav_responsive_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
context 'when menu is closed' do
it 'has page content and hides responsive menu', :aggregate_failures do
- expect(page).to have_css('.page-title', text: 'Projects')
+ expect(page).to have_css('.page-title', text: 'Explore projects')
expect(page).to have_link('Dashboard', id: 'logo')
expect(page).to have_no_css('.top-nav-responsive')
@@ -34,14 +34,15 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
end
it 'hides everything and shows responsive menu', :aggregate_failures do
- expect(page).to have_no_css('.page-title', text: 'Projects')
+ expect(page).to have_no_css('.page-title', text: 'Explore projects')
expect(page).to have_no_link('Dashboard', id: 'logo')
within '.top-nav-responsive' do
expect(page).to have_link(nil, href: search_path)
expect(page).to have_button('Projects')
expect(page).to have_button('Groups')
- expect(page).to have_link('Snippets', href: dashboard_snippets_path)
+ expect(page).to have_link('Your work', href: dashboard_projects_path)
+ expect(page).to have_link('Explore', href: explore_projects_path)
end
end
diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb
index dc2fcdd7305..d6ff8c066c4 100644
--- a/spec/features/snippets/show_spec.rb
+++ b/spec/features/snippets/show_spec.rb
@@ -28,11 +28,10 @@ RSpec.describe 'Snippet', :js, feature_category: :source_code_management do
it_behaves_like 'a dashboard page with sidebar', :dashboard_snippets_path, :snippets
context 'when unauthenticated' do
- it 'does not have the sidebar' do
+ it 'shows the "Explore" sidebar' do
visit snippet_path(snippet)
- expect(page).to have_title _('Snippets')
- expect(page).not_to have_css('aside.nav-sidebar')
+ expect(page).to have_css('aside.nav-sidebar[aria-label="Explore"]')
end
end
diff --git a/spec/finders/abuse_reports_finder_spec.rb b/spec/finders/abuse_reports_finder_spec.rb
index 5b92dcd9069..d3b148375d4 100644
--- a/spec/finders/abuse_reports_finder_spec.rb
+++ b/spec/finders/abuse_reports_finder_spec.rb
@@ -5,8 +5,11 @@ require 'spec_helper'
RSpec.describe AbuseReportsFinder, '#execute' do
let_it_be(:user1) { create(:user) }
let_it_be(:user2) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
let_it_be(:abuse_report_1) { create(:abuse_report, id: 20, category: 'spam', user: user1) }
- let_it_be(:abuse_report_2) { create(:abuse_report, :closed, id: 30, category: 'phishing', user: user2) }
+ let_it_be(:abuse_report_2) do
+ create(:abuse_report, :closed, id: 30, category: 'phishing', user: user2, reporter: reporter)
+ end
let(:params) { {} }
@@ -26,17 +29,15 @@ RSpec.describe AbuseReportsFinder, '#execute' do
end
end
- context 'when params[:user] is present' do
- let(:params) { { user: abuse_report_1.user.username } }
-
- it 'returns abuse reports for the specified user' do
- expect(subject).to match_array([abuse_report_1])
+ shared_examples 'returns filtered reports' do |filter_field|
+ it "returns abuse reports filtered by #{filter_field}_id" do
+ expect(subject).to match_array(filtered_reports)
end
- context 'when no user has username = params[:user]' do
+ context "when no user has username = params[:#{filter_field}]" do
before do
allow(User).to receive_message_chain(:by_username, :pick)
- .with(params[:user])
+ .with(params[filter_field])
.with(:id)
.and_return(nil)
end
@@ -47,6 +48,20 @@ RSpec.describe AbuseReportsFinder, '#execute' do
end
end
+ context 'when params[:user] is present' do
+ it_behaves_like 'returns filtered reports', :user do
+ let(:params) { { user: user1.username } }
+ let(:filtered_reports) { [abuse_report_1] }
+ end
+ end
+
+ context 'when params[:reporter] is present' do
+ it_behaves_like 'returns filtered reports', :reporter do
+ let(:params) { { reporter: reporter.username } }
+ let(:filtered_reports) { [abuse_report_2] }
+ end
+ end
+
context 'when params[:status] is present' do
context 'when value is "open"' do
let(:params) { { status: 'open' } }
diff --git a/spec/frontend/boards/components/board_form_spec.js b/spec/frontend/boards/components/board_form_spec.js
index 7f881a92964..62db59f8f57 100644
--- a/spec/frontend/boards/components/board_form_spec.js
+++ b/spec/frontend/boards/components/board_form_spec.js
@@ -136,7 +136,7 @@ describe('BoardForm', () => {
it('passes correct primary action text and variant', () => {
expect(findModalActionPrimary().text).toBe('Create board');
- expect(findModalActionPrimary().attributes[0].variant).toBe('confirm');
+ expect(findModalActionPrimary().attributes.variant).toBe('confirm');
});
it('does not render delete confirmation message', () => {
@@ -248,7 +248,7 @@ describe('BoardForm', () => {
it('passes correct primary action text and variant', () => {
expect(findModalActionPrimary().text).toBe('Save changes');
- expect(findModalActionPrimary().attributes[0].variant).toBe('confirm');
+ expect(findModalActionPrimary().attributes.variant).toBe('confirm');
});
it('does not render delete confirmation message', () => {
@@ -369,7 +369,7 @@ describe('BoardForm', () => {
it('passes correct primary action text and variant', () => {
createComponent({ canAdminBoard: true, currentPage: formType.delete });
expect(findModalActionPrimary().text).toBe('Delete');
- expect(findModalActionPrimary().attributes[0].variant).toBe('danger');
+ expect(findModalActionPrimary().attributes.variant).toBe('danger');
});
it('renders delete confirmation message', () => {
diff --git a/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js b/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js
index 7e6d4ec4bf8..e4ff9a0545b 100644
--- a/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js
@@ -25,14 +25,12 @@ describe('Take ownership modal', () => {
const actionPrimary = findModal().props('actionPrimary');
expect(actionPrimary.attributes).toEqual(
- expect.objectContaining([
- {
- category: 'primary',
- variant: 'confirm',
- href: url,
- 'data-method': 'post',
- },
- ]),
+ expect.objectContaining({
+ category: 'primary',
+ variant: 'confirm',
+ href: url,
+ 'data-method': 'post',
+ }),
);
});
diff --git a/spec/frontend/clusters/agents/components/revoke_token_button_spec.js b/spec/frontend/clusters/agents/components/revoke_token_button_spec.js
index 9199c76585f..ed7c940bb04 100644
--- a/spec/frontend/clusters/agents/components/revoke_token_button_spec.js
+++ b/spec/frontend/clusters/agents/components/revoke_token_button_spec.js
@@ -45,7 +45,7 @@ describe('RevokeTokenButton', () => {
const findInput = () => wrapper.findComponent(GlFormInput);
const findTooltip = () => wrapper.findComponent(GlTooltip);
const findPrimaryAction = () => findModal().props('actionPrimary');
- const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[0][attr];
+ const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[attr];
const createMockApolloProvider = ({ mutationResponse }) => {
revokeSpy = jest.fn().mockResolvedValue(mutationResponse);
diff --git a/spec/frontend/clusters_list/components/delete_agent_button_spec.js b/spec/frontend/clusters_list/components/delete_agent_button_spec.js
index a0642996a20..53cf67bca0f 100644
--- a/spec/frontend/clusters_list/components/delete_agent_button_spec.js
+++ b/spec/frontend/clusters_list/components/delete_agent_button_spec.js
@@ -33,7 +33,7 @@ describe('DeleteAgentButton', () => {
const findDeleteBtn = () => wrapper.findComponent(GlButton);
const findInput = () => wrapper.findComponent(GlFormInput);
const findPrimaryAction = () => findModal().props('actionPrimary');
- const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[0][attr];
+ const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[attr];
const findDeleteAgentButtonTooltip = () => wrapper.findByTestId('delete-agent-button-tooltip');
const getTooltipText = (el) => {
const binding = getBinding(el, 'gl-tooltip');
diff --git a/spec/frontend/environments/canary_update_modal_spec.js b/spec/frontend/environments/canary_update_modal_spec.js
index 7eb2a54a080..a101ed4e00a 100644
--- a/spec/frontend/environments/canary_update_modal_spec.js
+++ b/spec/frontend/environments/canary_update_modal_spec.js
@@ -45,7 +45,7 @@ describe('/environments/components/canary_update_modal.vue', () => {
modalId: 'confirm-canary-change',
actionPrimary: {
text: 'Change ratio',
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
actionCancel: { text: 'Cancel' },
});
diff --git a/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js b/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js
index 4851e03f713..b06e0340991 100644
--- a/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js
+++ b/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js
@@ -50,7 +50,7 @@ describe('Configure Feature Flags Modal', () => {
});
it('should default disable the primary action', () => {
- const [{ disabled }] = findSecondaryAction().attributes;
+ const { disabled } = findSecondaryAction().attributes;
expect(disabled).toBe(true);
});
@@ -116,7 +116,7 @@ describe('Configure Feature Flags Modal', () => {
it('should enable the secondary action', async () => {
findProjectNameInput().vm.$emit('input', provide.projectName);
await nextTick();
- const [{ disabled }] = findSecondaryAction().attributes;
+ const { disabled } = findSecondaryAction().attributes;
expect(disabled).toBe(false);
});
});
diff --git a/spec/frontend/ide/components/new_dropdown/modal_spec.js b/spec/frontend/ide/components/new_dropdown/modal_spec.js
index a0c454dde82..36c3d323e63 100644
--- a/spec/frontend/ide/components/new_dropdown/modal_spec.js
+++ b/spec/frontend/ide/components/new_dropdown/modal_spec.js
@@ -93,11 +93,11 @@ describe('new file modal component', () => {
it('renders modal', () => {
expect(findGlModal().props()).toMatchObject({
actionCancel: {
- attributes: [{ variant: 'default' }],
+ attributes: { variant: 'default' },
text: 'Cancel',
},
actionPrimary: {
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
text: 'Create file',
},
actionSecondary: null,
@@ -169,7 +169,7 @@ describe('new file modal component', () => {
expect(findGlModal().props()).toMatchObject({
title: modalTitle,
actionPrimary: {
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
text: btnTitle,
},
});
@@ -297,7 +297,7 @@ describe('new file modal component', () => {
expect(findGlModal().props()).toMatchObject({
title,
actionPrimary: {
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
text: title,
},
});
diff --git a/spec/frontend/invite_members/components/invite_members_trigger_spec.js b/spec/frontend/invite_members/components/invite_members_trigger_spec.js
index 699a0ad5809..cdb6182e2ae 100644
--- a/spec/frontend/invite_members/components/invite_members_trigger_spec.js
+++ b/spec/frontend/invite_members/components/invite_members_trigger_spec.js
@@ -1,10 +1,9 @@
-import { GlButton, GlLink, GlIcon, GlDropdownItem } from '@gitlab/ui';
+import { GlButton, GlLink, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
import eventHub from '~/invite_members/event_hub';
import {
TRIGGER_ELEMENT_BUTTON,
- TRIGGER_ELEMENT_SIDE_NAV,
TRIGGER_DEFAULT_QA_SELECTOR,
TRIGGER_ELEMENT_WITH_EMOJI,
TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
@@ -22,7 +21,6 @@ let findButton;
const triggerComponent = {
button: GlButton,
anchor: GlLink,
- 'side-nav': GlLink,
'text-emoji': GlLink,
'dropdown-text-emoji': GlDropdownItem,
};
@@ -48,10 +46,6 @@ const triggerItems = [
triggerElement: 'anchor',
},
{
- triggerElement: TRIGGER_ELEMENT_SIDE_NAV,
- icon: 'plus',
- },
- {
triggerElement: TRIGGER_ELEMENT_WITH_EMOJI,
icon: 'shaking_hands',
},
@@ -101,17 +95,6 @@ describe.each(triggerItems)('with triggerElement as %s', (triggerItem) => {
});
});
-describe('side-nav with icon', () => {
- it('includes the specified icon with correct size when triggerElement is link', () => {
- const findIcon = () => wrapper.findComponent(GlIcon);
-
- createComponent({ triggerElement: TRIGGER_ELEMENT_SIDE_NAV, icon: 'plus' });
-
- expect(findIcon().exists()).toBe(true);
- expect(findIcon().props('name')).toBe('plus');
- });
-});
-
describe('link with emoji', () => {
it('includes the specified icon with correct size when triggerElement is link', () => {
const findEmoji = () => wrapper.findComponent(GlEmoji);
diff --git a/spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js b/spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js
index d60043f33f7..712269a1e83 100644
--- a/spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js
+++ b/spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js
@@ -64,13 +64,11 @@ describe('Job Retry Forward Deployment Modal', () => {
beforeEach(createWrapper);
it('should correctly configure the primary action', () => {
- expect(findModal().props('actionPrimary').attributes).toMatchObject([
- {
- 'data-method': 'post',
- href: job.retry_path,
- variant: 'danger',
- },
- ]);
+ expect(findModal().props('actionPrimary').attributes).toMatchObject({
+ 'data-method': 'post',
+ href: job.retry_path,
+ variant: 'danger',
+ });
});
});
});
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js
index 992e2eb6f3e..860f9b3a0c1 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js
@@ -30,7 +30,7 @@ describe('Delete Modal', () => {
const expectPrimaryActionStatus = (disabled = true) =>
expect(findModal().props('actionPrimary')).toMatchObject(
expect.objectContaining({
- attributes: [{ variant: 'danger' }, { disabled }],
+ attributes: { variant: 'danger', disabled },
}),
);
diff --git a/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js b/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js
index 9c1ebf5a2eb..d0817a8678e 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js
@@ -45,7 +45,7 @@ describe('DeleteModal', () => {
it('passes actionPrimary prop', () => {
expect(findModal().props('actionPrimary')).toStrictEqual({
text: 'Permanently delete',
- attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ attributes: { variant: 'danger', category: 'primary' },
});
});
diff --git a/spec/frontend/pages/profiles/password_prompt/password_prompt_modal_spec.js b/spec/frontend/pages/profiles/password_prompt/password_prompt_modal_spec.js
index 439bb342d01..18a0098a715 100644
--- a/spec/frontend/pages/profiles/password_prompt/password_prompt_modal_spec.js
+++ b/spec/frontend/pages/profiles/password_prompt/password_prompt_modal_spec.js
@@ -25,8 +25,7 @@ describe('Password prompt modal', () => {
const findField = () => wrapper.findByTestId('password-prompt-field');
const findModal = () => wrapper.findComponent(GlModal);
const findConfirmBtn = () => findModal().props('actionPrimary');
- const findConfirmBtnDisabledState = () =>
- findModal().props('actionPrimary').attributes[2].disabled;
+ const findConfirmBtnDisabledState = () => findModal().props('actionPrimary').attributes.disabled;
const findCancelBtn = () => findModal().props('actionCancel');
diff --git a/spec/frontend/repository/components/delete_blob_modal_spec.js b/spec/frontend/repository/components/delete_blob_modal_spec.js
index 5846174296a..9ca45bfb655 100644
--- a/spec/frontend/repository/components/delete_blob_modal_spec.js
+++ b/spec/frontend/repository/components/delete_blob_modal_spec.js
@@ -183,7 +183,7 @@ describe('DeleteBlobModal', () => {
});
it('disables submit button', async () => {
- expect(findModal().props('actionPrimary').attributes[0]).toEqual(
+ expect(findModal().props('actionPrimary').attributes).toEqual(
expect.objectContaining({ disabled: true }),
);
});
@@ -203,7 +203,7 @@ describe('DeleteBlobModal', () => {
});
it('enables submit button', async () => {
- expect(findModal().props('actionPrimary').attributes[0]).toEqual(
+ expect(findModal().props('actionPrimary').attributes).toEqual(
expect.objectContaining({ disabled: false }),
);
});
diff --git a/spec/frontend/repository/components/new_directory_modal_spec.js b/spec/frontend/repository/components/new_directory_modal_spec.js
index d70021650ed..c920159375f 100644
--- a/spec/frontend/repository/components/new_directory_modal_spec.js
+++ b/spec/frontend/repository/components/new_directory_modal_spec.js
@@ -181,7 +181,7 @@ describe('NewDirectoryModal', () => {
it('disables submit button', async () => {
await fillForm({ dirName: '', branchName: '', commitMessage: '' });
- expect(findModal().props('actionPrimary').attributes[0].disabled).toBe(true);
+ expect(findModal().props('actionPrimary').attributes.disabled).toBe(true);
});
it('creates an alert error', async () => {
diff --git a/spec/frontend/repository/components/tree_content_spec.js b/spec/frontend/repository/components/tree_content_spec.js
index 76a50c41a66..0f4edb19632 100644
--- a/spec/frontend/repository/components/tree_content_spec.js
+++ b/spec/frontend/repository/components/tree_content_spec.js
@@ -1,6 +1,5 @@
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
-import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql';
import FilePreview from '~/repository/components/preview/index.vue';
import FileTable from '~/repository/components/table/index.vue';
import TreeContent from 'jh_else_ce/repository/components/tree_content.vue';
@@ -33,12 +32,6 @@ function factory(path, appoloMockResponse = mockResponse) {
mocks: {
$apollo,
},
- provide: {
- glFeatures: {
- increasePageSizeExponentially: true,
- paginatedTreeGraphqlQuery: true,
- },
- },
});
}
@@ -167,37 +160,6 @@ describe('Repository table component', () => {
expect(findFileTable().props('hasMore')).toBe(limitReached);
});
-
- it.each`
- fetchCounter | pageSize
- ${0} | ${10}
- ${2} | ${30}
- ${4} | ${50}
- ${6} | ${70}
- ${8} | ${90}
- ${10} | ${100}
- ${20} | ${100}
- ${100} | ${100}
- ${200} | ${100}
- `('exponentially increases page size, to a maximum of 100', ({ fetchCounter, pageSize }) => {
- factory('/');
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- vm.setData({ fetchCounter });
-
- vm.vm.fetchFiles();
-
- expect($apollo.query).toHaveBeenCalledWith({
- query: paginatedTreeQuery,
- variables: {
- pageSize,
- nextPageCursor: '',
- path: '/',
- projectPath: '',
- ref: '',
- },
- });
- });
});
describe('commit data', () => {
diff --git a/spec/frontend/repository/components/upload_blob_modal_spec.js b/spec/frontend/repository/components/upload_blob_modal_spec.js
index 21699f81900..f7c31f91cd7 100644
--- a/spec/frontend/repository/components/upload_blob_modal_spec.js
+++ b/spec/frontend/repository/components/upload_blob_modal_spec.js
@@ -53,9 +53,9 @@ describe('UploadBlobModal', () => {
const findBranchName = () => wrapper.findComponent(GlFormInput);
const findMrToggle = () => wrapper.findComponent(GlToggle);
const findUploadDropzone = () => wrapper.findComponent(UploadDropzone);
- const actionButtonDisabledState = () => findModal().props('actionPrimary').attributes[0].disabled;
- const cancelButtonDisabledState = () => findModal().props('actionCancel').attributes[0].disabled;
- const actionButtonLoadingState = () => findModal().props('actionPrimary').attributes[0].loading;
+ const actionButtonDisabledState = () => findModal().props('actionPrimary').attributes.disabled;
+ const cancelButtonDisabledState = () => findModal().props('actionCancel').attributes.disabled;
+ const actionButtonLoadingState = () => findModal().props('actionPrimary').attributes.loading;
describe.each`
canPushCode | displayBranchName | displayForkedBranchMessage
diff --git a/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js b/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js
index 715f66d305a..a7c3867c359 100644
--- a/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js
+++ b/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js
@@ -47,8 +47,8 @@ describe('Create Timelog Form', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findDocsLink = () => wrapper.findByTestId('timetracking-docs-link');
const findSaveButton = () => findModal().props('actionPrimary');
- const findSaveButtonLoadingState = () => findSaveButton().attributes[0].loading;
- const findSaveButtonDisabledState = () => findSaveButton().attributes[0].disabled;
+ const findSaveButtonLoadingState = () => findSaveButton().attributes.loading;
+ const findSaveButtonDisabledState = () => findSaveButton().attributes.disabled;
const submitForm = () => findForm().trigger('submit');
diff --git a/spec/frontend/super_sidebar/components/user_bar_spec.js b/spec/frontend/super_sidebar/components/user_bar_spec.js
index a5faad967fc..ae15dd55644 100644
--- a/spec/frontend/super_sidebar/components/user_bar_spec.js
+++ b/spec/frontend/super_sidebar/components/user_bar_spec.js
@@ -13,6 +13,7 @@ describe('UserBar component', () => {
const findCreateMenu = () => wrapper.findComponent(CreateMenu);
const findCounter = (at) => wrapper.findAllComponents(Counter).at(at);
const findMergeRequestMenu = () => wrapper.findComponent(MergeRequestMenu);
+ const findBrandLogo = () => wrapper.findByTestId('brand-header-custom-logo');
const createWrapper = (extraSidebarData = {}) => {
wrapper = shallowMountExtended(UserBar, {
@@ -55,6 +56,11 @@ describe('UserBar component', () => {
expect(findCounter(2).props('href')).toBe('/dashboard/todos');
expect(findCounter(2).props('label')).toBe(__('To-Do list'));
});
+
+ it('renders branding logo', () => {
+ expect(findBrandLogo().exists()).toBe(true);
+ expect(findBrandLogo().attributes('src')).toBe(sidebarData.logo_url);
+ });
});
describe('GitLab Next badge', () => {
diff --git a/spec/frontend/super_sidebar/mock_data.js b/spec/frontend/super_sidebar/mock_data.js
index 2cd055e6d07..32f56e5c107 100644
--- a/spec/frontend/super_sidebar/mock_data.js
+++ b/spec/frontend/super_sidebar/mock_data.js
@@ -68,6 +68,7 @@ export const sidebarData = {
name: 'Administrator',
username: 'root',
avatar_url: 'path/to/img_administrator',
+ logo_url: 'path/to/logo',
assigned_open_issues_count: 1,
todos_pending_count: 3,
issues_dashboard_path: 'path/to/issues',
diff --git a/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js b/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
index b03b6bfb61d..d7f94c00d09 100644
--- a/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
+++ b/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
@@ -24,7 +24,7 @@ describe('Confirm Danger Modal', () => {
const findAdditionalMessage = () => wrapper.findByTestId('confirm-danger-message');
const findPrimaryAction = () => findModal().props('actionPrimary');
const findCancelAction = () => findModal().props('actionCancel');
- const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[0][attr];
+ const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[attr];
const createComponent = ({ provide = {} } = {}) =>
shallowMountExtended(ConfirmDangerModal, {
diff --git a/spec/helpers/explore_helper_spec.rb b/spec/helpers/explore_helper_spec.rb
index 4ae1b738858..68c5289a85f 100644
--- a/spec/helpers/explore_helper_spec.rb
+++ b/spec/helpers/explore_helper_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe ExploreHelper do
describe '#explore_nav_links' do
it 'has all the expected links by default' do
- menu_items = [:projects, :groups, :snippets]
+ menu_items = [:projects, :groups, :topics, :snippets]
expect(helper.explore_nav_links).to contain_exactly(*menu_items)
end
diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb
index ce5ac2e5404..2b69557b840 100644
--- a/spec/helpers/nav/top_nav_helper_spec.rb
+++ b/spec/helpers/nav/top_nav_helper_spec.rb
@@ -56,6 +56,7 @@ RSpec.describe Nav::TopNavHelper do
expected_primary = [
{ href: '/explore', icon: 'project', id: 'project', title: 'Projects' },
{ href: '/explore/groups', icon: 'group', id: 'groups', title: 'Groups' },
+ { href: '/explore/projects/topics', icon: 'labels', id: 'topics', title: 'Topics' },
{ href: '/explore/snippets', icon: 'snippet', id: 'snippets', title: 'Snippets' }
].map do |item|
::Gitlab::Nav::TopNavMenuItem.build(**item)
@@ -79,6 +80,12 @@ RSpec.describe Nav::TopNavHelper do
css_class: 'dashboard-shortcuts-groups'
},
{
+ href: '/explore/projects/topics',
+ id: 'topics-shortcut',
+ title: 'Topics',
+ css_class: 'dashboard-shortcuts-topics'
+ },
+ {
href: '/explore/snippets',
id: 'snippets-shortcut',
title: 'Snippets',
@@ -320,20 +327,6 @@ RSpec.describe Nav::TopNavHelper do
context 'with milestones' do
let(:with_milestones) { true }
- it 'has expected :primary' do
- expected_header = ::Gitlab::Nav::TopNavMenuHeader.build(
- title: 'Explore'
- )
- expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
- data: { **menu_data_tracking_attrs('milestones') },
- href: '/dashboard/milestones',
- icon: 'clock',
- id: 'milestones',
- title: 'Milestones'
- )
- expect(subject[:primary]).to eq([expected_header, expected_primary])
- end
-
it 'has expected :shortcuts' do
expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build(
id: 'milestones-shortcut',
@@ -348,23 +341,6 @@ RSpec.describe Nav::TopNavHelper do
context 'with snippets' do
let(:with_snippets) { true }
- it 'has expected :primary' do
- expected_header = ::Gitlab::Nav::TopNavMenuHeader.build(
- title: 'Explore'
- )
- expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'snippets_link',
- **menu_data_tracking_attrs('snippets')
- },
- href: '/dashboard/snippets',
- icon: 'snippet',
- id: 'snippets',
- title: 'Snippets'
- )
- expect(subject[:primary]).to eq([expected_header, expected_primary])
- end
-
it 'has expected :shortcuts' do
expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build(
id: 'snippets-shortcut',
@@ -379,20 +355,6 @@ RSpec.describe Nav::TopNavHelper do
context 'with activity' do
let(:with_activity) { true }
- it 'has expected :primary' do
- expected_header = ::Gitlab::Nav::TopNavMenuHeader.build(
- title: 'Explore'
- )
- expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
- data: { **menu_data_tracking_attrs('activity') },
- href: '/dashboard/activity',
- icon: 'history',
- id: 'activity',
- title: 'Activity'
- )
- expect(subject[:primary]).to eq([expected_header, expected_primary])
- end
-
it 'has expected :shortcuts' do
expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build(
id: 'activity-shortcut',
diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
index 671f1ee1a0a..f457ba06074 100644
--- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
@@ -275,7 +275,8 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
it 'sends a create_repository message without arguments' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:create_repository)
- .with(gitaly_request_with_path(storage_name, relative_path).and(gitaly_request_with_params(default_branch: '')), kind_of(Hash))
+ .with(gitaly_request_with_path(storage_name, relative_path)
+ .and(gitaly_request_with_params(default_branch: '')), kind_of(Hash))
.and_return(double)
client.create_repository
@@ -284,11 +285,23 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
it 'sends a create_repository message with default branch' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:create_repository)
- .with(gitaly_request_with_path(storage_name, relative_path).and(gitaly_request_with_params(default_branch: 'default-branch-name')), kind_of(Hash))
+ .with(gitaly_request_with_path(storage_name, relative_path)
+ .and(gitaly_request_with_params(default_branch: 'default-branch-name')), kind_of(Hash))
.and_return(double)
client.create_repository('default-branch-name')
end
+
+ it 'sends a create_repository message with default branch containing non ascii chars' do
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:create_repository)
+ .with(gitaly_request_with_path(storage_name, relative_path)
+ .and(gitaly_request_with_params(
+ default_branch: Gitlab::EncodingHelper.encode_binary('feature/新機能'))), kind_of(Hash)
+ ).and_return(double)
+
+ client.create_repository('feature/新機能')
+ end
end
describe '#create_from_snapshot' do
diff --git a/spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb b/spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb
deleted file mode 100644
index a79e5182f45..00000000000
--- a/spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Sidebars::Groups::Menus::InviteTeamMembersMenu do
- let_it_be(:owner) { create(:user) }
- let_it_be(:guest) { create(:user) }
- let_it_be(:group) do
- build(:group).tap do |g|
- g.add_owner(owner)
- end
- end
-
- let(:context) { Sidebars::Groups::Context.new(current_user: owner, container: group) }
-
- subject(:invite_menu) { described_class.new(context) }
-
- context 'when the group is viewed by an owner of the group' do
- describe '#render?' do
- it 'renders the Invite team members link' do
- expect(invite_menu.render?).to eq(true)
- end
-
- context 'when the group already has at least 2 members' do
- before do
- group.add_guest(guest)
- end
-
- it 'does not render the link' do
- expect(invite_menu.render?).to eq(false)
- end
- end
- end
-
- describe '#title' do
- it 'displays the correct Invite team members text for the link in the side nav' do
- expect(invite_menu.title).to eq('Invite members')
- end
- end
- end
-
- context 'when the group is viewed by a guest user without admin permissions' do
- let(:context) { Sidebars::Groups::Context.new(current_user: guest, container: group) }
-
- before do
- group.add_guest(guest)
- end
-
- describe '#render?' do
- it 'does not render the link' do
- expect(subject.render?).to eq(false)
- end
- end
- end
-end
diff --git a/spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb b/spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb
deleted file mode 100644
index 9838aa8c3e3..00000000000
--- a/spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Sidebars::Projects::Menus::InviteTeamMembersMenu do
- let_it_be(:project) { create(:project) }
- let_it_be(:guest) { create(:user) }
-
- let(:context) { Sidebars::Projects::Context.new(current_user: owner, container: project) }
-
- subject(:invite_menu) { described_class.new(context) }
-
- context 'when the project is viewed by an owner of the group' do
- let(:owner) { project.first_owner }
-
- describe '#render?' do
- it 'renders the Invite team members link' do
- expect(invite_menu.render?).to eq(true)
- end
-
- context 'when the project already has at least 2 members' do
- before do
- project.add_guest(guest)
- end
-
- it 'does not render the link' do
- expect(invite_menu.render?).to eq(false)
- end
- end
- end
-
- describe '#title' do
- it 'displays the correct Invite team members text for the link in the side nav' do
- expect(invite_menu.title).to eq('Invite members')
- end
- end
- end
-
- context 'when the project is viewed by a guest user without admin permissions' do
- let(:context) { Sidebars::Projects::Context.new(current_user: guest, container: project) }
-
- before do
- project.add_guest(guest)
- end
-
- describe '#render?' do
- it 'does not render' do
- expect(invite_menu.render?).to eq(false)
- end
- end
- end
-end
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index 30639f5a580..9026a870138 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -71,9 +71,18 @@ RSpec.describe AbuseReport, feature_category: :insider_threat do
end
describe 'scopes' do
- let_it_be(:report1) { create(:abuse_report) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:report1) { create(:abuse_report, reporter: reporter) }
let_it_be(:report2) { create(:abuse_report, :closed, category: 'phishing') }
+ describe '.by_reporter_id' do
+ subject(:results) { described_class.by_reporter_id(reporter.id) }
+
+ it 'returns reports with reporter_id equal to the given user id' do
+ expect(subject).to match_array([report1])
+ end
+ end
+
describe '.open' do
subject(:results) { described_class.open }
diff --git a/spec/requests/api/graphql/mutations/work_items/create_spec.rb b/spec/requests/api/graphql/mutations/work_items/create_spec.rb
index 16f78b67b5c..7519389ab49 100644
--- a/spec/requests/api/graphql/mutations/work_items/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/create_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
'title' => 'new title',
'description' => 'new description',
'confidential' => true,
- 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_global_id.to_s
+ 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_gid.to_s
}
end
@@ -43,14 +43,14 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
expect(created_work_item.work_item_type.base_type).to eq('task')
expect(mutation_response['workItem']).to include(
input.except('workItemTypeId').merge(
- 'id' => created_work_item.to_global_id.to_s,
+ 'id' => created_work_item.to_gid.to_s,
'workItemType' => hash_including('name' => 'Task')
)
)
end
context 'when input is invalid' do
- let(:input) { { 'title' => '', 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_global_id.to_s } }
+ let(:input) { { 'title' => '', 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_gid.to_s } }
it 'does not create and returns validation errors' do
expect do
@@ -98,8 +98,8 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
let(:input) do
{
title: 'item1',
- workItemTypeId: WorkItems::Type.default_by_type(:task).to_global_id.to_s,
- hierarchyWidget: { 'parentId' => parent.to_global_id.to_s }
+ workItemTypeId: WorkItems::Type.default_by_type(:task).to_gid.to_s,
+ hierarchyWidget: { 'parentId' => parent.to_gid.to_s }
}
end
@@ -110,7 +110,7 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
expect(widgets_response).to include(
{
'children' => { 'edges' => [] },
- 'parent' => { 'id' => parent.to_global_id.to_s },
+ 'parent' => { 'id' => parent.to_gid.to_s },
'type' => 'HIERARCHY'
}
)
@@ -137,6 +137,40 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
expect(graphql_errors.first['message']).to include('No object found for `parentId')
end
end
+
+ context 'when adjacent is already in place' do
+ let_it_be(:adjacent) { create(:work_item, :task, project: project) }
+
+ let(:work_item) { WorkItem.last }
+
+ let(:input) do
+ {
+ title: 'item1',
+ workItemTypeId: WorkItems::Type.default_by_type(:task).to_gid.to_s,
+ hierarchyWidget: { 'parentId' => parent.to_gid.to_s }
+ }
+ end
+
+ before(:all) do
+ create(:parent_link, work_item_parent: parent, work_item: adjacent, relative_position: 0)
+ end
+
+ it 'creates work item and sets the relative position to be AFTER adjacent' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change(WorkItem, :count).by(1)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(widgets_response).to include(
+ {
+ 'children' => { 'edges' => [] },
+ 'parent' => { 'id' => parent.to_gid.to_s },
+ 'type' => 'HIERARCHY'
+ }
+ )
+ expect(work_item.parent_link.relative_position).to be > adjacent.parent_link.relative_position
+ end
+ end
end
context 'when unsupported widget input is sent' do
@@ -144,7 +178,7 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
{
'title' => 'new title',
'description' => 'new description',
- 'workItemTypeId' => WorkItems::Type.default_by_type(:test_case).to_global_id.to_s,
+ 'workItemTypeId' => WorkItems::Type.default_by_type(:test_case).to_gid.to_s,
'hierarchyWidget' => {}
}
end
@@ -181,8 +215,8 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
let(:input) do
{
title: 'some WI',
- workItemTypeId: WorkItems::Type.default_by_type(:task).to_global_id.to_s,
- milestoneWidget: { 'milestoneId' => milestone.to_global_id.to_s }
+ workItemTypeId: WorkItems::Type.default_by_type(:task).to_gid.to_s,
+ milestoneWidget: { 'milestoneId' => milestone.to_gid.to_s }
}
end
@@ -196,7 +230,7 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
expect(widgets_response).to include(
{
'type' => 'MILESTONE',
- 'milestone' => { 'id' => milestone.to_global_id.to_s }
+ 'milestone' => { 'id' => milestone.to_gid.to_s }
}
)
end
diff --git a/spec/services/work_items/parent_links/create_service_spec.rb b/spec/services/work_items/parent_links/create_service_spec.rb
index 5884847eac3..a989ecf9c07 100644
--- a/spec/services/work_items/parent_links/create_service_spec.rb
+++ b/spec/services/work_items/parent_links/create_service_spec.rb
@@ -68,6 +68,40 @@ RSpec.describe WorkItems::ParentLinks::CreateService, feature_category: :portfol
end
end
+ context 'when adjacent is already in place' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be_with_reload(:parent_item) { create(:work_item, :objective, project: project) }
+ let_it_be_with_reload(:current_item) { create(:work_item, :objective, project: project) }
+
+ let_it_be_with_reload(:adjacent) do
+ create(:work_item, :objective, project: project)
+ end
+
+ let_it_be_with_reload(:link_to_adjacent) do
+ create(:parent_link, work_item_parent: parent_item, work_item: adjacent)
+ end
+
+ subject { described_class.new(parent_item, user, { target_issuable: current_item }).execute }
+
+ where(:adjacent_position, :expected_order) do
+ -100 | lazy { [adjacent, current_item] }
+ 0 | lazy { [adjacent, current_item] }
+ 100 | lazy { [adjacent, current_item] }
+ end
+
+ with_them do
+ before do
+ link_to_adjacent.update!(relative_position: adjacent_position)
+ end
+
+ it 'sets relative positions' do
+ expect { subject }.to change(parent_link_class, :count).by(1)
+ expect(parent_item.work_item_children_by_relative_position).to eq(expected_order)
+ end
+ end
+ end
+
context 'when there are tasks to relate' do
let(:params) { { issuable_references: [task1, task2] } }
diff --git a/spec/services/work_items/widgets/hierarchy_service/create_service_spec.rb b/spec/services/work_items/widgets/hierarchy_service/create_service_spec.rb
new file mode 100644
index 00000000000..8d834c9a4f8
--- /dev/null
+++ b/spec/services/work_items/widgets/hierarchy_service/create_service_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::Widgets::HierarchyService::CreateService, feature_category: :portfolio_management do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:parent_item) { create(:work_item, project: project) }
+
+ let(:widget) { parent_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Hierarchy) } }
+
+ shared_examples 'raises a WidgetError' do
+ it { expect { subject }.to raise_error(described_class::WidgetError, message) }
+ end
+
+ before(:all) do
+ project.add_developer(user)
+ end
+
+ describe '#create' do
+ subject { described_class.new(widget: widget, current_user: user).after_create_in_transaction(params: params) }
+
+ context 'when invalid params are present' do
+ let(:params) { { other_parent: 'parent_work_item' } }
+
+ it_behaves_like 'raises a WidgetError' do
+ let(:message) { 'One or more arguments are invalid: other_parent.' }
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb
index 8b03d8a2770..866a97b0e3c 100644
--- a/spec/support/shared_contexts/navbar_structure_context.rb
+++ b/spec/support/shared_contexts/navbar_structure_context.rb
@@ -259,3 +259,30 @@ RSpec.shared_context 'dashboard navbar structure' do
]
end
end
+
+RSpec.shared_context '"Explore" navbar structure' do
+ let(:structure) do
+ [
+ {
+ nav_item: "Explore",
+ nav_sub_items: []
+ },
+ {
+ nav_item: _("Projects"),
+ nav_sub_items: []
+ },
+ {
+ nav_item: _("Groups"),
+ nav_sub_items: []
+ },
+ {
+ nav_item: _("Topics"),
+ nav_sub_items: []
+ },
+ {
+ nav_item: _("Snippets"),
+ nav_sub_items: []
+ }
+ ]
+ end
+end