diff --git a/x-pack/solutions/security/packages/connectors/src/connector_selector.test.tsx b/x-pack/solutions/security/packages/connectors/src/connector_selector.test.tsx
new file mode 100644
index 0000000000000..a389634081ea6
--- /dev/null
+++ b/x-pack/solutions/security/packages/connectors/src/connector_selector.test.tsx
@@ -0,0 +1,86 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react';
+import { ConnectorSelector } from './connector_selector';
+
+const testSubj = 'connector-selector';
+
+describe('ConnectorSelector', () => {
+ const mockOnChange = jest.fn();
+ const mockOnNewConnectorClicked = jest.fn();
+
+ const connectors = [
+ { id: '1', name: 'Connector One', description: 'First test connector' },
+ { id: '2', name: 'Connector Two', description: 'Second test connector' },
+ ];
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should render with provided connectors', () => {
+ const { getByTestId } = render(
+
+ );
+ expect(getByTestId(testSubj)).toBeInTheDocument();
+ });
+
+ it('should call onChange when a connector is selected', () => {
+ const { getByTestId } = render(
+
+ );
+
+ fireEvent.click(getByTestId(testSubj));
+ fireEvent.click(getByTestId('1'));
+
+ expect(mockOnChange).toHaveBeenCalledWith('1');
+ });
+
+ it('should show the add new connector option when onNewConnectorClicked is provided', () => {
+ const { getByTestId } = render(
+
+ );
+ fireEvent.click(getByTestId(testSubj));
+ expect(getByTestId('addNewConnectorButton')).toBeInTheDocument();
+ });
+
+ it('should call onNewConnectorClicked when add new connector is selected', () => {
+ const { getByTestId } = render(
+
+ );
+ fireEvent.click(getByTestId(testSubj));
+ fireEvent.click(getByTestId('addNewConnectorButton'));
+ expect(mockOnNewConnectorClicked).toHaveBeenCalled();
+ });
+
+ it('should disable selection when isDisabled is true', () => {
+ const { getByTestId } = render(
+
+ );
+ expect(getByTestId(testSubj)).toBeDisabled();
+ });
+
+ it('should render a button to add a new connector when no connectors exist', () => {
+ const { getByTestId } = render(
+
+ );
+ expect(getByTestId('addNewConnectorButton')).toBeInTheDocument();
+ });
+});
diff --git a/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_cards.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_cards.test.tsx
new file mode 100644
index 0000000000000..21be2f596728a
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_cards.test.tsx
@@ -0,0 +1,123 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { ConnectorCards } from './connector_cards';
+import { useLoadActionTypes } from '@kbn/elastic-assistant/impl/connectorland/use_load_action_types';
+import type { AIConnector } from './types';
+
+jest.mock('@kbn/elastic-assistant/impl/connectorland/use_load_action_types');
+jest.mock('@kbn/elastic-assistant/impl/connectorland/use_load_action_types', () => ({
+ useLoadActionTypes: jest.fn(),
+}));
+
+jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({
+ useKibana: () => ({
+ services: {
+ http: {
+ get: jest.fn(),
+ },
+ notifications: {
+ toasts: {
+ addDanger: jest.fn(),
+ addSuccess: jest.fn(),
+ },
+ },
+ triggersActionsUi: {
+ actionTypeRegistry: {
+ get: jest.fn(() => ({ iconClass: 'testIcon' })),
+ },
+ },
+ },
+ }),
+}));
+
+const mockConnectors: AIConnector[] = [
+ {
+ id: '1',
+ name: 'Connector 1',
+ actionTypeId: 'testType',
+ isPreconfigured: false,
+ isSystemAction: false,
+ isDeprecated: false,
+ config: {},
+ secrets: {},
+ },
+ {
+ id: '2',
+ name: 'Connector 2',
+ actionTypeId: 'testType',
+ isPreconfigured: false,
+ isSystemAction: false,
+ isDeprecated: false,
+ config: {},
+ secrets: {},
+ },
+];
+
+describe('ConnectorCards', () => {
+ beforeEach(() => {
+ (useLoadActionTypes as jest.Mock).mockReturnValue({
+ data: [
+ {
+ id: 'testType1',
+ name: 'Test Action 1',
+ enabled: true,
+ enabledInConfig: true,
+ enabledInLicense: true,
+ minimumLicenseRequired: 'basic',
+ supportedFeatureIds: ['alerting'],
+ isSystemActionType: false,
+ },
+ ],
+ isLoading: false,
+ error: null,
+ });
+ });
+
+ it('renders a loading spinner when connectors are not provided', () => {
+ render(
+
+ );
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
+ });
+
+ it('calls onConnectorSelected when a connector is selected', async () => {
+ const onConnectorSelected = jest.fn();
+ render(
+
+ );
+
+ await userEvent.click(screen.getByRole('button', { name: /Connector Selector/i }));
+ await userEvent.click(screen.getByText('Connector 1'));
+ expect(onConnectorSelected).toHaveBeenCalledWith(mockConnectors[0]);
+ });
+
+ it('shows missing privileges callout if user lacks privileges and has no connectors', () => {
+ render(
+
+ );
+ expect(screen.getByText('Missing privileges')).toBeInTheDocument();
+ });
+});
diff --git a/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_selector_panel.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_selector_panel.test.tsx
new file mode 100644
index 0000000000000..5c05ed008ad3c
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_selector_panel.test.tsx
@@ -0,0 +1,76 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { ConnectorSelectorPanel } from './connector_selector_panel';
+import type { AIConnector } from './types';
+
+const mockConnectors: AIConnector[] = [
+ {
+ id: '1',
+ name: 'Connector 1',
+ actionTypeId: 'testType',
+ isPreconfigured: false,
+ isSystemAction: false,
+ isDeprecated: false,
+ config: {},
+ secrets: {},
+ },
+ {
+ id: '2',
+ name: 'Connector 2',
+ actionTypeId: 'testType',
+ isPreconfigured: false,
+ isSystemAction: false,
+ isDeprecated: false,
+ config: {},
+ secrets: {},
+ },
+];
+
+const mockActionTypeRegistry = {
+ get: jest.fn(() => ({ iconClass: 'testIcon', name: 'Test Action' })),
+};
+
+jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({
+ useKibana: () => ({
+ services: { triggersActionsUi: { actionTypeRegistry: mockActionTypeRegistry } },
+ }),
+}));
+
+describe('ConnectorSelectorPanel', () => {
+ it('renders correctly', () => {
+ render();
+ expect(screen.getByText('Selected provider')).toBeInTheDocument();
+ });
+
+ it('preselects the only connector if there is one', () => {
+ const onConnectorSelected = jest.fn();
+ render(
+
+ );
+ expect(onConnectorSelected).toHaveBeenCalledWith(mockConnectors[0]);
+ });
+
+ it('calls onConnectorSelected when a connector is selected', async () => {
+ const onConnectorSelected = jest.fn();
+ render(
+
+ );
+ await userEvent.click(screen.getByRole('button', { name: /Connector Selector/i }));
+ await userEvent.click(screen.getByText('Connector 2'));
+ expect(onConnectorSelected).toHaveBeenCalledWith(mockConnectors[1]);
+ });
+});
diff --git a/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_setup.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_setup.test.tsx
new file mode 100644
index 0000000000000..b15ce466568f5
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_setup.test.tsx
@@ -0,0 +1,87 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { ConnectorSetup } from './connector_setup';
+import type { ActionType } from '@kbn/actions-plugin/common';
+import { useKibana } from '../../../../../../common/lib/kibana';
+
+jest.mock('../../../../../../common/lib/kibana', () => ({
+ useKibana: jest.fn(),
+}));
+
+jest.mock('@kbn/elastic-assistant/impl/connectorland/add_connector_modal', () => ({
+ AddConnectorModal: jest.fn(() =>
{'Mock Modal'}
),
+}));
+
+describe('ConnectorSetup', () => {
+ const mockActionTypeRegistry = {
+ get: jest.fn(() => ({ iconClass: 'testIcon' })),
+ };
+
+ const mockActionTypes: ActionType[] = [
+ {
+ id: 'testType1',
+ name: 'Test Action 1',
+ enabled: true,
+ enabledInConfig: true,
+ enabledInLicense: true,
+ minimumLicenseRequired: 'basic',
+ supportedFeatureIds: ['alerting'],
+ isSystemActionType: false,
+ },
+ {
+ id: 'testType2',
+ name: 'Test Action 2',
+ enabled: true,
+ enabledInConfig: true,
+ enabledInLicense: true,
+ minimumLicenseRequired: 'gold',
+ supportedFeatureIds: ['alerting'],
+ isSystemActionType: false,
+ },
+ ];
+
+ beforeEach(() => {
+ (useKibana as jest.Mock).mockReturnValue({
+ services: {
+ triggersActionsUi: { actionTypeRegistry: mockActionTypeRegistry },
+ },
+ });
+ });
+
+ it('renders correctly', () => {
+ render();
+
+ expect(mockActionTypeRegistry.get).toHaveBeenCalledWith('testType1');
+ expect(mockActionTypeRegistry.get).toHaveBeenCalledWith('testType2');
+
+ expect(screen.getByRole('button', { name: 'AI service provider' })).toBeInTheDocument();
+ });
+
+ it('opens the modal when the button is clicked', async () => {
+ render();
+
+ await userEvent.click(screen.getByRole('button', { name: 'AI service provider' }));
+
+ expect(screen.getByTestId('addConnectorModal')).toBeInTheDocument();
+ });
+
+ it('calls onConnectorSaved when a connector is saved', async () => {
+ const mockOnConnectorSaved = jest.fn();
+ render(
+
+ );
+ await userEvent.click(screen.getByRole('button', { name: 'AI service provider' }));
+
+ mockOnConnectorSaved({ id: '1', name: 'New Connector' });
+
+ expect(mockOnConnectorSaved).toHaveBeenCalledWith({ id: '1', name: 'New Connector' });
+ });
+});