Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update tests to support Grafana 10 #222

Merged
merged 2 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/ui/ConfigEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export class ConfigEditor extends PureComponent<Props, State> {
onChange={this.onEditionChange}
value={jsonData.edition}
placeholder="Select your checkmk edition"
inputId="checkmk-edition"
/>
</InlineField>
<InlineField
Expand Down
7 changes: 5 additions & 2 deletions src/ui/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export const CheckMkSelect = <Key extends RequestSpecStringKeys>(props: CheckMkS
return (
<InlineField labelWidth={LABEL_WIDTH} label={props.label}>
<CheckMkAsyncSelect
inputId={`input_${props.label}`}
inputId={`input_${props.label?.replace(/ /g, '_')}`}
label={label}
autocompleter={autocompleter}
onChange={onChange}
Expand Down Expand Up @@ -376,11 +376,12 @@ export const HostTagFilter: React.FC<HostTagFilterProps> = (props) => {
};

interface HostLabelProps extends CommonProps<RequestSpec['host_labels']> {
inputId: string;
autocompleter: (value: string) => Promise<Array<SelectableValue<string>>>;
}

export const HostLabelFilter: React.FC<HostLabelProps> = (props) => {
const { value, autocompleter, label, onChange } = props;
const { value, autocompleter, label, onChange, inputId } = props;

const onLabelsChange = (items: Array<SelectableValue<string>>) => {
const result: string[] = [];
Expand Down Expand Up @@ -410,6 +411,7 @@ export const HostLabelFilter: React.FC<HostLabelProps> = (props) => {
onChange={onLabelsChange}
value={toMultiSelectValue(value)}
placeholder="Type to trigger search"
inputId={inputId}
/>
</InlineField>
);
Expand Down Expand Up @@ -487,6 +489,7 @@ export const OnlyActiveChildren = (props: OnlyActiveChildrenProps): JSX.Element
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
onChange={(value) => setActiveComponents((c) => [...c, value.value!])}
value={{ label: 'Add Filter' }}
inputId="input_add_filter"
/>
</InlineField>
)}
Expand Down
1 change: 1 addition & 0 deletions src/ui/filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export const Filters = (props: FiltersProp): JSX.Element => {
value={qHost.host_labels}
onChange={(host_labels: string[]) => setHostFilter({ ...qHost, host_labels: host_labels })}
autocompleter={hostLabelAutocompleter}
inputId="input_host_label"
/>
<HostTagFilter
label={labelForRequestSpecKey('host_tags', requestSpec)}
Expand Down
55 changes: 46 additions & 9 deletions tests/cypress/e2e/spec.cy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import '../support/api_commands';
import CheckmkSelectors from '../support/checkmk_selectors';
import '../support/commands';

describe('e2e tests', () => {
Expand All @@ -12,20 +13,41 @@ describe('e2e tests', () => {
const CmkCRE = 'Raw Edition';

const inputDatasourceId = 'data-source-picker';
const inputFilterId = 'react-select-7-input';
const inputGraphId = 'input_Predefined graph';
const inputGraphTypeId = 'input_Graph type';
const inputFilterId = CheckmkSelectors.AddDashboard.filterFieldId;
const inputGraphId = 'input_Predefined_graph';
const inputGraphTypeId = 'input_Graph_type';
const inputHostId = 'input_Hostname';
const inputMetricId = 'input_Single metric';
const inputMetricId = 'input_Single_metric';
const inputServiceId = 'input_Service';
const inputSiteId = 'input_Site';
const inputHostLabelId = CheckmkSelectors.AddDashboard.hostLabelFieldId;

const inputHostRegexDataTestId = 'host_name_regex-filter-input';
const inputServiceRegexDataTestId = 'service_regex-filter-input';

const queryEditorSelector = '[class="query-editor-row"]';

let cmkSite = 'cmk';

before(() => {
//Determine site name from variables
const grafanaCMKSite = Cypress.env('grafanaToCheckmkUrl')
? new URL(Cypress.env('grafanaToCheckmkUrl')).pathname.split('/').pop()
: 'cmk';

const cypressCMKSite = Cypress.env('cypressToCheckmkUrl')
? new URL(Cypress.env('cypressToCheckmkUrl')).pathname.split('/').pop()
: 'cmk';

if (grafanaCMKSite !== cypressCMKSite) {
console.log('Site name mismatch between grafanaToCheckmkUrl and cypressToCheckmkUrl');
console.log({ grafanaCMKSite, cypressCMKSite });
throw new Error('grafanaToCheckmkUrl and cypressToCheckmkUrl must have the same site name');
}

cmkSite = grafanaCMKSite;
console.log(`Site name is "${cmkSite}"`);

cy.deleteCmkAutomationUser(false); // clean-up possible existing user
cy.createCmkAutomationUser();

Expand All @@ -38,7 +60,7 @@ describe('e2e tests', () => {
cy.executeServiceDiscovery(hostName0, 'fix_all');
cy.executeServiceDiscovery(hostName1, 'refresh');
cy.executeServiceDiscovery(hostName1, 'fix_all');
cy.activateCmkChanges('cmk');
cy.activateCmkChanges(cmkSite);
cy.waitForPendingServices(2000);

cy.loginGrafana();
Expand All @@ -52,7 +74,7 @@ describe('e2e tests', () => {
cy.deleteCmkHost(hostName0);
cy.deleteCmkHost(hostName1);
cy.deleteCmkAutomationUser(true);
cy.activateCmkChanges('cmk');
cy.activateCmkChanges(cmkSite);
});

beforeEach(() => {
Expand All @@ -66,6 +88,8 @@ describe('e2e tests', () => {
});
describe('CEE tests', () => {
it('time-usage panel by service (single host)', {}, () => {
cy.selectDataSource(CmkCEE);

cy.contains('Checkmk ' + CmkCEE).should('be.visible'); // Assert Cmk CEE datasource is used

cy.inputLocatorById(inputFilterId).type('Hostname{enter}'); // Filter -> 'Host name'
Expand Down Expand Up @@ -100,12 +124,17 @@ describe('e2e tests', () => {
});

it('time-usage panel by service (multiple hosts)', {}, () => {
cy.selectDataSource(CmkCEE);

cy.contains('Checkmk ' + CmkCEE).should('be.visible'); // Assert Cmk CEE datasource is used
cy.inputLocatorById(inputFilterId).type('Service{enter}'); // Filter -> 'Service'

cy.inputLocatorById(inputServiceId).type('{enter}'); // Service -> 'Check_MK' (first entry)
cy.contains('Check_MK').should('exist');

cy.inputLocatorById(inputFilterId).type('regex{enter}'); // Filter -> 'Hostname regex'
cy.get('input[data-test-id="host_name_regex-filter-input"]').type('localhost_grafana[0-9]+{enter}');

cy.inputLocatorById(inputGraphId).click();
cy.get('[class="scrollbar-view"]')
.children()
Expand Down Expand Up @@ -135,6 +164,7 @@ describe('e2e tests', () => {
});

it('RAM-used panel by service regex (multiple hosts)', {}, () => {
cy.selectDataSource(CmkCEE);
cy.contains('Checkmk ' + CmkCEE).should('be.visible'); // Assert Cmk CEE datasource is used
cy.inputLocatorById(inputFilterId).type('Service regex{enter}'); // Filter -> 'Service'
cy.contains('Service regex').should('exist');
Expand All @@ -155,14 +185,15 @@ describe('e2e tests', () => {
});

it('RAM-used panel by host labels (multiple hosts, single metric)', {}, () => {
cy.selectDataSource(CmkCEE);
cy.contains('Checkmk ' + CmkCEE).should('be.visible'); // Assert Cmk CEE datasource is used
cy.inputLocatorById(inputFilterId).type('Host labels{enter}'); // Filter -> 'Host labels'
cy.contains('Host labels').should('exist');

cy.inputLocatorById('react-select-15-input').type('cmk/site:cm'); // Host labels -> 'cmk/site:cm' (one entry)
cy.inputLocatorById(inputHostLabelId).type('cmk/site:cm'); // Host labels -> 'cmk/site:cm' (one entry)
// TODO: should only contain a single lable, but shows all?
cy.contains('cmk/site:cmk').should('exist');
cy.contains('cmk/site:cmk').click();
cy.contains(`cmk/site:${cmkSite}`).should('exist');
cy.contains(`cmk/site:${cmkSite}`).click();

cy.inputLocatorById(inputGraphTypeId).click(); // Graph type -> 'Single metric'
cy.contains('Single metric').click();
Expand All @@ -182,6 +213,7 @@ describe('e2e tests', () => {
});

it('RAM-used panel by service regex and hostname regex', {}, () => {
cy.selectDataSource(CmkCEE);
cy.contains('Checkmk ' + CmkCEE).should('be.visible'); // Assert Cmk CEE datasource is used
cy.inputLocatorById(inputFilterId).type('Service regex{enter}'); // Filter -> 'Service'
cy.contains('Service regex').should('exist');
Expand Down Expand Up @@ -224,6 +256,7 @@ describe('e2e tests', () => {
});

it('Uptime panel by hostname', {}, () => {
cy.selectDataSource(CmkCEE);
cy.contains('Checkmk ' + CmkCEE).should('be.visible'); // Assert Cmk CEE datasource is used
cy.inputLocatorById(inputFilterId).type('Hostname{enter}'); // Filter -> 'Host name'

Expand All @@ -250,6 +283,8 @@ describe('e2e tests', () => {
});
describe('CRE tests', () => {
it('time-usage panel by service (single host)', {}, () => {
cy.selectDataSource(CmkCRE);

cy.passOnException('ResizeObserver loop limit exceeded');
cy.inputLocatorById(inputDatasourceId).type('Checkmk ' + CmkCRE + '{enter}');
cy.contains('Checkmk ' + CmkCRE).should('be.visible');
Expand Down Expand Up @@ -282,6 +317,8 @@ describe('e2e tests', () => {
cy.contains("Could not find 'cmk_cpu_time_by_phase'").should('be.visible'); // Assert previous graph input not visible
});
it('Used-RAM panel by service (single host)', {}, () => {
cy.selectDataSource(CmkCRE);

cy.passOnException('ResizeObserver loop limit exceeded');
cy.inputLocatorById(inputDatasourceId).type('Checkmk ' + CmkCRE + '{enter}');
cy.contains('Checkmk ' + CmkCRE).should('be.visible');
Expand Down
16 changes: 16 additions & 0 deletions tests/cypress/support/checkmk_selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const Selectors = {
SetupForm: {
name: 'input[id="basic-settings-name"]',
url: '[data-test-id="checkmk-url"]',
edition: 'input[id="checkmk-edition"]',
username: '[data-test-id="checkmk-username"]',
password: '[data-test-id="checkmk-password"]',
version: '[id="checkmk-version"]',
},
AddDashboard: {
filterFieldId: 'input_add_filter',
hostLabelFieldId: 'input_host_label',
},
};

export default Selectors;
34 changes: 22 additions & 12 deletions tests/cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import CheckMkSelectors from './checkmk_selectors';
import GrafanaSelectors from './grafana_selectors';

export {};

const panelContentSelector = '[class$="panel-content"]';
Expand All @@ -7,9 +10,9 @@ const plottedHoverSelectorOn = '[class="u-cursor-pt"]';

Cypress.Commands.add('loginGrafana', () => {
cy.visit('/login');
cy.get('input[name="user"]').type(Cypress.env('grafanaUsername'));
cy.get('input[name="password"]').type(Cypress.env('grafanaPassword'));
cy.get('[aria-label="Login button"]').click();
cy.get(GrafanaSelectors.Login.username_input).type(Cypress.env('grafanaUsername'));
cy.get(GrafanaSelectors.Login.password_input).type(Cypress.env('grafanaPassword'));
cy.get(GrafanaSelectors.Login.login_button).click();
// wait until page after logged in is fully loaded
cy.contains('Recently viewed dashboards').should('be.visible');
});
Expand All @@ -21,23 +24,29 @@ Cypress.Commands.add('logoutGrafana', () => {
Cypress.Commands.add('addNewPanel', () => {
// add a new panel in a new dashboard
cy.visit('/dashboard/new');
cy.get('button[aria-label="Add new panel"]').click();
cy.get(GrafanaSelectors.AddDashboard.add_new_panel_button).click();
});

Cypress.Commands.add('selectDataSource', (edition: string) => {
if (GrafanaSelectors.grafanaVersion >= 10) {
cy.get(`${GrafanaSelectors.AddDashboard.datasources_list}`).contains('button', `Checkmk ${edition}`).click();
}
});

Cypress.Commands.add('addCmkDatasource', (cmkUser: string, cmkPass: string, edition: string) => {
cy.visit('/datasources/new');
cy.get('button[aria-label="Add new data source Checkmk"]').contains('Checkmk').click();
cy.get(GrafanaSelectors.AddDataSource.select_datasource_button('Checkmk')).contains('Checkmk').click();

cy.get('input[id="basic-settings-name"]').type(' ' + edition);
cy.get('[data-test-id="checkmk-url"]').type(Cypress.env('grafanaToCheckmkUrl'));
cy.get('input[id="react-select-2-input"]').type(edition + '{enter}'); // TODO: introduce an id for the input selector
cy.get(CheckMkSelectors.SetupForm.name).type(' ' + edition);
cy.get(CheckMkSelectors.SetupForm.url).type(Cypress.env('grafanaToCheckmkUrl'));
cy.get(CheckMkSelectors.SetupForm.edition).type(edition + '{enter}');
cy.contains(edition).should('exist');

cy.get('[data-test-id="checkmk-username"]').type(cmkUser);
cy.get('[data-test-id="checkmk-password"]').type(cmkPass);
cy.get('[id="checkmk-version"]').type('<{enter}');
cy.get(CheckMkSelectors.SetupForm.username).type(cmkUser);
cy.get(CheckMkSelectors.SetupForm.password).type(cmkPass);
cy.get(CheckMkSelectors.SetupForm.version).type('<{enter}');

cy.get('[aria-label="Data source settings page Save and Test button"]').click();
cy.get(GrafanaSelectors.AddDataSource.save_and_test_button).click();

cy.get('[data-testid="data-testid Alert success"]').should('be.visible');
cy.contains('Data source is working').should('be.visible');
Expand Down Expand Up @@ -144,6 +153,7 @@ declare global {
assertLegendElement(text: string): Chainable<void>;
inputLocatorById(id: string): Chainable<JQuery>;
inputLocatorByDataTestId(dataTestId: string): Chainable<JQuery>;
selectDataSource(edition: string): Chainable<JQuery>;
}
}
}
28 changes: 28 additions & 0 deletions tests/cypress/support/grafana_selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const grafanaVersion = 10;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you looked into @grafana/e2e-selectors if this could help us in the long run?
i would be okay with updating this dependency to 10

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried using @grafana/e2e-selectors but they were not working with Cypress tests, so I did a workaround. I need to explore it a little more


const addDataSourceSaveAndTestButtonV9 = 'button[aria-label="Data source settings page Save and Test button"]';
const addDataSourceSaveAndTestButtonV10 = `button[data-testid="data-testid Data source settings page Save and Test button"]`;

const addNewPanelButtonV9 = 'button[aria-label="Add new panel"]';
const addNewPanelButtonV10 = 'button[data-testid="data-testid Create new panel button"]';

const Selectors = {
grafanaVersion,
Login: {
username_input: 'input[name="user"]',
password_input: 'input[name="password"]',
login_button: 'button[aria-label="Login button"]',
},

AddDataSource: {
select_datasource_button: (name: string): string => `button[aria-label="${`Add new data source ${name}`}"]`,
save_and_test_button: grafanaVersion >= 10 ? addDataSourceSaveAndTestButtonV10 : addDataSourceSaveAndTestButtonV9,
},

AddDashboard: {
add_new_panel_button: grafanaVersion >= 10 ? addNewPanelButtonV10 : addNewPanelButtonV9,
datasources_list: 'div[data-testid="data-sources-list"]',
},
};

export default Selectors;
2 changes: 1 addition & 1 deletion tests/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: '3'

services:
grafana:
image: grafana/grafana-oss:9.5.3-ubuntu
image: grafana/grafana-oss:latest
volumes:
- ../dist/:/var/lib/grafana/plugins/grafana-checkmk-datasource
environment:
Expand Down
2 changes: 1 addition & 1 deletion tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
"author": "",
"license": "GPL-2.0-only",
"devDependencies": {
"cypress": "^12.11.0"
"cypress": "13.3.3"
}
}
Loading
Loading