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-06-15 21:09:29 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-06-15 21:09:29 +0300
commit0e5ce539275e32cfd7592362e03673807fca9cc7 (patch)
tree9d2c10afd7965a6dec4a48a36f9d0c886f55247c /spec
parent977720d7565377672df302ecb82b1e7a221cfba6 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/fixtures/pipeline_header.rb26
-rw-r--r--spec/frontend/pipelines/mock_data.js8
-rw-r--r--spec/frontend/pipelines/pipeline_details_header_spec.js14
-rw-r--r--spec/frontend/search/sort/components/app_spec.js23
-rw-r--r--spec/lib/atlassian/jira_connect/client_spec.rb7
-rw-r--r--spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb2
-rw-r--r--spec/models/error_tracking/project_error_tracking_setting_spec.rb2
-rw-r--r--spec/requests/api/admin/dictionary_spec.rb59
-rw-r--r--spec/requests/api/integrations_spec.rb1
-rw-r--r--spec/scripts/api/create_merge_request_note_spec.rb37
-rw-r--r--spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb279
11 files changed, 441 insertions, 17 deletions
diff --git a/spec/frontend/fixtures/pipeline_header.rb b/spec/frontend/fixtures/pipeline_header.rb
index 89f548caf72..3fdc45b1194 100644
--- a/spec/frontend/fixtures/pipeline_header.rb
+++ b/spec/frontend/fixtures/pipeline_header.rb
@@ -64,6 +64,32 @@ RSpec.describe "GraphQL Pipeline Header", '(JavaScript fixtures)', type: :reques
end
end
+ context 'with running pipeline and duration' do
+ let_it_be(:pipeline) do
+ create(
+ :ci_pipeline,
+ project: project,
+ sha: commit.id,
+ ref: 'master',
+ user: user,
+ status: :running,
+ duration: 7210,
+ created_at: 2.hours.ago,
+ started_at: 1.hour.ago
+ )
+ end
+
+ let_it_be(:build) { create(:ci_build, :running, pipeline: pipeline, ref: 'master') }
+
+ it "graphql/pipelines/pipeline_header_running_with_duration.json" do
+ query = get_graphql_query_as_string(query_path)
+
+ post_graphql(query, current_user: user, variables: { fullPath: project.full_path, iid: pipeline.iid })
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+
context 'with failed pipeline' do
let_it_be(:pipeline) do
create(
diff --git a/spec/frontend/pipelines/mock_data.js b/spec/frontend/pipelines/mock_data.js
index 8bbe0ef78c0..62c0d6e2d91 100644
--- a/spec/frontend/pipelines/mock_data.js
+++ b/spec/frontend/pipelines/mock_data.js
@@ -1,5 +1,6 @@
import pipelineHeaderSuccess from 'test_fixtures/graphql/pipelines/pipeline_header_success.json';
import pipelineHeaderRunning from 'test_fixtures/graphql/pipelines/pipeline_header_running.json';
+import pipelineHeaderRunningWithDuration from 'test_fixtures/graphql/pipelines/pipeline_header_running_with_duration.json';
import pipelineHeaderFailed from 'test_fixtures/graphql/pipelines/pipeline_header_failed.json';
const PIPELINE_RUNNING = 'RUNNING';
@@ -9,7 +10,12 @@ const PIPELINE_FAILED = 'FAILED';
const threeWeeksAgo = new Date();
threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
-export { pipelineHeaderSuccess, pipelineHeaderRunning, pipelineHeaderFailed };
+export {
+ pipelineHeaderSuccess,
+ pipelineHeaderRunning,
+ pipelineHeaderRunningWithDuration,
+ pipelineHeaderFailed,
+};
export const pipelineRetryMutationResponseSuccess = {
data: { pipelineRetry: { errors: [] } },
diff --git a/spec/frontend/pipelines/pipeline_details_header_spec.js b/spec/frontend/pipelines/pipeline_details_header_spec.js
index 2fef4924cc7..deaf5c6f72f 100644
--- a/spec/frontend/pipelines/pipeline_details_header_spec.js
+++ b/spec/frontend/pipelines/pipeline_details_header_spec.js
@@ -16,6 +16,7 @@ import getPipelineDetailsQuery from '~/pipelines/graphql/queries/get_pipeline_he
import {
pipelineHeaderSuccess,
pipelineHeaderRunning,
+ pipelineHeaderRunningWithDuration,
pipelineHeaderFailed,
pipelineRetryMutationResponseSuccess,
pipelineCancelMutationResponseSuccess,
@@ -33,6 +34,7 @@ describe('Pipeline details header', () => {
const successHandler = jest.fn().mockResolvedValue(pipelineHeaderSuccess);
const runningHandler = jest.fn().mockResolvedValue(pipelineHeaderRunning);
+ const runningHandlerWithDuration = jest.fn().mockResolvedValue(pipelineHeaderRunningWithDuration);
const failedHandler = jest.fn().mockResolvedValue(pipelineHeaderFailed);
const retryMutationHandlerSuccess = jest
@@ -273,6 +275,18 @@ describe('Pipeline details header', () => {
});
});
+ describe('running pipeline with duration', () => {
+ beforeEach(async () => {
+ createComponent([[getPipelineDetailsQuery, runningHandlerWithDuration]]);
+
+ await waitForPromises();
+ });
+
+ it('does not display pipeline duration text', () => {
+ expect(findPipelineDuration().exists()).toBe(false);
+ });
+ });
+
describe('actions', () => {
describe('retry action', () => {
beforeEach(async () => {
diff --git a/spec/frontend/search/sort/components/app_spec.js b/spec/frontend/search/sort/components/app_spec.js
index 322ce1b16ef..09c295e3ea9 100644
--- a/spec/frontend/search/sort/components/app_spec.js
+++ b/spec/frontend/search/sort/components/app_spec.js
@@ -1,4 +1,4 @@
-import { GlButtonGroup, GlButton, GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlButtonGroup, GlButton, GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
@@ -35,13 +35,16 @@ describe('GlobalSearchSort', () => {
...defaultProps,
...props,
},
+ stubs: {
+ GlCollapsibleListbox,
+ },
});
};
const findSortButtonGroup = () => wrapper.findComponent(GlButtonGroup);
- const findSortDropdown = () => wrapper.findComponent(GlDropdown);
+ const findSortDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
const findSortDirectionButton = () => wrapper.findComponent(GlButton);
- const findDropdownItems = () => findSortDropdown().findAllComponents(GlDropdownItem);
+ const findDropdownItems = () => findSortDropdown().findAllComponents(GlListboxItem);
const findDropdownItemsText = () => findDropdownItems().wrappers.map((w) => w.text());
describe('template', () => {
@@ -89,7 +92,7 @@ describe('GlobalSearchSort', () => {
});
it('is set correctly', () => {
- expect(findSortDropdown().attributes('text')).toBe(value);
+ expect(findSortDropdown().props('toggleText')).toBe(value);
});
});
});
@@ -116,14 +119,14 @@ describe('GlobalSearchSort', () => {
describe('actions', () => {
describe.each`
- description | index | value
- ${'non-sortable'} | ${0} | ${MOCK_SORT_OPTIONS[0].sortParam}
- ${'sortable'} | ${1} | ${MOCK_SORT_OPTIONS[1].sortParam.desc}
- `('handleSortChange', ({ description, index, value }) => {
- describe(`when clicking a ${description} option`, () => {
+ description | text | value
+ ${'non-sortable'} | ${MOCK_SORT_OPTIONS[0].title} | ${MOCK_SORT_OPTIONS[0].sortParam}
+ ${'sortable'} | ${MOCK_SORT_OPTIONS[1].title} | ${MOCK_SORT_OPTIONS[1].sortParam.desc}
+ `('handleSortChange', ({ description, text, value }) => {
+ describe(`when selecting a ${description} option`, () => {
beforeEach(() => {
createComponent();
- findDropdownItems().at(index).vm.$emit('click');
+ findSortDropdown().vm.$emit('select', text);
});
it('calls setQuery and applyQuery correctly', () => {
diff --git a/spec/lib/atlassian/jira_connect/client_spec.rb b/spec/lib/atlassian/jira_connect/client_spec.rb
index f1f9dd38947..66ae3658a92 100644
--- a/spec/lib/atlassian/jira_connect/client_spec.rb
+++ b/spec/lib/atlassian/jira_connect/client_spec.rb
@@ -11,9 +11,10 @@ RSpec.describe Atlassian::JiraConnect::Client, feature_category: :integrations d
let_it_be(:mrs_by_title) { create_list(:merge_request, 4, :unique_branches, :jira_title) }
let_it_be(:mrs_by_branch) { create_list(:merge_request, 2, :jira_branch) }
let_it_be(:red_herrings) { create_list(:merge_request, 1, :unique_branches) }
+ let_it_be(:mrs_by_description) { create_list(:merge_request, 2, :unique_branches, :jira_description) }
let_it_be(:pipelines) do
- (red_herrings + mrs_by_branch + mrs_by_title).map do |mr|
+ (red_herrings + mrs_by_branch + mrs_by_title + mrs_by_description).map do |mr|
create(:ci_pipeline, merge_request: mr)
end
end
@@ -253,7 +254,7 @@ RSpec.describe Atlassian::JiraConnect::Client, feature_category: :integrations d
it 'only sends information about relevant MRs' do
expect(subject).to receive(:post).with(
- '/rest/deployments/0.1/bulk', { deployments: have_attributes(size: 6) }
+ '/rest/deployments/0.1/bulk', { deployments: have_attributes(size: 8) }
).and_call_original
subject.send(:store_deploy_info, project: project, deployments: deployments)
@@ -378,7 +379,7 @@ RSpec.describe Atlassian::JiraConnect::Client, feature_category: :integrations d
it 'only sends information about relevant MRs' do
expect(subject).to receive(:post)
- .with('/rest/builds/0.1/bulk', { builds: have_attributes(size: 6) })
+ .with('/rest/builds/0.1/bulk', { builds: have_attributes(size: 8) })
.and_call_original
subject.send(:store_build_info, project: project, pipelines: pipelines)
diff --git a/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb b/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb
index f6fca39fa68..523b7ddaa09 100644
--- a/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb
+++ b/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb
@@ -69,7 +69,7 @@ RSpec.describe Atlassian::JiraConnect::Serializers::DeploymentEntity, feature_ca
subject.deployable.update!(pipeline: pipeline)
end
- %i[jira_branch jira_title].each do |trait|
+ %i[jira_branch jira_title jira_description].each do |trait|
context "because it belongs to an MR with a #{trait}" do
let(:merge_request) { create(:merge_request, trait) }
diff --git a/spec/models/error_tracking/project_error_tracking_setting_spec.rb b/spec/models/error_tracking/project_error_tracking_setting_spec.rb
index 34be6ec7fa9..a86283ea4ba 100644
--- a/spec/models/error_tracking/project_error_tracking_setting_spec.rb
+++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb
@@ -300,7 +300,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting, feature_category: :er
it { expect(result[:issue].gitlab_commit_path).to eq(nil) }
end
- context 'when repo commit matches first relase version' do
+ context 'when repo commit matches first release version' do
let(:commit) { instance_double(Commit, id: commit_id) }
let(:repository) { instance_double(Repository, commit: commit) }
diff --git a/spec/requests/api/admin/dictionary_spec.rb b/spec/requests/api/admin/dictionary_spec.rb
new file mode 100644
index 00000000000..effd3572423
--- /dev/null
+++ b/spec/requests/api/admin/dictionary_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Admin::Dictionary, feature_category: :database do
+ let(:admin) { create(:admin) }
+ let(:path) { "/admin/databases/main/dictionary/tables/achievements" }
+
+ describe 'GET admin/databases/:database_name/dictionary/tables/:table_name' do
+ it_behaves_like "GET request permissions for admin mode"
+
+ subject(:show_table_dictionary) do
+ get api(path, admin, admin_mode: true)
+ end
+
+ context 'when the database does not exist' do
+ it 'returns bad request' do
+ get api("/admin/databases/#{non_existing_record_id}/dictionary/tables/achievements", admin, admin_mode: true)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context 'when the table does not exist' do
+ it 'returns not found' do
+ get api("/admin/databases/main/dictionary/tables/#{non_existing_record_id}", admin, admin_mode: true)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'with a malicious table_name' do
+ it 'returns an error' do
+ get api("/admin/databases/main/dictionary/tables/%2E%2E%2Fpasswords.yml", admin, admin_mode: true)
+
+ expect(response).to have_gitlab_http_status(:error)
+ end
+ end
+
+ context 'when the params are correct' do
+ let(:dictionary_dir) { Rails.root.join('spec/fixtures') }
+ let(:path_file) { Rails.root.join(dictionary_dir, 'achievements.yml') }
+
+ it 'fetches the table dictionary' do
+ allow(Gitlab::Database::GitlabSchema).to receive(:dictionary_paths).and_return([dictionary_dir])
+
+ expect(Gitlab::PathTraversal).to receive(:check_allowed_absolute_path_and_path_traversal!).twice.with(
+ path_file.to_s, [dictionary_dir.to_s]).and_call_original
+
+ show_table_dictionary
+
+ aggregate_failures "testing response" do
+ expect(json_response['table_name']).to eq('achievements')
+ expect(json_response['feature_categories']).to eq(['feature_category_example'])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/integrations_spec.rb b/spec/requests/api/integrations_spec.rb
index 8334d6b6832..6fd2aafd546 100644
--- a/spec/requests/api/integrations_spec.rb
+++ b/spec/requests/api/integrations_spec.rb
@@ -68,7 +68,6 @@ RSpec.describe API::Integrations, feature_category: :integrations do
let(:missing_attributes) do
{
datadog: %i[archive_trace_events],
- discord: %i[branches_to_be_notified notify_only_broken_pipelines],
hangouts_chat: %i[notify_only_broken_pipelines],
jira: %i[issues_enabled project_key jira_issue_regex jira_issue_prefix vulnerabilities_enabled vulnerabilities_issuetype],
mattermost: %i[deployment_channel labels_to_be_notified],
diff --git a/spec/scripts/api/create_merge_request_note_spec.rb b/spec/scripts/api/create_merge_request_note_spec.rb
new file mode 100644
index 00000000000..74cc68146c5
--- /dev/null
+++ b/spec/scripts/api/create_merge_request_note_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require_relative '../../../scripts/api/create_merge_request_note'
+
+RSpec.describe CreateMergeRequestNote, feature_category: :tooling do
+ describe '#execute' do
+ let(:project_id) { 12345 }
+ let(:iid) { 1 }
+ let(:content) { 'test123' }
+
+ let(:options) do
+ {
+ api_token: 'token',
+ endpoint: 'https://example.gitlab.com',
+ project: project_id,
+ merge_request: Struct.new(:iid).new(iid)
+ }
+ end
+
+ subject { described_class.new(options) }
+
+ it 'requests create_merge_request_comment from the gitlab client' do
+ client = double('Gitlab::Client') # rubocop:disable RSpec/VerifiedDoubles
+
+ expect(Gitlab).to receive(:client)
+ .with(endpoint: options[:endpoint], private_token: options[:api_token])
+ .and_return(client)
+
+ expect(client).to receive(:create_merge_request_comment).with(
+ project_id, iid, content
+ ).and_return(true)
+
+ subject.execute(content)
+ end
+ end
+end
diff --git a/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb b/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb
new file mode 100644
index 00000000000..aee16334003
--- /dev/null
+++ b/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb
@@ -0,0 +1,279 @@
+# frozen_string_literal: true
+
+# rubocop:disable RSpec/VerifiedDoubles
+
+require 'fast_spec_helper'
+require_relative '../../scripts/generate-message-to-run-e2e-pipeline'
+require_relative '../support/helpers/stub_env'
+
+RSpec.describe GenerateMessageToRunE2ePipeline, feature_category: :tooling do
+ include StubENV
+
+ let(:options) do
+ {
+ project: '13083',
+ pipeline_id: '13083',
+ api_token: 'asdf1234',
+ endpoint: 'https://gitlab.com/api/v4'
+ }
+ end
+
+ let(:client) { double('Gitlab::Client') }
+
+ let(:note_content) do
+ <<~MARKDOWN
+ <!-- Run e2e warning begin -->
+ Some note
+ <!-- Run e2e warning end -->
+ MARKDOWN
+ end
+
+ before do
+ allow(Gitlab).to receive(:client)
+ .with(endpoint: options[:endpoint], private_token: options[:api_token])
+ .and_return(client)
+ end
+
+ subject { described_class.new(options) }
+
+ describe '#execute' do
+ let(:commit_merge_request) do
+ Struct.new(:author, :iid).new(
+ Struct.new(:id, :username).new(
+ '2',
+ 'test_user'
+ ),
+ '123'
+ )
+ end
+
+ let(:merge_request) { instance_double(CommitMergeRequests, execute: [commit_merge_request]) }
+ let(:merge_request_note_client) { instance_double(CreateMergeRequestNote, execute: true) }
+
+ before do
+ stub_env(
+ 'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA' => 'bfcd2b9b5cad0b889494ce830697392c8ca11257'
+ )
+
+ allow(CommitMergeRequests).to receive(:new)
+ .with(options.merge(sha: ENV['CI_MERGE_REQUEST_SOURCE_BRANCH_SHA']))
+ .and_return(merge_request)
+ end
+
+ context 'when there are qa_test_folders' do
+ before do
+ allow(subject).to receive(:qa_tests_folders?).and_return(true)
+ end
+
+ context 'when there is no existing note' do
+ before do
+ allow(subject).to receive(:existing_note).and_return(nil)
+ allow(subject).to receive(:content).and_return(note_content)
+
+ allow(client).to receive(:create_merge_request_comment)
+ .with(options[:project], '123', note_content)
+ end
+
+ it 'adds a new note' do
+ expect(CreateMergeRequestNote).to receive(:new)
+ .with(options.merge(merge_request: commit_merge_request))
+ .and_return(merge_request_note_client)
+
+ expect(merge_request_note_client).to receive(:execute).with(note_content)
+
+ subject.execute
+ end
+ end
+
+ context 'when there is existing note' do
+ before do
+ allow(subject).to receive(:existing_note).and_return(true)
+ end
+
+ it 'does not add a new note' do
+ expect(CreateMergeRequestNote).not_to receive(:new)
+
+ subject.execute
+ end
+ end
+ end
+
+ context 'when there are no qa_test_folders' do
+ before do
+ allow(subject).to receive(:qa_tests_folders?).and_return(false)
+ end
+
+ it 'does not add a new note' do
+ expect(CreateMergeRequestNote).not_to receive(:new)
+
+ subject.execute
+ end
+ end
+ end
+
+ describe '#qa_tests_folders?' do
+ before do
+ allow(File).to receive(:exist?).with(any_args).and_return(true)
+ allow(File).to receive(:open).with(any_args).and_return(file_contents)
+ end
+
+ context 'when QA_TESTS is empty' do
+ let(:file_contents) do
+ %w[
+ QA_SUITES='QA::Scenario::Test::Instance::All'
+ QA_TESTS=''
+ QA_FEATURE_FLAGS=''
+ ]
+ end
+
+ it 'returns false' do
+ expect(subject.send(:qa_tests_folders?)).to be_falsy
+ end
+ end
+
+ context 'when QA_TESTS has a spec file' do
+ let(:file_contents) do
+ %w[
+ QA_SUITES='QA::Scenario::Test::Instance::All'
+ QA_TESTS='qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb'
+ QA_FEATURE_FLAGS=''
+ ]
+ end
+
+ it 'returns false' do
+ expect(subject.send(:qa_tests_folders?)).to be_falsy
+ end
+ end
+
+ context 'when QA_TESTS has folders' do
+ let(:file_contents) do
+ [
+ "QA_SUITES='QA::Scenario::Test::Instance::All'",
+ "QA_TESTS='qa/specs/features/browser_ui/1_manage/ qa/specs/features/browser_ui/2_plan'",
+ "QA_FEATURE_FLAGS=''"
+ ]
+ end
+
+ it 'returns true' do
+ expect(subject.send(:qa_tests_folders?)).to be_truthy
+ end
+ end
+ end
+
+ describe '#match?' do
+ it 'returns true for a note that matches NOTE_PATTERN' do
+ expect(subject.send(:match?, note_content)).to be_truthy
+ end
+
+ it 'returns false for a note that does not match NOTE_PATTERN' do
+ expect(subject.send(:match?, 'Some random text')).to be_falsy
+ end
+ end
+
+ describe '#existing_note' do
+ let(:mr_comments_response) do
+ [
+ double(:mr_comment, id: 1, body: 'foo'),
+ double(:mr_comment, id: 2, body: 'bar'),
+ existing_note
+ ]
+ end
+
+ before do
+ allow(client)
+ .to receive(:merge_request_comments)
+ .with(any_args)
+ .and_return(double(auto_paginate: mr_comments_response))
+ allow(subject).to receive(:merge_request).and_return(double(:merge_request, id: 2, iid: 123))
+ end
+
+ context 'when note exists' do
+ let(:existing_note) do
+ double(
+ :mr_comment,
+ id: 3,
+ body: note_content
+ )
+ end
+
+ it 'returns the existing note' do
+ expect(subject.send(:existing_note)).to eq existing_note
+ end
+ end
+
+ context 'when note doesnt exists' do
+ let(:existing_note) do
+ double(
+ :mr_comment,
+ id: 3,
+ body: 'random content'
+ )
+ end
+
+ it 'returns nil' do
+ expect(subject.send(:existing_note)).to eq nil
+ end
+ end
+ end
+
+ describe '#content' do
+ let(:author_username) { 'sam_smith' }
+
+ let(:expected_content) do
+ <<~MARKDOWN
+ <!-- Run e2e warning begin -->
+ :warning: @#{author_username} Some end-to-end (E2E) tests have been selected based on the stage label on this MR.
+ If not run already, please run the `e2e:package-and-test-ee` job in the `qa` stage
+ and review the results **before merging this MR**. (E2E tests are not run automatically on some MRs due to [runner resource constraints](https://gitlab.com/gitlab-org/gitlab-qa/-/issues/261).)
+
+ If you would like to run all e2e tests, please apply the ~"pipeline:run-all-e2e" label and restart the pipeline.
+
+ Once done, please apply the ✅ emoji on this comment.
+
+ For any questions or help in reviewing the E2E test results, please reach out on the internal #quality Slack channel.
+ <!-- Run e2e warning end -->
+ MARKDOWN
+ end
+
+ before do
+ allow(subject).to receive(:merge_request).and_return(double(:merge_request,
+ author: double(username: author_username)))
+ end
+
+ it 'returns content text with author username' do
+ expect(subject.send(:content)).to eq expected_content
+ end
+ end
+
+ describe '#author_username' do
+ let(:author_username) { 'sam_smith' }
+
+ before do
+ allow(subject).to receive(:merge_request).and_return(double(:merge_request,
+ author: double(username: author_username)))
+ end
+
+ it 'returns nil' do
+ expect(subject.send(:author_username)).to eq author_username
+ end
+ end
+
+ describe '#env' do
+ before do
+ stub_env(
+ 'VAR_WITH_VALUE' => 'bfcd2b9b5cad0b889494ce830697392c8ca11257',
+ 'EMPTY_VAR' => ' '
+ )
+ end
+
+ it 'returns env var when not empty' do
+ expect(subject.send(:env, 'VAR_WITH_VALUE')).to eq 'bfcd2b9b5cad0b889494ce830697392c8ca11257'
+ end
+
+ it 'returns nil when env var is empty' do
+ expect(subject.send(:env, 'EMPTY_VAR')).to be_nil
+ end
+ end
+end
+
+# rubocop:enable RSpec/VerifiedDoubles