Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
282 changes: 282 additions & 0 deletions tests/PATTERNFLY_COMMANDS_EXAMPLES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
# PatternFly Cypress Commands - Usage Examples

This file provides comprehensive examples of PatternFly-aware Cypress commands for distributed tracing UI testing, focusing on semantic selectors and efficient testing patterns.

## ✅ Recommended Usage Patterns

### 1. Simple Component Interactions

```typescript
// Empty State - Clean and reliable
cy.pfEmptyState().within(() => {
cy.byRole('heading').should('contain', 'No items found');
});

// Buttons - Direct and stable
cy.pfButton('Create Instance').click();
cy.pfButton('Save Changes').should('be.disabled');
cy.pfButton('Cancel').should('be.visible');
```

### 2. Menu Navigation

```typescript
// Basic menu toggle
cy.pfMenuToggle('Select Instance').click();
cy.pfMenuItem('TempoStack').click();

// Or with error handling for dynamic content
cy.get('body').then(($body) => {
if ($body.find('.pf-v6-c-menu-toggle:contains("Create Instance")').length > 0) {
cy.pfMenuToggle('Create Instance').click();
cy.pfMenuItem('TempoStack Instance').click();
}
});
```

### 3. Toolbar Interactions (Recommended Approach)

```typescript
// Simple toolbar item selection
cy.pfToolbarItem(0).within(() => {
cy.get('.pf-v6-c-menu-toggle, .pf-v5-c-menu-toggle').first().click();
});
cy.get('.pf-v6-c-menu__item, .pf-v5-c-menu__item').contains('Option 1').click();

// Wait for stability between interactions
cy.wait(1000);
cy.pfToolbarItem(1).within(() => {
cy.get('.pf-v6-c-menu-toggle, .pf-v5-c-menu-toggle').first().click();
});
```

### 4. Form Interactions

```typescript
// Using label-based selection
cy.byLabelText('Instance Name').type('my-instance');
cy.byLabelText('Namespace').select('default');

// Form submission
cy.pfButton('Submit').click();
```

## 🆕 New Distributed Tracing UI Commands

### Menu & Dropdown Interactions

```typescript
// Tempo instance selection
cy.pfTypeahead('Select a Tempo instance').click();
cy.pfSelectMenuItem('chainsaw-rbac / simplst').click();

// Service filtering with checkboxes
cy.pfMenuToggleByLabel('Multi typeahead checkbox').click();
cy.pfCheckMenuItem('http-rbac-1');
cy.pfCheckMenuItem('http-rbac-2', true); // Explicitly check
cy.pfCheckMenuItem('grpc-rbac-1', false); // Uncheck

// Time range selection
cy.pfMenuToggle('Last 30 minutes').click();
cy.pfSelectMenuItem('Last 1 hour').click();
```

### Navigation Commands

```typescript
// Breadcrumb navigation
cy.pfBreadcrumb('Traces').click();
cy.pfBreadcrumb('Observability').should('be.visible');

// Close buttons (chip groups, modals, etc.)
cy.pfCloseButton('Close chip group').click(); // PatternFly 5
cy.pfCloseButton('Close label group').click(); // PatternFly 6
cy.pfCloseButton().click(); // First close button found (any version)
```

### Trace & Span Interactions

```typescript
// Click on traces
cy.muiFirstTraceLink().click(); // First trace in list
cy.muiTraceLink('http-rbac-2').click(); // Specific service trace

// Interact with span bars
cy.muiFirstSpanBar().click(); // First span bar
cy.muiSpanBar('http-rbac-2').click(); // Specific service span
cy.findByTestId('span-duration-bar').first().click(); // By test ID (multiple spans)
```

### Trace Attribute Validation

```typescript
// Single attribute validation
cy.muiTraceAttribute('net.peer.ip', '1.2.3.4');
cy.muiTraceAttribute('peer.service', 'telemetrygen-client');
cy.muiTraceAttribute('k8s.container.name', 'telemetrygen', true); // Optional attribute

// Custom validation with function
cy.muiTraceAttribute('service.name', (text) => {
return ['http-rbac-1', 'http-rbac-2', 'grpc-rbac-1', 'grpc-rbac-2'].includes(text);
}, false, 'TempoStack'); // Required attribute with logging

// Bulk attribute validation (recommended for multiple attributes)
cy.muiTraceAttributes({
'net.peer.ip': { value: '1.2.3.4' },
'peer.service': { value: 'telemetrygen-client' },
'k8s.container.name': {
value: 'telemetrygen',
optional: true
},
'k8s.namespace.name': {
value: (text) => text.startsWith('chainsaw-'),
optional: true
},
'service.name': {
value: ['http-rbac-1', 'http-rbac-2', 'grpc-rbac-1', 'grpc-rbac-2']
}
}, 'Debug'); // Log prefix for debugging
```

