diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-01-27 15:09:15 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-01-27 15:09:15 +0000 |
commit | 0cbb4a75699e1ab6a0cb704b551e672e09192377 (patch) | |
tree | 3464aa858cfe0051bf898c919c097905c9f5f8da /spec | |
parent | 507c0e71cd73201beadf9c5e1e0361fc8e9e2665 (diff) | |
download | gitlab-ce-0cbb4a75699e1ab6a0cb704b551e672e09192377.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/admin/cohorts_controller_spec.rb | 34 | ||||
-rw-r--r-- | spec/controllers/admin/users_controller_spec.rb | 5 | ||||
-rw-r--r-- | spec/controllers/projects/forks_controller_spec.rb | 22 | ||||
-rw-r--r-- | spec/features/admin/admin_cohorts_spec.rb | 33 | ||||
-rw-r--r-- | spec/features/admin/admin_users_spec.rb | 70 | ||||
-rw-r--r-- | spec/frontend/admin/users/index_spec.js | 4 | ||||
-rw-r--r-- | spec/frontend/filtered_search/recent_searches_root_spec.js | 49 | ||||
-rw-r--r-- | spec/frontend/onboarding_issues/index_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/terraform/components/states_table_actions_spec.js | 87 | ||||
-rw-r--r-- | spec/frontend/terraform/components/states_table_spec.js | 19 | ||||
-rw-r--r-- | spec/frontend/terraform/components/terraform_list_spec.js | 23 | ||||
-rw-r--r-- | spec/requests/api/projects_spec.rb | 13 | ||||
-rw-r--r-- | spec/routing/admin_routing_spec.rb | 7 | ||||
-rw-r--r-- | spec/services/projects/fork_service_spec.rb | 44 |
14 files changed, 311 insertions, 101 deletions
diff --git a/spec/controllers/admin/cohorts_controller_spec.rb b/spec/controllers/admin/cohorts_controller_spec.rb index 9eb2a713517..77a9c8eb223 100644 --- a/spec/controllers/admin/cohorts_controller_spec.rb +++ b/spec/controllers/admin/cohorts_controller_spec.rb @@ -3,37 +3,15 @@ require 'spec_helper' RSpec.describe Admin::CohortsController do - context 'as admin' do - let(:user) { create(:admin) } + let(:user) { create(:admin) } - before do - sign_in(user) - end - - it 'renders 200' do - get :index - - expect(response).to have_gitlab_http_status(:success) - end - - describe 'GET #index' do - it_behaves_like 'tracking unique visits', :index do - let(:target_id) { 'i_analytics_cohorts' } - end - end + before do + sign_in(user) end - context 'as normal user' do - let(:user) { create(:user) } - - before do - sign_in(user) - end - - it 'renders a 404' do - get :index + it 'redirects to Overview->Users' do + get :index - expect(response).to have_gitlab_http_status(:not_found) - end + expect(response).to redirect_to(admin_users_path(tab: 'cohorts')) end end diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index 20df72c25ea..6faec315eb6 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -29,6 +29,11 @@ RSpec.describe Admin::UsersController do expect(assigns(:users).first.association(:authorized_projects)).to be_loaded end + + it_behaves_like 'tracking unique visits', :index do + let(:target_id) { 'i_analytics_cohorts' } + let(:request_params) { { tab: 'cohorts' } } + end end describe 'GET :id' do diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb index e8b30294cdd..7da3d403b53 100644 --- a/spec/controllers/projects/forks_controller_spec.rb +++ b/spec/controllers/projects/forks_controller_spec.rb @@ -209,6 +209,13 @@ RSpec.describe Projects::ForksController do } end + let(:created_project) do + Namespace + .find_by_id(params[:namespace_key]) + .projects + .find_by_path(params.fetch(:path, project.path)) + end + subject do post :create, params: params end @@ -260,6 +267,21 @@ RSpec.describe Projects::ForksController do expect(response).to redirect_to(namespace_project_import_path(user.namespace, project, continue: continue_params)) end end + + context 'custom attributes set' do + let(:params) { super().merge(path: 'something_custom', name: 'Something Custom', description: 'Something Custom', visibility: 'private') } + + it 'creates a project with custom values' do + subject + + expect(response).to have_gitlab_http_status(:found) + expect(response).to redirect_to(namespace_project_import_path(user.namespace, params[:path])) + expect(created_project.path).to eq(params[:path]) + expect(created_project.name).to eq(params[:name]) + expect(created_project.description).to eq(params[:description]) + expect(created_project.visibility).to eq(params[:visibility]) + end + end end context 'when user is not signed in' do diff --git a/spec/features/admin/admin_cohorts_spec.rb b/spec/features/admin/admin_cohorts_spec.rb deleted file mode 100644 index 982a9333275..00000000000 --- a/spec/features/admin/admin_cohorts_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Cohorts page' do - before do - admin = create(:admin) - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - end - - context 'with usage ping enabled' do - it 'shows users count per month' do - stub_application_setting(usage_ping_enabled: true) - - create_list(:user, 2) - - visit admin_cohorts_path - - expect(page).to have_content("#{Time.now.strftime('%b %Y')} 3 0") - end - end - - context 'with usage ping disabled' do - it 'shows empty state', :js do - stub_application_setting(usage_ping_enabled: false) - - visit admin_cohorts_path - - expect(page).to have_selector(".js-empty-state") - end - end -end diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb new file mode 100644 index 00000000000..4fc60d17886 --- /dev/null +++ b/spec/features/admin/admin_users_spec.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe "Admin::Users" do + let(:current_user) { create(:admin) } + + before do + sign_in(current_user) + gitlab_enable_admin_mode_sign_in(current_user) + end + + describe 'Tabs', :js do + let(:tabs_selector) { '.js-users-tabs' } + let(:active_tab_selector) { '.nav-link.active' } + + it 'does not add the tab param when the Users tab is selected' do + visit admin_users_path + + within tabs_selector do + click_link 'Users' + end + + expect(page).to have_current_path(admin_users_path) + end + + it 'adds the ?tab=cohorts param when the Cohorts tab is selected' do + visit admin_users_path + + within tabs_selector do + click_link 'Cohorts' + end + + expect(page).to have_current_path(admin_users_path(tab: 'cohorts')) + end + + it 'shows the cohorts tab when the tab param is set' do + visit admin_users_path(tab: 'cohorts') + + within tabs_selector do + expect(page).to have_selector active_tab_selector, text: 'Cohorts' + end + end + end + + describe 'Cohorts tab content' do + context 'with usage ping enabled' do + it 'shows users count per month' do + stub_application_setting(usage_ping_enabled: true) + + create_list(:user, 2) + + visit admin_users_path(tab: 'cohorts') + + expect(page).to have_content("#{Time.now.strftime('%b %Y')} 3 0") + end + end + + context 'with usage ping disabled' do + it 'shows empty state', :js do + stub_application_setting(usage_ping_enabled: false) + + visit admin_users_path(tab: 'cohorts') + + expect(page).to have_selector(".js-empty-state") + expect(page).to have_content("Activate user activity analysis") + end + end + end +end diff --git a/spec/frontend/admin/users/index_spec.js b/spec/frontend/admin/users/index_spec.js index 171d54c8f4f..20b60bd8640 100644 --- a/spec/frontend/admin/users/index_spec.js +++ b/spec/frontend/admin/users/index_spec.js @@ -1,5 +1,5 @@ import { createWrapper } from '@vue/test-utils'; -import initAdminUsers from '~/admin/users'; +import { initAdminUsersApp } from '~/admin/users'; import AdminUsersApp from '~/admin/users/components/app.vue'; import { users, paths } from './mock_data'; @@ -16,7 +16,7 @@ describe('initAdminUsersApp', () => { document.body.appendChild(el); - wrapper = createWrapper(initAdminUsers(el)); + wrapper = createWrapper(initAdminUsersApp(el)); }); afterEach(() => { diff --git a/spec/frontend/filtered_search/recent_searches_root_spec.js b/spec/frontend/filtered_search/recent_searches_root_spec.js index 6bb9e68d591..fa3267c98a1 100644 --- a/spec/frontend/filtered_search/recent_searches_root_spec.js +++ b/spec/frontend/filtered_search/recent_searches_root_spec.js @@ -1,32 +1,51 @@ -import Vue from 'vue'; +import { setHTMLFixture } from 'helpers/fixtures'; import RecentSearchesRoot from '~/filtered_search/recent_searches_root'; -jest.mock('vue'); +const containerId = 'test-container'; +const dropdownElementId = 'test-dropdown-element'; describe('RecentSearchesRoot', () => { describe('render', () => { - let recentSearchesRoot; - let data; - let template; + let recentSearchesRootMockInstance; + let vm; + let containerEl; beforeEach(() => { - recentSearchesRoot = { + setHTMLFixture(` + <div id="${containerId}"> + <div id="${dropdownElementId}"></div> + </div> + `); + + containerEl = document.getElementById(containerId); + + recentSearchesRootMockInstance = { store: { - state: 'state', + state: { + recentSearches: ['foo', 'bar', 'qux'], + isLocalStorageAvailable: true, + allowedKeys: ['test'], + }, }, + wrapperElement: document.getElementById(dropdownElementId), }; - Vue.mockImplementation((options) => { - ({ data, template } = options); - }); + RecentSearchesRoot.prototype.render.call(recentSearchesRootMockInstance); + vm = recentSearchesRootMockInstance.vm; - RecentSearchesRoot.prototype.render.call(recentSearchesRoot); + return vm.$nextTick(); }); - it('should instantiate Vue', () => { - expect(Vue).toHaveBeenCalled(); - expect(data()).toBe(recentSearchesRoot.store.state); - expect(template).toContain(':is-local-storage-available="isLocalStorageAvailable"'); + afterEach(() => { + vm.$destroy(); + }); + + it('should render the recent searches', () => { + const { recentSearches } = recentSearchesRootMockInstance.store.state; + + recentSearches.forEach((recentSearch) => { + expect(containerEl.textContent).toContain(recentSearch); + }); }); }); }); diff --git a/spec/frontend/onboarding_issues/index_spec.js b/spec/frontend/onboarding_issues/index_spec.js index d476ba1cf5a..13093901e16 100644 --- a/spec/frontend/onboarding_issues/index_spec.js +++ b/spec/frontend/onboarding_issues/index_spec.js @@ -118,7 +118,7 @@ describe('Onboarding Issues Popovers', () => { describe('when dismissing the popover', () => { beforeEach(() => { jest.spyOn(Tracking, 'event'); - document.querySelector('.learn-gitlab.popover .close').click(); + document.querySelector('.learn-gitlab.popover .js-close-learn-gitlab').click(); }); it('deletes the cookie', () => { diff --git a/spec/frontend/terraform/components/states_table_actions_spec.js b/spec/frontend/terraform/components/states_table_actions_spec.js index 3f5df8a96f8..1f9bede2e6e 100644 --- a/spec/frontend/terraform/components/states_table_actions_spec.js +++ b/spec/frontend/terraform/components/states_table_actions_spec.js @@ -1,6 +1,7 @@ import { GlDropdown, GlModal, GlSprintf } from '@gitlab/ui'; import { createLocalVue, shallowMount } from '@vue/test-utils'; import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; import VueApollo from 'vue-apollo'; import StateActions from '~/terraform/components/states_table_actions.vue'; import lockStateMutation from '~/terraform/graphql/mutations/lock_state.mutation.graphql'; @@ -14,6 +15,7 @@ describe('StatesTableActions', () => { let lockResponse; let removeResponse; let unlockResponse; + let updateStateResponse; let wrapper; const defaultProps = { @@ -26,7 +28,9 @@ describe('StatesTableActions', () => { }; const createMockApolloProvider = () => { - lockResponse = jest.fn().mockResolvedValue({ data: { terraformStateLock: { errors: [] } } }); + lockResponse = jest + .fn() + .mockResolvedValue({ data: { terraformStateLock: { errors: ['There was an error'] } } }); removeResponse = jest .fn() @@ -36,11 +40,20 @@ describe('StatesTableActions', () => { .fn() .mockResolvedValue({ data: { terraformStateUnlock: { errors: [] } } }); - return createMockApollo([ - [lockStateMutation, lockResponse], - [removeStateMutation, removeResponse], - [unlockStateMutation, unlockResponse], - ]); + updateStateResponse = jest.fn().mockResolvedValue({}); + + return createMockApollo( + [ + [lockStateMutation, lockResponse], + [removeStateMutation, removeResponse], + [unlockStateMutation, unlockResponse], + ], + { + Mutation: { + addDataToTerraformState: updateStateResponse, + }, + }, + ); }; const createComponent = (propsData = defaultProps) => { @@ -56,6 +69,7 @@ describe('StatesTableActions', () => { return wrapper.vm.$nextTick(); }; + const findActionsDropdown = () => wrapper.find(GlDropdown); const findLockBtn = () => wrapper.find('[data-testid="terraform-state-lock"]'); const findUnlockBtn = () => wrapper.find('[data-testid="terraform-state-unlock"]'); const findDownloadBtn = () => wrapper.find('[data-testid="terraform-state-download"]'); @@ -70,9 +84,25 @@ describe('StatesTableActions', () => { lockResponse = null; removeResponse = null; unlockResponse = null; + updateStateResponse = null; wrapper.destroy(); }); + describe('when the state is loading', () => { + beforeEach(() => { + return createComponent({ + state: { + ...defaultProps.state, + loadingActions: true, + }, + }); + }); + + it('disables the actions dropdown', () => { + expect(findActionsDropdown().props('disabled')).toBe(true); + }); + }); + describe('download button', () => { it('displays a download button', () => { expect(findDownloadBtn().text()).toBe('Download JSON'); @@ -104,7 +134,8 @@ describe('StatesTableActions', () => { describe('when clicking the unlock button', () => { beforeEach(() => { findUnlockBtn().vm.$emit('click'); - return wrapper.vm.$nextTick(); + + return waitForPromises(); }); it('calls the unlock mutation', () => { @@ -137,7 +168,8 @@ describe('StatesTableActions', () => { describe('when clicking the lock button', () => { beforeEach(() => { findLockBtn().vm.$emit('click'); - return wrapper.vm.$nextTick(); + + return waitForPromises(); }); it('calls the lock mutation', () => { @@ -145,6 +177,42 @@ describe('StatesTableActions', () => { stateID: unlockedProps.state.id, }); }); + + it('calls mutations to set loading and errors', () => { + // loading update + expect(updateStateResponse).toHaveBeenNthCalledWith( + 1, + {}, + { + terraformState: { + ...unlockedProps.state, + _showDetails: false, + errorMessages: [], + loadingActions: true, + }, + }, + // Apollo fields + expect.any(Object), + expect.any(Object), + ); + + // final update + expect(updateStateResponse).toHaveBeenNthCalledWith( + 2, + {}, + { + terraformState: { + ...unlockedProps.state, + _showDetails: true, + errorMessages: ['There was an error'], + loadingActions: false, + }, + }, + // Apollo fields + expect.any(Object), + expect.any(Object), + ); + }); }); }); @@ -156,7 +224,8 @@ describe('StatesTableActions', () => { describe('when clicking the remove button', () => { beforeEach(() => { findRemoveBtn().vm.$emit('click'); - return wrapper.vm.$nextTick(); + + return waitForPromises(); }); it('displays a remove modal', () => { diff --git a/spec/frontend/terraform/components/states_table_spec.js b/spec/frontend/terraform/components/states_table_spec.js index f2b7bc00e5b..ba676c9741e 100644 --- a/spec/frontend/terraform/components/states_table_spec.js +++ b/spec/frontend/terraform/components/states_table_spec.js @@ -11,6 +11,8 @@ describe('StatesTable', () => { const defaultProps = { states: [ { + _showDetails: true, + errorMessages: ['State 1 has errored'], name: 'state-1', lockedAt: '2020-10-13T00:00:00Z', lockedByUser: { @@ -20,6 +22,8 @@ describe('StatesTable', () => { latestVersion: null, }, { + _showDetails: false, + errorMessages: [], name: 'state-2', lockedAt: null, lockedByUser: null, @@ -27,6 +31,8 @@ describe('StatesTable', () => { latestVersion: null, }, { + _showDetails: false, + errorMessages: [], name: 'state-3', lockedAt: '2020-10-10T00:00:00Z', lockedByUser: { @@ -54,6 +60,8 @@ describe('StatesTable', () => { }, }, { + _showDetails: true, + errorMessages: ['State 4 has errored'], name: 'state-4', lockedAt: '2020-10-10T00:00:00Z', lockedByUser: null, @@ -154,6 +162,17 @@ describe('StatesTable', () => { expect(findActions().length).toEqual(0); }); + it.each` + errorMessage | lineNumber + ${defaultProps.states[0].errorMessages[0]} | ${0} + ${defaultProps.states[3].errorMessages[0]} | ${1} + `('displays table error message "$errorMessage"', ({ errorMessage, lineNumber }) => { + const states = wrapper.findAll('[data-testid="terraform-states-table-error"]'); + const state = states.at(lineNumber); + + expect(state.text()).toBe(errorMessage); + }); + describe('when user is a terraform administrator', () => { beforeEach(() => { return createComponent({ diff --git a/spec/frontend/terraform/components/terraform_list_spec.js b/spec/frontend/terraform/components/terraform_list_spec.js index fb56a7135a3..043fde3be17 100644 --- a/spec/frontend/terraform/components/terraform_list_spec.js +++ b/spec/frontend/terraform/components/terraform_list_spec.js @@ -27,6 +27,15 @@ describe('TerraformList', () => { }, }; + // Override @client _showDetails + getStatesQuery.getStates.definitions[1].selectionSet.selections[0].directives = []; + + // Override @client errorMessages + getStatesQuery.getStates.definitions[1].selectionSet.selections[1].directives = []; + + // Override @client loadingActions + getStatesQuery.getStates.definitions[1].selectionSet.selections[2].directives = []; + const statsQueryResponse = queryResponse || jest.fn().mockResolvedValue(apolloQueryResponse); const apolloProvider = createMockApollo([[getStatesQuery, statsQueryResponse]]); @@ -52,20 +61,26 @@ describe('TerraformList', () => { describe('when there is a list of terraform states', () => { const states = [ { + _showDetails: false, + errorMessages: [], id: 'gid://gitlab/Terraform::State/1', name: 'state-1', + latestVersion: null, + loadingActions: false, lockedAt: null, - updatedAt: null, lockedByUser: null, - latestVersion: null, + updatedAt: null, }, { + _showDetails: false, + errorMessages: [], id: 'gid://gitlab/Terraform::State/2', name: 'state-2', + latestVersion: null, + loadingActions: false, lockedAt: null, - updatedAt: null, lockedByUser: null, - latestVersion: null, + updatedAt: null, }, ]; diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 4acd0eea448..a2589ef3401 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -3328,8 +3328,8 @@ RSpec.describe API::Projects do expect(json_response['message']['path']).to eq(['has already been taken']) end - it 'accepts a name for the target project' do - post api("/projects/#{project.id}/fork", user2), params: { name: 'My Random Project' } + it 'accepts custom parameters for the target project' do + post api("/projects/#{project.id}/fork", user2), params: { name: 'My Random Project', description: 'A description', visibility: 'private' } expect(response).to have_gitlab_http_status(:created) expect(json_response['name']).to eq('My Random Project') @@ -3337,6 +3337,8 @@ RSpec.describe API::Projects do expect(json_response['owner']['id']).to eq(user2.id) expect(json_response['namespace']['id']).to eq(user2.namespace.id) expect(json_response['forked_from_project']['id']).to eq(project.id) + expect(json_response['description']).to eq('A description') + expect(json_response['visibility']).to eq('private') expect(json_response['import_status']).to eq('scheduled') expect(json_response).to include("import_error") end @@ -3368,6 +3370,13 @@ RSpec.describe API::Projects do expect(json_response['message']['path']).to eq(['has already been taken']) expect(json_response['message']['name']).to eq(['has already been taken']) end + + it 'fails to fork with an unknown visibility level' do + post api("/projects/#{project.id}/fork", user2), params: { visibility: 'something' } + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['error']).to eq('visibility does not have a valid value') + end end context 'when unauthenticated' do diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb index 9374df0c4a2..8c36d7d4668 100644 --- a/spec/routing/admin_routing_spec.rb +++ b/spec/routing/admin_routing_spec.rb @@ -141,13 +141,6 @@ RSpec.describe Admin::DevOpsReportController, "routing" do end end -# admin_cohorts GET /admin/cohorts(.:format) admin/cohorst#index -RSpec.describe Admin::CohortsController, "routing" do - it "to #index" do - expect(get("/admin/cohorts")).to route_to('admin/cohorts#index') - end -end - RSpec.describe Admin::GroupsController, "routing" do let(:name) { 'complex.group-namegit' } diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index a11f16573f5..df02f8ea15d 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -323,6 +323,50 @@ RSpec.describe Projects::ForkService do end end end + + describe 'fork with optional attributes' do + let(:public_project) { create(:project, :public) } + + it 'sets optional attributes to specified values' do + forked_project = fork_project( + public_project, + nil, + namespace: public_project.namespace, + path: 'forked', + name: 'My Fork', + description: 'Description', + visibility: 'internal', + using_service: true + ) + + expect(forked_project.path).to eq('forked') + expect(forked_project.name).to eq('My Fork') + expect(forked_project.description).to eq('Description') + expect(forked_project.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) + end + + it 'sets visibility level to private if an unknown visibility is requested' do + forked_project = fork_project(public_project, nil, using_service: true, visibility: 'unknown') + + expect(forked_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) + end + + it 'sets visibility level to project visibility level if requested visibility is greater' do + private_project = create(:project, :private) + + forked_project = fork_project(private_project, nil, using_service: true, visibility: 'public') + + expect(forked_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) + end + + it 'sets visibility level to target namespace visibility level if requested visibility is greater' do + private_group = create(:group, :private) + + forked_project = fork_project(public_project, nil, namespace: private_group, using_service: true, visibility: 'public') + + expect(forked_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) + end + end end context 'when a project is already forked' do |