Skip to content

Commit ab7c3e3

Browse files
authored
Add FT for Timeline (#1343)
Signed-off-by: Huy Nguyen <[email protected]>
1 parent c13164a commit ab7c3e3

File tree

8 files changed

+20251
-0
lines changed

8 files changed

+20251
-0
lines changed

cypress/fixtures/dashboard/opensearch_dashboards/vis_type_timeline/vis-timeline.data.txt

Lines changed: 20000 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
import {
6+
TL_INDEX_ID,
7+
TL_PATH_INDEX_DATA,
8+
TL_INDEX_START_TIME,
9+
TL_INDEX_END_TIME,
10+
TL_CREATE_URL,
11+
TL_VIS_APP_PATH,
12+
TL_INDEX_PATTERN,
13+
TL_ERROR_TOAST_MESSAGE_CLASSES,
14+
TL_ERROR_TOAST_MESSAGE_CLOSE_BUTTON,
15+
} from '../../../../../utils/constants';
16+
import { CURRENT_TENANT } from '../../../../../utils/commands';
17+
import { DS_NO_AUTH_LABEL } from '../../../../../utils/dashboards/datasource-management-dashboards-plugin/constants';
18+
import { constructTimelineExpression } from './utils';
19+
20+
if (Cypress.env('DATASOURCE_MANAGEMENT_ENABLED')) {
21+
describe('Timeline Visualization (MDS enabled)', () => {
22+
before(() => {
23+
CURRENT_TENANT.newTenant = 'global';
24+
cy.fleshTenantSettings();
25+
cy.deleteIndex(TL_INDEX_ID);
26+
cy.bulkUploadDocs(TL_PATH_INDEX_DATA);
27+
28+
// Dashboards requires an index pattern to continue to the Create Visualization stage
29+
cy.deleteIndexPattern(TL_INDEX_PATTERN);
30+
cy.createIndexPattern(TL_INDEX_PATTERN, {
31+
title: TL_INDEX_PATTERN,
32+
timeFieldName: 'timestamp',
33+
});
34+
35+
cy.deleteDataSourceIndexNoAuth(TL_INDEX_ID);
36+
cy.deleteAllDataSources();
37+
38+
// Create and setup datasource
39+
cy.createDataSourceNoAuth();
40+
cy.bulkUploadDocsToDataSourceNoAuth(TL_PATH_INDEX_DATA);
41+
42+
// Visit the page
43+
cy.log('create a new timeline visualization: ', TL_CREATE_URL);
44+
cy.visit(TL_CREATE_URL);
45+
cy.url().should('contain', TL_VIS_APP_PATH);
46+
47+
cy.setTopNavDate(TL_INDEX_START_TIME, TL_INDEX_END_TIME);
48+
49+
// Wait for page to load
50+
cy.waitForLoader();
51+
});
52+
53+
[
54+
{
55+
dataSourceName: DS_NO_AUTH_LABEL,
56+
toastExists: 'not.exist',
57+
},
58+
{
59+
dataSourceName: 'non-existent datasource',
60+
toastExists: 'exist',
61+
},
62+
].forEach(({ dataSourceName, toastExists }) => {
63+
it(`should query data from ${dataSourceName} and the error toast message should ${toastExists}`, () => {
64+
const timelineExpression = constructTimelineExpression({
65+
indexName: TL_INDEX_ID,
66+
avgMetricName: 'salary',
67+
timefield: 'timestamp',
68+
dataSourceName,
69+
});
70+
71+
cy.tlSetTimelineExpression(timelineExpression);
72+
cy.tlUpdateVisualization();
73+
74+
cy.get(`div${TL_ERROR_TOAST_MESSAGE_CLASSES}`).should(toastExists);
75+
76+
if (toastExists === `exist`) {
77+
// Toast must be cleared for other tests
78+
cy.get(TL_ERROR_TOAST_MESSAGE_CLOSE_BUTTON).click();
79+
}
80+
});
81+
});
82+
83+
it('should query from local cluster when data_source_name is not present', () => {
84+
const timelineExpression = constructTimelineExpression({
85+
indexName: TL_INDEX_ID,
86+
avgMetricName: 'salary',
87+
timefield: 'timestamp',
88+
});
89+
90+
cy.tlSetTimelineExpression(timelineExpression);
91+
cy.tlUpdateVisualization();
92+
93+
// Correct visualizations do not throw any toast message
94+
cy.get(`div${TL_ERROR_TOAST_MESSAGE_CLASSES}`).should('not.exist');
95+
});
96+
97+
after(() => {
98+
cy.deleteIndex(TL_INDEX_ID);
99+
cy.deleteIndexPattern(TL_INDEX_PATTERN);
100+
101+
cy.deleteDataSourceIndexNoAuth(TL_INDEX_ID);
102+
cy.deleteAllDataSources();
103+
});
104+
});
105+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
import {
6+
TL_INDEX_ID,
7+
TL_PATH_INDEX_DATA,
8+
TL_INDEX_START_TIME,
9+
TL_INDEX_END_TIME,
10+
TL_CREATE_URL,
11+
TL_VIS_APP_PATH,
12+
TL_INDEX_PATTERN,
13+
TL_ERROR_TOAST_MESSAGE_CLASSES,
14+
TL_ERROR_TOAST_MESSAGE_CLOSE_BUTTON,
15+
} from '../../../../../utils/constants';
16+
import { CURRENT_TENANT } from '../../../../../utils/commands';
17+
import { constructTimelineExpression } from './utils';
18+
19+
if (!Cypress.env('DATASOURCE_MANAGEMENT_ENABLED')) {
20+
describe('Timeline Visualization', () => {
21+
before(() => {
22+
CURRENT_TENANT.newTenant = 'global';
23+
cy.fleshTenantSettings();
24+
cy.deleteIndex(TL_INDEX_ID);
25+
cy.bulkUploadDocs(TL_PATH_INDEX_DATA);
26+
27+
// Dashboards requires an index pattern to continue to the Create Visualization stage
28+
cy.deleteIndexPattern(TL_INDEX_PATTERN);
29+
cy.createIndexPattern(TL_INDEX_PATTERN, {
30+
title: TL_INDEX_PATTERN,
31+
timeFieldName: 'timestamp',
32+
});
33+
34+
// Visit the page
35+
cy.log('create a new timeline visualization: ', TL_CREATE_URL);
36+
cy.visit(TL_CREATE_URL);
37+
cy.url().should('contain', TL_VIS_APP_PATH);
38+
39+
cy.setTopNavDate(TL_INDEX_START_TIME, TL_INDEX_END_TIME);
40+
41+
// Wait for page to load
42+
cy.waitForLoader();
43+
});
44+
45+
it('should throw a toast message when data_source_name is used', () => {
46+
const timelineExpression = constructTimelineExpression({
47+
indexName: TL_INDEX_ID,
48+
avgMetricName: 'salary',
49+
timefield: 'timestamp',
50+
dataSourceName: 'non-existent datasource',
51+
});
52+
53+
cy.tlSetTimelineExpression(timelineExpression);
54+
cy.tlUpdateVisualization();
55+
56+
cy.get(`div${TL_ERROR_TOAST_MESSAGE_CLASSES}`).should('exist');
57+
58+
// Toast must be cleared for other tests
59+
cy.get(TL_ERROR_TOAST_MESSAGE_CLOSE_BUTTON).click();
60+
});
61+
62+
it('should query from local cluster when data_source_name is not present', () => {
63+
const timelineExpression = constructTimelineExpression({
64+
indexName: TL_INDEX_ID,
65+
avgMetricName: 'salary',
66+
timefield: 'timestamp',
67+
});
68+
69+
cy.tlSetTimelineExpression(timelineExpression);
70+
cy.tlUpdateVisualization();
71+
72+
// Correct visualizations do not throw any toast message
73+
cy.get(`div${TL_ERROR_TOAST_MESSAGE_CLASSES}`).should('not.exist');
74+
});
75+
76+
after(() => {
77+
cy.deleteIndex(TL_INDEX_ID);
78+
cy.deleteIndexPattern(TL_INDEX_PATTERN);
79+
});
80+
});
81+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
import { TL_CHAINABLE_EXPRESSION } from '../../../../../utils/constants';
6+
7+
export const constructTimelineExpression = ({
8+
indexName,
9+
avgMetricName,
10+
timefield,
11+
dataSourceName,
12+
}) => {
13+
const openSearchFunction = dataSourceName
14+
? `.opensearch(index=${indexName}, metric=avg:${avgMetricName}, timefield=${timefield}, data_source_name="${dataSourceName}")`
15+
: `.opensearch(index=${indexName}, metric=avg:${avgMetricName}, timefield=${timefield})`;
16+
17+
return `${openSearchFunction}${TL_CHAINABLE_EXPRESSION}.yaxis(label="Average ${avgMetricName}")`;
18+
};

cypress/utils/dashboards/commands.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import './vis_builder/commands';
7+
import './vis_type_timeline/commands';
78
import './vis_type_table/commands';
89
import './vis_type_vega/commands';
910
import './vis-augmenter/commands';

cypress/utils/dashboards/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const SAVED_OBJECTS_PATH =
2020

2121
export * from './vis_builder/constants';
2222
export * from './vis_type_table/constants';
23+
export * from './vis_type_timeline/constants';
2324
export * from './vis-augmenter/constants';
2425
export * from './data_explorer/constants';
2526
export * from './vis_type_vega/constants';
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
Cypress.Commands.add('tlSetTimelineExpression', (expression) => {
6+
cy.get('.react-monaco-editor-container textarea')
7+
.first()
8+
.click()
9+
.focused()
10+
.type('{ctrl}a')
11+
.type(expression, {
12+
delay: 0,
13+
parseSpecialCharSequences: false,
14+
});
15+
});
16+
17+
Cypress.Commands.add('tlUpdateVisualization', () => {
18+
cy.contains('button', 'Update').click();
19+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
import { BASE_PATH } from '../../base_constants';
6+
7+
// Data
8+
export const TL_INDEX_DATA = 'vis-timeline.data.txt';
9+
export const TL_PATH_FIXTURE =
10+
'dashboard/opensearch_dashboards/vis_type_timeline/';
11+
export const TL_PATH_INDEX_DATA = TL_PATH_FIXTURE + TL_INDEX_DATA;
12+
export const TL_INDEX_START_TIME = 'Dec 31, 2021 @ 00:00:00.000';
13+
export const TL_INDEX_END_TIME = 'Oct 2, 2022 @ 00:00:00.000';
14+
export const TL_INDEX_ID = 'vis-timeline';
15+
export const TL_INDEX_PATTERN = 'index-pattern-vis-timeline';
16+
17+
// App URL Paths
18+
export const TL_VIS_APP_PATH = '/app/visualize';
19+
export const TL_CREATE_URL = `${BASE_PATH}${TL_VIS_APP_PATH}#/create?type=timelion`; // URL pattern still uses Timelion
20+
21+
// Visualization
22+
export const TL_CHAINABLE_EXPRESSION = '.lines(show=true)';
23+
export const TL_ERROR_TOAST_MESSAGE_CLASSES =
24+
'.euiToast.euiToast--danger.euiGlobalToastListItem';
25+
export const TL_ERROR_TOAST_MESSAGE_CLOSE_BUTTON =
26+
'button.euiToast__closeButton';

0 commit comments

Comments
 (0)