### Complete Workflow Examples

```typescript
// Complete trace inspection workflow
describe('Trace inspection', () => {
it('should navigate and validate trace details', () => {
// Navigate to traces page
cy.visit('/observe/traces');

// Select Tempo instance
cy.pfTypeahead('Select a Tempo instance').click();
cy.pfSelectMenuItem('chainsaw-rbac / simplst').click();

// Set time range
cy.pfMenuToggle('Last 30 minutes').click();
cy.pfSelectMenuItem('Last 1 hour').click();

// Filter by services
cy.pfMenuToggleByLabel('Multi typeahead checkbox').click();
cy.pfCheckMenuItem('http-rbac-1');
cy.pfCheckMenuItem('http-rbac-2');

// Click first trace
cy.muiFirstTraceLink().click();

// Click on span for details
cy.muiFirstSpanBar().click();

// Validate trace attributes efficiently
cy.muiTraceAttributes({
'net.peer.ip': { value: '1.2.3.4' },
'peer.service': { value: 'telemetrygen-client' },
'service.name': {
value: (text) => text.includes('rbac')
}
});

// Navigate back
cy.pfBreadcrumb('Traces').click();
});
});
```

## 🔄 PatternFly 5 & 6 Compatibility

Our commands seamlessly support both PatternFly 5 and PatternFly 6 components:

### Close Buttons

```typescript
// PatternFly 5 - Chip Group
// <button aria-label="Close chip group" class="pf-v5-c-button pf-m-plain">
cy.pfCloseButton('Close chip group').click();

// PatternFly 6 - Label Group
// <button aria-label="Close label group" class="pf-v6-c-button pf-m-plain pf-m-no-padding">
cy.pfCloseButton('Close label group').click();

// Works with both versions automatically
cy.pfCloseButton('Close').click(); // Finds any close button
```

### Menu Components

```typescript
// Both PF5 and PF6 menu structures supported
cy.pfMenuToggle('Select Instance').click(); // Works with .pf-v5-c-menu-toggle or .pf-v6-c-menu-toggle
cy.pfSelectMenuItem('tempo-stack').click(); // Works with .pf-v5-c-menu__item or .pf-v6-c-menu__item
cy.pfCheckMenuItem('service-name'); // Handles both PF5/PF6 checkbox patterns
```

### Button Components

```typescript
// PatternFly button targeting (version-agnostic)
cy.pfButton('Create Instance').click(); // Targets .pf-v5-c-button or .pf-v6-c-button
cy.pfEmptyState().should('be.visible'); // Works with both .pf-v5-c-empty-state and .pf-v6-c-empty-state
```

### Key Benefits

- ✅ **Automatic detection** - Commands work with both PF5 and PF6 automatically
- ✅ **Future-proof** - Ready for PatternFly version upgrades
- ✅ **Consistent API** - Same command syntax across versions
- ✅ **Robust selectors** - Uses semantic attributes over version-specific classes

## 🛡️ Defensive Programming Patterns

### 1. Check Element Existence

```typescript
// Safe menu interaction
cy.get('body').then(($body) => {
if ($body.find('.pf-v6-c-menu-toggle:contains("Actions")').length > 0) {
cy.pfMenuToggle('Actions').click();
if ($body.find('.pf-v6-c-menu__item:contains("Delete")').length > 0) {
cy.pfMenuItem('Delete').click();
}
}
});
```

### 2. Wait for Stability

```typescript
// Wait for page load and React hydration
cy.visit('/traces');
cy.wait(2000); // Allow initial React state to settle

// Perform interactions
cy.pfEmptyState().should('be.visible');
cy.pfButton('Create Instance').click();
```

### 3. Use Timeouts

```typescript
// Custom timeouts for slow-loading components
cy.pfMenuToggle('Select Instance', { timeout: 15000 }).click();
cy.pfMenuItem('TempoStack', { timeout: 10000 }).click();
```

## 🎯 Best Practices Summary

