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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-02-23 00:07:43 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-23 00:07:43 +0300
commitf19ffffacda2d7f415f682f6e50e3cf06182e15e (patch)
treeb8a78ba727ab2ef38808c028401842e7370948b0 /spec
parentd0f16d56f3716d4a60027eb261f12080094f8db3 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/projects.rb12
-rw-r--r--spec/frontend/fixtures/jobs.rb22
-rw-r--r--spec/frontend/ide/stores/modules/commit/actions_spec.js66
-rw-r--r--spec/frontend/jobs/components/table/graphql/cache_config_spec.js19
-rw-r--r--spec/frontend/jobs/components/table/job_table_app_spec.js45
-rw-r--r--spec/frontend/jobs/mock_data.js2
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js93
-rw-r--r--spec/helpers/broadcast_messages_helper_spec.rb29
-rw-r--r--spec/helpers/ide_helper_spec.rb163
-rw-r--r--spec/lib/bulk_imports/clients/http_spec.rb31
-rw-r--r--spec/models/onboarding/completion_spec.rb65
-rw-r--r--spec/requests/ide_controller_spec.rb22
12 files changed, 469 insertions, 100 deletions
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index f113ca2425f..dde2848c36c 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -354,6 +354,18 @@ FactoryBot.define do
end
end
+ trait :stubbed_commit_count do
+ after(:build) do |project|
+ stub_method(project.repository, :commit_count) { 2 }
+ end
+ end
+
+ trait :stubbed_branch_count do
+ after(:build) do |project|
+ stub_method(project.repository, :branch_count) { 2 }
+ end
+ end
+
trait :wiki_repo do
after(:create) do |project|
stub_feature_flags(main_branch_over_master: false)
diff --git a/spec/frontend/fixtures/jobs.rb b/spec/frontend/fixtures/jobs.rb
index 6d452bf1bff..3583beb83c2 100644
--- a/spec/frontend/fixtures/jobs.rb
+++ b/spec/frontend/fixtures/jobs.rb
@@ -93,4 +93,26 @@ RSpec.describe 'Jobs (JavaScript fixtures)' do
expect_graphql_errors_to_be_empty
end
end
+
+ describe 'get_jobs_count.query.graphql', type: :request do
+ let!(:build) { create(:ci_build, :success, name: 'build', pipeline: pipeline) }
+ let!(:cancelable) { create(:ci_build, :cancelable, name: 'cancelable', pipeline: pipeline) }
+ let!(:failed) { create(:ci_build, :failed, name: 'failed', pipeline: pipeline) }
+
+ fixtures_path = 'graphql/jobs/'
+ get_jobs_count_query = 'get_jobs_count.query.graphql'
+ full_path = 'frontend-fixtures/builds-project'
+
+ let_it_be(:query) do
+ get_graphql_query_as_string("jobs/components/table/graphql/queries/#{get_jobs_count_query}")
+ end
+
+ it "#{fixtures_path}#{get_jobs_count_query}.json" do
+ post_graphql(query, current_user: user, variables: {
+ fullPath: full_path
+ })
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
end
diff --git a/spec/frontend/ide/stores/modules/commit/actions_spec.js b/spec/frontend/ide/stores/modules/commit/actions_spec.js
index 4068a9d0919..685935954bd 100644
--- a/spec/frontend/ide/stores/modules/commit/actions_spec.js
+++ b/spec/frontend/ide/stores/modules/commit/actions_spec.js
@@ -1,6 +1,7 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { file } from 'jest/ide/helpers';
import { commitActionTypes, PERMISSION_CREATE_MR } from '~/ide/constants';
import eventHub from '~/ide/eventhub';
@@ -39,12 +40,14 @@ describe('IDE commit module actions', () => {
let mock;
let store;
let router;
+ let trackingSpy;
beforeEach(() => {
store = createStore();
router = createRouter(store);
gon.api_version = 'v1';
mock = new MockAdapter(axios);
+ trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
jest.spyOn(router, 'push').mockImplementation();
mock
@@ -53,6 +56,7 @@ describe('IDE commit module actions', () => {
});
afterEach(() => {
+ unmockTracking();
delete gon.api_version;
mock.restore();
});
@@ -430,6 +434,28 @@ describe('IDE commit module actions', () => {
});
});
});
+
+ describe('learnGitlabSource', () => {
+ describe('learnGitlabSource is true', () => {
+ it('tracks commit', async () => {
+ store.state.learnGitlabSource = true;
+
+ await store.dispatch('commit/commitChanges');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'commit', {
+ label: 'web_ide_learn_gitlab_source',
+ });
+ });
+ });
+
+ describe('learnGitlabSource is false', () => {
+ it('does not track commit', async () => {
+ await store.dispatch('commit/commitChanges');
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+ });
});
describe('success response with failed message', () => {
@@ -447,6 +473,26 @@ describe('IDE commit module actions', () => {
expect(alert.textContent.trim()).toBe('failed message');
});
+
+ describe('learnGitlabSource', () => {
+ describe('learnGitlabSource is true', () => {
+ it('does not track commit', async () => {
+ store.state.learnGitlabSource = true;
+
+ await store.dispatch('commit/commitChanges');
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('learnGitlabSource is false', () => {
+ it('does not track commit', async () => {
+ await store.dispatch('commit/commitChanges');
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+ });
});
describe('failed response', () => {
@@ -466,6 +512,26 @@ describe('IDE commit module actions', () => {
['commit/SET_ERROR', createUnexpectedCommitError(), undefined],
]);
});
+
+ describe('learnGitlabSource', () => {
+ describe('learnGitlabSource is true', () => {
+ it('does not track commit', async () => {
+ store.state.learnGitlabSource = true;
+
+ await store.dispatch('commit/commitChanges').catch(() => {});
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('learnGitlabSource is false', () => {
+ it('does not track commit', async () => {
+ await store.dispatch('commit/commitChanges').catch(() => {});
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+ });
});
describe('first commit of a branch', () => {
diff --git a/spec/frontend/jobs/components/table/graphql/cache_config_spec.js b/spec/frontend/jobs/components/table/graphql/cache_config_spec.js
index 88c97285b85..e3b1ca1cce3 100644
--- a/spec/frontend/jobs/components/table/graphql/cache_config_spec.js
+++ b/spec/frontend/jobs/components/table/graphql/cache_config_spec.js
@@ -84,4 +84,23 @@ describe('jobs/components/table/graphql/cache_config', () => {
expect(res.nodes).toHaveLength(CIJobConnectionIncomingCacheRunningStatus.nodes.length);
});
});
+
+ describe('when incoming data has no nodes', () => {
+ it('should return existing cache', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge(
+ CIJobConnectionExistingCache,
+ { __typename: 'CiJobConnection', count: 500 },
+ {
+ args: { statuses: 'SUCCESS' },
+ },
+ );
+
+ const expectedResponse = {
+ ...CIJobConnectionExistingCache,
+ statuses: 'SUCCESS',
+ };
+
+ expect(res).toEqual(expectedResponse);
+ });
+ });
});
diff --git a/spec/frontend/jobs/components/table/job_table_app_spec.js b/spec/frontend/jobs/components/table/job_table_app_spec.js
index 109cef6f817..b14a3bae54f 100644
--- a/spec/frontend/jobs/components/table/job_table_app_spec.js
+++ b/spec/frontend/jobs/components/table/job_table_app_spec.js
@@ -14,6 +14,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import { TEST_HOST } from 'spec/test_constants';
import { createAlert } from '~/flash';
import getJobsQuery from '~/jobs/components/table/graphql/queries/get_jobs.query.graphql';
+import getJobsCountQuery from '~/jobs/components/table/graphql/queries/get_jobs_count.query.graphql';
import JobsTable from '~/jobs/components/table/jobs_table.vue';
import JobsTableApp from '~/jobs/components/table/jobs_table_app.vue';
import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
@@ -23,6 +24,7 @@ import {
mockJobsResponsePaginated,
mockJobsResponseEmpty,
mockFailedSearchToken,
+ mockJobsCountResponse,
} from '../../mock_data';
const projectPath = 'gitlab-org/gitlab';
@@ -37,6 +39,8 @@ describe('Job table app', () => {
const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
const emptyHandler = jest.fn().mockResolvedValue(mockJobsResponseEmpty);
+ const countSuccessHandler = jest.fn().mockResolvedValue(mockJobsCountResponse);
+
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
const findTable = () => wrapper.findComponent(JobsTable);
@@ -48,14 +52,18 @@ describe('Job table app', () => {
const triggerInfiniteScroll = () =>
wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
- const createMockApolloProvider = (handler) => {
- const requestHandlers = [[getJobsQuery, handler]];
+ const createMockApolloProvider = (handler, countHandler) => {
+ const requestHandlers = [
+ [getJobsQuery, handler],
+ [getJobsCountQuery, countHandler],
+ ];
return createMockApollo(requestHandlers);
};
const createComponent = ({
handler = successHandler,
+ countHandler = countSuccessHandler,
mountFn = shallowMount,
data = {},
} = {}) => {
@@ -68,7 +76,7 @@ describe('Job table app', () => {
provide: {
fullPath: projectPath,
},
- apolloProvider: createMockApolloProvider(handler),
+ apolloProvider: createMockApolloProvider(handler, countHandler),
});
};
@@ -148,12 +156,39 @@ describe('Job table app', () => {
});
describe('error state', () => {
- it('should show an alert if there is an error fetching the data', async () => {
+ it('should show an alert if there is an error fetching the jobs data', async () => {
createComponent({ handler: failedHandler });
await waitForPromises();
- expect(findAlert().exists()).toBe(true);
+ expect(findAlert().text()).toBe('There was an error fetching the jobs for your project.');
+ expect(findTable().exists()).toBe(false);
+ });
+
+ it('should show an alert if there is an error fetching the jobs count data', async () => {
+ createComponent({ handler: successHandler, countHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findAlert().text()).toBe(
+ 'There was an error fetching the number of jobs for your project.',
+ );
+ });
+
+ it('jobs table should still load if count query fails', async () => {
+ createComponent({ handler: successHandler, countHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it('jobs count should be zero if count query fails', async () => {
+ createComponent({ handler: successHandler, countHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findTabs().props('allJobsCount')).toBe(0);
});
});
diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js
index 9abd610c26d..483b4ca711f 100644
--- a/spec/frontend/jobs/mock_data.js
+++ b/spec/frontend/jobs/mock_data.js
@@ -1,3 +1,4 @@
+import mockJobsCount from 'test_fixtures/graphql/jobs/get_jobs_count.query.graphql.json';
import mockJobsEmpty from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.empty.json';
import mockJobsPaginated from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.paginated.json';
import mockJobs from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.json';
@@ -13,6 +14,7 @@ export const mockJobsResponsePaginated = mockJobsPaginated;
export const mockJobsResponseEmpty = mockJobsEmpty;
export const mockJobsNodes = mockJobs.data.project.jobs.nodes;
export const mockJobsNodesAsGuest = mockJobsAsGuest.data.project.jobs.nodes;
+export const mockJobsCountResponse = mockJobsCount;
export const stages = [
{
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js
index 311d5a13280..3b09cf581cc 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js
@@ -13,6 +13,7 @@ import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { OPTIONS_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
import BranchToken from '~/vue_shared/components/filtered_search_bar/tokens/branch_token.vue';
+import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { mockBranches, mockBranchToken } from '../mock_data';
@@ -54,58 +55,83 @@ describe('BranchToken', () => {
let mock;
let wrapper;
+ const findBaseToken = () => wrapper.findComponent(BaseToken);
+ const triggerFetchBranches = (searchTerm = null) => {
+ findBaseToken().vm.$emit('fetch-suggestions', searchTerm);
+ return waitForPromises();
+ };
+
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('methods', () => {
- beforeEach(() => {
- wrapper = createComponent();
- });
-
describe('fetchBranches', () => {
- it('calls `config.fetchBranches` with provided searchTerm param', () => {
- jest.spyOn(wrapper.vm.config, 'fetchBranches');
-
- wrapper.vm.fetchBranches('foo');
+ it('sets loading state', async () => {
+ wrapper = createComponent({
+ config: {
+ fetchBranches: jest.fn().mockResolvedValue(new Promise(() => {})),
+ },
+ });
+ await nextTick();
- expect(wrapper.vm.config.fetchBranches).toHaveBeenCalledWith('foo');
+ expect(findBaseToken().props('suggestionsLoading')).toBe(true);
});
- it('sets response to `branches` when request is succesful', () => {
- jest.spyOn(wrapper.vm.config, 'fetchBranches').mockResolvedValue({ data: mockBranches });
+ describe('when request is successful', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ config: {
+ fetchBranches: jest.fn().mockResolvedValue({ data: mockBranches }),
+ },
+ });
+ });
+
+ it('calls `config.fetchBranches` with provided searchTerm param', async () => {
+ const searchTerm = 'foo';
+ await triggerFetchBranches(searchTerm);
- wrapper.vm.fetchBranches('foo');
+ expect(findBaseToken().props('config').fetchBranches).toHaveBeenCalledWith(searchTerm);
+ });
+
+ it('sets response to `branches`', async () => {
+ await triggerFetchBranches();
- return waitForPromises().then(() => {
- expect(wrapper.vm.branches).toEqual(mockBranches);
+ expect(findBaseToken().props('suggestions')).toEqual(mockBranches);
+ });
+
+ it('sets `loading` to false when request completes', async () => {
+ await triggerFetchBranches();
+
+ expect(findBaseToken().props('suggestionsLoading')).toBe(false);
});
});
- it('calls `createAlert` with flash error message when request fails', () => {
- jest.spyOn(wrapper.vm.config, 'fetchBranches').mockRejectedValue({});
+ describe('when request fails', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ config: {
+ fetchBranches: jest.fn().mockRejectedValue({}),
+ },
+ });
+ });
- wrapper.vm.fetchBranches('foo');
+ it('calls `createAlert` with flash error message when request fails', async () => {
+ await triggerFetchBranches();
- return waitForPromises().then(() => {
expect(createAlert).toHaveBeenCalledWith({
message: 'There was a problem fetching branches.',
});
});
- });
-
- it('sets `loading` to false when request completes', () => {
- jest.spyOn(wrapper.vm.config, 'fetchBranches').mockRejectedValue({});
- wrapper.vm.fetchBranches('foo');
+ it('sets `loading` to false when request completes', async () => {
+ await triggerFetchBranches();
- return waitForPromises().then(() => {
- expect(wrapper.vm.loading).toBe(false);
+ expect(findBaseToken().props('suggestionsLoading')).toBe(false);
});
});
});
@@ -120,16 +146,13 @@ describe('BranchToken', () => {
await nextTick();
}
- beforeEach(async () => {
- wrapper = createComponent({ value: { data: mockBranches[0].name } });
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- branches: mockBranches,
+ beforeEach(() => {
+ wrapper = createComponent({
+ value: { data: mockBranches[0].name },
+ config: {
+ initialBranches: mockBranches,
+ },
});
-
- await nextTick();
});
it('renders gl-filtered-search-token component', () => {
diff --git a/spec/helpers/broadcast_messages_helper_spec.rb b/spec/helpers/broadcast_messages_helper_spec.rb
index d4021a2eb59..e0bdb09f257 100644
--- a/spec/helpers/broadcast_messages_helper_spec.rb
+++ b/spec/helpers/broadcast_messages_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BroadcastMessagesHelper do
+RSpec.describe BroadcastMessagesHelper, feature_category: :onboarding do
include Gitlab::Routing.url_helpers
let_it_be(:user) { create(:user) }
@@ -68,7 +68,7 @@ RSpec.describe BroadcastMessagesHelper do
end
end
- describe 'current_broadcast_notification_message' do
+ describe '#current_broadcast_notification_message' do
subject { helper.current_broadcast_notification_message }
context 'with available broadcast notification messages' do
@@ -97,7 +97,7 @@ RSpec.describe BroadcastMessagesHelper do
end
end
- describe 'current_broadcast_banner_messages' do
+ describe '#current_broadcast_banner_messages' do
describe 'user access level targeted messages' do
let_it_be(:message) { create(:broadcast_message, broadcast_type: 'banner', starts_at: Time.now, target_access_levels: [Gitlab::Access::DEVELOPER]) }
@@ -107,7 +107,7 @@ RSpec.describe BroadcastMessagesHelper do
end
end
- describe 'broadcast_message' do
+ describe '#broadcast_message' do
let(:current_broadcast_message) { BroadcastMessage.new(message: 'Current Message') }
it 'returns nil when no current message' do
@@ -119,7 +119,7 @@ RSpec.describe BroadcastMessagesHelper do
end
end
- describe 'broadcast_message_status' do
+ describe '#broadcast_message_status' do
it 'returns Active' do
message = build(:broadcast_message)
@@ -138,4 +138,23 @@ RSpec.describe BroadcastMessagesHelper do
expect(helper.broadcast_message_status(message)).to eq 'Pending'
end
end
+
+ describe '#admin_broadcast_messages_data' do
+ let(:starts_at) { 1.day.ago }
+ let(:ends_at) { 1.day.from_now }
+ let(:message) { build(:broadcast_message, id: non_existing_record_id, starts_at: starts_at, ends_at: ends_at) }
+
+ subject(:single_broadcast_message) { Gitlab::Json.parse(admin_broadcast_messages_data([message])).first }
+
+ it 'returns the expected messages data attributes' do
+ keys = %w[id status preview starts_at ends_at target_roles target_path type edit_path delete_path]
+
+ expect(single_broadcast_message.keys).to match(keys)
+ end
+
+ it 'has the correct iso formatted date', time_travel_to: '2020-01-01 00:00:00 +0000' do
+ expect(single_broadcast_message['starts_at']).to eq('2019-12-31T00:00:00Z')
+ expect(single_broadcast_message['ends_at']).to eq('2020-01-02T00:00:00Z')
+ end
+ end
end
diff --git a/spec/helpers/ide_helper_spec.rb b/spec/helpers/ide_helper_spec.rb
index e2ee4f33eee..811b7a3490c 100644
--- a/spec/helpers/ide_helper_spec.rb
+++ b/spec/helpers/ide_helper_spec.rb
@@ -18,32 +18,63 @@ RSpec.describe IdeHelper, feature_category: :web_ide do
end
it 'returns hash' do
- expect(helper.ide_data(project: project, branch: 'master', path: 'foo/README.md', merge_request: '7',
-fork_info: nil))
- .to match(
- 'can-use-new-web-ide' => 'true',
- 'use-new-web-ide' => 'true',
- 'user-preferences-path' => profile_preferences_path,
- 'new-web-ide-help-page-path' =>
- help_page_path('user/project/web_ide/index.md', anchor: 'vscode-reimplementation'),
- 'branch-name' => 'master',
- 'project-path' => project.path_with_namespace,
- 'csp-nonce' => 'test-csp-nonce',
- 'ide-remote-path' => ide_remote_path(remote_host: ':remote_host', remote_path: ':remote_path'),
- 'file-path' => 'foo/README.md',
- 'editor-font-family' => 'JetBrains Mono',
- 'editor-font-format' => 'woff2',
- 'editor-font-src-url' => a_string_matching(%r{jetbrains-mono/JetBrainsMono}),
- 'merge-request' => '7',
- 'fork-info' => nil
+ expect(
+ helper.ide_data(
+ project: project,
+ branch: 'master',
+ path: 'foo/README.md',
+ merge_request: '7',
+ fork_info: nil,
+ learn_gitlab_source: nil
)
+ ).to match(
+ 'can-use-new-web-ide' => 'true',
+ 'use-new-web-ide' => 'true',
+ 'user-preferences-path' => profile_preferences_path,
+ 'new-web-ide-help-page-path' =>
+ help_page_path('user/project/web_ide/index.md', anchor: 'vscode-reimplementation'),
+ 'branch-name' => 'master',
+ 'project-path' => project.path_with_namespace,
+ 'csp-nonce' => 'test-csp-nonce',
+ 'ide-remote-path' => ide_remote_path(remote_host: ':remote_host', remote_path: ':remote_path'),
+ 'file-path' => 'foo/README.md',
+ 'editor-font-family' => 'JetBrains Mono',
+ 'editor-font-format' => 'woff2',
+ 'editor-font-src-url' => a_string_matching(%r{jetbrains-mono/JetBrainsMono}),
+ 'merge-request' => '7',
+ 'fork-info' => nil,
+ 'learn-gitlab-source' => 'false'
+ )
end
it 'does not use new web ide if user.use_legacy_web_ide' do
allow(user).to receive(:use_legacy_web_ide).and_return(true)
- expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil,
-fork_info: nil)).to include('use-new-web-ide' => 'false')
+ expect(
+ helper.ide_data(
+ project: project,
+ branch: nil,
+ path: nil,
+ merge_request: nil,
+ fork_info: nil,
+ learn_gitlab_source: nil
+ )
+ ).to include('use-new-web-ide' => 'false')
+ end
+
+ it 'returns source data in the hash if learn gitlab source' do
+ allow(user).to receive(:use_legacy_web_ide).and_return(true)
+
+ expect(
+ helper.ide_data(
+ project: project,
+ branch: nil,
+ path: nil,
+ merge_request: nil,
+ fork_info: nil,
+ learn_gitlab_source: true
+ )
+ ).to include('learn-gitlab-source' => 'true')
end
end
@@ -54,18 +85,26 @@ fork_info: nil)).to include('use-new-web-ide' => 'false')
context 'when instance vars and parameters are not set' do
it 'returns instance data in the hash as nil' do
- expect(helper.ide_data(project: nil, branch: nil, path: nil, merge_request: nil, fork_info: nil))
- .to include(
- 'can-use-new-web-ide' => 'false',
- 'use-new-web-ide' => 'false',
- 'user-preferences-path' => profile_preferences_path,
- 'branch-name' => nil,
- 'file-path' => nil,
- 'merge-request' => nil,
- 'fork-info' => nil,
- 'project' => nil,
- 'preview-markdown-path' => nil
+ expect(
+ helper.ide_data(
+ project: nil,
+ branch: nil,
+ path: nil,
+ merge_request: nil,
+ fork_info: nil,
+ learn_gitlab_source: nil
)
+ ).to include(
+ 'can-use-new-web-ide' => 'false',
+ 'use-new-web-ide' => 'false',
+ 'user-preferences-path' => profile_preferences_path,
+ 'branch-name' => nil,
+ 'file-path' => nil,
+ 'merge-request' => nil,
+ 'fork-info' => nil,
+ 'project' => nil,
+ 'preview-markdown-path' => nil
+ )
end
end
@@ -75,16 +114,23 @@ fork_info: nil)).to include('use-new-web-ide' => 'false')
serialized_project = API::Entities::Project.represent(project, current_user: project.creator).to_json
- expect(helper.ide_data(project: project, branch: 'master', path: 'foo/bar', merge_request: '1',
-fork_info: fork_info))
- .to include(
- 'branch-name' => 'master',
- 'file-path' => 'foo/bar',
- 'merge-request' => '1',
- 'fork-info' => fork_info.to_json,
- 'project' => serialized_project,
- 'preview-markdown-path' => Gitlab::Routing.url_helpers.preview_markdown_project_path(project)
+ expect(
+ helper.ide_data(
+ project: project,
+ branch: 'master',
+ path: 'foo/bar',
+ merge_request: '1',
+ fork_info: fork_info,
+ learn_gitlab_source: nil
)
+ ).to include(
+ 'branch-name' => 'master',
+ 'file-path' => 'foo/bar',
+ 'merge-request' => '1',
+ 'fork-info' => fork_info.to_json,
+ 'project' => serialized_project,
+ 'preview-markdown-path' => Gitlab::Routing.url_helpers.preview_markdown_project_path(project)
+ )
end
end
@@ -95,8 +141,16 @@ fork_info: fork_info))
context 'when project has no enviornments' do
it 'enables environment guidance' do
- expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil,
-fork_info: nil)).to include('enable-environments-guidance' => 'true')
+ expect(
+ helper.ide_data(
+ project: project,
+ branch: nil,
+ path: nil,
+ merge_request: nil,
+ fork_info: nil,
+ learn_gitlab_source: nil
+ )
+ ).to include('enable-environments-guidance' => 'true')
end
context 'and the callout has been dismissed' do
@@ -104,8 +158,17 @@ fork_info: nil)).to include('enable-environments-guidance' => 'true')
callout = create(:callout, feature_name: :web_ide_ci_environments_guidance, user: project.creator)
callout.update!(dismissed_at: Time.now - 1.week)
allow(helper).to receive(:current_user).and_return(User.find(project.creator.id))
- expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil,
-fork_info: nil)).to include('enable-environments-guidance' => 'false')
+
+ expect(
+ helper.ide_data(
+ project: project,
+ branch: nil,
+ path: nil,
+ merge_request: nil,
+ fork_info: nil,
+ learn_gitlab_source: nil
+ )
+ ).to include('enable-environments-guidance' => 'false')
end
end
end
@@ -114,8 +177,16 @@ fork_info: nil)).to include('enable-environments-guidance' => 'false')
it 'disables environment guidance' do
create(:environment, project: project)
- expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil,
-fork_info: nil)).to include('enable-environments-guidance' => 'false')
+ expect(
+ helper.ide_data(
+ project: project,
+ branch: nil,
+ path: nil,
+ merge_request: nil,
+ fork_info: nil,
+ learn_gitlab_source: nil
+ )
+ ).to include('enable-environments-guidance' => 'false')
end
end
end
diff --git a/spec/lib/bulk_imports/clients/http_spec.rb b/spec/lib/bulk_imports/clients/http_spec.rb
index 780f61f8c61..09753b3c23d 100644
--- a/spec/lib/bulk_imports/clients/http_spec.rb
+++ b/spec/lib/bulk_imports/clients/http_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe BulkImports::Clients::HTTP, feature_category: :importers do
let(:resource) { 'resource' }
let(:version) { "#{BulkImport::MIN_MAJOR_VERSION}.0.0" }
let(:enterprise) { false }
+ let(:sidekiq_request_timeout) { described_class::SIDEKIQ_REQUEST_TIMEOUT }
let(:response_double) { double(code: 200, success?: true, parsed_response: {}) }
let(:metadata_response) do
double(
@@ -123,6 +124,36 @@ RSpec.describe BulkImports::Clients::HTTP, feature_category: :importers do
allow(Gitlab::HTTP).to receive(:get).with(uri, params).and_return(response)
end
end
+
+ context 'when the request is asynchronous' do
+ let(:expected_args) do
+ [
+ 'http://gitlab.example/api/v4/resource',
+ hash_including(
+ query: {
+ page: described_class::DEFAULT_PAGE,
+ per_page: described_class::DEFAULT_PER_PAGE,
+ private_token: token
+ },
+ headers: {
+ 'Content-Type' => 'application/json'
+ },
+ follow_redirects: true,
+ resend_on_redirect: false,
+ limit: 2,
+ timeout: sidekiq_request_timeout
+ )
+ ]
+ end
+
+ it 'sets a timeout that is double the default read timeout' do
+ allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
+
+ expect(Gitlab::HTTP).to receive(method).with(*expected_args).and_return(response_double)
+
+ subject.public_send(method, resource)
+ end
+ end
end
describe '#post' do
diff --git a/spec/models/onboarding/completion_spec.rb b/spec/models/onboarding/completion_spec.rb
index e1fad4255bc..175f8d6ef68 100644
--- a/spec/models/onboarding/completion_spec.rb
+++ b/spec/models/onboarding/completion_spec.rb
@@ -2,10 +2,14 @@
require 'spec_helper'
-RSpec.describe Onboarding::Completion do
+RSpec.describe Onboarding::Completion, feature_category: :onboarding do
+ let(:completed_actions) { {} }
+ let(:project) { build(:project, namespace: namespace) }
+ let!(:onboarding_progress) { create(:onboarding_progress, namespace: namespace, **completed_actions) }
+
+ let_it_be(:namespace) { create(:namespace) }
+
describe '#percentage' do
- let(:completed_actions) { {} }
- let!(:onboarding_progress) { create(:onboarding_progress, namespace: namespace, **completed_actions) }
let(:tracked_action_columns) do
[
*described_class::ACTION_ISSUE_IDS.keys,
@@ -14,12 +18,10 @@ RSpec.describe Onboarding::Completion do
].map { |key| ::Onboarding::Progress.column_name(key) }
end
- let_it_be(:namespace) { create(:namespace) }
-
- subject { described_class.new(namespace).percentage }
+ subject(:percentage) { described_class.new(project).percentage }
context 'when no onboarding_progress exists' do
- subject { described_class.new(build(:namespace)).percentage }
+ subject(:percentage) { described_class.new(build(:project)).percentage }
it { is_expected.to eq(0) }
end
@@ -29,6 +31,8 @@ RSpec.describe Onboarding::Completion do
end
context 'when all tracked actions have been completed' do
+ let(:project) { build(:project, :stubbed_commit_count, namespace: namespace) }
+
let(:completed_actions) do
tracked_action_columns.index_with { Time.current }
end
@@ -44,7 +48,7 @@ RSpec.describe Onboarding::Completion do
stub_experiments(security_actions_continuous_onboarding: :control)
end
- it { is_expected.to eq(11) }
+ it { is_expected.to eq(10) }
end
context 'when candidate' do
@@ -52,7 +56,50 @@ RSpec.describe Onboarding::Completion do
stub_experiments(security_actions_continuous_onboarding: :candidate)
end
- it { is_expected.to eq(9) }
+ it { is_expected.to eq(8) }
+ end
+ end
+ end
+
+ describe '#completed?' do
+ subject(:completed?) { described_class.new(project).completed?(column) }
+
+ context 'when code_added' do
+ let(:column) { :code_added }
+
+ context 'when commit_count > 1' do
+ let(:project) { build(:project, :stubbed_commit_count, namespace: namespace) }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'when branch_count > 1' do
+ let(:project) { build(:project, :stubbed_branch_count, namespace: namespace) }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'when empty repository' do
+ let(:project) { build(:project, namespace: namespace) }
+
+ it { is_expected.to eq(false) }
+ end
+ end
+
+ context 'when security_scan_enabled' do
+ let(:column) { :security_scan_enabled_at }
+ let(:completed_actions) { { security_scan_enabled_at: security_scan_enabled_at } }
+
+ context 'when is completed' do
+ let(:security_scan_enabled_at) { Time.current }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'when is not completed' do
+ let(:security_scan_enabled_at) { nil }
+
+ it { is_expected.to eq(false) }
end
end
end
diff --git a/spec/requests/ide_controller_spec.rb b/spec/requests/ide_controller_spec.rb
index 6e79943e83d..31a53949f2f 100644
--- a/spec/requests/ide_controller_spec.rb
+++ b/spec/requests/ide_controller_spec.rb
@@ -130,10 +130,27 @@ RSpec.describe IdeController, feature_category: :web_ide do
expect(assigns(:path)).to be_nil
expect(assigns(:merge_request)).to be_nil
expect(assigns(:fork_info)).to be_nil
+ expect(assigns(:learn_gitlab_source)).to be_nil
end
it_behaves_like 'user access rights check'
+ context "/-/ide/project/:project?learn_gitlab_source=true" do
+ let(:route) { "/-/ide/project/#{project.full_path}?learn_gitlab_source=true" }
+
+ it 'instantiates project instance var and returns 200' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(assigns(:project)).to eq project
+ expect(assigns(:branch)).to be_nil
+ expect(assigns(:path)).to be_nil
+ expect(assigns(:merge_request)).to be_nil
+ expect(assigns(:fork_info)).to be_nil
+ expect(assigns(:learn_gitlab_source)).to eq 'true'
+ end
+ end
+
%w(edit blob tree).each do |action|
context "/-/ide/project/:project/#{action}" do
let(:route) { "/-/ide/project/#{project.full_path}/#{action}" }
@@ -147,6 +164,7 @@ RSpec.describe IdeController, feature_category: :web_ide do
expect(assigns(:path)).to be_nil
expect(assigns(:merge_request)).to be_nil
expect(assigns(:fork_info)).to be_nil
+ expect(assigns(:learn_gitlab_source)).to be_nil
end
it_behaves_like 'user access rights check'
@@ -164,6 +182,7 @@ RSpec.describe IdeController, feature_category: :web_ide do
expect(assigns(:path)).to be_nil
expect(assigns(:merge_request)).to be_nil
expect(assigns(:fork_info)).to be_nil
+ expect(assigns(:learn_gitlab_source)).to be_nil
end
it_behaves_like 'user access rights check'
@@ -181,6 +200,7 @@ RSpec.describe IdeController, feature_category: :web_ide do
expect(assigns(:path)).to be_nil
expect(assigns(:merge_request)).to be_nil
expect(assigns(:fork_info)).to be_nil
+ expect(assigns(:learn_gitlab_source)).to be_nil
end
it_behaves_like 'user access rights check'
@@ -198,6 +218,7 @@ RSpec.describe IdeController, feature_category: :web_ide do
expect(assigns(:path)).to eq 'foo/.bar'
expect(assigns(:merge_request)).to be_nil
expect(assigns(:fork_info)).to be_nil
+ expect(assigns(:learn_gitlab_source)).to be_nil
end
it_behaves_like 'user access rights check'
@@ -221,6 +242,7 @@ RSpec.describe IdeController, feature_category: :web_ide do
expect(assigns(:path)).to be_nil
expect(assigns(:merge_request)).to eq merge_request.id.to_s
expect(assigns(:fork_info)).to be_nil
+ expect(assigns(:learn_gitlab_source)).to be_nil
end
it_behaves_like 'user access rights check'