diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-23 00:07:43 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-23 00:07:43 +0300 |
commit | f19ffffacda2d7f415f682f6e50e3cf06182e15e (patch) | |
tree | b8a78ba727ab2ef38808c028401842e7370948b0 /spec | |
parent | d0f16d56f3716d4a60027eb261f12080094f8db3 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/factories/projects.rb | 12 | ||||
-rw-r--r-- | spec/frontend/fixtures/jobs.rb | 22 | ||||
-rw-r--r-- | spec/frontend/ide/stores/modules/commit/actions_spec.js | 66 | ||||
-rw-r--r-- | spec/frontend/jobs/components/table/graphql/cache_config_spec.js | 19 | ||||
-rw-r--r-- | spec/frontend/jobs/components/table/job_table_app_spec.js | 45 | ||||
-rw-r--r-- | spec/frontend/jobs/mock_data.js | 2 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js | 93 | ||||
-rw-r--r-- | spec/helpers/broadcast_messages_helper_spec.rb | 29 | ||||
-rw-r--r-- | spec/helpers/ide_helper_spec.rb | 163 | ||||
-rw-r--r-- | spec/lib/bulk_imports/clients/http_spec.rb | 31 | ||||
-rw-r--r-- | spec/models/onboarding/completion_spec.rb | 65 | ||||
-rw-r--r-- | spec/requests/ide_controller_spec.rb | 22 |
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' |