Skip to content

Commit 38b398e

Browse files
committed
edited tests
1 parent eac8cbc commit 38b398e

File tree

9 files changed

+116
-64
lines changed

9 files changed

+116
-64
lines changed

acceptance-tests/constants/systems-properties.constant.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,3 @@ export enum systemsColumn {
1111
workspace = 'workspace',
1212
scan_code = 'scan code',
1313
}
14-
15-
export const fieldsWithGetByTestIdSelectorForSystemsQueryEditor = ['Alias', 'Locked status', 'Model', 'Operating system', 'Scan code', 'Vendor', 'Workspace'];
16-
export const getByLabelSelectorFieldsForSystemsQueryEditor = ['Connection status', 'Minion ID'];

acceptance-tests/fake-api/database/systems.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ export const data = [
1313
"172.10.1.37"
1414
],
1515
},
16-
workspace: "Default",
16+
workspace: "default-workspace",
1717
scanCode: "scanCode1",
1818
},
1919
{
2020
alias: 'System-2',
2121
id: 'SYSTEM-2',
22-
state: "DISCONNECTED",
22+
state: "CONNECTED",
2323
locked: false,
2424
systemStartTime: "2025-01-8T16:59:31.000Z",
2525
model: "Model2",
@@ -30,7 +30,7 @@ export const data = [
3030
"10.5.136.55"
3131
]
3232
},
33-
workspace: "Default",
33+
workspace: "default-workspace",
3434
scanCode: "scanCode2",
3535
},
3636
{
@@ -47,7 +47,7 @@ export const data = [
4747
"10.5.136.44"
4848
]
4949
},
50-
workspace: "workspace3",
50+
workspace: "default-workspace",
5151
scanCode: "scanCode3",
5252
},
5353
{
@@ -64,7 +64,7 @@ export const data = [
6464
"10.8.127.44"
6565
]
6666
},
67-
workspace: "workspace4",
67+
workspace: "default-workspace",
6868
scanCode: "scanCode4",
6969
},
7070
{
@@ -81,7 +81,7 @@ export const data = [
8181
"127.6.0.1"
8282
]
8383
},
84-
workspace: "workspace5",
84+
workspace: "workspace-2",
8585
scanCode: "scanCode5",
8686
},
8787
{
@@ -98,7 +98,7 @@ export const data = [
9898
"10.6.0.1"
9999
]
100100
},
101-
workspace: "Default",
101+
workspace: "default-workspace",
102102
scanCode: "scanCode6",
103103
},
104104
{
@@ -115,7 +115,7 @@ export const data = [
115115
"10.6.0.1"
116116
]
117117
},
118-
workspace: "workspace7",
118+
workspace: "workspace-2",
119119
scanCode: "scanCode7",
120120
},
121121
{
@@ -132,7 +132,7 @@ export const data = [
132132
"10.8.0.1"
133133
]
134134
},
135-
workspace: "workspace8",
135+
workspace: "workspace-2",
136136
scanCode: "scanCode8",
137137
},
138138
{
@@ -149,7 +149,7 @@ export const data = [
149149
"10.8.0.2"
150150
]
151151
},
152-
workspace: "workspace9",
152+
workspace: "default-workspace",
153153
scanCode: "scanCode9",
154154
},
155155
{
@@ -166,7 +166,7 @@ export const data = [
166166
"10.9.0.11"
167167
]
168168
},
169-
workspace: "workspace10",
169+
workspace: "default-workspace",
170170
scanCode: "scanCode10",
171171
},
172172
]

