mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Automatic Import] Adding UI and FTR tests for automatic import cel creation flyout (#209418)
## Summary This PR adds the following tests for Automatic Import: - jest unit tests for the CEL generation flyout - FTR tests for the `analyze_api` and `cel` graph endpoints (excluding 200 tests due to https://github.com/elastic/kibana/issues/204177 still being open) There is also some very minor cleanup of a test mocking of the now deprecated FF for generateCel, and small refactor to move a function to a different file for consistency. (Cypress tests coming in a separate PR)
This commit is contained in:
parent
f058b50f93
commit
5878c77784
20 changed files with 1059 additions and 23 deletions
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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, type RenderResult } from '@testing-library/react';
|
||||
import { TestProvider } from '../../../../../mocks/test_provider';
|
||||
import { ActionsProvider } from '../../state';
|
||||
import { mockActions, mockState } from '../../mocks/state';
|
||||
import { CreateCelConfigFlyout } from './create_cel_config';
|
||||
|
||||
const wrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
|
||||
<TestProvider>
|
||||
<ActionsProvider value={mockActions}>{children}</ActionsProvider>
|
||||
</TestProvider>
|
||||
);
|
||||
|
||||
describe('CreateCelConfig', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<CreateCelConfigFlyout
|
||||
integrationSettings={undefined}
|
||||
connector={mockState.connector}
|
||||
isFlyoutGenerating={false}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('when open with initial state', () => {
|
||||
it('should render upload spec step', () => {
|
||||
expect(result.queryByTestId('uploadSpecStep')).toBeVisible();
|
||||
});
|
||||
|
||||
it('confirm settings step collapsed', () => {
|
||||
const accordionButton = result.queryByTestId('celGenStep2')?.querySelector('button');
|
||||
// Check the aria-expanded property of the button
|
||||
const isExpanded = accordionButton?.getAttribute('aria-expanded');
|
||||
expect(isExpanded).toBe('false');
|
||||
|
||||
expect(result.queryByTestId('confirmSettingsStep')).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -138,6 +138,7 @@ export const CreateCelConfigFlyout = React.memo<CreateCelConfigFlyoutProps>(
|
|||
paddingSize="m"
|
||||
forceState={isUploadStepExpanded ? 'open' : 'closed'}
|
||||
onToggle={handleToggleStep}
|
||||
data-test-subj="celGenStep1"
|
||||
buttonContent={
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m">
|
||||
<EuiStepNumber
|
||||
|
@ -174,6 +175,7 @@ export const CreateCelConfigFlyout = React.memo<CreateCelConfigFlyoutProps>(
|
|||
isDisabled={!isAnalyzeApiGenerationComplete}
|
||||
forceState={isConfirmStepExpanded ? 'open' : 'closed'}
|
||||
onToggle={handleToggleStep}
|
||||
data-test-subj="celGenStep2"
|
||||
buttonContent={
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m">
|
||||
<EuiStepNumber
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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, type RenderResult } from '@testing-library/react';
|
||||
import { TestProvider } from '../../../../../mocks/test_provider';
|
||||
import { Footer } from './footer';
|
||||
import { ActionsProvider } from '../../state';
|
||||
import { mockActions } from '../../mocks/state';
|
||||
|
||||
const wrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
|
||||
<TestProvider>
|
||||
<ActionsProvider value={mockActions}>{children}</ActionsProvider>
|
||||
</TestProvider>
|
||||
);
|
||||
|
||||
describe('Footer', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('when rendered everything enabled', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
result = render(
|
||||
<Footer
|
||||
isFlyoutGenerating={false}
|
||||
isValid={false}
|
||||
isGenerationComplete={false}
|
||||
showHint={false}
|
||||
hint={''}
|
||||
onCancel={() => {}}
|
||||
onSave={() => {}}
|
||||
/>,
|
||||
{
|
||||
wrapper,
|
||||
}
|
||||
);
|
||||
});
|
||||
it('should render cancel button', () => {
|
||||
expect(result.queryByTestId('footer-cancelButton')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render save button', () => {
|
||||
expect(result.queryByTestId('footer-saveButton')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render hint', () => {
|
||||
expect(result.queryByTestId('footer-showHint')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rendered with show validation', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
result = render(
|
||||
<Footer
|
||||
isFlyoutGenerating={false}
|
||||
isValid={false}
|
||||
isGenerationComplete={false}
|
||||
showHint={true}
|
||||
hint={''}
|
||||
onCancel={() => {}}
|
||||
onSave={() => {}}
|
||||
/>,
|
||||
{
|
||||
wrapper,
|
||||
}
|
||||
);
|
||||
});
|
||||
it('should render enabled cancel button', () => {
|
||||
expect(result.queryByTestId('footer-cancelButton')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render disabled save button', () => {
|
||||
expect(result.queryByTestId('footer-saveButton')).toBeDisabled();
|
||||
});
|
||||
|
||||
it('should render hint', () => {
|
||||
expect(result.queryByTestId('footer-showHint')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rendered while generating', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
result = render(
|
||||
<Footer
|
||||
isFlyoutGenerating={true}
|
||||
isValid={false}
|
||||
isGenerationComplete={false}
|
||||
showHint={false}
|
||||
hint={''}
|
||||
onCancel={() => {}}
|
||||
onSave={() => {}}
|
||||
/>,
|
||||
{
|
||||
wrapper,
|
||||
}
|
||||
);
|
||||
});
|
||||
it('should render enabled cancel button', () => {
|
||||
expect(result.queryByTestId('footer-cancelButton')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render disabled save button', () => {
|
||||
expect(result.queryByTestId('footer-saveButton')).toBeDisabled();
|
||||
});
|
||||
|
||||
it('should render hint', () => {
|
||||
expect(result.queryByTestId('footer-showHint')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -30,7 +30,11 @@ export const Footer = React.memo<FooterProps>(
|
|||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexGroup justifyContent="flexEnd" alignItems="center">
|
||||
{showHint && <EuiText size="s">{hint}</EuiText>}
|
||||
{showHint && (
|
||||
<EuiText size="s" data-test-subj="footer-showHint">
|
||||
{hint}
|
||||
</EuiText>
|
||||
)}
|
||||
<EuiButton
|
||||
fill={isGenerationComplete}
|
||||
color="primary"
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 } from '@testing-library/react';
|
||||
import { GenerationError } from './generation_error';
|
||||
|
||||
describe('GenerationError', () => {
|
||||
it('should render error', () => {
|
||||
const title = 'testErrorTitle';
|
||||
const errorMessage = 'testErrorMessage';
|
||||
const retryAction = () => {};
|
||||
|
||||
const { getByText } = render(
|
||||
<GenerationError title={title} error={errorMessage} retryAction={retryAction} />
|
||||
);
|
||||
const errorElement = getByText('testErrorTitle');
|
||||
expect(errorElement).toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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, type RenderResult } from '@testing-library/react';
|
||||
import { TestProvider } from '../../../../../../../mocks/test_provider';
|
||||
import { ActionsProvider } from '../../../../state';
|
||||
import { mockActions } from '../../../../mocks/state';
|
||||
import { AuthSelection } from './auth_selection';
|
||||
|
||||
const wrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
|
||||
<TestProvider>
|
||||
<ActionsProvider value={mockActions}>{children}</ActionsProvider>
|
||||
</TestProvider>
|
||||
);
|
||||
|
||||
describe('AuthSelection', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('when open with initial state', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<AuthSelection
|
||||
selectedAuth={'Basic'}
|
||||
specifiedAuthForPath={['Basic']}
|
||||
invalidAuth={false}
|
||||
isGenerating={false}
|
||||
showValidation={false}
|
||||
onChangeAuth={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render auth selection combobox', () => {
|
||||
expect(result.queryByTestId('authInputComboBox')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid auth & showing validation', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<AuthSelection
|
||||
selectedAuth={'Basic'}
|
||||
specifiedAuthForPath={['Basic']}
|
||||
invalidAuth={true}
|
||||
isGenerating={false}
|
||||
showValidation={true}
|
||||
onChangeAuth={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render warning', () => {
|
||||
expect(result.queryByTestId('authDoesNotAlignWarning')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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, type RenderResult } from '@testing-library/react';
|
||||
import { TestProvider } from '../../../../../../../mocks/test_provider';
|
||||
import { ActionsProvider } from '../../../../state';
|
||||
import { mockActions, mockState } from '../../../../mocks/state';
|
||||
import { ConfirmSettingsStep } from './confirm_settings_step';
|
||||
|
||||
const wrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
|
||||
<TestProvider>
|
||||
<ActionsProvider value={mockActions}>{children}</ActionsProvider>
|
||||
</TestProvider>
|
||||
);
|
||||
|
||||
jest.mock('@elastic/eui', () => {
|
||||
return {
|
||||
...jest.requireActual('@elastic/eui'),
|
||||
// Mocking EuiComboBox, as it utilizes "react-virtualized" for rendering search suggestions,
|
||||
// which does not produce a valid component wrapper
|
||||
EuiComboBox: (props: { onChange: (options: unknown) => void; 'data-test-subj': string }) => (
|
||||
<input
|
||||
data-test-subj={props['data-test-subj']}
|
||||
onChange={(syntheticEvent) => {
|
||||
props.onChange([{ value: syntheticEvent.target.value }]);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ConfirmSettingsStep', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('when open with initial state', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<ConfirmSettingsStep
|
||||
integrationSettings={undefined}
|
||||
connector={mockState.connector}
|
||||
isFlyoutGenerating={false}
|
||||
suggestedPaths={['/path1', '/path2', '/path3']}
|
||||
showValidation={false}
|
||||
onShowValidation={() => {}}
|
||||
onUpdateValidation={() => {}}
|
||||
onUpdateNeedsGeneration={() => {}}
|
||||
onCelInputGenerationComplete={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render confirm settings step', () => {
|
||||
expect(result.queryByTestId('suggestedPathsRadioGroup')).toBeInTheDocument();
|
||||
expect(result.queryByTestId('authInputComboBox')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('generate button enabled', () => {
|
||||
expect(result.queryByTestId('generateCelInputButton')).toBeEnabled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('generating in progress', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<ConfirmSettingsStep
|
||||
integrationSettings={undefined}
|
||||
connector={mockState.connector}
|
||||
isFlyoutGenerating={true}
|
||||
suggestedPaths={['/path1', '/path2', '/path3']}
|
||||
showValidation={false}
|
||||
onShowValidation={() => {}}
|
||||
onUpdateValidation={() => {}}
|
||||
onUpdateNeedsGeneration={() => {}}
|
||||
onCelInputGenerationComplete={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
it('generate button disabled; cancel button appears and is enabled', () => {
|
||||
expect(result.queryByTestId('generateCelInputButton')).toBeDisabled();
|
||||
expect(result.queryByTestId('cancelCelGenerationButton')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -26,6 +26,7 @@ import { EndpointSelection } from './endpoint_selection';
|
|||
import { AuthSelection } from './auth_selection';
|
||||
import { GenerationError } from '../../generation_error';
|
||||
import { useTelemetry } from '../../../../../telemetry';
|
||||
import type { IntegrationSettings } from '../../../../types';
|
||||
|
||||
export const translateDisplayAuthToType = (auth: string): string => {
|
||||
return auth === 'API Token' ? 'Header' : auth;
|
||||
|
@ -41,6 +42,14 @@ const getSpecifiedAuthForPath = (apiSpec: Oas | undefined, path: string) => {
|
|||
return specifiedAuth;
|
||||
};
|
||||
|
||||
const loadPaths = (integrationSettings: IntegrationSettings | undefined): string[] => {
|
||||
const pathObjs = integrationSettings?.apiSpec?.getPaths();
|
||||
if (!pathObjs) {
|
||||
return [];
|
||||
}
|
||||
return Object.keys(pathObjs).filter((path) => pathObjs[path].get);
|
||||
};
|
||||
|
||||
interface ConfirmSettingsStepProps {
|
||||
integrationSettings: State['integrationSettings'];
|
||||
connector: State['connector'];
|
||||
|
@ -296,7 +305,7 @@ export const ConfirmSettingsStep = React.memo<ConfirmSettingsStepProps>(
|
|||
<EuiFlexGroup direction="column" gutterSize="l" data-test-subj="confirmSettingsStep">
|
||||
<EuiPanel hasShadow={false} hasBorder={false}>
|
||||
<EndpointSelection
|
||||
integrationSettings={integrationSettings}
|
||||
allPaths={loadPaths(integrationSettings)}
|
||||
pathSuggestions={suggestedPaths}
|
||||
selectedPath={selectedPath}
|
||||
selectedOtherPath={selectedOtherPath}
|
||||
|
@ -330,7 +339,10 @@ export const ConfirmSettingsStep = React.memo<ConfirmSettingsStepProps>(
|
|||
<EuiButton
|
||||
fill
|
||||
fullWidth={false}
|
||||
isDisabled={isFlyoutGenerating}
|
||||
isDisabled={
|
||||
isFlyoutGenerating ||
|
||||
(showValidation && (fieldValidationErrors.path || fieldValidationErrors.auth))
|
||||
}
|
||||
isLoading={isFlyoutGenerating}
|
||||
iconSide="right"
|
||||
color="primary"
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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, type RenderResult } from '@testing-library/react';
|
||||
import { TestProvider } from '../../../../../../../mocks/test_provider';
|
||||
import { ActionsProvider } from '../../../../state';
|
||||
import { mockActions } from '../../../../mocks/state';
|
||||
import { EndpointSelection } from './endpoint_selection';
|
||||
|
||||
const wrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
|
||||
<TestProvider>
|
||||
<ActionsProvider value={mockActions}>{children}</ActionsProvider>
|
||||
</TestProvider>
|
||||
);
|
||||
|
||||
describe('EndpointSelection', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('when open with initial state', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<EndpointSelection
|
||||
allPaths={['/path1', '/path2', '/path3', '/path4']}
|
||||
pathSuggestions={['/path1', '/path2', '/path3']}
|
||||
selectedPath={'/path1'}
|
||||
selectedOtherPath={undefined}
|
||||
useOtherEndpoint={false}
|
||||
isGenerating={false}
|
||||
showValidation={false}
|
||||
onChangeSuggestedPath={() => {}}
|
||||
onChangeOtherPath={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render endpoint selection radio group', () => {
|
||||
expect(result.queryByTestId('suggestedPathsRadioGroup')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render all path options combo box', () => {
|
||||
expect(result.queryByTestId('allPathOptionsComboBox')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('show all path options radio group', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<EndpointSelection
|
||||
allPaths={['/path1', '/path2', '/path3', '/path4']}
|
||||
pathSuggestions={['/path1', '/path2', '/path3']}
|
||||
selectedPath={'Enter Manually'}
|
||||
selectedOtherPath={undefined}
|
||||
useOtherEndpoint={true}
|
||||
isGenerating={false}
|
||||
showValidation={false}
|
||||
onChangeSuggestedPath={() => {}}
|
||||
onChangeOtherPath={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render all path options combo box', () => {
|
||||
expect(result.queryByTestId('allPathOptionsComboBox')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid auth & showing validation', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<EndpointSelection
|
||||
allPaths={['/path1', '/path2', '/path3', '/path4']}
|
||||
pathSuggestions={['/path1', '/path2', '/path3']}
|
||||
selectedPath={'Enter manually'}
|
||||
selectedOtherPath={undefined}
|
||||
useOtherEndpoint={true}
|
||||
isGenerating={false}
|
||||
showValidation={true}
|
||||
onChangeSuggestedPath={() => {}}
|
||||
onChangeOtherPath={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
it('validation', () => {
|
||||
const otherEndpointSelection = result.getByTestId('allPathOptionsComboBox');
|
||||
expect(otherEndpointSelection).toHaveAttribute('aria-invalid');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -19,18 +19,9 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import * as i18n from './translations';
|
||||
import type { IntegrationSettings } from '../../../../types';
|
||||
|
||||
const loadPaths = (integrationSettings: IntegrationSettings | undefined): string[] => {
|
||||
const pathObjs = integrationSettings?.apiSpec?.getPaths();
|
||||
if (!pathObjs) {
|
||||
return [];
|
||||
}
|
||||
return Object.keys(pathObjs).filter((path) => pathObjs[path].get);
|
||||
};
|
||||
|
||||
interface EndpointSelectionProps {
|
||||
integrationSettings: IntegrationSettings | undefined;
|
||||
allPaths: string[];
|
||||
pathSuggestions: string[];
|
||||
selectedPath: string | undefined;
|
||||
selectedOtherPath: string | undefined;
|
||||
|
@ -43,7 +34,7 @@ interface EndpointSelectionProps {
|
|||
|
||||
export const EndpointSelection = React.memo<EndpointSelectionProps>(
|
||||
({
|
||||
integrationSettings,
|
||||
allPaths,
|
||||
pathSuggestions,
|
||||
selectedPath,
|
||||
selectedOtherPath,
|
||||
|
@ -53,7 +44,6 @@ export const EndpointSelection = React.memo<EndpointSelectionProps>(
|
|||
onChangeSuggestedPath,
|
||||
onChangeOtherPath,
|
||||
}) => {
|
||||
const allPaths = loadPaths(integrationSettings);
|
||||
const otherPathOptions = allPaths.map<EuiComboBoxOptionOption>((p) => ({ label: p }));
|
||||
|
||||
const hasSuggestedPaths = pathSuggestions.length > 0;
|
||||
|
@ -113,6 +103,7 @@ export const EndpointSelection = React.memo<EndpointSelectionProps>(
|
|||
fullWidth
|
||||
options={otherPathOptions}
|
||||
isDisabled={isGenerating}
|
||||
aria-invalid={showValidation && useOtherEndpoint && selectedOtherPath === undefined}
|
||||
isInvalid={showValidation && useOtherEndpoint && selectedOtherPath === undefined}
|
||||
selectedOptions={
|
||||
selectedOtherPath === undefined ? undefined : [{ label: selectedOtherPath }]
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* 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 { act, fireEvent, render, waitFor, type RenderResult } from '@testing-library/react';
|
||||
import { TestProvider } from '../../../../../../../mocks/test_provider';
|
||||
import { ApiDefinitionInput } from './api_definition_input';
|
||||
|
||||
import { ActionsProvider } from '../../../../state';
|
||||
import { mockActions } from '../../../../mocks/state';
|
||||
import Oas from 'oas';
|
||||
|
||||
const wrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
|
||||
<TestProvider>
|
||||
<ActionsProvider value={mockActions}>{children}</ActionsProvider>
|
||||
</TestProvider>
|
||||
);
|
||||
|
||||
const changeFile = async (input: HTMLElement, file: File) => {
|
||||
await act(async () => {
|
||||
fireEvent.change(input, { target: { files: [file] } });
|
||||
await waitFor(() => expect(input).toHaveAttribute('data-loading', 'true'));
|
||||
await waitFor(() => expect(input).toHaveAttribute('data-loading', 'false'));
|
||||
});
|
||||
};
|
||||
|
||||
const simpleOpenApiJson = `{"openapi":"3.0.0","info":{"title":"Sample API"},"paths":{"/users":{"get":{"summary":"Returns a list of users.","description":"Optional extended description in CommonMark or HTML.","responses":{"200":{"description":"A JSON array of user names","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}}}}}}`;
|
||||
const simpleOpenApiYaml = `openapi: 3.0.0
|
||||
info:
|
||||
title: Sample API
|
||||
paths:
|
||||
/users:
|
||||
get:
|
||||
summary: Returns a list of users.
|
||||
description: Optional extended description in CommonMark or HTML.
|
||||
responses:
|
||||
"200": # status code
|
||||
description: A JSON array of user names
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string`;
|
||||
|
||||
describe('SampleLogsInput', () => {
|
||||
let result: RenderResult;
|
||||
let input: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<ApiDefinitionInput
|
||||
integrationSettings={undefined}
|
||||
showValidation={false}
|
||||
isGenerating={false}
|
||||
onModifySpecFile={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
input = result.getByTestId('apiDefinitionFilePicker');
|
||||
});
|
||||
|
||||
describe('when uploading a json file', () => {
|
||||
const type = 'application/json';
|
||||
|
||||
describe('when the file is a valid json spec file', () => {
|
||||
beforeEach(async () => {
|
||||
await changeFile(input, new File([`${simpleOpenApiJson}`], 'test.json', { type }));
|
||||
});
|
||||
|
||||
it('should set the integrationSetting correctly', () => {
|
||||
expect(mockActions.setIntegrationSettings).toBeCalledWith({
|
||||
apiSpec: expect.any(Oas),
|
||||
apiSpecFileName: 'test.json',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the file is invalid', () => {
|
||||
const otherJson = `{"events":[\n{"message":"test message 1"},\n{"message":"test message 2"}\n]}`;
|
||||
beforeEach(async () => {
|
||||
await changeFile(input, new File([otherJson], 'test.json', { type }));
|
||||
});
|
||||
|
||||
it('should render invalid inputs', () => {
|
||||
expect(input).toHaveAttribute('aria-invalid');
|
||||
});
|
||||
|
||||
it('should set the integrationSetting correctly', () => {
|
||||
expect(mockActions.setIntegrationSettings).toBeCalledWith({
|
||||
apiSpec: undefined,
|
||||
apiSpecFileName: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when uploading a yaml spec file', () => {
|
||||
describe('when the file is a valid yaml spec file', () => {
|
||||
beforeEach(async () => {
|
||||
await changeFile(
|
||||
input,
|
||||
new File([`${simpleOpenApiYaml}`], 'test.yaml', { type: 'text/yaml' })
|
||||
);
|
||||
});
|
||||
|
||||
it('should set the integrationSetting correctly', () => {
|
||||
expect(mockActions.setIntegrationSettings).toBeCalledWith({
|
||||
apiSpec: expect.any(Oas),
|
||||
apiSpecFileName: 'test.yaml',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the file is invalid', () => {
|
||||
const otherYaml = `foo: 1
|
||||
bar: 2`;
|
||||
beforeEach(async () => {
|
||||
await changeFile(input, new File([otherYaml], 'test.json', { type }));
|
||||
});
|
||||
|
||||
it('should render invalid inputs', () => {
|
||||
expect(input).toHaveAttribute('aria-invalid');
|
||||
});
|
||||
|
||||
it('should set the integrationSetting correctly', () => {
|
||||
expect(mockActions.setIntegrationSettings).toBeCalledWith({
|
||||
apiSpec: undefined,
|
||||
apiSpecFileName: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the file is too large', () => {
|
||||
let jsonParseSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Simulate large content that would cause a RangeError
|
||||
jsonParseSpy = jest.spyOn(JSON, 'parse').mockImplementation(() => {
|
||||
throw new RangeError();
|
||||
});
|
||||
|
||||
await changeFile(input, new File(['...'], 'test.json', { type: 'text/plain' }));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
// Restore the original implementation after all tests
|
||||
jsonParseSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should display invalid', () => {
|
||||
expect(input).toHaveAttribute('aria-invalid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the file is neither a valid json nor yaml', () => {
|
||||
const plainTextFile = 'test message 1\ntest message 2';
|
||||
|
||||
beforeEach(async () => {
|
||||
await changeFile(input, new File([plainTextFile], 'test.txt', { type: 'text/plain' }));
|
||||
});
|
||||
|
||||
it('should render invalid inputs', () => {
|
||||
expect(input).toHaveAttribute('aria-invalid');
|
||||
});
|
||||
|
||||
it('should set the integrationSetting correctly', () => {
|
||||
expect(mockActions.setIntegrationSettings).toBeCalledWith({
|
||||
apiSpec: undefined,
|
||||
apiSpecFileName: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the file reader fails', () => {
|
||||
let myFileReader: FileReader;
|
||||
let fileReaderSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(async () => {
|
||||
myFileReader = new FileReader();
|
||||
fileReaderSpy = jest.spyOn(global, 'FileReader').mockImplementation(() => myFileReader);
|
||||
|
||||
jest.spyOn(myFileReader, 'readAsText').mockImplementation(() => {
|
||||
const errorEvent = new ProgressEvent('error');
|
||||
myFileReader.dispatchEvent(errorEvent);
|
||||
});
|
||||
|
||||
const file = new File([`...`], 'test.json', { type: 'application/json' });
|
||||
act(() => {
|
||||
fireEvent.change(input, { target: { files: [file] } });
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fileReaderSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should set input invalid', () => {
|
||||
expect(input).toHaveAttribute('aria-invalid');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -177,6 +177,7 @@ export const ApiDefinitionInput = React.memo<ApiDefinitionInputProps>(
|
|||
onChange={onChangeApiDefinition}
|
||||
display="large"
|
||||
aria-label="Upload API definition file"
|
||||
data-loading={isParsing || isGenerating}
|
||||
isLoading={isParsing || isGenerating}
|
||||
isInvalid={apiFileError != null || (showValidation && uploadedFile === undefined)}
|
||||
data-test-subj="apiDefinitionFilePicker"
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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 { act, fireEvent, render, waitFor, type RenderResult } from '@testing-library/react';
|
||||
import { TestProvider } from '../../../../../../../mocks/test_provider';
|
||||
import { ActionsProvider } from '../../../../state';
|
||||
import { mockActions, mockState } from '../../../../mocks/state';
|
||||
import { UploadSpecStep } from './upload_spec_step';
|
||||
|
||||
const wrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
|
||||
<TestProvider>
|
||||
<ActionsProvider value={mockActions}>{children}</ActionsProvider>
|
||||
</TestProvider>
|
||||
);
|
||||
|
||||
describe('UploadSpecStep', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('when open with initial state', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<UploadSpecStep
|
||||
integrationSettings={undefined}
|
||||
connector={mockState.connector}
|
||||
isFlyoutGenerating={false}
|
||||
showValidation={false}
|
||||
onShowValidation={() => {}}
|
||||
onUpdateValidation={() => {}}
|
||||
onUpdateNeedsGeneration={() => {}}
|
||||
onAnalyzeApiGenerationComplete={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render upload spec step', () => {
|
||||
expect(result.queryByTestId('dataStreamTitleInput')).toBeInTheDocument();
|
||||
expect(result.queryByTestId('apiDefinitionFilePicker')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('analyze button enabled', () => {
|
||||
expect(result.queryByTestId('analyzeApiButton')).toBeEnabled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when opened and validation enabled (clicking submit before filling out the fields)', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<UploadSpecStep
|
||||
integrationSettings={undefined}
|
||||
connector={mockState.connector}
|
||||
isFlyoutGenerating={false}
|
||||
showValidation={true}
|
||||
onShowValidation={() => {}}
|
||||
onUpdateValidation={() => {}}
|
||||
onUpdateNeedsGeneration={() => {}}
|
||||
onAnalyzeApiGenerationComplete={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
it('analyze button disabled', () => {
|
||||
expect(result.queryByTestId('analyzeApiButton')).toBeDisabled();
|
||||
});
|
||||
|
||||
describe('fills in fields', () => {
|
||||
beforeEach(async () => {
|
||||
await act(async () => {
|
||||
fireEvent.change(result.getByTestId('dataStreamTitleInput'), {
|
||||
target: { value: 'testDataStreamTitle' },
|
||||
});
|
||||
const filepicker = result.getByTestId('apiDefinitionFilePicker');
|
||||
fireEvent.change(filepicker, {
|
||||
target: { files: [new File(['...'], 'test.json', { type: 'application/json' })] },
|
||||
});
|
||||
await waitFor(() => expect(filepicker).toHaveAttribute('data-loading', 'true'));
|
||||
await waitFor(() => expect(filepicker).toHaveAttribute('data-loading', 'false'));
|
||||
});
|
||||
});
|
||||
|
||||
it('analyze button re-enabled', () => {
|
||||
expect(result.queryByTestId('analyzeApiButton')).toBeEnabled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('analyzing in progress', () => {
|
||||
let result: RenderResult;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
result = render(
|
||||
<UploadSpecStep
|
||||
integrationSettings={undefined}
|
||||
connector={mockState.connector}
|
||||
isFlyoutGenerating={true}
|
||||
showValidation={false}
|
||||
onShowValidation={() => {}}
|
||||
onUpdateValidation={() => {}}
|
||||
onUpdateNeedsGeneration={() => {}}
|
||||
onAnalyzeApiGenerationComplete={() => {}}
|
||||
/>,
|
||||
{ wrapper }
|
||||
);
|
||||
});
|
||||
|
||||
it('form is disabled', () => {
|
||||
expect(result.queryByTestId('dataStreamTitleInput')).toBeDisabled();
|
||||
});
|
||||
|
||||
it('analyze button disabled; cancel button appears and is enabled', () => {
|
||||
expect(result.queryByTestId('analyzeApiButton')).toBeDisabled();
|
||||
expect(result.queryByTestId('cancelAnalyzeApiButton')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -11,7 +11,6 @@ import { TestProvider } from '../../../../mocks/test_provider';
|
|||
import { Footer } from './footer';
|
||||
import { ActionsProvider } from '../state';
|
||||
import { mockActions } from '../mocks/state';
|
||||
import { ExperimentalFeaturesService } from '../../../../services';
|
||||
|
||||
const mockNavigate = jest.fn();
|
||||
jest.mock('../../../../common/hooks/use_navigate', () => ({
|
||||
|
@ -19,9 +18,6 @@ jest.mock('../../../../common/hooks/use_navigate', () => ({
|
|||
useNavigate: () => mockNavigate,
|
||||
}));
|
||||
|
||||
jest.mock('../../../../services');
|
||||
const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService);
|
||||
|
||||
const wrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
|
||||
<TestProvider>
|
||||
<ActionsProvider value={mockActions}>{children}</ActionsProvider>
|
||||
|
@ -31,10 +27,6 @@ const wrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
|
|||
describe('Footer', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
mockedExperimentalFeaturesService.get.mockReturnValue({
|
||||
generateCel: false,
|
||||
} as never);
|
||||
});
|
||||
|
||||
describe('when rendered for the most common case', () => {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 { postAnalyzeApi } from '../../../../common/lib/api/analyze_api';
|
||||
import { FtrProviderContext } from '../../../../../common/ftr_provider_context';
|
||||
import { User } from '../../../../common/lib/authentication/types';
|
||||
|
||||
export default ({ getService }: FtrProviderContext): void => {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('Run analyze api', () => {
|
||||
it('should get 404 when trying to run analyze_api with basic license', async () => {
|
||||
return await postAnalyzeApi({
|
||||
supertest,
|
||||
req: {
|
||||
dataStreamTitle: 'some data stream',
|
||||
connectorId: 'bedrock-connector',
|
||||
pathOptions: {
|
||||
'/path1': 'Returns the data from path1',
|
||||
'/path2': 'Returns the data from path2',
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
user: { username: 'elastic', password: 'elastic' } as User,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 { postCelInput } from '../../../../common/lib/api/cel';
|
||||
import { FtrProviderContext } from '../../../../../common/ftr_provider_context';
|
||||
import { User } from '../../../../common/lib/authentication/types';
|
||||
|
||||
export default ({ getService }: FtrProviderContext): void => {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('Run cel', () => {
|
||||
it('should get 404 when trying to run cel with basic license', async () => {
|
||||
return await postCelInput({
|
||||
supertest,
|
||||
req: {
|
||||
dataStreamTitle: 'some data stream',
|
||||
connectorId: 'bedrock-connector',
|
||||
celDetails: {
|
||||
path: '/path1',
|
||||
auth: 'basic',
|
||||
openApiDetails: {
|
||||
operation: '{ operationJson}',
|
||||
schemas: '{schemasJson}',
|
||||
auth: '{authJson}',
|
||||
},
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
user: { username: 'elastic', password: 'elastic' } as User,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../../../common/ftr_provider_context';
|
||||
import { postAnalyzeApi } from '../../../common/lib/api/analyze_api';
|
||||
import { User } from '../../../common/lib/authentication/types';
|
||||
import { BadRequestError } from '../../../common/lib/error/error';
|
||||
|
||||
export default function (providerContext: FtrProviderContext) {
|
||||
const { getService } = providerContext;
|
||||
const supertest = getService('supertest');
|
||||
describe('Run analyze api', () => {
|
||||
it('should get 400 when trying to run analyze api without connector action', async () => {
|
||||
const response = await postAnalyzeApi({
|
||||
supertest,
|
||||
req: {
|
||||
dataStreamTitle: 'some data stream',
|
||||
connectorId: 'preconfigured-dummy',
|
||||
pathOptions: {
|
||||
'/path1': 'Returns the data from path1',
|
||||
'/path2': 'Returns the data from path2',
|
||||
},
|
||||
},
|
||||
expectedHttpCode: 400,
|
||||
auth: {
|
||||
user: { username: 'elastic', password: 'elastic' } as User,
|
||||
},
|
||||
});
|
||||
if (response instanceof BadRequestError) {
|
||||
expect(response.message).to.be('Saved object [action/preconfigured-dummy] not found');
|
||||
} else {
|
||||
expect().fail('Expected BadRequestError');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../../../common/ftr_provider_context';
|
||||
import { postCelInput } from '../../../common/lib/api/cel';
|
||||
import { User } from '../../../common/lib/authentication/types';
|
||||
import { BadRequestError } from '../../../common/lib/error/error';
|
||||
|
||||
export default function (providerContext: FtrProviderContext) {
|
||||
const { getService } = providerContext;
|
||||
const supertest = getService('supertest');
|
||||
describe('Run cel', () => {
|
||||
it('should get 400 when trying to run cel without connector action', async () => {
|
||||
const response = await postCelInput({
|
||||
supertest,
|
||||
req: {
|
||||
dataStreamTitle: 'some data stream',
|
||||
connectorId: 'preconfigured-dummy',
|
||||
celDetails: {
|
||||
path: '/path1',
|
||||
auth: 'basic',
|
||||
openApiDetails: {
|
||||
operation: '{ operationJson}',
|
||||
schemas: '{schemasJson}',
|
||||
auth: '{authJson}',
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedHttpCode: 400,
|
||||
auth: {
|
||||
user: { username: 'elastic', password: 'elastic' } as User,
|
||||
},
|
||||
});
|
||||
if (response instanceof BadRequestError) {
|
||||
expect(response.message).to.be('Saved object [action/preconfigured-dummy] not found');
|
||||
} else {
|
||||
expect().fail('Expected BadRequestError');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 type SuperTest from 'supertest';
|
||||
import {
|
||||
AnalyzeApiRequestBody,
|
||||
ANALYZE_API_PATH,
|
||||
AnalyzeApiResponse,
|
||||
} from '@kbn/automatic-import-plugin/common';
|
||||
import { superUser } from '../authentication/users';
|
||||
import { User } from '../authentication/types';
|
||||
|
||||
export const postAnalyzeApi = async ({
|
||||
supertest,
|
||||
req,
|
||||
expectedHttpCode = 404,
|
||||
auth = { user: superUser },
|
||||
}: {
|
||||
supertest: SuperTest.Agent;
|
||||
req: AnalyzeApiRequestBody;
|
||||
expectedHttpCode?: number;
|
||||
auth: { user: User };
|
||||
}): Promise<AnalyzeApiResponse> => {
|
||||
const { body: response } = await supertest
|
||||
.post(`${ANALYZE_API_PATH}`)
|
||||
.send(req)
|
||||
.set('kbn-xsrf', 'abc')
|
||||
.set('elastic-api-version', '1')
|
||||
.auth(auth.user.username, auth.user.password)
|
||||
.expect(expectedHttpCode);
|
||||
|
||||
return response;
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 type SuperTest from 'supertest';
|
||||
import {
|
||||
CelInputRequestBody,
|
||||
CEL_INPUT_GRAPH_PATH,
|
||||
CelInputResponse,
|
||||
} from '@kbn/automatic-import-plugin/common';
|
||||
import { superUser } from '../authentication/users';
|
||||
import { User } from '../authentication/types';
|
||||
import { BadRequestError } from '../error/error';
|
||||
|
||||
export const postCelInput = async ({
|
||||
supertest,
|
||||
req,
|
||||
expectedHttpCode = 404,
|
||||
auth = { user: superUser },
|
||||
}: {
|
||||
supertest: SuperTest.Agent;
|
||||
req: CelInputRequestBody;
|
||||
expectedHttpCode?: number;
|
||||
auth: { user: User };
|
||||
}): Promise<CelInputResponse | BadRequestError> => {
|
||||
const { body: response } = await supertest
|
||||
.post(`${CEL_INPUT_GRAPH_PATH}`)
|
||||
.send(req)
|
||||
.set('kbn-xsrf', 'abc')
|
||||
.set('elastic-api-version', '1')
|
||||
.auth(auth.user.username, auth.user.password)
|
||||
.expect(expectedHttpCode);
|
||||
|
||||
if (response.statusCode === 400) {
|
||||
return new BadRequestError(response.message);
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue