Writing Tests
All new tests go in testing-v2/. The suite uses Cypress 13 with @badeball/cypress-cucumber-preprocessor for BDD-style Gherkin scenarios.
Directory structure
testing-v2/
├── cypress/
│ ├── e2e/
│ │ └── features/
│ │ ├── 01_login/
│ │ │ └── login.feature
│ │ ├── 02_dashboard/
│ │ │ └── dashboard.feature
│ │ └── 03_your_feature/ ← add new folders here
│ │ └── your_feature.feature
│ ├── pages/
│ │ ├── LoginPage.js
│ │ ├── DashboardPage.js
│ │ └── YourPage.js ← one page object per screen
│ └── support/
│ └── step_definitions/
│ ├── common/
│ │ └── auth_steps.js ← shared login/logout steps
│ ├── login/
│ │ └── login_steps.js
│ ├── dashboard/
│ │ └── dashboard_steps.js
│ └── your_feature/
│ └── your_feature_steps.js
├── .env.example
├── cypress.config.js
└── package.jsonAdding a new feature
1. Create a feature folder
Name it NN_feature_name (number prefix keeps the run order predictable):
testing-v2/cypress/e2e/features/03_employees/2. Write the feature file
Feature: Employee list
Background:
Given the admin is logged into the Nova Home Care portal
Scenario: Employee list page loads
When the admin navigates to the Employees section
Then the employee list is visible
Scenario: Employee count is shown
When the admin navigates to the Employees section
Then the page shows at least one employeeRules:
- One feature file per user-facing capability
- Use
Background:for shared preconditions (e.g. login) - Scenarios describe behaviour, not implementation
- Keep scenarios independent — no shared state between them
3. Create a page object
One class per screen. Page objects hold selectors and actions — no assertions.
// cypress/pages/EmployeesPage.js
class EmployeesPage {
visit() {
cy.visit('/employees');
}
employeeList() {
return cy.get('[data-cy=employee-list]');
}
employeeCount() {
return cy.get('[data-cy=employee-list-item]');
}
}
export default EmployeesPage;Selector rule: always use data-cy attributes — never CSS classes or text. CSS classes change with Chakra UI rebuilds. If a data-cy attribute is missing on a portals element, add it there first.
4. Write step definitions
// cypress/support/step_definitions/employees/employees_steps.js
import { When, Then } from '@badeball/cypress-cucumber-preprocessor';
import EmployeesPage from '../../../pages/EmployeesPage';
const page = new EmployeesPage();
When('the admin navigates to the Employees section', () => {
page.visit();
});
Then('the employee list is visible', () => {
page.employeeList().should('be.visible');
});
Then('the page shows at least one employee', () => {
page.employeeCount().should('have.length.at.least', 1);
});5. Reuse shared steps
Login steps are already defined in common/auth_steps.js. Use them in any feature:
Background:
Given the admin is logged into the Nova Home Care portalNo need to re-implement login in every step definition file.
Selectors
| ✅ Use | ❌ Avoid |
|---|---|
cy.get('[data-cy=employee-list]') | cy.get('.chakra-text.css-6q9ebm') |
cy.get('[data-cy=submit-btn]') | cy.get('button:contains("Submit")') |
cy.get('header') (semantic HTML) | cy.get('.css-generated-class') |
Chakra UI generates class names at build time — they change whenever the component tree changes. data-cy attributes are stable and explicit.
Environment variables
Credentials and URLs come from testing-v2/.env. Access them in steps via Cypress.env():
Cypress.env('MASTER_EMAIL') // superadmin@novavirtual.site
Cypress.env('MASTER_PASSWORD') // a1234
Cypress.env('ADMIN_EMAIL') // admin@novavirtual.site
Cypress.env('ADMIN_PASSWORD') // Test1234!
Cypress.env('NOVA_ORG_TOKEN') // Nova org token
Cypress.env('BASE_URL') // http://localhost:3001Running your new test
Single file while developing:
docker compose --profile test run --rm e2e-v2 sh -c "npm install && cypress run --spec 'cypress/e2e/features/03_employees/employees.feature'"Full suite before merging:
make test-run