Skip to content

Commit

Permalink
✅ Integrate last tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dej611 committed Dec 19, 2024
1 parent aece621 commit affa1f9
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 28 deletions.
96 changes: 78 additions & 18 deletions x-pack/plugins/lens/public/react_embeddable/data_loader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import {
LensApi,
LensEmbeddableStartServices,
LensInternalApi,
LensOverrides,
LensPublicCallbacks,
LensRuntimeState,
} from './types';
import {
HasParentApi,
Expand Down Expand Up @@ -84,12 +86,14 @@ type ChangeFnType = ({

async function callDataLoader(
changeFn: ChangeFnType,
attributes: LensDocument = getLensAttributesMock(),
parentApiOverrides?: Partial<{
filters$: BehaviorSubject<Filter[] | undefined>;
query$: BehaviorSubject<Query | AggregateQuery | undefined>;
timeRange$: BehaviorSubject<TimeRange | undefined>;
}>
runtimeState: LensRuntimeState = { attributes: getLensAttributesMock() },
parentApiOverrides?: Partial<
{
filters$: BehaviorSubject<Filter[] | undefined>;
query$: BehaviorSubject<Query | AggregateQuery | undefined>;
timeRange$: BehaviorSubject<TimeRange | undefined>;
} & LensOverrides
>
): Promise<void> {
const parentApi = {
...createUnifiedSearchApi(),
Expand All @@ -111,9 +115,7 @@ async function callDataLoader(
...getLensApiMock(),
parentApi,
};
const getState = jest.fn(() => ({
attributes,
}));
const getState = jest.fn(() => runtimeState);
const internalApi = getLensInternalApiMock();
const services = makeEmbeddableServices(new BehaviorSubject<string>(''), undefined, {
visOverrides: { id: 'lnsXY' },
Expand All @@ -126,7 +128,7 @@ async function callDataLoader(
api,
parentApi,
internalApi,
services,
services
);
// there's a debounce, so skip to the next tick
jest.advanceTimersByTime(100);
Expand Down Expand Up @@ -302,7 +304,7 @@ describe('Data Loader', () => {

return false;
},
attributes,
{ attributes },
createUnifiedSearchApi(parentApiQuery, parentApiFilters, parentApiTimeRange)
);
});
Expand Down Expand Up @@ -342,13 +344,71 @@ describe('Data Loader', () => {

return false;
},
getLensAttributesMock({
references: [
{ type: 'index-pattern', id: '123', name: 'abc' },
{ type: 'index-pattern', id: '123', name: 'def' },
{ type: 'index-pattern', id: '456', name: 'ghi' },
],
})
{
attributes: getLensAttributesMock({
references: [
{ type: 'index-pattern', id: '123', name: 'abc' },
{ type: 'index-pattern', id: '123', name: 'def' },
{ type: 'index-pattern', id: '456', name: 'ghi' },
],
}),
}
);
});

it('should override noPadding in the display options if noPadding is set in the embeddable input', async () => {
await callDataLoader(async ({ internalApi }) => {
await waitForValue(
internalApi.expressionParams$,
(v: unknown) => isObject(v) && 'expression' in v && typeof v.expression != null
);

const params = internalApi.expressionParams$.getValue()!;
expect(params.noPadding).toBeUndefined();
return false;
});
});

it('should reload only once when the attributes or savedObjectId and the search context change at the same time', async () => {
await callDataLoader(async ({ internalApi, api }) => {
// trigger a change by changing the title in the attributes
(internalApi.attributes$ as BehaviorSubject<LensDocument | undefined>).next({
...internalApi.attributes$.getValue(),
title: faker.lorem.word(),
});
(api.savedObjectId as BehaviorSubject<string | undefined>).next('newSavedObjectId');
});
});

it('should pass over the overrides as variables', async () => {
await callDataLoader(
async ({ internalApi }) => {
await waitForValue(
internalApi.expressionParams$,
(v: unknown) => isObject(v) && 'variables' in v && typeof v.variables != null
);

const params = internalApi.expressionParams$.getValue()!;
expect(params.variables).toEqual(
expect.objectContaining({
overrides: {
settings: {
onBrushEnd: 'ignore',
},
},
})
);
return false;
},
// send a runtime state with the overrides
{
attributes: getLensAttributesMock(),
overrides: {
settings: {
onBrushEnd: 'ignore',
},
},
}
);
});
});
8 changes: 1 addition & 7 deletions x-pack/plugins/lens/public/react_embeddable/data_loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,7 @@ export function loadEmbeddableData(
updateWarnings,
resetMessages,
updateMessages,
} = buildUserMessagesHelpers(
api,
internalApi,
services,
onBeforeBadgesRender,
metaInfo
);
} = buildUserMessagesHelpers(api, internalApi, services, onBeforeBadgesRender, metaInfo);

