[APM] Improve Cypress tests with sessions and better async handling (#139278)

This commit is contained in:
Søren Louv-Jansen 2022-08-23 20:56:55 +02:00 committed by GitHub
parent 6f0bfcfd0d
commit 50821db39c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 324 additions and 289 deletions

View file

@ -6,11 +6,14 @@
"screenshotsFolder": "./cypress/screenshots",
"supportFile": "./cypress/support/index.ts",
"videosFolder": "./cypress/videos",
"requestTimeout": 10000,
"responseTimeout": 40000,
"defaultCommandTimeout": 30000,
"execTimeout": 120000,
"pageLoadTimeout": 120000,
"viewportHeight": 900,
"viewportWidth": 1440,
"video": false,
"screenshotOnRunFailure": false
"screenshotOnRunFailure": false,
"experimentalSessionAndOrigin": true
}

View file

@ -10,9 +10,9 @@ import { opbeans } from '../../../fixtures/synthtrace/opbeans';
const start = '2021-10-10T00:00:00.000Z';
const end = '2021-10-10T00:15:00.000Z';
describe.skip('Comparison feature flag', () => {
before(async () => {
await synthtrace.index(
describe('Comparison feature flag', () => {
before(() => {
synthtrace.index(
opbeans({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -20,29 +20,33 @@ describe.skip('Comparison feature flag', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
describe('when comparison feature is enabled', () => {
beforeEach(() => {
cy.loginAsEditorUser();
cy.updateAdvancedSettings({
'observability:enableComparisonByDefault': true,
});
});
it('shows the comparison feature enabled in services overview', () => {
cy.visit('/app/apm/services');
cy.visitKibana('/app/apm/services');
cy.get('input[type="checkbox"]#comparison').should('be.checked');
cy.get('[data-test-subj="comparisonSelect"]').should('not.be.disabled');
});
it('shows the comparison feature enabled in services overview', () => {
cy.visit('/app/apm/dependencies');
it('shows the comparison feature enabled in dependencies overview', () => {
cy.visitKibana('/app/apm/dependencies');
cy.get('input[type="checkbox"]#comparison').should('be.checked');
cy.get('[data-test-subj="comparisonSelect"]').should('not.be.disabled');
});
it('shows the comparison feature disabled in service map overview page', () => {
cy.visit('/app/apm/service-map');
cy.visitKibana('/app/apm/service-map');
cy.get('input[type="checkbox"]#comparison').should('be.checked');
cy.get('[data-test-subj="comparisonSelect"]').should('not.be.disabled');
});
@ -50,11 +54,11 @@ describe.skip('Comparison feature flag', () => {
describe('when comparison feature is disabled', () => {
beforeEach(() => {
cy.loginAsEditorUser().then(() => {
// Disables comparison feature on advanced settings
cy.updateAdvancedSettings({
'observability:enableComparisonByDefault': false,
});
cy.loginAsEditorUser();
// Disables comparison feature on advanced settings
cy.updateAdvancedSettings({
'observability:enableComparisonByDefault': false,
});
});
@ -65,7 +69,7 @@ describe.skip('Comparison feature flag', () => {
});
it('shows the comparison feature disabled in services overview', () => {
cy.visit('/app/apm/services');
cy.visitKibana('/app/apm/services');
cy.get('input[type="checkbox"]#comparison').should('not.be.checked');
cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled');
});
@ -74,14 +78,14 @@ describe.skip('Comparison feature flag', () => {
cy.intercept('GET', '/internal/apm/dependencies/top_dependencies?*').as(
'topDependenciesRequest'
);
cy.visit('/app/apm/dependencies');
cy.wait('@topDependenciesRequest', { requestTimeout: 10000 });
cy.visitKibana('/app/apm/dependencies');
cy.wait('@topDependenciesRequest');
cy.get('input[type="checkbox"]#comparison').should('not.be.checked');
cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled');
});
it('shows the comparison feature disabled in service map overview page', () => {
cy.visit('/app/apm/service-map');
cy.visitKibana('/app/apm/service-map');
cy.get('input[type="checkbox"]#comparison').should('not.be.checked');
cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled');
});

View file

@ -27,9 +27,9 @@ const nodeServiceInfraPageHref = url.format({
query: { rangeFrom: start, rangeTo: end },
});
describe.skip('Infrastructure page', () => {
before(async () => {
await synthtrace.index(
describe('Infrastructure page', () => {
before(() => {
synthtrace.index(
generateData({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -37,8 +37,8 @@ describe.skip('Infrastructure page', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
beforeEach(() => {
@ -47,7 +47,7 @@ describe.skip('Infrastructure page', () => {
describe('when data is loaded', () => {
it('has no detectable a11y violations on load', () => {
cy.visit(goServiceInfraPageHref);
cy.visitKibana(goServiceInfraPageHref);
cy.contains('Infrastructure');
// set skipFailures to true to not fail the test when there are accessibility failures
checkA11y({ skipFailures: true });
@ -55,7 +55,7 @@ describe.skip('Infrastructure page', () => {
describe('when container ids, pod names and host names are returned by the api call', () => {
it('shows all tabs', () => {
cy.visit(goServiceInfraPageHref);
cy.visitKibana(goServiceInfraPageHref);
cy.contains('Containers');
cy.contains('Pods');
cy.contains('Hosts');
@ -64,14 +64,14 @@ describe.skip('Infrastructure page', () => {
describe('when only host names are returned by the api call', () => {
it('shows only Hosts tab', () => {
cy.visit(javaServiceInfraPageHref);
cy.visitKibana(javaServiceInfraPageHref);
cy.contains('Hosts');
});
});
describe('when none infrastructure attributes are returned by the api call', () => {
it('shows no data message', () => {
cy.visit(nodeServiceInfraPageHref);
cy.visitKibana(nodeServiceInfraPageHref);
cy.contains('No results match your search criteria.');
});
});

View file

@ -57,7 +57,7 @@ describe.skip('when navigating to integration page', () => {
const integrationsPath = '/app/integrations/browse';
cy.loginAsEditorUser();
cy.visit(integrationsPath);
cy.visitKibana(integrationsPath);
// open integration policy form
cy.get('[data-test-subj="integration-card:epr:apm:featured').click();
@ -79,17 +79,17 @@ describe.skip('when navigating to integration page', () => {
});
it('should display Tail-based section on latest version', () => {
cy.visit('/app/fleet/integrations/apm/add-integration');
cy.visitKibana('/app/fleet/integrations/apm/add-integration');
cy.contains('Tail-based sampling').should('exist');
});
it('should hide Tail-based section for 8.0.0 apm package', () => {
cy.visit('/app/fleet/integrations/apm-8.0.0/add-integration');
cy.visitKibana('/app/fleet/integrations/apm-8.0.0/add-integration');
cy.contains('Tail-based sampling').should('not.exist');
});
it('should Display Debug section', () => {
cy.visit('/app/fleet/integrations/apm-8.0.0/add-integration');
cy.visitKibana('/app/fleet/integrations/apm-8.0.0/add-integration');
cy.contains('Debug settings').should('exist');
});
});

View file

@ -5,60 +5,55 @@
* 2.0.
*/
const apmIndicesSaveURL = '/internal/apm/settings/apm-indices/save';
describe('No data screen', () => {
describe('bypass no data screen on settings pages', () => {
before(() => {
// Change indices
setApmIndices({
sourcemap: 'foo-*',
error: 'foo-*',
onboarding: 'foo-*',
span: 'foo-*',
transaction: 'foo-*',
metric: 'foo-*',
});
});
beforeEach(() => {
cy.loginAsEditorUser();
});
before(() => {
// Change default indices
cy.request({
url: apmIndicesSaveURL,
method: 'POST',
body: {
sourcemap: 'foo-*',
error: 'foo-*',
onboarding: 'foo-*',
span: 'foo-*',
transaction: 'foo-*',
metric: 'foo-*',
},
headers: {
'kbn-xsrf': true,
},
auth: { user: 'editor', pass: 'changeme' },
});
});
it('shows no data screen instead of service inventory', () => {
cy.visit('/app/apm/');
cy.visitKibana('/app/apm/');
cy.contains('Welcome to Elastic Observability!');
});
it('shows settings page', () => {
cy.visit('/app/apm/settings');
cy.visitKibana('/app/apm/settings');
cy.contains('Welcome to Elastic Observability!').should('not.exist');
cy.get('h1').contains('Settings');
});
after(() => {
// reset to default indices
cy.request({
url: apmIndicesSaveURL,
method: 'POST',
body: {
sourcemap: '',
error: '',
onboarding: '',
span: '',
transaction: '',
metric: '',
},
headers: { 'kbn-xsrf': true },
auth: { user: 'editor', pass: 'changeme' },
setApmIndices({
sourcemap: '',
error: '',
onboarding: '',
span: '',
transaction: '',
metric: '',
});
});
});
});
function setApmIndices(body: Record<string, string>) {
cy.request({
url: '/internal/apm/settings/apm-indices/save',
method: 'POST',
body,
headers: { 'kbn-xsrf': true },
auth: { user: 'editor', pass: 'changeme' },
});
}

View file

@ -6,10 +6,12 @@
*/
function deleteAllRules() {
cy.log('Delete all rules');
cy.request({
log: false,
method: 'GET',
url: '/api/alerting/rules/_find',
auth: { user: 'editor', pass: 'changeme' },
}).then(({ body }) => {
if (body.data.length > 0) {
cy.log(`Deleting rules`);
@ -21,12 +23,21 @@ function deleteAllRules() {
log: false,
method: 'DELETE',
url: `/api/alerting/rule/${id}`,
auth: { user: 'editor', pass: 'changeme' },
});
});
});
}
describe('Rules', () => {
beforeEach(() => {
deleteAllRules();
});
after(() => {
deleteAllRules();
});
describe('Error count', () => {
const ruleName = 'Error count threshold';
const comboBoxInputSelector =
@ -36,18 +47,11 @@ describe('Rules', () => {
describe('when created from APM', () => {
describe('when created from Service Inventory', () => {
before(() => {
cy.loginAsEditorUser();
deleteAllRules();
});
after(() => {
deleteAllRules();
});
it('creates a rule', () => {
cy.loginAsEditorUser();
// Create a rule in APM
cy.visit('/app/apm/services');
cy.visitKibana('/app/apm/services');
cy.contains('Alerts and rules').click();
cy.contains('Create error count rule').click();
@ -67,18 +71,13 @@ describe('Rules', () => {
});
describe('when created from Stack management', () => {
before(() => {
cy.loginAsEditorUser();
deleteAllRules();
});
after(() => {
deleteAllRules();
});
it('creates a rule', () => {
cy.loginAsEditorUser();
// Go to stack management
cy.visit('/app/management/insightsAndAlerting/triggersActions/rules');
cy.visitKibana(
'/app/management/insightsAndAlerting/triggersActions/rules'
);
// Create a rule
cy.contains('button', 'Create rule').click();

View file

@ -55,10 +55,10 @@ function generateData({
}
describe('Agent configuration', () => {
before(async () => {
before(() => {
const { rangeFrom, rangeTo } = timeRange;
await synthtrace.index(
synthtrace.index(
generateData({
from: new Date(rangeFrom).getTime(),
to: new Date(rangeTo).getTime(),
@ -67,13 +67,13 @@ describe('Agent configuration', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
beforeEach(() => {
cy.loginAsEditorUser();
cy.visit(agentConfigHref);
cy.visitKibana(agentConfigHref);
});
it('persists service enviroment when clicking on edit button', () => {

View file

@ -13,13 +13,13 @@ describe('Custom links', () => {
});
it('shows empty message and create button', () => {
cy.visit(basePath);
cy.visitKibana(basePath);
cy.contains('No links found');
cy.contains('Create custom link');
});
it('creates custom link', () => {
cy.visit(basePath);
cy.visitKibana(basePath);
const emptyPrompt = cy.get('[data-test-subj="customLinksEmptyPrompt"]');
cy.contains('Create custom link').click();
cy.contains('Create link');
@ -36,7 +36,7 @@ describe('Custom links', () => {
});
it('clears filter values when field is selected', () => {
cy.visit(basePath);
cy.visitKibana(basePath);
cy.contains('Create custom link').click();
cy.get('[data-test-subj="filter-0"]').select('service.name');
cy.get(

View file

@ -6,11 +6,11 @@
*/
describe('APM deep links', () => {
before(() => {
beforeEach(() => {
cy.loginAsViewerUser();
});
it('navigates to apm links on search elastic', () => {
cy.visit('/');
cy.visitKibana('/');
cy.get('[data-test-subj="nav-search-input"]').type('APM');
cy.contains('APM');
cy.contains('APM / Services');

View file

@ -17,8 +17,8 @@ const timeRange = {
};
describe.skip('Dependencies', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
opbeans({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -26,8 +26,8 @@ describe.skip('Dependencies', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
beforeEach(() => {
@ -36,7 +36,7 @@ describe.skip('Dependencies', () => {
describe('top-level dependencies page', () => {
it('has a list of dependencies and you can navigate to the page for one', () => {
cy.visit(`/app/apm/services?${new URLSearchParams(timeRange)}`);
cy.visitKibana(`/app/apm/services?${new URLSearchParams(timeRange)}`);
cy.contains('nav a', 'Dependencies').click();
// `force: true` because Cypress says the element is 0x0
@ -46,7 +46,7 @@ describe.skip('Dependencies', () => {
});
it('has no detectable a11y violations on load', () => {
cy.visit(
cy.visitKibana(
`/app/apm/services/opbeans-java/dependencies?${new URLSearchParams(
timeRange
)}`
@ -59,7 +59,7 @@ describe.skip('Dependencies', () => {
describe.skip('dependency overview page', () => {
it('shows dependency information and you can navigate to a page for an upstream service', () => {
cy.visit(
cy.visitKibana(
`/app/apm/dependencies/overview?${new URLSearchParams({
...timeRange,
dependencyName: 'postgresql',
@ -76,7 +76,7 @@ describe.skip('Dependencies', () => {
});
it('has no detectable a11y violations on load', () => {
cy.visit(
cy.visitKibana(
`/app/apm/dependencies/overview?${new URLSearchParams({
...timeRange,
dependencyName: 'postgresql',
@ -90,7 +90,7 @@ describe.skip('Dependencies', () => {
describe('service overview page', () => {
it('shows dependency information and you can navigate to a page for a dependency', () => {
cy.visit(
cy.visitKibana(
`/app/apm/services/opbeans-java/overview?${new URLSearchParams(
timeRange
)}`
@ -104,7 +104,7 @@ describe.skip('Dependencies', () => {
describe('service dependencies tab', () => {
it('shows dependency information and you can navigate to a page for a dependency', () => {
cy.visit(
cy.visitKibana(
`/app/apm/services/opbeans-java/overview?${new URLSearchParams(
timeRange
)}`

View file

@ -27,8 +27,8 @@ describe('Error details', () => {
});
describe('when data is loaded', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
generateData({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -36,12 +36,12 @@ describe('Error details', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
it('has no detectable a11y violations on load', () => {
cy.visit(errorDetailsPageHref);
cy.visitKibana(errorDetailsPageHref);
cy.contains('Error group 00000');
// set skipFailures to true to not fail the test when there are accessibility failures
checkA11y({ skipFailures: true });
@ -49,7 +49,7 @@ describe('Error details', () => {
describe('when error has no occurrences', () => {
it('shows an empty message', () => {
cy.visit(
cy.visitKibana(
url.format({
pathname:
'/app/apm/services/opbeans-java/errors/0000000000000000000000000Error%201',
@ -66,13 +66,13 @@ describe('Error details', () => {
describe('when error has data', () => {
it('shows errors distribution chart', () => {
cy.visit(errorDetailsPageHref);
cy.visitKibana(errorDetailsPageHref);
cy.contains('Error group 00000');
cy.get('[data-test-subj="errorDistribution"]').contains('Occurrences');
});
it('shows top erroneous transactions table', () => {
cy.visit(errorDetailsPageHref);
cy.visitKibana(errorDetailsPageHref);
cy.contains('Top 5 affected transactions');
cy.get('[data-test-subj="topErroneousTransactionsTable"]')
.contains('a', 'GET /apple 🍎')
@ -81,14 +81,14 @@ describe('Error details', () => {
});
it('shows a Stacktrace and Metadata tabs', () => {
cy.visit(errorDetailsPageHref);
cy.visitKibana(errorDetailsPageHref);
cy.contains('button', 'Exception stack trace');
cy.contains('button', 'Metadata');
});
describe('when clicking on related transaction sample', () => {
it('should redirects to the transaction details page', () => {
cy.visit(errorDetailsPageHref);
cy.visitKibana(errorDetailsPageHref);
cy.contains('Error group 00000');
cy.contains('a', 'GET /apple 🍎').click();
cy.url().should('include', 'opbeans-java/transactions/view');
@ -97,7 +97,7 @@ describe('Error details', () => {
describe('when clicking on View x occurences in discover', () => {
it.skip('should redirects the user to discover', () => {
cy.visit(errorDetailsPageHref);
cy.visitKibana(errorDetailsPageHref);
cy.contains('View 1 occurrence in Discover').click();
cy.url().should('include', 'app/discover');
});

View file

@ -29,8 +29,8 @@ describe('Errors page', () => {
});
describe('when data is loaded', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
generateData({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -38,12 +38,12 @@ describe('Errors page', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
it('has no detectable a11y violations on load', () => {
cy.visit(javaServiceErrorsPageHref);
cy.visitKibana(javaServiceErrorsPageHref);
cy.contains('Error occurrences');
// set skipFailures to true to not fail the test when there are accessibility failures
checkA11y({ skipFailures: true });
@ -51,7 +51,7 @@ describe('Errors page', () => {
describe('when service has no errors', () => {
it('shows empty message', () => {
cy.visit(nodeServiceErrorsPageHref);
cy.visitKibana(nodeServiceErrorsPageHref);
cy.contains('opbeans-node');
cy.contains('No errors found');
});
@ -59,28 +59,28 @@ describe('Errors page', () => {
describe('when service has errors', () => {
it('shows errors distribution chart', () => {
cy.visit(javaServiceErrorsPageHref);
cy.visitKibana(javaServiceErrorsPageHref);
cy.contains('Error occurrences');
});
it('shows failed transaction rate chart', () => {
cy.visit(javaServiceErrorsPageHref);
cy.visitKibana(javaServiceErrorsPageHref);
cy.contains('Failed transaction rate');
});
it('errors table is populated', () => {
cy.visit(javaServiceErrorsPageHref);
cy.visitKibana(javaServiceErrorsPageHref);
cy.contains('Error 0');
});
it('clicking on an error in the list navigates to error detail page', () => {
cy.visit(javaServiceErrorsPageHref);
cy.visitKibana(javaServiceErrorsPageHref);
cy.contains('a', 'Error 1').click();
cy.contains('div', 'Error 1');
});
it('clicking on type adds a filter in the kuerybar', () => {
cy.visit(javaServiceErrorsPageHref);
cy.visitKibana(javaServiceErrorsPageHref);
cy.get('[data-test-subj="headerFilterKuerybar"]')
.invoke('val')
.should('be.empty');
@ -97,13 +97,13 @@ describe('Errors page', () => {
});
it('sorts by ocurrences', () => {
cy.visit(javaServiceErrorsPageHref);
cy.visitKibana(javaServiceErrorsPageHref);
cy.contains('span', 'Occurrences').click();
cy.url().should('include', '&sortField=occurrences&sortDirection=asc');
});
it('sorts by latest occurrences', () => {
cy.visit(javaServiceErrorsPageHref);
cy.visitKibana(javaServiceErrorsPageHref);
cy.contains('span', 'Last seen').click();
cy.url().should('include', '&sortField=lastSeen&sortDirection=asc');
});
@ -112,9 +112,8 @@ describe('Errors page', () => {
});
describe('Check detailed statistics API with multiple errors', () => {
before(async () => {
cy.loginAsViewerUser();
await synthtrace.index(
before(() => {
synthtrace.index(
generateErrors({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -123,8 +122,12 @@ describe('Check detailed statistics API with multiple errors', () => {
);
});
after(async () => {
await synthtrace.clean();
beforeEach(() => {
cy.loginAsViewerUser();
});
after(() => {
synthtrace.clean();
});
it('calls detailed API with visible items only', () => {
@ -136,7 +139,7 @@ describe('Check detailed statistics API with multiple errors', () => {
'POST',
'/internal/apm/services/opbeans-java/errors/groups/detailed_statistics?*'
).as('errorsDetailedStatistics');
cy.visit(`${javaServiceErrorsPageHref}&pageSize=10`);
cy.visitKibana(`${javaServiceErrorsPageHref}&pageSize=10`);
cy.wait('@errorsMainStatistics');
cy.get('.euiPagination__list').children().should('have.length', 5);
cy.wait('@errorsDetailedStatistics').then((payload) => {

View file

@ -24,8 +24,8 @@ const serviceInventoryHref = url.format({
});
describe.skip('Home page', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
opbeans({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -33,8 +33,8 @@ describe.skip('Home page', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
beforeEach(() => {
@ -42,7 +42,7 @@ describe.skip('Home page', () => {
});
it('Redirects to service page with comparisonEnabled, environment, rangeFrom, rangeTo and offset added to the URL', () => {
cy.visit('/app/apm');
cy.visitKibana('/app/apm');
cy.url().should(
'include',
@ -51,7 +51,7 @@ describe.skip('Home page', () => {
});
it('includes services with only metric documents', () => {
cy.visit(
cy.visitKibana(
`${serviceInventoryHref}&kuery=not%20(processor.event%3A%22transaction%22)`
);
cy.contains('opbeans-java');
@ -60,7 +60,7 @@ describe.skip('Home page', () => {
describe('navigations', () => {
it('navigates to service overview page with transaction type', () => {
cy.visit(serviceInventoryHref);
cy.visitKibana(serviceInventoryHref);
cy.contains('Services');
cy.contains('opbeans-rum').click({ force: true });

View file

@ -20,8 +20,8 @@ const specialServiceName =
'service 1 / ? # [ ] @ ! $ & ( ) * + , ; = < > % {} | ^ ` <>';
describe('Service inventory - header filters', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
generateData({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -30,8 +30,8 @@ describe('Service inventory - header filters', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
beforeEach(() => {
@ -40,7 +40,7 @@ describe('Service inventory - header filters', () => {
describe('Filtering by kuerybar', () => {
it('filters by service.name with special characters', () => {
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.contains('Services');
cy.contains('opbeans-node');
cy.contains('service 1');

View file

@ -44,12 +44,9 @@ const mainAliasNames = mainApiRequestsToIntercept.map(
);
describe('When navigating to the service inventory', () => {
before(async () => {
cy.loginAsViewerUser();
cy.visit(serviceInventoryHref);
before(() => {
const { rangeFrom, rangeTo } = timeRange;
await synthtrace.index(
synthtrace.index(
opbeans({
from: new Date(rangeFrom).getTime(),
to: new Date(rangeTo).getTime(),
@ -57,8 +54,13 @@ describe('When navigating to the service inventory', () => {
);
});
after(async () => {
await synthtrace.clean();
beforeEach(() => {
cy.loginAsViewerUser();
cy.visitKibana(serviceInventoryHref);
});
after(() => {
synthtrace.clean();
});
it('has no detectable a11y violations on load', () => {
@ -92,7 +94,7 @@ describe('When navigating to the service inventory', () => {
);
cy.loginAsViewerUser();
cy.visit(serviceInventoryHref);
cy.visitKibana(serviceInventoryHref);
});
it('with the correct environment when changing the environment', () => {
@ -135,11 +137,9 @@ describe('When navigating to the service inventory', () => {
});
describe('Check detailed statistics API with multiple services', () => {
before(async () => {
cy.loginAsViewerUser();
before(() => {
const { rangeFrom, rangeTo } = timeRange;
await synthtrace.index(
synthtrace.index(
generateMultipleServicesData({
from: new Date(rangeFrom).getTime(),
to: new Date(rangeTo).getTime(),
@ -147,8 +147,12 @@ describe('Check detailed statistics API with multiple services', () => {
);
});
after(async () => {
await synthtrace.clean();
beforeEach(() => {
cy.loginAsViewerUser();
});
after(() => {
synthtrace.clean();
});
it('calls detailed API with visible items only', () => {
@ -157,7 +161,7 @@ describe('Check detailed statistics API with multiple services', () => {
);
cy.intercept('GET', '/internal/apm/services?*').as('mainStatisticsRequest');
cy.visit(
cy.visitKibana(
`${serviceInventoryHref}&pageSize=10&sortField=serviceName&sortDirection=asc`
);
cy.wait('@mainStatisticsRequest');

View file

@ -23,8 +23,8 @@ const apiToIntercept = {
};
describe('Service overview - aws lambda', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
generateData({
start: new Date(start).getTime(),
end: new Date(end).getTime(),
@ -32,19 +32,16 @@ describe('Service overview - aws lambda', () => {
);
});
after(async () => {
await synthtrace.clean();
});
beforeEach(() => {
cy.loginAsViewerUser();
after(() => {
synthtrace.clean();
});
it('displays a cold start rate chart and not a transaction breakdown chart', () => {
const { endpoint, name } = apiToIntercept;
cy.intercept('GET', endpoint).as(name);
cy.visit(serviceOverviewHref);
cy.loginAsViewerUser();
cy.visitKibana(serviceOverviewHref);
cy.wait(`@${name}`);
cy.contains('Cold start rate');

View file

@ -18,8 +18,8 @@ const serviceOverviewHref = url.format({
});
describe('Errors table', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
opbeans({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -27,8 +27,8 @@ describe('Errors table', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
beforeEach(() => {
@ -36,20 +36,20 @@ describe('Errors table', () => {
});
it('errors table is populated', () => {
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.contains('opbeans-java');
cy.contains('[MockError] Foo');
});
it('navigates to the errors page', () => {
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.contains('opbeans-java');
cy.contains('a', 'View errors').click();
cy.url().should('include', '/opbeans-java/errors');
});
it('clicking on type adds a filter in the kuerybar and navigates to errors page', () => {
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.get('[data-test-subj="headerFilterKuerybar"]')
.invoke('val')
.should('be.empty');
@ -64,7 +64,7 @@ describe('Errors table', () => {
});
it('navigates to error detail page', () => {
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.contains('a', '[MockError] Foo').click();
cy.contains('div', 'Exception message');
});

View file

@ -59,14 +59,14 @@ const apisToIntercept = [
];
describe('Service overview - header filters', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime() })
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
describe('Filtering by transaction type', () => {
@ -74,7 +74,7 @@ describe('Service overview - header filters', () => {
cy.loginAsViewerUser();
});
it('changes url when selecting different value', () => {
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.contains('opbeans-node');
cy.url().should('not.include', 'transactionType');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
@ -93,7 +93,7 @@ describe('Service overview - header filters', () => {
apisToIntercept.map(({ endpoint, name }) => {
cy.intercept('GET', endpoint).as(name);
});
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'request'
@ -122,7 +122,7 @@ describe('Service overview - header filters', () => {
cy.loginAsViewerUser();
});
it('filters by transaction.name', () => {
cy.visit(
cy.visitKibana(
url.format({
pathname: '/app/apm/services/opbeans-java/overview',
query: { rangeFrom: start, rangeTo: end },

View file

@ -41,19 +41,19 @@ describe('Instances table', () => {
cy.loginAsViewerUser();
});
// describe('when data is not loaded', () => {
// it('shows empty message', () => {
// cy.visit(serviceOverviewHref);
// cy.contains('opbeans-java');
// cy.get('[data-test-subj="serviceInstancesTableContainer"]').contains(
// 'No items found'
// );
// });
// });
describe.skip('when data is not loaded', () => {
it('shows empty message', () => {
cy.visitKibana(serviceOverviewHref);
cy.contains('opbeans-java');
cy.get('[data-test-subj="serviceInstancesTableContainer"]').contains(
'No items found'
);
});
});
describe('when data is loaded', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
opbeans({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -61,12 +61,12 @@ describe('Instances table', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
it('has data in the table', () => {
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.contains('opbeans-java');
cy.contains(serviceNodeName);
});
@ -75,7 +75,7 @@ describe('Instances table', () => {
cy.intercept('GET', endpoint).as(name);
});
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.contains('opbeans-java');
cy.wait('@instancesMainRequest');
@ -96,7 +96,7 @@ describe('Instances table', () => {
cy.intercept('GET', endpoint).as(name);
});
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.contains('opbeans-java');
cy.wait('@instancesMainRequest');

View file

@ -86,8 +86,8 @@ const aliasNamesWithComparison = apiRequestsToInterceptWithComparison.map(
const aliasNames = [...aliasNamesNoComparison, ...aliasNamesWithComparison];
describe('Service Overview', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
opbeans({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -95,14 +95,14 @@ describe('Service Overview', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
describe('renders', () => {
before(() => {
beforeEach(() => {
cy.loginAsViewerUser();
cy.visit(baseUrl);
cy.visitKibana(baseUrl);
});
it('renders all components on the page', () => {
@ -122,7 +122,6 @@ describe('Service Overview', () => {
describe('transactions', () => {
beforeEach(() => {
cy.loginAsViewerUser();
cy.visit(baseUrl);
});
it('persists transaction type selected when clicking on Transactions tab', () => {
@ -130,6 +129,9 @@ describe('Service Overview', () => {
'GET',
'/internal/apm/services/opbeans-node/transaction_types?*'
).as('transactionTypesRequest');
cy.visitKibana(baseUrl);
cy.wait('@transactionTypesRequest');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
@ -148,11 +150,14 @@ describe('Service Overview', () => {
);
});
it.skip('persists transaction type selected when clicking on View Transactions link', () => {
it('persists transaction type selected when clicking on View Transactions link', () => {
cy.intercept(
'GET',
'/internal/apm/services/opbeans-node/transaction_types?*'
).as('transactionTypesRequest');
cy.visitKibana(baseUrl);
cy.wait('@transactionTypesRequest');
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
@ -173,20 +178,20 @@ describe('Service Overview', () => {
});
describe('when RUM service', () => {
before(() => {
it('hides dependency tab when RUM service', () => {
cy.loginAsViewerUser();
cy.visit(
cy.intercept('GET', '/internal/apm/services/opbeans-rum/agent?*').as(
'agentRequest'
);
cy.visitKibana(
url.format({
pathname: '/app/apm/services/opbeans-rum/overview',
query: { rangeFrom: start, rangeTo: end },
})
);
});
it('hides dependency tab when RUM service', () => {
cy.intercept('GET', '/internal/apm/services/opbeans-rum/agent?*').as(
'agentRequest'
);
cy.contains('Overview');
cy.contains('Transactions');
cy.contains('Error');
@ -204,17 +209,18 @@ describe('Service Overview', () => {
describe('Calls APIs', () => {
beforeEach(() => {
cy.loginAsViewerUser();
cy.visit(baseUrl);
apiRequestsToIntercept.map(({ endpoint, aliasName }) => {
cy.intercept('GET', endpoint).as(aliasName);
});
apiRequestsToInterceptWithComparison.map(({ endpoint, aliasName }) => {
cy.intercept('GET', endpoint).as(aliasName);
});
cy.visitKibana(baseUrl);
});
it.skip('with the correct environment when changing the environment', () => {
cy.wait(aliasNames, { requestTimeout: 10000 });
cy.wait(aliasNames);
cy.intercept('GET', 'internal/apm/suggestions?*').as(
'suggestionsRequest'
@ -241,11 +247,11 @@ describe('Service Overview', () => {
it('when clicking the refresh button', () => {
cy.contains('Refresh').click();
cy.wait(aliasNames, { requestTimeout: 10000 });
cy.wait(aliasNames);
});
it.skip('when selecting a different time range and clicking the update button', () => {
cy.wait(aliasNames, { requestTimeout: 10000 });
cy.wait(aliasNames);
const timeStart = moment(start).subtract(5, 'm').toISOString();
const timeEnd = moment(end).subtract(5, 'm').toISOString();

View file

@ -51,8 +51,8 @@ const apisToIntercept = [
];
describe.skip('Service overview: Time Comparison', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
opbeans({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -60,8 +60,8 @@ describe.skip('Service overview: Time Comparison', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
beforeEach(() => {
@ -69,14 +69,14 @@ describe.skip('Service overview: Time Comparison', () => {
});
it('enables by default the time comparison feature with Last 24 hours selected', () => {
cy.visit(serviceOverviewPath);
cy.visitKibana(serviceOverviewPath);
cy.url().should('include', 'comparisonEnabled=true');
cy.url().should('include', 'offset=1d');
});
describe('when comparison is toggled off', () => {
it('disables select box', () => {
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.contains('opbeans-java');
// Comparison is enabled by default
@ -91,7 +91,7 @@ describe.skip('Service overview: Time Comparison', () => {
apisToIntercept.map(({ endpoint, name }) => {
cy.intercept('GET', endpoint).as(name);
});
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.get('[data-test-subj="comparisonSelect"]').should('be.enabled');
const offset = `offset=1d`;
@ -125,7 +125,7 @@ describe.skip('Service overview: Time Comparison', () => {
apisToIntercept.map(({ endpoint, name }) => {
cy.intercept('GET', endpoint).as(name);
});
cy.visit(serviceOverviewPath);
cy.visitKibana(serviceOverviewPath);
cy.contains('opbeans-java');
// opens the page with "Day before" selected
cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1d');
@ -136,7 +136,7 @@ describe.skip('Service overview: Time Comparison', () => {
});
it('changes comparison type when a new time range is selected', () => {
cy.visit(serviceOverviewHref);
cy.visitKibana(serviceOverviewHref);
cy.contains('opbeans-java');
// Time comparison default value
cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1d');
@ -189,7 +189,7 @@ describe.skip('Service overview: Time Comparison', () => {
apisToIntercept.map(({ endpoint, name }) => {
cy.intercept('GET', endpoint).as(name);
});
cy.visit(
cy.visitKibana(
url.format({
pathname: serviceOverviewPath,
query: {

View file

@ -296,7 +296,7 @@ function getConsumerMultiple({
* ----Span E
* ------span.links= producer-external-only / Span B | producer-consumer / Transaction C
*/
export async function generateSpanLinksData() {
export function generateSpanLinksData() {
const producerInternalOnly = getProducerInternalOnly();
const producerExternalOnly = getProducerExternalOnly();
const producerConsumer = getProducerConsumer({
@ -309,7 +309,7 @@ export async function generateSpanLinksData() {
producerExternalOnlySpanBSpanLink: producerExternalOnly.spanBSpanLink,
});
await synthtrace.index(
synthtrace.index(
new EntityArrayIterable(producerInternalOnly.apmFields).merge(
new EntityArrayIterable(producerExternalOnly.apmFields),
new EntityArrayIterable(producerConsumer.apmFields),

View file

@ -35,17 +35,17 @@ describe('Span links', () => {
describe('when data is loaded', () => {
let ids: Awaited<ReturnType<typeof generateSpanLinksData>>;
before(async () => {
ids = await generateSpanLinksData();
before(() => {
ids = generateSpanLinksData();
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
describe('span links count on trace waterfall', () => {
it('Shows two children and no parents on producer-internal-only Span A', () => {
cy.visit(
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'producer-internal-only' })
);
cy.contains('Transaction A').click();
@ -59,7 +59,7 @@ describe('Span links', () => {
});
it('Shows one parent and one children on producer-external-only Span B', () => {
cy.visit(
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'producer-external-only' })
);
cy.contains('Transaction B').click();
@ -73,7 +73,9 @@ describe('Span links', () => {
});
it('Shows one parent and one children on producer-consumer Transaction C', () => {
cy.visit(getServiceInventoryUrl({ serviceName: 'producer-consumer' }));
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'producer-consumer' })
);
cy.contains('Transaction C').click();
cy.contains('2 Span links');
cy.get(
@ -85,7 +87,9 @@ describe('Span links', () => {
});
it('Shows no parent and one children on producer-consumer Span C', () => {
cy.visit(getServiceInventoryUrl({ serviceName: 'producer-consumer' }));
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'producer-consumer' })
);
cy.contains('Transaction C').click();
cy.contains('1 Span link');
cy.get(
@ -97,7 +101,9 @@ describe('Span links', () => {
});
it('Shows two parents and one children on consumer-multiple Transaction D', () => {
cy.visit(getServiceInventoryUrl({ serviceName: 'consumer-multiple' }));
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'consumer-multiple' })
);
cy.contains('Transaction D').click();
cy.contains('2 Span links');
cy.get(
@ -109,7 +115,9 @@ describe('Span links', () => {
});
it('Shows two parents and one children on consumer-multiple Span E', () => {
cy.visit(getServiceInventoryUrl({ serviceName: 'consumer-multiple' }));
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'consumer-multiple' })
);
cy.contains('Transaction D').click();
cy.contains('2 Span links');
cy.get(
@ -123,7 +131,7 @@ describe('Span links', () => {
describe('span link flyout', () => {
it('Shows children details on producer-internal-only Span A', () => {
cy.visit(
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'producer-internal-only' })
);
cy.contains('Transaction A').click();
@ -154,7 +162,7 @@ describe('Span links', () => {
});
it('Shows children and parents details on producer-external-only Span B', () => {
cy.visit(
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'producer-external-only' })
);
cy.contains('Transaction B').click();
@ -178,7 +186,9 @@ describe('Span links', () => {
});
it('Shows children and parents details on producer-consumer Transaction C', () => {
cy.visit(getServiceInventoryUrl({ serviceName: 'producer-consumer' }));
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'producer-consumer' })
);
cy.contains('Transaction C').click();
cy.get(
`[aria-controls="${ids.producerConsumerIds.transactionCId}"]`
@ -210,7 +220,9 @@ describe('Span links', () => {
});
it('Shows children and parents details on producer-consumer Span C', () => {
cy.visit(getServiceInventoryUrl({ serviceName: 'producer-consumer' }));
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'producer-consumer' })
);
cy.contains('Transaction C').click();
cy.contains('Span C').click();
cy.get('[data-test-subj="spanLinksTab"]').click();
@ -232,7 +244,9 @@ describe('Span links', () => {
});
it('Shows children and parents details on consumer-multiple Transaction D', () => {
cy.visit(getServiceInventoryUrl({ serviceName: 'consumer-multiple' }));
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'consumer-multiple' })
);
cy.contains('Transaction D').click();
cy.get(
`[aria-controls="${ids.producerMultipleIds.transactionDId}"]`
@ -266,7 +280,9 @@ describe('Span links', () => {
});
it('Shows children and parents details on consumer-multiple Span E', () => {
cy.visit(getServiceInventoryUrl({ serviceName: 'consumer-multiple' }));
cy.visitKibana(
getServiceInventoryUrl({ serviceName: 'consumer-multiple' })
);
cy.contains('Transaction D').click();
cy.contains('Span E').click();
cy.get('[data-test-subj="spanLinksTab"]').click();

View file

@ -17,8 +17,8 @@ const timeRange = {
};
describe('Transaction details', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
opbeans({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -26,13 +26,13 @@ describe('Transaction details', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
beforeEach(() => {
cy.loginAsViewerUser();
cy.visit(
cy.visitKibana(
`/app/apm/services/opbeans-java/transactions/view?${new URLSearchParams({
...timeRange,
transactionName: 'GET /api/product',

View file

@ -19,8 +19,8 @@ const serviceTransactionsHref = url.format({
});
describe('Transactions Overview', () => {
before(async () => {
await synthtrace.index(
before(() => {
synthtrace.index(
opbeans({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
@ -28,8 +28,8 @@ describe('Transactions Overview', () => {
);
});
after(async () => {
await synthtrace.clean();
after(() => {
synthtrace.clean();
});
beforeEach(() => {
@ -37,7 +37,7 @@ describe('Transactions Overview', () => {
});
it('has no detectable a11y violations on load', () => {
cy.visit(serviceTransactionsHref);
cy.visitKibana(serviceTransactionsHref);
cy.get('a:contains(Transactions)').should(
'have.attr',
'aria-selected',
@ -48,7 +48,7 @@ describe('Transactions Overview', () => {
});
it('persists transaction type selected when navigating to Overview tab', () => {
cy.visit(serviceTransactionsHref);
cy.visitKibana(serviceTransactionsHref);
cy.get('[data-test-subj="headerFilterTransactionType"]').should(
'have.value',
'request'

View file

@ -6,9 +6,9 @@
*/
describe('APM tutorial', () => {
before(() => {
beforeEach(() => {
cy.loginAsViewerUser();
cy.visit('/app/home#/tutorial/apm');
cy.visitKibana('/app/home#/tutorial/apm');
});
it('includes section for APM Server', () => {

View file

@ -21,21 +21,24 @@ Cypress.Commands.add('loginAsEditorUser', () => {
Cypress.Commands.add(
'loginAs',
({ username, password }: { username: string; password: string }) => {
cy.log(`Logging in as ${username}`);
const kibanaUrl = Cypress.env('KIBANA_URL');
return cy.request({
log: false,
method: 'POST',
url: `${kibanaUrl}/internal/security/login`,
body: {
providerType: 'basic',
providerName: 'basic',
currentURL: `${kibanaUrl}/login`,
params: { username, password },
},
headers: {
'kbn-xsrf': 'e2e_test',
},
cy.log(`Calling 'loginAs'`);
cy.session([username, password], () => {
cy.log(`Logging in as ${username}`);
const kibanaUrl = Cypress.env('KIBANA_URL');
cy.request({
log: false,
method: 'POST',
url: `${kibanaUrl}/internal/security/login`,
body: {
providerType: 'basic',
providerName: 'basic',
currentURL: `${kibanaUrl}/login`,
params: { username, password },
},
headers: {
'kbn-xsrf': 'e2e_test',
},
});
});
}
);
@ -45,6 +48,14 @@ Cypress.Commands.add('changeTimeRange', (value: string) => {
cy.contains(value).click();
});
Cypress.Commands.add('visitKibana', (url: string) => {
cy.visit(url);
cy.get('[data-test-subj="kbnLoadingMessage"]').should('exist');
cy.get('[data-test-subj="kbnLoadingMessage"]').should('not.exist', {
timeout: 50000,
});
});
Cypress.Commands.add(
'selectAbsoluteTimeRange',
(start: string, end: string) => {
@ -96,6 +107,7 @@ Cypress.Commands.add(
headers: {
'kbn-xsrf': 'e2e_test',
},
auth: { user: 'editor', pass: 'changeme' },
});
}
);

View file

@ -14,6 +14,7 @@ declare namespace Cypress {
password: string;
}): Cypress.Chainable<Cypress.Response<any>>;
changeTimeRange(value: string): void;
visitKibana(url: string): void;
selectAbsoluteTimeRange(start: string, end: string): void;
expectAPIsToHaveBeenCalledWith(params: {
apisIntercepted: string[];

View file

@ -8,11 +8,6 @@ import type { EntityIterable } from '@kbn/apm-synthtrace';
export const synthtrace = {
index: (events: EntityIterable) =>
new Promise((resolve) => {
cy.task('synthtrace:index', events.toArray()).then(resolve);
}),
clean: () =>
new Promise((resolve) => {
cy.task('synthtrace:clean').then(resolve);
}),
cy.task('synthtrace:index', events.toArray()),
clean: () => cy.task('synthtrace:clean'),
};