mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Search] [Playground] FTR tests (#183329)
Approach with different configs for kibana ui and serverless was peek out from security_solution test. 48 serverless config files are defined in the test folder. Test: no index check no index message Test: no connector Add Index of example data (can be 10 docs into elasticsearch, BM25) Add a connector (showing the modal) verify the modal is shown Test: with connector seed ES with a connector in the test Ask a question Validate the connector has been called and respond back validate the response is returned validate the view query can be opened and content (query + fields) is as expected validate the edit context is can be opened and the fields is as expected
This commit is contained in:
parent
e450763e12
commit
a9cb7d2423
22 changed files with 456 additions and 50 deletions
|
@ -322,6 +322,7 @@ enabled:
|
|||
- x-pack/test/functional/apps/saved_query_management/config.ts
|
||||
- x-pack/test/functional/apps/security/config.ts
|
||||
- x-pack/test/functional/apps/slo/embeddables/config.ts
|
||||
- x-pack/test/functional/apps/search_playground/config.ts
|
||||
- x-pack/test/functional/apps/snapshot_restore/config.ts
|
||||
- x-pack/test/functional/apps/spaces/config.ts
|
||||
- x-pack/test/functional/apps/spaces/in_solution_navigation/config.ts
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useMemo } from 'react';
|
||||
import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem, EuiPageTemplate } from '@elastic/eui';
|
||||
import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem, EuiPageTemplate, EuiTitle } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { PlaygroundProvider } from './providers/playground_provider';
|
||||
|
||||
|
@ -39,15 +39,21 @@ export const ChatPlaygroundOverview: React.FC = () => {
|
|||
grow={false}
|
||||
>
|
||||
<EuiPageTemplate.Header
|
||||
css={{ '.euiPageHeaderContent > .euiFlexGroup': { flexWrap: 'wrap' } }}
|
||||
pageTitle={
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<span data-test-subj="chat-playground-home-page-title">
|
||||
<FormattedMessage
|
||||
id="xpack.searchPlayground.pageTitle"
|
||||
defaultMessage="Playground"
|
||||
/>
|
||||
</span>
|
||||
<EuiTitle
|
||||
css={{ whiteSpace: 'nowrap' }}
|
||||
data-test-subj="chat-playground-home-page-title"
|
||||
>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.searchPlayground.pageTitle"
|
||||
defaultMessage="Playground"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBetaBadge
|
||||
|
|
|
@ -117,6 +117,7 @@ export const Chat = () => {
|
|||
component="form"
|
||||
css={{ display: 'flex', flexGrow: 1 }}
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
data-test-subj="chatPage"
|
||||
>
|
||||
<EuiFlexGroup gutterSize="none">
|
||||
<EuiFlexItem
|
||||
|
@ -220,6 +221,7 @@ export const Chat = () => {
|
|||
isLoading={isSubmitting}
|
||||
isDisabled={!isValid}
|
||||
iconType={TelegramIcon}
|
||||
data-test-subj="sendQuestionButton"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,11 @@ export const EditContextAction: React.FC = () => {
|
|||
return (
|
||||
<>
|
||||
{showFlyout && <EditContextFlyout onClose={closeFlyout} />}
|
||||
<EuiButtonEmpty onClick={() => setShowFlyout(true)} disabled={selectedIndices?.length === 0}>
|
||||
<EuiButtonEmpty
|
||||
onClick={() => setShowFlyout(true)}
|
||||
disabled={selectedIndices?.length === 0}
|
||||
data-test-subj="editContextActionButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.searchPlayground.editContext.actionButtonLabel"
|
||||
defaultMessage="Edit context"
|
||||
|
|
|
@ -85,7 +85,7 @@ export const EditContextFlyout: React.FC<EditContextFlyoutProps> = ({ onClose })
|
|||
}, [usageTracker]);
|
||||
|
||||
return (
|
||||
<EuiFlyout ownFocus onClose={onClose} size="s">
|
||||
<EuiFlyout ownFocus onClose={onClose} size="s" data-test-subj="editContextFlyout">
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="m">
|
||||
<h2>
|
||||
|
@ -172,6 +172,7 @@ export const EditContextFlyout: React.FC<EditContextFlyoutProps> = ({ onClose })
|
|||
options={group.source_fields.map((field) => ({
|
||||
value: field,
|
||||
inputDisplay: field,
|
||||
'data-test-subj': 'contextField',
|
||||
}))}
|
||||
valueOfSelected={tempSourceFields[index]?.[0]}
|
||||
onChange={(value) => updateSourceField(index, value)}
|
||||
|
|
|
@ -57,6 +57,7 @@ export const UserMessage: React.FC<UserMessageProps> = ({ content, createdAt })
|
|||
})}
|
||||
/>
|
||||
}
|
||||
data-test-subj="userMessage"
|
||||
>
|
||||
<EuiText size="s" css={UserMessageCSS}>
|
||||
<p>{content}</p>
|
||||
|
|
|
@ -66,6 +66,7 @@ export const QuestionInput: React.FC<QuestionInputProps> = ({
|
|||
onChange={handleChange}
|
||||
disabled={isDisabled}
|
||||
resize="none"
|
||||
data-test-subj="questionInput"
|
||||
/>
|
||||
|
||||
<div
|
||||
|
|
|
@ -58,6 +58,7 @@ export const AddIndicesField: React.FC<AddIndicesFieldProps> = ({
|
|||
disabled: selectedIndices.includes(index),
|
||||
}))}
|
||||
isClearable={false}
|
||||
data-test-subj="selectIndicesComboBox"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
|
|
|
@ -41,7 +41,7 @@ export const StartNewChat: React.FC<StartNewChatProps> = ({ onStartClick }) => {
|
|||
}, [usageTracker]);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup justifyContent="center" className="eui-yScroll">
|
||||
<EuiFlexGroup justifyContent="center" className="eui-yScroll" data-test-subj="startChatPage">
|
||||
<EuiFlexGroup
|
||||
css={{
|
||||
height: 'fit-content',
|
||||
|
@ -85,7 +85,7 @@ export const StartNewChat: React.FC<StartNewChatProps> = ({ onStartClick }) => {
|
|||
<SourcesPanelForStartChat />
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexGroup justifyContent="flexEnd" data-test-subj="startChatButton">
|
||||
<EuiFlexGroup justifyContent="flexEnd">
|
||||
<EuiButton
|
||||
fill
|
||||
iconType="arrowRight"
|
||||
|
@ -96,6 +96,7 @@ export const StartNewChat: React.FC<StartNewChatProps> = ({ onStartClick }) => {
|
|||
!watch(ChatFormFields.elasticsearchQuery, '')
|
||||
}
|
||||
onClick={onStartClick}
|
||||
data-test-subj="startChatButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.searchPlayground.startNewChat.startBtn"
|
||||
|
|
|
@ -26,6 +26,7 @@ export const ViewCodeAction: React.FC = () => {
|
|||
fill
|
||||
onClick={() => setShowFlyout(true)}
|
||||
disabled={!selectedIndices || selectedIndices?.length === 0}
|
||||
data-test-subj="viewCodeActionButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.searchPlayground.viewCode.actionButtonLabel"
|
||||
|
|
|
@ -78,7 +78,7 @@ export const ViewCodeFlyout: React.FC<ViewCodeFlyoutProps> = ({ onClose }) => {
|
|||
}, [usageTracker, selectedLanguage]);
|
||||
|
||||
return (
|
||||
<EuiFlyout ownFocus onClose={onClose}>
|
||||
<EuiFlyout ownFocus onClose={onClose} data-test-subj="viewCodeFlyout">
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="m">
|
||||
<h2>
|
||||
|
|
|
@ -20,7 +20,11 @@ export const ViewQueryAction: React.FC = () => {
|
|||
return (
|
||||
<>
|
||||
{showFlyout && <ViewQueryFlyout onClose={() => setShowFlyout(false)} />}
|
||||
<EuiButtonEmpty onClick={() => setShowFlyout(true)} disabled={selectedIndices?.length === 0}>
|
||||
<EuiButtonEmpty
|
||||
onClick={() => setShowFlyout(true)}
|
||||
disabled={selectedIndices?.length === 0}
|
||||
data-test-subj="viewQueryActionButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.searchPlayground.viewQuery.actionButtonLabel"
|
||||
defaultMessage="View query"
|
||||
|
|
|
@ -126,7 +126,7 @@ export const ViewQueryFlyout: React.FC<ViewQueryFlyoutProps> = ({ onClose }) =>
|
|||
}, [usageTracker]);
|
||||
|
||||
return (
|
||||
<EuiFlyout ownFocus onClose={onClose} size="l">
|
||||
<EuiFlyout ownFocus onClose={onClose} size="l" data-test-subj="viewQueryFlyout">
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="m">
|
||||
<h2>
|
||||
|
@ -216,6 +216,7 @@ export const ViewQueryFlyout: React.FC<ViewQueryFlyoutProps> = ({ onClose }) =>
|
|||
/>
|
||||
),
|
||||
checked: checked ? 'on' : undefined,
|
||||
'data-test-subj': 'queryField',
|
||||
};
|
||||
})}
|
||||
listProps={{
|
||||
|
|
17
x-pack/test/functional/apps/search_playground/config.ts
Normal file
17
x-pack/test/functional/apps/search_playground/config.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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 { FtrConfigProviderContext } from '@kbn/test';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const functionalConfig = await readConfigFile(require.resolve('../../config.base.js'));
|
||||
|
||||
return {
|
||||
...functionalConfig.getAll(),
|
||||
testFiles: [require.resolve('.')],
|
||||
};
|
||||
}
|
13
x-pack/test/functional/apps/search_playground/index.ts
Normal file
13
x-pack/test/functional/apps/search_playground/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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 { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||
describe('playground', async () => {
|
||||
loadTestFile(require.resolve('./playground_overview.ess.ts'));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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 { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { createOpenAIConnector } from './utils/create_openai_connector';
|
||||
import { MachineLearningCommonAPIProvider } from '../../services/ml/common_api';
|
||||
|
||||
const indexName = 'basic_index';
|
||||
const esArchiveIndex = 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index';
|
||||
|
||||
export default function (ftrContext: FtrProviderContext) {
|
||||
const { getService, getPageObjects } = ftrContext;
|
||||
const pageObjects = getPageObjects(['common', 'searchPlayground']);
|
||||
const commonAPI = MachineLearningCommonAPIProvider(ftrContext);
|
||||
const supertest = getService('supertest');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const createIndex = async () => await esArchiver.load(esArchiveIndex);
|
||||
let removeOpenAIConnector: () => Promise<void>;
|
||||
const createConnector = async () => {
|
||||
removeOpenAIConnector = await createOpenAIConnector({
|
||||
supertest,
|
||||
requestHeader: commonAPI.getCommonRequestHeader(),
|
||||
});
|
||||
};
|
||||
|
||||
describe('Playground Overview', () => {
|
||||
before(async () => {
|
||||
await pageObjects.common.navigateToApp('enterpriseSearchApplications/playground');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await esArchiver.unload(esArchiveIndex);
|
||||
await removeOpenAIConnector?.();
|
||||
});
|
||||
|
||||
describe('start chat page', () => {
|
||||
it('playground app is loaded', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundStartChatPageComponentsToExist();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundHeaderComponentsToExist();
|
||||
});
|
||||
|
||||
it('show no index callout', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectNoIndexCalloutExists();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectCreateIndexButtonToExists();
|
||||
});
|
||||
|
||||
it('hide no index callout when index added', async () => {
|
||||
await createIndex();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectSelectIndex(indexName);
|
||||
});
|
||||
|
||||
it('show add connector button', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectAddConnectorButtonExists();
|
||||
});
|
||||
|
||||
it('click add connector button opens connector flyout', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectOpenConnectorPagePlayground();
|
||||
});
|
||||
|
||||
it('hide gen ai panel when connector exists', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectHideGenAIPanelConnector(
|
||||
createConnector
|
||||
);
|
||||
});
|
||||
|
||||
it('show chat page', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectSelectIndex(indexName);
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectToStartChatPage();
|
||||
});
|
||||
});
|
||||
|
||||
describe('chat page', () => {
|
||||
it('chat works', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundChatPage.expectChatWorks();
|
||||
});
|
||||
|
||||
it('open view code', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundChatPage.expectOpenViewCode();
|
||||
});
|
||||
|
||||
it('show fields and code in view query', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundChatPage.expectViewQueryHasFields();
|
||||
});
|
||||
|
||||
it('show edit context', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundChatPage.expectEditContextOpens();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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';
|
||||
|
||||
export async function createOpenAIConnector({
|
||||
supertest,
|
||||
requestHeader = {},
|
||||
apiKeyHeader = {},
|
||||
}: {
|
||||
supertest: SuperTest.Agent;
|
||||
requestHeader?: Record<string, string>;
|
||||
apiKeyHeader?: Record<string, string>;
|
||||
}): Promise<() => Promise<void>> {
|
||||
const config = {
|
||||
apiProvider: 'OpenAI',
|
||||
defaultModel: 'gpt-4',
|
||||
apiUrl: 'http://localhost:3002',
|
||||
};
|
||||
|
||||
const connector: { id: string } | undefined = (
|
||||
await supertest
|
||||
.post('/api/actions/connector')
|
||||
.set(requestHeader)
|
||||
.set(apiKeyHeader)
|
||||
.send({
|
||||
name: 'test Open AI',
|
||||
connector_type_id: '.gen-ai',
|
||||
config,
|
||||
secrets: {
|
||||
apiKey: 'genAiApiKey',
|
||||
},
|
||||
})
|
||||
.expect(200)
|
||||
).body;
|
||||
|
||||
return async () => {
|
||||
if (connector) {
|
||||
await supertest
|
||||
.delete(`/api/actions/connector/${connector.id}`)
|
||||
.set(requestHeader)
|
||||
.set(apiKeyHeader)
|
||||
.expect(204);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -53,6 +53,7 @@ import { UptimePageObject } from './uptime_page';
|
|||
import { UserProfilePageProvider } from './user_profile_page';
|
||||
import { WatcherPageObject } from './watcher_page';
|
||||
import { SearchProfilerPageProvider } from './search_profiler_page';
|
||||
import { SearchPlaygroundPageProvider } from './search_playground_page';
|
||||
|
||||
// just like services, PageObjects are defined as a map of
|
||||
// names to Providers. Merge in Kibana's or pick specific ones
|
||||
|
@ -93,6 +94,7 @@ export const pageObjects = {
|
|||
roleMappings: RoleMappingsPageProvider,
|
||||
rollup: RollupPageObject,
|
||||
searchProfiler: SearchProfilerPageProvider,
|
||||
searchPlayground: SearchPlaygroundPageProvider,
|
||||
searchSessionsManagement: SearchSessionsPageProvider,
|
||||
security: SecurityPageObject,
|
||||
shareSavedObjectsToSpace: ShareSavedObjectsToSpacePageProvider,
|
||||
|
|
114
x-pack/test/functional/page_objects/search_playground_page.ts
Normal file
114
x-pack/test/functional/page_objects/search_playground_page.ts
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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 '../ftr_provider_context';
|
||||
|
||||
export function SearchPlaygroundPageProvider({ getService }: FtrProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const comboBox = getService('comboBox');
|
||||
const browser = getService('browser');
|
||||
|
||||
return {
|
||||
PlaygroundStartChatPage: {
|
||||
async expectPlaygroundStartChatPageComponentsToExist() {
|
||||
await testSubjects.existOrFail('startChatPage');
|
||||
await testSubjects.existOrFail('selectIndicesChatPanel');
|
||||
await testSubjects.existOrFail('startChatButton');
|
||||
},
|
||||
|
||||
async expectPlaygroundHeaderComponentsToExist() {
|
||||
await testSubjects.existOrFail('playground-header-actions');
|
||||
await testSubjects.existOrFail('playground-documentation-link');
|
||||
},
|
||||
|
||||
async expectCreateIndexButtonToMissed() {
|
||||
await testSubjects.missingOrFail('createIndexButton');
|
||||
},
|
||||
|
||||
async expectCreateIndexButtonToExists() {
|
||||
await testSubjects.existOrFail('createIndexButton');
|
||||
},
|
||||
|
||||
async expectNoIndexCalloutExists() {
|
||||
await testSubjects.existOrFail('createIndexCallout');
|
||||
},
|
||||
|
||||
async expectSelectIndex(indexName: string) {
|
||||
await browser.refresh();
|
||||
await testSubjects.missingOrFail('createIndexCallout');
|
||||
await testSubjects.existOrFail('selectIndicesComboBox');
|
||||
await comboBox.setCustom('selectIndicesComboBox', indexName);
|
||||
},
|
||||
|
||||
async expectNoIndicesFieldsWarningExists() {
|
||||
await testSubjects.existOrFail('NoIndicesFieldsMessage');
|
||||
},
|
||||
|
||||
async expectAddConnectorButtonExists() {
|
||||
await testSubjects.existOrFail('setupGenAIConnectorButton');
|
||||
},
|
||||
|
||||
async expectOpenConnectorPagePlayground() {
|
||||
await testSubjects.click('setupGenAIConnectorButton');
|
||||
await testSubjects.existOrFail('create-connector-flyout');
|
||||
},
|
||||
|
||||
async expectHideGenAIPanelConnector(createConnector: () => Promise<void>) {
|
||||
await createConnector();
|
||||
await browser.refresh();
|
||||
await testSubjects.missingOrFail('connectToLLMChatPanel');
|
||||
},
|
||||
|
||||
async expectToStartChatPage() {
|
||||
expect(await testSubjects.isEnabled('startChatButton')).to.be(true);
|
||||
await testSubjects.click('startChatButton');
|
||||
await testSubjects.existOrFail('chatPage');
|
||||
},
|
||||
},
|
||||
PlaygroundChatPage: {
|
||||
async expectChatWorks() {
|
||||
await testSubjects.existOrFail('questionInput');
|
||||
await testSubjects.setValue('questionInput', 'test question');
|
||||
await testSubjects.click('sendQuestionButton');
|
||||
await testSubjects.existOrFail('userMessage');
|
||||
},
|
||||
|
||||
async expectOpenViewCode() {
|
||||
await testSubjects.click('viewCodeActionButton');
|
||||
await testSubjects.existOrFail('viewCodeFlyout');
|
||||
await testSubjects.click('euiFlyoutCloseButton');
|
||||
},
|
||||
|
||||
async expectViewQueryHasFields() {
|
||||
await testSubjects.click('viewQueryActionButton');
|
||||
await testSubjects.existOrFail('viewQueryFlyout');
|
||||
const fields = await testSubjects.findAll('queryField');
|
||||
|
||||
expect(fields.length).to.be(1);
|
||||
|
||||
const codeBlock = await testSubjects.find('ViewElasticsearchQueryResult');
|
||||
const code = await codeBlock.getVisibleText();
|
||||
expect(code.replace(/ /g, '')).to.be(
|
||||
'{\n"retriever":{\n"standard":{\n"query":{\n"multi_match":{\n"query":"{query}",\n"fields":[\n"baz"\n]\n}\n}\n}\n}\n}'
|
||||
);
|
||||
await testSubjects.click('euiFlyoutCloseButton');
|
||||
},
|
||||
|
||||
async expectEditContextOpens() {
|
||||
await testSubjects.click('editContextActionButton');
|
||||
await testSubjects.existOrFail('editContextFlyout');
|
||||
await testSubjects.click('contextFieldsSelectable_basic_index');
|
||||
await testSubjects.existOrFail('contextField');
|
||||
const fields = await testSubjects.findAll('contextField');
|
||||
|
||||
expect(fields.length).to.be(1);
|
||||
await testSubjects.click('euiFlyoutCloseButton');
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
|
@ -21,7 +21,6 @@ import { SvlRuleDetailsPageProvider } from './svl_rule_details_ui_page';
|
|||
import { SvlSearchConnectorsPageProvider } from './svl_search_connectors_page';
|
||||
import { SvlManagementPageProvider } from './svl_management_page';
|
||||
import { SvlIngestPipelines } from './svl_ingest_pipelines';
|
||||
import { SvlPlaygroundPageProvider } from './svl_playground_page';
|
||||
|
||||
export const pageObjects = {
|
||||
...xpackFunctionalPageObjects,
|
||||
|
@ -39,5 +38,4 @@ export const pageObjects = {
|
|||
svlRuleDetailsUI: SvlRuleDetailsPageProvider,
|
||||
svlManagementPage: SvlManagementPageProvider,
|
||||
svlIngestPipelines: SvlIngestPipelines,
|
||||
svlPlaygroundUI: SvlPlaygroundPageProvider,
|
||||
};
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* 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 { FtrProviderContext } from '../ftr_provider_context';
|
||||
|
||||
export function SvlPlaygroundPageProvider({ getService }: FtrProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
return {
|
||||
PlaygrounStartChatPage: {
|
||||
async expectPlaygroundStartChatPageComponentsToExist() {
|
||||
await testSubjects.existOrFail('chat-playground-home-page-title');
|
||||
await testSubjects.existOrFail('selectIndicesChatPanel');
|
||||
await testSubjects.existOrFail('startChatButton');
|
||||
},
|
||||
|
||||
async expectPlaygroundHeaderComponentsToExist() {
|
||||
await testSubjects.existOrFail('playground-header-actions');
|
||||
await testSubjects.existOrFail('playground-documentation-link');
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
|
@ -5,24 +5,144 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import type SuperTest from 'supertest';
|
||||
import { testHasEmbeddedConsole } from './embedded_console';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { RoleCredentials } from '../../../shared/services';
|
||||
|
||||
const indexName = 'basic_index';
|
||||
const esArchiveIndex = 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index';
|
||||
async function createOpenAIConnector({
|
||||
supertest,
|
||||
requestHeader = {},
|
||||
apiKeyHeader = {},
|
||||
}: {
|
||||
supertest: SuperTest.Agent;
|
||||
requestHeader?: Record<string, string>;
|
||||
apiKeyHeader?: Record<string, string>;
|
||||
}): Promise<() => Promise<void>> {
|
||||
const config = {
|
||||
apiProvider: 'OpenAI',
|
||||
defaultModel: 'gpt-4',
|
||||
apiUrl: 'http://localhost:3002',
|
||||
};
|
||||
|
||||
const connector: { id: string } | undefined = (
|
||||
await supertest
|
||||
.post('/api/actions/connector')
|
||||
.set(requestHeader)
|
||||
.set(apiKeyHeader)
|
||||
.send({
|
||||
name: 'test Open AI',
|
||||
connector_type_id: '.gen-ai',
|
||||
config,
|
||||
secrets: {
|
||||
apiKey: 'genAiApiKey',
|
||||
},
|
||||
})
|
||||
.expect(200)
|
||||
).body;
|
||||
|
||||
return async () => {
|
||||
if (connector) {
|
||||
await supertest
|
||||
.delete(`/api/actions/connector/${connector.id}`)
|
||||
.set(requestHeader)
|
||||
.set(apiKeyHeader)
|
||||
.expect(204);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||
const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation', 'searchPlayground']);
|
||||
const svlCommonApi = getService('svlCommonApi');
|
||||
const svlUserManager = getService('svlUserManager');
|
||||
const supertestWithoutAuth = getService('supertestWithoutAuth');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const createIndex = async () => await esArchiver.load(esArchiveIndex);
|
||||
let roleAuthc: RoleCredentials;
|
||||
|
||||
describe('Serverless Playground Overview', () => {
|
||||
let removeOpenAIConnector: () => Promise<void>;
|
||||
let createConnector: () => Promise<void>;
|
||||
|
||||
export default function ({ getPageObjects }: FtrProviderContext) {
|
||||
const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation', 'svlPlaygroundUI']);
|
||||
describe('Playground', function () {
|
||||
before(async () => {
|
||||
await pageObjects.svlCommonPage.login();
|
||||
await pageObjects.svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'searchPlayground' });
|
||||
await pageObjects.svlCommonNavigation.sidenav.clickLink({
|
||||
deepLinkId: 'searchPlayground',
|
||||
});
|
||||
|
||||
const requestHeader = svlCommonApi.getInternalRequestHeader();
|
||||
roleAuthc = await svlUserManager.createApiKeyForRole('admin');
|
||||
createConnector = async () => {
|
||||
removeOpenAIConnector = await createOpenAIConnector({
|
||||
supertest: supertestWithoutAuth,
|
||||
requestHeader,
|
||||
apiKeyHeader: roleAuthc.apiKeyHeader,
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await removeOpenAIConnector?.();
|
||||
await esArchiver.unload(esArchiveIndex);
|
||||
await svlUserManager.invalidateApiKeyForRole(roleAuthc);
|
||||
await pageObjects.svlCommonPage.forceLogout();
|
||||
});
|
||||
|
||||
it('playground app is loaded', async () => {
|
||||
await pageObjects.svlPlaygroundUI.PlaygrounStartChatPage.expectPlaygroundStartChatPageComponentsToExist();
|
||||
await pageObjects.svlPlaygroundUI.PlaygrounStartChatPage.expectPlaygroundHeaderComponentsToExist();
|
||||
describe('start chat page', () => {
|
||||
it('playground app is loaded', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundStartChatPageComponentsToExist();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundHeaderComponentsToExist();
|
||||
});
|
||||
|
||||
it('show no index callout', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectNoIndexCalloutExists();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectCreateIndexButtonToMissed();
|
||||
});
|
||||
|
||||
it('hide no index callout when index added', async () => {
|
||||
await createIndex();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectSelectIndex(indexName);
|
||||
});
|
||||
|
||||
it('show add connector button', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectAddConnectorButtonExists();
|
||||
});
|
||||
|
||||
it('click add connector button opens connector flyout', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectOpenConnectorPagePlayground();
|
||||
});
|
||||
|
||||
it('hide gen ai panel when connector exists', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectHideGenAIPanelConnector(
|
||||
createConnector
|
||||
);
|
||||
});
|
||||
|
||||
it('show chat page', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectSelectIndex(indexName);
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectToStartChatPage();
|
||||
});
|
||||
});
|
||||
|
||||
describe('chat page', () => {
|
||||
it('chat works', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundChatPage.expectChatWorks();
|
||||
});
|
||||
|
||||
it('open view code', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundChatPage.expectOpenViewCode();
|
||||
});
|
||||
|
||||
it('show fields and code in view query', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundChatPage.expectViewQueryHasFields();
|
||||
});
|
||||
|
||||
it('show edit context', async () => {
|
||||
await pageObjects.searchPlayground.PlaygroundChatPage.expectEditContextOpens();
|
||||
});
|
||||
});
|
||||
|
||||
it('has embedded console', async () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue