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-03-17 18:07:44 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-03-17 18:07:44 +0300
commit6c41e447edac3453ae0df99fb9232ec71b679b75 (patch)
tree125416ba49222f7c0deb44950e451e39d45c433b /spec
parent77ee26b43bda4b092f356d5185f424bad232af36 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/concerns/product_analytics_tracking_spec.rb171
-rw-r--r--spec/controllers/jira_connect/events_controller_spec.rb54
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_conflicts_spec.js4
-rw-r--r--spec/frontend/vue_mr_widget/extentions/code_quality/index_spec.js145
-rw-r--r--spec/frontend/vue_mr_widget/extentions/code_quality/mock_data.js87
-rw-r--r--spec/models/project_spec.rb32
6 files changed, 450 insertions, 43 deletions
diff --git a/spec/controllers/concerns/product_analytics_tracking_spec.rb b/spec/controllers/concerns/product_analytics_tracking_spec.rb
new file mode 100644
index 00000000000..250cc3cf2cf
--- /dev/null
+++ b/spec/controllers/concerns/product_analytics_tracking_spec.rb
@@ -0,0 +1,171 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe ProductAnalyticsTracking, :snowplow do
+ include TrackingHelpers
+ include SnowplowHelpers
+
+ let(:user) { create(:user) }
+ let!(:group) { create(:group) }
+
+ before do
+ allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event)
+ end
+
+ controller(ApplicationController) do
+ include ProductAnalyticsTracking
+
+ skip_before_action :authenticate_user!, only: :show
+ track_event(:index, :show, name: 'g_analytics_valuestream', destinations: [:redis_hll, :snowplow],
+ conditions: [:custom_condition_one?, :custom_condition_two?]) { |controller| controller.get_custom_id }
+
+ def index
+ render html: 'index'
+ end
+
+ def new
+ render html: 'new'
+ end
+
+ def show
+ render html: 'show'
+ end
+
+ def get_custom_id
+ 'some_custom_id'
+ end
+
+ private
+
+ def tracking_namespace_source
+ Group.first
+ end
+
+ def custom_condition_one?
+ true
+ end
+
+ def custom_condition_two?
+ true
+ end
+ end
+
+ def expect_tracking(user: self.user)
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).to have_received(:track_event)
+ .with('g_analytics_valuestream', values: instance_of(String))
+
+ expect_snowplow_event(
+ category: anything,
+ action: 'g_analytics_valuestream',
+ namespace: group,
+ user: user
+ )
+ end
+
+ def expect_no_tracking
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+
+ expect_no_snowplow_event
+ end
+
+ context 'when user is logged in' do
+ before do
+ sign_in(user)
+ end
+
+ it 'tracks the event' do
+ get :index
+
+ expect_tracking
+ end
+
+ context 'when FF is disabled' do
+ before do
+ stub_feature_flags(route_hll_to_snowplow: false)
+ end
+
+ it 'doesnt track snowplow event' do
+ get :index
+
+ expect_no_snowplow_event
+ end
+ end
+
+ it 'tracks the event if DNT is not enabled' do
+ stub_do_not_track('0')
+
+ get :index
+
+ expect_tracking
+ end
+
+ it 'does not track the event if DNT is enabled' do
+ stub_do_not_track('1')
+
+ get :index
+
+ expect_no_tracking
+ end
+
+ it 'does not track the event if the format is not HTML' do
+ get :index, format: :json
+
+ expect_no_tracking
+ end
+
+ it 'does not track the event if a custom condition returns false' do
+ allow(controller).to receive(:custom_condition_two?).and_return(false)
+
+ get :index
+
+ expect_no_tracking
+ end
+
+ it 'does not track the event for untracked actions' do
+ get :new
+
+ expect_no_tracking
+ end
+ end
+
+ context 'when user is not logged in' do
+ let(:visitor_id) { SecureRandom.uuid }
+
+ it 'tracks the event when there is a visitor id' do
+ cookies[:visitor_id] = { value: visitor_id, expires: 24.months }
+
+ get :show, params: { id: 1 }
+
+ expect_tracking(user: nil)
+ end
+ end
+
+ context 'when user is not logged in and there is no visitor_id' do
+ it 'does not track the event' do
+ get :index
+
+ expect_no_tracking
+ end
+
+ it 'tracks the event when there is custom id' do
+ get :show, params: { id: 1 }
+
+ expect_tracking(user: nil)
+ end
+
+ it 'does not track the HLL event when there is no custom id' do
+ allow(controller).to receive(:get_custom_id).and_return(nil)
+
+ get :show, params: { id: 2 }
+
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+ expect_snowplow_event(
+ category: anything,
+ action: 'g_analytics_valuestream',
+ namespace: group,
+ user: nil
+ )
+ end
+ end
+end
diff --git a/spec/controllers/jira_connect/events_controller_spec.rb b/spec/controllers/jira_connect/events_controller_spec.rb
index 2a70a2ea683..2129b24b2fb 100644
--- a/spec/controllers/jira_connect/events_controller_spec.rb
+++ b/spec/controllers/jira_connect/events_controller_spec.rb
@@ -43,14 +43,15 @@ RSpec.describe JiraConnect::EventsController do
end
describe '#installed' do
- let(:client_key) { '1234' }
- let(:shared_secret) { 'secret' }
+ let_it_be(:client_key) { '1234' }
+ let_it_be(:shared_secret) { 'secret' }
+ let_it_be(:base_url) { 'https://test.atlassian.net' }
let(:params) do
{
clientKey: client_key,
sharedSecret: shared_secret,
- baseUrl: 'https://test.atlassian.net'
+ baseUrl: base_url
}
end
@@ -77,11 +78,11 @@ RSpec.describe JiraConnect::EventsController do
expect(installation.base_url).to eq('https://test.atlassian.net')
end
- context 'when it is a version update and shared_secret is not sent' do
+ context 'when the shared_secret param is missing' do
let(:params) do
{
clientKey: client_key,
- baseUrl: 'https://test.atlassian.net'
+ baseUrl: base_url
}
end
@@ -90,13 +91,48 @@ RSpec.describe JiraConnect::EventsController do
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
+ end
+
+ context 'when an installation already exists' do
+ let_it_be(:installation) { create(:jira_connect_installation, base_url: base_url, client_key: client_key, shared_secret: shared_secret) }
+
+ it 'validates the JWT token in authorization header and returns 200 without creating a new installation', :aggregate_failures do
+ expect { subject }.not_to change { JiraConnectInstallation.count }
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ context 'when parameters include a new shared secret and base_url' do
+ let(:shared_secret) { 'new_secret' }
+ let(:base_url) { 'https://new_test.atlassian.net' }
- context 'and an installation exists' do
- let!(:installation) { create(:jira_connect_installation, client_key: client_key, shared_secret: shared_secret) }
+ it 'updates the installation', :aggregate_failures do
+ subject
- it 'validates the JWT token in authorization header and returns 200 without creating a new installation' do
- expect { subject }.not_to change { JiraConnectInstallation.count }
expect(response).to have_gitlab_http_status(:ok)
+ expect(installation.reload).to have_attributes(
+ shared_secret: shared_secret,
+ base_url: base_url
+ )
+ end
+
+ context 'when the `jira_connect_installation_update` feature flag is disabled' do
+ before do
+ stub_feature_flags(jira_connect_installation_update: false)
+ end
+
+ it 'does not update the installation', :aggregate_failures do
+ expect { subject }.not_to change { installation.reload.attributes }
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+
+ context 'when the new base_url is invalid' do
+ let(:base_url) { 'invalid' }
+
+ it 'renders 422', :aggregate_failures do
+ expect { subject }.not_to change { installation.reload.base_url }
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
end
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 bdc38eb0b22..7a92484695c 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
@@ -224,8 +224,8 @@ describe('MRWidgetConflicts', () => {
});
});
- it('should not allow you to resolve the conflicts', () => {
- expect(findResolveButton().exists()).toBe(false);
+ it('should allow you to resolve the conflicts', () => {
+ expect(findResolveButton().exists()).toBe(true);
});
});
diff --git a/spec/frontend/vue_mr_widget/extentions/code_quality/index_spec.js b/spec/frontend/vue_mr_widget/extentions/code_quality/index_spec.js
new file mode 100644
index 00000000000..9a72e4a086b
--- /dev/null
+++ b/spec/frontend/vue_mr_widget/extentions/code_quality/index_spec.js
@@ -0,0 +1,145 @@
+import MockAdapter from 'axios-mock-adapter';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { trimText } from 'helpers/text_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import axios from '~/lib/utils/axios_utils';
+import extensionsContainer from '~/vue_merge_request_widget/components/extensions/container';
+import { registerExtension } from '~/vue_merge_request_widget/components/extensions';
+import codeQualityExtension from '~/vue_merge_request_widget/extensions/code_quality';
+import httpStatusCodes from '~/lib/utils/http_status';
+import {
+ codeQualityResponseNewErrors,
+ codeQualityResponseResolvedErrors,
+ codeQualityResponseResolvedAndNewErrors,
+ codeQualityResponseNoErrors,
+} from './mock_data';
+
+describe('Code Quality extension', () => {
+ let wrapper;
+ let mock;
+
+ registerExtension(codeQualityExtension);
+
+ const endpoint = '/root/repo/-/merge_requests/4/accessibility_reports.json';
+
+ const mockApi = (statusCode, data) => {
+ mock.onGet(endpoint).reply(statusCode, data);
+ };
+
+ const findToggleCollapsedButton = () => wrapper.findByTestId('toggle-button');
+ const findAllExtensionListItems = () => wrapper.findAllByTestId('extension-list-item');
+
+ const createComponent = () => {
+ wrapper = mountExtended(extensionsContainer, {
+ propsData: {
+ mr: {
+ codeQuality: endpoint,
+ blobPath: {
+ head_path: 'example/path',
+ base_path: 'example/path',
+ },
+ },
+ },
+ });
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ mock.restore();
+ });
+
+ describe('summary', () => {
+ it('displays loading text', () => {
+ mockApi(httpStatusCodes.OK, codeQualityResponseNewErrors);
+
+ createComponent();
+
+ expect(wrapper.text()).toBe('Code Quality test metrics results are being parsed');
+ });
+
+ it('displays failed loading text', async () => {
+ mockApi(httpStatusCodes.INTERNAL_SERVER_ERROR);
+
+ createComponent();
+
+ await waitForPromises();
+ expect(wrapper.text()).toBe('Code Quality failed loading results');
+ });
+
+ it('displays quality degradation', async () => {
+ mockApi(httpStatusCodes.OK, codeQualityResponseNewErrors);
+
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.text()).toBe('Code Quality degraded on 2 points.');
+ });
+
+ it('displays quality improvement', async () => {
+ mockApi(httpStatusCodes.OK, codeQualityResponseResolvedErrors);
+
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.text()).toBe('Code Quality improved on 2 points.');
+ });
+
+ it('displays quality improvement and degradation', async () => {
+ mockApi(httpStatusCodes.OK, codeQualityResponseResolvedAndNewErrors);
+
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.text()).toBe('Code Quality improved on 1 point and degraded on 1 point.');
+ });
+
+ it('displays no detected errors', async () => {
+ mockApi(httpStatusCodes.OK, codeQualityResponseNoErrors);
+
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.text()).toBe('No changes to Code Quality.');
+ });
+ });
+
+ describe('expanded data', () => {
+ beforeEach(async () => {
+ mockApi(httpStatusCodes.OK, codeQualityResponseResolvedAndNewErrors);
+
+ createComponent();
+
+ await waitForPromises();
+
+ findToggleCollapsedButton().trigger('click');
+
+ await waitForPromises();
+ });
+
+ it('displays all report list items in viewport', async () => {
+ expect(findAllExtensionListItems()).toHaveLength(2);
+ });
+
+ it('displays report list item formatted', () => {
+ const text = {
+ newError: trimText(findAllExtensionListItems().at(0).text().replace(/\s+/g, ' ').trim()),
+ resolvedError: findAllExtensionListItems().at(1).text().replace(/\s+/g, ' ').trim(),
+ };
+
+ expect(text.newError).toContain(
+ "Minor - Parsing error: 'return' outside of function in index.js:12",
+ );
+ expect(text.resolvedError).toContain(
+ "Minor - Parsing error: 'return' outside of function in index.js:12",
+ );
+ });
+ });
+});
diff --git a/spec/frontend/vue_mr_widget/extentions/code_quality/mock_data.js b/spec/frontend/vue_mr_widget/extentions/code_quality/mock_data.js
new file mode 100644
index 00000000000..f5ad0ce7377
--- /dev/null
+++ b/spec/frontend/vue_mr_widget/extentions/code_quality/mock_data.js
@@ -0,0 +1,87 @@
+export const codeQualityResponseNewErrors = {
+ status: 'failed',
+ new_errors: [
+ {
+ description: "Parsing error: 'return' outside of function",
+ severity: 'minor',
+ file_path: 'index.js',
+ line: 12,
+ },
+ {
+ description: 'TODO found',
+ severity: 'minor',
+ file_path: '.gitlab-ci.yml',
+ line: 73,
+ },
+ ],
+ resolved_errors: [],
+ existing_errors: [],
+ summary: {
+ total: 2,
+ resolved: 0,
+ errored: 2,
+ },
+};
+
+export const codeQualityResponseResolvedErrors = {
+ status: 'failed',
+ new_errors: [],
+ resolved_errors: [
+ {
+ description: "Parsing error: 'return' outside of function",
+ severity: 'minor',
+ file_path: 'index.js',
+ line: 12,
+ },
+ {
+ description: 'TODO found',
+ severity: 'minor',
+ file_path: '.gitlab-ci.yml',
+ line: 73,
+ },
+ ],
+ existing_errors: [],
+ summary: {
+ total: 2,
+ resolved: 2,
+ errored: 0,
+ },
+};
+
+export const codeQualityResponseResolvedAndNewErrors = {
+ status: 'failed',
+ new_errors: [
+ {
+ description: "Parsing error: 'return' outside of function",
+ severity: 'minor',
+ file_path: 'index.js',
+ line: 12,
+ },
+ ],
+ resolved_errors: [
+ {
+ description: "Parsing error: 'return' outside of function",
+ severity: 'minor',
+ file_path: 'index.js',
+ line: 12,
+ },
+ ],
+ existing_errors: [],
+ summary: {
+ total: 2,
+ resolved: 1,
+ errored: 1,
+ },
+};
+
+export const codeQualityResponseNoErrors = {
+ status: 'failed',
+ new_errors: [],
+ resolved_errors: [],
+ existing_errors: [],
+ summary: {
+ total: 0,
+ resolved: 0,
+ errored: 0,
+ },
+};
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 21d12ce2856..fc7ac35ed41 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -631,38 +631,6 @@ RSpec.describe Project, factory_default: :keep do
expect(project).not_to be_valid
end
-
- context 'restrict_special_characters_in_project_path feature flag is disabled' do
- before do
- stub_feature_flags(restrict_special_characters_in_project_path: false)
- end
-
- it "allows a path ending in '#{special_character}'" do
- project = build(:project, path: "foo#{special_character}")
-
- expect(project).to be_valid
- end
- end
- end
-
- context 'restrict_special_characters_in_project_path feature flag is disabled' do
- before do
- stub_feature_flags(restrict_special_characters_in_project_path: false)
- end
-
- %w[. _].each do |special_character|
- it "allows a path starting with '#{special_character}'" do
- project = build(:project, path: "#{special_character}foo")
-
- expect(project).to be_valid
- end
- end
-
- it "rejects a path starting with '-'" do
- project = build(:project, path: "-foo")
-
- expect(project).not_to be_valid
- end
end
end
end