1. **Add waits between complex interactions** to let React state stabilize
2. **Use defensive checks** for dynamic content
3. **Prefer direct PatternFly commands** over complex CSS selectors
4. **Break complex operations** into smaller, testable steps
5. **Handle uncaught exceptions** gracefully in support files
6. **Use timeouts** for components that load asynchronously

## 🔧 Troubleshooting

If you encounter "e is not a function" errors:

1. **Add `cy.wait(1000-2000)`** between interactions
2. **Check if elements exist** before interacting
3. **Use more specific selectors** instead of nth-child
4. **Verify React components have finished rendering**
5. **Review browser console** for additional React errors

These patterns will make your tests more reliable and less prone to React state management issues.
99 changes: 88 additions & 11 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,25 @@ node_modules/ -> dependencies will be installed at runtime here
## Directory structure
After dependencies are installed successfully and before we run actual tests, please confirm if we have correct structure as below.
```bash
% ls -ltr tests
drwxr-xr-x views
-rw-r--r-- reporter-config.json
-rw-r--r-- package.json
drwxr-xr-x node_modules
drwxr-xr-x cypress
-rw-r--r-- cypress.config.ts
-rw-r--r-- README.md
drwxr-xr-x tests
-rw-r--r-- tsconfig.json
drwxr-xr-x fixtures
tree -L 1
.
├── cypress
├── cypress.config.ts
├── Dockerfile
├── Dockerfile-cypress
├── e2e
├── fixtures
├── node_modules
├── package-lock.json
├── package.json
├── PATTERNFLY_COMMANDS_EXAMPLES.md
├── README.md
├── reporter-config.json
├── SELECTOR_BEST_PRACTICES.md
├── tsconfig.json
└── views

6 directories, 10 files
````

### Export necessary variables
Expand Down Expand Up @@ -77,4 +85,73 @@ We can either open Cypress GUI(open) or run Cypress in headless mode(run) to run
```bash
npx cypress open
npx cypress run

# Run specific test files
npx cypress run --spec "e2e/dt-plugin-tests.cy.ts"

# Skip debug files during CI runs
npx cypress run --ignore-pattern "**/*debug*.cy.ts"
```

## Test Architecture & Best Practices

### Custom Commands
This project includes a comprehensive set of custom Cypress commands optimized for PatternFly and Material-UI components. These commands provide:

- **Semantic selectors** instead of brittle CSS selectors
- **Component-aware interactions** for PatternFly elements
- **Bulk validation** for trace attributes (75% code reduction)
- **Debug-friendly** commands with built-in logging

### Key Command Categories

#### PatternFly Components
```typescript
// Menu interactions
cy.pfMenuToggle('Select Instance').click()
cy.pfSelectMenuItem('tempo-stack').click()
cy.pfCheckMenuItem('service-name')

// Navigation
cy.pfBreadcrumb('Traces').click()
cy.pfButton('Create').click()
cy.pfCloseButton('Close dialog').click()

// Form controls
cy.pfTypeahead('Select a Tempo instance').click()
cy.pfMenuToggleByLabel('Multi typeahead').click()
```

#### Trace & Observability
```typescript
// Trace interactions
cy.muiFirstTraceLink().click()
cy.muiTraceLink('http-service').click()
cy.muiSpanBar('grpc-service').click()

// Attribute validation (bulk)
cy.muiTraceAttributes({
'service.name': { value: 'my-service' },
'net.peer.ip': { value: '1.2.3.4' },
'k8s.namespace': { value: 'test-ns', optional: true }
})
```

### Debug Testing
A debug test file (`dt-plugin-tests-debug.cy.ts.skip`) is available for rapid iteration without setup/teardown overhead. To use:

```bash
# Enable debug test
mv tests/e2e/dt-plugin-tests-debug.cy.ts.skip tests/e2e/dt-plugin-tests-debug.cy.ts

# Run debug test only
npx cypress run --spec "e2e/dt-plugin-tests-debug.cy.ts"

# Disable debug test
mv tests/e2e/dt-plugin-tests-debug.cy.ts tests/e2e/dt-plugin-tests-debug.cy.ts.skip
```

### Documentation
- **SELECTOR_BEST_PRACTICES.md** - Comprehensive selector guidelines and command usage
- **PATTERNFLY_COMMANDS_EXAMPLES.md** - Complete command examples and workflows
- **README.md** - This file with setup and architecture overview
Loading