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>2021-08-20 12:09:16 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-08-20 12:09:16 +0300
commit55e6eebd6fc60bd98d94303983468b3020d2a211 (patch)
treec922d4773a92a2c34c1f134746ada25113e67bb1 /spec
parent52fac331ea3cc2b2dbc126f4b859350f30167632 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/customer_relations/contacts.rb14
-rw-r--r--spec/features/atom/issues_spec.rb84
-rw-r--r--spec/features/atom/merge_requests_spec.rb88
-rw-r--r--spec/features/issues/rss_spec.rb39
-rw-r--r--spec/features/merge_requests/rss_spec.rb46
-rw-r--r--spec/frontend/lib/utils/text_markdown_spec.js19
-rw-r--r--spec/lib/error_tracking/collector/dsn_spec.rb26
-rw-r--r--spec/models/ci/pipeline_spec.rb45
-rw-r--r--spec/models/customer_relations/contact_spec.rb37
-rw-r--r--spec/models/customer_relations/organization_spec.rb2
-rw-r--r--spec/requests/jira_connect/installations_controller_spec.rb95
-rw-r--r--spec/support/shared_examples/features/atom/issuable_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/features/rss_shared_examples.rb20
13 files changed, 418 insertions, 109 deletions
diff --git a/spec/factories/customer_relations/contacts.rb b/spec/factories/customer_relations/contacts.rb
new file mode 100644
index 00000000000..437f8feea48
--- /dev/null
+++ b/spec/factories/customer_relations/contacts.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :contact, class: 'CustomerRelations::Contact' do
+ group
+
+ first_name { generate(:name) }
+ last_name { generate(:name) }
+
+ trait :with_organization do
+ organization
+ end
+ end
+end
diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb
index 13798a94fe9..e6a862ddccc 100644
--- a/spec/features/atom/issues_spec.rb
+++ b/spec/features/atom/issues_spec.rb
@@ -4,61 +4,75 @@ require 'spec_helper'
RSpec.describe 'Issues Feed' do
describe 'GET /issues' do
- let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') }
- let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') }
- let!(:group) { create(:group) }
- let!(:project) { create(:project) }
- let!(:issue) { create(:issue, author: user, assignees: [assignee], project: project) }
-
- before do
+ let_it_be_with_reload(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') }
+ let_it_be(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:issue) { create(:issue, author: user, assignees: [assignee], project: project, due_date: Date.today) }
+ let_it_be(:issuable) { issue } # "alias" for shared examples
+
+ before_all do
project.add_developer(user)
group.add_developer(user)
end
+ RSpec.shared_examples 'an authenticated issue atom feed' do
+ it 'renders atom feed with additional issue information' do
+ expect(body).to have_selector('title', text: "#{project.name} issues")
+ expect(body).to have_selector('due_date', text: issue.due_date)
+ end
+ end
+
context 'when authenticated' do
- it 'renders atom feed' do
+ before do
sign_in user
visit project_issues_path(project, :atom)
-
- expect(response_headers['Content-Type'])
- .to have_content('application/atom+xml')
- expect(body).to have_selector('title', text: "#{project.name} issues")
- expect(body).to have_selector('author email', text: issue.author_public_email)
- expect(body).to have_selector('assignees assignee email', text: issue.assignees.first.public_email)
- expect(body).to have_selector('assignee email', text: issue.assignees.first.public_email)
- expect(body).to have_selector('entry summary', text: issue.title)
end
+
+ it_behaves_like 'an authenticated issuable atom feed'
+ it_behaves_like 'an authenticated issue atom feed'
end
context 'when authenticated via personal access token' do
- it 'renders atom feed' do
+ before do
personal_access_token = create(:personal_access_token, user: user)
visit project_issues_path(project, :atom,
- private_token: personal_access_token.token)
-
- expect(response_headers['Content-Type'])
- .to have_content('application/atom+xml')
- expect(body).to have_selector('title', text: "#{project.name} issues")
- expect(body).to have_selector('author email', text: issue.author_public_email)
- expect(body).to have_selector('assignees assignee email', text: issue.assignees.first.public_email)
- expect(body).to have_selector('assignee email', text: issue.assignees.first.public_email)
- expect(body).to have_selector('entry summary', text: issue.title)
+ private_token: personal_access_token.token)
end
+
+ it_behaves_like 'an authenticated issuable atom feed'
+ it_behaves_like 'an authenticated issue atom feed'
end
context 'when authenticated via feed token' do
- it 'renders atom feed' do
+ before do
visit project_issues_path(project, :atom,
- feed_token: user.feed_token)
+ feed_token: user.feed_token)
+ end
- expect(response_headers['Content-Type'])
- .to have_content('application/atom+xml')
- expect(body).to have_selector('title', text: "#{project.name} issues")
- expect(body).to have_selector('author email', text: issue.author_public_email)
- expect(body).to have_selector('assignees assignee email', text: issue.assignees.first.public_email)
- expect(body).to have_selector('assignee email', text: issue.assignees.first.public_email)
- expect(body).to have_selector('entry summary', text: issue.title)
+ it_behaves_like 'an authenticated issuable atom feed'
+ it_behaves_like 'an authenticated issue atom feed'
+ end
+
+ context 'when not authenticated' do
+ before do
+ visit project_issues_path(project, :atom)
+ end
+
+ context 'and the project is private' do
+ it 'redirects to login page' do
+ expect(page).to have_current_path(new_user_session_path)
+ end
+ end
+
+ context 'and the project is public' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:issue) { create(:issue, author: user, assignees: [assignee], project: project, due_date: Date.today) }
+ let_it_be(:issuable) { issue } # "alias" for shared examples
+
+ it_behaves_like 'an authenticated issuable atom feed'
+ it_behaves_like 'an authenticated issue atom feed'
end
end
diff --git a/spec/features/atom/merge_requests_spec.rb b/spec/features/atom/merge_requests_spec.rb
new file mode 100644
index 00000000000..29f0b4660c9
--- /dev/null
+++ b/spec/features/atom/merge_requests_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge Requests Feed' do
+ describe 'GET /merge_requests' do
+ let_it_be_with_reload(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') }
+ let_it_be(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project, assignees: [assignee]) }
+ let_it_be(:issuable) { merge_request } # "alias" for shared examples
+
+ before_all do
+ project.add_developer(user)
+ group.add_developer(user)
+ end
+
+ RSpec.shared_examples 'an authenticated merge request atom feed' do
+ it 'renders atom feed with additional merge request information' do
+ expect(body).to have_selector('title', text: "#{project.name} merge requests")
+ end
+ end
+
+ context 'when authenticated' do
+ before do
+ sign_in user
+ visit project_merge_requests_path(project, :atom)
+ end
+
+ it_behaves_like 'an authenticated issuable atom feed'
+ it_behaves_like 'an authenticated merge request atom feed'
+
+ context 'but the use can not see the project' do
+ let_it_be(:other_project) { create(:project) }
+
+ it 'renders 404 page' do
+ visit project_issues_path(other_project, :atom)
+
+ expect(page).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'when authenticated via personal access token' do
+ before do
+ personal_access_token = create(:personal_access_token, user: user)
+
+ visit project_merge_requests_path(project, :atom,
+ private_token: personal_access_token.token)
+ end
+
+ it_behaves_like 'an authenticated issuable atom feed'
+ it_behaves_like 'an authenticated merge request atom feed'
+ end
+
+ context 'when authenticated via feed token' do
+ before do
+ visit project_merge_requests_path(project, :atom,
+ feed_token: user.feed_token)
+ end
+
+ it_behaves_like 'an authenticated issuable atom feed'
+ it_behaves_like 'an authenticated merge request atom feed'
+ end
+
+ context 'when not authenticated' do
+ before do
+ visit project_merge_requests_path(project, :atom)
+ end
+
+ context 'and the project is private' do
+ it 'redirects to login page' do
+ expect(page).to have_current_path(new_user_session_path)
+ end
+ end
+
+ context 'and the project is public' do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project, assignees: [assignee]) }
+ let_it_be(:issuable) { merge_request } # "alias" for shared examples
+
+ it_behaves_like 'an authenticated issuable atom feed'
+ it_behaves_like 'an authenticated merge request atom feed'
+ end
+ end
+ end
+end
diff --git a/spec/features/issues/rss_spec.rb b/spec/features/issues/rss_spec.rb
index 6c4498ea711..b20502ecc25 100644
--- a/spec/features/issues/rss_spec.rb
+++ b/spec/features/issues/rss_spec.rb
@@ -3,21 +3,24 @@
require 'spec_helper'
RSpec.describe 'Project Issues RSS' do
- let!(:user) { create(:user) }
- let(:group) { create(:group) }
- let(:project) { create(:project, group: group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
- let(:path) { project_issues_path(project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
+ let_it_be(:path) { project_issues_path(project) }
+ let_it_be(:issue) { create(:issue, project: project, assignees: [user]) }
- before do
- create(:issue, project: project, assignees: [user])
+ before_all do
group.add_developer(user)
end
context 'when signed in' do
- let(:user) { create(:user) }
+ let_it_be(:user) { create(:user) }
- before do
+ before_all do
project.add_developer(user)
+ end
+
+ before do
sign_in(user)
visit path
end
@@ -36,26 +39,6 @@ RSpec.describe 'Project Issues RSS' do
end
describe 'feeds' do
- shared_examples 'updates atom feed link' do |type|
- it "for #{type}" do
- sign_in(user)
- visit path
-
- link = find_link('Subscribe to RSS feed')
- params = CGI.parse(URI.parse(link[:href]).query)
- auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
- auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
-
- expected = {
- 'feed_token' => [user.feed_token],
- 'assignee_id' => [user.id.to_s]
- }
-
- expect(params).to include(expected)
- expect(auto_discovery_params).to include(expected)
- end
- end
-
it_behaves_like 'updates atom feed link', :project do
let(:path) { project_issues_path(project, assignee_id: user.id) }
end
diff --git a/spec/features/merge_requests/rss_spec.rb b/spec/features/merge_requests/rss_spec.rb
new file mode 100644
index 00000000000..9fc3d3d6ae1
--- /dev/null
+++ b/spec/features/merge_requests/rss_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Project Merge Requests RSS' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :repository, group: group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project, assignees: [user]) }
+ let_it_be(:path) { project_merge_requests_path(project) }
+
+ before_all do
+ group.add_developer(user)
+ end
+
+ context 'when signed in' do
+ let_it_be(:user) { create(:user) }
+
+ before_all do
+ project.add_developer(user)
+ end
+
+ before do
+ sign_in(user)
+ visit path
+ end
+
+ it_behaves_like "it has an RSS button with current_user's feed token"
+ it_behaves_like "an autodiscoverable RSS feed with current_user's feed token"
+ end
+
+ context 'when signed out' do
+ before do
+ visit path
+ end
+
+ it_behaves_like "it has an RSS button without a feed token"
+ it_behaves_like "an autodiscoverable RSS feed without a feed token"
+ end
+
+ describe 'feeds' do
+ it_behaves_like 'updates atom feed link', :project do
+ let(:path) { project_merge_requests_path(project, assignee_id: user.id) }
+ end
+ end
+end
diff --git a/spec/frontend/lib/utils/text_markdown_spec.js b/spec/frontend/lib/utils/text_markdown_spec.js
index beedb9b2eba..9fe2780fde2 100644
--- a/spec/frontend/lib/utils/text_markdown_spec.js
+++ b/spec/frontend/lib/utils/text_markdown_spec.js
@@ -70,6 +70,25 @@ describe('init markdown', () => {
expect(textArea.value).toContain('# Does not parse the `$` currently.');
});
+ it('inserts a new line correctly', () => {
+ const initialValue = '';
+
+ textArea.value = initialValue;
+ textArea.selectionStart = 0;
+ textArea.selectionEnd = 0;
+
+ insertMarkdownText({
+ textArea,
+ text: textArea.value,
+ tag: '```suggestion:-0+0\n{text}\n```',
+ blockTag: true,
+ selected: '# Does not parse the \\n currently.',
+ wrap: false,
+ });
+
+ expect(textArea.value).toContain('# Does not parse the \\n currently.');
+ });
+
it('inserts the tag on a new line if the current one is not empty', () => {
const initialValue = 'some text';
diff --git a/spec/lib/error_tracking/collector/dsn_spec.rb b/spec/lib/error_tracking/collector/dsn_spec.rb
new file mode 100644
index 00000000000..af55e6f20ec
--- /dev/null
+++ b/spec/lib/error_tracking/collector/dsn_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ErrorTracking::Collector::Dsn do
+ describe '.build__url' do
+ let(:gitlab) do
+ double(
+ protocol: 'https',
+ https: true,
+ host: 'gitlab.example.com',
+ port: '4567',
+ relative_url_root: nil
+ )
+ end
+
+ subject { described_class.build_url('abcdef1234567890', 778) }
+
+ it 'returns a valid URL' do
+ allow(Settings).to receive(:gitlab).and_return(gitlab)
+ allow(Settings).to receive(:gitlab_on_standard_port?).and_return(false)
+
+ is_expected.to eq('https://abcdef1234567890@gitlab.example.com:4567/api/v4/error_tracking/collector/778')
+ end
+ end
+end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index da89eccc3b2..597d532f8f1 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -4524,51 +4524,6 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
subject(:reset_bridge) { pipeline.reset_source_bridge!(project.owner) }
- # This whole block will be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/329194
- # It contains some duplicate checks.
- context 'when the FF ci_reset_bridge_with_subsequent_jobs is disabled' do
- before do
- stub_feature_flags(ci_reset_bridge_with_subsequent_jobs: false)
- end
-
- context 'when the pipeline is a child pipeline and the bridge is depended' do
- let!(:parent_pipeline) { create(:ci_pipeline) }
- let!(:bridge) { create_bridge(parent_pipeline, pipeline, true) }
-
- it 'marks source bridge as pending' do
- reset_bridge
-
- expect(bridge.reload).to be_pending
- end
-
- context 'when the parent pipeline has subsequent jobs after the bridge' do
- let!(:after_bridge_job) { create(:ci_build, :skipped, pipeline: parent_pipeline, stage_idx: bridge.stage_idx + 1) }
-
- it 'does not touch subsequent jobs of the bridge' do
- reset_bridge
-
- expect(after_bridge_job.reload).to be_skipped
- end
- end
-
- context 'when the parent pipeline has a dependent upstream pipeline' do
- let(:upstream_pipeline) { create(:ci_pipeline, project: create(:project)) }
- let!(:upstream_bridge) { create_bridge(upstream_pipeline, parent_pipeline, true) }
-
- let(:upstream_upstream_pipeline) { create(:ci_pipeline, project: create(:project)) }
- let!(:upstream_upstream_bridge) { create_bridge(upstream_upstream_pipeline, upstream_pipeline, true) }
-
- it 'marks all source bridges as pending' do
- reset_bridge
-
- expect(bridge.reload).to be_pending
- expect(upstream_bridge.reload).to be_pending
- expect(upstream_upstream_bridge.reload).to be_pending
- end
- end
- end
- end
-
context 'when the pipeline is a child pipeline and the bridge is depended' do
let!(:parent_pipeline) { create(:ci_pipeline) }
let!(:bridge) { create_bridge(parent_pipeline, pipeline, true) }
diff --git a/spec/models/customer_relations/contact_spec.rb b/spec/models/customer_relations/contact_spec.rb
new file mode 100644
index 00000000000..b19554dd67e
--- /dev/null
+++ b/spec/models/customer_relations/contact_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe CustomerRelations::Contact, type: :model do
+ describe 'associations' do
+ it { is_expected.to belong_to(:group) }
+ it { is_expected.to belong_to(:organization).optional }
+ end
+
+ describe 'validations' do
+ subject { build(:contact) }
+
+ it { is_expected.to validate_presence_of(:group) }
+ it { is_expected.to validate_presence_of(:first_name) }
+ it { is_expected.to validate_presence_of(:last_name) }
+
+ it { is_expected.to validate_length_of(:phone).is_at_most(32) }
+ it { is_expected.to validate_length_of(:first_name).is_at_most(255) }
+ it { is_expected.to validate_length_of(:last_name).is_at_most(255) }
+ it { is_expected.to validate_length_of(:email).is_at_most(255) }
+ it { is_expected.to validate_length_of(:description).is_at_most(1024) }
+
+ it_behaves_like 'an object with RFC3696 compliant email-formatted attributes', :email
+ end
+
+ describe '#before_validation' do
+ it 'strips leading and trailing whitespace' do
+ contact = described_class.new(first_name: ' First ', last_name: ' Last ', phone: ' 123456 ')
+ contact.valid?
+
+ expect(contact.first_name).to eq('First')
+ expect(contact.last_name).to eq('Last')
+ expect(contact.phone).to eq('123456')
+ end
+ end
+end
diff --git a/spec/models/customer_relations/organization_spec.rb b/spec/models/customer_relations/organization_spec.rb
index b79b5748156..71b455ae8c8 100644
--- a/spec/models/customer_relations/organization_spec.rb
+++ b/spec/models/customer_relations/organization_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe CustomerRelations::Organization, type: :model do
end
describe 'validations' do
- subject { create(:organization) }
+ subject { build(:organization) }
it { is_expected.to validate_presence_of(:group) }
it { is_expected.to validate_presence_of(:name) }
diff --git a/spec/requests/jira_connect/installations_controller_spec.rb b/spec/requests/jira_connect/installations_controller_spec.rb
new file mode 100644
index 00000000000..6315c66a41a
--- /dev/null
+++ b/spec/requests/jira_connect/installations_controller_spec.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe JiraConnect::InstallationsController do
+ let_it_be(:installation) { create(:jira_connect_installation) }
+
+ describe 'GET /-/jira_connect/installations' do
+ before do
+ get '/-/jira_connect/installations', params: { jwt: jwt }
+ end
+
+ context 'without JWT' do
+ let(:jwt) { nil }
+
+ it 'returns 403' do
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'with valid JWT' do
+ let(:qsh) { Atlassian::Jwt.create_query_string_hash('https://gitlab.test/installations', 'GET', 'https://gitlab.test') }
+ let(:jwt) { Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret) }
+
+ it 'returns status ok' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns the installation as json' do
+ expect(json_response).to eq({
+ 'gitlab_com' => true,
+ 'instance_url' => nil
+ })
+ end
+
+ context 'with instance_url' do
+ let_it_be(:installation) { create(:jira_connect_installation, instance_url: 'https://example.com') }
+
+ it 'returns the installation as json' do
+ expect(json_response).to eq({
+ 'gitlab_com' => false,
+ 'instance_url' => 'https://example.com'
+ })
+ end
+ end
+ end
+ end
+
+ describe 'PUT /-/jira_connect/installations' do
+ before do
+ put '/-/jira_connect/installations', params: { jwt: jwt, installation: { instance_url: update_instance_url } }
+ end
+
+ let(:update_instance_url) { 'https://example.com' }
+
+ context 'without JWT' do
+ let(:jwt) { nil }
+
+ it 'returns 403' do
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'with valid JWT' do
+ let(:qsh) { Atlassian::Jwt.create_query_string_hash('https://gitlab.test/subscriptions', 'GET', 'https://gitlab.test') }
+ let(:jwt) { Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret) }
+
+ it 'returns 200' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'updates the instance_url' do
+ expect(json_response).to eq({
+ 'gitlab_com' => false,
+ 'instance_url' => 'https://example.com'
+ })
+ end
+
+ context 'invalid URL' do
+ let(:update_instance_url) { 'invalid url' }
+
+ it 'returns 422 and errors', :aggregate_failures do
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response).to eq({
+ 'errors' => {
+ 'instance_url' => [
+ 'is blocked: Only allowed schemes are http, https'
+ ]
+ }
+ })
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/atom/issuable_shared_examples.rb b/spec/support/shared_examples/features/atom/issuable_shared_examples.rb
new file mode 100644
index 00000000000..17993830f37
--- /dev/null
+++ b/spec/support/shared_examples/features/atom/issuable_shared_examples.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples "an authenticated issuable atom feed" do
+ it "renders atom feed with common issuable information" do
+ expect(response_headers['Content-Type'])
+ .to have_content('application/atom+xml')
+ expect(body).to have_selector('author email', text: issuable.author_public_email)
+ expect(body).to have_selector('assignees assignee email', text: issuable.assignees.first.public_email)
+ expect(body).to have_selector('assignee email', text: issuable.assignees.first.public_email)
+ expect(body).to have_selector('entry summary', text: issuable.title)
+ end
+end
diff --git a/spec/support/shared_examples/features/rss_shared_examples.rb b/spec/support/shared_examples/features/rss_shared_examples.rb
index c7c2aeea358..0991de21d8d 100644
--- a/spec/support/shared_examples/features/rss_shared_examples.rb
+++ b/spec/support/shared_examples/features/rss_shared_examples.rb
@@ -25,3 +25,23 @@ RSpec.shared_examples "it has an RSS button without a feed token" do
.to have_css("a:has(.qa-rss-icon):not([href*='feed_token'])") # rubocop:disable QA/SelectorUsage
end
end
+
+RSpec.shared_examples "updates atom feed link" do |type|
+ it "for #{type}" do
+ sign_in(user)
+ visit path
+
+ link = find_link('Subscribe to RSS feed')
+ params = CGI.parse(URI.parse(link[:href]).query)
+ auto_discovery_link = find("link[type='application/atom+xml']", visible: false)
+ auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
+
+ expected = {
+ 'feed_token' => [user.feed_token],
+ 'assignee_id' => [user.id.to_s]
+ }
+
+ expect(params).to include(expected)
+ expect(auto_discovery_params).to include(expected)
+ end
+end