mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-11 20:59:00 +08:00
Feature(FE): cypress base test case are updated (#275)
* chore: video config is updated as it will not generate any video while running cypress * chore: cypress.env.json is added in the env file * chore: tsConfig is updated * feature: Cypress is updated with some of the test cases * chore: default test case is removed * chore: convertToNanoSecondsToSecond function is updated * chore: lock files, node_modules are ignored in git * test: metric are updated Co-authored-by: Ankit Nayan <ankit@signoz.io>
This commit is contained in:
parent
e0be48a527
commit
66b423588e
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
node_modules
|
||||
yarn.lock
|
||||
|
||||
deploy/docker/environment_tiny/common_test
|
||||
frontend/node_modules
|
||||
frontend/.pnp
|
||||
@ -23,6 +26,9 @@ frontend/yarn-error.log*
|
||||
frontend/src/constants/env.ts
|
||||
frontend/cypress/**/*.mp4
|
||||
|
||||
# env file for cypress
|
||||
frontend/cypress.env.json
|
||||
|
||||
.idea
|
||||
|
||||
**/.vscode
|
||||
|
@ -1 +1,3 @@
|
||||
{}
|
||||
{
|
||||
"video": false
|
||||
}
|
||||
|
45
frontend/cypress/CustomFunctions/Login.ts
Normal file
45
frontend/cypress/CustomFunctions/Login.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import ROUTES from "constants/routes";
|
||||
|
||||
const Login = ({ email, name }: LoginProps): void => {
|
||||
const emailInput = cy.findByPlaceholderText("mike@netflix.com");
|
||||
|
||||
emailInput.then((emailInput) => {
|
||||
const element = emailInput[0];
|
||||
// element is present
|
||||
expect(element).not.undefined;
|
||||
expect(element.nodeName).to.be.equal("INPUT");
|
||||
});
|
||||
emailInput.type(email).then((inputElements) => {
|
||||
const inputElement = inputElements[0];
|
||||
const inputValue = inputElement.getAttribute("value");
|
||||
expect(inputValue).to.be.equals(email);
|
||||
});
|
||||
|
||||
const firstNameInput = cy.findByPlaceholderText("Mike");
|
||||
firstNameInput.then((firstNameInput) => {
|
||||
const element = firstNameInput[0];
|
||||
// element is present
|
||||
expect(element).not.undefined;
|
||||
expect(element.nodeName).to.be.equal("INPUT");
|
||||
});
|
||||
|
||||
firstNameInput.type(name).then((inputElements) => {
|
||||
const inputElement = inputElements[0];
|
||||
const inputValue = inputElement.getAttribute("value");
|
||||
expect(inputValue).to.be.equals(name);
|
||||
});
|
||||
|
||||
const gettingStartedButton = cy.get("button");
|
||||
gettingStartedButton.click();
|
||||
|
||||
cy.location("pathname").then((e) => {
|
||||
expect(e).to.be.equal(ROUTES.APPLICATION);
|
||||
});
|
||||
};
|
||||
|
||||
export interface LoginProps {
|
||||
email: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export default Login;
|
35
frontend/cypress/fixtures/defaultApp.json
Normal file
35
frontend/cypress/fixtures/defaultApp.json
Normal file
@ -0,0 +1,35 @@
|
||||
[
|
||||
{
|
||||
"serviceName": "frontend",
|
||||
"p99": 1134610000,
|
||||
"avgDuration": 744523000,
|
||||
"numCalls": 267,
|
||||
"callRate": 0.89,
|
||||
"numErrors": 0,
|
||||
"errorRate": 0,
|
||||
"num4XX": 0,
|
||||
"fourXXRate": 0
|
||||
},
|
||||
{
|
||||
"serviceName": "customer",
|
||||
"p99": 734422400,
|
||||
"avgDuration": 348678530,
|
||||
"numCalls": 267,
|
||||
"callRate": 0.89,
|
||||
"numErrors": 0,
|
||||
"errorRate": 0,
|
||||
"num4XX": 0,
|
||||
"fourXXRate": 0
|
||||
},
|
||||
{
|
||||
"serviceName": "driver",
|
||||
"p99": 239234080,
|
||||
"avgDuration": 204662290,
|
||||
"numCalls": 267,
|
||||
"callRate": 0.89,
|
||||
"numErrors": 0,
|
||||
"errorRate": 0,
|
||||
"num4XX": 0,
|
||||
"fourXXRate": 0
|
||||
}
|
||||
]
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// Welcome to Cypress!
|
||||
//
|
||||
// This spec file contains a variety of sample tests
|
||||
// for a todo list app that are designed to demonstrate
|
||||
// the power of writing tests in Cypress.
|
||||
//
|
||||
// To learn more about how Cypress works and
|
||||
// what makes it such an awesome testing tool,
|
||||
// please read our getting started guide:
|
||||
// https://on.cypress.io/introduction-to-cypress
|
||||
|
||||
describe('example to-do app', () => {
|
||||
beforeEach(() => {
|
||||
// Cypress starts out with a blank slate for each test
|
||||
// so we must tell it to visit our website with the `cy.visit()` command.
|
||||
// Since we want to visit the same URL at the start of all our tests,
|
||||
// we include it in our beforeEach function so that it runs before each test
|
||||
cy.visit('https://example.cypress.io/todo');
|
||||
});
|
||||
|
||||
it('displays two todo items by default', () => {
|
||||
// We use the `cy.get()` command to get all elements that match the selector.
|
||||
// Then, we use `should` to assert that there are two matched items,
|
||||
// which are the two default items.
|
||||
cy.get('.todo-list li').should('have.length', 2);
|
||||
|
||||
// We can go even further and check that the default todos each contain
|
||||
// the correct text. We use the `first` and `last` functions
|
||||
// to get just the first and last matched elements individually,
|
||||
// and then perform an assertion with `should`.
|
||||
cy.get('.todo-list li').first().should('have.text', 'Pay electric bill');
|
||||
cy.get('.todo-list li').last().should('have.text', 'Walk the dog');
|
||||
});
|
||||
|
||||
it('can add new todo items', () => {
|
||||
// We'll store our item text in a variable so we can reuse it
|
||||
const newItem = 'Feed the cat';
|
||||
|
||||
// Let's get the input element and use the `type` command to
|
||||
// input our new list item. After typing the content of our item,
|
||||
// we need to type the enter key as well in order to submit the input.
|
||||
// This input has a data-test attribute so we'll use that to select the
|
||||
// element in accordance with best practices:
|
||||
// https://on.cypress.io/selecting-elements
|
||||
cy.get('[data-test=new-todo]').type(`${newItem}{enter}`);
|
||||
|
||||
// Now that we've typed our new item, let's check that it actually was added to the list.
|
||||
// Since it's the newest item, it should exist as the last element in the list.
|
||||
// In addition, with the two default items, we should have a total of 3 elements in the list.
|
||||
// Since assertions yield the element that was asserted on,
|
||||
// we can chain both of these assertions together into a single statement.
|
||||
cy
|
||||
.get('.todo-list li')
|
||||
.should('have.length', 3)
|
||||
.last()
|
||||
.should('have.text', newItem);
|
||||
});
|
||||
|
||||
it('can check off an item as completed', () => {
|
||||
// In addition to using the `get` command to get an element by selector,
|
||||
// we can also use the `contains` command to get an element by its contents.
|
||||
// However, this will yield the <label>, which is lowest-level element that contains the text.
|
||||
// In order to check the item, we'll find the <input> element for this <label>
|
||||
// by traversing up the dom to the parent element. From there, we can `find`
|
||||
// the child checkbox <input> element and use the `check` command to check it.
|
||||
cy
|
||||
.contains('Pay electric bill')
|
||||
.parent()
|
||||
.find('input[type=checkbox]')
|
||||
.check();
|
||||
|
||||
// Now that we've checked the button, we can go ahead and make sure
|
||||
// that the list element is now marked as completed.
|
||||
// Again we'll use `contains` to find the <label> element and then use the `parents` command
|
||||
// to traverse multiple levels up the dom until we find the corresponding <li> element.
|
||||
// Once we get that element, we can assert that it has the completed class.
|
||||
cy
|
||||
.contains('Pay electric bill')
|
||||
.parents('li')
|
||||
.should('have.class', 'completed');
|
||||
});
|
||||
|
||||
context('with a checked task', () => {
|
||||
beforeEach(() => {
|
||||
// We'll take the command we used above to check off an element
|
||||
// Since we want to perform multiple tests that start with checking
|
||||
// one element, we put it in the beforeEach hook
|
||||
// so that it runs at the start of every test.
|
||||
cy
|
||||
.contains('Pay electric bill')
|
||||
.parent()
|
||||
.find('input[type=checkbox]')
|
||||
.check();
|
||||
});
|
||||
|
||||
it('can filter for uncompleted tasks', () => {
|
||||
// We'll click on the "active" button in order to
|
||||
// display only incomplete items
|
||||
cy.contains('Active').click();
|
||||
|
||||
// After filtering, we can assert that there is only the one
|
||||
// incomplete item in the list.
|
||||
cy
|
||||
.get('.todo-list li')
|
||||
.should('have.length', 1)
|
||||
.first()
|
||||
.should('have.text', 'Walk the dog');
|
||||
|
||||
// For good measure, let's also assert that the task we checked off
|
||||
// does not exist on the page.
|
||||
cy.contains('Pay electric bill').should('not.exist');
|
||||
});
|
||||
|
||||
it('can filter for completed tasks', () => {
|
||||
// We can perform similar steps as the test above to ensure
|
||||
// that only completed tasks are shown
|
||||
cy.contains('Completed').click();
|
||||
|
||||
cy
|
||||
.get('.todo-list li')
|
||||
.should('have.length', 1)
|
||||
.first()
|
||||
.should('have.text', 'Pay electric bill');
|
||||
|
||||
cy.contains('Walk the dog').should('not.exist');
|
||||
});
|
||||
|
||||
it('can delete all completed tasks', () => {
|
||||
// First, let's click the "Clear completed" button
|
||||
// `contains` is actually serving two purposes here.
|
||||
// First, it's ensuring that the button exists within the dom.
|
||||
// This button only appears when at least one task is checked
|
||||
// so this command is implicitly verifying that it does exist.
|
||||
// Second, it selects the button so we can click it.
|
||||
cy.contains('Clear completed').click();
|
||||
|
||||
// Then we can make sure that there is only one element
|
||||
// in the list and our element does not exist
|
||||
cy
|
||||
.get('.todo-list li')
|
||||
.should('have.length', 1)
|
||||
.should('not.have.text', 'Pay electric bill');
|
||||
|
||||
// Finally, make sure that the clear button no longer exists.
|
||||
cy.contains('Clear completed').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export {};
|
26
frontend/cypress/integration/appLayout/index.spec.ts
Normal file
26
frontend/cypress/integration/appLayout/index.spec.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/// <reference types="cypress" />
|
||||
import ROUTES from "constants/routes";
|
||||
|
||||
describe("App Layout", () => {
|
||||
beforeEach(() => {
|
||||
cy.visit(Cypress.env("baseUrl"));
|
||||
});
|
||||
|
||||
it("Check the user is in Logged Out State", async () => {
|
||||
cy.location("pathname").then((e) => {
|
||||
expect(e).to.be.equal(ROUTES.SIGN_UP);
|
||||
});
|
||||
});
|
||||
|
||||
it("Logged In State", () => {
|
||||
const testEmail = "test@test.com";
|
||||
const firstName = "Test";
|
||||
|
||||
cy.login({
|
||||
email: testEmail,
|
||||
name: firstName,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export {};
|
62
frontend/cypress/integration/metrics/index.spec.ts
Normal file
62
frontend/cypress/integration/metrics/index.spec.ts
Normal file
@ -0,0 +1,62 @@
|
||||
/// <reference types="cypress" />
|
||||
import defaultApps from "../../fixtures/defaultApp.json";
|
||||
import convertToNanoSecondsToSecond from "lib/convertToNanoSecondsToSecond";
|
||||
|
||||
describe("Metrics", () => {
|
||||
beforeEach(() => {
|
||||
cy.visit(Cypress.env("baseUrl"));
|
||||
|
||||
const testEmail = "test@test.com";
|
||||
const firstName = "Test";
|
||||
cy
|
||||
.intercept("GET", "/api/v1//services?start*", { fixture: "defaultApp.json" })
|
||||
.as("defaultApps");
|
||||
|
||||
cy.login({
|
||||
email: testEmail,
|
||||
name: firstName,
|
||||
});
|
||||
});
|
||||
|
||||
it("Default Apps", () => {
|
||||
cy.wait("@defaultApps");
|
||||
|
||||
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());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export {};
|
@ -1,26 +1,12 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
import '@testing-library/cypress/add-commands';
|
||||
import Login, { LoginProps } from '../CustomFunctions/Login';
|
||||
|
||||
Cypress.Commands.add('login', Login);
|
||||
|
||||
declare global {
|
||||
namespace Cypress {
|
||||
interface Chainable<Subject> {
|
||||
login(props: LoginProps): void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"target": "es5",
|
||||
"lib": ["es5", "dom"],
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
// be explicit about types included
|
||||
|
5
frontend/src/lib/convertToNanoSecondsToSecond.ts
Normal file
5
frontend/src/lib/convertToNanoSecondsToSecond.ts
Normal file
@ -0,0 +1,5 @@
|
||||
const convertToNanoSecondsToSecond = (number: number) => {
|
||||
return parseFloat((number / 1000000).toString()).toFixed(2);
|
||||
};
|
||||
|
||||
export default convertToNanoSecondsToSecond;
|
@ -17,6 +17,7 @@
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"baseUrl": "./src"
|
||||
"baseUrl": "./src",
|
||||
"downlevelIteration": true
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user