|
| 1 | +--- |
| 2 | +description: Comprehensive guidelines for creating and maintaining Cypress E2E tests including Robot Framework migrations and new feature testing |
| 3 | +globs: [] |
| 4 | +alwaysApply: false |
| 5 | +--- |
| 6 | +# Cypress E2E Test Rules |
| 7 | + |
| 8 | +## Test Sources & Context Requirements |
| 9 | + |
| 10 | +**CRITICAL**: Always ask for context before implementing any test. Never proceed without understanding the test source and purpose. |
| 11 | + |
| 12 | +### Test Source Indicators |
| 13 | + |
| 14 | +**Robot Framework Conversions**: |
| 15 | +- JIRA issues mentioning "Robot Framework", "Robot test", or "migration" |
| 16 | +- References to existing Robot test files or ODS-CI repository |
| 17 | +- Tags like "ODS-XXXX" referring to original Robot test tickets |
| 18 | + |
| 19 | +**New Feature Tests**: |
| 20 | +- JIRA epics for new dashboard features |
| 21 | +- Requirements from Miro boards or feature documentation |
| 22 | +- References to new UI components or workflows |
| 23 | + |
| 24 | +### Required Context for Robot Conversions |
| 25 | +1. **Original Robot Framework test code** - Get the complete .robot file content |
| 26 | +2. **JIRA URL context** - Review the original ODS tickets and current migration ticket |
| 27 | +3. **Original test purpose** - Understand the user journey, edge cases, and validation points |
| 28 | +4. **Environment setup** - What test data, users, and cluster state is required |
| 29 | + |
| 30 | +### Required Context for New Features |
| 31 | +1. **JIRA epic and related tickets** - Understand the full feature scope |
| 32 | +2. **Miro boards or design docs** - Review the intended user experience |
| 33 | +3. **Feature documentation** - Check for API changes, new components, or workflows |
| 34 | +4. **Existing mock tests** - Verify if component-level tests already exist |
| 35 | + |
| 36 | +### E2E vs Mock Tests |
| 37 | +- **E2E Tests**: End-to-end user journeys on live clusters with real backend APIs |
| 38 | +- **Mock Tests**: Component testing with mocked backends for faster, isolated testing |
| 39 | +- Both serve different purposes - E2E tests verify full system integration |
| 40 | + |
| 41 | +### Implementation Approach |
| 42 | +1. **Gather Context** - Always ask for and review all context before starting |
| 43 | +2. **Review Existing Tests** - Search for similar tests in the e2e directory first |
| 44 | +3. **Plan Structure** - Break down into utilities, fixtures, and test scenarios |
| 45 | +4. **Implement with Standards** - Follow all patterns below |
| 46 | +5. **Verify and Test** - Run linting and ensure test quality |
| 47 | + |
| 48 | +## Framework Structure and Standards |
| 49 | + |
| 50 | +### Folder Structure |
| 51 | +``` |
| 52 | +frontend/src/__tests__/cypress/cypress/ |
| 53 | +├── fixtures/e2e/ # Test data files (YAML only) |
| 54 | +├── pages/ # Page Object Model files |
| 55 | +├── tests/e2e/ # Test files organized by feature area |
| 56 | +├── utils/ # Utility functions |
| 57 | +│ ├── oc_commands/ # OpenShift CLI operations |
| 58 | +│ └── ... # Other utilities |
| 59 | +└── types.ts # Type definitions |
| 60 | +``` |
| 61 | + |
| 62 | +### Test Data Management |
| 63 | + |
| 64 | +**Use test-variables.yml for user data**: |
| 65 | +- User configuration is ALWAYS stored in `test-variables.yml` |
| 66 | +- Reference users, buckets, clusters from this file like other tests |
| 67 | +- Use `test-variables.yml.example` as template for what gets checked in |
| 68 | +- Load test variables: `cy.getTestConfig().then((config) => { ... })` |
| 69 | + |
| 70 | +**Fixture files for test configuration**: |
| 71 | +- Store test-specific data in YAML fixture files |
| 72 | +- Use descriptive names like `testFeatureName.yaml` |
| 73 | +- Load fixtures: `cy.fixture('e2e/path/file.yaml')` |
| 74 | +- **NEVER include tags in fixture files** - tags are subject to change and belong in test files (see below for tagging convention) |
| 75 | +- **NEVER include user credentials in fixtures** - use test-variables.yml |
| 76 | + |
| 77 | +**Tagging convention**: |
| 78 | +- Tags should be specified in the test file, in the `it()` block options, e.g. `it('...', { tags: ['@Tag'] }, ...)` |
| 79 | +- Never include tags in fixture files. |
| 80 | +- See [project tagging guidelines](#) for more details (update with actual link if available). |
| 81 | + |
| 82 | +**No interfaces for test data**: |
| 83 | +- Don't create TypeScript interfaces for test data |
| 84 | +- Use direct object access patterns like other tests |
| 85 | +- Follow existing patterns in the codebase |
| 86 | + |
| 87 | +### Test Organization |
| 88 | + |
| 89 | +**File naming**: Use descriptive names matching feature area |
| 90 | +- `testFeatureName.cy.ts` for main functionality |
| 91 | +- Group related tests in feature directories |
| 92 | + |
| 93 | +**Test structure**: |
| 94 | +```typescript |
| 95 | +describe('Feature Name', () => { |
| 96 | + // No beforeEach - not standard pattern |
| 97 | + |
| 98 | + before(() => { |
| 99 | + // Setup only what's absolutely necessary |
| 100 | + }); |
| 101 | + |
| 102 | + after(() => { |
| 103 | + // Cleanup only |
| 104 | + }); |
| 105 | + |
| 106 | + it('should describe specific behavior', { tags: ['@Tag'] }, () => { |
| 107 | + // Test implementation |
| 108 | + }); |
| 109 | +}); |
| 110 | +``` |
| 111 | + |
| 112 | +### Navigation and Page Interactions |
| 113 | + |
| 114 | +**MANDATORY: Use page objects for ALL UI interactions**: |
| 115 | +- **NEVER use `cy.findByTestId()` directly in tests** |
| 116 | +- **NEVER use `cy.findByRole()` directly in tests** |
| 117 | +- **Do NOT call `cy.get()` directly in test files; use it only inside page-object `find...` helper methods.** |
| 118 | +- All UI interactions must go through page objects |
| 119 | +- If a test ID exists but no page object, create the page object method |
| 120 | +- If a test ID doesn't exist, create both the test ID and page object method |
| 121 | +- Search existing page objects first before creating new ones |
| 122 | +- Example: `projectDetails.findSectionTab('cluster-storages').click()` |
| 123 | + |
| 124 | +**Page object requirements**: |
| 125 | +- All selectors must be encapsulated in page object methods |
| 126 | +- Page objects should return Cypress chainables or other page objects |
| 127 | +- Use descriptive method names that indicate the action or element |
| 128 | +- Group related functionality in the same page object class |
| 129 | + |
| 130 | +**Navigation patterns**: |
| 131 | +- Use `.navigate()` methods when available instead of `cy.visit()` |
| 132 | +- Example: `projectListPage.navigate()` instead of `cy.visit('/projects')` |
| 133 | +- Follow navigation patterns from existing tests |
| 134 | + |
| 135 | +**Step documentation**: |
| 136 | +- Use `cy.step('Description')` instead of `cy.log()` |
| 137 | +- Steps auto-number and provide better test reporting |
| 138 | +- Be descriptive about what each step accomplishes |
| 139 | + |
| 140 | +### Waiting and Timing |
| 141 | + |
| 142 | +**No arbitrary waits**: |
| 143 | +- Never use `cy.wait(milliseconds)` for arbitrary time periods |
| 144 | +- Use OC commands to wait for resource state changes |
| 145 | +- Wait for specific UI elements with proper selectors |
| 146 | +- Use retryable assertions with should() statements |
| 147 | + |
| 148 | +**OC command waiting**: |
| 149 | +```typescript |
| 150 | +// Wait for resource readiness using OC commands |
| 151 | +cy.exec('oc wait --for=condition=Ready pod/my-pod --timeout=300s'); |
| 152 | +``` |
| 153 | + |
| 154 | +### Validation Patterns |
| 155 | + |
| 156 | +**Prefer test IDs over text validation**: |
| 157 | +- Use `data-testid` attributes for validation when possible |
| 158 | +- Avoid text-based assertions unless absolutely necessary |
| 159 | +- Text can change, test IDs provide stable selectors |
| 160 | + |
| 161 | +**Validation examples**: |
| 162 | +```typescript |
| 163 | +// Good: Test ID validation through page objects |
| 164 | +pageObject.findStatusIndicator().should('have.attr', 'data-testid', 'status-ready'); |
| 165 | + |
| 166 | +// Acceptable when needed: Text validation with proper page object |
| 167 | +pageObject.findStatusText().should('contain', 'Running'); |
| 168 | +``` |
| 169 | + |
| 170 | +### Utility Functions |
| 171 | + |
| 172 | +**OC commands in utilities**: |
| 173 | +- All OpenShift CLI operations must be in `utils/oc_commands/` |
| 174 | +- Group by functionality (e.g., `pvcManagement.ts`, `projectOperations.ts`) |
| 175 | +- Return Cypress chainables for test integration |
| 176 | + |
| 177 | +**API requests in utilities**: |
| 178 | +- All API calls must be in utility functions in `utils/` |
| 179 | +- Don't make inline API requests in tests |
| 180 | +- Provide clear error handling and logging |
| 181 | + |
| 182 | +### Code Quality and Linting |
| 183 | + |
| 184 | +**MANDATORY: Always lint before claiming test is complete**: |
| 185 | + |
| 186 | +> **Linting/fixing commands (frontend only):** |
| 187 | +> - From the frontend directory, run: |
| 188 | +> ```bash |
| 189 | +> npm run test:lint |
| 190 | +> npm run test:fix |
| 191 | +> ``` |
| 192 | + |
| 193 | +**All linting errors must be fixed**: |
| 194 | +- No test is ready until ALL linting errors are resolved |
| 195 | +- Use object destructuring for variables |
| 196 | +- Proper formatting and spacing |
| 197 | +- No unused variables or imports |
| 198 | +- No `any` types unless absolutely necessary |
| 199 | +- Follow existing code patterns |
| 200 | + |
| 201 | +### Reusability and Research |
| 202 | + |
| 203 | +**Search existing tests first**: |
| 204 | +- Before writing new page objects, search for existing ones |
| 205 | +- Look for similar test patterns in the e2e directory |
| 206 | +- Reuse existing utility functions and patterns |
| 207 | +- Example: Search for "workbench" or "cluster storage" tests |
| 208 | + |
| 209 | +**Page object reuse**: |
| 210 | +- Use existing page objects like `projectDetails`, `clusterStorage` |
| 211 | +- Extend existing page objects rather than duplicating |
| 212 | +- Follow established patterns for new page objects |
| 213 | + |
| 214 | +### Test Independence |
| 215 | + |
| 216 | +**Each test should be independent**: |
| 217 | +- Tests should not depend on other tests running first |
| 218 | +- Clean up test artifacts after each test |
| 219 | +- Use unique identifiers (UUIDs) for test resources |
| 220 | + |
| 221 | +**Resource cleanup**: |
| 222 | +- Delete test projects, PVCs, and other resources after tests |
| 223 | +- Use `after()` hooks for cleanup |
| 224 | +- Handle cleanup failures gracefully |
| 225 | + |
| 226 | +### Error Handling |
| 227 | + |
| 228 | +**Robust error handling**: |
| 229 | +- Handle expected failure scenarios |
| 230 | +- Provide clear error messages |
| 231 | +- Use proper Cypress assertions and retries |
| 232 | + |
| 233 | +**Debug information**: |
| 234 | +- Log important test state and variables |
| 235 | +- Use descriptive step names for troubleshooting |
| 236 | +- Capture relevant system state on failures |
| 237 | + |
| 238 | +## Implementation Checklist |
| 239 | + |
| 240 | +Before writing any test: |
| 241 | +- [ ] Gathered all required context (Robot code, JIRA details, etc.) |
| 242 | +- [ ] Searched for existing similar tests to reuse patterns |
| 243 | +- [ ] Reviewed existing page objects and utilities |
| 244 | +- [ ] Planned test data strategy using test-variables.yml |
| 245 | +- [ ] Identified reusable components and utilities needed |
| 246 | + |
| 247 | +During implementation: |
| 248 | +- [ ] Use page objects for ALL UI interactions (no direct cy.findByTestId, cy.findByRole, cy.get) |
| 249 | +- [ ] Create page object methods for any missing test IDs or UI elements |
| 250 | +- [ ] Follow navigation patterns (.navigate() over cy.visit()) |
| 251 | +- [ ] Use cy.step() for test documentation |
| 252 | +- [ ] Implement proper waiting strategies (no cy.wait()) |
| 253 | +- [ ] Prefer test ID validation over text validation |
| 254 | +- [ ] Place OC commands and API calls in utility functions |
| 255 | +- [ ] Never include tags in fixture files |
| 256 | + |
| 257 | +After implementation: |
| 258 | +- [ ] Run linting: `npm run test:lint && npm run test:fix` (from the frontend directory) |
| 259 | +- [ ] Fix ALL linting errors before claiming test is complete |
| 260 | +- [ ] Verify test independence and cleanup |
| 261 | +- [ ] Test on clean environment |
| 262 | +- [ ] Document any new page objects or utilities created |
| 263 | + |
| 264 | +## Pre-Execution Checklist: Test Variables & Cluster Connection |
| 265 | + |
| 266 | +**MANDATORY: Before running any E2E test, ensure the following:** |
| 267 | + |
| 268 | +1. **Test Variables Configuration** |
| 269 | + - Update `test-variables.yml` with the correct user credentials, cluster details, and any other required test data. |
| 270 | + - Ensure the users, buckets, and clusters referenced in the test exist and match the current environment. |
| 271 | + - If unsure, review `test-variables.yml.example` for required fields. |
| 272 | + |
| 273 | +2. **Cluster Connection** |
| 274 | + - Confirm you are connected to the correct OpenShift/Kubernetes cluster where the test will run. |
| 275 | + - Your `oc` CLI context should match the cluster referenced in `test-variables.yml`. |
| 276 | + - Run `oc whoami` and `oc config current-context` to verify your connection. |
| 277 | + |
| 278 | +3. **User Prompt Before Test Execution** |
| 279 | + - Always prompt the user to: |
| 280 | + - Provide or confirm the test variable details (users, cluster, etc.) |
| 281 | + - Confirm cluster connection and context |
| 282 | + - Do not proceed with test execution until these details are confirmed. |
| 283 | + |
| 284 | +**Checklist Before Running E2E Test:** |
| 285 | +- [ ] Updated `test-variables.yml` with correct users and cluster details |
| 286 | +- [ ] Confirmed connection to the correct cluster (`oc whoami`, `oc config current-context`) |
| 287 | +- [ ] User has provided/confirmed all required test variable and cluster details |
| 288 | + |
| 289 | +## Test Execution & Failure Handling |
| 290 | + |
| 291 | +**After user confirms test variables and cluster connection:** |
| 292 | + |
| 293 | +1. **Run the E2E Test(s):** |
| 294 | + - Execute the created E2E test(s) against the connected cluster. |
| 295 | + - Use Cypress in headless mode for automated runs, or Cypress open mode for live debugging if requested or if failures occur. |
| 296 | + |
| 297 | +2. **Test Passes:** |
| 298 | + - If the test passes, proceed as normal and report success. |
| 299 | + |
| 300 | +3. **Test Fails:** |
| 301 | + - If the test fails: |
| 302 | + - Perform a basic analysis of the failure output/logs. |
| 303 | + - Hypothesize possible causes and suggest next steps or fixes. |
| 304 | + - Recommend running the test in Cypress open mode (`cypress open`) to allow the user to observe the test execution live and assist with debugging. |
| 305 | + |
| 306 | +**Checklist:** |
| 307 | +- [ ] Run E2E test(s) after user confirmation |
| 308 | +- [ ] If test fails, analyze output and suggest fixes |
| 309 | +- [ ] Offer Cypress open mode for live debugging |
| 310 | + |
| 311 | +## Namespace Handling for OC Commands |
| 312 | + |
| 313 | +**MANDATORY: Never hardcode namespaces in tests or utilities.** |
| 314 | +- Always derive namespaces from test variables, typically using `Cypress.env('APPLICATIONS_NAMESPACE')` or similar environment variables loaded from `test-variables.yml`. |
| 315 | +- This ensures tests are portable between RHOAI and ODH environments, where namespaces may differ. |
| 316 | +- When writing or updating utilities, accept the namespace as a parameter or use the environment variable as the default. |
| 317 | +- Review existing utilities in `oc_commands/` for examples of this pattern. |
| 318 | + |
| 319 | +## Cypress Test Execution Directory and Input Handling |
| 320 | + |
| 321 | +- When running Cypress tests, always run from the correct directory (e.g., 'frontend') so that the --project flag is relative to that directory. |
| 322 | +- Do not use absolute or user-specific paths in scripts or documentation; use relative paths for portability. |
| 323 | +- When updating input fields in E2E tests, always clear the field before typing a new value to avoid concatenation issues (e.g., use .clear().type('newValue')). |
| 324 | + |
| 325 | +## Page Object and Test Action Separation |
| 326 | + |
| 327 | +- All page object methods named `find...` must only return Cypress chainables for elements, never perform actions (e.g., no `.click()` or `.type()` inside the method). |
| 328 | +- All actions (e.g., `.click()`, `.type()`) must be performed in the test itself, not inside the page object method. |
| 329 | +- When updating cluster settings or any backend-driven config, always verify the backend value is updated (e.g., using `cy.getDashboardConfig`) before proceeding to UI validation or further steps. |
| 330 | +- Always add `data-testid` attributes to the UI and corresponding `find...` methods in page objects whenever a test needs to interact with or validate an element. |
0 commit comments