mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[CLOUD] Add security question in onboarding (#208229)
## Summary https://github.com/elastic/cloud/issues/133183 ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Kateryna Stukan <92258556+galaxxyz@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
cdcd47136f
commit
ac22f58bc3
7 changed files with 404 additions and 79 deletions
|
@ -47,6 +47,41 @@ describe('persistTokenCloudData', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('creates a new saved object if none exists and security details are provided', async () => {
|
||||
(mockSavedObjectsClient.get as jest.Mock).mockRejectedValue(
|
||||
SavedObjectsErrorHelpers.createGenericNotFoundError()
|
||||
);
|
||||
await persistTokenCloudData(mockSavedObjectsClient, {
|
||||
logger: mockLogger,
|
||||
solutionType: 'security',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: true,
|
||||
type: 'splunk',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockSavedObjectsClient.create).toHaveBeenCalledWith(
|
||||
CLOUD_DATA_SAVED_OBJECT_TYPE,
|
||||
{
|
||||
onboardingData: {
|
||||
solutionType: 'security',
|
||||
token: '',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: true,
|
||||
type: 'splunk',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ id: CLOUD_DATA_SAVED_OBJECT_ID }
|
||||
);
|
||||
});
|
||||
|
||||
it('updates an existing saved object if onboardingToken is provided and different', async () => {
|
||||
(mockSavedObjectsClient.get as jest.Mock).mockResolvedValue({
|
||||
id: CLOUD_DATA_SAVED_OBJECT_ID,
|
||||
|
@ -75,13 +110,67 @@ describe('persistTokenCloudData', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('does nothing if onboardingToken is the same', async () => {
|
||||
it('updates an existing saved object if security details are provided and different', async () => {
|
||||
(mockSavedObjectsClient.get as jest.Mock).mockResolvedValue({
|
||||
id: CLOUD_DATA_SAVED_OBJECT_ID,
|
||||
attributes: {
|
||||
onboardingData: {
|
||||
solutionType: 'security',
|
||||
token: 'test_token',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: true,
|
||||
type: 'splunk',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await persistTokenCloudData(mockSavedObjectsClient, {
|
||||
logger: mockLogger,
|
||||
solutionType: 'security',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockSavedObjectsClient.update).toHaveBeenCalledWith(
|
||||
CLOUD_DATA_SAVED_OBJECT_TYPE,
|
||||
CLOUD_DATA_SAVED_OBJECT_ID,
|
||||
{
|
||||
onboardingData: {
|
||||
solutionType: 'security',
|
||||
token: 'test_token',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('does nothing if onboardingToken and security details are the same', async () => {
|
||||
(mockSavedObjectsClient.get as jest.Mock).mockResolvedValue({
|
||||
id: CLOUD_DATA_SAVED_OBJECT_ID,
|
||||
attributes: {
|
||||
onboardingData: {
|
||||
token: 'same_token',
|
||||
solutionType: 'test_solution',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: true,
|
||||
type: 'splunk',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -89,6 +178,13 @@ describe('persistTokenCloudData', () => {
|
|||
logger: mockLogger,
|
||||
onboardingToken: 'same_token',
|
||||
solutionType: 'test_solution',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: true,
|
||||
type: 'splunk',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockSavedObjectsClient.update).not.toHaveBeenCalled();
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { isDeepEqual } from 'react-use/lib/util';
|
||||
|
||||
import { Logger, SavedObjectsClientContract, SavedObjectsErrorHelpers } from '@kbn/core/server';
|
||||
import { CloudDataAttributes, SolutionType } from '../routes/types';
|
||||
import { CloudDataAttributes, CloudSecurityAnswer, SolutionType } from '../routes/types';
|
||||
import { CLOUD_DATA_SAVED_OBJECT_TYPE } from '../saved_objects';
|
||||
import { CLOUD_DATA_SAVED_OBJECT_ID } from '../routes/constants';
|
||||
|
||||
|
@ -17,11 +19,13 @@ export const persistTokenCloudData = async (
|
|||
returnError,
|
||||
onboardingToken,
|
||||
solutionType,
|
||||
security,
|
||||
}: {
|
||||
logger?: Logger;
|
||||
returnError?: boolean;
|
||||
onboardingToken?: string;
|
||||
solutionType?: string;
|
||||
security?: CloudSecurityAnswer;
|
||||
}
|
||||
): Promise<void> => {
|
||||
let cloudDataSo = null;
|
||||
|
@ -41,23 +45,25 @@ export const persistTokenCloudData = async (
|
|||
}
|
||||
}
|
||||
}
|
||||
const securityAttributes = cloudDataSo?.attributes.onboardingData?.security;
|
||||
|
||||
try {
|
||||
if (onboardingToken && cloudDataSo === null) {
|
||||
if ((onboardingToken || security) && cloudDataSo === null) {
|
||||
await savedObjectsClient.create<CloudDataAttributes>(
|
||||
CLOUD_DATA_SAVED_OBJECT_TYPE,
|
||||
{
|
||||
onboardingData: {
|
||||
solutionType: solutionType as SolutionType,
|
||||
token: onboardingToken,
|
||||
token: onboardingToken ?? '',
|
||||
security,
|
||||
},
|
||||
},
|
||||
{ id: CLOUD_DATA_SAVED_OBJECT_ID }
|
||||
);
|
||||
} else if (
|
||||
onboardingToken &&
|
||||
cloudDataSo?.attributes.onboardingData.token &&
|
||||
cloudDataSo?.attributes.onboardingData.token !== onboardingToken
|
||||
cloudDataSo &&
|
||||
(cloudDataSo?.attributes.onboardingData.token !== onboardingToken ||
|
||||
!isDeepEqual(securityAttributes, security))
|
||||
) {
|
||||
await savedObjectsClient.update<CloudDataAttributes>(
|
||||
CLOUD_DATA_SAVED_OBJECT_TYPE,
|
||||
|
@ -66,7 +72,8 @@ export const persistTokenCloudData = async (
|
|||
onboardingData: {
|
||||
solutionType:
|
||||
(solutionType as SolutionType) ?? cloudDataSo?.attributes.onboardingData.solutionType,
|
||||
token: onboardingToken,
|
||||
token: onboardingToken ?? cloudDataSo?.attributes.onboardingData.token,
|
||||
security: security ?? securityAttributes,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
|
|
@ -13,6 +13,7 @@ import type { SolutionId } from '@kbn/core-chrome-browser';
|
|||
import { schema } from '@kbn/config-schema';
|
||||
import { parseNextURL } from '@kbn/std';
|
||||
|
||||
import camelcaseKeys from 'camelcase-keys';
|
||||
import type { CloudConfigType } from './config';
|
||||
|
||||
import { registerCloudDeploymentMetadataAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context';
|
||||
|
@ -215,6 +216,24 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
|
|||
{
|
||||
next: schema.maybe(schema.string()),
|
||||
onboarding_token: schema.maybe(schema.string()),
|
||||
security: schema.maybe(
|
||||
schema.object({
|
||||
use_case: schema.oneOf([
|
||||
schema.literal('siem'),
|
||||
schema.literal('cloud'),
|
||||
schema.literal('edr'),
|
||||
schema.literal('other'),
|
||||
]),
|
||||
migration: schema.maybe(
|
||||
schema.object({
|
||||
value: schema.boolean(),
|
||||
type: schema.maybe(
|
||||
schema.oneOf([schema.literal('splunk'), schema.literal('other')])
|
||||
),
|
||||
})
|
||||
),
|
||||
})
|
||||
),
|
||||
},
|
||||
{ unknowns: 'ignore' }
|
||||
)
|
||||
|
@ -237,9 +256,16 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
|
|||
// need to get reed of ../../ to make sure we will not be out of space basePath
|
||||
const normalizedRoute = new URL(route, 'https://localhost');
|
||||
|
||||
const queryOnboardingToken = request.url.searchParams.get('onboarding_token');
|
||||
const queryOnboardingToken = request.query?.onboarding_token ?? undefined;
|
||||
const queryOnboardingSecurityRaw = request.query?.security ?? undefined;
|
||||
const queryOnboardingSecurity = queryOnboardingSecurityRaw
|
||||
? camelcaseKeys(queryOnboardingSecurityRaw, {
|
||||
deep: true,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
const solutionType = this.config.onboarding?.default_solution;
|
||||
if (queryOnboardingToken) {
|
||||
if (queryOnboardingToken || queryOnboardingSecurity) {
|
||||
core
|
||||
.getStartServices()
|
||||
.then(async ([coreStart]) => {
|
||||
|
@ -251,6 +277,7 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
|
|||
logger: this.logger,
|
||||
onboardingToken: queryOnboardingToken,
|
||||
solutionType,
|
||||
security: queryOnboardingSecurity,
|
||||
});
|
||||
})
|
||||
.catch((errorMsg) => this.logger.error(errorMsg));
|
||||
|
|
|
@ -16,5 +16,14 @@ export interface CloudDataAttributes {
|
|||
onboardingData: {
|
||||
solutionType?: SolutionType;
|
||||
token: string;
|
||||
security?: CloudSecurityAnswer;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CloudSecurityAnswer {
|
||||
useCase: 'siem' | 'cloud' | 'edr' | 'other';
|
||||
migration?: {
|
||||
value: boolean;
|
||||
type?: 'splunk' | 'other';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
const testEndpointsPlugin = resolve(__dirname, '../security_functional/plugins/test_endpoints');
|
||||
|
||||
return {
|
||||
testFiles: [resolve(__dirname, './tests/onboarding_token.ts')],
|
||||
testFiles: [resolve(__dirname, './tests/onboarding.ts')],
|
||||
|
||||
services,
|
||||
pageObjects,
|
||||
|
|
254
x-pack/test/functional_cloud/tests/onboarding.ts
Normal file
254
x-pack/test/functional_cloud/tests/onboarding.ts
Normal file
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 { parse } from 'url';
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
import { MAIN_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server';
|
||||
import type { FtrProviderContext } from '../../security_functional/ftr_provider_context';
|
||||
|
||||
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const es = getService('es');
|
||||
const find = getService('find');
|
||||
const browser = getService('browser');
|
||||
const deployment = getService('deployment');
|
||||
const PageObjects = getPageObjects(['common']);
|
||||
const supertest = getService('supertest');
|
||||
|
||||
const deleteSavedObject = async () => {
|
||||
await es.deleteByQuery({
|
||||
index: MAIN_SAVED_OBJECT_INDEX,
|
||||
q: 'type:cloud',
|
||||
wait_for_completion: true,
|
||||
refresh: true,
|
||||
body: {},
|
||||
conflicts: 'proceed',
|
||||
});
|
||||
};
|
||||
|
||||
describe('Onboarding integration', function () {
|
||||
this.tags('includeFirefox');
|
||||
|
||||
before(async () => {
|
||||
await getService('esSupertest')
|
||||
.post('/_security/role_mapping/saml1')
|
||||
.send({ roles: ['superuser'], enabled: true, rules: { field: { 'realm.name': 'saml1' } } })
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await browser.get(deployment.getHostPort() + '/logout');
|
||||
await PageObjects.common.waitUntilUrlIncludes('logged_out');
|
||||
|
||||
await deleteSavedObject();
|
||||
});
|
||||
|
||||
it('Redirect and save token', async () => {
|
||||
await browser.get(
|
||||
deployment.getHostPort() +
|
||||
`/app/cloud/onboarding?onboarding_token=vector&next=${encodeURIComponent(
|
||||
'/app/elasticsearch/vector_search'
|
||||
)}#some=hash-value`
|
||||
);
|
||||
await find.byCssSelector('[data-test-subj="userMenuButton"]', 20000);
|
||||
|
||||
// We need to make sure that both path and hash are respected.
|
||||
const currentURL = parse(await browser.getCurrentUrl());
|
||||
expect(currentURL.pathname).to.eql('/app/elasticsearch/vector_search');
|
||||
expect(currentURL.hash).to.eql('#some=hash-value');
|
||||
|
||||
const {
|
||||
body: { onboardingData },
|
||||
} = await supertest
|
||||
.get('/internal/cloud/solution')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('x-elastic-internal-origin', 'cloud')
|
||||
.set('elastic-api-version', '1')
|
||||
.expect(200);
|
||||
expect(onboardingData).to.eql({ token: 'vector' });
|
||||
});
|
||||
|
||||
it('Redirect and save security details at creation time', async () => {
|
||||
const securityDetails = '{"use_case":"siem","migration":{"value":true,"type":"splunk"}}';
|
||||
|
||||
await browser.get(
|
||||
deployment.getHostPort() +
|
||||
`/app/cloud/onboarding?onboarding_token=security&security=${securityDetails}&next=${encodeURIComponent(
|
||||
'/app/security/get_started'
|
||||
)}#some=hash-value`
|
||||
);
|
||||
await find.byCssSelector('[data-test-subj="userMenuButton"]', 20000);
|
||||
|
||||
// We need to make sure that both path and hash are respected.
|
||||
const currentURL = parse(await browser.getCurrentUrl());
|
||||
expect(currentURL.pathname).to.eql('/app/security/get_started');
|
||||
expect(currentURL.hash).to.eql('#some=hash-value');
|
||||
|
||||
const {
|
||||
body: { onboardingData },
|
||||
} = await supertest
|
||||
.get('/internal/cloud/solution')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('x-elastic-internal-origin', 'cloud')
|
||||
.set('elastic-api-version', '1')
|
||||
.expect(200);
|
||||
expect(onboardingData).to.eql({
|
||||
token: 'security',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: true,
|
||||
type: 'splunk',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Redirect and update security details', async () => {
|
||||
const securityDetails = '{"use_case":"siem","migration":{"value":true,"type":"splunk"}}';
|
||||
|
||||
await browser.get(
|
||||
deployment.getHostPort() +
|
||||
`/app/cloud/onboarding?onboarding_token=security&security=${securityDetails}&next=${encodeURIComponent(
|
||||
'/app/security/get_started'
|
||||
)}#some=hash-value`
|
||||
);
|
||||
await find.byCssSelector('[data-test-subj="userMenuButton"]', 20000);
|
||||
|
||||
// We need to make sure that both path and hash are respected.
|
||||
const currentURL = parse(await browser.getCurrentUrl());
|
||||
expect(currentURL.pathname).to.eql('/app/security/get_started');
|
||||
expect(currentURL.hash).to.eql('#some=hash-value');
|
||||
|
||||
const {
|
||||
body: { onboardingData },
|
||||
} = await supertest
|
||||
.get('/internal/cloud/solution')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('x-elastic-internal-origin', 'cloud')
|
||||
.set('elastic-api-version', '1')
|
||||
.expect(200);
|
||||
|
||||
expect(onboardingData).to.eql({
|
||||
token: 'security',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: true,
|
||||
type: 'splunk',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const securityDetailsUpdated =
|
||||
'{"use_case":"cloud","migration":{"value":true,"type":"other"}}';
|
||||
|
||||
await browser.get(
|
||||
deployment.getHostPort() +
|
||||
`/app/cloud/onboarding?onboarding_token=security&security=${securityDetailsUpdated}&next=${encodeURIComponent(
|
||||
'/app/security/get_started'
|
||||
)}#some=hash-value`
|
||||
);
|
||||
|
||||
await find.byCssSelector('[data-test-subj="userMenuButton"]', 20000);
|
||||
|
||||
const {
|
||||
body: { onboardingData: onboardingDataUpdated },
|
||||
} = await supertest
|
||||
.get('/internal/cloud/solution')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('x-elastic-internal-origin', 'cloud')
|
||||
.set('elastic-api-version', '1')
|
||||
.expect(200);
|
||||
|
||||
expect(onboardingDataUpdated).to.eql({
|
||||
token: 'security',
|
||||
security: {
|
||||
useCase: 'cloud',
|
||||
migration: {
|
||||
value: true,
|
||||
type: 'other',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it(`Redirect and keep initial onboarding token when it's not provided on update`, async () => {
|
||||
const securityDetails = '{"use_case":"siem","migration":{"value":true,"type":"splunk"}}';
|
||||
|
||||
await browser.get(
|
||||
deployment.getHostPort() +
|
||||
`/app/cloud/onboarding?onboarding_token=security&security=${securityDetails}&next=${encodeURIComponent(
|
||||
'/app/security/get_started'
|
||||
)}#some=hash-value`
|
||||
);
|
||||
await find.byCssSelector('[data-test-subj="userMenuButton"]', 20000);
|
||||
|
||||
// We need to make sure that both path and hash are respected.
|
||||
const currentURL = parse(await browser.getCurrentUrl());
|
||||
expect(currentURL.pathname).to.eql('/app/security/get_started');
|
||||
expect(currentURL.hash).to.eql('#some=hash-value');
|
||||
|
||||
const {
|
||||
body: { onboardingData },
|
||||
} = await supertest
|
||||
.get('/internal/cloud/solution')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('x-elastic-internal-origin', 'cloud')
|
||||
.set('elastic-api-version', '1')
|
||||
.expect(200);
|
||||
|
||||
expect(onboardingData).to.eql({
|
||||
token: 'security',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: true,
|
||||
type: 'splunk',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await browser.get(
|
||||
deployment.getHostPort() +
|
||||
`/app/cloud/onboarding?security=${securityDetails}&next=${encodeURIComponent(
|
||||
'/app/security/get_started'
|
||||
)}#some=hash-value`
|
||||
);
|
||||
|
||||
await find.byCssSelector('[data-test-subj="userMenuButton"]', 20000);
|
||||
|
||||
const {
|
||||
body: { onboardingData: onboardingDataUpdated },
|
||||
} = await supertest
|
||||
.get('/internal/cloud/solution')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('x-elastic-internal-origin', 'cloud')
|
||||
.set('elastic-api-version', '1')
|
||||
.expect(200);
|
||||
|
||||
expect(onboardingDataUpdated).to.eql({
|
||||
token: 'security',
|
||||
security: {
|
||||
useCase: 'siem',
|
||||
migration: {
|
||||
value: true,
|
||||
type: 'splunk',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,68 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 { parse } from 'url';
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
import type { FtrProviderContext } from '../../security_functional/ftr_provider_context';
|
||||
|
||||
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const find = getService('find');
|
||||
const browser = getService('browser');
|
||||
const deployment = getService('deployment');
|
||||
const PageObjects = getPageObjects(['common']);
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('onboarding token', function () {
|
||||
this.tags('includeFirefox');
|
||||
|
||||
before(async () => {
|
||||
await getService('esSupertest')
|
||||
.post('/_security/role_mapping/saml1')
|
||||
.send({ roles: ['superuser'], enabled: true, rules: { field: { 'realm.name': 'saml1' } } })
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await browser.get(deployment.getHostPort() + '/logout');
|
||||
await PageObjects.common.waitUntilUrlIncludes('logged_out');
|
||||
});
|
||||
|
||||
it('Redirect and save token', async () => {
|
||||
await browser.get(
|
||||
deployment.getHostPort() +
|
||||
`/app/cloud/onboarding?onboarding_token=vector&next=${encodeURIComponent(
|
||||
'/app/elasticsearch/vector_search'
|
||||
)}#some=hash-value`
|
||||
);
|
||||
await find.byCssSelector('[data-test-subj="userMenuButton"]', 20000);
|
||||
|
||||
// We need to make sure that both path and hash are respected.
|
||||
const currentURL = parse(await browser.getCurrentUrl());
|
||||
expect(currentURL.pathname).to.eql('/app/elasticsearch/vector_search');
|
||||
expect(currentURL.hash).to.eql('#some=hash-value');
|
||||
|
||||
const {
|
||||
body: { onboardingData },
|
||||
} = await supertest
|
||||
.get('/internal/cloud/solution')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('x-elastic-internal-origin', 'cloud')
|
||||
.set('elastic-api-version', '1')
|
||||
.expect(200);
|
||||
expect(onboardingData).to.eql({ token: 'vector' });
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue