Skip to content

Commit a4fe7f3

Browse files
authored
E2E: Rewrite mysql tests to playwright (#83424)
* E2E: Rewrite mysql tests to playwright * Fix lint * Add more selectors and address comments * Scope locators when locating text * Don't run it 20 times * Update new-datasource-variable to assert mysql
1 parent 351425a commit a4fe7f3

File tree

13 files changed

+212
-206
lines changed

13 files changed

+212
-206
lines changed

e2e/dashboards-suite/new-datasource-variable.spec.ts

+10-11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { e2e } from '../utils';
33
const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output';
44
const DASHBOARD_NAME = 'Test variable output';
55

6+
const gdev_mysql = 'gdev-mysql';
7+
const gdev_mysql_ds_tests = 'gdev-mysql-ds-tests';
8+
69
describe('Variables - Datasource', () => {
710
beforeEach(() => {
811
e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD'));
@@ -20,30 +23,26 @@ describe('Variables - Datasource', () => {
2023
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalNameInputV2().clear().type('VariableUnderTest').blur();
2124
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInputV2().type('Variable under test').blur();
2225

23-
// If this is failing, but sure to check there are Prometheus datasources named "gdev-prometheus" and "gdev-slow-prometheus"
26+
// If this is failing, but sure to check there are MySQL datasources named "gdev-mysql" and "gdev-mysql-ds-tests"
2427
// Or, just update is to match some gdev datasources to test with :)
2528
e2e.pages.Dashboard.Settings.Variables.Edit.DatasourceVariable.datasourceSelect().within(() => {
26-
cy.get('input').type('Prometheus{enter}');
29+
cy.get('input').type('MySQL{enter}');
2730
});
31+
e2e.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption().should('contain.text', gdev_mysql);
2832
e2e.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption().should(
2933
'contain.text',
30-
'gdev-prometheus'
31-
);
32-
e2e.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption().should(
33-
'contain.text',
34-
'gdev-slow-prometheus'
34+
gdev_mysql_ds_tests
3535
);
3636

3737
// Navigate back to the homepage and change the selected variable value
3838
e2e.pages.Dashboard.Settings.Variables.Edit.General.submitButton().click();
3939
e2e.pages.Dashboard.Settings.Actions.close().click();
4040
e2e.components.RefreshPicker.runButtonV2().click();
4141

42-
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('gdev-prometheus').click();
43-
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('gdev-slow-prometheus').click();
42+
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts(gdev_mysql).click();
43+
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts(gdev_mysql_ds_tests).click();
4444

4545
// Assert it was rendered
46-
cy.get('.markdown-html').should('include.text', 'VariableUnderTest: gdev-slow-prometheus-uid');
47-
cy.get('.markdown-html').should('include.text', 'VariableUnderTestText: gdev-slow-prometheus');
46+
cy.get('.markdown-html').should('include.text', `VariableUnderTestText: ${gdev_mysql_ds_tests}`);
4847
});
4948
});
+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
export const normalTableName = 'normalTable';
2+
export const tableNameWithSpecialCharacter = 'table-name';
3+
export const tablesResponse = {
4+
results: {
5+
tables: {
6+
status: 200,
7+
frames: [
8+
{
9+
schema: {
10+
refId: 'tables',
11+
meta: {
12+
executedQueryString:
13+
"SELECT table_name FROM information_schema.tables WHERE table_schema = 'DataMaker' ORDER BY table_name",
14+
},
15+
fields: [{ name: 'TABLE_NAME', type: 'string', typeInfo: { frame: 'string', nullable: true } }],
16+
},
17+
data: { values: [[normalTableName, tableNameWithSpecialCharacter]] },
18+
},
19+
],
20+
},
21+
},
22+
};
23+
24+
export const fieldsResponse = {
25+
results: {
26+
fields: {
27+
status: 200,
28+
frames: [
29+
{
30+
schema: {
31+
refId: 'fields',
32+
meta: {
33+
executedQueryString:
34+
"SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'DataMaker' AND table_name = 'RandomIntsWithTimes' ORDER BY column_name",
35+
},
36+
fields: [
37+
{ name: 'COLUMN_NAME', type: 'string', typeInfo: { frame: 'string', nullable: true } },
38+
{ name: 'DATA_TYPE', type: 'string', typeInfo: { frame: 'string', nullable: true } },
39+
],
40+
},
41+
data: {
42+
values: [
43+
['createdAt', 'id', 'time', 'updatedAt', 'bigint'],
44+
['datetime', 'int', 'datetime', 'datetime', 'int'],
45+
],
46+
},
47+
},
48+
],
49+
},
50+
},
51+
};
52+
53+
export const datasetResponse = {
54+
results: {
55+
datasets: {
56+
status: 200,
57+
frames: [
58+
{
59+
schema: {
60+
refId: 'datasets',
61+
meta: {
62+
executedQueryString:
63+
"SELECT DISTINCT TABLE_SCHEMA from information_schema.TABLES where TABLE_TYPE != 'SYSTEM VIEW' ORDER BY TABLE_SCHEMA",
64+
},
65+
fields: [{ name: 'TABLE_SCHEMA', type: 'string', typeInfo: { frame: 'string', nullable: true } }],
66+
},
67+
data: { values: [['DataMaker', 'mysql', 'performance_schema', 'sys']] },
68+
},
69+
],
70+
},
71+
},
72+
};

e2e/plugin-e2e/mysql/mysql.spec.ts

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { selectors } from '@grafana/e2e-selectors';
2+
import { expect, test } from '@grafana/plugin-e2e';
3+
4+
import {
5+
tablesResponse,
6+
fieldsResponse,
7+
datasetResponse,
8+
normalTableName,
9+
tableNameWithSpecialCharacter,
10+
} from './mocks/mysql.mocks';
11+
12+
test.beforeEach(async ({ context, selectors, explorePage }) => {
13+
await explorePage.datasource.set('gdev-mysql');
14+
await context.route(selectors.apis.DataSource.queryPattern, async (route, request) => {
15+
switch (request.postDataJSON().queries[0].refId) {
16+
case 'tables':
17+
return route.fulfill({ json: tablesResponse, status: 200 });
18+
case 'fields':
19+
return route.fulfill({ json: fieldsResponse, status: 200 });
20+
case 'datasets':
21+
return route.fulfill({ json: datasetResponse, status: 200 });
22+
default:
23+
return route.continue();
24+
}
25+
});
26+
});
27+
28+
test('code editor autocomplete should handle table name escaping/quoting', async ({ explorePage, selectors, page }) => {
29+
await page.getByLabel('Code').check();
30+
31+
const editor = explorePage.getByTestIdOrAriaLabel(selectors.components.CodeEditor.container).getByRole('textbox');
32+
await editor.fill('S');
33+
await page.getByLabel('SELECT <column> FROM <table>').locator('a').click();
34+
await expect(page.getByLabel(tableNameWithSpecialCharacter)).toBeVisible();
35+
await page.keyboard.press('Enter');
36+
37+
await expect(editor).toHaveValue(`SELECT FROM grafana.\`${tableNameWithSpecialCharacter}\``);
38+
39+
for (let i = 0; i < tableNameWithSpecialCharacter.length + 2; i++) {
40+
await page.keyboard.press('Backspace');
41+
}
42+
43+
await page.keyboard.press('Control+I');
44+
await expect(page.getByLabel(tableNameWithSpecialCharacter)).toBeVisible();
45+
});
46+
47+
test('visual query builder should handle time filter macro', async ({ explorePage, page }) => {
48+
await explorePage.getByTestIdOrAriaLabel(selectors.components.SQLQueryEditor.headerTableSelector).click();
49+
await page.getByText(normalTableName, { exact: true }).click();
50+
51+
// Open column selector
52+
await explorePage.getByTestIdOrAriaLabel(selectors.components.SQLQueryEditor.selectColumn).click();
53+
const select = page.getByLabel('Select options menu');
54+
await select.locator(page.getByText('createdAt')).click();
55+
56+
// Toggle where row
57+
await page.getByLabel('Filter').click();
58+
59+
// Click add filter button
60+
await page.getByRole('button', { name: 'Add filter' }).click();
61+
await page.getByRole('button', { name: 'Add filter' }).click(); // For some reason we need to click twice
62+
63+
// Open field selector
64+
await explorePage.getByTestIdOrAriaLabel(selectors.components.SQLQueryEditor.filterField).click();
65+
await select.locator(page.getByText('createdAt')).click();
66+
67+
// Open operator selector
68+
await explorePage.getByTestIdOrAriaLabel(selectors.components.SQLQueryEditor.filterOperator).click();
69+
await select.locator(page.getByText('Macros')).click();
70+
71+
// Open macros value selector
72+
await explorePage.getByTestIdOrAriaLabel('Macros value selector').click();
73+
await select.locator(page.getByText('timeFilter', { exact: true })).click();
74+
75+
// Validate that the timeFilter macro was added
76+
await expect(
77+
explorePage.getByTestIdOrAriaLabel(selectors.components.CodeEditor.container).getByRole('textbox')
78+
).toHaveValue(`SELECT\n createdAt\nFROM\n DataMaker.normalTable\nWHERE\n $__timeFilter(createdAt)\nLIMIT\n 50`);
79+
80+
// Validate that the timeFilter macro was removed when changed to equals operator
81+
await explorePage.getByTestIdOrAriaLabel(selectors.components.SQLQueryEditor.filterOperator).click();
82+
await select.locator(page.getByText('==')).click();
83+
84+
await explorePage.getByTestIdOrAriaLabel(selectors.components.DateTimePicker.input).click();
85+
await explorePage.getByTestIdOrAriaLabel(selectors.components.DateTimePicker.input).blur();
86+
87+
await expect(
88+
explorePage.getByTestIdOrAriaLabel(selectors.components.CodeEditor.container).getByRole('textbox')
89+
).not.toHaveValue(`SELECT\n createdAt\nFROM\n DataMaker.normalTable\nWHERE\n createdAt = NULL\nLIMIT\n 50`);
90+
});

e2e/various-suite/fixtures/datasets-response.json

-21
This file was deleted.

e2e/various-suite/fixtures/fields-response.json

-27
This file was deleted.

e2e/various-suite/fixtures/tables-response.json

-19
This file was deleted.

0 commit comments

Comments
 (0)