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>2022-08-04 12:10:47 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-08-04 12:10:47 +0300
commit13f31ab91aeb5233a7b64f2740fee246294161fc (patch)
treed47fa67102b45131f0dd04257e97ab955a134c17 /spec
parentbf3e636cc03f219a8411cdd723a364a08c8502b1 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/groups/members/manage_members_spec.rb4
-rw-r--r--spec/frontend/content_editor/services/markdown_serializer_spec.js80
-rw-r--r--spec/frontend/invite_members/components/members_token_select_spec.js34
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js10
-rw-r--r--spec/frontend/work_items/mock_data.js17
-rw-r--r--spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url_spec.rb41
-rw-r--r--spec/migrations/20220725150127_update_jira_tracker_data_deployment_type_based_on_url_spec.rb (renamed from spec/migrations/20210421163509_schedule_update_jira_tracker_data_deployment_type_based_on_url_spec.rb)24
-rw-r--r--spec/models/merge_request/approval_removal_settings_spec.rb52
-rw-r--r--spec/requests/api/project_attributes.yml1
-rw-r--r--spec/requests/projects/cycle_analytics_events_spec.rb4
-rw-r--r--spec/support/helpers/features/invite_members_modal_helper.rb31
-rw-r--r--spec/support/shared_examples/features/inviting_members_shared_examples.rb67
13 files changed, 269 insertions, 98 deletions
diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb
index 468001c3be6..5f28afc23f1 100644
--- a/spec/features/groups/members/manage_members_spec.rb
+++ b/spec/features/groups/members/manage_members_spec.rb
@@ -74,8 +74,8 @@ RSpec.describe 'Groups > Members > Manage members' do
invite_member(user1.name, role: 'Reporter', refresh: false)
- expect(page).to have_selector(invite_modal_selector)
- expect(page).to have_content("not authorized to update member")
+ invite_modal = page.find(invite_modal_selector)
+ expect(invite_modal).to have_content("not authorized to update member")
page.refresh
diff --git a/spec/frontend/content_editor/services/markdown_serializer_spec.js b/spec/frontend/content_editor/services/markdown_serializer_spec.js
index d55e5fbadad..55f17727df7 100644
--- a/spec/frontend/content_editor/services/markdown_serializer_spec.js
+++ b/spec/frontend/content_editor/services/markdown_serializer_spec.js
@@ -1213,45 +1213,47 @@ paragraph
};
it.each`
- mark | markdown | modifiedMarkdown | editAction
- ${'bold'} | ${'**bold**'} | ${'**bold modified**'} | ${defaultEditAction}
- ${'bold'} | ${'__bold__'} | ${'__bold modified__'} | ${defaultEditAction}
- ${'bold'} | ${'<strong>bold</strong>'} | ${'<strong>bold modified</strong>'} | ${defaultEditAction}
- ${'bold'} | ${'<b>bold</b>'} | ${'<b>bold modified</b>'} | ${defaultEditAction}
- ${'italic'} | ${'_italic_'} | ${'_italic modified_'} | ${defaultEditAction}
- ${'italic'} | ${'*italic*'} | ${'*italic modified*'} | ${defaultEditAction}
- ${'italic'} | ${'<em>italic</em>'} | ${'<em>italic modified</em>'} | ${defaultEditAction}
- ${'italic'} | ${'<i>italic</i>'} | ${'<i>italic modified</i>'} | ${defaultEditAction}
- ${'link'} | ${'[gitlab](https://gitlab.com)'} | ${'[gitlab modified](https://gitlab.com)'} | ${defaultEditAction}
- ${'link'} | ${'<a href="https://gitlab.com">link</a>'} | ${'<a href="https://gitlab.com/">link modified</a>'} | ${defaultEditAction}
- ${'link'} | ${'link www.gitlab.com'} | ${'modified link www.gitlab.com'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com'} | ${'modified link https://www.gitlab.com'} | ${prependContentEditAction}
- ${'link'} | ${'link(https://www.gitlab.com)'} | ${'modified link(https://www.gitlab.com)'} | ${prependContentEditAction}
- ${'link'} | ${'link(engineering@gitlab.com)'} | ${'modified link(engineering@gitlab.com)'} | ${prependContentEditAction}
- ${'link'} | ${'link <https://www.gitlab.com>'} | ${'modified link <https://www.gitlab.com>'} | ${prependContentEditAction}
- ${'link'} | ${'link [https://www.gitlab.com>'} | ${'modified link \\[https://www.gitlab.com>'} | ${prependContentEditAction}
- ${'link'} | ${'link <https://www.gitlab.com'} | ${'modified link <https://www.gitlab.com'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com>'} | ${'modified link [https://www.gitlab.com>](https://www.gitlab.com%3E)'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com/path'} | ${'modified link https://www.gitlab.com/path'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com?query=search'} | ${'modified link https://www.gitlab.com?query=search'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com/#fragment'} | ${'modified link https://www.gitlab.com/#fragment'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com/?query=search'} | ${'modified link https://www.gitlab.com/?query=search'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com#fragment'} | ${'modified link https://www.gitlab.com#fragment'} | ${prependContentEditAction}
- ${'link'} | ${'link **https://www.gitlab.com]**'} | ${'modified link [**https://www.gitlab.com\\]**](https://www.gitlab.com%5D)'} | ${prependContentEditAction}
- ${'code'} | ${'`code`'} | ${'`code modified`'} | ${defaultEditAction}
- ${'code'} | ${'<code>code</code>'} | ${'<code>code modified</code>'} | ${defaultEditAction}
- ${'strike'} | ${'~~striked~~'} | ${'~~striked modified~~'} | ${defaultEditAction}
- ${'strike'} | ${'<del>striked</del>'} | ${'<del>striked modified</del>'} | ${defaultEditAction}
- ${'strike'} | ${'<strike>striked</strike>'} | ${'<strike>striked modified</strike>'} | ${defaultEditAction}
- ${'strike'} | ${'<s>striked</s>'} | ${'<s>striked modified</s>'} | ${defaultEditAction}
- ${'list'} | ${'- list item'} | ${'- list item modified'} | ${defaultEditAction}
- ${'list'} | ${'* list item'} | ${'* list item modified'} | ${defaultEditAction}
- ${'list'} | ${'+ list item'} | ${'+ list item modified'} | ${defaultEditAction}
- ${'list'} | ${'- list item 1\n- list item 2'} | ${'- list item 1\n- list item 2 modified'} | ${defaultEditAction}
- ${'list'} | ${'2) list item'} | ${'2) list item modified'} | ${defaultEditAction}
- ${'list'} | ${'1. list item'} | ${'1. list item modified'} | ${defaultEditAction}
- ${'taskList'} | ${'2) [ ] task list item'} | ${'2) [ ] task list item modified'} | ${defaultEditAction}
- ${'taskList'} | ${'2) [x] task list item'} | ${'2) [x] task list item modified'} | ${defaultEditAction}
+ mark | markdown | modifiedMarkdown | editAction
+ ${'bold'} | ${'**bold**'} | ${'**bold modified**'} | ${defaultEditAction}
+ ${'bold'} | ${'__bold__'} | ${'__bold modified__'} | ${defaultEditAction}
+ ${'bold'} | ${'<strong>bold</strong>'} | ${'<strong>bold modified</strong>'} | ${defaultEditAction}
+ ${'bold'} | ${'<b>bold</b>'} | ${'<b>bold modified</b>'} | ${defaultEditAction}
+ ${'italic'} | ${'_italic_'} | ${'_italic modified_'} | ${defaultEditAction}
+ ${'italic'} | ${'*italic*'} | ${'*italic modified*'} | ${defaultEditAction}
+ ${'italic'} | ${'<em>italic</em>'} | ${'<em>italic modified</em>'} | ${defaultEditAction}
+ ${'italic'} | ${'<i>italic</i>'} | ${'<i>italic modified</i>'} | ${defaultEditAction}
+ ${'link'} | ${'[gitlab](https://gitlab.com)'} | ${'[gitlab modified](https://gitlab.com)'} | ${defaultEditAction}
+ ${'link'} | ${'<a href="https://gitlab.com">link</a>'} | ${'<a href="https://gitlab.com/">link modified</a>'} | ${defaultEditAction}
+ ${'link'} | ${'link www.gitlab.com'} | ${'modified link www.gitlab.com'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com'} | ${'modified link https://www.gitlab.com'} | ${prependContentEditAction}
+ ${'link'} | ${'link(https://www.gitlab.com)'} | ${'modified link(https://www.gitlab.com)'} | ${prependContentEditAction}
+ ${'link'} | ${'link(engineering@gitlab.com)'} | ${'modified link(engineering@gitlab.com)'} | ${prependContentEditAction}
+ ${'link'} | ${'link <https://www.gitlab.com>'} | ${'modified link <https://www.gitlab.com>'} | ${prependContentEditAction}
+ ${'link'} | ${'link [https://www.gitlab.com>'} | ${'modified link \\[https://www.gitlab.com>'} | ${prependContentEditAction}
+ ${'link'} | ${'link <https://www.gitlab.com'} | ${'modified link <https://www.gitlab.com'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com>'} | ${'modified link [https://www.gitlab.com>](https://www.gitlab.com%3E)'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com/path'} | ${'modified link https://www.gitlab.com/path'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com?query=search'} | ${'modified link https://www.gitlab.com?query=search'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com/#fragment'} | ${'modified link https://www.gitlab.com/#fragment'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com/?query=search'} | ${'modified link https://www.gitlab.com/?query=search'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com#fragment'} | ${'modified link https://www.gitlab.com#fragment'} | ${prependContentEditAction}
+ ${'link'} | ${'link **https://www.gitlab.com]**'} | ${'modified link [**https://www.gitlab.com\\]**](https://www.gitlab.com%5D)'} | ${prependContentEditAction}
+ ${'code'} | ${'`code`'} | ${'`code modified`'} | ${defaultEditAction}
+ ${'code'} | ${'<code>code</code>'} | ${'<code>code modified</code>'} | ${defaultEditAction}
+ ${'strike'} | ${'~~striked~~'} | ${'~~striked modified~~'} | ${defaultEditAction}
+ ${'strike'} | ${'<del>striked</del>'} | ${'<del>striked modified</del>'} | ${defaultEditAction}
+ ${'strike'} | ${'<strike>striked</strike>'} | ${'<strike>striked modified</strike>'} | ${defaultEditAction}
+ ${'strike'} | ${'<s>striked</s>'} | ${'<s>striked modified</s>'} | ${defaultEditAction}
+ ${'list'} | ${'- list item'} | ${'- list item modified'} | ${defaultEditAction}
+ ${'list'} | ${'* list item'} | ${'* list item modified'} | ${defaultEditAction}
+ ${'list'} | ${'+ list item'} | ${'+ list item modified'} | ${defaultEditAction}
+ ${'list'} | ${'- list item 1\n- list item 2'} | ${'- list item 1\n- list item 2 modified'} | ${defaultEditAction}
+ ${'list'} | ${'2) list item'} | ${'2) list item modified'} | ${defaultEditAction}
+ ${'list'} | ${'1. list item'} | ${'1. list item modified'} | ${defaultEditAction}
+ ${'taskList'} | ${'2) [ ] task list item'} | ${'2) [ ] task list item modified'} | ${defaultEditAction}
+ ${'taskList'} | ${'2) [x] task list item'} | ${'2) [x] task list item modified'} | ${defaultEditAction}
+ ${'image'} | ${'![image](image.png)'} | ${'![image](image.png) modified'} | ${defaultEditAction}
+ ${'footnoteReference'} | ${'[^1] footnote\n\n[^1]: footnote definition'} | ${'modified [^1] footnote\n\n[^1]: footnote definition'} | ${prependContentEditAction}
`(
'preserves original $mark syntax when sourceMarkdown is available for $markdown',
async ({ markdown, modifiedMarkdown, editAction }) => {
diff --git a/spec/frontend/invite_members/components/members_token_select_spec.js b/spec/frontend/invite_members/components/members_token_select_spec.js
index 6375d0f7e2e..0455460918c 100644
--- a/spec/frontend/invite_members/components/members_token_select_spec.js
+++ b/spec/frontend/invite_members/components/members_token_select_spec.js
@@ -5,6 +5,7 @@ import { stubComponent } from 'helpers/stub_component';
import waitForPromises from 'helpers/wait_for_promises';
import * as UserApi from '~/api/user_api';
import MembersTokenSelect from '~/invite_members/components/members_token_select.vue';
+import { VALID_TOKEN_BACKGROUND, INVALID_TOKEN_BACKGROUND } from '~/invite_members/constants';
const label = 'testgroup';
const placeholder = 'Search for a member';
@@ -49,6 +50,39 @@ describe('MembersTokenSelect', () => {
});
});
+ describe('when there are invalidMembers', () => {
+ it('adds in the correct class values for the tokens', async () => {
+ const badToken = { ...user1, class: INVALID_TOKEN_BACKGROUND };
+ const goodToken = { ...user2, class: VALID_TOKEN_BACKGROUND };
+
+ wrapper = createComponent();
+
+ findTokenSelector().vm.$emit('input', [user1, user2]);
+
+ await waitForPromises();
+
+ expect(findTokenSelector().props('selectedTokens')).toEqual([user1, user2]);
+
+ await wrapper.setProps({ invalidMembers: { one_1: 'bad stuff' } });
+
+ expect(findTokenSelector().props('selectedTokens')).toEqual([badToken, goodToken]);
+ });
+
+ it('does not change class when invalid members are cleared', async () => {
+ // arrange - invalidMembers is non-empty and then tokens are added
+ wrapper = createComponent();
+ await wrapper.setProps({ invalidMembers: { one_1: 'bad stuff' } });
+ findTokenSelector().vm.$emit('input', [user1, user2]);
+ await waitForPromises();
+
+ // act - invalidMembers clears out
+ await wrapper.setProps({ invalidMembers: {} });
+
+ // assert - we didn't try to update the tokens
+ expect(findTokenSelector().props('selectedTokens')).toEqual([user1, user2]);
+ });
+ });
+
describe('users', () => {
beforeEach(() => {
jest.spyOn(UserApi, 'getUsers').mockResolvedValue({ data: allUsers });
diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js
index f8471b7f167..69316b7f0ca 100644
--- a/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js
@@ -6,7 +6,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import WorkItemLinksMenu from '~/work_items/components/work_item_links/work_item_links_menu.vue';
-import changeWorkItemParentMutation from '~/work_items/graphql/change_work_item_parent_link.mutation.graphql';
+import changeWorkItemParentMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
import getWorkItemLinksQuery from '~/work_items/graphql/work_item_links.query.graphql';
import { WIDGET_TYPE_HIERARCHY } from '~/work_items/constants';
import { workItemHierarchyResponse, changeWorkItemParentMutationResponse } from '../../mock_data';
@@ -87,8 +87,12 @@ describe('WorkItemLinksMenu', () => {
await waitForPromises();
expect(mutationHandler).toHaveBeenCalledWith({
- id: WORK_ITEM_ID,
- parentId: null,
+ input: {
+ id: WORK_ITEM_ID,
+ hierarchyWidget: {
+ parentId: null,
+ },
+ },
});
});
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index 46aaf480564..050d3c56727 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -480,14 +480,19 @@ export const changeWorkItemParentMutationResponse = {
data: {
workItemUpdate: {
workItem: {
+ description: null,
id: 'gid://gitlab/WorkItem/2',
- workItemType: {
- id: 'gid://gitlab/WorkItems::Type/5',
- __typename: 'WorkItemType',
- },
- title: 'Foo',
state: 'OPEN',
- __typename: 'WorkItem',
+ title: 'Foo',
+ widgets: [
+ {
+ type: 'HIERARCHY',
+ parent: null,
+ children: {
+ nodes: [],
+ },
+ },
+ ],
},
errors: [],
__typename: 'WorkItemUpdatePayload',
diff --git a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb
index b5122af5cd4..6f75d3faef3 100644
--- a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migrat
let(:file_name) { 'file_name.rb' }
let(:content) { 'content' }
- let(:ids) { snippets.pluck('MIN(id)', 'MAX(id)').first }
+ let(:ids) { snippets.pick('MIN(id)', 'MAX(id)') }
let(:service) { described_class.new }
subject { service.perform(*ids) }
diff --git a/spec/lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url_spec.rb b/spec/lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url_spec.rb
index b96d3f7f0b5..564d970280c 100644
--- a/spec/lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url_spec.rb
+++ b/spec/lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url_spec.rb
@@ -2,10 +2,26 @@
require 'spec_helper'
-RSpec.describe Gitlab::BackgroundMigration::UpdateJiraTrackerDataDeploymentTypeBasedOnUrl, schema: 20210421163509 do
- let(:services_table) { table(:services) }
- let(:service_jira_cloud) { services_table.create!(id: 1, type: 'JiraService') }
- let(:service_jira_server) { services_table.create!(id: 2, type: 'JiraService') }
+RSpec.describe Gitlab::BackgroundMigration::UpdateJiraTrackerDataDeploymentTypeBasedOnUrl do
+ let(:integrations_table) { table(:integrations) }
+ let(:service_jira_cloud) { integrations_table.create!(id: 1, type_new: 'JiraService') }
+ let(:service_jira_server) { integrations_table.create!(id: 2, type_new: 'JiraService') }
+ let(:service_jira_unknown) { integrations_table.create!(id: 3, type_new: 'JiraService') }
+
+ let(:table_name) { :jira_tracker_data }
+ let(:batch_column) { :id }
+ let(:sub_batch_size) { 1 }
+ let(:pause_ms) { 0 }
+ let(:migration) do
+ described_class.new(start_id: 1, end_id: 10,
+ batch_table: table_name, batch_column: batch_column,
+ sub_batch_size: sub_batch_size, pause_ms: pause_ms,
+ connection: ApplicationRecord.connection)
+ end
+
+ subject(:perform_migration) do
+ migration.perform
+ end
before do
jira_tracker_data = Class.new(ApplicationRecord) do
@@ -27,18 +43,21 @@ RSpec.describe Gitlab::BackgroundMigration::UpdateJiraTrackerDataDeploymentTypeB
end
stub_const('JiraTrackerData', jira_tracker_data)
- end
- let!(:tracker_data_cloud) { JiraTrackerData.create!(id: 1, service_id: service_jira_cloud.id, url: "https://test-domain.atlassian.net", deployment_type: 0) }
- let!(:tracker_data_server) { JiraTrackerData.create!(id: 2, service_id: service_jira_server.id, url: "http://totally-not-jira-server.company.org", deployment_type: 0) }
+ stub_const('UNKNOWN', 0)
+ stub_const('SERVER', 1)
+ stub_const('CLOUD', 2)
+ end
- subject { described_class.new.perform(tracker_data_cloud.id, tracker_data_server.id) }
+ let!(:tracker_data_cloud) { JiraTrackerData.create!(id: 1, service_id: service_jira_cloud.id, url: "https://test-domain.atlassian.net", deployment_type: UNKNOWN) }
+ let!(:tracker_data_server) { JiraTrackerData.create!(id: 2, service_id: service_jira_server.id, url: "http://totally-not-jira-server.company.org", deployment_type: UNKNOWN) }
+ let!(:tracker_data_unknown) { JiraTrackerData.create!(id: 3, service_id: service_jira_unknown.id, url: "", deployment_type: UNKNOWN) }
it "changes unknown deployment_types based on URL" do
- expect(JiraTrackerData.pluck(:deployment_type)).to eq([0, 0])
+ expect(JiraTrackerData.pluck(:deployment_type)).to match_array([UNKNOWN, UNKNOWN, UNKNOWN])
- subject
+ perform_migration
- expect(JiraTrackerData.pluck(:deployment_type)).to eq([2, 1])
+ expect(JiraTrackerData.order(:id).pluck(:deployment_type)).to match_array([CLOUD, SERVER, UNKNOWN])
end
end
diff --git a/spec/migrations/20210421163509_schedule_update_jira_tracker_data_deployment_type_based_on_url_spec.rb b/spec/migrations/20220725150127_update_jira_tracker_data_deployment_type_based_on_url_spec.rb
index 9a59c739ecd..a471b00592c 100644
--- a/spec/migrations/20210421163509_schedule_update_jira_tracker_data_deployment_type_based_on_url_spec.rb
+++ b/spec/migrations/20220725150127_update_jira_tracker_data_deployment_type_based_on_url_spec.rb
@@ -3,10 +3,10 @@
require 'spec_helper'
require_migration!
-RSpec.describe ScheduleUpdateJiraTrackerDataDeploymentTypeBasedOnUrl, :migration do
- let(:services_table) { table(:services) }
- let(:service_jira_cloud) { services_table.create!(id: 1, type: 'JiraService') }
- let(:service_jira_server) { services_table.create!(id: 2, type: 'JiraService') }
+RSpec.describe UpdateJiraTrackerDataDeploymentTypeBasedOnUrl, :migration do
+ let(:integrations_table) { table(:integrations) }
+ let(:service_jira_cloud) { integrations_table.create!(id: 1, type_new: 'JiraService') }
+ let(:service_jira_server) { integrations_table.create!(id: 2, type_new: 'JiraService') }
before do
jira_tracker_data = Class.new(ApplicationRecord) do
@@ -29,20 +29,30 @@ RSpec.describe ScheduleUpdateJiraTrackerDataDeploymentTypeBasedOnUrl, :migration
stub_const('JiraTrackerData', jira_tracker_data)
stub_const("#{described_class}::BATCH_SIZE", 1)
+ stub_const("#{described_class}::SUB_BATCH_SIZE", 1)
end
+ # rubocop:disable Layout/LineLength
+ # rubocop:disable RSpec/ScatteredLet
let!(:tracker_data_cloud) { JiraTrackerData.create!(id: 1, service_id: service_jira_cloud.id, url: "https://test-domain.atlassian.net", deployment_type: 0) }
let!(:tracker_data_server) { JiraTrackerData.create!(id: 2, service_id: service_jira_server.id, url: "http://totally-not-jira-server.company.org", deployment_type: 0) }
+ # rubocop:enable Layout/LineLength
+ # rubocop:enable RSpec/ScatteredLet
around do |example|
freeze_time { Sidekiq::Testing.fake! { example.run } }
end
+ let(:migration) { described_class::MIGRATION } # rubocop:disable RSpec/ScatteredLet
+
it 'schedules background migration' do
migrate!
- expect(BackgroundMigrationWorker.jobs.size).to eq(2)
- expect(described_class::MIGRATION).to be_scheduled_migration(tracker_data_cloud.id, tracker_data_cloud.id)
- expect(described_class::MIGRATION).to be_scheduled_migration(tracker_data_server.id, tracker_data_server.id)
+ expect(migration).to have_scheduled_batched_migration(
+ table_name: :jira_tracker_data,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL,
+ gitlab_schema: :gitlab_main
+ )
end
end
diff --git a/spec/models/merge_request/approval_removal_settings_spec.rb b/spec/models/merge_request/approval_removal_settings_spec.rb
new file mode 100644
index 00000000000..e84fd403a55
--- /dev/null
+++ b/spec/models/merge_request/approval_removal_settings_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe MergeRequest::ApprovalRemovalSettings do
+ describe 'validations' do
+ let(:reset_approvals_on_push) { }
+ let(:selective_code_owner_removals) { }
+
+ subject { described_class.new(project, reset_approvals_on_push, selective_code_owner_removals) }
+
+ context 'when enabling selective_code_owner_removals and reset_approvals_on_push is disabled' do
+ let(:project) { create(:project, reset_approvals_on_push: false) }
+ let(:selective_code_owner_removals) { true }
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'when enabling selective_code_owner_removals and reset_approvals_on_push is enabled' do
+ let(:project) { create(:project) }
+ let(:selective_code_owner_removals) { true }
+
+ it { is_expected.not_to be_valid }
+ end
+
+ context 'when enabling reset_approvals_on_push and selective_code_owner_removals is disabled' do
+ let(:project) { create(:project) }
+ let(:reset_approvals_on_push) { true }
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'when enabling reset_approvals_on_push and selective_code_owner_removals is enabled' do
+ let(:project) { create(:project) }
+ let(:reset_approvals_on_push) { true }
+
+ before do
+ project.project_setting.update!(selective_code_owner_removals: true)
+ end
+
+ it { is_expected.not_to be_valid }
+ end
+
+ context 'when enabling reset_approvals_on_push and selective_code_owner_removals' do
+ let(:project) { create(:project) }
+ let(:reset_approvals_on_push) { true }
+ let(:selective_code_owner_removals) { true }
+
+ it { is_expected.not_to be_valid }
+ end
+ end
+end
diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml
index 8d3622ca17d..af93c1b6de2 100644
--- a/spec/requests/api/project_attributes.yml
+++ b/spec/requests/api/project_attributes.yml
@@ -157,6 +157,7 @@ project_setting:
- cve_id_request_enabled
- mr_default_target_self
- target_platforms
+ - selective_code_owner_removals
build_service_desk_setting: # service_desk_setting
unexposed_attributes:
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb
index b092df4a116..65540f86d34 100644
--- a/spec/requests/projects/cycle_analytics_events_spec.rb
+++ b/spec/requests/projects/cycle_analytics_events_spec.rb
@@ -10,8 +10,8 @@ RSpec.describe 'value stream analytics events' do
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
describe 'GET /:namespace/:project/value_stream_analytics/events/issues' do
- let(:first_issue_iid) { project.issues.sort_by_attribute(:created_desc).pluck(:iid).first.to_s }
- let(:first_mr_iid) { project.merge_requests.sort_by_attribute(:created_desc).pluck(:iid).first.to_s }
+ let(:first_issue_iid) { project.issues.sort_by_attribute(:created_desc).pick(:iid).to_s }
+ let(:first_mr_iid) { project.merge_requests.sort_by_attribute(:created_desc).pick(:iid).to_s }
before do
project.add_developer(user)
diff --git a/spec/support/helpers/features/invite_members_modal_helper.rb b/spec/support/helpers/features/invite_members_modal_helper.rb
index b56ac5b32c6..42b5c44a1c6 100644
--- a/spec/support/helpers/features/invite_members_modal_helper.rb
+++ b/spec/support/helpers/features/invite_members_modal_helper.rb
@@ -11,7 +11,7 @@ module Spec
page.within invite_modal_selector do
select_members(names)
choose_options(role, expires_at)
- click_button 'Invite'
+ submit_invites
end
page.refresh if refresh
@@ -42,11 +42,15 @@ module Spec
click_button name
choose_options(role, expires_at)
- click_button 'Invite'
+ submit_invites
page.refresh
end
+ def submit_invites
+ click_button 'Invite'
+ end
+
def choose_options(role, expires_at)
unless role == 'Guest'
click_button 'Guest'
@@ -92,6 +96,29 @@ module Spec
end
end
+ def expect_to_have_successful_invite_indicator(page, user)
+ expect(page).to have_selector("#{member_token_selector(user.id)} .gl-bg-green-100")
+ expect(page).not_to have_text("#{user.name}: ")
+ end
+
+ def expect_to_have_invalid_invite_indicator(page, user)
+ expect(page).to have_selector("#{member_token_selector(user.id)} .gl-bg-red-100")
+ expect(page).to have_selector(member_token_error_selector(user.id))
+ expect(page).to have_text("#{user.name}: Access level should be greater than or equal to")
+ end
+
+ def expect_to_have_normal_invite_indicator(page, user)
+ expect(page).to have_selector(member_token_selector(user.id))
+ expect(page).not_to have_selector("#{member_token_selector(user.id)} .gl-bg-red-100")
+ expect(page).not_to have_selector("#{member_token_selector(user.id)} .gl-bg-green-100")
+ expect(page).not_to have_text("#{user.name}: ")
+ end
+
+ def expect_to_have_invite_removed(page, user)
+ expect(page).not_to have_selector(member_token_selector(user.id))
+ expect(page).not_to have_text("#{user.name}: Access level should be greater than or equal to")
+ end
+
def expect_to_have_group(group)
expect(page).to have_selector("[entity-id='#{group.id}']")
end
diff --git a/spec/support/shared_examples/features/inviting_members_shared_examples.rb b/spec/support/shared_examples/features/inviting_members_shared_examples.rb
index bca0e02fcdd..9d22b78c71d 100644
--- a/spec/support/shared_examples/features/inviting_members_shared_examples.rb
+++ b/spec/support/shared_examples/features/inviting_members_shared_examples.rb
@@ -147,9 +147,9 @@ RSpec.shared_examples 'inviting members' do |snowplow_invite_label|
invite_member(user2.name, role: role, refresh: false)
- expect(page).to have_selector(invite_modal_selector)
- expect(page).to have_content "#{user2.name}: Access level should be greater than or equal to Developer " \
- "inherited membership from group #{group.name}"
+ invite_modal = page.find(invite_modal_selector)
+ expect(invite_modal).to have_content "#{user2.name}: Access level should be greater than or equal to " \
+ "Developer inherited membership from group #{group.name}"
page.refresh
@@ -166,31 +166,44 @@ RSpec.shared_examples 'inviting members' do |snowplow_invite_label|
group.add_maintainer(user3)
end
- it 'shows the user errors and then removes them from the form', :js do
+ it 'shows the partial user error and success and then removes them from the form', :js do
+ user4 = create(:user)
+ user5 = create(:user)
+
visit subentity_members_page_path
- invite_member([user2.name, user3.name], role: role, refresh: false)
+ invite_member([user2.name, user3.name, user4.name], role: role, refresh: false)
+
+ invite_modal = page.find(invite_modal_selector)
+ expect(invite_modal).to have_text("The following 2 members couldn't be invited")
+ expect_to_have_invalid_invite_indicator(invite_modal, user2)
+ expect_to_have_invalid_invite_indicator(invite_modal, user3)
+ expect_to_have_successful_invite_indicator(invite_modal, user4)
- expect(page).to have_selector(invite_modal_selector)
- expect(page).to have_selector(member_token_error_selector(user2.id))
- expect(page).to have_selector(member_token_error_selector(user3.id))
- expect(page).to have_text("The following 2 members couldn't be invited")
- expect(page).to have_text("#{user2.name}: Access level should be greater than or equal to")
- expect(page).to have_text("#{user3.name}: Access level should be greater than or equal to")
+ # adds new token, but doesn't submit
+ select_members(user5.name)
+
+ expect_to_have_normal_invite_indicator(invite_modal, user5)
remove_token(user2.id)
- expect(page).not_to have_selector(member_token_error_selector(user2.id))
- expect(page).to have_selector(member_token_error_selector(user3.id))
- expect(page).to have_text("The following member couldn't be invited")
- expect(page).not_to have_text("#{user2.name}: Access level should be greater than or equal to")
+ expect(invite_modal).to have_text("The following member couldn't be invited")
+ expect_to_have_invite_removed(invite_modal, user2)
+ expect_to_have_invalid_invite_indicator(invite_modal, user3)
+ expect_to_have_successful_invite_indicator(invite_modal, user4)
+ expect_to_have_normal_invite_indicator(invite_modal, user5)
remove_token(user3.id)
- expect(page).not_to have_selector(member_token_error_selector(user3.id))
- expect(page).not_to have_text("The following member couldn't be invited")
- expect(page).not_to have_text("Review the invite errors and try again")
- expect(page).not_to have_text("#{user3.name}: Access level should be greater than or equal to")
+ expect(invite_modal).not_to have_text("The following member couldn't be invited")
+ expect(invite_modal).not_to have_text("Review the invite errors and try again")
+ expect_to_have_invite_removed(invite_modal, user3)
+ expect_to_have_successful_invite_indicator(invite_modal, user4)
+ expect_to_have_normal_invite_indicator(invite_modal, user5)
+
+ submit_invites
+
+ expect(page).not_to have_selector(invite_modal_selector)
page.refresh
@@ -203,6 +216,10 @@ RSpec.shared_examples 'inviting members' do |snowplow_invite_label|
expect(page).to have_content('Maintainer')
expect(page).not_to have_button('Maintainer')
end
+
+ page.within find_invited_member_row(user4.name) do
+ expect(page).to have_button(role)
+ end
end
it 'only shows the error for an invalid formatted email and does not display other member errors', :js do
@@ -210,12 +227,12 @@ RSpec.shared_examples 'inviting members' do |snowplow_invite_label|
invite_member([user2.name, user3.name, 'bad@email'], role: role, refresh: false)
- expect(page).to have_selector(invite_modal_selector)
- expect(page).to have_text('email contains an invalid email address')
- expect(page).not_to have_text("The following 2 members couldn't be invited")
- expect(page).not_to have_text("Review the invite errors and try again")
- expect(page).not_to have_text("#{user2.name}: Access level should be greater than or equal to")
- expect(page).not_to have_text("#{user3.name}: Access level should be greater than or equal to")
+ invite_modal = page.find(invite_modal_selector)
+ expect(invite_modal).to have_text('email contains an invalid email address')
+ expect(invite_modal).not_to have_text("The following 2 members couldn't be invited")
+ expect(invite_modal).not_to have_text("Review the invite errors and try again")
+ expect(invite_modal).not_to have_text("#{user2.name}: Access level should be greater than or equal to")
+ expect(invite_modal).not_to have_text("#{user3.name}: Access level should be greater than or equal to")
end
end
end