diff --git a/frontend/cypress/CustomFunctions/Login.ts b/frontend/cypress/CustomFunctions/Login.ts index 7b99516b44..dba33d90aa 100644 --- a/frontend/cypress/CustomFunctions/Login.ts +++ b/frontend/cypress/CustomFunctions/Login.ts @@ -1,5 +1,3 @@ -import ROUTES from 'constants/routes'; - const Login = ({ email, name }: LoginProps): void => { const emailInput = cy.findByPlaceholderText('mike@netflix.com'); @@ -29,12 +27,16 @@ const Login = ({ email, name }: LoginProps): void => { expect(inputValue).to.be.equals(name); }); - const gettingStartedButton = cy.get('button'); + const gettingStartedButton = cy.findByText('Get Started'); gettingStartedButton.click(); - cy.location('pathname').then((e) => { - expect(e).to.be.equal(ROUTES.APPLICATION); - }); + cy + .intercept('POST', '/api/v1/user?email*', { + statusCode: 200, + }) + .as('defaultUser'); + + cy.wait('@defaultUser'); }; export interface LoginProps { diff --git a/frontend/cypress/CustomFunctions/checkRouteDefaultGlobalTimeOptions.ts b/frontend/cypress/CustomFunctions/checkRouteDefaultGlobalTimeOptions.ts new file mode 100644 index 0000000000..b19b4bdeeb --- /dev/null +++ b/frontend/cypress/CustomFunctions/checkRouteDefaultGlobalTimeOptions.ts @@ -0,0 +1,49 @@ +import { + getDefaultOption, + getOptions, +} from 'container/Header/DateTimeSelection/config'; +// import { AppState } from 'store/reducers'; + +const CheckRouteDefaultGlobalTimeOptions = ({ + route, +}: CheckRouteDefaultGlobalTimeOptionsProps): void => { + cy.visit(Cypress.env('baseUrl') + route); + + const allOptions = getOptions(route); + + const defaultValue = getDefaultOption(route); + + const defaultSelectedOption = allOptions.find((e) => e.value === defaultValue); + + expect(defaultSelectedOption).not.undefined; + + cy + .findAllByTestId('dropDown') + .find('span') + .then((el) => { + const elements = el.get(); + + const item = elements[1]; + + expect(defaultSelectedOption?.label).to.be.equals( + item.innerText, + 'Default option is not matching', + ); + }); + + // cy + // .window() + // .its('store') + // .invoke('getState') + // .then((e: AppState) => { + // const { globalTime } = e; + // const { maxTime, minTime } = globalTime; + // // @TODO match the global min time and max time according to the selected option + // }); +}; + +export interface CheckRouteDefaultGlobalTimeOptionsProps { + route: string; +} + +export default CheckRouteDefaultGlobalTimeOptions; diff --git a/frontend/cypress/fixtures/errorPercentage.json b/frontend/cypress/fixtures/errorPercentage.json new file mode 100644 index 0000000000..61c326ffc2 --- /dev/null +++ b/frontend/cypress/fixtures/errorPercentage.json @@ -0,0 +1 @@ +{ "status": "success", "data": { "resultType": "matrix", "result": [] } } diff --git a/frontend/cypress/fixtures/requestPerSecond.json b/frontend/cypress/fixtures/requestPerSecond.json new file mode 100644 index 0000000000..4cd3062454 --- /dev/null +++ b/frontend/cypress/fixtures/requestPerSecond.json @@ -0,0 +1,29 @@ +{ + "status": "success", + "data": { + "resultType": "matrix", + "result": [ + { + "metric": {}, + "values": [ + [1634741764.961, "0.9"], + [1634741824.961, "0.9"], + [1634741884.961, "0.8666666666666667"], + [1634741944.961, "1"], + [1634742004.961, "0.9166666666666666"], + [1634742064.961, "0.95"], + [1634742124.961, "0.9333333333333333"], + [1634742184.961, "0.95"], + [1634742244.961, "1.0333333333333334"], + [1634742304.961, "0.9333333333333333"], + [1634742364.961, "0.9166666666666666"], + [1634742424.961, "0.9"], + [1634742484.961, "1.0166666666666666"], + [1634742544.961, "0.8333333333333334"], + [1634742604.961, "0.9166666666666666"], + [1634742664.961, "0.95"] + ] + } + ] + } +} diff --git a/frontend/cypress/fixtures/serviceOverview.json b/frontend/cypress/fixtures/serviceOverview.json new file mode 100644 index 0000000000..d3a51c35b2 --- /dev/null +++ b/frontend/cypress/fixtures/serviceOverview.json @@ -0,0 +1,62 @@ +[ + { + "timestamp": 1634742600000000000, + "p50": 720048500, + "p95": 924409540, + "p99": 974744300, + "numCalls": 48, + "callRate": 0.8, + "numErrors": 0, + "errorRate": 0 + }, + { + "timestamp": 1634742540000000000, + "p50": 712614000, + "p95": 955580700, + "p99": 1045595400, + "numCalls": 59, + "callRate": 0.98333335, + "numErrors": 0, + "errorRate": 0 + }, + { + "timestamp": 1634742480000000000, + "p50": 720842000, + "p95": 887187600, + "p99": 943676860, + "numCalls": 53, + "callRate": 0.8833333, + "numErrors": 0, + "errorRate": 0 + }, + { + "timestamp": 1634742420000000000, + "p50": 712287000, + "p95": 908505540, + "p99": 976507650, + "numCalls": 58, + "callRate": 0.96666664, + "numErrors": 0, + "errorRate": 0 + }, + { + "timestamp": 1634742360000000000, + "p50": 697125500, + "p95": 975581800, + "p99": 1190121900, + "numCalls": 54, + "callRate": 0.9, + "numErrors": 0, + "errorRate": 0 + }, + { + "timestamp": 1634742300000000000, + "p50": 711592500, + "p95": 880559900, + "p99": 1100105500, + "numCalls": 40, + "callRate": 0.6666667, + "numErrors": 0, + "errorRate": 0 + } +] diff --git a/frontend/cypress/fixtures/topEndPoints.json b/frontend/cypress/fixtures/topEndPoints.json new file mode 100644 index 0000000000..4892b6e93a --- /dev/null +++ b/frontend/cypress/fixtures/topEndPoints.json @@ -0,0 +1,9 @@ +[ + { + "p50": 710824000, + "p95": 1003231400, + "p99": 1231265500, + "numCalls": 299, + "name": "HTTP GET /dispatch" + } +] diff --git a/frontend/cypress/integration/appLayout/index.spec.ts b/frontend/cypress/integration/appLayout/index.spec.ts index 38a063953a..4d45291dea 100644 --- a/frontend/cypress/integration/appLayout/index.spec.ts +++ b/frontend/cypress/integration/appLayout/index.spec.ts @@ -22,5 +22,3 @@ describe('App Layout', () => { }); }); }); - -export {}; diff --git a/frontend/cypress/integration/globalTime/default.spec.ts b/frontend/cypress/integration/globalTime/default.spec.ts new file mode 100644 index 0000000000..249bcf30c6 --- /dev/null +++ b/frontend/cypress/integration/globalTime/default.spec.ts @@ -0,0 +1,44 @@ +/// +import ROUTES from 'constants/routes'; + +describe('default time', () => { + beforeEach(() => { + window.localStorage.setItem('isLoggedIn', 'yes'); + }); + + it('Metrics Page default time', () => { + cy.checkDefaultGlobalOption({ + route: ROUTES.APPLICATION, + }); + }); + + it('Dashboard Page default time', () => { + cy.checkDefaultGlobalOption({ + route: ROUTES.ALL_DASHBOARD, + }); + }); + + it('Trace Page default time', () => { + cy.checkDefaultGlobalOption({ + route: ROUTES.TRACES, + }); + }); + + it('Instrumentation Page default time', () => { + cy.checkDefaultGlobalOption({ + route: ROUTES.INSTRUMENTATION, + }); + }); + + it('Service Page default time', () => { + cy.checkDefaultGlobalOption({ + route: ROUTES.SERVICE_MAP, + }); + }); + + it('Settings Page default time', () => { + cy.checkDefaultGlobalOption({ + route: ROUTES.SETTINGS, + }); + }); +}); diff --git a/frontend/cypress/integration/globalTime/metricsApplication.spec.ts b/frontend/cypress/integration/globalTime/metricsApplication.spec.ts new file mode 100644 index 0000000000..e64ef6711e --- /dev/null +++ b/frontend/cypress/integration/globalTime/metricsApplication.spec.ts @@ -0,0 +1,126 @@ +/// +import getGlobalDropDownFormatedDate from 'lib/getGlobalDropDownFormatedDate'; +import { AppState } from 'store/reducers'; + +import topEndPoints from '../../fixtures/topEndPoints.json'; + +describe('Global Time Metrics Application', () => { + beforeEach(() => { + cy.visit(Cypress.env('baseUrl')); + + const testEmail = 'test@test.com'; + const firstName = 'Test'; + + cy.login({ + email: testEmail, + name: firstName, + }); + }); + + it('Metrics Application', async () => { + cy + .intercept('GET', '/api/v1/services*', { + fixture: 'defaultApp.json', + }) + .as('defaultApps'); + + cy.wait('@defaultApps'); + + //clicking on frontend + cy.get('tr:nth-child(1) > td:first-child').click(); + + cy + .intercept('GET', '/api/v1/service/top_endpoints*', { + fixture: 'topEndPoints.json', + }) + .as('topEndPoints'); + + cy + .intercept('GET', '/api/v1/service/overview?*', { + fixture: 'serviceOverview.json', + }) + .as('serviceOverview'); + + cy + .intercept( + 'GET', + `/api/v1/query_range?query=sum(rate(signoz_latency_count*`, + { + fixture: 'requestPerSecond.json', + }, + ) + .as('requestPerSecond'); + + cy + .window() + .its('store') + .invoke('getState') + .then((e: AppState) => { + const { globalTime } = e; + + const { maxTime, minTime } = globalTime; + + // intercepting metrics application call + + cy.wait('@topEndPoints'); + cy.wait('@serviceOverview'); + //TODO add errorPercentage also + // cy.wait('@errorPercentage'); + cy.wait('@requestPerSecond'); + + cy + .get('tbody tr:first-child td:first-child') + .then((el) => { + const elements = el.get(); + + expect(elements.length).to.be.equals(1); + + const element = elements[0]; + + expect(element.innerText).to.be.equals(topEndPoints[0].name); + }) + .click(); + + cy + .findAllByTestId('dropDown') + .find('span.ant-select-selection-item') + .then((e) => { + const elements = e; + + const element = elements[0]; + + const customSelectedTime = element.innerText; + + const startTime = new Date(minTime / 1000000); + const endTime = new Date(maxTime / 1000000); + + const startString = getGlobalDropDownFormatedDate(startTime); + const endString = getGlobalDropDownFormatedDate(endTime); + + const result = `${startString} - ${endString}`; + + expect(customSelectedTime).to.be.equals(result); + }); + + cy + .findByTestId('dropDown') + .click() + .then(() => { + cy.findByTitle('Last 30 min').click(); + }); + + cy + .findByTestId('dropDown') + .find('span.ant-select-selection-item') + .then((e) => { + const elements = e; + + const element = elements[0]; + + const selectedTime = element.innerText; + + expect(selectedTime).to.be.equals('Last 30 min'); + }); + }); + }); +}); diff --git a/frontend/cypress/integration/metrics/index.spec.ts b/frontend/cypress/integration/metrics/index.spec.ts index 3169f5eb2d..91cf3b7e38 100644 --- a/frontend/cypress/integration/metrics/index.spec.ts +++ b/frontend/cypress/integration/metrics/index.spec.ts @@ -1,4 +1,5 @@ /// +import ROUTES from 'constants/routes'; import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond'; import defaultApps from '../../fixtures/defaultApp.json'; @@ -9,9 +10,6 @@ describe('Metrics', () => { const testEmail = 'test@test.com'; const firstName = 'Test'; - cy - .intercept('GET', '/api/v1//services?start*', { fixture: 'defaultApp.json' }) - .as('defaultApps'); cy.login({ email: testEmail, @@ -20,41 +18,47 @@ describe('Metrics', () => { }); it('Default Apps', () => { + cy + .intercept('GET', '/api/v1/services*', { + fixture: 'defaultApp.json', + }) + .as('defaultApps'); + cy.wait('@defaultApps'); - cy.get('tbody').then((elements) => { - const trElements = elements.children(); - expect(trElements.length).to.be.equal(defaultApps.length); + cy.location().then((e) => { + expect(e.pathname).to.be.equals(ROUTES.APPLICATION); - const getChildren = (row: Element): Element => { - if (row.children.length === 0) { - return row; - } - return getChildren(row.children[0]); - }; + cy.get('tbody').then((elements) => { + const trElements = elements.children(); + expect(trElements.length).to.be.equal(defaultApps.length); + const getChildren = (row: Element): Element => { + if (row.children.length === 0) { + return row; + } + return getChildren(row.children[0]); + }; - // this is row element - trElements.map((index, element) => { - const [ - applicationElement, - p99Element, - errorRateElement, - rpsElement, - ] = element.children; - - const applicationName = getChildren(applicationElement).innerHTML; - const p99Name = getChildren(p99Element).innerHTML; - const errorRateName = getChildren(errorRateElement).innerHTML; - const rpsName = getChildren(rpsElement).innerHTML; - - const { serviceName, p99, errorRate, callRate } = defaultApps[index]; - - expect(applicationName).to.be.equal(serviceName); - expect(p99Name).to.be.equal(convertToNanoSecondsToSecond(p99).toString()); - expect(errorRateName).to.be.equals( - parseFloat(errorRate.toString()).toFixed(2), - ); - expect(rpsName).to.be.equals(callRate.toString()); + // this is row element + trElements.map((index, element) => { + const [ + applicationElement, + p99Element, + errorRateElement, + rpsElement, + ] = element.children; + const applicationName = getChildren(applicationElement).innerHTML; + const p99Name = getChildren(p99Element).innerHTML; + const errorRateName = getChildren(errorRateElement).innerHTML; + const rpsName = getChildren(rpsElement).innerHTML; + const { serviceName, p99, errorRate, callRate } = defaultApps[index]; + expect(applicationName).to.be.equal(serviceName); + expect(p99Name).to.be.equal(convertToNanoSecondsToSecond(p99).toString()); + expect(errorRateName).to.be.equals( + parseFloat(errorRate.toString()).toFixed(2), + ); + expect(rpsName).to.be.equals(callRate.toString()); + }); }); }); }); diff --git a/frontend/cypress/plugins/index.ts b/frontend/cypress/plugins/index.ts index 70100f1464..0db3bdca21 100644 --- a/frontend/cypress/plugins/index.ts +++ b/frontend/cypress/plugins/index.ts @@ -19,6 +19,6 @@ /** * @type {Cypress.PluginConfig} */ -module.exports = (on, config: Cypress.ConfigOptions) => {}; +module.exports = (on, config: Cypress.ConfigOptions): void => {}; export {}; diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts index 9fb840e8d9..370f984791 100644 --- a/frontend/cypress/support/commands.ts +++ b/frontend/cypress/support/commands.ts @@ -1,13 +1,24 @@ import '@testing-library/cypress/add-commands'; +import CheckRouteDefaultGlobalTimeOptions, { + CheckRouteDefaultGlobalTimeOptionsProps, +} from '../CustomFunctions/checkRouteDefaultGlobalTimeOptions'; import Login, { LoginProps } from '../CustomFunctions/Login'; Cypress.Commands.add('login', Login); +Cypress.Commands.add( + 'checkDefaultGlobalOption', + CheckRouteDefaultGlobalTimeOptions, +); declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace namespace Cypress { - interface Chainable { + interface Chainable { login(props: LoginProps): void; + checkDefaultGlobalOption( + props: CheckRouteDefaultGlobalTimeOptionsProps, + ): void; } } } diff --git a/frontend/cypress/tsconfig.json b/frontend/cypress/tsconfig.json index 4a12ce0a87..249c11127d 100644 --- a/frontend/cypress/tsconfig.json +++ b/frontend/cypress/tsconfig.json @@ -6,7 +6,8 @@ "noEmit": true, // be explicit about types included // to avoid clashing with Jest types - "types": ["cypress", "@testing-library/cypress"] + "types": ["cypress", "@testing-library/cypress"], + "isolatedModules": false }, "include": ["../node_modules/cypress", "./**/*.ts"] } diff --git a/frontend/package.json b/frontend/package.json index 8b51c3a076..d6f41e8b44 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -143,7 +143,7 @@ "babel-plugin-styled-components": "^1.12.0", "compression-webpack-plugin": "^8.0.0", "copy-webpack-plugin": "^7.0.0", - "cypress": "^8.3.0", + "cypress": "8.6.0", "eslint": "^7.30.0", "eslint-config-prettier": "^8.3.0", "eslint-config-standard": "^16.0.3", diff --git a/frontend/src/container/Header/DateTimeSelection/index.tsx b/frontend/src/container/Header/DateTimeSelection/index.tsx index 2cfd86d758..bd7046d96f 100644 --- a/frontend/src/container/Header/DateTimeSelection/index.tsx +++ b/frontend/src/container/Header/DateTimeSelection/index.tsx @@ -278,6 +278,7 @@ const DateTimeSelection = ({ onSelectHandler(value as Time)} value={getInputLabel(startTime, endTime, selectedTimeInterval)} + data-testid="dropDown" > {options.map(({ value, label }) => (