diff --git a/ee/app/assets/javascripts/vulnerabilities/components/explain_vulnerability/explain_vulnerability.vue b/ee/app/assets/javascripts/vulnerabilities/components/explain_vulnerability/explain_vulnerability.vue index 0682c3bc99235e48c807dab3b60da446ae620651..476fec6947b2cd13950abbdc7b4087cea505a43b 100644 --- a/ee/app/assets/javascripts/vulnerabilities/components/explain_vulnerability/explain_vulnerability.vue +++ b/ee/app/assets/javascripts/vulnerabilities/components/explain_vulnerability/explain_vulnerability.vue @@ -4,8 +4,7 @@ import { s__ } from '~/locale'; import { helpPagePath } from '~/helpers/help_page_helper'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import { TYPENAME_VULNERABILITY } from '~/graphql_shared/constants'; -import chatMutation from 'ee/ai/graphql/chat.mutation.graphql'; -import { duoChatGlobalState } from '~/super_sidebar/constants'; +import { sendDuoChatCommand } from 'ee/ai/utils'; export default { components: { @@ -28,14 +27,9 @@ export default { }, methods: { triggerDuoChat() { - duoChatGlobalState.isShown = true; - - this.$apollo.mutate({ - mutation: chatMutation, - variables: { - question: '/vulnerability_explain', - resourceId: this.vulnerabilityGraphqlId, - }, + sendDuoChatCommand({ + question: '/vulnerability_explain', + resourceId: this.vulnerabilityGraphqlId, }); }, }, diff --git a/ee/app/assets/javascripts/vulnerabilities/components/header.vue b/ee/app/assets/javascripts/vulnerabilities/components/header.vue index 36d415fe45b86ef0d3cb224b549aba57dba49172..63d719c98fc013b8e026aa9773fc587a2a2b134c 100644 --- a/ee/app/assets/javascripts/vulnerabilities/components/header.vue +++ b/ee/app/assets/javascripts/vulnerabilities/components/header.vue @@ -3,6 +3,7 @@ import { GlLoadingIcon, GlTooltipDirective as GlTooltip } from '@gitlab/ui'; import { v4 as uuidv4 } from 'uuid'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glAbilitiesMixin from '~/vue_shared/mixins/gl_abilities_mixin'; +import { sendDuoChatCommand } from 'ee/ai/utils'; import vulnerabilityStateMutations from 'ee/security_dashboard/graphql/mutate_vulnerability_state'; import StatusBadge from 'ee/vue_shared/security_reports/components/status_badge.vue'; import { createAlert } from '~/alert'; @@ -14,8 +15,6 @@ import download from '~/lib/utils/downloader'; import { visitUrl } from '~/lib/utils/url_utility'; import UsersCache from '~/lib/utils/users_cache'; import { __, s__ } from '~/locale'; -import { duoChatGlobalState } from '~/super_sidebar/constants'; -import chatMutation from 'ee/ai/graphql/chat.mutation.graphql'; import aiResponseSubscription from 'ee/graphql_shared/subscriptions/ai_completion_response.subscription.graphql'; import aiResolveVulnerability from '../graphql/ai_resolve_vulnerability.mutation.graphql'; import { @@ -247,14 +246,9 @@ export default { } }, explainVulnerability() { - duoChatGlobalState.isShown = true; - - this.$apollo.mutate({ - mutation: chatMutation, - variables: { - question: '/vulnerability_explain', - resourceId: this.vulnerabilityGraphqlId, - }, + sendDuoChatCommand({ + question: '/vulnerability_explain', + resourceId: this.vulnerabilityGraphqlId, }); }, resolveVulnerability() { diff --git a/ee/spec/frontend/vulnerabilities/explain_vulnerability/explain_vulnerability_spec.js b/ee/spec/frontend/vulnerabilities/explain_vulnerability/explain_vulnerability_spec.js index b70692826329c0e0300e3502c1f9e03fe939452b..0a741804615c10bd66a0c3dee7aa7159316026da 100644 --- a/ee/spec/frontend/vulnerabilities/explain_vulnerability/explain_vulnerability_spec.js +++ b/ee/spec/frontend/vulnerabilities/explain_vulnerability/explain_vulnerability_spec.js @@ -2,11 +2,11 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; import { GlLink, GlSprintf } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import * as utils from 'ee/ai/utils'; import ExplainVulnerability from 'ee/vulnerabilities/components/explain_vulnerability/explain_vulnerability.vue'; -import { duoChatGlobalState } from '~/super_sidebar/constants'; -import chatMutation from 'ee/ai/graphql/chat.mutation.graphql'; -import createMockApollo from 'helpers/mock_apollo_helper'; -import { MOCK_TANUKI_BOT_MUTATATION_RES } from 'ee_jest/ai/tanuki_bot/mock_data'; + +jest.mock('ee/ai/utils'); +jest.spyOn(utils, 'sendDuoChatCommand'); Vue.use(VueApollo); @@ -15,17 +15,12 @@ const MOCK_VULNERABILITY_ID = 1; describe('Explain Vulnerability component', () => { let wrapper; - const chatMutationHandlerMock = jest.fn().mockResolvedValue(MOCK_TANUKI_BOT_MUTATATION_RES); - const createWrapper = () => { - const apolloProvider = createMockApollo([[chatMutation, chatMutationHandlerMock]]); - wrapper = shallowMountExtended(ExplainVulnerability, { propsData: { vulnerabilityId: MOCK_VULNERABILITY_ID }, stubs: { GlSprintf, }, - apolloProvider, }); }; @@ -65,20 +60,12 @@ describe('Explain Vulnerability component', () => { }); describe('when the "Explain vulnerability" button is clicked', () => { - it('opens the global DuoChat drawer', () => { - expect(duoChatGlobalState.isShown).toBe(false); - - clickExplainVulnerabilityButton(); - - expect(duoChatGlobalState.isShown).toBe(true); - }); - - it('calls a custom chat mutation with the correct prompt and resource-id', () => { - expect(chatMutationHandlerMock).not.toHaveBeenCalled(); + it('calls sendDuoChatCommand with correct prompt and resource-id', () => { + expect(utils.sendDuoChatCommand).not.toHaveBeenCalled(); clickExplainVulnerabilityButton(); - expect(chatMutationHandlerMock).toHaveBeenCalledWith({ + expect(utils.sendDuoChatCommand).toHaveBeenCalledWith({ question: '/vulnerability_explain', resourceId: `gid://gitlab/Vulnerability/${MOCK_VULNERABILITY_ID}`, }); diff --git a/ee/spec/frontend/vulnerabilities/header_spec.js b/ee/spec/frontend/vulnerabilities/header_spec.js index 8426b7f980d64d1506c6bc76e73b04d6303fb6a3..a9a417e1ab8ff88c9ffc91dc4cac6f65990eedd4 100644 --- a/ee/spec/frontend/vulnerabilities/header_spec.js +++ b/ee/spec/frontend/vulnerabilities/header_spec.js @@ -5,6 +5,7 @@ import MockAdapter from 'axios-mock-adapter'; import VueApollo from 'vue-apollo'; import { createMockSubscription } from 'mock-apollo-client'; import { createMockDirective } from 'helpers/vue_mock_directive'; +import * as aiUtils from 'ee/ai/utils'; import aiResponseSubscription from 'ee/graphql_shared/subscriptions/ai_completion_response.subscription.graphql'; import aiResolveVulnerability from 'ee/vulnerabilities/graphql/ai_resolve_vulnerability.mutation.graphql'; import Api from 'ee/api'; @@ -25,9 +26,6 @@ import { convertObjectPropsToSnakeCase } from '~/lib/utils/common_utils'; import download from '~/lib/utils/downloader'; import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status'; import { visitUrl } from '~/lib/utils/url_utility'; -import chatMutation from 'ee/ai/graphql/chat.mutation.graphql'; -import { MOCK_TANUKI_BOT_MUTATATION_RES } from 'ee_jest/ai/tanuki_bot/mock_data'; -import { duoChatGlobalState } from '~/super_sidebar/constants'; import { getVulnerabilityStatusMutationResponse, dismissalDescriptions, @@ -51,6 +49,8 @@ jest.mock('~/lib/utils/url_utility', () => ({ ...jest.requireActual('~/lib/utils/url_utility'), visitUrl: jest.fn(), })); +jest.mock('ee/ai/utils'); +jest.spyOn(aiUtils, 'sendDuoChatCommand'); describe('Vulnerability Header', () => { let wrapper; @@ -637,18 +637,11 @@ describe('Vulnerability Header', () => { }); describe('explain with AI button', () => { - let chatMutationHandlerMock; - const findExplainWithAIButton = () => findSplitButton().props('buttons')[1]; beforeEach(() => { - chatMutationHandlerMock = jest.fn().mockResolvedValue(MOCK_TANUKI_BOT_MUTATATION_RES); - - const apolloProvider = createApolloProvider([chatMutation, chatMutationHandlerMock]); - createWrapper({ vulnerability: getVulnerability(), - apolloProvider, }); }); @@ -662,19 +655,13 @@ describe('Vulnerability Header', () => { }); }); - it('opens the global DuoChat drawer when clicked', async () => { - expect(duoChatGlobalState.isShown).toBe(false); - - await clickButton('explain-vulnerability'); - - expect(duoChatGlobalState.isShown).toBe(true); - }); + it('calls sendDuoChatCommand with the correct parameters when clicked', async () => { + expect(aiUtils.sendDuoChatCommand).not.toHaveBeenCalled(); - it('calls the correct mutation with the correct parameters when clicked', async () => { await clickButton('explain-vulnerability'); await waitForPromises(); - expect(chatMutationHandlerMock).toHaveBeenCalledWith({ + expect(aiUtils.sendDuoChatCommand).toHaveBeenCalledWith({ question: '/vulnerability_explain', resourceId: `gid://gitlab/Vulnerability/${defaultVulnerability.id}`, });