acceptance-tests/fake-api/routes/systemsRoutes.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class SystemsRoutes {
3030
const idFilterForSecondSystemFromDb = 'id = "SYSTEM-2"';
3131
const scanCodeFilterForFirstSystemFromDb = 'scanCode = "scanCode1"';
3232
const scanCodeFilterForEighthSystemFromDb = 'scanCode = "scanCode8"';
33-
const complexFilter = 'id = "SYSTEM-2" && connected.data.state = "Disconnected" || grains.data.minion_blackout.Equals(True)';
33+
const complexFilterForPanel = 'id = "SYSTEM-2" && connected.data.state = "Disconnected" || grains.data.minion_blackout.Equals(True)';
34+
const complexFilterForVariable = 'connected.data.state = "CONNECTED" && workspace = "default-workspace" || grains.data.productname = "Model8"';
3435

3536
if (req.method !== 'POST') {
3637
return;
@@ -56,11 +57,16 @@ class SystemsRoutes {
5657
return;
5758
}
5859

59-
if (req.body.filter === complexFilter) {
60+
if (req.body.filter === complexFilterForPanel) {
6061
res.status(200).json({ count: 2, data: data.filter(data => (data.id === 'SYSTEM-2' && data.state === "DISCONNECTED" || data.locked === true)) });
6162
return;
6263
}
6364

65+
if (req.body.filter === complexFilterForVariable) {
66+
res.status(200).json({ count: 3, data: data.filter(data => (data.state === "CONNECTED" && data.workspace === "default-workspace" || data.productName === "Model8")) });
67+
return;
68+
}
69+
6470
res.status(200).json({ count: data.length, data: data });
6571
}
6672
}

acceptance-tests/page-objects/dashboard/components/dashboard-variable/dashboard-system-variable.component.ts

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ export class DashboardSystemVariableComponent extends DashboardVariableBaseCompo
2525
}
2626

2727
public get andFilterGroupButton(): Locator {
28-
return this.page.getByLabel('And', { exact: true }).getByText('And');
28+
return this.page.getByRole('menuitem', { name: 'And', exact: true });
2929
}
3030

3131
public get orFilterGroupButton(): Locator {
32-
return this.page.getByText('Or', { exact: true });
32+
return this.page.getByRole('menuitem', { name: 'Or', exact: true });
3333
}
3434

3535
public queryBuilderValueField(property: string): Locator {
@@ -49,24 +49,23 @@ export class DashboardSystemVariableComponent extends DashboardVariableBaseCompo
4949
if (property.toLowerCase() === systemsColumn.workspace || property.toLowerCase() === systemsColumn.connection_status || property.toLowerCase() === systemsColumn.locked_status) {
5050
await this.queryBuilderValueField(property).click();
5151
await this.page.keyboard.type(value);
52-
// The jqx query builder needs some time to process the typed text, otherwise the next click action will not find the option in the dropdown and will fail
53-
await new Promise(resolve => setTimeout(resolve, 100));
54-
await this.page.locator('a').filter({ hasText: new RegExp(`^${value}$`) }).waitFor({ state: 'visible' });
55-
await this.page.locator('a').filter({ hasText: new RegExp(`^${value}$`) }).click();
52+
const option = this.page.locator('[data-label="' + value + '"]');
53+
await option.waitFor({ state: 'visible' });
54+
await option.click();
55+
5656
} else {
5757
await this.queryBuilderValueField(property).click();
5858
await this.page.keyboard.type(value);
5959
}
6060
}
6161

