diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-19 12:11:29 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-19 12:11:29 +0300 |
commit | 39e7e7beda5ab61c707eb050304a68bffa91dabd (patch) | |
tree | c024ee27baa67beddb8d5e19d564d56bbe4acf94 /spec | |
parent | 8c68904468d88beaeb618bfe81289a6c1eb8538c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/projects/analytics/cycle_analytics/stages_controller_spec.rb | 1 | ||||
-rw-r--r-- | spec/controllers/projects/cycle_analytics_controller_spec.rb | 12 | ||||
-rw-r--r-- | spec/controllers/projects/graphs_controller_spec.rb | 15 | ||||
-rw-r--r-- | spec/controllers/projects/pipelines_controller_spec.rb | 12 | ||||
-rw-r--r-- | spec/features/cycle_analytics_spec.rb | 4 | ||||
-rw-r--r-- | spec/features/groups_spec.rb | 3 | ||||
-rw-r--r-- | spec/features/profiles/user_visits_profile_spec.rb | 8 | ||||
-rw-r--r-- | spec/features/project_variables_spec.rb | 30 | ||||
-rw-r--r-- | spec/features/projects_spec.rb | 11 | ||||
-rw-r--r-- | spec/frontend/ci_variable_list/components/ci_project_variables_spec.js | 215 | ||||
-rw-r--r-- | spec/frontend/ci_variable_list/mocks.js | 9 | ||||
-rw-r--r-- | spec/frontend/vue_merge_request_widget/components/widget/app_spec.js | 4 | ||||
-rw-r--r-- | spec/helpers/storage_helper_spec.rb | 16 |
13 files changed, 319 insertions, 21 deletions
diff --git a/spec/controllers/projects/analytics/cycle_analytics/stages_controller_spec.rb b/spec/controllers/projects/analytics/cycle_analytics/stages_controller_spec.rb index 8903592ba15..b9e569b1647 100644 --- a/spec/controllers/projects/analytics/cycle_analytics/stages_controller_spec.rb +++ b/spec/controllers/projects/analytics/cycle_analytics/stages_controller_spec.rb @@ -16,7 +16,6 @@ RSpec.describe Projects::Analytics::CycleAnalytics::StagesController do end before do - stub_feature_flags(use_vsa_aggregated_tables: false) sign_in(user) end diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb index ccd213fdffa..f5dd8abd67b 100644 --- a/spec/controllers/projects/cycle_analytics_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb @@ -30,6 +30,18 @@ RSpec.describe Projects::CycleAnalyticsController do let(:request_params) { { namespace_id: project.namespace, project_id: project } } let(:target_id) { 'p_analytics_valuestream' } end + + it_behaves_like 'Snowplow event tracking' do + subject { get :show, params: request_params, format: :html } + + let(:request_params) { { namespace_id: project.namespace, project_id: project } } + let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } + let(:category) { described_class.name } + let(:action) { 'perform_analytics_usage_action' } + let(:namespace) { project.namespace } + let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' } + let(:property) { 'p_analytics_valuestream' } + end end include_examples GracefulTimeoutHandling diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index be89fa0d361..9227c7dd70a 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -89,6 +89,21 @@ RSpec.describe Projects::GraphsController do let(:request_params) { { namespace_id: project.namespace.path, project_id: project.path, id: 'master' } } let(:target_id) { 'p_analytics_repo' } end + + it_behaves_like 'Snowplow event tracking' do + subject do + sign_in(user) + get :charts, params: request_params, format: :html + end + + let(:request_params) { { namespace_id: project.namespace.path, project_id: project.path, id: 'master' } } + let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } + let(:category) { described_class.name } + let(:action) { 'perform_analytics_usage_action' } + let(:namespace) { project.namespace } + let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' } + let(:property) { 'p_analytics_repo' } + end end context 'when languages were previously detected' do diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 06930d8727b..48aaff67c95 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -841,6 +841,18 @@ RSpec.describe Projects::PipelinesController do let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id, chart: tab[:chart_param] } } let(:target_id) { ['p_analytics_pipelines', tab[:event]] } end + + it_behaves_like 'Snowplow event tracking' do + subject { get :charts, params: request_params, format: :html } + + let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id, chart: tab[:chart_param] } } + let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } + let(:category) { described_class.name } + let(:action) { 'perform_analytics_usage_action' } + let(:namespace) { project.namespace } + let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' } + let(:property) { 'p_analytics_pipelines' } + end end end diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb index 7714783172f..488a4f84297 100644 --- a/spec/features/cycle_analytics_spec.rb +++ b/spec/features/cycle_analytics_spec.rb @@ -36,10 +36,6 @@ RSpec.describe 'Value Stream Analytics', :js do wait_for_all_requests end - before do - stub_feature_flags(use_vsa_aggregated_tables: false) - end - context 'as an allowed user' do context 'when project is new' do before do diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index c93ed01b873..65cb8770662 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -519,10 +519,11 @@ RSpec.describe 'Group' do end describe 'storage_enforcement_banner', :js do - let_it_be(:group) { create(:group) } + let_it_be_with_refind(:group) { create(:group, :with_root_storage_statistics) } let_it_be_with_refind(:user) { create(:user) } before do + group.root_storage_statistics.update!(storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE) group.add_owner(user) sign_in(user) end diff --git a/spec/features/profiles/user_visits_profile_spec.rb b/spec/features/profiles/user_visits_profile_spec.rb index 7dd2e6aafa3..4859e796954 100644 --- a/spec/features/profiles/user_visits_profile_spec.rb +++ b/spec/features/profiles/user_visits_profile_spec.rb @@ -89,6 +89,14 @@ RSpec.describe 'User visits their profile' do end describe 'storage_enforcement_banner', :js do + let_it_be(:root_storage_statistics) do + create( + :namespace_root_storage_statistics, + namespace: user.namespace, + storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE + ) + end + before do stub_feature_flags(namespace_storage_limit_bypass_date_check: false) end diff --git a/spec/features/project_variables_spec.rb b/spec/features/project_variables_spec.rb index 89dbd1afc6b..d3bedbf3a75 100644 --- a/spec/features/project_variables_spec.rb +++ b/spec/features/project_variables_spec.rb @@ -14,8 +14,6 @@ RSpec.describe 'Project variables', :js do project.variables << variable end - # TODO: Add same tests but with FF enabled context when - # the new graphQL app for variable settings is enabled. context 'with disabled ff `ci_variable_settings_graphql' do before do stub_feature_flags(ci_variable_settings_graphql: false) @@ -44,4 +42,32 @@ RSpec.describe 'Project variables', :js do end end end + + context 'with enabled ff `ci_variable_settings_graphql' do + before do + visit page_path + end + + it_behaves_like 'variable list' + + it 'adds a new variable with an environment scope' do + click_button('Add variable') + + page.within('#add-ci-variable') do + fill_in 'Key', with: 'akey' + find('#ci-variable-value').set('akey_value') + find('[data-testid="environment-scope"]').click + find('[data-testid="ci-environment-search"]').set('review/*') + find('[data-testid="create-wildcard-button"]').click + + click_button('Add variable') + end + + wait_for_requests + + page.within('[data-testid="ci-variable-table"]') do + expect(find('.js-ci-variable-row:first-child [data-label="Environments"]').text).to eq('review/*') + end + end + end end diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index d228fb084c3..d9030b9ec89 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -441,11 +441,12 @@ RSpec.describe 'Project' do end describe 'storage_enforcement_banner', :js do - let_it_be(:group) { create(:group) } + let_it_be_with_refind(:group) { create(:group, :with_root_storage_statistics) } let_it_be_with_refind(:user) { create(:user) } let_it_be(:project) { create(:project, group: group) } before do + group.root_storage_statistics.update!(storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE) group.add_maintainer(user) sign_in(user) end @@ -475,9 +476,15 @@ RSpec.describe 'Project' do end context 'when in a user namespace project page' do - let_it_be(:project) { create(:project, namespace: user.namespace) } + let_it_be_with_refind(:project) { create(:project, namespace: user.namespace) } before do + create( + :namespace_root_storage_statistics, + namespace: user.namespace, + storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE + ) + allow_next_found_instance_of(Namespaces::UserNamespace) do |user_namespace| allow(user_namespace).to receive(:storage_enforcement_date).and_return(storage_enforcement_date) end diff --git a/spec/frontend/ci_variable_list/components/ci_project_variables_spec.js b/spec/frontend/ci_variable_list/components/ci_project_variables_spec.js new file mode 100644 index 00000000000..867f8e0cf8f --- /dev/null +++ b/spec/frontend/ci_variable_list/components/ci_project_variables_spec.js @@ -0,0 +1,215 @@ +import Vue, { nextTick } from 'vue'; +import VueApollo from 'vue-apollo'; +import { GlLoadingIcon, GlTable } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import createFlash from '~/flash'; +import { resolvers } from '~/ci_variable_list/graphql/resolvers'; +import { convertToGraphQLId } from '~/graphql_shared/utils'; + +import ciProjectVariables from '~/ci_variable_list/components/ci_project_variables.vue'; +import ciVariableSettings from '~/ci_variable_list/components/ci_variable_settings.vue'; +import ciVariableTable from '~/ci_variable_list/components/ci_variable_table.vue'; +import getProjectEnvironments from '~/ci_variable_list/graphql/queries/project_environments.query.graphql'; +import getProjectVariables from '~/ci_variable_list/graphql/queries/project_variables.query.graphql'; + +import addProjectVariable from '~/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql'; +import deleteProjectVariable from '~/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql'; +import updateProjectVariable from '~/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql'; + +import { + environmentFetchErrorText, + genericMutationErrorText, + variableFetchErrorText, +} from '~/ci_variable_list/constants'; + +import { + devName, + mockProjectEnvironments, + mockProjectVariables, + newVariable, + prodName, +} from '../mocks'; + +jest.mock('~/flash'); + +Vue.use(VueApollo); + +const mockProvide = { + endpoint: '/variables', + projectFullPath: '/namespace/project', + projectId: 1, +}; + +describe('Ci Project Variable list', () => { + let wrapper; + + let mockApollo; + let mockEnvironments; + let mockVariables; + + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + const findCiTable = () => wrapper.findComponent(GlTable); + const findCiSettings = () => wrapper.findComponent(ciVariableSettings); + + // eslint-disable-next-line consistent-return + const createComponentWithApollo = async ({ isLoading = false } = {}) => { + const handlers = [ + [getProjectEnvironments, mockEnvironments], + [getProjectVariables, mockVariables], + ]; + + mockApollo = createMockApollo(handlers, resolvers); + + wrapper = shallowMount(ciProjectVariables, { + provide: mockProvide, + apolloProvider: mockApollo, + stubs: { ciVariableSettings, ciVariableTable }, + }); + + if (!isLoading) { + return waitForPromises(); + } + }; + + beforeEach(() => { + mockEnvironments = jest.fn(); + mockVariables = jest.fn(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('while queries are being fetch', () => { + beforeEach(() => { + createComponentWithApollo({ isLoading: true }); + }); + + it('shows a loading icon', () => { + expect(findLoadingIcon().exists()).toBe(true); + expect(findCiTable().exists()).toBe(false); + }); + }); + + describe('when queries are resolved', () => { + describe('successfuly', () => { + beforeEach(async () => { + mockEnvironments.mockResolvedValue(mockProjectEnvironments); + mockVariables.mockResolvedValue(mockProjectVariables); + + await createComponentWithApollo(); + }); + + it('passes down the expected environments as props', () => { + expect(findCiSettings().props('environments')).toEqual([prodName, devName]); + }); + + it('passes down the expected variables as props', () => { + expect(findCiSettings().props('variables')).toEqual( + mockProjectVariables.data.project.ciVariables.nodes, + ); + }); + + it('createFlash was not called', () => { + expect(createFlash).not.toHaveBeenCalled(); + }); + }); + + describe('with an error for variables', () => { + beforeEach(async () => { + mockEnvironments.mockResolvedValue(mockProjectEnvironments); + mockVariables.mockRejectedValue(); + + await createComponentWithApollo(); + }); + + it('calls createFlash with the expected error message', () => { + expect(createFlash).toHaveBeenCalledWith({ message: variableFetchErrorText }); + }); + }); + + describe('with an error for environments', () => { + beforeEach(async () => { + mockEnvironments.mockRejectedValue(); + mockVariables.mockResolvedValue(mockProjectVariables); + + await createComponentWithApollo(); + }); + + it('calls createFlash with the expected error message', () => { + expect(createFlash).toHaveBeenCalledWith({ message: environmentFetchErrorText }); + }); + }); + }); + + describe('mutations', () => { + beforeEach(async () => { + mockEnvironments.mockResolvedValue(mockProjectEnvironments); + mockVariables.mockResolvedValue(mockProjectVariables); + + await createComponentWithApollo(); + }); + it.each` + actionName | mutation | event + ${'add'} | ${addProjectVariable} | ${'add-variable'} + ${'update'} | ${updateProjectVariable} | ${'update-variable'} + ${'delete'} | ${deleteProjectVariable} | ${'delete-variable'} + `( + 'calls the right mutation when user performs $actionName variable', + async ({ event, mutation }) => { + jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(); + await findCiSettings().vm.$emit(event, newVariable); + + expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({ + mutation, + variables: { + endpoint: mockProvide.endpoint, + fullPath: mockProvide.projectFullPath, + projectId: convertToGraphQLId('Project', mockProvide.projectId), + variable: newVariable, + }, + }); + }, + ); + + it.each` + actionName | event | mutationName + ${'add'} | ${'add-variable'} | ${'addProjectVariable'} + ${'update'} | ${'update-variable'} | ${'updateProjectVariable'} + ${'delete'} | ${'delete-variable'} | ${'deleteProjectVariable'} + `( + 'throws with the specific graphql error if present when user performs $actionName variable', + async ({ event, mutationName }) => { + const graphQLErrorMessage = 'There is a problem with this graphQL action'; + jest + .spyOn(wrapper.vm.$apollo, 'mutate') + .mockResolvedValue({ data: { [mutationName]: { errors: [graphQLErrorMessage] } } }); + await findCiSettings().vm.$emit(event, newVariable); + await nextTick(); + + expect(wrapper.vm.$apollo.mutate).toHaveBeenCalled(); + expect(createFlash).toHaveBeenCalledWith({ message: graphQLErrorMessage }); + }, + ); + + it.each` + actionName | event + ${'add'} | ${'add-variable'} + ${'update'} | ${'update-variable'} + ${'delete'} | ${'delete-variable'} + `( + 'throws generic error when the mutation fails with no graphql errors and user performs $actionName variable', + async ({ event }) => { + jest.spyOn(wrapper.vm.$apollo, 'mutate').mockImplementationOnce(() => { + throw new Error(); + }); + await findCiSettings().vm.$emit(event, newVariable); + + expect(wrapper.vm.$apollo.mutate).toHaveBeenCalled(); + expect(createFlash).toHaveBeenCalledWith({ message: genericMutationErrorText }); + }, + ); + }); +}); diff --git a/spec/frontend/ci_variable_list/mocks.js b/spec/frontend/ci_variable_list/mocks.js index 89ba77858dc..b030005cb8d 100644 --- a/spec/frontend/ci_variable_list/mocks.js +++ b/spec/frontend/ci_variable_list/mocks.js @@ -1,4 +1,9 @@ -import { variableTypes, groupString, instanceString } from '~/ci_variable_list/constants'; +import { + variableTypes, + groupString, + instanceString, + projectString, +} from '~/ci_variable_list/constants'; export const devName = 'dev'; export const prodName = 'prod'; @@ -77,7 +82,7 @@ export const mockProjectVariables = { project: { __typename: 'Project', id: 1, - ciVariables: createDefaultVars(), + ciVariables: createDefaultVars({ kind: projectString }), }, }, }; diff --git a/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js index 6bb718082a4..8dbee9b370c 100644 --- a/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js @@ -12,8 +12,8 @@ describe('MR Widget App', () => { }); }; - it('mounts the component', () => { + it('does not mount if widgets array is empty', () => { createComponent(); - expect(wrapper.findByTestId('mr-widget-app').exists()).toBe(true); + expect(wrapper.findByTestId('mr-widget-app').exists()).toBe(false); }); }); diff --git a/spec/helpers/storage_helper_spec.rb b/spec/helpers/storage_helper_spec.rb index 6c3556c874b..e0628fe9235 100644 --- a/spec/helpers/storage_helper_spec.rb +++ b/spec/helpers/storage_helper_spec.rb @@ -53,8 +53,8 @@ RSpec.describe StorageHelper do describe "storage_enforcement_banner" do let_it_be_with_refind(:current_user) { create(:user) } - let_it_be(:free_group) { create(:group) } - let_it_be(:paid_group) { create(:group) } + let_it_be(:free_group) { create(:group, :with_root_storage_statistics) } + let_it_be(:paid_group) { create(:group, :with_root_storage_statistics) } before do allow(helper).to receive(:can?).with(current_user, :maintainer_access, free_group).and_return(true) @@ -62,6 +62,9 @@ RSpec.describe StorageHelper do allow(helper).to receive(:current_user) { current_user } allow(paid_group).to receive(:paid?).and_return(true) + free_group.root_storage_statistics.update!(storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE) + paid_group.root_storage_statistics.update!(storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE) + stub_feature_flags(namespace_storage_limit_bypass_date_check: false) end @@ -110,13 +113,13 @@ RSpec.describe StorageHelper do }) end - context 'when namespace has used storage' do + context 'when namespace is under MIN_STORAGE_ENFORCEMENT_USAGE limit' do before do - create(:namespace_root_storage_statistics, namespace: free_group, storage_size: 102400) + free_group.root_storage_statistics.update!(storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE - 1) end - it 'returns a hash with the correct storage size text' do - expect(helper.storage_enforcement_banner_info(free_group)[:text_paragraph_2]).to eql("The namespace is currently using <strong>100 KB</strong> of namespace storage. Group owners can view namespace storage usage and purchase more from <strong>Group settings > Usage quotas</strong>. <a href=\"/help/user/usage_quotas#manage-your-storage-usage\" >Learn more.</a>") + it 'returns nil' do + expect(helper.storage_enforcement_banner_info(free_group)).to be(nil) end end @@ -141,7 +144,6 @@ RSpec.describe StorageHelper do end it 'returns the enforcement info' do - puts helper.storage_enforcement_banner_info(free_group)[:text_paragraph_1] expect(helper.storage_enforcement_banner_info(free_group)[:text_paragraph_1]).to include("Effective #{Date.current}, namespace storage limits will apply") end end |