+
{table}
diff --git a/src/plugins/discover/public/application/view_components/canvas/discover_table.tsx b/src/plugins/discover/public/application/view_components/canvas/discover_table.tsx
index e292303d9f8d..3cdf48a30dfc 100644
--- a/src/plugins/discover/public/application/view_components/canvas/discover_table.tsx
+++ b/src/plugins/discover/public/application/view_components/canvas/discover_table.tsx
@@ -17,7 +17,7 @@ import {
useDispatch,
useSelector,
} from '../../utils/state_management';
-import { ResultStatus, SearchData } from '../utils/use_search';
+import { ResultStatus, SearchData, useSearch } from '../utils/use_search';
import { IndexPatternField, opensearchFilters } from '../../../../../data/public';
import { DocViewFilterFn } from '../../doc_views/doc_views_types';
import { SortOrder } from '../../../saved_searches/types';
@@ -71,6 +71,7 @@ export const DiscoverTable = ({ history }: Props) => {
);
const { rows } = fetchState || {};
+ const { savedSearch } = useSearch(services);
useEffect(() => {
const subscription = data$.subscribe((next) => {
@@ -107,6 +108,8 @@ export const DiscoverTable = ({ history }: Props) => {
rows={rows}
displayTimeColumn={displayTimeColumn}
services={services}
+ title={savedSearch?.id ? savedSearch.title : ''}
+ description={savedSearch?.id ? savedSearch.description : ''}
/>
);
};
diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts
index 2560fc6d3567..aa14f6e69dd8 100644
--- a/src/plugins/discover/public/application/view_components/utils/use_search.ts
+++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts
@@ -67,6 +67,7 @@ export type RefetchSubject = Subject;
* }, [data$]);
*/
export const useSearch = (services: DiscoverServices) => {
+ const initalSearchComplete = useRef(false);
const [savedSearch, setSavedSearch] = useState(undefined);
const { savedSearch: savedSearchId, sort, interval } = useSelector((state) => state.discover);
const indexPattern = useIndexPattern(services);
@@ -205,6 +206,8 @@ export const useSearch = (services: DiscoverServices) => {
});
data.search.showError(error as Error);
+ } finally {
+ initalSearchComplete.current = true;
}
}, [
indexPattern,
@@ -240,18 +243,29 @@ export const useSearch = (services: DiscoverServices) => {
})();
});
- // kick off initial fetch
- refetch$.next();
+ // kick off initial refetch on page load
+ if (shouldSearchOnPageLoad() || initalSearchComplete.current === true) {
+ refetch$.next();
+ }
return () => {
subscription.unsubscribe();
};
- }, [data$, data.query.queryString, filterManager, refetch$, timefilter, fetch, core.fatalErrors]);
+ }, [
+ data$,
+ data.query.queryString,
+ filterManager,
+ refetch$,
+ timefilter,
+ fetch,
+ core.fatalErrors,
+ shouldSearchOnPageLoad,
+ ]);
// Get savedSearch if it exists
useEffect(() => {
(async () => {
- const savedSearchInstance = await getSavedSearchById(savedSearchId || '');
+ const savedSearchInstance = await getSavedSearchById(savedSearchId);
setSavedSearch(savedSearchInstance);
// sync initial app filters from savedObject to filterManager
diff --git a/src/plugins/discover/public/build_services.ts b/src/plugins/discover/public/build_services.ts
index ebe4e80a70c5..785e72536417 100644
--- a/src/plugins/discover/public/build_services.ts
+++ b/src/plugins/discover/public/build_services.ts
@@ -78,7 +78,7 @@ export interface DiscoverServices {
urlForwarding: UrlForwardingStart;
timefilter: TimefilterContract;
toastNotifications: ToastsStart;
- getSavedSearchById: (id: string) => Promise;
+ getSavedSearchById: (id?: string) => Promise;
getSavedSearchUrlById: (id: string) => Promise;
uiSettings: IUiSettingsClient;
visualizations: VisualizationsStart;
@@ -107,7 +107,7 @@ export function buildServices(
docLinks: core.docLinks,
theme: plugins.charts.theme,
filterManager: plugins.data.query.filterManager,
- getSavedSearchById: async (id: string) => savedObjectService.get(id),
+ getSavedSearchById: async (id?: string) => savedObjectService.get(id),
getSavedSearchUrlById: async (id: string) => savedObjectService.urlFor(id),
history: getHistory,
indexPatterns: plugins.data.indexPatterns,
diff --git a/src/plugins/discover/public/embeddable/search_embeddable.tsx b/src/plugins/discover/public/embeddable/search_embeddable.tsx
index 76b6b9f449c4..6a0fd097aeef 100644
--- a/src/plugins/discover/public/embeddable/search_embeddable.tsx
+++ b/src/plugins/discover/public/embeddable/search_embeddable.tsx
@@ -87,6 +87,7 @@ export interface SearchProps {
isLoading?: boolean;
displayTimeColumn?: boolean;
services: DiscoverServices;
+ title?: string;
}
interface SearchEmbeddableConfig {
@@ -226,6 +227,7 @@ export class SearchEmbeddable
inspectorAdapters: this.inspectorAdaptors,
rows: [],
description: this.savedSearch.description,
+ title: this.savedSearch.title,
services: this.services,
indexPattern,
isLoading: false,
diff --git a/src/plugins/discover/public/embeddable/search_embeddable_component.tsx b/src/plugins/discover/public/embeddable/search_embeddable_component.tsx
index f019d75db116..c8ae54a16429 100644
--- a/src/plugins/discover/public/embeddable/search_embeddable_component.tsx
+++ b/src/plugins/discover/public/embeddable/search_embeddable_component.tsx
@@ -38,6 +38,8 @@ export function SearchEmbeddableComponent({ searchProps }: SearchEmbeddableProps
displayTimeColumn: searchProps.displayTimeColumn,
services: searchProps.services,
totalHitCount: searchProps.totalHitCount,
+ title: searchProps.title,
+ description: searchProps.description,
} as DiscoverEmbeddableProps;
return (
diff --git a/test/functional/apps/dashboard/dashboard_filter_bar.js b/test/functional/apps/dashboard/dashboard_filter_bar.js
index 0d19c84a5089..9a0ce6a9042a 100644
--- a/test/functional/apps/dashboard/dashboard_filter_bar.js
+++ b/test/functional/apps/dashboard/dashboard_filter_bar.js
@@ -193,7 +193,12 @@ export default function ({ getService, getPageObjects }) {
it('are added when a cell magnifying glass is clicked', async function () {
await dashboardAddPanel.addSavedSearch('Rendering-Test:-saved-search');
await PageObjects.dashboard.waitForRenderComplete();
- await testSubjects.click('docTableCellFilter');
+
+ // Expand a doc row
+ await testSubjects.click('docTableExpandToggleColumn-0');
+
+ // Add a field filter
+ await testSubjects.click('tableDocViewRow-@message > addInclusiveFilterButton');
const filterCount = await filterBar.getFilterCount();
expect(filterCount).to.equal(1);
diff --git a/test/functional/apps/dashboard/dashboard_filtering.js b/test/functional/apps/dashboard/dashboard_filtering.js
index b3ff62c8b9da..e934169513f6 100644
--- a/test/functional/apps/dashboard/dashboard_filtering.js
+++ b/test/functional/apps/dashboard/dashboard_filtering.js
@@ -123,7 +123,7 @@ export default function ({ getService, getPageObjects }) {
});
it('saved search is filtered', async () => {
- await dashboardExpect.savedSearchRowCount(0);
+ await testSubjects.missingOrFail('euiDataGrid');
});
it('vega is filtered', async () => {
@@ -171,7 +171,7 @@ export default function ({ getService, getPageObjects }) {
});
it('saved search is filtered', async () => {
- await dashboardExpect.savedSearchRowCount(0);
+ await testSubjects.missingOrFail('euiDataGrid');
});
it('vega is filtered', async () => {
diff --git a/test/functional/apps/dashboard/dashboard_query_bar.js b/test/functional/apps/dashboard/dashboard_query_bar.js
index f1c2893268a9..91885a282b15 100644
--- a/test/functional/apps/dashboard/dashboard_query_bar.js
+++ b/test/functional/apps/dashboard/dashboard_query_bar.js
@@ -49,7 +49,8 @@ export default function ({ getService, getPageObjects }) {
await PageObjects.dashboard.loadSavedDashboard('dashboard with filter');
});
- it('causes panels to reload when refresh is clicked', async () => {
+ // https://github.com/opensearch-project/OpenSearch-Dashboards/issues/5116
+ it.skip('causes panels to reload when refresh is clicked', async () => {
await opensearchArchiver.unload('dashboard/current/data');
await queryBar.clickQuerySubmitButton();
diff --git a/test/functional/apps/home/_navigation.ts b/test/functional/apps/home/_navigation.ts
index 03230f1270ed..733888f59711 100644
--- a/test/functional/apps/home/_navigation.ts
+++ b/test/functional/apps/home/_navigation.ts
@@ -33,14 +33,18 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const browser = getService('browser');
- const PageObjects = getPageObjects(['common', 'header', 'home', 'timePicker']);
+ const PageObjects = getPageObjects(['common', 'header', 'home', 'timePicker', 'discover']);
const appsMenu = getService('appsMenu');
const opensearchArchiver = getService('opensearchArchiver');
+ const opensearchDashboardsServer = getService('opensearchDashboardsServer');
describe('OpenSearch Dashboards browser back navigation should work', function describeIndexTests() {
before(async () => {
await opensearchArchiver.loadIfNeeded('discover');
await opensearchArchiver.loadIfNeeded('logstash_functional');
+ await opensearchDashboardsServer.uiSettings.replace({
+ defaultIndex: 'logstash-*',
+ });
});
it('detect navigate back issues', async () => {
@@ -51,8 +55,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const homeUrl = await browser.getCurrentUrl();
// Navigate to discover app
- await appsMenu.clickLink('Discover');
+ await PageObjects.common.navigateToApp('discover');
const discoverUrl = await browser.getCurrentUrl();
+
await PageObjects.timePicker.setDefaultAbsoluteRange();
const modifiedTimeDiscoverUrl = await browser.getCurrentUrl();
diff --git a/test/functional/apps/home/_sample_data.ts b/test/functional/apps/home/_sample_data.ts
index 9f78c5eec4e6..4c1cf4f69ce1 100644
--- a/test/functional/apps/home/_sample_data.ts
+++ b/test/functional/apps/home/_sample_data.ts
@@ -125,8 +125,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await pieChart.expectPieSliceCount(4);
log.debug('Checking area, bar and heatmap charts rendered');
await dashboardExpect.seriesElementCount(15);
+ // The saved search of data explorer now renders 100 lines max
log.debug('Checking saved searches rendered');
- await dashboardExpect.savedSearchRowCount(50);
+ await dashboardExpect.savedSearchRowCount(100);
log.debug('Checking input controls rendered');
await dashboardExpect.inputControlItemCount(3);
log.debug('Checking tag cloud rendered');
diff --git a/test/functional/apps/management/_index_pattern_results_sort.js b/test/functional/apps/management/_index_pattern_results_sort.js
index 1823c678b2bb..f5c1b7114d9c 100644
--- a/test/functional/apps/management/_index_pattern_results_sort.js
+++ b/test/functional/apps/management/_index_pattern_results_sort.js
@@ -39,6 +39,12 @@ export default function ({ getService, getPageObjects }) {
before(async function () {
// delete .kibana index and then wait for OpenSearch Dashboards to re-create it
await opensearchDashboardsServer.uiSettings.replace({});
+ await PageObjects.settings.navigateTo();
+ await PageObjects.settings.createIndexPattern();
+ });
+
+ after(async function () {
+ return await PageObjects.settings.removeIndexPattern();
});
const columns = [
@@ -64,14 +70,6 @@ export default function ({ getService, getPageObjects }) {
columns.forEach(function (col) {
describe('sort by heading - ' + col.heading, function indexPatternCreation() {
- before(async function () {
- await PageObjects.settings.createIndexPattern();
- });
-
- after(async function () {
- return await PageObjects.settings.removeIndexPattern();
- });
-
it('should sort ascending', async function () {
await PageObjects.settings.sortBy(col.heading);
const rowText = await col.selector();
@@ -85,17 +83,9 @@ export default function ({ getService, getPageObjects }) {
});
});
});
+
describe('field list pagination', function () {
const EXPECTED_FIELD_COUNT = 86;
-
- before(async function () {
- await PageObjects.settings.createIndexPattern();
- });
-
- after(async function () {
- return await PageObjects.settings.removeIndexPattern();
- });
-
it('makelogs data should have expected number of fields', async function () {
await retry.try(async function () {
const TabCount = await PageObjects.settings.getFieldsTabCount();
diff --git a/test/functional/apps/management/_opensearch_dashboards_settings.js b/test/functional/apps/management/_opensearch_dashboards_settings.js
index 98cda687e23b..0e310953e8a2 100644
--- a/test/functional/apps/management/_opensearch_dashboards_settings.js
+++ b/test/functional/apps/management/_opensearch_dashboards_settings.js
@@ -39,8 +39,8 @@ export default function ({ getService, getPageObjects }) {
before(async function () {
// delete .kibana index and then wait for OpenSearch Dashboards to re-create it
await opensearchDashboardsServer.uiSettings.replace({});
- await PageObjects.settings.createIndexPattern('logstash-*');
await PageObjects.settings.navigateTo();
+ await PageObjects.settings.createIndexPattern('logstash-*');
});
after(async function afterAll() {
diff --git a/test/functional/apps/management/_scripted_fields.js b/test/functional/apps/management/_scripted_fields.js
index 7d9ae2be1166..7acceff07fce 100644
--- a/test/functional/apps/management/_scripted_fields.js
+++ b/test/functional/apps/management/_scripted_fields.js
@@ -161,6 +161,7 @@ export default function ({ getService, getPageObjects }) {
const fromTime = 'Sep 17, 2015 @ 06:31:44.000';
const toTime = 'Sep 18, 2015 @ 18:31:44.000';
await PageObjects.common.navigateToApp('discover');
+ await PageObjects.discover.selectIndexPattern('logstash-*');
await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime);
await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName);
@@ -169,31 +170,31 @@ export default function ({ getService, getPageObjects }) {
});
await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\n18');
- });
+ const rowData = await PageObjects.discover.getDataGridTableValues();
+ expect(rowData[0][0]).to.be('Sep 18, 2015 @ 18:20:57.916');
+ expect(rowData[0][1]).to.be('18');
});
//add a test to sort numeric scripted field
it('should sort scripted field value in Discover', async function () {
- await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName}`);
- // after the first click on the scripted field, it becomes secondary sort after time.
- // click on the timestamp twice to make it be the secondary sort key.
- await testSubjects.click('docTableHeaderFieldSort_@timestamp');
- await testSubjects.click('docTableHeaderFieldSort_@timestamp');
+ await testSubjects.click(`dataGridHeaderCell-${scriptedPainlessFieldName}`);
+ await PageObjects.discover.clickTableHeaderListItem(scriptedPainlessFieldName, 'Sort A-Z');
await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('Sep 17, 2015 @ 10:53:14.181\n-1');
- });
-
- await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName}`);
+ await testSubjects.click('dataGridHeaderCell-@timestamp');
+ await PageObjects.discover.clickTableHeaderListItem('@timestamp', 'Sort A-Z');
await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479\n20');
- });
+ const sortedDataByTimeField = await PageObjects.discover.getDataGridTableValues();
+ expect(sortedDataByTimeField[0][0]).contain('Sep 17, 2015 @ 10:53:14.181');
+ expect(sortedDataByTimeField[0][1]).contain('-1');
+
+ // click the column sorting button to remove painless field sort
+ // should sort only by time field
+ await testSubjects.click('dataGridColumnSortingButton');
+ await PageObjects.discover.removeSort(`${scriptedPainlessFieldName}`);
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ const sortedDataByPainlessField = await PageObjects.discover.getDataGridTableValues();
+ expect(sortedDataByPainlessField[0][0]).contain('Sep 17, 2015 @ 06:32:29.479');
+ expect(sortedDataByPainlessField[0][1]).contain('20');
});
it('should filter by scripted field value in Discover', async function () {
@@ -278,6 +279,7 @@ export default function ({ getService, getPageObjects }) {
const fromTime = 'Sep 17, 2015 @ 06:31:44.000';
const toTime = 'Sep 18, 2015 @ 18:31:44.000';
await PageObjects.common.navigateToApp('discover');
+ await PageObjects.discover.selectIndexPattern('logstash-*');
await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime);
await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2);
@@ -286,31 +288,31 @@ export default function ({ getService, getPageObjects }) {
});
await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ngood');
- });
+ const rowData = await PageObjects.discover.getDataGridTableValues();
+ expect(rowData[0][0]).to.be('Sep 18, 2015 @ 18:20:57.916');
+ expect(rowData[0][1]).to.be('good');
});
//add a test to sort string scripted field
it('should sort scripted field value in Discover', async function () {
- await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`);
- // after the first click on the scripted field, it becomes secondary sort after time.
- // click on the timestamp twice to make it be the secondary sort key.
- await testSubjects.click('docTableHeaderFieldSort_@timestamp');
- await testSubjects.click('docTableHeaderFieldSort_@timestamp');
+ await testSubjects.click(`dataGridHeaderCell-${scriptedPainlessFieldName2}`);
+ await PageObjects.discover.clickTableHeaderListItem(scriptedPainlessFieldName2, 'Sort A-Z');
await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('Sep 17, 2015 @ 09:48:40.594\nbad');
- });
-
- await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`);
+ await testSubjects.click('dataGridHeaderCell-@timestamp');
+ await PageObjects.discover.clickTableHeaderListItem('@timestamp', 'Sort A-Z');
await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479\ngood');
- });
+ const sortedDataByTimeField = await PageObjects.discover.getDataGridTableValues();
+ expect(sortedDataByTimeField[0][0]).contain('Sep 17, 2015 @ 09:48:40.594');
+ expect(sortedDataByTimeField[0][1]).contain('bad');
+
+ // click the column sorting button to remove painless field sort
+ // should sort only by time field
+ await testSubjects.click('dataGridColumnSortingButton');
+ await PageObjects.discover.removeSort(`${scriptedPainlessFieldName2}`);
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ const sortedDataByPainlessField = await PageObjects.discover.getDataGridTableValues();
+ expect(sortedDataByPainlessField[0][0]).contain('Sep 17, 2015 @ 06:32:29.479');
+ expect(sortedDataByPainlessField[0][1]).contain('good');
});
it('should filter by scripted field value in Discover', async function () {
@@ -373,6 +375,7 @@ export default function ({ getService, getPageObjects }) {
const fromTime = 'Sep 17, 2015 @ 06:31:44.000';
const toTime = 'Sep 18, 2015 @ 18:31:44.000';
await PageObjects.common.navigateToApp('discover');
+ await PageObjects.discover.selectIndexPattern('logstash-*');
await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime);
await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2);
@@ -381,10 +384,33 @@ export default function ({ getService, getPageObjects }) {
});
await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ntrue');
- });
+ const rowData = await PageObjects.discover.getDataGridTableValues();
+ expect(rowData[0][0]).to.be('Sep 18, 2015 @ 18:20:57.916');
+ expect(rowData[0][1]).to.be('true');
+ });
+
+ // existing bug: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/5126 hence the issue is skipped
+ // TODO: replace updateExpectedResultHere with actual data value once bug is fixed
+ it.skip('should sort scripted field value in Discover', async function () {
+ await testSubjects.click(`dataGridHeaderCell-${scriptedPainlessFieldName2}`);
+ await PageObjects.discover.clickTableHeaderListItem(
+ scriptedPainlessFieldName2,
+ 'Sort True-False'
+ );
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ await testSubjects.click('dataGridHeaderCell-@timestamp');
+ await PageObjects.discover.clickTableHeaderListItem('@timestamp', 'Sort A-Z');
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ const sortedDataByTimeField = await PageObjects.discover.getDataGridTableValues();
+ expect(sortedDataByTimeField[0][0]).contain('updateExpectedResultHere');
+ expect(sortedDataByTimeField[0][1]).contain('true');
+
+ await testSubjects.click('dataGridColumnSortingButton');
+ await PageObjects.discover.removeSort(`${scriptedPainlessFieldName2}`);
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ const sortedDataByPainlessField = await PageObjects.discover.getDataGridTableValues();
+ expect(sortedDataByPainlessField[0][0]).contain('updateExpectedResultHere');
+ expect(sortedDataByPainlessField[0][1]).contain('false');
});
it('should filter by scripted field value in Discover', async function () {
@@ -399,28 +425,6 @@ export default function ({ getService, getPageObjects }) {
await filterBar.removeAllFilters();
});
- //add a test to sort boolean
- //existing bug: https://github.com/elastic/kibana/issues/75519 hence the issue is skipped.
- it.skip('should sort scripted field value in Discover', async function () {
- await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`);
- // after the first click on the scripted field, it becomes secondary sort after time.
- // click on the timestamp twice to make it be the secondary sort key.
- await testSubjects.click('docTableHeaderFieldSort_@timestamp');
- await testSubjects.click('docTableHeaderFieldSort_@timestamp');
- await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('updateExpectedResultHere\ntrue');
- });
-
- await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`);
- await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('updateExpectedResultHere\nfalse');
- });
- });
-
it('should visualize scripted field in vertical bar chart', async function () {
await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2);
await PageObjects.header.waitUntilLoadingHasFinished();
@@ -469,6 +473,7 @@ export default function ({ getService, getPageObjects }) {
const fromTime = 'Sep 17, 2015 @ 19:22:00.000';
const toTime = 'Sep 18, 2015 @ 07:00:00.000';
await PageObjects.common.navigateToApp('discover');
+ await PageObjects.discover.selectIndexPattern('logstash-*');
await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime);
await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2);
@@ -477,32 +482,30 @@ export default function ({ getService, getPageObjects }) {
});
await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('Sep 18, 2015 @ 06:52:55.953\n2015-09-18 07:00');
- });
+ const rowData = await PageObjects.discover.getDataGridTableValues();
+ expect(rowData[0][0]).to.be('Sep 18, 2015 @ 06:52:55.953');
+ expect(rowData[0][1]).to.be('2015-09-18 07:00');
});
- //add a test to sort date scripted field
- //https://github.com/elastic/kibana/issues/75711
+ // existing bug: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/5127 hence the issue is skipped
+ // TODO: replace updateExpectedResultHere with actual data value once bug is fixed
it.skip('should sort scripted field value in Discover', async function () {
- await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`);
- // after the first click on the scripted field, it becomes secondary sort after time.
- // click on the timestamp twice to make it be the secondary sort key.
- await testSubjects.click('docTableHeaderFieldSort_@timestamp');
- await testSubjects.click('docTableHeaderFieldSort_@timestamp');
+ await testSubjects.click(`dataGridHeaderCell-${scriptedPainlessFieldName2}`);
+ await PageObjects.discover.clickTableHeaderListItem(scriptedPainlessFieldName2, 'Sort A-Z');
await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00');
- });
+ await testSubjects.click('dataGridHeaderCell-@timestamp');
+ await PageObjects.discover.clickTableHeaderListItem('@timestamp', 'Sort A-Z');
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ const sortedDataByTimeField = await PageObjects.discover.getDataGridTableValues();
+ expect(sortedDataByTimeField[0][0]).contain('updateExpectedResultHere');
+ expect(sortedDataByTimeField[0][1]).contain('2015-09-18 07:00');
- await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`);
+ await testSubjects.click('dataGridColumnSortingButton');
+ await PageObjects.discover.removeSort(`${scriptedPainlessFieldName2}`);
await PageObjects.header.waitUntilLoadingHasFinished();
- await retry.try(async function () {
- const rowData = await PageObjects.discover.getDocTableIndex(1);
- expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00');
- });
+ const sortedDataByPainlessField = await PageObjects.discover.getDataGridTableValues();
+ expect(sortedDataByPainlessField[0][0]).contain('updateExpectedResultHere');
+ expect(sortedDataByPainlessField[0][1]).contain('2015-09-18 07:00');
});
it('should filter by scripted field value in Discover', async function () {
diff --git a/test/functional/apps/management/_scripted_fields_preview.js b/test/functional/apps/management/_scripted_fields_preview.js
index adeefa118345..304f757d006a 100644
--- a/test/functional/apps/management/_scripted_fields_preview.js
+++ b/test/functional/apps/management/_scripted_fields_preview.js
@@ -38,9 +38,8 @@ export default function ({ getService, getPageObjects }) {
describe('scripted fields preview', () => {
before(async function () {
await browser.setWindowSize(1200, 800);
- await PageObjects.settings.createIndexPattern();
-
await PageObjects.settings.navigateTo();
+ await PageObjects.settings.createIndexPattern();
await PageObjects.settings.clickOpenSearchDashboardsIndexPatterns();
await PageObjects.settings.clickIndexPatternLogstash();
await PageObjects.settings.clickScriptedFieldsTab();
diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts
index f09be976e38e..f81c287a478f 100644
--- a/test/functional/page_objects/discover_page.ts
+++ b/test/functional/page_objects/discover_page.ts
@@ -206,6 +206,7 @@ export function DiscoverPageProvider({ getService, getPageObjects }: FtrProvider
}
public async getDocHeader() {
+ const table = this.dataGrid;
const docHeader = await find.byCssSelector('thead > tr:nth-child(1)');
return await docHeader.getVisibleText();
}
@@ -439,6 +440,82 @@ export function DiscoverPageProvider({ getService, getPageObjects }: FtrProvider
public async clearSavedQuery() {
await testSubjects.click('saved-query-management-clear-button');
}
+
+ /**
+ * Retrieves data grid table values.
+ *
+ * This function fetches the values present in a data grid table.
+ *
+ * @returns {Promise} A promise resolving to the table values.
+ */
+ public async getDataGridTableValues(): Promise {
+ return await dataGridTable.getDataGridTableValues();
+ }
+
+ /**
+ * Removes sorting from a specified column in a data grid.
+ *
+ * This function removes sorting of column if applied in the sort field.
+ *
+ * @param {string} columnName - The name of the column from which sorting should be removed.
+ * @returns {Promise}
+ */
+ public async removeSort(columnName: string): Promise {
+ const parentDiv = await testSubjects.find(
+ `euiDataGridColumnSorting-sortColumn-${columnName}`
+ );
+
+ // Within this parent div, locate the button with the specified aria-label using CSS and click it
+ const cssSelector = `.euiDataGridColumnSorting__button[aria-label^="Remove from data grid sort: ${columnName}"]`;
+ const buttonToRemoveSort = await parentDiv.findByCssSelector(cssSelector);
+ await buttonToRemoveSort.click();
+ }
+
+ /**
+ * Clicks on a list item within the table column header based on column name and title.
+ *
+ * This function searches for a list item via title associated with a given column name.
+ * Once the item is found, its associated button is clicked.
+ *
+ * @param {string} columnName - The name of the column.
+ * @param {string} title - The title of the list item to be clicked.
+ * @returns {Promise}
+ * @throws Will throw an error if a clickable list item with the specified title is not found.
+ */
+ public async clickTableHeaderListItem(columnName: string, title: string): Promise {
+ // locate the ul using the columnName
+ const ulElement = await testSubjects.find(`dataGridHeaderCellActionGroup-${columnName}`);
+ const $ = await ulElement.parseDomContent();
+
+ // loop through each within the ul
+ const liElements = $('li').toArray();
+ let index = 0;
+
+ for (const liElement of liElements) {
+ const li = $(liElement);
+
+ // Check if the li contains the isClickable class substring
+ if (li.is('li[class*="euiListGroupItem-isClickable"]')) {
+ const span = li.find(`span[title="${title}"]`);
+
+ // If the span with the given title is found
+ if (span.length > 0) {
+ // find and click the button
+ const seleniumLiElement = await ulElement.findByCssSelector(
+ `li:nth-child(${index + 1}) button`
+ );
+ // Click on the located WebElement
+ await seleniumLiElement.click();
+ return;
+ }
+ }
+ index++;
+ }
+
+ throw new Error(
+ `Could not find a clickable list item for column "${columnName}" with list item "${title}".`
+ );
+ }
}
return new DiscoverPage();
diff --git a/test/functional/services/dashboard/expectations.ts b/test/functional/services/dashboard/expectations.ts
index 4bdf355eb049..641c56b586fd 100644
--- a/test/functional/services/dashboard/expectations.ts
+++ b/test/functional/services/dashboard/expectations.ts
@@ -36,6 +36,7 @@ export function DashboardExpectProvider({ getService, getPageObjects }: FtrProvi
const log = getService('log');
const retry = getService('retry');
const testSubjects = getService('testSubjects');
+ const dataGrid = getService('dataGrid');
const find = getService('find');
const filterBar = getService('filterBar');
const PageObjects = getPageObjects(['dashboard', 'visualize']);
@@ -233,11 +234,9 @@ export function DashboardExpectProvider({ getService, getPageObjects }: FtrProvi
async savedSearchRowCount(expectedCount: number) {
log.debug(`DashboardExpect.savedSearchRowCount(${expectedCount})`);
await retry.try(async () => {
- const savedSearchRows = await testSubjects.findAll(
- 'docTableExpandToggleColumn',
- findTimeout
- );
- expect(savedSearchRows.length).to.be(expectedCount);
+ // Need to change it here to find out how many rows there are
+ const timeStamps = await dataGrid.getDataGridTableColumn('date');
+ expect(timeStamps.length).to.be(expectedCount);
});
}
diff --git a/test/functional/services/data_grid.ts b/test/functional/services/data_grid.ts
index a80c377e1a7d..b23eabb4ef01 100644
--- a/test/functional/services/data_grid.ts
+++ b/test/functional/services/data_grid.ts
@@ -42,6 +42,7 @@ export function DataGridProvider({ getService }: FtrProviderContext) {
class DataGrid {
// This test no longer works in the new data explorer data grid table
// since each data grid table cell is now rendered differently
+ // https://github.com/opensearch-project/OpenSearch-Dashboards/issues/5108
async getDataGridTableData(): Promise {
const table = await find.byCssSelector('.euiDataGrid');
const $ = await table.parseDomContent();
@@ -70,6 +71,34 @@ export function DataGridProvider({ getService }: FtrProviderContext) {
};
}
+ /**
+ * Retrieves the values from a data grid table.
+ *
+ * The function fetches values present in a data grid table and organizes them into rows and columns.
+ * Each row is an array of strings, and the entire table is an array of such rows.
+ *
+ * @returns {Promise} A promise resolving to a 2D array of table values.
+ */
+ async getDataGridTableValues(): Promise {
+ const table = await testSubjects.find('docTable');
+ const $ = await table.parseDomContent();
+ const cellsArr = $.findTestSubjects('dataGridRowCell').toArray();
+ const rows: string[][] = [];
+ let rowIdx = -1;
+
+ for (const cell of cellsArr) {
+ const cCell = $(cell);
+ const isFirstColumn = cCell.attr('class').includes('euiDataGridRowCell--firstColumn');
+ if (isFirstColumn) {
+ rowIdx++;
+ rows[rowIdx] = [];
+ } else {
+ rows[rowIdx].push(this.getTextFromCell(cCell));
+ }
+ }
+ return Promise.resolve(rows);
+ }
+
/**
* Retrieves the header fields of the data grid.
*
@@ -99,6 +128,15 @@ export function DataGridProvider({ getService }: FtrProviderContext) {
await find.clickByButtonText('Remove column');
}
+ /**
+ * Retrieves values from a specific column in a data grid table.
+ *
+ * This function targets a column based on a CSS class selector and retrieves its cell values.
+ * It makes use of the Cheerio library to parse and navigate the DOM.
+ *
+ * @param {string} selector - The CSS class suffix used to identify cells of the desired column.
+ * @returns {Promise} A promise resolving to an array of cell values from the specified column.
+ */
async getDataGridTableColumn(selector: string): Promise {
const table = await find.byCssSelector('.euiDataGrid');
const $ = await table.parseDomContent();
@@ -110,12 +148,26 @@ export function DataGridProvider({ getService }: FtrProviderContext) {
const cCell = $(cell);
if (cCell.hasClass(`euiDataGridRowCell--${selector}`)) {
// The column structure is very nested to get the actual text
- columnValues.push(cCell.children().children().children().children().text());
+ columnValues.push(this.getTextFromCell(cCell));
}
});
return columnValues;
}
+
+ /**
+ * Extracts the text from a cell in the data grid.
+ *
+ * Given a cell represented by a Cheerio object, this function navigates its nested structure
+ * to extract the contained text.
+ *
+ * @param {any} cCell - The Cheerio representation of the cell from which text needs to be extracted.
+ * @returns {string} The extracted text from the cell.
+ */
+ getTextFromCell(cCell: any): string {
+ // navigate the nested structure and get the text
+ return cCell.children().children().children().children().text();
+ }
}
return new DataGrid();