62-
async addFilterBySelectingProperty(property: string, operation: string, value: string): Promise<void> {
62+
async addFilterByTypingPropertyName(property: string, operation: string, value: string): Promise<void> {
6363
await this.queryBuilderPropertyField.last().click();
6464
await this.queryBuilderPropertyFieldOpened.clear();
6565
await this.page.keyboard.type(property);
6666
// The jqx query builder needs some time to process the typed text, otherwise the next click action will not find the option in the dropdown and will fail
6767
await this.page.getByRole('option', { name: property }).waitFor({ state: 'visible' });
6868
await pressEnter(this.page);
69-
await this.page.getByRole('option', { name: property }).waitFor({ state: 'hidden' });
7069
// The library makes the Operator field unclickable via CSS (pointer-events: none).
7170
// Using dispatchEvent bypasses this restriction and fires the event directly on the element.
7271
await this.queryBuilderOperationField.last().dispatchEvent('pointerdown', { bubbles: true, isPrimary: true });
@@ -77,13 +76,32 @@ export class DashboardSystemVariableComponent extends DashboardVariableBaseCompo
7776
}
7877

7978
async addFilterGroup(operator: string): Promise<void> {
80-
await this.addGroupFilterButton.click();
81-
if (operator.toLowerCase() === 'and') {
82-
await this.andFilterGroupButton.waitFor({ state: 'visible' });
83-
await this.andFilterGroupButton.click();
84-
} else if (operator.toLowerCase() === 'or') {
85-
await this.orFilterGroupButton.waitFor({ state: 'visible' });
86-
await this.orFilterGroupButton.click();
87-
}
79+
// The conditionsMenu popup is clipped by the variable-settings form's scroll container.
80+
// The QB itself has overflow:visible, so the popup escapes the QB element, but Grafana's
81+
// form panel clips it. Scrolling the form to the bottom before clicking ensures the popup
82+
// opens in visible space below the button. After selecting the option, scroll back to top
83+
// so subsequent interactions can find the newly added condition row.
84+
await this.page.evaluate(() => {
85+
const scrollContainer = document.querySelector('[class*="scrollbar-view"]') as HTMLElement
86+
?? document.querySelector('.scrollbar-view') as HTMLElement;
87+
if (scrollContainer) { scrollContainer.scrollTop = scrollContainer.scrollHeight; }
88+
});
89+
// Wait for the button to be stable after scrolling before clicking.
90+
await this.addGroupFilterButton.waitFor({ state: 'visible' });
91+
const menuButton = operator.toLowerCase() === 'and' ? this.andFilterGroupButton : this.orFilterGroupButton;
92+
// The first click can miss the dropdown opening if the page hasn't fully settled after
93+
// the scroll. Retry until the And/Or menu item becomes visible.
94+
await expect(async () => {
95+
await this.addGroupFilterButton.click();
96+
await menuButton.waitFor({ state: 'visible', timeout: 2000 });
97+
}).toPass({ timeout: 10000 });
98+
await menuButton.click();
99+
// Scroll back so the new empty condition row (appended at the bottom of the QB) is visible.
100+
await this.page.evaluate(() => {
101+
const scrollContainer = document.querySelector('[class*="scrollbar-view"]') as HTMLElement
102+
?? document.querySelector('.scrollbar-view') as HTMLElement;
103+
if (scrollContainer) { scrollContainer.scrollTop = 0; }
104+
});
105+
await this.queryBuilderPropertyField.last().waitFor({ state: 'visible' });
88106
}
89107
}

acceptance-tests/page-objects/dashboard/components/panel-query-editor/systems-query-editor.component.ts

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Page, Locator } from '@playwright/test';
22
import { pressEnter, selectAllAndDeleteTextInInputField } from '../../../../utils/keyboard-utilities';
3-
import { fieldsWithGetByTestIdSelectorForSystemsQueryEditor, getByLabelSelectorFieldsForSystemsQueryEditor } from '../../../../constants/systems-properties.constant';
43

