mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
unskips application leave confirm & application deep links tests (#168741)
fix https://github.com/elastic/kibana/issues/166838 fix https://github.com/elastic/kibana/issues/166893 fix https://github.com/elastic/kibana/issues/75963 I modified the deep links tests because the side nav was overlaying the in-app nav. While, theoretically, the side nav should work for the tests, it tends to be flaky. I added logs for the url so that if these tests do fail, we'll have a bit more data to go on for debugging. These tests pass on local test runs. latest flaky test runs (50): https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3604 - [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: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
60a41ae19b
commit
e811b624ff
7 changed files with 122 additions and 32 deletions
|
@ -411,9 +411,18 @@ export class CommonPageObject extends FtrService {
|
|||
* Clicks cancel button on modal
|
||||
* @param overlayWillStay pass in true if your test will show multiple modals in succession
|
||||
*/
|
||||
async clickCancelOnModal(overlayWillStay = true) {
|
||||
async clickCancelOnModal(overlayWillStay = true, ignorePageLeaveWarning = false) {
|
||||
this.log.debug('Clicking modal cancel');
|
||||
await this.testSubjects.click('confirmModalCancelButton');
|
||||
await this.testSubjects.exists('confirmModalTitleText');
|
||||
|
||||
await this.retry.try(async () => {
|
||||
const warning = await this.testSubjects.exists('confirmModalTitleText');
|
||||
if (warning) {
|
||||
await this.testSubjects.click(
|
||||
ignorePageLeaveWarning ? 'confirmModalConfirmButton' : 'confirmModalCancelButton'
|
||||
);
|
||||
}
|
||||
});
|
||||
if (!overlayWillStay) {
|
||||
await this.ensureModalOverlayHidden();
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ export class AppsMenuService extends FtrService {
|
|||
if (!(await this.testSubjects.exists('collapsibleNav'))) {
|
||||
await this.testSubjects.click('toggleNavButton');
|
||||
}
|
||||
await this.testSubjects.exists('collapsibleNav');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Plugin, CoreSetup } from '@kbn/core/public';
|
||||
import { Plugin, CoreSetup, DEFAULT_APP_CATEGORIES } from '@kbn/core/public';
|
||||
|
||||
export class CoreAppLeavePlugin
|
||||
implements Plugin<CoreAppLeavePluginSetup, CoreAppLeavePluginStart>
|
||||
|
@ -15,6 +15,8 @@ export class CoreAppLeavePlugin
|
|||
core.application.register({
|
||||
id: 'appleave1',
|
||||
title: 'AppLeave 1',
|
||||
appRoute: '/app/appleave1',
|
||||
category: DEFAULT_APP_CATEGORIES.kibana,
|
||||
async mount(params) {
|
||||
const { renderApp } = await import('./application');
|
||||
params.onAppLeave((actions) => actions.confirm('confirm-message', 'confirm-title'));
|
||||
|
@ -24,9 +26,11 @@ export class CoreAppLeavePlugin
|
|||
core.application.register({
|
||||
id: 'appleave2',
|
||||
title: 'AppLeave 2',
|
||||
appRoute: '/app/appleave2',
|
||||
category: DEFAULT_APP_CATEGORIES.kibana,
|
||||
async mount(params) {
|
||||
const { renderApp } = await import('./application');
|
||||
params.onAppLeave((actions) => actions.default());
|
||||
params.onAppLeave((actions) => actions.confirm('confirm-message', 'confirm-title'));
|
||||
return renderApp('AppLeave 2', params);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -50,7 +50,7 @@ const PageA = () => (
|
|||
<EuiPageHeader>
|
||||
<EuiPageHeaderSection>
|
||||
<EuiTitle size="l">
|
||||
<h1>DL Page A</h1>
|
||||
<h1>DL page A</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageHeaderSection>
|
||||
</EuiPageHeader>
|
||||
|
@ -70,7 +70,7 @@ const PageB = () => (
|
|||
<EuiPageHeader>
|
||||
<EuiPageHeaderSection>
|
||||
<EuiTitle size="l">
|
||||
<h1>DL Page B</h1>
|
||||
<h1>DL page B</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageHeaderSection>
|
||||
</EuiPageHeader>
|
||||
|
|
|
@ -29,7 +29,7 @@ export class CorePluginDeepLinksPlugin
|
|||
},
|
||||
{
|
||||
id: 'pageA',
|
||||
title: 'DL Page A',
|
||||
title: 'DL page A',
|
||||
path: '/page-a',
|
||||
navLinkStatus: AppNavLinkStatus.visible,
|
||||
},
|
||||
|
@ -39,7 +39,7 @@ export class CorePluginDeepLinksPlugin
|
|||
deepLinks: [
|
||||
{
|
||||
id: 'pageB',
|
||||
title: 'DL Page B',
|
||||
title: 'DL page B',
|
||||
path: '/page-b',
|
||||
navLinkStatus: AppNavLinkStatus.visible,
|
||||
},
|
||||
|
@ -47,7 +47,7 @@ export class CorePluginDeepLinksPlugin
|
|||
},
|
||||
{
|
||||
id: 'pageC',
|
||||
title: 'DL Page C',
|
||||
title: 'DL page C',
|
||||
path: '/page-c',
|
||||
// navLinkStatus hidden by default
|
||||
},
|
||||
|
|
|
@ -18,6 +18,7 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
const testSubjects = getService('testSubjects');
|
||||
const retry = getService('retry');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const log = getService('log');
|
||||
|
||||
const loadingScreenNotShown = async () =>
|
||||
expect(await testSubjects.exists('kbnLoadingMessage')).to.be(false);
|
||||
|
@ -35,12 +36,20 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
const waitForUrlToBe = (pathname?: string, search?: string) => {
|
||||
const expectedUrl = getKibanaUrl(pathname, search);
|
||||
return retry.waitFor(`Url to be ${expectedUrl}`, async () => {
|
||||
return (await browser.getCurrentUrl()) === expectedUrl;
|
||||
const currentUrl = await browser.getCurrentUrl();
|
||||
log?.debug(`waiting for currentUrl ${currentUrl} to be expectedUrl ${expectedUrl}`);
|
||||
return currentUrl === expectedUrl;
|
||||
});
|
||||
};
|
||||
|
||||
// Failing: See https://github.com/elastic/kibana/issues/166893
|
||||
describe.skip('application deep links navigation', function describeDeepLinksTests() {
|
||||
const navigateToAppLinks = async (subject: string) => {
|
||||
if (!(await testSubjects.exists(subject))) {
|
||||
log.debug(`side nav in app not in DOM`);
|
||||
}
|
||||
await testSubjects.click(subject);
|
||||
};
|
||||
|
||||
describe('application deep links navigation', function describeDeepLinksTests() {
|
||||
before(async () => {
|
||||
await esArchiver.emptyKibanaIndex();
|
||||
await PageObjects.common.navigateToApp('dl');
|
||||
|
@ -51,28 +60,29 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
});
|
||||
|
||||
it('should navigate to page A when navlink is clicked', async () => {
|
||||
await appsMenu.clickLink('DL Page A');
|
||||
await navigateToAppLinks('dlNavPageA');
|
||||
await waitForUrlToBe('/app/dl/page-a');
|
||||
await loadingScreenNotShown();
|
||||
await testSubjects.existOrFail('dlAppPageA');
|
||||
await testSubjects.existOrFail('dlNavPageA');
|
||||
});
|
||||
|
||||
it('should be able to use the back button to navigate back to previous deep link', async () => {
|
||||
await browser.goBack();
|
||||
await waitForUrlToBe('/app/dl/home');
|
||||
await loadingScreenNotShown();
|
||||
await testSubjects.existOrFail('dlAppHome');
|
||||
await testSubjects.existOrFail('dlNavHome');
|
||||
});
|
||||
|
||||
it('should navigate to nested page B when navlink is clicked', async () => {
|
||||
await appsMenu.clickLink('DL Page B');
|
||||
await navigateToAppLinks('dlNavDeepPageB');
|
||||
await waitForUrlToBe('/app/dl/page-b');
|
||||
await loadingScreenNotShown();
|
||||
await testSubjects.existOrFail('dlAppPageB');
|
||||
await testSubjects.existOrFail('dlNavDeepPageB');
|
||||
});
|
||||
|
||||
it('should navigate to Home when navlink is clicked inside the defined category group', async () => {
|
||||
await appsMenu.clickLink('DL Home', { category: 'securitySolution' });
|
||||
await navigateToAppLinks('dlAppHome');
|
||||
await waitForUrlToBe('/app/dl/home');
|
||||
await loadingScreenNotShown();
|
||||
await testSubjects.existOrFail('dlAppHome');
|
||||
|
@ -82,14 +92,14 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
await testSubjects.click('dlNavDeepPageB');
|
||||
await waitForUrlToBe('/app/dl/page-b');
|
||||
await loadingScreenNotShown();
|
||||
await testSubjects.existOrFail('dlAppPageB');
|
||||
await testSubjects.existOrFail('dlNavDeepPageB');
|
||||
});
|
||||
|
||||
it('should navigate to nested page A using navigateToApp deepLinkId', async () => {
|
||||
await testSubjects.click('dlNavDeepPageAById');
|
||||
await waitForUrlToBe('/app/dl/page-a');
|
||||
await loadingScreenNotShown();
|
||||
await testSubjects.existOrFail('dlAppPageA');
|
||||
await testSubjects.existOrFail('dlNavPageA');
|
||||
});
|
||||
|
||||
it('should not display hidden deep links', async () => {
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import url from 'url';
|
||||
import expect from '@kbn/expect';
|
||||
import url from 'url';
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
|
||||
const getKibanaUrl = (pathname?: string, search?: string) =>
|
||||
|
@ -20,30 +20,96 @@ const getKibanaUrl = (pathname?: string, search?: string) =>
|
|||
});
|
||||
|
||||
export default function ({ getService, getPageObjects }: PluginFunctionalProviderContext) {
|
||||
const PageObjects = getPageObjects(['common']);
|
||||
const PageObjects = getPageObjects(['common', 'header']);
|
||||
const browser = getService('browser');
|
||||
const appsMenu = getService('appsMenu');
|
||||
const log = getService('log');
|
||||
const retry = getService('retry');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const config = getService('config');
|
||||
|
||||
// Failing: See https://github.com/elastic/kibana/issues/75963
|
||||
// Failing: See https://github.com/elastic/kibana/issues/166838
|
||||
describe.skip('application using leave confirmation', () => {
|
||||
const waitForUrlToBe = async (pathname?: string, search?: string) => {
|
||||
const expectedUrl = getKibanaUrl(pathname, search);
|
||||
return await retry.waitFor(`Url to be ${expectedUrl}`, async () => {
|
||||
const currentUrl = await browser.getCurrentUrl();
|
||||
log.debug(`waiting for currentUrl ${currentUrl} to be expectedUrl ${expectedUrl}`);
|
||||
return currentUrl === expectedUrl;
|
||||
});
|
||||
};
|
||||
|
||||
const ensureModalOpen = async (
|
||||
defaultTryTimeout: number,
|
||||
attempts: number,
|
||||
timeMultiplier: number,
|
||||
action: 'cancel' | 'confirm',
|
||||
linkText: string = 'home'
|
||||
): Promise<void> => {
|
||||
let isConfirmCancelModalOpenState = false;
|
||||
|
||||
await retry.tryForTime(defaultTryTimeout * timeMultiplier, async () => {
|
||||
await appsMenu.clickLink(linkText);
|
||||
isConfirmCancelModalOpenState = await testSubjects.exists('confirmModalTitleText', {
|
||||
allowHidden: true,
|
||||
timeout: defaultTryTimeout * timeMultiplier,
|
||||
});
|
||||
});
|
||||
if (isConfirmCancelModalOpenState) {
|
||||
log.debug(`defaultTryTimeout * ${timeMultiplier} is long enough`);
|
||||
return action === 'cancel'
|
||||
? await PageObjects.common.clickCancelOnModal(true, false)
|
||||
: await PageObjects.common.clickConfirmOnModal();
|
||||
} else {
|
||||
log.debug(`defaultTryTimeout * ${timeMultiplier} is not long enough`);
|
||||
return await ensureModalOpen(
|
||||
defaultTryTimeout,
|
||||
(attempts = attempts > 0 ? attempts - 1 : 0),
|
||||
(timeMultiplier = timeMultiplier < 10 ? timeMultiplier + 1 : 10),
|
||||
action,
|
||||
linkText
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
describe('application using leave confirmation', () => {
|
||||
const defaultTryTimeout = config.get('timeouts.try');
|
||||
const attempts = 5;
|
||||
describe('when navigating to another app', () => {
|
||||
const timeMultiplier = 10;
|
||||
beforeEach(async () => {
|
||||
await PageObjects.common.navigateToApp('home');
|
||||
});
|
||||
it('prevents navigation if user click cancel on the confirmation dialog', async () => {
|
||||
await PageObjects.common.navigateToApp('appleave1');
|
||||
await appsMenu.clickLink('AppLeave 2');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await waitForUrlToBe('/app/appleave1');
|
||||
|
||||
await testSubjects.existOrFail('appLeaveConfirmModal');
|
||||
await PageObjects.common.clickCancelOnModal(false);
|
||||
expect(await browser.getCurrentUrl()).to.eql(getKibanaUrl('/app/appleave1'));
|
||||
await ensureModalOpen(defaultTryTimeout, attempts, timeMultiplier, 'cancel', 'AppLeave 2');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await retry.waitFor('navigate to appleave1', async () => {
|
||||
const currentUrl = await browser.getCurrentUrl();
|
||||
log.debug(`currentUrl ${currentUrl}`);
|
||||
return currentUrl.includes('appleave1');
|
||||
});
|
||||
const currentUrl = await browser.getCurrentUrl();
|
||||
expect(currentUrl).to.contain('appleave1');
|
||||
await PageObjects.common.navigateToApp('home');
|
||||
});
|
||||
|
||||
it('allows navigation if user click confirm on the confirmation dialog', async () => {
|
||||
await PageObjects.common.navigateToApp('appleave1');
|
||||
await appsMenu.clickLink('AppLeave 2');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await waitForUrlToBe('/app/appleave1');
|
||||
|
||||
await testSubjects.existOrFail('appLeaveConfirmModal');
|
||||
await PageObjects.common.clickConfirmOnModal();
|
||||
expect(await browser.getCurrentUrl()).to.eql(getKibanaUrl('/app/appleave2'));
|
||||
await ensureModalOpen(defaultTryTimeout, attempts, timeMultiplier, 'confirm', 'AppLeave 2');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await retry.waitFor('navigate to appleave1', async () => {
|
||||
const currentUrl = await browser.getCurrentUrl();
|
||||
log.debug(`currentUrl ${currentUrl}`);
|
||||
return currentUrl.includes('appleave2');
|
||||
});
|
||||
const currentUrl = await browser.getCurrentUrl();
|
||||
expect(currentUrl).to.contain('appleave2');
|
||||
await PageObjects.common.navigateToApp('home');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue