Skip to content

Commit

Permalink
[APM] e2e tests (elastic#99098) (elastic#99231)
Browse files Browse the repository at this point in the history
* adding e2e tests

* adding e2e tests

* adding e2e tests

* fixing ci

* fixing ci

* fixing e2e and jest

Co-authored-by: Cauê Marcondes <55978943+cauemarcondes@users.noreply.github.com>
  • Loading branch information
kibanamachine and cauemarcondes authored May 4, 2021
1 parent 078f3e0 commit 187d24b
Show file tree
Hide file tree
Showing 10 changed files with 322 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,45 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import url from 'url';
import archives_metadata from '../../fixtures/es_archiver/archives_metadata';
import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';

const { start, end } = archives_metadata['apm_8.0.0'];

const servicesPath = '/app/apm/services';
const baseUrl = url.format({
pathname: servicesPath,
query: { rangeFrom: start, rangeTo: end },
});

describe('Home page', () => {
before(() => {
esArchiverLoad('apm_8.0.0');
cy.loginAsReadOnlyUser();
});
after(() => {
esArchiverUnload('apm_8.0.0');
});
beforeEach(() => {
cy.loginAsReadOnlyUser();
});
it('Redirects to service page with rangeFrom and rangeTo added to the URL', () => {
const baseUrl = url.format({
pathname: '/app/apm',
query: { rangeFrom: start, rangeTo: end },
});
cy.visit('/app/apm');

cy.visit(baseUrl);
cy.url().should(
'include',
'app/apm/services?rangeFrom=now-15m&rangeTo=now'
);
cy.get('.euiTabs .euiTab-isSelected').contains('Services');
});

it('includes services with only metric documents', () => {
cy.visit(
`${baseUrl}&kuery=not%2520(processor.event%2520%253A%2522transaction%2522%2520)`
);
cy.contains('opbeans-python');
cy.contains('opbeans-java');
cy.contains('opbeans-node');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import url from 'url';
import archives_metadata from '../../../fixtures/es_archiver/archives_metadata';
import { esArchiverLoad, esArchiverUnload } from '../../../tasks/es_archiver';

const { start, end } = archives_metadata['apm_8.0.0'];

const serviceOverviewPath = '/app/apm/services/kibana/overview';
const baseUrl = url.format({
pathname: serviceOverviewPath,
query: { rangeFrom: start, rangeTo: end },
});

const apisToIntercept = [
{
endpoint: '/api/apm/services/kibana/transactions/charts/latency',
as: 'latencyChartRequest',
},
{
endpoint: '/api/apm/services/kibana/throughput',
as: 'throughputChartRequest',
},
{
endpoint: '/api/apm/services/kibana/transactions/charts/error_rate',
as: 'errorRateChartRequest',
},
{
endpoint:
'/api/apm/services/kibana/transactions/groups/detailed_statistics',
as: 'transactionGroupsDetailedRequest',
},
{
endpoint:
'/api/apm/services/kibana/service_overview_instances/detailed_statistics',
as: 'instancesDetailedRequest',
},
{
endpoint:
'/api/apm/services/kibana/service_overview_instances/main_statistics',
as: 'instancesMainStatisticsRequest',
},
{
endpoint: '/api/apm/services/kibana/error_groups/main_statistics',
as: 'errorGroupsMainStatisticsRequest',
},
{
endpoint: '/api/apm/services/kibana/transaction/charts/breakdown',
as: 'transactonBreakdownRequest',
},
{
endpoint: '/api/apm/services/kibana/transactions/groups/main_statistics',
as: 'transactionsGroupsMainStatisticsRequest',
},
];

describe('Service overview - header filters', () => {
before(() => {
esArchiverLoad('apm_8.0.0');
});
after(() => {
esArchiverUnload('apm_8.0.0');
});
beforeEach(() => {
cy.loginAsReadOnlyUser();
});
describe('Filtering by transaction type', () => {
it('changes url when selecting different value', () => {
cy.visit(baseUrl);
cy.contains('Kibana');
cy.url().should('not.include', 'transactionType');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'request'
);
cy.get('[data-test-subj="headerFilterTransactionType"]').select(
'taskManager'
);
cy.url().should('include', 'transactionType=taskManager');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'taskManager'
);
});

it('calls APIs with correct transaction type', () => {
apisToIntercept.map(({ endpoint, as }) => {
cy.intercept('GET', endpoint).as(as);
});
cy.visit(baseUrl);
cy.contains('Kibana');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'request'
);

cy.expectAPIsToHaveBeenCalledWith({
apisIntercepted: apisToIntercept.map(({ as }) => `@${as}`),
value: 'transactionType=request',
});

cy.get('[data-test-subj="headerFilterTransactionType"]').select(
'taskManager'
);
cy.url().should('include', 'transactionType=taskManager');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'taskManager'
);
cy.expectAPIsToHaveBeenCalledWith({
apisIntercepted: apisToIntercept.map(({ as }) => `@${as}`),
value: 'transactionType=taskManager',
});
});
});

describe('Filtering by kuerybar', () => {
it('filters by transaction.name', () => {
cy.visit(
url.format({
pathname: '/app/apm/services/opbeans-java/overview',
query: { rangeFrom: start, rangeTo: end },
})
);
cy.contains('opbeans-java');
cy.get('[data-test-subj="headerFilterKuerybar"]').type('transaction.n');
cy.contains('transaction.name');
cy.get('[data-test-subj="suggestionContainer"]')
.find('li')
.first()
.click();
cy.get('[data-test-subj="headerFilterKuerybar"]').type(':');
cy.get('[data-test-subj="suggestionContainer"]')
.find('li')
.first()
.click();
cy.get('[data-test-subj="suggestionContainer"]').realPress('{enter}');
cy.url().should('include', '&kuery=transaction.name');
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import url from 'url';
import archives_metadata from '../../../fixtures/es_archiver/archives_metadata';
import { esArchiverLoad, esArchiverUnload } from '../../../tasks/es_archiver';

const { start, end } = archives_metadata['apm_8.0.0'];

const serviceOverviewPath = '/app/apm/services/opbeans-java/overview';
const baseUrl = url.format({
pathname: serviceOverviewPath,
query: { rangeFrom: start, rangeTo: end },
});

const apisToIntercept = [
{
endpoint:
'/api/apm/services/opbeans-java/service_overview_instances/main_statistics',
as: 'instancesMainRequest',
},
{
endpoint:
'/api/apm/services/opbeans-java/service_overview_instances/detailed_statistics',
as: 'instancesDetailsRequest',
},
{
endpoint:
'/api/apm/services/opbeans-java/service_overview_instances/details/02950c4c5fbb0fda1cc98c47bf4024b473a8a17629db6530d95dcee68bd54c6c',
as: 'instanceDetailsRequest',
},
{
endpoint:
'/api/apm/services/opbeans-java/service_overview_instances/details/02950c4c5fbb0fda1cc98c47bf4024b473a8a17629db6530d95dcee68bd54c6c',
as: 'instanceDetailsRequest',
},
];

describe('Instances table', () => {
beforeEach(() => {
cy.loginAsReadOnlyUser();
});
describe('when data is not loaded', () => {
it('shows empty message', () => {
cy.visit(baseUrl);
cy.contains('opbeans-java');
cy.get('[data-test-subj="serviceInstancesTableContainer"]').contains(
'No items found'
);
});
});

describe('when data is loaded', () => {
before(() => {
esArchiverLoad('apm_8.0.0');
});
after(() => {
esArchiverUnload('apm_8.0.0');
});
const serviceNodeName =
'02950c4c5fbb0fda1cc98c47bf4024b473a8a17629db6530d95dcee68bd54c6c';
it('has data in the table', () => {
cy.visit(baseUrl);
cy.contains('opbeans-java');
cy.contains(serviceNodeName);
});
it('shows instance details', () => {
apisToIntercept.map(({ endpoint, as }) => {
cy.intercept('GET', endpoint).as(as);
});

cy.visit(baseUrl);
cy.contains('opbeans-java');

cy.wait('@instancesMainRequest');
cy.contains(serviceNodeName);

cy.wait('@instancesDetailsRequest');
cy.get(
`[data-test-subj="instanceDetailsButton_${serviceNodeName}"]`
).realClick();
cy.get('[data-test-subj="loadingSpinner"]').should('be.visible');
cy.wait('@instanceDetailsRequest').then(() => {
cy.contains('Service');
});
});
it('shows actions available', () => {
apisToIntercept.map(({ endpoint, as }) => {
cy.intercept('GET', endpoint).as(as);
});

cy.visit(baseUrl);
cy.contains('opbeans-java');

cy.wait('@instancesMainRequest');
cy.contains(serviceNodeName);

cy.wait('@instancesDetailsRequest');
cy.get(
`[data-test-subj="instanceActionsButton_${serviceNodeName}"]`
).realClick();
cy.contains('Pod logs');
cy.contains('Pod metrics');
cy.contains('Container logs');
cy.contains('Container metrics');
cy.contains('Filter overview by instance');
cy.contains('Metrics');
});
});
});
22 changes: 22 additions & 0 deletions x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/
import 'cypress-real-events/support';
import { Interception } from 'cypress/types/net-stubbing';

Cypress.Commands.add('loginAsReadOnlyUser', () => {
cy.loginAs({ username: 'apm_read_user', password: 'changeme' });
Expand Down Expand Up @@ -39,3 +40,24 @@ Cypress.Commands.add('changeTimeRange', (value: string) => {
cy.get('[data-test-subj="superDatePickerToggleQuickMenuButton"]').click();
cy.contains(value).click();
});

Cypress.Commands.add(
'expectAPIsToHaveBeenCalledWith',
({
apisIntercepted,
value,
}: {
apisIntercepted: string[];
value: string;
}) => {
cy.wait(apisIntercepted).then((interceptions) => {
if (Array.isArray(interceptions)) {
interceptions.map((interception) => {
expect(interception.request.url).include(value);
});
} else {
expect((interceptions as Interception).request.url).include(value);
}
});
}
);
4 changes: 4 additions & 0 deletions x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@ declare namespace Cypress {
loginAsSuperUser(): void;
loginAs(params: { username: string; password: string }): void;
changeTimeRange(value: string): void;
expectAPIsToHaveBeenCalledWith(params: {
apisIntercepted: string[];
value: string;
}): void;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ export function getColumns({
anchorPosition="leftCenter"
button={
<EuiButtonIcon
data-test-subj={`instanceActionsButton_${instanceItem.serviceNodeName}`}
iconType="boxesHorizontal"
onClick={() =>
toggleRowActionMenu(instanceItem.serviceNodeName)
Expand All @@ -257,6 +258,7 @@ export function getColumns({
render: (instanceItem: MainStatsServiceInstanceItem) => {
return (
<EuiButtonIcon
data-test-subj={`instanceDetailsButton_${instanceItem.serviceNodeName}`}
onClick={() => toggleRowDetails(instanceItem.serviceNodeName)}
aria-label={
itemIdToExpandedRowMap[instanceItem.serviceNodeName]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,13 @@ export function ServiceOverviewInstancesTable({
</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexItem data-test-subj="serviceInstancesTableContainer">
<TableFetchWrapper status={status}>
<ServiceOverviewTableContainer
isEmptyAndLoading={mainStatsItemCount === 0 && isLoading}
>
<EuiBasicTable
data-test-subj="instancesTable"
loading={isLoading}
items={mainStatsItems}
columns={columns}
Expand Down
Loading

0 comments on commit 187d24b

Please sign in to comment.