diff --git a/CHANGELOG.md b/CHANGELOG.md index 020ce3583eba..56ca0743f81f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Data Explorer][Discover] Allow data grid to auto adjust size based on fetched data count ([#5191](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5191)) - [BUG] Fix wrong test due to time conversion ([#5174](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5174)) - [BUG][Data Explorer][Discover] Allow filter and query persist when refresh page or paste url to a new tab ([#5206](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5206)) +- [BUG][Fuctional Test] Make setDefaultAbsoluteRange more robust and update doc views tests ([#5242](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5242)) ### 🚞 Infrastructure diff --git a/test/functional/page_objects/time_picker.ts b/test/functional/page_objects/time_picker.ts index 05108f787b2c..0c48f69c65a3 100644 --- a/test/functional/page_objects/time_picker.ts +++ b/test/functional/page_objects/time_picker.ts @@ -52,6 +52,7 @@ export function TimePickerProvider({ getService, getPageObjects }: FtrProviderCo const { header } = getPageObjects(['header']); const opensearchDashboardsServer = getService('opensearchDashboardsServer'); const MenuToggle = getService('MenuToggle'); + const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const quickSelectTimeMenuToggle = new MenuToggle({ name: 'QuickSelectTime Menu', @@ -130,6 +131,32 @@ export function TimePickerProvider({ getService, getPageObjects }: FtrProviderCo await testSubjects.exists('superDatePickerstartDatePopoverButton'); } + // Helper function to set input value and verify + private async setInputValueWithRetry(testSubjectId: string, value: string) { + const MAX_ATTEMPTS = 3; + + for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) { + // try to set the value + await this.inputValue(testSubjectId, value); + await sleep(500); + + // verify if the value was correctly set + const actualValue = await (await testSubjects.find(testSubjectId)).getAttribute('value'); + if (actualValue === value) { + return; + } + + // if it's the last attempt and value wasn't set correctly, throw an error + if (attempt === MAX_ATTEMPTS - 1) { + throw new Error( + `Failed to set ${testSubjectId} to ${value} after ${MAX_ATTEMPTS} attempts.` + ); + } + + await sleep(500); // wait before retrying + } + } + /** * @param {String} fromTime MMM D, YYYY @ HH:mm:ss.SSS * @param {String} toTime MMM D, YYYY @ HH:mm:ss.SSS @@ -137,13 +164,16 @@ export function TimePickerProvider({ getService, getPageObjects }: FtrProviderCo public async setAbsoluteRange(fromTime: string, toTime: string) { log.debug(`Setting absolute range to ${fromTime} to ${toTime}`); await this.showStartEndTimes(); + // make sure to close this verify panel + await browser.pressKeys(browser.keys.ESCAPE); + await sleep(500); // set to time await testSubjects.click('superDatePickerendDatePopoverButton'); let panel = await this.getTimePickerPanel(); await testSubjects.click('superDatePickerAbsoluteTab'); await testSubjects.click('superDatePickerAbsoluteDateInput'); - await this.inputValue('superDatePickerAbsoluteDateInput', toTime); + await this.setInputValueWithRetry('superDatePickerAbsoluteDateInput', toTime); await browser.pressKeys(browser.keys.ESCAPE); // close popover because sometimes browser can't find start input // set from time @@ -152,7 +182,8 @@ export function TimePickerProvider({ getService, getPageObjects }: FtrProviderCo panel = await this.getTimePickerPanel(); await testSubjects.click('superDatePickerAbsoluteTab'); await testSubjects.click('superDatePickerAbsoluteDateInput'); - await this.inputValue('superDatePickerAbsoluteDateInput', fromTime); + await this.setInputValueWithRetry('superDatePickerAbsoluteDateInput', fromTime); + await browser.pressKeys(browser.keys.ESCAPE); const superDatePickerApplyButtonExists = await testSubjects.exists( 'superDatePickerApplyTimeButton' diff --git a/test/plugin_functional/test_suites/doc_views/doc_views.ts b/test/plugin_functional/test_suites/doc_views/doc_views.ts index 4a25bed25256..2cecbc0f01ef 100644 --- a/test/plugin_functional/test_suites/doc_views/doc_views.ts +++ b/test/plugin_functional/test_suites/doc_views/doc_views.ts @@ -43,7 +43,7 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide }); it('should show custom doc views', async () => { - await testSubjects.click('docTableExpandToggleColumn'); + await testSubjects.click('docTableExpandToggleColumn-0'); const reactTab = await find.byButtonText('React doc view'); expect(await reactTab.isDisplayed()).to.be(true); }); diff --git a/test/plugin_functional/test_suites/doc_views_links/doc_views_links.ts b/test/plugin_functional/test_suites/doc_views_links/doc_views_links.ts index 2933e0add118..751083d3cda5 100644 --- a/test/plugin_functional/test_suites/doc_views_links/doc_views_links.ts +++ b/test/plugin_functional/test_suites/doc_views_links/doc_views_links.ts @@ -11,36 +11,81 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide const find = getService('find'); const browser = getService('browser'); const PageObjects = getPageObjects(['common', 'discover', 'timePicker']); + const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + const waitFor = async (conditionFunction, timeoutMs = 10000, intervalMs = 100) => { + const start = Date.now(); + + let lastError; + while (Date.now() - start < timeoutMs) { + try { + if (await conditionFunction()) { + return; + } + } catch (error) { + lastError = error; + } + + await sleep(intervalMs); + } + + throw new Error( + `waitFor condition did not become true within ${timeoutMs}ms. Last error: ${ + lastError && lastError.message + }` + ); + }; describe('custom doc views links', function () { beforeEach(async () => { await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setDefaultAbsoluteRange(); - await testSubjects.click('docTableExpandToggleColumn'); + await testSubjects.click('docTableExpandToggleColumn-0'); }); - it('should show href and generateCb doc views link', async () => { + it('should show href and generateCb doc views link and not show generateCbHidden doc views link', async () => { const hrefLink = await find.byLinkText('href doc view link'); const generateCbLink = await find.byLinkText('generateCb doc view link'); - expect(await hrefLink.isDisplayed()).to.be(true); expect(await generateCbLink.isDisplayed()).to.be(true); - }); - - it('should not render generateCbHidden doc views link', async () => { expect(await find.existsByLinkText('generateCbHidden doc view link')).to.eql(false); }); it('should render href doc view link', async () => { const hrefLink = await find.byLinkText('href doc view link'); + const originalTabCount = (await browser.getAllWindowHandles()).length; await hrefLink.click(); - expect(await browser.getCurrentUrl()).to.eql('http://some-url/'); + + // wait until a new tab is opened + await waitFor(async () => (await browser.getAllWindowHandles()).length > originalTabCount); + + // switch to the originalTabCount in case previous tab is not closed in time + await browser.switchTab(originalTabCount); + + const currentUrl = await browser.getCurrentUrl(); + expect(currentUrl).to.eql('http://some-url/'); + + // close new tab and switch back to original tab + await browser.closeCurrentWindow(); + await browser.switchTab(0); }); it('should render generateCb doc view link', async () => { const generateCbLink = await find.byLinkText('generateCb doc view link'); + const originalTabCount = (await browser.getAllWindowHandles()).length; await generateCbLink.click(); - expect(await browser.getCurrentUrl()).to.eql('http://some-url/'); + + // wait until a new tab is opened + await waitFor(async () => (await browser.getAllWindowHandles()).length > originalTabCount); + + // switch to the originalTabCount in case previous tab is not closed in time + await browser.switchTab(originalTabCount); + + const currentUrl = await browser.getCurrentUrl(); + expect(currentUrl).to.eql('http://some-url/'); + + // close new tab and switch back to original tab + await browser.closeCurrentWindow(); + await browser.switchTab(0); }); }); }