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-04-07 21:09:45 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-07 21:09:45 +0300
commit413119517cca6a47f52d77b49ae3cab4cdaf9884 (patch)
tree046eb80cb92bb948cd49a99b7c34bf8dc6884c4f /spec
parent40b78ea2b6f5f0ef730c2cd811911be3449562e6 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/benchmarks/banzai_benchmark.rb7
-rw-r--r--spec/controllers/registrations/welcome_controller_spec.rb22
-rw-r--r--spec/features/markdown/markdown_spec.rb11
-rw-r--r--spec/features/registrations/welcome_spec.rb21
-rw-r--r--spec/finders/repositories/branch_names_finder_spec.rb25
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/user/public.json3
-rw-r--r--spec/frontend/pipelines/pipeline_graph/mock_data.js36
-rw-r--r--spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js28
-rw-r--r--spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap6
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js19
-rw-r--r--spec/frontend/vue_shared/components/runner_instructions/mock_data.js16
-rw-r--r--spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js184
-rw-r--r--spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js138
-rw-r--r--spec/graphql/resolvers/merge_requests_resolver_spec.rb19
-rw-r--r--spec/graphql/types/project_type_spec.rb1
-rw-r--r--spec/helpers/avatars_helper_spec.rb24
-rw-r--r--spec/helpers/markup_helper_spec.rb2
-rw-r--r--spec/initializers/active_record_locking_spec.rb4
-rw-r--r--spec/initializers/fog_google_https_private_urls_spec.rb2
-rw-r--r--spec/lib/banzai/filter/gollum_tags_filter_spec.rb8
-rw-r--r--spec/lib/banzai/filter/math_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/suggestion_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/syntax_highlight_filter_spec.rb12
-rw-r--r--spec/lib/banzai/pipeline/wiki_pipeline_spec.rb2
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb6
-rw-r--r--spec/lib/gitlab/graphql/negatable_arguments_spec.rb45
-rw-r--r--spec/lib/gitlab/profiler_spec.rb9
-rw-r--r--spec/lib/gitlab/repository_set_cache_spec.rb12
-rw-r--r--spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb1
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb2
-rw-r--r--spec/mailers/emails/in_product_marketing_spec.rb34
-rw-r--r--spec/models/concerns/cascading_namespace_setting_attribute_spec.rb320
-rw-r--r--spec/models/concerns/ci/has_status_spec.rb6
-rw-r--r--spec/models/project_services/chat_message/merge_message_spec.rb26
-rw-r--r--spec/models/repository_spec.rb16
-rw-r--r--spec/models/user_spec.rb28
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb2
-rw-r--r--spec/spec_helper.rb18
-rw-r--r--spec/support/shared_examples/lib/api/ci/runner_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/wiki_shared_examples.rb42
-rw-r--r--spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb2
-rw-r--r--spec/views/registrations/welcome/show.html.haml_spec.rb24
-rw-r--r--spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb56
43 files changed, 928 insertions, 327 deletions
diff --git a/spec/benchmarks/banzai_benchmark.rb b/spec/benchmarks/banzai_benchmark.rb
index 4cf079b2130..05c41eed889 100644
--- a/spec/benchmarks/banzai_benchmark.rb
+++ b/spec/benchmarks/banzai_benchmark.rb
@@ -54,9 +54,10 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures do
context 'pipelines' do
it 'benchmarks several pipelines' do
- path = 'images/example.jpg'
- gitaly_wiki_file = Gitlab::GitalyClient::WikiFile.new(path: path)
- allow(wiki).to receive(:find_file).with(path, load_content: false).and_return(Gitlab::Git::WikiFile.new(gitaly_wiki_file))
+ name = 'example.jpg'
+ path = "images/#{name}"
+ blob = double(name: name, path: path, mime_type: 'image/jpeg', data: nil)
+ allow(wiki).to receive(:find_file).with(path, load_content: false).and_return(Gitlab::Git::WikiFile.new(blob))
allow(wiki).to receive(:wiki_base_path) { '/namespace1/gitlabhq/wikis' }
puts "\n--> Benchmarking Full, Wiki, and Plain pipelines\n"
diff --git a/spec/controllers/registrations/welcome_controller_spec.rb b/spec/controllers/registrations/welcome_controller_spec.rb
index d32c936b8c9..008259a8bfa 100644
--- a/spec/controllers/registrations/welcome_controller_spec.rb
+++ b/spec/controllers/registrations/welcome_controller_spec.rb
@@ -60,8 +60,10 @@ RSpec.describe Registrations::WelcomeController do
end
describe '#update' do
+ let(:email_opted_in) { '0' }
+
subject(:update) do
- patch :update, params: { user: { role: 'software_developer', setup_for_company: 'false' } }
+ patch :update, params: { user: { role: 'software_developer', setup_for_company: 'false', email_opted_in: email_opted_in } }
end
context 'without a signed in user' do
@@ -74,6 +76,24 @@ RSpec.describe Registrations::WelcomeController do
end
it { is_expected.to redirect_to(dashboard_projects_path)}
+
+ context 'when the user opted in' do
+ let(:email_opted_in) { '1' }
+
+ it 'sets the email_opted_in field' do
+ subject
+
+ expect(controller.current_user.email_opted_in).to eq(true)
+ end
+ end
+
+ context 'when the user opted out' do
+ it 'sets the email_opted_in field' do
+ subject
+
+ expect(controller.current_user.email_opted_in).to eq(false)
+ end
+ end
end
end
end
diff --git a/spec/features/markdown/markdown_spec.rb b/spec/features/markdown/markdown_spec.rb
index e84b300a748..3208ad82c03 100644
--- a/spec/features/markdown/markdown_spec.rb
+++ b/spec/features/markdown/markdown_spec.rb
@@ -63,8 +63,8 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures do
end
aggregate_failures 'parses fenced code blocks' do
- expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.c')
- expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.python')
+ expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.language-c')
+ expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.language-python')
end
aggregate_failures 'parses mermaid code block' do
@@ -288,9 +288,10 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures do
@wiki = @feat.wiki
@wiki_page = @feat.wiki_page
- path = 'images/example.jpg'
- gitaly_wiki_file = Gitlab::GitalyClient::WikiFile.new(path: path)
- expect(@wiki).to receive(:find_file).with(path, load_content: false).and_return(Gitlab::Git::WikiFile.new(gitaly_wiki_file))
+ name = 'example.jpg'
+ path = "images/#{name}"
+ blob = double(name: name, path: path, mime_type: 'image/jpeg', data: nil)
+ expect(@wiki).to receive(:find_file).with(path, load_content: false).and_return(Gitlab::Git::WikiFile.new(blob))
allow(@wiki).to receive(:wiki_base_path) { '/namespace1/gitlabhq/wikis' }
@html = markdown(@feat.raw_markdown, { pipeline: :wiki, wiki: @wiki, page_slug: @wiki_page.slug })
diff --git a/spec/features/registrations/welcome_spec.rb b/spec/features/registrations/welcome_spec.rb
new file mode 100644
index 00000000000..74320b69f19
--- /dev/null
+++ b/spec/features/registrations/welcome_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Welcome screen' do
+ let(:user) { create(:user) }
+
+ before do
+ gitlab_sign_in(user)
+
+ visit users_sign_up_welcome_path
+ end
+
+ it 'shows the email opt in' do
+ select 'Software Developer', from: 'user_role'
+ check 'user_email_opted_in'
+ click_button 'Get started!'
+
+ expect(user.reload.email_opted_in).to eq(true)
+ end
+end
diff --git a/spec/finders/repositories/branch_names_finder_spec.rb b/spec/finders/repositories/branch_names_finder_spec.rb
new file mode 100644
index 00000000000..4d8bfcc0f20
--- /dev/null
+++ b/spec/finders/repositories/branch_names_finder_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Repositories::BranchNamesFinder do
+ let(:project) { create(:project, :repository) }
+
+ let(:branch_names_finder) { described_class.new(project.repository, search: 'conflict-*') }
+
+ describe '#execute' do
+ subject(:execute) { branch_names_finder.execute }
+
+ it 'filters branch names' do
+ expect(execute).to contain_exactly(
+ 'conflict-binary-file',
+ 'conflict-resolvable',
+ 'conflict-contains-conflict-markers',
+ 'conflict-missing-side',
+ 'conflict-start',
+ 'conflict-non-utf8',
+ 'conflict-too-large'
+ )
+ end
+ end
+end
diff --git a/spec/fixtures/api/schemas/public_api/v4/user/public.json b/spec/fixtures/api/schemas/public_api/v4/user/public.json
index faa126b65f2..ee848eda9ed 100644
--- a/spec/fixtures/api/schemas/public_api/v4/user/public.json
+++ b/spec/fixtures/api/schemas/public_api/v4/user/public.json
@@ -70,6 +70,7 @@
"can_create_group": { "type": "boolean" },
"can_create_project": { "type": "boolean" },
"two_factor_enabled": { "type": "boolean" },
- "external": { "type": "boolean" }
+ "external": { "type": "boolean" },
+ "commit_email": { "type": "string" }
}
}
diff --git a/spec/frontend/pipelines/pipeline_graph/mock_data.js b/spec/frontend/pipelines/pipeline_graph/mock_data.js
index 339aac9f349..a79917bfd48 100644
--- a/spec/frontend/pipelines/pipeline_graph/mock_data.js
+++ b/spec/frontend/pipelines/pipeline_graph/mock_data.js
@@ -98,6 +98,42 @@ export const pipelineData = {
],
};
+export const invalidNeedsData = {
+ stages: [
+ {
+ name: 'build',
+ groups: [
+ {
+ name: 'build_1',
+ jobs: [{ script: 'echo hello', stage: 'build' }],
+ },
+ ],
+ },
+ {
+ name: 'test',
+ groups: [
+ {
+ name: 'test_1',
+ jobs: [{ script: 'yarn test', stage: 'test' }],
+ },
+ {
+ name: 'test_2',
+ jobs: [{ script: 'yarn karma', stage: 'test' }],
+ },
+ ],
+ },
+ {
+ name: 'deploy',
+ groups: [
+ {
+ name: 'deploy_1',
+ jobs: [{ script: 'yarn magick', stage: 'deploy', needs: ['invalid_job'] }],
+ },
+ ],
+ },
+ ],
+};
+
export const parallelNeedData = {
stages: [
{
diff --git a/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js b/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
index aeb567a8869..6deec06e344 100644
--- a/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
+++ b/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
@@ -1,11 +1,13 @@
import { GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { CI_CONFIG_STATUS_INVALID, CI_CONFIG_STATUS_VALID } from '~/pipeline_editor/constants';
+import LinksInner from '~/pipelines/components/graph_shared/links_inner.vue';
+import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue';
import JobPill from '~/pipelines/components/pipeline_graph/job_pill.vue';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
import StagePill from '~/pipelines/components/pipeline_graph/stage_pill.vue';
import { DRAW_FAILURE, EMPTY_PIPELINE_DATA, INVALID_CI_CONFIG } from '~/pipelines/constants';
-import { pipelineData, singleStageData } from './mock_data';
+import { invalidNeedsData, pipelineData, singleStageData } from './mock_data';
describe('pipeline graph component', () => {
const defaultProps = { pipelineData };
@@ -16,19 +18,28 @@ describe('pipeline graph component', () => {
propsData: {
...props,
},
+ stubs: { LinksLayer, LinksInner },
+ data() {
+ return {
+ measurements: {
+ width: 1000,
+ height: 1000,
+ },
+ };
+ },
});
};
- const findPipelineGraph = () => wrapper.find('[data-testid="graph-container"]');
- const findAlert = () => wrapper.find(GlAlert);
- const findAllStagePills = () => wrapper.findAll(StagePill);
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findAllJobPills = () => wrapper.findAll(JobPill);
const findAllStageBackgroundElements = () => wrapper.findAll('[data-testid="stage-background"]');
+ const findAllStagePills = () => wrapper.findAllComponents(StagePill);
+ const findLinksLayer = () => wrapper.findComponent(LinksLayer);
+ const findPipelineGraph = () => wrapper.find('[data-testid="graph-container"]');
const findStageBackgroundElementAt = (index) => findAllStageBackgroundElements().at(index);
- const findAllJobPills = () => wrapper.findAll(JobPill);
afterEach(() => {
wrapper.destroy();
- wrapper = null;
});
describe('with no data', () => {
@@ -36,7 +47,7 @@ describe('pipeline graph component', () => {
wrapper = createComponent({ pipelineData: {} });
});
- it('renders an empty section', () => {
+ it('does not render the graph', () => {
expect(wrapper.text()).toBe(wrapper.vm.$options.errorTexts[EMPTY_PIPELINE_DATA]);
expect(findPipelineGraph().exists()).toBe(false);
expect(findAllStagePills()).toHaveLength(0);
@@ -74,10 +85,11 @@ describe('pipeline graph component', () => {
describe('with error while rendering the links with needs', () => {
beforeEach(() => {
- wrapper = createComponent();
+ wrapper = createComponent({ pipelineData: invalidNeedsData });
});
it('renders the error that link could not be drawn', () => {
+ expect(findLinksLayer().exists()).toBe(true);
expect(findAlert().exists()).toBe(true);
expect(findAlert().text()).toBe(wrapper.vm.$options.errorTexts[DRAW_FAILURE]);
});
diff --git a/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap b/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap
index fc51825f15b..c37f6415898 100644
--- a/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap
+++ b/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap
@@ -21,7 +21,11 @@ exports[`CiCdAnalyticsAreaChart matches the snapshot 1`] = `
option="[object Object]"
thresholds=""
width="0"
- />
+ >
+ <template />
+
+ <template />
+ </glareachart-stub>
</div>
</div>
`;
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
index dc2f227b29c..fee78d3af94 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
@@ -1,4 +1,3 @@
-import { GlPopover } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants';
import { removeBreakLine } from 'helpers/text_helper';
@@ -10,7 +9,6 @@ describe('MRWidgetConflicts', () => {
let mergeRequestWidgetGraphql = null;
const path = '/conflicts';
- const findPopover = () => wrapper.find(GlPopover);
const findResolveButton = () => wrapper.findByTestId('resolve-conflicts-button');
const findMergeLocalButton = () => wrapper.findByTestId('merge-locally-button');
@@ -219,12 +217,8 @@ describe('MRWidgetConflicts', () => {
});
});
- it('sets resolve button as disabled', () => {
- expect(findResolveButton().attributes('disabled')).toBe('true');
- });
-
- it('shows the popover', () => {
- expect(findPopover().exists()).toBe(true);
+ it('should not allow you to resolve the conflicts', () => {
+ expect(findResolveButton().exists()).toBe(false);
});
});
@@ -241,12 +235,9 @@ describe('MRWidgetConflicts', () => {
});
});
- it('sets resolve button as disabled', () => {
- expect(findResolveButton().attributes('disabled')).toBe(undefined);
- });
-
- it('does not show the popover', () => {
- expect(findPopover().exists()).toBe(false);
+ it('should allow you to resolve the conflicts', () => {
+ expect(findResolveButton().text()).toContain('Resolve conflicts');
+ expect(findResolveButton().attributes('href')).toEqual(TEST_HOST);
});
});
});
diff --git a/spec/frontend/vue_shared/components/runner_instructions/mock_data.js b/spec/frontend/vue_shared/components/runner_instructions/mock_data.js
index 01f7f3d49c7..bc1545014d7 100644
--- a/spec/frontend/vue_shared/components/runner_instructions/mock_data.js
+++ b/spec/frontend/vue_shared/components/runner_instructions/mock_data.js
@@ -98,9 +98,21 @@ export const mockGraphqlInstructions = {
data: {
runnerSetup: {
installInstructions:
- "# Download the binary for your system\nsudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64\n\n# Give it permissions to execute\nsudo chmod +x /usr/local/bin/gitlab-runner\n\n# Create a GitLab CI user\nsudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash\n\n# Install and run as service\nsudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner\nsudo gitlab-runner start\n",
+ '# Install and run as service\nsudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner\nsudo gitlab-runner start',
registerInstructions:
- 'sudo gitlab-runner register --url http://192.168.1.81:3000/ --registration-token GE5gsjeep_HAtBf9s3Yz',
+ 'sudo gitlab-runner register --url http://gdk.test:3000/ --registration-token $REGISTRATION_TOKEN',
+ __typename: 'RunnerSetup',
+ },
+ },
+};
+
+export const mockGraphqlInstructionsWindows = {
+ data: {
+ runnerSetup: {
+ installInstructions:
+ '# Windows runner, then run\n.gitlab-runner.exe install\n.gitlab-runner.exe start',
+ registerInstructions:
+ './gitlab-runner.exe register --url http://gdk.test:3000/ --registration-token $REGISTRATION_TOKEN',
__typename: 'RunnerSetup',
},
},
diff --git a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js
new file mode 100644
index 00000000000..4033c943b82
--- /dev/null
+++ b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js
@@ -0,0 +1,184 @@
+import { GlAlert, GlLoadingIcon, GlSkeletonLoader } from '@gitlab/ui';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import getRunnerPlatformsQuery from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_platforms.query.graphql';
+import getRunnerSetupInstructionsQuery from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_setup.query.graphql';
+import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
+
+import {
+ mockGraphqlRunnerPlatforms,
+ mockGraphqlInstructions,
+ mockGraphqlInstructionsWindows,
+} from './mock_data';
+
+const localVue = createLocalVue();
+localVue.use(VueApollo);
+
+describe('RunnerInstructionsModal component', () => {
+ let wrapper;
+ let fakeApollo;
+ let runnerPlatformsHandler;
+ let runnerSetupInstructionsHandler;
+
+ const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
+ const findGlLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findPlatformButtons = () => wrapper.findAllByTestId('platform-button');
+ const findArchitectureDropdownItems = () => wrapper.findAllByTestId('architecture-dropdown-item');
+ const findBinaryInstructions = () => wrapper.findByTestId('binary-instructions');
+ const findRegisterCommand = () => wrapper.findByTestId('register-command');
+
+ const createComponent = () => {
+ const requestHandlers = [
+ [getRunnerPlatformsQuery, runnerPlatformsHandler],
+ [getRunnerSetupInstructionsQuery, runnerSetupInstructionsHandler],
+ ];
+
+ fakeApollo = createMockApollo(requestHandlers);
+
+ wrapper = extendedWrapper(
+ shallowMount(RunnerInstructionsModal, {
+ propsData: {
+ modalId: 'runner-instructions-modal',
+ },
+ localVue,
+ apolloProvider: fakeApollo,
+ }),
+ );
+ };
+
+ beforeEach(async () => {
+ runnerPlatformsHandler = jest.fn().mockResolvedValue(mockGraphqlRunnerPlatforms);
+ runnerSetupInstructionsHandler = jest.fn().mockResolvedValue(mockGraphqlInstructions);
+
+ createComponent();
+
+ await nextTick();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should not show alert', () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+
+ it('should contain a number of platforms buttons', () => {
+ expect(runnerPlatformsHandler).toHaveBeenCalledWith({});
+
+ const buttons = findPlatformButtons();
+
+ expect(buttons).toHaveLength(mockGraphqlRunnerPlatforms.data.runnerPlatforms.nodes.length);
+ });
+
+ it('should contain a number of dropdown items for the architecture options', () => {
+ expect(findArchitectureDropdownItems()).toHaveLength(
+ mockGraphqlRunnerPlatforms.data.runnerPlatforms.nodes[0].architectures.nodes.length,
+ );
+ });
+
+ describe('should display default instructions', () => {
+ const { installInstructions, registerInstructions } = mockGraphqlInstructions.data.runnerSetup;
+
+ it('runner instructions are requested', () => {
+ expect(runnerSetupInstructionsHandler).toHaveBeenCalledWith({
+ platform: 'linux',
+ architecture: 'amd64',
+ });
+ });
+
+ it('binary instructions are shown', () => {
+ const instructions = findBinaryInstructions().text();
+
+ expect(instructions).toBe(installInstructions);
+ });
+
+ it('register command is shown', () => {
+ const instructions = findRegisterCommand().text();
+
+ expect(instructions).toBe(registerInstructions);
+ });
+ });
+
+ describe('after a platform and architecture are selected', () => {
+ const {
+ installInstructions,
+ registerInstructions,
+ } = mockGraphqlInstructionsWindows.data.runnerSetup;
+
+ beforeEach(async () => {
+ runnerSetupInstructionsHandler.mockResolvedValue(mockGraphqlInstructionsWindows);
+
+ findPlatformButtons().at(2).vm.$emit('click'); // another option, happens to be windows
+ await nextTick();
+
+ findArchitectureDropdownItems().at(1).vm.$emit('click'); // another option
+ await nextTick();
+ });
+
+ it('runner instructions are requested', () => {
+ expect(runnerSetupInstructionsHandler).toHaveBeenCalledWith({
+ platform: 'windows',
+ architecture: '386',
+ });
+ });
+
+ it('other binary instructions are shown', () => {
+ const instructions = findBinaryInstructions().text();
+
+ expect(instructions).toBe(installInstructions);
+ });
+
+ it('register command is shown', () => {
+ const command = findRegisterCommand().text();
+
+ expect(command).toBe(registerInstructions);
+ });
+ });
+
+ describe('when apollo is loading', () => {
+ it('should show a skeleton loader', async () => {
+ createComponent();
+ expect(findSkeletonLoader().exists()).toBe(true);
+ expect(findGlLoadingIcon().exists()).toBe(false);
+
+ await nextTick(); // wait for platforms
+
+ expect(findGlLoadingIcon().exists()).toBe(true);
+ });
+
+ it('once loaded, should not show a loading state', async () => {
+ createComponent();
+
+ await nextTick(); // wait for platforms
+ await nextTick(); // wait for architectures
+
+ expect(findSkeletonLoader().exists()).toBe(false);
+ expect(findGlLoadingIcon().exists()).toBe(false);
+ });
+ });
+
+ describe('when instructions cannot be loaded', () => {
+ beforeEach(async () => {
+ runnerSetupInstructionsHandler.mockRejectedValue();
+
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('should show alert', () => {
+ expect(findAlert().exists()).toBe(true);
+ });
+
+ it('should not show instructions', () => {
+ expect(findBinaryInstructions().exists()).toBe(false);
+ expect(findRegisterCommand().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js
index 4446c3cd88f..23f8d6afcb5 100644
--- a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js
+++ b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js
@@ -1,147 +1,41 @@
-import { GlAlert } from '@gitlab/ui';
-import { shallowMount, createLocalVue } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import getRunnerPlatforms from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_platforms.query.graphql';
-import getRunnerSetupInstructions from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_setup.query.graphql';
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import RunnerInstructions from '~/vue_shared/components/runner_instructions/runner_instructions.vue';
-
-import { mockGraphqlRunnerPlatforms, mockGraphqlInstructions } from './mock_data';
-
-const projectPath = 'gitlab-org/gitlab';
-const localVue = createLocalVue();
-localVue.use(VueApollo);
+import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
describe('RunnerInstructions component', () => {
let wrapper;
- let fakeApollo;
- let runnerPlatformsHandler;
- let runnerSetupInstructionsHandler;
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findModalButton = () => wrapper.find('[data-testid="show-modal-button"]');
- const findPlatformButtons = () => wrapper.findAll('[data-testid="platform-button"]');
- const findArchitectureDropdownItems = () =>
- wrapper.findAll('[data-testid="architecture-dropdown-item"]');
- const findBinaryInstructionsSection = () => wrapper.find('[data-testid="binary-instructions"]');
- const findRunnerInstructionsSection = () => wrapper.find('[data-testid="runner-instructions"]');
+ const findModalButton = () => wrapper.findByTestId('show-modal-button');
+ const findModal = () => wrapper.findComponent(RunnerInstructionsModal);
const createComponent = () => {
- const requestHandlers = [
- [getRunnerPlatforms, runnerPlatformsHandler],
- [getRunnerSetupInstructions, runnerSetupInstructionsHandler],
- ];
-
- fakeApollo = createMockApollo(requestHandlers);
-
- wrapper = shallowMount(RunnerInstructions, {
- provide: {
- projectPath,
- },
- localVue,
- apolloProvider: fakeApollo,
- });
+ wrapper = extendedWrapper(shallowMount(RunnerInstructions));
};
- beforeEach(async () => {
- runnerPlatformsHandler = jest.fn().mockResolvedValue(mockGraphqlRunnerPlatforms);
- runnerSetupInstructionsHandler = jest.fn().mockResolvedValue(mockGraphqlInstructions);
-
+ beforeEach(() => {
createComponent();
-
- await wrapper.vm.$nextTick();
});
afterEach(() => {
wrapper.destroy();
- wrapper = null;
- });
-
- it('should not show alert', () => {
- expect(findAlert().exists()).toBe(false);
});
it('should show the "Show Runner installation instructions" button', () => {
- const button = findModalButton();
-
- expect(button.exists()).toBe(true);
- expect(button.text()).toBe('Show Runner installation instructions');
- });
-
- it('should contain a number of platforms buttons', () => {
- const buttons = findPlatformButtons();
-
- expect(buttons).toHaveLength(mockGraphqlRunnerPlatforms.data.runnerPlatforms.nodes.length);
- });
-
- it('should contain a number of dropdown items for the architecture options', () => {
- const platformButton = findPlatformButtons().at(0);
- platformButton.vm.$emit('click');
-
- return wrapper.vm.$nextTick(() => {
- const dropdownItems = findArchitectureDropdownItems();
-
- expect(dropdownItems).toHaveLength(
- mockGraphqlRunnerPlatforms.data.runnerPlatforms.nodes[0].architectures.nodes.length,
- );
- });
+ expect(findModalButton().exists()).toBe(true);
+ expect(findModalButton().text()).toBe('Show Runner installation instructions');
});
- it('should display the binary installation instructions for a selected architecture', async () => {
- const platformButton = findPlatformButtons().at(0);
- platformButton.vm.$emit('click');
-
- await wrapper.vm.$nextTick();
-
- const dropdownItem = findArchitectureDropdownItems().at(0);
- dropdownItem.vm.$emit('click');
-
- await wrapper.vm.$nextTick();
-
- const runner = findBinaryInstructionsSection();
-
- expect(runner.text()).toMatch('sudo chmod +x /usr/local/bin/gitlab-runner');
- expect(runner.text()).toMatch(
- `sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash`,
- );
- expect(runner.text()).toMatch(
- 'sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner',
- );
- expect(runner.text()).toMatch('sudo gitlab-runner start');
+ it('should not render the modal once mounted', () => {
+ expect(findModal().exists()).toBe(false);
});
- it('should display the runner register instructions for a selected architecture', async () => {
- const platformButton = findPlatformButtons().at(0);
- platformButton.vm.$emit('click');
-
- await wrapper.vm.$nextTick();
-
- const dropdownItem = findArchitectureDropdownItems().at(0);
- dropdownItem.vm.$emit('click');
-
- await wrapper.vm.$nextTick();
-
- const runner = findRunnerInstructionsSection();
-
- expect(runner.text()).toMatch(mockGraphqlInstructions.data.runnerSetup.registerInstructions);
- });
-
- describe('when instructions cannot be loaded', () => {
- beforeEach(async () => {
- runnerSetupInstructionsHandler.mockRejectedValue();
-
- createComponent();
-
- await wrapper.vm.$nextTick();
- });
+ it('should render the modal once clicked', async () => {
+ findModalButton().vm.$emit('click');
- it('should show alert', () => {
- expect(findAlert().exists()).toBe(true);
- });
+ await nextTick();
- it('should not show instructions', () => {
- expect(findBinaryInstructionsSection().exists()).toBe(false);
- expect(findRunnerInstructionsSection().exists()).toBe(false);
- });
+ expect(findModal().exists()).toBe(true);
});
});
diff --git a/spec/graphql/resolvers/merge_requests_resolver_spec.rb b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
index 09f5181107d..aec6c6c6708 100644
--- a/spec/graphql/resolvers/merge_requests_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_requests_resolver_spec.rb
@@ -189,6 +189,17 @@ RSpec.describe Resolvers::MergeRequestsResolver do
end
end
+ context 'with negated label argument' do
+ let_it_be(:label) { merge_request_6.labels.first }
+ let_it_be(:with_label) { create(:labeled_merge_request, :closed, labels: [label], **common_attrs) }
+
+ it 'excludes merge requests with given label from selection' do
+ result = resolve_mr(project, not: { labels: [label.title] })
+
+ expect(result).not_to include(merge_request_6, with_label)
+ end
+ end
+
context 'with merged_after and merged_before arguments' do
before do
merge_request_1.metrics.update!(merged_at: 10.days.ago)
@@ -221,6 +232,14 @@ RSpec.describe Resolvers::MergeRequestsResolver do
end
end
+ context 'with negated milestone argument' do
+ it 'filters out merge requests with given milestone title' do
+ result = resolve_mr(project, not: { milestone_title: milestone.title })
+
+ expect(result).not_to include(merge_request_with_milestone)
+ end
+ end
+
describe 'combinations' do
it 'requires all filters' do
create(:merge_request, :closed, **common_attrs, source_branch: merge_request_4.source_branch)
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 33f4953b07b..7a8c6464acc 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -243,6 +243,7 @@ RSpec.describe GitlabSchema.types['Project'] do
:assignee_username,
:reviewer_username,
:milestone_title,
+ :not,
:sort
)
end
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb
index 7fcd5ae880a..120dbe7cb49 100644
--- a/spec/helpers/avatars_helper_spec.rb
+++ b/spec/helpers/avatars_helper_spec.rb
@@ -121,27 +121,13 @@ RSpec.describe AvatarsHelper do
end
end
- context "when :avatar_cache_for_email flag is enabled" do
- before do
- stub_feature_flags(avatar_cache_for_email: true)
- end
-
- it_behaves_like "returns avatar for email"
+ it_behaves_like "returns avatar for email"
- it "caches the request" do
- expect(User).to receive(:find_by_any_email).once.and_call_original
-
- expect(helper.avatar_icon_for_email(user.email).to_s).to eq(user.avatar.url)
- expect(helper.avatar_icon_for_email(user.email).to_s).to eq(user.avatar.url)
- end
- end
-
- context "when :avatar_cache_for_email flag is disabled" do
- before do
- stub_feature_flags(avatar_cache_for_email: false)
- end
+ it "caches the request" do
+ expect(User).to receive(:find_by_any_email).once.and_call_original
- it_behaves_like "returns avatar for email"
+ expect(helper.avatar_icon_for_email(user.email).to_s).to eq(user.avatar.url)
+ expect(helper.avatar_icon_for_email(user.email).to_s).to eq(user.avatar.url)
end
end
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 91e9075f575..08a20e87f4b 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -575,7 +575,7 @@ FooBar
it 'preserves code color scheme' do
object = create_object("```ruby\ndef test\n 'hello world'\nend\n```")
- expected = "<pre class=\"code highlight js-syntax-highlight ruby\">" \
+ expected = "<pre class=\"code highlight js-syntax-highlight language-ruby\">" \
"<code><span class=\"line\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>\n" \
"</code></pre>"
diff --git a/spec/initializers/active_record_locking_spec.rb b/spec/initializers/active_record_locking_spec.rb
index e979fa0b793..735ef7b916b 100644
--- a/spec/initializers/active_record_locking_spec.rb
+++ b/spec/initializers/active_record_locking_spec.rb
@@ -11,13 +11,13 @@ RSpec.describe 'ActiveRecord locking' do
end
it 'can be updated' do
- issue.update(title: "New title")
+ issue.update!(title: "New title")
expect(issue.reload.lock_version).to eq(new_lock_version)
end
it 'can be deleted' do
- expect { issue.destroy }.to change { Issue.count }.by(-1)
+ expect { issue.destroy! }.to change { Issue.count }.by(-1)
end
end
diff --git a/spec/initializers/fog_google_https_private_urls_spec.rb b/spec/initializers/fog_google_https_private_urls_spec.rb
index 4825525a3d8..f7b21bf850e 100644
--- a/spec/initializers/fog_google_https_private_urls_spec.rb
+++ b/spec/initializers/fog_google_https_private_urls_spec.rb
@@ -13,11 +13,13 @@ RSpec.describe 'Fog::Storage::GoogleXML::File', :fog_requests do
end
let(:file) do
+ # rubocop:disable Rails/SaveBang
directory = storage.directories.create(key: 'data')
directory.files.create(
body: 'Hello World!',
key: 'hello_world.txt'
)
+ # rubocop:enable Rails/SaveBang
end
it 'delegates to #get_https_url' do
diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
index b0136ce1fef..23626576c0c 100644
--- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
+++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
@@ -16,12 +16,8 @@ RSpec.describe Banzai::Filter::GollumTagsFilter do
context 'linking internal images' do
it 'creates img tag if image exists' do
- gollum_file_double = double('Gollum::File',
- mime_type: 'image/jpeg',
- name: 'images/image.jpg',
- path: 'images/image.jpg',
- raw_data: '')
- wiki_file = Gitlab::Git::WikiFile.new(gollum_file_double)
+ blob = double(mime_type: 'image/jpeg', name: 'images/image.jpg', path: 'images/image.jpg', data: '')
+ wiki_file = Gitlab::Git::WikiFile.new(blob)
expect(wiki).to receive(:find_file).with('images/image.jpg', load_content: false).and_return(wiki_file)
tag = '[[images/image.jpg]]'
diff --git a/spec/lib/banzai/filter/math_filter_spec.rb b/spec/lib/banzai/filter/math_filter_spec.rb
index 9f6688f4f7d..6d22fa3a001 100644
--- a/spec/lib/banzai/filter/math_filter_spec.rb
+++ b/spec/lib/banzai/filter/math_filter_spec.rb
@@ -91,35 +91,35 @@ RSpec.describe Banzai::Filter::MathFilter do
# Display math
it 'adds data-math-style display attribute to display math' do
- doc = filter('<pre class="code highlight js-syntax-highlight math" v-pre="true"><code>2+2</code></pre>')
+ doc = filter('<pre class="code highlight js-syntax-highlight language-math" v-pre="true"><code>2+2</code></pre>')
pre = doc.xpath('descendant-or-self::pre').first
expect(pre['data-math-style']).to eq 'display'
end
it 'adds js-render-math class to display math' do
- doc = filter('<pre class="code highlight js-syntax-highlight math" v-pre="true"><code>2+2</code></pre>')
+ doc = filter('<pre class="code highlight js-syntax-highlight language-math" v-pre="true"><code>2+2</code></pre>')
pre = doc.xpath('descendant-or-self::pre').first
expect(pre[:class]).to include("js-render-math")
end
it 'ignores code blocks that are not math' do
- input = '<pre class="code highlight js-syntax-highlight plaintext" v-pre="true"><code>2+2</code></pre>'
+ input = '<pre class="code highlight js-syntax-highlight language-plaintext" v-pre="true"><code>2+2</code></pre>'
doc = filter(input)
expect(doc.to_s).to eq input
end
it 'requires the pre to contain both code and math' do
- input = '<pre class="highlight js-syntax-highlight plaintext math" v-pre="true"><code>2+2</code></pre>'
+ input = '<pre class="highlight js-syntax-highlight language-plaintext language-math" v-pre="true"><code>2+2</code></pre>'
doc = filter(input)
expect(doc.to_s).to eq input
end
it 'dollar signs around to display math' do
- doc = filter('$<pre class="code highlight js-syntax-highlight math" v-pre="true"><code>2+2</code></pre>$')
+ doc = filter('$<pre class="code highlight js-syntax-highlight language-math" v-pre="true"><code>2+2</code></pre>$')
before = doc.xpath('descendant-or-self::text()[1]').first
after = doc.xpath('descendant-or-self::text()[3]').first
diff --git a/spec/lib/banzai/filter/suggestion_filter_spec.rb b/spec/lib/banzai/filter/suggestion_filter_spec.rb
index 7d6092e21e9..d74bac4898e 100644
--- a/spec/lib/banzai/filter/suggestion_filter_spec.rb
+++ b/spec/lib/banzai/filter/suggestion_filter_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Banzai::Filter::SuggestionFilter do
include FilterSpecHelper
- let(:input) { %(<pre class="code highlight js-syntax-highlight suggestion"><code>foo\n</code></pre>) }
+ let(:input) { %(<pre class="code highlight js-syntax-highlight language-suggestion"><code>foo\n</code></pre>) }
let(:default_context) do
{ suggestions_filter_enabled: true }
end
@@ -26,7 +26,7 @@ RSpec.describe Banzai::Filter::SuggestionFilter do
context 'multi-line suggestions' do
let(:data_attr) { Banzai::Filter::SyntaxHighlightFilter::LANG_PARAMS_ATTR }
- let(:input) { %(<pre class="code highlight js-syntax-highlight suggestion" #{data_attr}="-3+2"><code>foo\n</code></pre>) }
+ let(:input) { %(<pre class="code highlight js-syntax-highlight language-suggestion" #{data_attr}="-3+2"><code>foo\n</code></pre>) }
it 'element has correct data-lang-params' do
doc = filter(input, default_context)
diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
index 78f84ee44f7..16e30604c99 100644
--- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
+++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "highlights as plaintext" do
result = filter('<pre><code>def fun end</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">def fun end</span></code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">def fun end</span></code></pre>')
end
include_examples "XSS prevention", ""
@@ -38,7 +38,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "highlights as that language" do
result = filter('<pre><code lang="ruby">def fun end</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight ruby" lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></span></code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight language-ruby" lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></span></code></pre>')
end
include_examples "XSS prevention", "ruby"
@@ -48,7 +48,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "highlights as plaintext" do
result = filter('<pre><code lang="gnuplot">This is a test</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre>')
end
include_examples "XSS prevention", "gnuplot"
@@ -63,7 +63,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "highlights as plaintext but with the correct language attribute and class" do
result = filter(%{<pre><code lang="#{lang}">This is a test</code></pre>})
- expect(result.to_html).to eq(%{<pre class="code highlight js-syntax-highlight #{lang}" lang="#{lang}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre>})
+ expect(result.to_html).to eq(%{<pre class="code highlight js-syntax-highlight language-#{lang}" lang="#{lang}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre>})
end
include_examples "XSS prevention", lang
@@ -75,7 +75,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "includes data-lang-params tag with extra information" do
result = filter(%{<pre><code lang="#{lang}#{delimiter}#{lang_params}">This is a test</code></pre>})
- expect(result.to_html).to eq(%{<pre class="code highlight js-syntax-highlight #{lang}" lang="#{lang}" #{data_attr}="#{lang_params}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre>})
+ expect(result.to_html).to eq(%{<pre class="code highlight js-syntax-highlight language-#{lang}" lang="#{lang}" #{data_attr}="#{lang_params}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre>})
end
include_examples "XSS prevention", lang
@@ -93,7 +93,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "delimits on the first appearance" do
result = filter(%{<pre><code lang="#{lang}#{delimiter}#{lang_params}#{delimiter}more-things">This is a test</code></pre>})
- expect(result.to_html).to eq(%{<pre class="code highlight js-syntax-highlight #{lang}" lang="#{lang}" #{data_attr}="#{lang_params}#{delimiter}more-things" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre>})
+ expect(result.to_html).to eq(%{<pre class="code highlight js-syntax-highlight language-#{lang}" lang="#{lang}" #{data_attr}="#{lang_params}#{delimiter}more-things" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre>})
end
end
end
diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
index ab6093e9198..007d310247b 100644
--- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
@@ -297,7 +297,7 @@ RSpec.describe Banzai::Pipeline::WikiPipeline do
mime_type: 'image/jpeg',
name: 'images/image.jpg',
path: 'images/image.jpg',
- raw_data: '')
+ data: '')
wiki_file = Gitlab::Git::WikiFile.new(gollum_file_double)
markdown = "[[#{wiki_file.path}]]"
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index 3eb015a5a22..f3799c58fed 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -83,7 +83,7 @@ module Gitlab
},
'fenced code with inline script' => {
input: '```mypre"><script>alert(3)</script>',
- output: "<div>\n<div>\n<pre class=\"code highlight js-syntax-highlight plaintext\" lang=\"plaintext\" v-pre=\"true\"><code><span id=\"LC1\" class=\"line\" lang=\"plaintext\">\"&gt;</span></code></pre>\n</div>\n</div>"
+ output: "<div>\n<div>\n<pre class=\"code highlight js-syntax-highlight language-plaintext\" lang=\"plaintext\" v-pre=\"true\"><code><span id=\"LC1\" class=\"line\" lang=\"plaintext\">\"&gt;</span></code></pre>\n</div>\n</div>"
}
}
@@ -353,7 +353,7 @@ module Gitlab
output = <<~HTML
<div>
<div>
- <pre class="code highlight js-syntax-highlight javascript" lang="javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello world</span><span class="dl">'</span><span class="p">)</span></span></code></pre>
+ <pre class="code highlight js-syntax-highlight language-javascript" lang="javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello world</span><span class="dl">'</span><span class="p">)</span></span></code></pre>
</div>
</div>
HTML
@@ -380,7 +380,7 @@ module Gitlab
<div>
<div>class.cpp</div>
<div>
- <pre class="code highlight js-syntax-highlight cpp" lang="cpp" v-pre="true"><code><span id="LC1" class="line" lang="cpp"><span class="cp">#include &lt;stdio.h&gt;</span></span>
+ <pre class="code highlight js-syntax-highlight language-cpp" lang="cpp" v-pre="true"><code><span id="LC1" class="line" lang="cpp"><span class="cp">#include &lt;stdio.h&gt;</span></span>
<span id="LC2" class="line" lang="cpp"></span>
<span id="LC3" class="line" lang="cpp"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span></span>
<span id="LC4" class="line" lang="cpp"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">"*"</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span></span>
diff --git a/spec/lib/gitlab/graphql/negatable_arguments_spec.rb b/spec/lib/gitlab/graphql/negatable_arguments_spec.rb
new file mode 100644
index 00000000000..bc6e25eb018
--- /dev/null
+++ b/spec/lib/gitlab/graphql/negatable_arguments_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Graphql::NegatableArguments do
+ let(:test_resolver) do
+ Class.new(Resolvers::BaseResolver).tap do |klass|
+ klass.extend described_class
+ allow(klass).to receive(:name).and_return('Resolvers::TestResolver')
+ end
+ end
+
+ describe '#negated' do
+ it 'defines :not argument' do
+ test_resolver.negated {}
+
+ expect(test_resolver.arguments['not'].type.name).to eq "Types::TestResolverNegatedParamsType"
+ end
+
+ it 'defines any arguments passed as block' do
+ test_resolver.negated do
+ argument :foo, GraphQL::STRING_TYPE, required: false
+ end
+
+ expect(test_resolver.arguments['not'].type.arguments.keys).to match_array(['foo'])
+ end
+
+ it 'defines all arguments passed as block even if called multiple times' do
+ test_resolver.negated do
+ argument :foo, GraphQL::STRING_TYPE, required: false
+ end
+ test_resolver.negated do
+ argument :bar, GraphQL::STRING_TYPE, required: false
+ end
+
+ expect(test_resolver.arguments['not'].type.arguments.keys).to match_array(%w[foo bar])
+ end
+
+ it 'allows to specify custom argument name' do
+ test_resolver.negated(param_key: :negative) {}
+
+ expect(test_resolver.arguments).to include('negative')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/profiler_spec.rb b/spec/lib/gitlab/profiler_spec.rb
index 89917e515d0..48e2a2e9794 100644
--- a/spec/lib/gitlab/profiler_spec.rb
+++ b/spec/lib/gitlab/profiler_spec.rb
@@ -78,13 +78,8 @@ RSpec.describe Gitlab::Profiler do
end
it 'strips out the private token' do
- expect(custom_logger).to receive(:add) do |severity, _progname, message|
- next if message.include?('spec/')
-
- expect(severity).to eq(Logger::DEBUG)
- expect(message).to include('public').and include(described_class::FILTERED_STRING)
- expect(message).not_to include(private_token)
- end.at_least(1) # This spec could be wrapped in more blocks in the future
+ allow(custom_logger).to receive(:add).and_call_original
+ expect(custom_logger).to receive(:add).with(Logger::DEBUG, anything, 'public [FILTERED]').at_least(1)
custom_logger.debug("public #{private_token}")
end
diff --git a/spec/lib/gitlab/repository_set_cache_spec.rb b/spec/lib/gitlab/repository_set_cache_spec.rb
index 6bdcc5ea2b7..eaecbb0233d 100644
--- a/spec/lib/gitlab/repository_set_cache_spec.rb
+++ b/spec/lib/gitlab/repository_set_cache_spec.rb
@@ -124,6 +124,18 @@ RSpec.describe Gitlab::RepositorySetCache, :clean_gitlab_redis_cache do
end
end
+ describe '#search' do
+ subject do
+ cache.search(:foo, 'val*') do
+ %w[value helloworld notvalmatch]
+ end
+ end
+
+ it 'returns search pattern matches from the key' do
+ is_expected.to contain_exactly('value')
+ end
+ end
+
describe '#include?' do
it 'checks inclusion in the Redis set' do
cache.write(:foo, ['value'])
diff --git a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
index e7681ae5706..a948815171e 100644
--- a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
@@ -34,6 +34,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
'source_code',
'incident_management',
'incident_management_alerts',
+ 'incident_management_oncall',
'testing',
'issues_edit',
'ci_secrets_management',
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 31066419ee4..d819f28e114 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -1362,7 +1362,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
let(:categories) { ::Gitlab::UsageDataCounters::HLLRedisCounter.categories }
let(:ineligible_total_categories) do
- %w[source_code ci_secrets_management incident_management_alerts snippets terraform]
+ %w[source_code ci_secrets_management incident_management_alerts snippets terraform incident_management_oncall]
end
context 'with redis_hll_tracking feature enabled' do
diff --git a/spec/mailers/emails/in_product_marketing_spec.rb b/spec/mailers/emails/in_product_marketing_spec.rb
index e4157eaf5dc..25735e64bdf 100644
--- a/spec/mailers/emails/in_product_marketing_spec.rb
+++ b/spec/mailers/emails/in_product_marketing_spec.rb
@@ -13,6 +13,38 @@ RSpec.describe Emails::InProductMarketing do
describe '#in_product_marketing_email' do
using RSpec::Parameterized::TableSyntax
+ let(:track) { :create }
+ let(:series) { 0 }
+
+ subject { Notify.in_product_marketing_email(user.id, group.id, track, series) }
+
+ include_context 'gitlab email notification'
+
+ it 'sends to the right user with a link to unsubscribe' do
+ aggregate_failures do
+ expect(subject).to deliver_to(user.notification_email)
+ expect(subject).to have_body_text(profile_notifications_url)
+ end
+ end
+
+ context 'when on gitlab.com' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(true)
+ end
+
+ it 'has custom headers' do
+ aggregate_failures do
+ expect(subject).to deliver_from(described_class::FROM_ADDRESS)
+ expect(subject).to reply_to(described_class::FROM_ADDRESS)
+ expect(subject).to have_header('X-Mailgun-Track', 'yes')
+ expect(subject).to have_header('X-Mailgun-Track-Clicks', 'yes')
+ expect(subject).to have_header('X-Mailgun-Track-Opens', 'yes')
+ expect(subject).to have_header('X-Mailgun-Tag', 'marketing')
+ expect(subject).to have_body_text('%tag_unsubscribe_url%')
+ end
+ end
+ end
+
where(:track, :series) do
:create | 0
:create | 1
@@ -29,8 +61,6 @@ RSpec.describe Emails::InProductMarketing do
end
with_them do
- subject { Notify.in_product_marketing_email(user.id, group.id, track, series) }
-
it 'has the correct subject and content' do
aggregate_failures do
is_expected.to have_subject(subject_line(track, series))
diff --git a/spec/models/concerns/cascading_namespace_setting_attribute_spec.rb b/spec/models/concerns/cascading_namespace_setting_attribute_spec.rb
new file mode 100644
index 00000000000..ddff9ce32b4
--- /dev/null
+++ b/spec/models/concerns/cascading_namespace_setting_attribute_spec.rb
@@ -0,0 +1,320 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe NamespaceSetting, 'CascadingNamespaceSettingAttribute' do
+ let(:group) { create(:group) }
+ let(:subgroup) { create(:group, parent: group) }
+
+ def group_settings
+ group.namespace_settings
+ end
+
+ def subgroup_settings
+ subgroup.namespace_settings
+ end
+
+ describe '#delayed_project_removal' do
+ subject(:delayed_project_removal) { subgroup_settings.delayed_project_removal }
+
+ context 'when the feature is disabled' do
+ before do
+ stub_feature_flags(cascading_namespace_settings: false)
+
+ group_settings.update!(delayed_project_removal: true)
+ end
+
+ it 'does not cascade' do
+ expect(delayed_project_removal).to eq(nil)
+ end
+ end
+
+ context 'when there is no parent' do
+ context 'and the value is not nil' do
+ before do
+ group_settings.update!(delayed_project_removal: true)
+ end
+
+ it 'returns the local value' do
+ expect(group_settings.delayed_project_removal).to eq(true)
+ end
+ end
+
+ context 'and the value is nil' do
+ before do
+ group_settings.update!(delayed_project_removal: nil)
+ stub_application_setting(delayed_project_removal: false)
+ end
+
+ it 'returns the application settings value' do
+ expect(group_settings.delayed_project_removal).to eq(false)
+ end
+ end
+ end
+
+ context 'when parent does not lock the attribute' do
+ context 'and value is not nil' do
+ before do
+ group_settings.update!(delayed_project_removal: false)
+ end
+
+ it 'returns local setting when present' do
+ subgroup_settings.update!(delayed_project_removal: true)
+
+ expect(delayed_project_removal).to eq(true)
+ end
+
+ it 'returns the parent value when local value is nil' do
+ subgroup_settings.update!(delayed_project_removal: nil)
+
+ expect(delayed_project_removal).to eq(false)
+ end
+
+ it 'returns the correct dirty value' do
+ subgroup_settings.delayed_project_removal = true
+
+ expect(delayed_project_removal).to eq(true)
+ end
+
+ it 'does not return the application setting value when parent value is false' do
+ stub_application_setting(delayed_project_removal: true)
+
+ expect(delayed_project_removal).to eq(false)
+ end
+ end
+
+ context 'and the value is nil' do
+ before do
+ group_settings.update!(delayed_project_removal: nil, lock_delayed_project_removal: false)
+ subgroup_settings.update!(delayed_project_removal: nil)
+
+ subgroup_settings.clear_memoization(:delayed_project_removal)
+ end
+
+ it 'cascades to the application settings value' do
+ expect(delayed_project_removal).to eq(false)
+ end
+ end
+
+ context 'when multiple ancestors set a value' do
+ let(:third_level_subgroup) { create(:group, parent: subgroup) }
+
+ before do
+ group_settings.update!(delayed_project_removal: true)
+ subgroup_settings.update!(delayed_project_removal: false)
+ end
+
+ it 'returns the closest ancestor value' do
+ expect(third_level_subgroup.namespace_settings.delayed_project_removal).to eq(false)
+ end
+ end
+ end
+
+ context 'when parent locks the attribute' do
+ before do
+ subgroup_settings.update!(delayed_project_removal: true)
+ group_settings.update!(lock_delayed_project_removal: true, delayed_project_removal: false)
+
+ subgroup_settings.clear_memoization(:delayed_project_removal)
+ subgroup_settings.clear_memoization(:delayed_project_removal_locked_ancestor)
+ end
+
+ it 'returns the parent value' do
+ expect(delayed_project_removal).to eq(false)
+ end
+
+ it 'does not allow the local value to be saved' do
+ subgroup_settings.delayed_project_removal = nil
+
+ expect { subgroup_settings.save! }
+ .to raise_error(ActiveRecord::RecordInvalid, /Delayed project removal cannot be changed because it is locked by an ancestor/)
+ end
+ end
+
+ context 'when the application settings locks the attribute' do
+ before do
+ subgroup_settings.update!(delayed_project_removal: true)
+ stub_application_setting(lock_delayed_project_removal: true, delayed_project_removal: true)
+ end
+
+ it 'returns the application setting value' do
+ expect(delayed_project_removal).to eq(true)
+ end
+
+ it 'does not allow the local value to be saved' do
+ subgroup_settings.delayed_project_removal = nil
+
+ expect { subgroup_settings.save! }
+ .to raise_error(ActiveRecord::RecordInvalid, /Delayed project removal cannot be changed because it is locked by an ancestor/)
+ end
+ end
+ end
+
+ describe '#delayed_project_removal?' do
+ before do
+ subgroup_settings.update!(delayed_project_removal: true)
+ group_settings.update!(lock_delayed_project_removal: true, delayed_project_removal: false)
+
+ subgroup_settings.clear_memoization(:delayed_project_removal)
+ subgroup_settings.clear_memoization(:delayed_project_removal_locked_ancestor)
+ end
+
+ it 'aliases the method when the attribute is a boolean' do
+ expect(subgroup_settings.delayed_project_removal?).to eq(subgroup_settings.delayed_project_removal)
+ end
+ end
+
+ describe '#delayed_project_removal_locked?' do
+ shared_examples 'not locked' do
+ it 'is not locked by an ancestor' do
+ expect(subgroup_settings.delayed_project_removal_locked_by_ancestor?).to eq(false)
+ end
+
+ it 'is not locked by application setting' do
+ expect(subgroup_settings.delayed_project_removal_locked_by_application_setting?).to eq(false)
+ end
+
+ it 'does not return a locked namespace' do
+ expect(subgroup_settings.delayed_project_removal_locked_ancestor).to be_nil
+ end
+ end
+
+ context 'when the feature is disabled' do
+ before do
+ stub_feature_flags(cascading_namespace_settings: false)
+
+ group_settings.update!(delayed_project_removal: true)
+ end
+
+ it_behaves_like 'not locked'
+ end
+
+ context 'when parent does not lock the attribute' do
+ it_behaves_like 'not locked'
+ end
+
+ context 'when parent locks the attribute' do
+ before do
+ group_settings.update!(lock_delayed_project_removal: true, delayed_project_removal: false)
+
+ subgroup_settings.clear_memoization(:delayed_project_removal)
+ subgroup_settings.clear_memoization(:delayed_project_removal_locked_ancestor)
+ end
+
+ it 'is locked by an ancestor' do
+ expect(subgroup_settings.delayed_project_removal_locked_by_ancestor?).to eq(true)
+ end
+
+ it 'is not locked by application setting' do
+ expect(subgroup_settings.delayed_project_removal_locked_by_application_setting?).to eq(false)
+ end
+
+ it 'returns a locked namespace settings object' do
+ expect(subgroup_settings.delayed_project_removal_locked_ancestor.namespace_id).to eq(group_settings.namespace_id)
+ end
+ end
+
+ context 'when not locked by application settings' do
+ before do
+ stub_application_setting(lock_delayed_project_removal: false)
+ end
+
+ it_behaves_like 'not locked'
+ end
+
+ context 'when locked by application settings' do
+ before do
+ stub_application_setting(lock_delayed_project_removal: true)
+ end
+
+ it 'is not locked by an ancestor' do
+ expect(subgroup_settings.delayed_project_removal_locked_by_ancestor?).to eq(false)
+ end
+
+ it 'is locked by application setting' do
+ expect(subgroup_settings.delayed_project_removal_locked_by_application_setting?).to eq(true)
+ end
+
+ it 'does not return a locked namespace' do
+ expect(subgroup_settings.delayed_project_removal_locked_ancestor).to be_nil
+ end
+ end
+ end
+
+ describe '#lock_delayed_project_removal=' do
+ context 'when parent locks the attribute' do
+ before do
+ group_settings.update!(lock_delayed_project_removal: true, delayed_project_removal: false)
+
+ subgroup_settings.clear_memoization(:delayed_project_removal)
+ subgroup_settings.clear_memoization(:delayed_project_removal_locked_ancestor)
+ end
+
+ it 'does not allow the attribute to be saved' do
+ subgroup_settings.lock_delayed_project_removal = true
+
+ expect { subgroup_settings.save! }
+ .to raise_error(ActiveRecord::RecordInvalid, /Lock delayed project removal cannot be changed because it is locked by an ancestor/)
+ end
+ end
+
+ context 'when parent does not lock the attribute' do
+ before do
+ group_settings.update!(lock_delayed_project_removal: false)
+
+ subgroup_settings.lock_delayed_project_removal = true
+ end
+
+ it 'allows the lock to be set when the attribute is not nil' do
+ subgroup_settings.delayed_project_removal = true
+
+ expect(subgroup_settings.save).to eq(true)
+ end
+
+ it 'does not allow the lock to be saved when the attribute is nil' do
+ subgroup_settings.delayed_project_removal = nil
+
+ expect { subgroup_settings.save! }
+ .to raise_error(ActiveRecord::RecordInvalid, /Delayed project removal cannot be nil when locking the attribute/)
+ end
+ end
+
+ context 'when application settings locks the attribute' do
+ before do
+ stub_application_setting(lock_delayed_project_removal: true)
+ end
+
+ it 'does not allow the attribute to be saved' do
+ subgroup_settings.lock_delayed_project_removal = true
+
+ expect { subgroup_settings.save! }
+ .to raise_error(ActiveRecord::RecordInvalid, /Lock delayed project removal cannot be changed because it is locked by an ancestor/)
+ end
+ end
+
+ context 'when application_settings does not lock the attribute' do
+ before do
+ stub_application_setting(lock_delayed_project_removal: false)
+ end
+
+ it 'allows the attribute to be saved' do
+ subgroup_settings.delayed_project_removal = true
+ subgroup_settings.lock_delayed_project_removal = true
+
+ expect(subgroup_settings.save).to eq(true)
+ end
+ end
+ end
+
+ describe 'after update callback' do
+ before do
+ subgroup_settings.update!(lock_delayed_project_removal: true, delayed_project_removal: false)
+ end
+
+ it 'clears descendant locks' do
+ group_settings.update!(lock_delayed_project_removal: true, delayed_project_removal: true)
+
+ expect(subgroup_settings.reload.lock_delayed_project_removal).to eq(false)
+ end
+ end
+end
diff --git a/spec/models/concerns/ci/has_status_spec.rb b/spec/models/concerns/ci/has_status_spec.rb
index ea7dbf0411c..b16420bc658 100644
--- a/spec/models/concerns/ci/has_status_spec.rb
+++ b/spec/models/concerns/ci/has_status_spec.rb
@@ -197,12 +197,6 @@ RSpec.describe Ci::HasStatus do
end
end
- describe '.completed_and_blocked_statuses' do
- subject { Ci::Pipeline.completed_and_blocked_statuses }
-
- it { is_expected.to eq [:success, :failed, :canceled, :skipped, :manual, :scheduled] }
- end
-
context 'for scope with one status' do
shared_examples 'having a job' do |status|
%i[ci_build generic_commit_status].each do |type|
diff --git a/spec/models/project_services/chat_message/merge_message_spec.rb b/spec/models/project_services/chat_message/merge_message_spec.rb
index 02b266e4fae..71cfe3ff45b 100644
--- a/spec/models/project_services/chat_message/merge_message_spec.rb
+++ b/spec/models/project_services/chat_message/merge_message_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe ChatMessage::MergeMessage do
project_url: 'http://somewhere.com',
object_attributes: {
- title: "Merge Request title\nSecond line",
+ title: "Merge request title\nSecond line",
id: 10,
iid: 100,
assignee_id: 1,
@@ -35,7 +35,7 @@ RSpec.describe ChatMessage::MergeMessage do
context 'open' do
it 'returns a message regarding opening of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) opened merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge Request title*> in <http://somewhere.com|project_name>')
+ 'Test User (test.user) opened merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge request title*> in <http://somewhere.com|project_name>')
expect(subject.attachments).to be_empty
end
end
@@ -46,7 +46,7 @@ RSpec.describe ChatMessage::MergeMessage do
end
it 'returns a message regarding closing of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) closed merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge Request title*> in <http://somewhere.com|project_name>')
+ 'Test User (test.user) closed merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge request title*> in <http://somewhere.com|project_name>')
expect(subject.attachments).to be_empty
end
end
@@ -60,12 +60,12 @@ RSpec.describe ChatMessage::MergeMessage do
context 'open' do
it 'returns a message regarding opening of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) opened merge request [!100 *Merge Request title*](http://somewhere.com/-/merge_requests/100) in [project_name](http://somewhere.com)')
+ 'Test User (test.user) opened merge request [!100 *Merge request title*](http://somewhere.com/-/merge_requests/100) in [project_name](http://somewhere.com)')
expect(subject.attachments).to be_empty
expect(subject.activity).to eq({
- title: 'Merge Request opened by Test User (test.user)',
+ title: 'Merge request opened by Test User (test.user)',
subtitle: 'in [project_name](http://somewhere.com)',
- text: '[!100 *Merge Request title*](http://somewhere.com/-/merge_requests/100)',
+ text: '[!100 *Merge request title*](http://somewhere.com/-/merge_requests/100)',
image: 'http://someavatar.com'
})
end
@@ -78,12 +78,12 @@ RSpec.describe ChatMessage::MergeMessage do
it 'returns a message regarding closing of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) closed merge request [!100 *Merge Request title*](http://somewhere.com/-/merge_requests/100) in [project_name](http://somewhere.com)')
+ 'Test User (test.user) closed merge request [!100 *Merge request title*](http://somewhere.com/-/merge_requests/100) in [project_name](http://somewhere.com)')
expect(subject.attachments).to be_empty
expect(subject.activity).to eq({
- title: 'Merge Request closed by Test User (test.user)',
+ title: 'Merge request closed by Test User (test.user)',
subtitle: 'in [project_name](http://somewhere.com)',
- text: '[!100 *Merge Request title*](http://somewhere.com/-/merge_requests/100)',
+ text: '[!100 *Merge request title*](http://somewhere.com/-/merge_requests/100)',
image: 'http://someavatar.com'
})
end
@@ -97,7 +97,7 @@ RSpec.describe ChatMessage::MergeMessage do
it 'returns a message regarding completed approval of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) approved merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge Request title*> '\
+ 'Test User (test.user) approved merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge request title*> '\
'in <http://somewhere.com|project_name>')
expect(subject.attachments).to be_empty
end
@@ -110,7 +110,7 @@ RSpec.describe ChatMessage::MergeMessage do
it 'returns a message regarding revocation of completed approval of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) unapproved merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge Request title*> '\
+ 'Test User (test.user) unapproved merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge request title*> '\
'in <http://somewhere.com|project_name>')
expect(subject.attachments).to be_empty
end
@@ -123,7 +123,7 @@ RSpec.describe ChatMessage::MergeMessage do
it 'returns a message regarding added approval of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) added their approval to merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge Request title*> '\
+ 'Test User (test.user) added their approval to merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge request title*> '\
'in <http://somewhere.com|project_name>')
expect(subject.attachments).to be_empty
end
@@ -136,7 +136,7 @@ RSpec.describe ChatMessage::MergeMessage do
it 'returns a message regarding revoking approval of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) removed their approval from merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge Request title*> '\
+ 'Test User (test.user) removed their approval from merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge request title*> '\
'in <http://somewhere.com|project_name>')
expect(subject.attachments).to be_empty
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 84404a31f76..c1a292c9b30 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -170,6 +170,22 @@ RSpec.describe Repository do
end
end
+ describe '#search_branch_names' do
+ subject(:search_branch_names) { repository.search_branch_names('conflict-*') }
+
+ it 'returns matching branch names' do
+ expect(search_branch_names).to contain_exactly(
+ 'conflict-binary-file',
+ 'conflict-resolvable',
+ 'conflict-contains-conflict-markers',
+ 'conflict-missing-side',
+ 'conflict-start',
+ 'conflict-non-utf8',
+ 'conflict-too-large'
+ )
+ end
+ end
+
describe '#list_last_commits_for_tree' do
let(:path_to_commit) do
{
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index ac92311e132..ee67afcd50b 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2521,32 +2521,12 @@ RSpec.describe User do
describe "#clear_avatar_caches" do
let(:user) { create(:user) }
- context "when :avatar_cache_for_email flag is enabled" do
- before do
- stub_feature_flags(avatar_cache_for_email: true)
- end
-
- it "clears the avatar cache when saving" do
- allow(user).to receive(:avatar_changed?).and_return(true)
-
- expect(Gitlab::AvatarCache).to receive(:delete_by_email).with(*user.verified_emails)
-
- user.update(avatar: fixture_file_upload('spec/fixtures/dk.png'))
- end
- end
-
- context "when :avatar_cache_for_email flag is disabled" do
- before do
- stub_feature_flags(avatar_cache_for_email: false)
- end
-
- it "doesn't attempt to clear the avatar cache" do
- allow(user).to receive(:avatar_changed?).and_return(true)
+ it "clears the avatar cache when saving" do
+ allow(user).to receive(:avatar_changed?).and_return(true)
- expect(Gitlab::AvatarCache).not_to receive(:delete_by_email)
+ expect(Gitlab::AvatarCache).to receive(:delete_by_email).with(*user.verified_emails)
- user.update(avatar: fixture_file_upload('spec/fixtures/dk.png'))
- end
+ user.update(avatar: fixture_file_upload('spec/fixtures/dk.png'))
end
end
diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb
index c72fd71884e..36055779a2e 100644
--- a/spec/services/ci/pipeline_trigger_service_spec.rb
+++ b/spec/services/ci/pipeline_trigger_service_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Ci::PipelineTriggerService do
stub_ci_pipeline_to_return_yaml_file
end
- describe '#execute', :context_aware do
+ describe '#execute' do
let_it_be(:user) { create(:user) }
let(:result) { described_class.new(project, user, params).execute }
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 84c38ca0ce2..a3925a0c0fb 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -338,20 +338,10 @@ RSpec.configure do |config|
RequestStore.clear!
end
- if ENV['SKIP_RSPEC_CONTEXT_WRAPPING']
- config.around(:example, :context_aware) do |example|
- # Wrap each example in it's own context to make sure the contexts don't
- # leak
- Gitlab::ApplicationContext.with_raw_context { example.run }
- end
- else
- config.around do |example|
- if [:controller, :request, :feature].include?(example.metadata[:type]) || example.metadata[:context_aware]
- Gitlab::ApplicationContext.with_raw_context { example.run }
- else
- example.run
- end
- end
+ config.around do |example|
+ # Wrap each example in it's own context to make sure the contexts don't
+ # leak
+ Gitlab::ApplicationContext.with_raw_context { example.run }
end
config.around do |example|
diff --git a/spec/support/shared_examples/lib/api/ci/runner_shared_examples.rb b/spec/support/shared_examples/lib/api/ci/runner_shared_examples.rb
index c775ca182e6..d5ebda28f0a 100644
--- a/spec/support/shared_examples/lib/api/ci/runner_shared_examples.rb
+++ b/spec/support/shared_examples/lib/api/ci/runner_shared_examples.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.shared_examples 'API::CI::Runner application context metadata' do |api_route|
- it 'contains correct context metadata', :context_aware do
+ it 'contains correct context metadata' do
# Avoids popping the context from the thread so we can
# check its content after the request.
allow(Labkit::Context).to receive(:pop)
diff --git a/spec/support/shared_examples/models/wiki_shared_examples.rb b/spec/support/shared_examples/models/wiki_shared_examples.rb
index 50d50bee727..6b243aef3e6 100644
--- a/spec/support/shared_examples/models/wiki_shared_examples.rb
+++ b/spec/support/shared_examples/models/wiki_shared_examples.rb
@@ -354,33 +354,29 @@ RSpec.shared_examples 'wiki model' do
subject.repository.create_file(user, 'image.png', image, branch_name: subject.default_branch, message: 'add image')
end
- shared_examples 'find_file results' do
- it 'returns the latest version of the file if it exists' do
- file = subject.find_file('image.png')
+ it 'returns the latest version of the file if it exists' do
+ file = subject.find_file('image.png')
- expect(file.mime_type).to eq('image/png')
- end
+ expect(file.mime_type).to eq('image/png')
+ end
- it 'returns nil if the page does not exist' do
- expect(subject.find_file('non-existent')).to eq(nil)
- end
+ it 'returns nil if the page does not exist' do
+ expect(subject.find_file('non-existent')).to eq(nil)
+ end
- it 'returns a Gitlab::Git::WikiFile instance' do
- file = subject.find_file('image.png')
+ it 'returns a Gitlab::Git::WikiFile instance' do
+ file = subject.find_file('image.png')
- expect(file).to be_a Gitlab::Git::WikiFile
- end
+ expect(file).to be_a Gitlab::Git::WikiFile
+ end
- it 'returns the whole file' do
- file = subject.find_file('image.png')
- image.rewind
+ it 'returns the whole file' do
+ file = subject.find_file('image.png')
+ image.rewind
- expect(file.raw_data.b).to eq(image.read.b)
- end
+ expect(file.raw_data.b).to eq(image.read.b)
end
- it_behaves_like 'find_file results'
-
context 'when load_content is disabled' do
it 'includes the file data in the Gitlab::Git::WikiFile' do
file = subject.find_file('image.png', load_content: false)
@@ -388,14 +384,6 @@ RSpec.shared_examples 'wiki model' do
expect(file.raw_data).to be_empty
end
end
-
- context 'when feature flag :gitaly_find_file is disabled' do
- before do
- stub_feature_flags(gitaly_find_file: false)
- end
-
- it_behaves_like 'find_file results'
- end
end
describe '#create_page' do
diff --git a/spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb b/spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb
index 57e28e6df57..cb06c9fa596 100644
--- a/spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.shared_examples 'storing arguments in the application context' do
- it 'places the expected params in the application context', :context_aware do
+ it 'places the expected params in the application context' do
# Stub the clearing of the context so we can validate it later
allow(Labkit::Context).to receive(:pop)
diff --git a/spec/views/registrations/welcome/show.html.haml_spec.rb b/spec/views/registrations/welcome/show.html.haml_spec.rb
index d9774582545..639759ae095 100644
--- a/spec/views/registrations/welcome/show.html.haml_spec.rb
+++ b/spec/views/registrations/welcome/show.html.haml_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'registrations/welcome/show' do
- using RSpec::Parameterized::TableSyntax
+ let(:is_gitlab_com) { false }
let_it_be(:user) { User.new }
@@ -13,7 +13,7 @@ RSpec.describe 'registrations/welcome/show' do
allow(view).to receive(:in_trial_flow?).and_return(false)
allow(view).to receive(:user_has_memberships?).and_return(false)
allow(view).to receive(:in_oauth_flow?).and_return(false)
- allow(Gitlab).to receive(:com?).and_return(false)
+ allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
render
end
@@ -22,4 +22,24 @@ RSpec.describe 'registrations/welcome/show' do
it { is_expected.not_to have_selector('label[for="user_setup_for_company"]') }
it { is_expected.to have_button('Get started!') }
+ it { is_expected.to have_selector('input[name="user[email_opted_in]"]') }
+
+ describe 'email opt in' do
+ context 'when on gitlab.com' do
+ let(:is_gitlab_com) { true }
+
+ it 'hides the email-opt in by default' do
+ expect(subject).to have_css('.js-email-opt-in.hidden')
+ end
+ end
+
+ context 'when not on gitlab.com' do
+ let(:is_gitlab_com) { false }
+
+ it 'hides the email-opt in by default' do
+ expect(subject).not_to have_css('.js-email-opt-in.hidden')
+ expect(subject).to have_css('.js-email-opt-in')
+ end
+ end
+ end
end
diff --git a/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb b/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb
index 24143e8cf8a..af4a6dac6cd 100644
--- a/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb
+++ b/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb
@@ -3,45 +3,49 @@
require 'spec_helper'
RSpec.describe Namespaces::InProductMarketingEmailsWorker, '#perform' do
- context 'when the application setting is enabled' do
+ using RSpec::Parameterized::TableSyntax
+
+ RSpec.shared_examples 'in-product marketing email' do
before do
- stub_application_setting(in_product_marketing_emails_enabled: true)
+ stub_application_setting(in_product_marketing_emails_enabled: in_product_marketing_emails_enabled)
+ stub_experiment(in_product_marketing_emails: experiment_active)
+ allow(::Gitlab).to receive(:com?).and_return(is_gitlab_com)
end
- context 'when the experiment is inactive' do
- before do
- stub_experiment(in_product_marketing_emails: false)
- end
-
- it 'does not execute the in product marketing emails service' do
- expect(Namespaces::InProductMarketingEmailsService).not_to receive(:send_for_all_tracks_and_intervals)
+ it 'executes the email service service' do
+ expect(Namespaces::InProductMarketingEmailsService).to receive(:send_for_all_tracks_and_intervals).exactly(executes_service).times
- subject.perform
- end
+ subject.perform
end
+ end
- context 'when the experiment is active' do
- before do
- stub_experiment(in_product_marketing_emails: true)
- end
+ context 'not on gitlab.com' do
+ let(:is_gitlab_com) { false }
- it 'calls the send_for_all_tracks_and_intervals method on the in product marketing emails service' do
- expect(Namespaces::InProductMarketingEmailsService).to receive(:send_for_all_tracks_and_intervals)
+ where(:in_product_marketing_emails_enabled, :experiment_active, :executes_service) do
+ true | true | 1
+ true | false | 1
+ false | false | 0
+ false | true | 0
+ end
- subject.perform
- end
+ with_them do
+ include_examples 'in-product marketing email'
end
end
- context 'when the application setting is disabled' do
- before do
- stub_application_setting(in_product_marketing_emails_enabled: false)
- end
+ context 'on gitlab.com' do
+ let(:is_gitlab_com) { true }
- it 'does not execute the in product marketing emails service' do
- expect(Namespaces::InProductMarketingEmailsService).not_to receive(:send_for_all_tracks_and_intervals)
+ where(:in_product_marketing_emails_enabled, :experiment_active, :executes_service) do
+ true | true | 1
+ true | false | 0
+ false | false | 0
+ false | true | 0
+ end
- subject.perform
+ with_them do
+ include_examples 'in-product marketing email'
end
end
end