const dispatchBlockingErrorIfAny = () => {
const blockingErrors = getUserMessages(blockingMessageDisplayLocations, {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* 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 { faker } from '@faker-js/faker';
import { initializeEditApi } from './initialize_edit';
import {
getLensApiMock,
getLensInternalApiMock,
getLensRuntimeStateMock,
makeEmbeddableServices,
} from '../mocks';
import { BehaviorSubject } from 'rxjs';
import { ApplicationStart } from '@kbn/core/public';
import { LensEmbeddableStartServices } from '../types';

function createEditApi(servicesOverrides: Partial<LensEmbeddableStartServices> = {}) {
const internalApi = getLensInternalApiMock();
const runtimeState = getLensRuntimeStateMock();
const api = getLensApiMock();
const services = {
...makeEmbeddableServices(new BehaviorSubject<string>(''), undefined, {
visOverrides: { id: 'lnsXY' },
dataOverrides: { id: 'formBased' },
}),
...servicesOverrides,
};
return initializeEditApi(
faker.string.uuid(),
runtimeState,
() => runtimeState,
internalApi,
api,
api,
() => false, // DSL based
services,
{ getAppContext: () => ({ currentAppId: 'lens' }), viewMode: new BehaviorSubject('edit') }
);
}

describe('edit features', () => {
it('should be editable if visualize library privileges allow it', () => {
const editApi = createEditApi();
expect(editApi.api.isEditingEnabled()).toBe(true);
});

it('should not be editable if visualize library privileges do not allow it', () => {
const editApi = createEditApi({
capabilities: {
visualize: {
// cannot save
save: false,
saveQuery: true,
// cannot see the visualization
show: true,
createShortUrl: true,
},
dashboard: {
// cannot edit in dashboard
showWriteControls: false,
},
} as unknown as ApplicationStart['capabilities'],
});

expect(editApi.api.isEditingEnabled()).toBe(false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,12 @@ export function initializeEditApi(
* Check everything here: user/app permissions and the current inline editing state
*/
isEditingEnabled: () => {
return apiHasAppContext(parentApi) && canEdit() && panelManagementApi.isEditingEnabled();
return Boolean(
parentApi &&
apiHasAppContext(parentApi) &&
canEdit() &&
panelManagementApi.isEditingEnabled()
);
},
getEditHref: async () => {
if (!parentApi || !apiHasAppContext(parentApi)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ function buildUserMessagesApi(metaInfo?: SharingSavedObjectProps) {
const internalApi = getLensInternalApiMock();
const services = makeEmbeddableServices(new BehaviorSubject<string>(''), undefined, {
visOverrides: { id: 'lnsXY' },
dataOverrides: { id: 'form_based' },
dataOverrides: { id: 'formBased' },
});
// fill the context with some data
internalApi.updateVisualizationContext({
activeAttributes: getLensAttributesMock({
state: {
datasourceStates: { form_based: { something: {} } },
datasourceStates: { formBased: { something: {} } },
visualization: { activeId: 'lnsXY', state: {} },
query: { query: '', language: 'kuery' },
filters: [],
Expand Down

0 comments on commit affa1f9

Please sign in to comment.