diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-16 03:10:37 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-16 03:10:37 +0300 |
commit | 84025108bca604c1428d2cf6a6b69616ee90956c (patch) | |
tree | 7c0fd8ec032c12bee563daeee6c721e2d7f7d44f /spec/frontend | |
parent | 73778b9c53d13a2e06a693c30073366deedead8f (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
10 files changed, 291 insertions, 23 deletions
diff --git a/spec/frontend/admin/abuse_report/components/notes/abuse_report_note_spec.js b/spec/frontend/admin/abuse_report/components/notes/abuse_report_note_spec.js index f0174cd7b4a..bc7aa8ef5de 100644 --- a/spec/frontend/admin/abuse_report/components/notes/abuse_report_note_spec.js +++ b/spec/frontend/admin/abuse_report/components/notes/abuse_report_note_spec.js @@ -93,6 +93,26 @@ describe('Abuse Report Note', () => { }); describe('Editing', () => { + it('should show edit button when resolveNote is true', () => { + createComponent({ + note: { ...mockNote, userPermissions: { resolveNote: true } }, + }); + + expect(findNoteActions().props()).toMatchObject({ + showEditButton: true, + }); + }); + + it('should not show edit button when resolveNote is false', () => { + createComponent({ + note: { ...mockNote, userPermissions: { resolveNote: false } }, + }); + + expect(findNoteActions().props()).toMatchObject({ + showEditButton: false, + }); + }); + it('should not be in edit mode by default', () => { expect(findEditNote().exists()).toBe(false); }); @@ -164,16 +184,14 @@ describe('Abuse Report Note', () => { }); }); - describe('Actions', () => { - it('should show note actions', () => { - expect(findNoteActions().exists()).toBe(true); + describe('Replying', () => { + it('should show reply button', () => { expect(findNoteActions().props()).toMatchObject({ - showReplyButton: mockShowReplyButton, - showEditButton: true, + showReplyButton: true, }); }); - it('should emit `startReplying`', () => { + it('should bubble up `startReplying` event', () => { findNoteActions().vm.$emit('startReplying'); expect(wrapper.emitted('startReplying')).toHaveLength(1); diff --git a/spec/frontend/admin/abuse_report/mock_data.js b/spec/frontend/admin/abuse_report/mock_data.js index a958c4d30b1..9790b44c976 100644 --- a/spec/frontend/admin/abuse_report/mock_data.js +++ b/spec/frontend/admin/abuse_report/mock_data.js @@ -153,7 +153,7 @@ export const mockDiscussionWithNoReplies = [ }, lastEditedBy: null, userPermissions: { - adminNote: true, + resolveNote: true, __typename: 'NotePermissions', }, discussion: { @@ -192,7 +192,7 @@ export const mockDiscussionWithReplies = [ }, lastEditedBy: null, userPermissions: { - adminNote: true, + resolveNote: true, __typename: 'NotePermissions', }, discussion: { @@ -237,7 +237,7 @@ export const mockDiscussionWithReplies = [ }, lastEditedBy: null, userPermissions: { - adminNote: true, + resolveNote: true, __typename: 'NotePermissions', }, discussion: { @@ -282,7 +282,7 @@ export const mockDiscussionWithReplies = [ }, lastEditedBy: null, userPermissions: { - adminNote: true, + resolveNote: true, __typename: 'NotePermissions', }, discussion: { @@ -368,7 +368,7 @@ export const createAbuseReportNoteResponse = { }, lastEditedBy: null, userPermissions: { - adminNote: true, + resolveNote: true, }, discussion: { id: 'gid://gitlab/Discussion/90ca230051611e6e1676c50ba7178e0baeabd98d', @@ -413,7 +413,7 @@ export const editAbuseReportNoteResponse = { }, lastEditedBy: 'root', userPermissions: { - adminNote: true, + resolveNote: true, __typename: 'NotePermissions', }, }, diff --git a/spec/frontend/deploy_keys/graphql/resolvers_spec.js b/spec/frontend/deploy_keys/graphql/resolvers_spec.js new file mode 100644 index 00000000000..458232697cb --- /dev/null +++ b/spec/frontend/deploy_keys/graphql/resolvers_spec.js @@ -0,0 +1,249 @@ +import MockAdapter from 'axios-mock-adapter'; +import { HTTP_STATUS_OK, HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status'; +import axios from '~/lib/utils/axios_utils'; +import pageInfoQuery from '~/graphql_shared/client/page_info.query.graphql'; +import currentPageQuery from '~/deploy_keys/graphql/queries/current_page.query.graphql'; +import currentScopeQuery from '~/deploy_keys/graphql/queries/current_scope.query.graphql'; +import confirmRemoveKeyQuery from '~/deploy_keys/graphql/queries/confirm_remove_key.query.graphql'; +import { resolvers } from '~/deploy_keys/graphql/resolvers'; + +const ENDPOINTS = { + enabledKeysEndpoint: '/enabled_keys', + availableProjectKeysEndpoint: '/available_project_keys', + availablePublicKeysEndpoint: '/available_public_keys', +}; + +describe('~/deploy_keys/graphql/resolvers', () => { + let mockResolvers; + let mock; + let client; + + beforeEach(() => { + mockResolvers = resolvers(ENDPOINTS); + mock = new MockAdapter(axios); + client = { + writeQuery: jest.fn(), + readQuery: jest.fn(), + readFragment: jest.fn(), + cache: { evict: jest.fn(), gc: jest.fn() }, + }; + }); + + afterEach(() => { + mock.reset(); + }); + + describe('deployKeys', () => { + const key = { id: 1, title: 'hello', edit_path: '/edit' }; + + it.each(['enabledKeys', 'availableProjectKeys', 'availablePublicKeys'])( + 'should request the endpoint for the %s scope', + async (scope) => { + mock.onGet(ENDPOINTS[`${scope}Endpoint`]).reply(HTTP_STATUS_OK, { keys: [key] }); + + const keys = await mockResolvers.Project.deployKeys(null, { scope, page: 1 }, { client }); + + expect(keys).toEqual([ + { id: 1, title: 'hello', editPath: '/edit', __typename: 'LocalDeployKey' }, + ]); + }, + ); + + it('should default to enabled keys if a bad scope is given', async () => { + const scope = 'bad'; + mock.onGet(ENDPOINTS.enabledKeysEndpoint).reply(HTTP_STATUS_OK, { keys: [key] }); + + const keys = await mockResolvers.Project.deployKeys(null, { scope, page: 1 }, { client }); + + expect(keys).toEqual([ + { id: 1, title: 'hello', editPath: '/edit', __typename: 'LocalDeployKey' }, + ]); + }); + + it('should request the given page', async () => { + const scope = 'enabledKeys'; + const page = 2; + mock + .onGet(ENDPOINTS.enabledKeysEndpoint, { params: { page } }) + .reply(HTTP_STATUS_OK, { keys: [key] }); + + const keys = await mockResolvers.Project.deployKeys(null, { scope, page }, { client }); + + expect(keys).toEqual([ + { id: 1, title: 'hello', editPath: '/edit', __typename: 'LocalDeployKey' }, + ]); + }); + + it('should write pagination info to the cache', async () => { + const scope = 'enabledKeys'; + const page = 1; + + mock.onGet(ENDPOINTS.enabledKeysEndpoint).reply( + HTTP_STATUS_OK, + { keys: [key] }, + { + 'x-next-page': '2', + 'x-page': '1', + 'X-Per-Page': '2', + 'X-Prev-Page': '', + 'X-TOTAL': '37', + 'X-Total-Pages': '5', + }, + ); + + await mockResolvers.Project.deployKeys(null, { scope, page }, { client }); + + expect(client.writeQuery).toHaveBeenCalledWith({ + query: pageInfoQuery, + variables: { input: { scope, page } }, + data: { + pageInfo: { + total: 37, + perPage: 2, + previousPage: NaN, + totalPages: 5, + nextPage: 2, + page: 1, + __typename: 'LocalPageInfo', + }, + }, + }); + }); + + it('should not write page info if the request fails', async () => { + const scope = 'enabledKeys'; + const page = 1; + + mock.onGet(ENDPOINTS.enabledKeysEndpoint).reply(HTTP_STATUS_NOT_FOUND); + + try { + await mockResolvers.Project.deployKeys(null, { scope, page }, { client }); + } catch { + expect(client.writeQuery).not.toHaveBeenCalled(); + } + }); + }); + + describe('currentPage', () => { + it('sets the current page', () => { + const page = 5; + mockResolvers.Mutation.currentPage(null, { page }, { client }); + + expect(client.writeQuery).toHaveBeenCalledWith({ + query: currentPageQuery, + data: { currentPage: page }, + }); + }); + }); + + describe('currentScope', () => { + let scope; + + beforeEach(() => { + scope = 'enabledKeys'; + mockResolvers.Mutation.currentScope(null, { scope }, { client }); + }); + + it('sets the current scope', () => { + expect(client.writeQuery).toHaveBeenCalledWith({ + query: currentScopeQuery, + data: { currentScope: scope }, + }); + }); + + it('resets the page to 1', () => { + expect(client.writeQuery).toHaveBeenCalledWith({ + query: currentPageQuery, + data: { currentPage: 1 }, + }); + }); + }); + + describe('disableKey', () => { + it('disables the key that is pending confirmation', async () => { + const key = { id: 1, title: 'hello', disablePath: '/disable', __typename: 'LocalDeployKey' }; + client.readQuery.mockReturnValue({ deployKeyToRemove: key }); + client.readFragment.mockReturnValue(key); + mock.onPut(key.disablePath).reply(HTTP_STATUS_OK); + await mockResolvers.Mutation.disableKey(null, null, { client }); + + expect(client.readQuery).toHaveBeenCalledWith({ query: confirmRemoveKeyQuery }); + expect(client.readFragment).toHaveBeenCalledWith( + expect.objectContaining({ id: `LocalDeployKey:${key.id}` }), + ); + expect(client.cache.evict).toHaveBeenCalledWith({ fieldName: 'deployKeyToRemove' }); + expect(client.cache.evict).toHaveBeenCalledWith({ id: `LocalDeployKey:${key.id}` }); + expect(client.cache.gc).toHaveBeenCalled(); + }); + + it('does not remove the key from the cache on fail', async () => { + const key = { id: 1, title: 'hello', disablePath: '/disable', __typename: 'LocalDeployKey' }; + client.readQuery.mockReturnValue({ deployKeyToRemove: key }); + client.readFragment.mockReturnValue(key); + mock.onPut(key.disablePath).reply(HTTP_STATUS_NOT_FOUND); + + try { + await mockResolvers.Mutation.disableKey(null, null, { client }); + } catch { + expect(client.readQuery).toHaveBeenCalledWith({ query: confirmRemoveKeyQuery }); + expect(client.readFragment).toHaveBeenCalledWith( + expect.objectContaining({ id: `LocalDeployKey:${key.id}` }), + ); + expect(client.cache.evict).not.toHaveBeenCalled(); + expect(client.cache.gc).not.toHaveBeenCalled(); + } + }); + }); + + describe('enableKey', () => { + it("calls the key's enable path", async () => { + const key = { id: 1, title: 'hello', enablePath: '/enable', __typename: 'LocalDeployKey' }; + client.readQuery.mockReturnValue({ deployKeyToRemove: key }); + client.readFragment.mockReturnValue(key); + mock.onPut(key.enablePath).reply(HTTP_STATUS_OK); + await mockResolvers.Mutation.enableKey(null, key, { client }); + + expect(client.readFragment).toHaveBeenCalledWith( + expect.objectContaining({ id: `LocalDeployKey:${key.id}` }), + ); + expect(client.cache.evict).toHaveBeenCalledWith({ id: `LocalDeployKey:${key.id}` }); + expect(client.cache.gc).toHaveBeenCalled(); + }); + + it('does not remove the key from the cache on failure', async () => { + const key = { id: 1, title: 'hello', enablePath: '/enable', __typename: 'LocalDeployKey' }; + client.readQuery.mockReturnValue({ deployKeyToRemove: key }); + client.readFragment.mockReturnValue(key); + mock.onPut(key.enablePath).reply(HTTP_STATUS_NOT_FOUND); + try { + await mockResolvers.Mutation.enableKey(null, key, { client }); + } catch { + expect(client.readFragment).toHaveBeenCalledWith( + expect.objectContaining({ id: `LocalDeployKey:${key.id}` }), + ); + expect(client.cache.evict).not.toHaveBeenCalled(); + expect(client.cache.gc).not.toHaveBeenCalled(); + } + }); + }); + + describe('confirmDisable', () => { + it('sets the key to disable', () => { + const key = { id: 1, title: 'hello', enablePath: '/enable', __typename: 'LocalDeployKey' }; + mockResolvers.Mutation.confirmDisable(null, key, { client }); + + expect(client.writeQuery).toHaveBeenCalledWith({ + query: confirmRemoveKeyQuery, + data: { deployKeyToRemove: { id: key.id, __type: 'LocalDeployKey' } }, + }); + }); + it('clears the value when null id is passed', () => { + mockResolvers.Mutation.confirmDisable(null, { id: null }, { client }); + + expect(client.writeQuery).toHaveBeenCalledWith({ + query: confirmRemoveKeyQuery, + data: { deployKeyToRemove: null }, + }); + }); + }); +}); diff --git a/spec/frontend/environments/graphql/resolvers/base_spec.js b/spec/frontend/environments/graphql/resolvers/base_spec.js index f78146fe48e..939ccc0780c 100644 --- a/spec/frontend/environments/graphql/resolvers/base_spec.js +++ b/spec/frontend/environments/graphql/resolvers/base_spec.js @@ -9,7 +9,7 @@ import environmentToStopQuery from '~/environments/graphql/queries/environment_t import createMockApollo from 'helpers/mock_apollo_helper'; import pollIntervalQuery from '~/environments/graphql/queries/poll_interval.query.graphql'; import isEnvironmentStoppingQuery from '~/environments/graphql/queries/is_environment_stopping.query.graphql'; -import pageInfoQuery from '~/environments/graphql/queries/page_info.query.graphql'; +import pageInfoQuery from '~/graphql_shared/client/page_info.query.graphql'; import { TEST_HOST } from 'helpers/test_constants'; import { environmentsApp, diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js index 364fe733a41..94d888bb067 100644 --- a/spec/frontend/security_configuration/components/app_spec.js +++ b/spec/frontend/security_configuration/components/app_spec.js @@ -5,10 +5,10 @@ import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser'; import stubChildren from 'helpers/stub_children'; import { mountExtended } from 'helpers/vue_test_utils_helper'; -import SecurityConfigurationApp, { i18n } from '~/security_configuration/components/app.vue'; +import SecurityConfigurationApp from '~/security_configuration/components/app.vue'; import AutoDevopsAlert from '~/security_configuration/components/auto_dev_ops_alert.vue'; import AutoDevopsEnabledAlert from '~/security_configuration/components/auto_dev_ops_enabled_alert.vue'; -import { AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY } from '~/security_configuration/components/constants'; +import { AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY } from '~/security_configuration/constants'; import FeatureCard from '~/security_configuration/components/feature_card.vue'; import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue'; import { securityFeaturesMock, provideMock } from '../mock_data'; @@ -19,6 +19,8 @@ const { vulnerabilityTrainingDocsPath, projectFullPath } = provideMock; useLocalStorageSpy(); Vue.use(VueApollo); +const { i18n } = SecurityConfigurationApp; + describe('~/security_configuration/components/app', () => { let wrapper; let userCalloutDismissSpy; diff --git a/spec/frontend/security_configuration/components/feature_card_spec.js b/spec/frontend/security_configuration/components/feature_card_spec.js index 983a66a7fd3..9efee2a409a 100644 --- a/spec/frontend/security_configuration/components/feature_card_spec.js +++ b/spec/frontend/security_configuration/components/feature_card_spec.js @@ -1,7 +1,7 @@ import { GlIcon } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; -import { securityFeatures } from '~/security_configuration/components/constants'; +import { securityFeatures } from '~/security_configuration/constants'; import FeatureCard from '~/security_configuration/components/feature_card.vue'; import FeatureCardBadge from '~/security_configuration/components/feature_card_badge.vue'; import ManageViaMr from '~/vue_shared/security_configuration/components/manage_via_mr.vue'; diff --git a/spec/frontend/security_configuration/components/training_provider_list_spec.js b/spec/frontend/security_configuration/components/training_provider_list_spec.js index 5b2b3f46df6..ef20d8f56a4 100644 --- a/spec/frontend/security_configuration/components/training_provider_list_spec.js +++ b/spec/frontend/security_configuration/components/training_provider_list_spec.js @@ -19,8 +19,8 @@ import { TRACK_TOGGLE_TRAINING_PROVIDER_LABEL, TRACK_PROVIDER_LEARN_MORE_CLICK_ACTION, TRACK_PROVIDER_LEARN_MORE_CLICK_LABEL, + TEMP_PROVIDER_URLS, } from '~/security_configuration/constants'; -import { TEMP_PROVIDER_URLS } from '~/security_configuration/components/constants'; import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue'; import { updateSecurityTrainingOptimisticResponse } from '~/security_configuration/graphql/cache_utils'; import securityTrainingProvidersQuery from '~/security_configuration/graphql/security_training_providers.query.graphql'; @@ -61,10 +61,9 @@ const TEMP_PROVIDER_LOGOS = { svg: '<svg>Secure Code Warrior</svg>', }, }; -jest.mock('~/security_configuration/components/constants', () => { +jest.mock('~/security_configuration/constants', () => { return { - TEMP_PROVIDER_URLS: jest.requireActual('~/security_configuration/components/constants') - .TEMP_PROVIDER_URLS, + TEMP_PROVIDER_URLS: jest.requireActual('~/security_configuration/constants').TEMP_PROVIDER_URLS, // NOTE: Jest hoists all mocks to the top so we can't use TEMP_PROVIDER_LOGOS // here directly. TEMP_PROVIDER_LOGOS: { diff --git a/spec/frontend/security_configuration/mock_data.js b/spec/frontend/security_configuration/mock_data.js index df10d33e2f0..208256afdbd 100644 --- a/spec/frontend/security_configuration/mock_data.js +++ b/spec/frontend/security_configuration/mock_data.js @@ -4,7 +4,7 @@ import { SAST_DESCRIPTION, SAST_HELP_PATH, SAST_CONFIG_HELP_PATH, -} from '~/security_configuration/components/constants'; +} from '~/security_configuration/constants'; import { REPORT_TYPE_SAST } from '~/vue_shared/security_reports/constants'; export const testProjectPath = 'foo/bar'; diff --git a/spec/frontend/security_configuration/utils_spec.js b/spec/frontend/security_configuration/utils_spec.js index ea04e9e7993..3c6d4baa30f 100644 --- a/spec/frontend/security_configuration/utils_spec.js +++ b/spec/frontend/security_configuration/utils_spec.js @@ -1,5 +1,5 @@ import { augmentFeatures, translateScannerNames } from '~/security_configuration/utils'; -import { SCANNER_NAMES_MAP } from '~/security_configuration/components/constants'; +import { SCANNER_NAMES_MAP } from '~/security_configuration/constants'; describe('augmentFeatures', () => { const mockSecurityFeatures = [ diff --git a/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js b/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js index f3d0d66cdd1..2b36344cfa8 100644 --- a/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js +++ b/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js @@ -2,7 +2,7 @@ import { GlButton } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; -import { featureToMutationMap } from 'ee_else_ce/security_configuration/components/constants'; +import { featureToMutationMap } from 'ee_else_ce/security_configuration/constants'; import createMockApollo from 'helpers/mock_apollo_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; |