Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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(
<ConnectorSelector connectors={connectors} onChange={mockOnChange} />
);
expect(getByTestId(testSubj)).toBeInTheDocument();
});

it('should call onChange when a connector is selected', () => {
const { getByTestId } = render(
<ConnectorSelector connectors={connectors} onChange={mockOnChange} />
);

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(
<ConnectorSelector
connectors={connectors}
onChange={mockOnChange}
onNewConnectorClicked={mockOnNewConnectorClicked}
/>
);
fireEvent.click(getByTestId(testSubj));
expect(getByTestId('addNewConnectorButton')).toBeInTheDocument();
});

it('should call onNewConnectorClicked when add new connector is selected', () => {
const { getByTestId } = render(
<ConnectorSelector
connectors={connectors}
onChange={mockOnChange}
onNewConnectorClicked={mockOnNewConnectorClicked}
/>
);
fireEvent.click(getByTestId(testSubj));
fireEvent.click(getByTestId('addNewConnectorButton'));
expect(mockOnNewConnectorClicked).toHaveBeenCalled();
});

it('should disable selection when isDisabled is true', () => {
const { getByTestId } = render(
<ConnectorSelector connectors={connectors} onChange={mockOnChange} isDisabled />
);
expect(getByTestId(testSubj)).toBeDisabled();
});

it('should render a button to add a new connector when no connectors exist', () => {
const { getByTestId } = render(
<ConnectorSelector
connectors={[]}
onChange={mockOnChange}
onNewConnectorClicked={mockOnNewConnectorClicked}
/>
);
expect(getByTestId('addNewConnectorButton')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -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(
<ConnectorCards
connectors={undefined}
onNewConnectorSaved={jest.fn()}
canCreateConnectors={true}
onConnectorSelected={jest.fn()}
/>
);
expect(screen.getByRole('progressbar')).toBeInTheDocument();
});

it('calls onConnectorSelected when a connector is selected', async () => {
const onConnectorSelected = jest.fn();
render(
<ConnectorCards
connectors={mockConnectors}
onNewConnectorSaved={jest.fn()}
canCreateConnectors={true}
onConnectorSelected={onConnectorSelected}
/>
);

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(
<ConnectorCards
connectors={[]}
onNewConnectorSaved={jest.fn()}
canCreateConnectors={false}
onConnectorSelected={jest.fn()}
/>
);
expect(screen.getByText('Missing privileges')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -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(<ConnectorSelectorPanel connectors={mockConnectors} onConnectorSelected={jest.fn()} />);
expect(screen.getByText('Selected provider')).toBeInTheDocument();
});

it('preselects the only connector if there is one', () => {
const onConnectorSelected = jest.fn();
render(
<ConnectorSelectorPanel
connectors={[mockConnectors[0]]}
onConnectorSelected={onConnectorSelected}
/>
);
expect(onConnectorSelected).toHaveBeenCalledWith(mockConnectors[0]);
});

it('calls onConnectorSelected when a connector is selected', async () => {
const onConnectorSelected = jest.fn();
render(
<ConnectorSelectorPanel
connectors={mockConnectors}
onConnectorSelected={onConnectorSelected}
/>
);
await userEvent.click(screen.getByRole('button', { name: /Connector Selector/i }));
await userEvent.click(screen.getByText('Connector 2'));
expect(onConnectorSelected).toHaveBeenCalledWith(mockConnectors[1]);
});
});
Original file line number Diff line number Diff line change
@@ -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(() => <div data-test-subj="addConnectorModal">{'Mock Modal'}</div>),
}));

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(<ConnectorSetup actionTypes={mockActionTypes} onConnectorSaved={jest.fn()} />);

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(<ConnectorSetup actionTypes={mockActionTypes} onConnectorSaved={jest.fn()} />);

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(
<ConnectorSetup actionTypes={mockActionTypes} onConnectorSaved={mockOnConnectorSaved} />
);
await userEvent.click(screen.getByRole('button', { name: 'AI service provider' }));

mockOnConnectorSaved({ id: '1', name: 'New Connector' });

expect(mockOnConnectorSaved).toHaveBeenCalledWith({ id: '1', name: 'New Connector' });
});
});