Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unskip Chrome UI Functional Tests.test/functional/apps/dashboard/group3/dashboard_state·ts #152245

Merged
merged 12 commits into from
Feb 28, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -37,28 +37,35 @@ export const isPanelVersionTooOld = (panels: SavedDashboardPanel[]) => {
return false;
};

function getPanelsMap(appStateInUrl: SharedDashboardState): DashboardPanelMap | undefined {
if (!appStateInUrl.panels) {
return undefined;
}

if (appStateInUrl.panels.length === 0) {
return {};
}

if (isPanelVersionTooOld(appStateInUrl.panels)) {
pluginServices.getServices().notifications.toasts.addWarning(getPanelTooOldErrorString());
return undefined;
}

return convertSavedPanelsToPanelMap(appStateInUrl.panels);
}

/**
* Loads any dashboard state from the URL, and removes the state from the URL.
*/
export const loadAndRemoveDashboardState = (
kbnUrlStateStorage: IKbnUrlStateStorage
): Partial<DashboardContainerByValueInput> => {
const {
notifications: { toasts },
} = pluginServices.getServices();
const rawAppStateInUrl = kbnUrlStateStorage.get<SharedDashboardState>(
DASHBOARD_STATE_STORAGE_KEY
);
if (!rawAppStateInUrl) return {};

let panelsMap: DashboardPanelMap | undefined;
if (rawAppStateInUrl.panels && rawAppStateInUrl.panels.length > 0) {
if (isPanelVersionTooOld(rawAppStateInUrl.panels)) {
toasts.addWarning(getPanelTooOldErrorString());
} else {
panelsMap = convertSavedPanelsToPanelMap(rawAppStateInUrl.panels);
}
}
const panelsMap = getPanelsMap(rawAppStateInUrl);

const nextUrl = replaceUrlHashQuery(window.location.href, (hashQuery) => {
delete hashQuery[DASHBOARD_STATE_STORAGE_KEY];
Expand Down
142 changes: 127 additions & 15 deletions test/functional/apps/dashboard/group3/dashboard_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@

import expect from '@kbn/expect';
import chroma from 'chroma-js';

import rison from '@kbn/rison';
import { DEFAULT_PANEL_WIDTH } from '@kbn/dashboard-plugin/public/dashboard_constants';
import type { SharedDashboardState } from '@kbn/dashboard-plugin/common';
import { PIE_CHART_VIS_NAME, AREA_CHART_VIS_NAME } from '../../../page_objects/dashboard_page';
import { FtrProviderContext } from '../../../ftr_provider_context';

export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects([
'common',
'dashboard',
'visualize',
'header',
Expand All @@ -31,6 +33,36 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const elasticChart = getService('elasticChart');
const dashboardAddPanel = getService('dashboardAddPanel');
const xyChartSelector = 'xyVisChart';
const log = getService('log');

const updateAppStateQueryParam = (
url: string,
setAppState: (appState: Partial<SharedDashboardState>) => Partial<SharedDashboardState>
) => {
log.debug(`updateAppStateQueryParam, before url: ${url}`);

// Using lastIndexOf because URL may have 2 sets of query parameters.
// 1) server query parameters, '_t'
// 2) client query parameters, '_g' and '_a'. Anything after the '#' in a URL is used by the client
// Example shape of URL http://localhost:5620/app/dashboards?_t=12345#/create?_g=()
const clientQueryParamsStartIndex = url.lastIndexOf('?');
if (clientQueryParamsStartIndex === -1) {
throw Error(`Unable to locate query parameters in URL: ${url}`);
}
const urlBeforeClientQueryParams = url.substring(0, clientQueryParamsStartIndex);
const urlParams = new URLSearchParams(url.substring(clientQueryParamsStartIndex + 1));
const appState: Partial<SharedDashboardState> = urlParams.has('_a')
? (rison.decode(urlParams.get('_a')!) as Partial<SharedDashboardState>)
: {};
const newAppState = {
...appState,
...setAppState(appState),
};
urlParams.set('_a', rison.encode(newAppState));
const newUrl = urlBeforeClientQueryParams + '?' + urlParams.toString();
log.debug(`updateAppStateQueryParam, after url: ${newUrl}`);
return newUrl;
};

const enableNewChartLibraryDebug = async (force = false) => {
if ((await PageObjects.visChart.isNewChartsLibraryEnabled()) || force) {
Expand All @@ -39,10 +71,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
}
};

// Failing: See https://github.com/elastic/kibana/issues/139762
describe.skip('dashboard state', function describeIndexTests() {
// Used to track flag before and after reset

describe('dashboard state', function () {
before(async function () {
await PageObjects.dashboard.initTests();
await PageObjects.dashboard.preserveCrossAppState();
Expand Down Expand Up @@ -140,8 +169,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
it('Saved search will update when the query is changed in the URL', async () => {
const currentQuery = await queryBar.getQueryString();
expect(currentQuery).to.equal('');
const currentUrl = await getUrlFromShare();
const newUrl = currentUrl.replace(`query:''`, `query:'abc12345678910'`);
const newUrl = updateAppStateQueryParam(
await getUrlFromShare(),
(appState: Partial<SharedDashboardState>) => {
return {
query: {
language: 'kuery',
query: 'abc12345678910',
},
};
}
);

// We need to add a timestamp to the URL because URL changes now only work with a hard refresh.
await browser.get(newUrl.toString());
Expand All @@ -153,9 +191,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});

const getUrlFromShare = async () => {
log.debug(`getUrlFromShare`);
await PageObjects.share.clickShareTopNavButton();
const sharedUrl = await PageObjects.share.getSharedUrl();
await PageObjects.share.clickShareTopNavButton();
log.debug(`sharedUrl: ${sharedUrl}`);
return sharedUrl;
};

Expand All @@ -177,11 +217,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {

const changeQuery = async (useHardRefresh: boolean, newQuery: string) => {
await queryBar.clickQuerySubmitButton();
const oldQuery = await queryBar.getQueryString();
const currentUrl = await getUrlFromShare();
const newUrl = currentUrl.replace(`query:'${oldQuery}'`, `query:'${newQuery}'`);
const newUrl = updateAppStateQueryParam(
currentUrl,
(appState: Partial<SharedDashboardState>) => {
return {
query: {
language: 'kuery',
query: newQuery,
},
};
}
);

await browser.get(newUrl.toString(), !useHardRefresh);
await PageObjects.dashboard.waitForRenderComplete();
const queryBarContentsAfterRefresh = await queryBar.getQueryString();
expect(queryBarContentsAfterRefresh).to.equal(newQuery);
};
Expand All @@ -202,9 +252,25 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await dashboardAddPanel.addVisualization(PIE_CHART_VIS_NAME);
const currentUrl = await getUrlFromShare();
const currentPanelDimensions = await PageObjects.dashboard.getPanelDimensions();
const newUrl = currentUrl.replace(
`w:${DEFAULT_PANEL_WIDTH}`,
`w:${DEFAULT_PANEL_WIDTH * 2}`
const newUrl = updateAppStateQueryParam(
currentUrl,
(appState: Partial<SharedDashboardState>) => {
log.debug(JSON.stringify(appState, null, ' '));
return {
panels: (appState.panels ?? []).map((panel) => {
return {
...panel,
gridData: {
...panel.gridData,
w:
panel.gridData.w === DEFAULT_PANEL_WIDTH
? DEFAULT_PANEL_WIDTH * 2
: panel.gridData.w,
},
};
}),
};
}
);
await hardRefresh(newUrl);

Expand All @@ -229,7 +295,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
it('when removing a panel', async function () {
await PageObjects.dashboard.waitForRenderComplete();
const currentUrl = await getUrlFromShare();
const newUrl = currentUrl.replace(/panels:\!\(.*\),query/, 'panels:!(),query');
const newUrl = updateAppStateQueryParam(
currentUrl,
(appState: Partial<SharedDashboardState>) => {
return {
panels: [],
};
}
);
await hardRefresh(newUrl);

await retry.try(async () => {
Expand All @@ -255,7 +328,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
);
await PageObjects.visChart.selectNewLegendColorChoice('#F9D9F9');
const currentUrl = await getUrlFromShare();
const newUrl = currentUrl.replace('F9D9F9', 'FFFFFF');
const newUrl = updateAppStateQueryParam(
currentUrl,
(appState: Partial<SharedDashboardState>) => {
return {
panels: (appState.panels ?? []).map((panel) => {
return {
...panel,
embeddableConfig: {
...(panel.embeddableConfig ?? {}),
vis: {
...((panel.embeddableConfig?.vis as object) ?? {}),
colors: {
...((panel.embeddableConfig?.vis as { colors: object })?.colors ?? {}),
['80000']: 'FFFFFF',
},
},
},
};
}),
};
}
);
await hardRefresh(newUrl);
await PageObjects.header.waitUntilLoadingHasFinished();

Expand All @@ -280,7 +374,25 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {

it('resets a pie slice color to the original when removed', async function () {
const currentUrl = await getUrlFromShare();
const newUrl = currentUrl.replace(`'80000':%23FFFFFF`, '');
const newUrl = updateAppStateQueryParam(
currentUrl,
(appState: Partial<SharedDashboardState>) => {
return {
panels: (appState.panels ?? []).map((panel) => {
return {
...panel,
embeddableConfig: {
...(panel.embeddableConfig ?? {}),
vis: {
...((panel.embeddableConfig?.vis as object) ?? {}),
colors: {},
},
},
};
}),
};
}
);

await hardRefresh(newUrl);
await PageObjects.header.waitUntilLoadingHasFinished();
Expand Down