54
export class SystemsQueryEditorComponent {
65
readonly page: Page;
@@ -41,15 +40,6 @@ export class SystemsQueryEditorComponent {
4140
return this.page.getByRole('radio', { name: queryType });
4241
}
4342

44-
public selectQueryBuilderPropertyOption(optionName: string): Locator {
45-
if (fieldsWithGetByTestIdSelectorForSystemsQueryEditor.includes(optionName)) {
46-
return this.page.getByTestId(`query-editor-row`).getByText(optionName);
47-
} else if (getByLabelSelectorFieldsForSystemsQueryEditor.includes(optionName)) {
48-
return this.page.getByLabel(optionName, { exact: true }).getByText(optionName);
49-
}
50-
return this.page.getByRole('option', { name: optionName }).locator('a');
51-
}
52-
5343
public variableDropdown(variableName: string): Locator {
5444
return this.page.getByTestId(`data-testid Dashboard template variables Variable Value DropDown value link text ${variableName}`);
5545
}
@@ -58,25 +48,11 @@ export class SystemsQueryEditorComponent {
5848
return this.page.getByRole('checkbox', { name: optionName });
5949
}
6050

61-
async addFilterBySelectingProperty(property: string, operation: string, value: string): Promise<void> {
62-
await this.queryBuilderPropertyField.last().click();
63-
await this.selectQueryBuilderPropertyOption(property).click();
64-
await this.page.getByRole('option', { name: property }).waitFor({ state: 'hidden' });
65-
// The library makes the Operator field unclickable via CSS (pointer-events: none).
66-
// Using dispatchEvent bypasses this restriction and fires the event directly on the element.
67-
await this.queryBuilderOperationField.last().dispatchEvent('pointerdown', { bubbles: true, isPrimary: true });
68-
await this.page.getByRole('option', { name: operation }).click();
69-
await this.queryBuilderValueField.last().click();
70-
await this.page.keyboard.type(value);
71-
await pressEnter(this.page);
72-
}
73-
7451
async addFilterByTypingPropertyName(property: string, operation: string, value: string): Promise<void> {
7552
await this.queryBuilderPropertyField.last().click();
7653
await selectAllAndDeleteTextInInputField(this.page);
7754
await this.page.keyboard.type(property);
78-
// The jqx query builder needs some time to process the typed text, otherwise the next click action will not find the option in the dropdown and will fail
79-
await new Promise(resolve => setTimeout(resolve, 100));
55+
await this.page.getByRole('option', { name: property }).waitFor({ state: 'visible' });
8056
await pressEnter(this.page);
8157
// The library makes the Operator field unclickable via CSS (pointer-events: none).
8258
// Using dispatchEvent bypasses this restriction and fires the event directly on the element.

acceptance-tests/page-objects/data-sources/data-sources.pageobject.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ export class DataSourcesPage {
4949
return this.page.getByTestId('data-testid Alert success').getByText('Data source connected and authentication successful!Next, you can start to');
5050
}
5151

52+
public get systemsFeatureFlagsSwitch(): Locator {
53+
return this.page.locator('div').filter({ hasText: /^System query builder$/ }).locator('input[role="switch"]');
54+
}
55+
5256
public existentDataSourceLink(dataSourceName: string): Locator {
5357
return this.page.getByRole('link', { name: dataSourceName, exact: true });
5458
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { test, expect } from '@playwright/test';
2+
import { DataSourcesPage } from '../../../page-objects/data-sources/data-sources.pageobject';
3+
import { FAKE_API_URL } from '../../../config/environment';
4+
import { timeOutPeriod } from '../../../constants/global.constant';
5+
6+
test.describe('Datasource Configuration', () => {
7+
let dataSource: DataSourcesPage;
8+
const dataSourceName = 'Systemlink Systems Configuration';
9+
10+
test.beforeAll(async ({ browser }) => {
11+
const context = await browser.newContext();
12+
const page = await context.newPage();
13+
dataSource = new DataSourcesPage(page);
14+
});
15+
16+
test.describe.serial('Creation and Deletion of SystemLink Systems data source', () => {
17+
test('should create a SystemLink Systems data source', async () => {
18+
await dataSource.navigateToDatasourcesPage();
19+
await dataSource.addDataSourceButton.click();
20+
await dataSource.dataSource('SystemLink Systems').click();
21+
await dataSource.nameSettingsInputField.waitFor({ state: 'visible', timeout: timeOutPeriod });
22+
await dataSource.httpSettingsURL.waitFor({ state: 'visible', timeout: timeOutPeriod });
23+
await dataSource.changeNameInputFieldValue(dataSourceName);
24+
25+
await dataSource.httpSettingsURL.fill(FAKE_API_URL);
26+
await expect(dataSource.systemsFeatureFlagsSwitch).toBeChecked();
27+
await dataSource.saveAndTestButton.click();
28+
29+
await expect(dataSource.dataSourceConnectedSuccessMessage).toBeVisible({ timeout: timeOutPeriod });
30+
31+
});
32+
33+
test('delete a SystemLink Systems data source', async () => {
34+
await dataSource.deleteDataSource(dataSourceName);
35+
await expect(dataSource.dataSourceSuccessMessage).toHaveText('Data source deleted', { timeout: timeOutPeriod });
36+
});
37+
});
38+
39+
test('should show error message when trying to connect with wrong URL', async () => {
40+
await dataSource.navigateToDatasourcesPage();
41+
await dataSource.addDataSourceButton.click();
42+
await dataSource.dataSource('SystemLink Systems').click();
43+
await dataSource.nameSettingsInputField.waitFor({ state: 'visible', timeout: timeOutPeriod });
44+
await dataSource.httpSettingsURL.waitFor({ state: 'visible', timeout: timeOutPeriod });
45+
await dataSource.changeNameInputFieldValue(dataSourceName);
46+
await dataSource.httpSettingsURL.fill('http://wrong-url.com');
47+
await dataSource.saveAndTestButton.click();
48+
await expect(dataSource.dataSourceErrorMessage).toContainText("failed with status code: 502", { timeout: timeOutPeriod });
49+
await dataSource.deleteDataSource(dataSourceName);
50+
});
51+
});

acceptance-tests/tests/datasources/system/global-variable-integration/system-ds.minion-id-return-type.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ test.describe('Systems data source with minion id return type', () => {
5151

5252
test('should add filter by minionId using the system variable', async () => {
5353
await dashboard.panel.systemsQueryEditor.selectQueryType('Properties');
54-
await dashboard.panel.systemsQueryEditor.addFilterBySelectingProperty('Minion ID', 'equals', '$id');
54+
await dashboard.panel.systemsQueryEditor.addFilterByTypingPropertyName('Minion ID', 'equals', '$id');
5555

5656
await expect(dashboard.panel.table.firstFilterRow).toContainText('Minion ID');
5757
await expect(dashboard.panel.table.firstFilterRow).toContainText('equals');
@@ -96,7 +96,7 @@ test.describe('Systems data source with minion id return type', () => {
9696

9797
test('should add complex filter', async () => {
9898
await dashboard.panel.systemsQueryEditor.addFilterGroup('And');
99-
await dashboard.panel.systemsQueryEditor.addFilterBySelectingProperty('Connection status', 'equals', 'Disconnected');
99+
await dashboard.panel.systemsQueryEditor.addFilterByTypingPropertyName('Connection status', 'equals', 'Disconnected');
100100
await pressEnter(dashboard.page);
101101

102102
await expect(dashboard.panel.table.secondFilterRow).toContainText('Connection status');

acceptance-tests/tests/datasources/system/global-variable-integration/system-ds.scan-code-return-type.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ test.describe('Systems data source with scan code return type', () => {
3939

4040
});
4141

42-
test('should add a complex filter to the creeated systems variable', async () => {
42+
test('should add a complex filter to the created systems variable', async () => {
4343
await dashboard.settings.editVariable('scanCode');
44-
await dashboard.settings.systemVariable.addFilterBySelectingProperty('Connection status', 'equals', 'Connected');
44+
await dashboard.settings.systemVariable.addFilterByTypingPropertyName('Connection status', 'equals', 'Connected');
4545

4646
await dashboard.settings.systemVariable.addFilterGroup('And');
47-
await dashboard.settings.systemVariable.addFilterBySelectingProperty('Workspace', 'equals', 'Default');
47+
await dashboard.settings.systemVariable.addFilterByTypingPropertyName('Workspace', 'equals', 'Default');
4848
await pressEnter(dashboard.page);
4949

5050
await dashboard.settings.systemVariable.addFilterGroup('Or');
51-
await dashboard.settings.systemVariable.addFilterBySelectingProperty('Model', 'equals', 'Model6');
51+
await dashboard.settings.systemVariable.addFilterByTypingPropertyName('Model', 'equals', 'Model8');
5252
await pressEnter(dashboard.page);
5353
});
5454

@@ -103,7 +103,7 @@ test.describe('Systems data source with scan code return type', () => {
103103
expect(await dashboard.panel.table.checkColumnValue(systemsColumn.vendor, 'Vendor8')).toBeTruthy();
104104
expect(await dashboard.panel.table.checkColumnValue(systemsColumn.operating_system, 'OS8')).toBeTruthy();
105105
expect(await dashboard.panel.table.checkColumnValue(systemsColumn.ip_address, '10.8.0.1')).toBeTruthy();
106-
expect(await dashboard.panel.table.checkColumnValue(systemsColumn.workspace, 'workspace8')).toBeTruthy();
106+
expect(await dashboard.panel.table.checkColumnValue(systemsColumn.workspace, 'Workspace 2')).toBeTruthy();
107107
expect(await dashboard.panel.table.checkColumnValue(systemsColumn.scan_code, 'scanCode8')).toBeTruthy();
108108
});
109109
});

0 commit comments

Comments
 (0)