Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-06-14 18:08:43 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-14 18:08:43 +0300
commit9b8269e5708ba1c38610189f84cf7224b640c0ed (patch)
tree70916a0afcfd90ed5425a80bab7f6bedca13d622 /spec
parent7a124e225ea58c2a432dd29f82ba682963886383 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/components/pajamas/alert_component_spec.rb48
-rw-r--r--spec/contracts/consumer/.eslintrc.yml7
-rw-r--r--spec/contracts/consumer/babel.config.json3
-rw-r--r--spec/contracts/consumer/endpoints/merge_requests.js64
-rw-r--r--spec/contracts/consumer/fixtures/diffs.fixture.js15
-rw-r--r--spec/contracts/consumer/fixtures/discussions.fixture.js9
-rw-r--r--spec/contracts/consumer/fixtures/metadata.fixture.js9
-rw-r--r--spec/contracts/consumer/package.json9
-rw-r--r--spec/contracts/consumer/specs/diffs.spec.js9
-rw-r--r--spec/contracts/consumer/specs/discussions.spec.js9
-rw-r--r--spec/contracts/consumer/specs/metadata.spec.js9
-rw-r--r--spec/frontend/ide/components/commit_sidebar/editor_header_spec.js2
-rw-r--r--spec/frontend/security_configuration/components/app_spec.js94
-rw-r--r--spec/frontend/security_configuration/mock_data.js9
-rw-r--r--spec/frontend/sidebar/components/attention_requested_toggle_spec.js12
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js8
-rw-r--r--spec/helpers/form_helper_spec.rb2
-rw-r--r--spec/lib/gitlab/audit/unauthenticated_author_spec.rb6
-rw-r--r--spec/lib/gitlab/diff/rendered/notebook/diff_file_helper_spec.rb134
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb27
-rw-r--r--spec/models/concerns/as_cte_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb56
-rw-r--r--spec/requests/api/release/links_spec.rb76
23 files changed, 421 insertions, 198 deletions
diff --git a/spec/components/pajamas/alert_component_spec.rb b/spec/components/pajamas/alert_component_spec.rb
index db425fb2dce..1e2845c44a8 100644
--- a/spec/components/pajamas/alert_component_spec.rb
+++ b/spec/components/pajamas/alert_component_spec.rb
@@ -50,10 +50,12 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
before do
render_inline described_class.new(
title: '_title_',
- alert_class: '_alert_class_',
- alert_data: {
- feature_id: '_feature_id_',
- dismiss_endpoint: '_dismiss_endpoint_'
+ alert_options: {
+ class: '_alert_class_',
+ data: {
+ feature_id: '_feature_id_',
+ dismiss_endpoint: '_dismiss_endpoint_'
+ }
}
)
end
@@ -106,9 +108,11 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
context 'with dismissible content' do
before do
render_inline described_class.new(
- close_button_class: '_close_button_class_',
- close_button_data: {
- testid: '_close_button_testid_'
+ close_button_options: {
+ class: '_close_button_class_',
+ data: {
+ testid: '_close_button_testid_'
+ }
}
)
end
@@ -138,35 +142,5 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
end
end
end
-
- context 'with alert_options' do
- let(:options) { { alert_options: { id: 'test_id', class: 'baz', data: { foo: 'bar' } } } }
-
- before do
- render_inline described_class.new(**options)
- end
-
- it 'renders the extra options' do
- expect(rendered_component).to have_css "#test_id.gl-alert.baz[data-foo='bar']"
- end
-
- context 'with custom classes or data' do
- let(:options) do
- {
- variant: :danger,
- alert_class: 'custom',
- alert_data: { foo: 'bar' },
- alert_options: {
- class: 'extra special',
- data: { foo: 'conflict' }
- }
- }
- end
-
- it 'doesn\'t conflict with internal alert_class or alert_data' do
- expect(rendered_component).to have_css ".extra.special.custom.gl-alert.gl-alert-danger[data-foo='bar']"
- end
- end
- end
end
end
diff --git a/spec/contracts/consumer/.eslintrc.yml b/spec/contracts/consumer/.eslintrc.yml
new file mode 100644
index 00000000000..e4b380714d3
--- /dev/null
+++ b/spec/contracts/consumer/.eslintrc.yml
@@ -0,0 +1,7 @@
+---
+extends:
+ - 'plugin:@gitlab/jest'
+settings:
+ import/core-modules:
+ - '@pact-foundation/pact'
+ - jest-pact
diff --git a/spec/contracts/consumer/babel.config.json b/spec/contracts/consumer/babel.config.json
new file mode 100644
index 00000000000..1320b9a3272
--- /dev/null
+++ b/spec/contracts/consumer/babel.config.json
@@ -0,0 +1,3 @@
+{
+ "presets": ["@babel/preset-env"]
+}
diff --git a/spec/contracts/consumer/endpoints/merge_requests.js b/spec/contracts/consumer/endpoints/merge_requests.js
index 04e66c57dc9..ae4d5544df6 100644
--- a/spec/contracts/consumer/endpoints/merge_requests.js
+++ b/spec/contracts/consumer/endpoints/merge_requests.js
@@ -1,42 +1,34 @@
-'use strict';
+import { request } from 'axios';
-const axios = require('axios');
+export function getMetadata(endpoint) {
+ const { url } = endpoint;
-exports.getMetadata = (endpoint) => {
- const url = endpoint.url;
+ return request({
+ method: 'GET',
+ baseURL: url,
+ url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_metadata.json',
+ headers: { Accept: '*/*' },
+ }).then((response) => response.data);
+}
- return axios
- .request({
- method: 'GET',
- baseURL: url,
- url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_metadata.json',
- headers: { Accept: '*/*' },
- })
- .then((response) => response.data);
-};
+export function getDiscussions(endpoint) {
+ const { url } = endpoint;
-exports.getDiscussions = (endpoint) => {
- const url = endpoint.url;
+ return request({
+ method: 'GET',
+ baseURL: url,
+ url: '/gitlab-org/gitlab-qa/-/merge_requests/1/discussions.json',
+ headers: { Accept: '*/*' },
+ }).then((response) => response.data);
+}
- return axios
- .request({
- method: 'GET',
- baseURL: url,
- url: '/gitlab-org/gitlab-qa/-/merge_requests/1/discussions.json',
- headers: { Accept: '*/*' },
- })
- .then((response) => response.data);
-};
+export function getDiffs(endpoint) {
+ const { url } = endpoint;
-exports.getDiffs = (endpoint) => {
- const url = endpoint.url;
-
- return axios
- .request({
- method: 'GET',
- baseURL: url,
- url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_batch.json?page=0',
- headers: { Accept: '*/*' },
- })
- .then((response) => response.data);
-};
+ return request({
+ method: 'GET',
+ baseURL: url,
+ url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_batch.json?page=0',
+ headers: { Accept: '*/*' },
+ }).then((response) => response.data);
+}
diff --git a/spec/contracts/consumer/fixtures/diffs.fixture.js b/spec/contracts/consumer/fixtures/diffs.fixture.js
index 7dbe825b093..cc2c054b08f 100644
--- a/spec/contracts/consumer/fixtures/diffs.fixture.js
+++ b/spec/contracts/consumer/fixtures/diffs.fixture.js
@@ -1,6 +1,6 @@
-'use strict';
+/* eslint-disable @gitlab/require-i18n-strings */
-const { Matchers } = require('@pact-foundation/pact');
+import { Matchers } from '@pact-foundation/pact';
const body = {
diff_files: Matchers.eachLike({
@@ -48,9 +48,9 @@ const body = {
context_lines_path: Matchers.string('/gitlab-qa-bot/...'),
highlighted_diff_lines: Matchers.eachLike({
// The following values can also be null which is not supported
- //line_code: Matchers.string('de3150c01c3a946a6168173c4116741379fe3579_1_1'),
- //old_line: Matchers.integer(1),
- //new_line: Matchers.integer(1),
+ // line_code: Matchers.string('de3150c01c3a946a6168173c4116741379fe3579_1_1'),
+ // old_line: Matchers.integer(1),
+ // new_line: Matchers.integer(1),
text: Matchers.string('source'),
rich_text: Matchers.string('<span></span>'),
can_receive_suggestion: Matchers.boolean(true),
@@ -70,7 +70,7 @@ const Diffs = {
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
- body: body,
+ body,
},
request: {
@@ -86,4 +86,5 @@ const Diffs = {
},
};
-exports.Diffs = Diffs;
+export { Diffs };
+/* eslint-enable @gitlab/require-i18n-strings */
diff --git a/spec/contracts/consumer/fixtures/discussions.fixture.js b/spec/contracts/consumer/fixtures/discussions.fixture.js
index c28b9bdd505..26f1d65f663 100644
--- a/spec/contracts/consumer/fixtures/discussions.fixture.js
+++ b/spec/contracts/consumer/fixtures/discussions.fixture.js
@@ -1,6 +1,6 @@
-'use strict';
+/* eslint-disable @gitlab/require-i18n-strings */
-const { Matchers } = require('@pact-foundation/pact');
+import { Matchers } from '@pact-foundation/pact';
const body = Matchers.eachLike({
id: Matchers.string('fd73763cbcbf7b29eb8765d969a38f7d735e222a'),
@@ -67,7 +67,7 @@ const Discussions = {
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
- body: body,
+ body,
},
request: {
@@ -82,4 +82,5 @@ const Discussions = {
},
};
-exports.Discussions = Discussions;
+export { Discussions };
+/* eslint-enable @gitlab/require-i18n-strings */
diff --git a/spec/contracts/consumer/fixtures/metadata.fixture.js b/spec/contracts/consumer/fixtures/metadata.fixture.js
index 3fca6cf9181..c19ca2175b3 100644
--- a/spec/contracts/consumer/fixtures/metadata.fixture.js
+++ b/spec/contracts/consumer/fixtures/metadata.fixture.js
@@ -1,6 +1,6 @@
-'use strict';
+/* eslint-disable @gitlab/require-i18n-strings */
-const { Matchers } = require('@pact-foundation/pact');
+import { Matchers } from '@pact-foundation/pact';
const body = {
real_size: Matchers.string('1'),
@@ -78,7 +78,7 @@ const Metadata = {
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
- body: body,
+ body,
},
request: {
@@ -93,4 +93,5 @@ const Metadata = {
},
};
-exports.Metadata = Metadata;
+export { Metadata };
+/* eslint-enable @gitlab/require-i18n-strings */
diff --git a/spec/contracts/consumer/package.json b/spec/contracts/consumer/package.json
index 6a427ff8a7b..6d3feaa6d4c 100644
--- a/spec/contracts/consumer/package.json
+++ b/spec/contracts/consumer/package.json
@@ -13,5 +13,14 @@
},
"scripts": {
"test": "jest --runInBand"
+ },
+ "jest": {
+ "transform": {
+ "^.+\\.[t|j]sx?$": "babel-jest"
+ }
+ },
+ "devDependencies": {
+ "@babel/preset-env": "^7.18.2",
+ "babel-jest": "^28.1.1"
}
}
diff --git a/spec/contracts/consumer/specs/diffs.spec.js b/spec/contracts/consumer/specs/diffs.spec.js
index b812461cb69..6b1cefdbdbc 100644
--- a/spec/contracts/consumer/specs/diffs.spec.js
+++ b/spec/contracts/consumer/specs/diffs.spec.js
@@ -1,9 +1,9 @@
-'use strict';
+/* eslint-disable @gitlab/require-i18n-strings */
-const { pactWith } = require('jest-pact');
+import { pactWith } from 'jest-pact';
-const { Diffs } = require('../fixtures/diffs.fixture');
-const { getDiffs } = require('../endpoints/merge_requests');
+import { Diffs } from '../fixtures/diffs.fixture';
+import { getDiffs } from '../endpoints/merge_requests';
pactWith(
{
@@ -34,3 +34,4 @@ pactWith(
});
},
);
+/* eslint-enable @gitlab/require-i18n-strings */
diff --git a/spec/contracts/consumer/specs/discussions.spec.js b/spec/contracts/consumer/specs/discussions.spec.js
index 304c240f7d3..2a5d0ba6267 100644
--- a/spec/contracts/consumer/specs/discussions.spec.js
+++ b/spec/contracts/consumer/specs/discussions.spec.js
@@ -1,9 +1,9 @@
-'use strict';
+/* eslint-disable @gitlab/require-i18n-strings */
-const { pactWith } = require('jest-pact');
+import { pactWith } from 'jest-pact';
-const { Discussions } = require('../fixtures/discussions.fixture');
-const { getDiscussions } = require('../endpoints/merge_requests');
+import { Discussions } from '../fixtures/discussions.fixture';
+import { getDiscussions } from '../endpoints/merge_requests';
pactWith(
{
@@ -34,3 +34,4 @@ pactWith(
});
},
);
+/* eslint-enable @gitlab/require-i18n-strings */
diff --git a/spec/contracts/consumer/specs/metadata.spec.js b/spec/contracts/consumer/specs/metadata.spec.js
index c49d4c354b1..fc082cb6a46 100644
--- a/spec/contracts/consumer/specs/metadata.spec.js
+++ b/spec/contracts/consumer/specs/metadata.spec.js
@@ -1,9 +1,9 @@
-'use strict';
+/* eslint-disable @gitlab/require-i18n-strings */
-const { pactWith } = require('jest-pact');
+import { pactWith } from 'jest-pact';
-const { Metadata } = require('../fixtures/metadata.fixture');
-const { getMetadata } = require('../endpoints/merge_requests');
+import { Metadata } from '../fixtures/metadata.fixture';
+import { getMetadata } from '../endpoints/merge_requests';
pactWith(
{
@@ -34,3 +34,4 @@ pactWith(
});
},
);
+/* eslint-enable @gitlab/require-i18n-strings */
diff --git a/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js b/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js
index 6e4c66cb780..d77e8e3d04c 100644
--- a/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js
@@ -68,7 +68,7 @@ describe('IDE commit editor header', () => {
it('calls discardFileChanges if dialog result is confirmed', () => {
expect(store.dispatch).not.toHaveBeenCalled();
- findDiscardModal().vm.$emit('ok');
+ findDiscardModal().vm.$emit('primary');
expect(store.dispatch).toHaveBeenCalledWith('discardFileChanges', TEST_FILE_PATH);
});
diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js
index d7d46d0d415..de91e51924d 100644
--- a/spec/frontend/security_configuration/components/app_spec.js
+++ b/spec/frontend/security_configuration/components/app_spec.js
@@ -2,7 +2,6 @@ import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { GlTab, GlTabs, GlLink } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
-
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser';
import stubChildren from 'helpers/stub_children';
@@ -20,22 +19,14 @@ import {
LICENSE_COMPLIANCE_DESCRIPTION,
LICENSE_COMPLIANCE_HELP_PATH,
AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY,
- LICENSE_ULTIMATE,
- LICENSE_PREMIUM,
- LICENSE_FREE,
} from '~/security_configuration/components/constants';
import FeatureCard from '~/security_configuration/components/feature_card.vue';
import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import currentLicenseQuery from '~/security_configuration/graphql/current_license.query.graphql';
-import waitForPromises from 'helpers/wait_for_promises';
-
import UpgradeBanner from '~/security_configuration/components/upgrade_banner.vue';
import {
REPORT_TYPE_LICENSE_COMPLIANCE,
REPORT_TYPE_SAST,
} from '~/vue_shared/security_reports/constants';
-import { getCurrentLicensePlanResponse } from '../mock_data';
const upgradePath = '/upgrade';
const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath';
@@ -50,31 +41,16 @@ Vue.use(VueApollo);
describe('App component', () => {
let wrapper;
let userCalloutDismissSpy;
- let mockApollo;
- const createComponent = ({
- shouldShowCallout = true,
- licenseQueryResponse = LICENSE_ULTIMATE,
- ...propsData
- }) => {
+ const createComponent = ({ shouldShowCallout = true, ...propsData }) => {
userCalloutDismissSpy = jest.fn();
- mockApollo = createMockApollo([
- [
- currentLicenseQuery,
- jest
- .fn()
- .mockResolvedValue(
- licenseQueryResponse instanceof Error
- ? licenseQueryResponse
- : getCurrentLicensePlanResponse(licenseQueryResponse),
- ),
- ],
- ]);
-
wrapper = extendedWrapper(
mount(SecurityConfigurationApp, {
- propsData,
+ propsData: {
+ securityTrainingEnabled: true,
+ ...propsData,
+ },
provide: {
upgradePath,
autoDevopsHelpPagePath,
@@ -82,7 +58,6 @@ describe('App component', () => {
projectFullPath,
vulnerabilityTrainingDocsPath,
},
- apolloProvider: mockApollo,
stubs: {
...stubChildren(SecurityConfigurationApp),
GlLink: false,
@@ -157,7 +132,6 @@ describe('App component', () => {
afterEach(() => {
wrapper.destroy();
- mockApollo = null;
});
describe('basic structure', () => {
@@ -166,7 +140,6 @@ describe('App component', () => {
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock,
});
- await waitForPromises();
});
it('renders main-heading with correct text', () => {
@@ -469,47 +442,42 @@ describe('App component', () => {
});
describe('Vulnerability management', () => {
- beforeEach(async () => {
+ it('does not show tab if security training is disabled', () => {
createComponent({
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock,
+ securityTrainingEnabled: false,
});
- await waitForPromises();
- });
- it('renders TrainingProviderList component', () => {
- expect(findTrainingProviderList().exists()).toBe(true);
+ expect(findVulnerabilityManagementTab().exists()).toBe(false);
});
- it('renders security training description', () => {
- expect(findVulnerabilityManagementTab().text()).toContain(i18n.securityTrainingDescription);
- });
-
- it('renders link to help docs', () => {
- const trainingLink = findVulnerabilityManagementTab().findComponent(GlLink);
-
- expect(trainingLink.text()).toBe('Learn more about vulnerability training');
- expect(trainingLink.attributes('href')).toBe(vulnerabilityTrainingDocsPath);
- });
-
- it.each`
- licenseQueryResponse | display
- ${LICENSE_ULTIMATE} | ${true}
- ${LICENSE_PREMIUM} | ${false}
- ${LICENSE_FREE} | ${false}
- ${null} | ${true}
- ${new Error()} | ${true}
- `(
- 'displays $display for license $licenseQueryResponse',
- async ({ licenseQueryResponse, display }) => {
+ describe('security training enabled', () => {
+ beforeEach(async () => {
createComponent({
- licenseQueryResponse,
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock,
});
- await waitForPromises();
- expect(findVulnerabilityManagementTab().exists()).toBe(display);
- },
- );
+ });
+
+ it('shows the tab if security training is enabled', () => {
+ expect(findVulnerabilityManagementTab().exists()).toBe(true);
+ });
+
+ it('renders TrainingProviderList component', () => {
+ expect(findTrainingProviderList().exists()).toBe(true);
+ });
+
+ it('renders security training description', () => {
+ expect(findVulnerabilityManagementTab().text()).toContain(i18n.securityTrainingDescription);
+ });
+
+ it('renders link to help docs', () => {
+ const trainingLink = findVulnerabilityManagementTab().findComponent(GlLink);
+
+ expect(trainingLink.text()).toBe('Learn more about vulnerability training');
+ expect(trainingLink.attributes('href')).toBe(vulnerabilityTrainingDocsPath);
+ });
+ });
});
});
diff --git a/spec/frontend/security_configuration/mock_data.js b/spec/frontend/security_configuration/mock_data.js
index 94a36472a1d..18a480bf082 100644
--- a/spec/frontend/security_configuration/mock_data.js
+++ b/spec/frontend/security_configuration/mock_data.js
@@ -111,12 +111,3 @@ export const tempProviderLogos = {
svg: `<svg>${[testProviderName[1]]}</svg>`,
},
};
-
-export const getCurrentLicensePlanResponse = (plan) => ({
- data: {
- currentLicense: {
- id: 'gid://gitlab/License/1',
- plan,
- },
- },
-});
diff --git a/spec/frontend/sidebar/components/attention_requested_toggle_spec.js b/spec/frontend/sidebar/components/attention_requested_toggle_spec.js
index 959fa799eb7..58fa878a189 100644
--- a/spec/frontend/sidebar/components/attention_requested_toggle_spec.js
+++ b/spec/frontend/sidebar/components/attention_requested_toggle_spec.js
@@ -41,18 +41,18 @@ describe('Attention require toggle', () => {
);
it.each`
- attentionRequested | variant
- ${true} | ${'warning'}
- ${false} | ${'default'}
+ attentionRequested | selected
+ ${true} | ${true}
+ ${false} | ${false}
`(
- 'renders button with variant $variant when attention_requested is $attentionRequested',
- ({ attentionRequested, variant }) => {
+ 'renders button with as selected when $selected when attention_requested is $attentionRequested',
+ ({ attentionRequested, selected }) => {
factory({
type: 'reviewer',
user: { attention_requested: attentionRequested, can_update_merge_request: true },
});
- expect(findToggle().props('variant')).toBe(variant);
+ expect(findToggle().props('selected')).toBe(selected);
},
);
diff --git a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js
index 82526af7afa..01fbcb2154f 100644
--- a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js
@@ -42,8 +42,8 @@ describe('Merge Request Collapsible Extension', () => {
expect(wrapper.find('[data-testid="collapsed-header"]').text()).toBe('hello there');
});
- it('renders angle-right icon', () => {
- expect(findIcon().props('name')).toBe('angle-right');
+ it('renders chevron-lg-right icon', () => {
+ expect(findIcon().props('name')).toBe('chevron-lg-right');
});
describe('onClick', () => {
@@ -60,8 +60,8 @@ describe('Merge Request Collapsible Extension', () => {
expect(findTitle().text()).toBe('Collapse');
});
- it('renders angle-down icon', () => {
- expect(findIcon().props('name')).toBe('angle-down');
+ it('renders chevron-lg-down icon', () => {
+ expect(findIcon().props('name')).toBe('chevron-lg-down');
});
});
});
diff --git a/spec/helpers/form_helper_spec.rb b/spec/helpers/form_helper_spec.rb
index 25dfa2251c3..c9c8c6b13b6 100644
--- a/spec/helpers/form_helper_spec.rb
+++ b/spec/helpers/form_helper_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe FormHelper do
expect(helper.form_errors(model, pajamas_alert: true))
.to include(
- '<div class="gl-alert gl-alert-danger gl-alert-not-dismissible gl-mb-5" id="error_explanation" role="alert">'
+ '<div class="gl-alert gl-mb-5 gl-alert-danger gl-alert-not-dismissible" id="error_explanation" role="alert">'
)
end
diff --git a/spec/lib/gitlab/audit/unauthenticated_author_spec.rb b/spec/lib/gitlab/audit/unauthenticated_author_spec.rb
index 4e5c477fc2a..70716ee7f4c 100644
--- a/spec/lib/gitlab/audit/unauthenticated_author_spec.rb
+++ b/spec/lib/gitlab/audit/unauthenticated_author_spec.rb
@@ -13,5 +13,11 @@ RSpec.describe Gitlab::Audit::UnauthenticatedAuthor do
expect(described_class.new)
.to have_attributes(id: -1, name: 'An unauthenticated user')
end
+
+ describe '#impersonated?' do
+ it 'returns false' do
+ expect(described_class.new.impersonated?).to be(false)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/diff/rendered/notebook/diff_file_helper_spec.rb b/spec/lib/gitlab/diff/rendered/notebook/diff_file_helper_spec.rb
new file mode 100644
index 00000000000..4810d55b541
--- /dev/null
+++ b/spec/lib/gitlab/diff/rendered/notebook/diff_file_helper_spec.rb
@@ -0,0 +1,134 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+RSpec.describe Gitlab::Diff::Rendered::Notebook::DiffFileHelper do
+ let(:dummy) { Class.new { include Gitlab::Diff::Rendered::Notebook::DiffFileHelper }.new }
+
+ describe '#strip_diff_frontmatter' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { dummy.strip_diff_frontmatter(diff) }
+
+ where(:diff, :result) do
+ "FileLine1\nFileLine2\n@@ -1,76 +1,74 @@\nhello\n" | "@@ -1,76 +1,74 @@\nhello\n"
+ "" | nil
+ nil | nil
+ end
+
+ with_them do
+ it { is_expected.to eq(result) }
+ end
+ end
+
+ describe '#map_transformed_line_to_source' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { dummy.map_transformed_line_to_source(1, transformed_blocks) }
+
+ where(:case, :transformed_blocks, :result) do
+ 'if transformed diff is empty' | [] | 0
+ 'if the transformed line does not map to any in the original file' | [{ source_line: nil }] | 0
+ 'if the transformed line maps to a line in the source file' | [{ source_line: 2 }] | 3
+ end
+
+ with_them do
+ it { is_expected.to eq(result) }
+ end
+ end
+
+ describe '#map_diff_block_to_source_line' do
+ let(:file_added) { false }
+ let(:file_deleted) { false }
+ let(:old_positions) { [1] }
+ let(:new_positions) { [1] }
+ let(:lines) { old_positions.zip(new_positions).map { |old, new| Gitlab::Diff::Line.new("", "", 0, old, new) } }
+
+ subject { dummy.map_diff_block_to_source_line(lines, file_added, file_deleted)}
+
+ context 'only additions' do
+ let(:old_positions) { [1, 2, 2, 2] }
+ let(:new_positions) { [1, 2, 3, 4] }
+
+ it 'computes the removals correctly' do
+ expect(subject[0]).to eq({ 1 => 1, 2 => 4 })
+ end
+
+ it 'computes the additions correctly' do
+ expect(subject[1]).to eq({ 1 => 1, 2 => 2, 3 => 2, 4 => 2 })
+ end
+ end
+
+ context 'only additions' do
+ let(:old_positions) { [1, 2, 3, 4] }
+ let(:new_positions) { [1, 2, 2, 2] }
+
+ it 'computes the removals correctly' do
+ expect(subject[0]).to eq({ 1 => 1, 2 => 2, 3 => 2, 4 => 2 })
+ end
+
+ it 'computes the additions correctly' do
+ expect(subject[1]).to eq({ 1 => 1, 2 => 4 })
+ end
+ end
+
+ context 'with additions and removals' do
+ let(:old_positions) { [1, 2, 3, 4, 4, 4] }
+ let(:new_positions) { [1, 2, 2, 2, 3, 4] }
+
+ it 'computes the removals correctly' do
+ expect(subject[0]).to eq({ 1 => 1, 2 => 2, 3 => 2, 4 => 4 })
+ end
+
+ it 'computes the additions correctly' do
+ expect(subject[1]).to eq({ 1 => 1, 2 => 4, 3 => 4, 4 => 4 })
+ end
+ end
+
+ context 'is new file' do
+ let(:file_added) { true }
+
+ it 'removals is empty' do
+ expect(subject[0]).to be_empty
+ end
+ end
+
+ context 'is deleted file' do
+ let(:file_deleted) { true }
+
+ it 'additions is empty' do
+ expect(subject[1]).to be_empty
+ end
+ end
+ end
+
+ describe '#image_as_rich_text' do
+ let(:img) { 'data:image/png;base64,some_image_here' }
+ let(:line_text) { " ![](#{img})"}
+
+ subject { dummy.image_as_rich_text(line_text) }
+
+ context 'text does not contain image' do
+ let(:img) { "not an image" }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'text contains image' do
+ it { is_expected.to eq("<img src=\"#{img}\">") }
+ end
+
+ context 'text contains image that has malicious html' do
+ let(:img) { 'data:image/png;base64,some_image_here"<div>Hello</div>' }
+
+ it 'sanitizes the html' do
+ expect(subject).not_to include('<div>Hello')
+ end
+
+ it 'adds image to src' do
+ expect(subject).to end_with('/div&gt;">')
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb
index ac1d1f5d74d..b7da9b27e19 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb
@@ -4,15 +4,30 @@ require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountImportedProjectsMetric do
let_it_be(:user) { create(:user) }
- let_it_be(:gitea_imports) do
- create_list(:project, 3, import_type: 'gitea', creator_id: user.id, created_at: 3.weeks.ago)
+
+ # Project records have to be created chronologically, because of
+ # metric SQL query optimizations that rely on the fact that `id`s
+ # increment monotonically over time.
+ #
+ # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89701
+ let_it_be(:old_import) { create(:project, import_type: 'gitea', creator_id: user.id, created_at: 2.months.ago) }
+ let_it_be(:gitea_import_1) { create(:project, import_type: 'gitea', creator_id: user.id, created_at: 21.days.ago) }
+
+ let_it_be(:gitea_import_2) do
+ create(:project, import_type: 'gitea', creator_id: user.id, created_at: 20.days.ago)
end
- let_it_be(:bitbucket_imports) do
- create_list(:project, 2, import_type: 'bitbucket', creator_id: user.id, created_at: 3.weeks.ago)
+ let_it_be(:gitea_import_3) do
+ create(:project, import_type: 'gitea', creator_id: user.id, created_at: 19.days.ago)
end
- let_it_be(:old_import) { create(:project, import_type: 'gitea', creator_id: user.id, created_at: 2.months.ago) }
+ let_it_be(:bitbucket_import_1) do
+ create(:project, import_type: 'bitbucket', creator_id: user.id, created_at: 2.weeks.ago)
+ end
+
+ let_it_be(:bitbucket_import_2) do
+ create(:project, import_type: 'bitbucket', creator_id: user.id, created_at: 1.week.ago)
+ end
context 'with import_type gitea' do
context 'with all time frame' do
@@ -53,7 +68,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountImportedProjectsMe
options: { import_type: 'bitbucket' }
end
- context 'for 28d time frame', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/362591' do
+ context 'for 28d time frame' do
let(:expected_value) { 2 }
let(:start) { 30.days.ago.to_s(:db) }
let(:finish) { 2.days.ago.to_s(:db) }
diff --git a/spec/models/concerns/as_cte_spec.rb b/spec/models/concerns/as_cte_spec.rb
index c92d46ef25f..06d9650ec46 100644
--- a/spec/models/concerns/as_cte_spec.rb
+++ b/spec/models/concerns/as_cte_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe AsCte do
it { expect(subject.query).to eq(query) }
it { expect(subject.table.name).to eq(name.to_s) }
- context 'with materialized parameter' do
+ context 'with materialized parameter', if: Gitlab::Database::AsWithMaterialized.materialized_supported? do
subject { query.as_cte(name, materialized: materialized).to_arel.to_sql }
context 'as true' do
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index 91008dd57e7..44646b02df0 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -407,17 +407,32 @@ RSpec.describe 'Query.runner(id)' do
<<~SINGLE
runner(id: "#{runner.to_global_id}") {
#{all_graphql_fields_for('CiRunner', excluded: excluded_fields)}
+ groups {
+ nodes {
+ id
+ }
+ }
+ projects {
+ nodes {
+ id
+ }
+ }
}
SINGLE
end
+ let(:active_project_runner2) { create(:ci_runner, :project) }
+ let(:active_group_runner2) { create(:ci_runner, :group) }
+
# Currently excluding a known N+1 issue, see https://gitlab.com/gitlab-org/gitlab/-/issues/334759
- let(:excluded_fields) { %w[jobCount] }
+ let(:excluded_fields) { %w[jobCount groups projects] }
let(:single_query) do
<<~QUERY
{
- active: #{runner_query(active_instance_runner)}
+ instance_runner1: #{runner_query(active_instance_runner)}
+ project_runner1: #{runner_query(active_project_runner)}
+ group_runner1: #{runner_query(active_group_runner)}
}
QUERY
end
@@ -425,22 +440,49 @@ RSpec.describe 'Query.runner(id)' do
let(:double_query) do
<<~QUERY
{
- active: #{runner_query(active_instance_runner)}
- inactive: #{runner_query(inactive_instance_runner)}
+ instance_runner1: #{runner_query(active_instance_runner)}
+ instance_runner2: #{runner_query(inactive_instance_runner)}
+ group_runner1: #{runner_query(active_group_runner)}
+ group_runner2: #{runner_query(active_group_runner2)}
+ project_runner1: #{runner_query(active_project_runner)}
+ project_runner2: #{runner_query(active_project_runner2)}
}
QUERY
end
it 'does not execute more queries per runner', :aggregate_failures do
# warm-up license cache and so on:
- post_graphql(single_query, current_user: user)
+ post_graphql(double_query, current_user: user)
control = ActiveRecord::QueryRecorder.new { post_graphql(single_query, current_user: user) }
expect { post_graphql(double_query, current_user: user) }
.not_to exceed_query_limit(control)
- expect(graphql_data_at(:active)).not_to be_nil
- expect(graphql_data_at(:inactive)).not_to be_nil
+
+ expect(graphql_data.count).to eq 6
+ expect(graphql_data).to match(
+ a_hash_including(
+ 'instance_runner1' => a_hash_including('id' => active_instance_runner.to_global_id.to_s),
+ 'instance_runner2' => a_hash_including('id' => inactive_instance_runner.to_global_id.to_s),
+ 'group_runner1' => a_hash_including(
+ 'id' => active_group_runner.to_global_id.to_s,
+ 'groups' => { 'nodes' => [a_hash_including('id' => group.to_global_id.to_s)] }
+ ),
+ 'group_runner2' => a_hash_including(
+ 'id' => active_group_runner2.to_global_id.to_s,
+ 'groups' => { 'nodes' => [a_hash_including('id' => active_group_runner2.groups[0].to_global_id.to_s)] }
+ ),
+ 'project_runner1' => a_hash_including(
+ 'id' => active_project_runner.to_global_id.to_s,
+ 'projects' => { 'nodes' => [a_hash_including('id' => active_project_runner.projects[0].to_global_id.to_s)] }
+ ),
+ 'project_runner2' => a_hash_including(
+ 'id' => active_project_runner2.to_global_id.to_s,
+ 'projects' => {
+ 'nodes' => [a_hash_including('id' => active_project_runner2.projects[0].to_global_id.to_s)]
+ }
+ )
+ ))
end
end
end
diff --git a/spec/requests/api/release/links_spec.rb b/spec/requests/api/release/links_spec.rb
index 00326426af5..2345c0063dd 100644
--- a/spec/requests/api/release/links_spec.rb
+++ b/spec/requests/api/release/links_spec.rb
@@ -49,6 +49,20 @@ RSpec.describe API::Release::Links do
expect(response).to match_response_schema('release/links')
end
+
+ context 'when using JOB-TOKEN auth' do
+ let(:job) { create(:ci_build, :running, user: maintainer) }
+
+ it 'returns releases links' do
+ get api("/projects/#{project.id}/releases/v0.1/assets/links", job_token: job.token)
+
+ aggregate_failures "testing response" do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('release/links')
+ expect(json_response.count).to eq(2)
+ end
+ end
+ end
end
context 'when release does not exist' do
@@ -116,6 +130,20 @@ RSpec.describe API::Release::Links do
expect(response).to match_response_schema('release/link')
end
+ context 'when using JOB-TOKEN auth' do
+ let(:job) { create(:ci_build, :running, user: maintainer) }
+
+ it 'returns releases link' do
+ get api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", job_token: job.token)
+
+ aggregate_failures "testing response" do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('release/link')
+ expect(json_response['name']).to eq(release_link.name)
+ end
+ end
+ end
+
context 'when specified tag is not found in the project' do
it_behaves_like '404 response' do
let(:request) { get api("/projects/#{project.id}/releases/non_existing_tag/assets/links/#{release_link.id}", maintainer) }
@@ -198,6 +226,25 @@ RSpec.describe API::Release::Links do
expect(response).to match_response_schema('release/link')
end
+ context 'when using JOB-TOKEN auth' do
+ let(:job) { create(:ci_build, :running, user: maintainer) }
+
+ it 'creates a new release link' do
+ expect do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links"), params: params.merge(job_token: job.token)
+ end.to change { Releases::Link.count }.by(1)
+
+ release.reload
+
+ aggregate_failures "testing response" do
+ expect(response).to have_gitlab_http_status(:created)
+ expect(last_release_link.name).to eq('awesome-app.dmg')
+ expect(last_release_link.filepath).to eq('/binaries/awesome-app.dmg')
+ expect(last_release_link.url).to eq('https://example.com/download/awesome-app.dmg')
+ end
+ end
+ end
+
context 'with protected tag' do
context 'when user has access to the protected tag' do
let!(:protected_tag) { create(:protected_tag, :developers_can_create, name: '*', project: project) }
@@ -314,6 +361,20 @@ RSpec.describe API::Release::Links do
expect(response).to match_response_schema('release/link')
end
+ context 'when using JOB-TOKEN auth' do
+ let(:job) { create(:ci_build, :running, user: maintainer) }
+
+ it 'updates the release link' do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}"), params: params.merge(job_token: job.token)
+
+ aggregate_failures "testing response" do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('release/link')
+ expect(json_response['name']).to eq('awesome-app.msi')
+ end
+ end
+ end
+
context 'with protected tag' do
context 'when user has access to the protected tag' do
let!(:protected_tag) { create(:protected_tag, :developers_can_create, name: '*', project: project) }
@@ -411,6 +472,21 @@ RSpec.describe API::Release::Links do
expect(response).to match_response_schema('release/link')
end
+ context 'when using JOB-TOKEN auth' do
+ let(:job) { create(:ci_build, :running, user: maintainer) }
+
+ it 'deletes the release link' do
+ expect do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", job_token: job.token)
+ end.to change { Releases::Link.count }.by(-1)
+
+ aggregate_failures "testing response" do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('release/link')
+ end
+ end
+ end
+
context 'with protected tag' do
context 'when user has access to the protected tag' do
let!(:protected_tag) { create(:protected_tag, :developers_can_create, name: '*', project: project) }