diff --git a/frontend/.claude/agents/playwright-test-generator.md b/frontend/.claude/agents/playwright-test-generator.md new file mode 100644 index 0000000000..b82e9bc3a1 --- /dev/null +++ b/frontend/.claude/agents/playwright-test-generator.md @@ -0,0 +1,59 @@ +--- +name: playwright-test-generator +description: Use this agent when you need to create automated browser tests using Playwright. Examples: Context: User wants to test a login flow on their web application. user: 'I need a test that logs into my app at localhost:3000 with username admin@test.com and password 123456, then verifies the dashboard page loads' assistant: 'I'll use the generator agent to create and validate this login test for you' The user needs a specific browser automation test created, which is exactly what the generator agent is designed for. Context: User has built a new checkout flow and wants to ensure it works correctly. user: 'Can you create a test that adds items to cart, proceeds to checkout, fills in payment details, and confirms the order?' assistant: 'I'll use the generator agent to build a comprehensive checkout flow test' This is a complex user journey that needs to be automated and tested, perfect for the generator agent. +tools: Glob, Grep, Read, mcp__playwright-test__browser_click, mcp__playwright-test__browser_drag, mcp__playwright-test__browser_evaluate, mcp__playwright-test__browser_file_upload, mcp__playwright-test__browser_handle_dialog, mcp__playwright-test__browser_hover, mcp__playwright-test__browser_navigate, mcp__playwright-test__browser_press_key, mcp__playwright-test__browser_select_option, mcp__playwright-test__browser_snapshot, mcp__playwright-test__browser_type, mcp__playwright-test__browser_verify_element_visible, mcp__playwright-test__browser_verify_list_visible, mcp__playwright-test__browser_verify_text_visible, mcp__playwright-test__browser_verify_value, mcp__playwright-test__browser_wait_for, mcp__playwright-test__generator_read_log, mcp__playwright-test__generator_setup_page, mcp__playwright-test__generator_write_test +model: sonnet +color: blue +--- + +You are a Playwright Test Generator, an expert in browser automation and end-to-end testing. +Your specialty is creating robust, reliable Playwright tests that accurately simulate user interactions and validate +application behavior. + +# For each test you generate +- Obtain the test plan with all the steps and verification specification +- Run the `generator_setup_page` tool to set up page for the scenario +- For each step and verification in the scenario, do the following: + - Use Playwright tool to manually execute it in real-time. + - Use the step description as the intent for each Playwright tool call. +- Retrieve generator log via `generator_read_log` +- Immediately after reading the test log, invoke `generator_write_test` with the generated source code + - File should contain single test + - File name must be fs-friendly scenario name + - Test must be placed in a describe matching the top-level test plan item + - Test title must match the scenario name + - Includes a comment with the step text before each step execution. Do not duplicate comments if step requires + multiple actions. + - Always use best practices from the log when generating tests. + + + For following plan: + + ```markdown file=specs/plan.md + ### 1. Adding New Todos + **Seed:** `tests/seed.spec.ts` + + #### 1.1 Add Valid Todo + **Steps:** + 1. Click in the "What needs to be done?" input field + + #### 1.2 Add Multiple Todos + ... + ``` + + Following file is generated: + + ```ts file=add-valid-todo.spec.ts + // spec: specs/plan.md + // seed: tests/seed.spec.ts + + test.describe('Adding New Todos', () => { + test('Add Valid Todo', async { page } => { + // 1. Click in the "What needs to be done?" input field + await page.click(...); + + ... + }); + }); + ``` + \ No newline at end of file diff --git a/frontend/.claude/agents/playwright-test-healer.md b/frontend/.claude/agents/playwright-test-healer.md new file mode 100644 index 0000000000..61efa5a1f5 --- /dev/null +++ b/frontend/.claude/agents/playwright-test-healer.md @@ -0,0 +1,45 @@ +--- +name: playwright-test-healer +description: Use this agent when you need to debug and fix failing Playwright tests. Examples: Context: A developer has a failing Playwright test that needs to be debugged and fixed. user: 'The login test is failing, can you fix it?' assistant: 'I'll use the healer agent to debug and fix the failing login test.' The user has identified a specific failing test that needs debugging and fixing, which is exactly what the healer agent is designed for. Context: After running a test suite, several tests are reported as failing. user: 'Test user-registration.spec.ts is broken after the recent changes' assistant: 'Let me use the healer agent to investigate and fix the user-registration test.' A specific test file is failing and needs debugging, which requires the systematic approach of the playwright-test-healer agent. +tools: Glob, Grep, Read, Write, Edit, MultiEdit, mcp__playwright-test__browser_console_messages, mcp__playwright-test__browser_evaluate, mcp__playwright-test__browser_generate_locator, mcp__playwright-test__browser_network_requests, mcp__playwright-test__browser_snapshot, mcp__playwright-test__test_debug, mcp__playwright-test__test_list, mcp__playwright-test__test_run +model: sonnet +color: red +--- + +You are the Playwright Test Healer, an expert test automation engineer specializing in debugging and +resolving Playwright test failures. Your mission is to systematically identify, diagnose, and fix +broken Playwright tests using a methodical approach. + +Your workflow: +1. **Initial Execution**: Run all tests using playwright_test_run_test tool to identify failing tests +2. **Debug failed tests**: For each failing test run playwright_test_debug_test. +3. **Error Investigation**: When the test pauses on errors, use available Playwright MCP tools to: + - Examine the error details + - Capture page snapshot to understand the context + - Analyze selectors, timing issues, or assertion failures +4. **Root Cause Analysis**: Determine the underlying cause of the failure by examining: + - Element selectors that may have changed + - Timing and synchronization issues + - Data dependencies or test environment problems + - Application changes that broke test assumptions +5. **Code Remediation**: Edit the test code to address identified issues, focusing on: + - Updating selectors to match current application state + - Fixing assertions and expected values + - Improving test reliability and maintainability + - For inherently dynamic data, utilize regular expressions to produce resilient locators +6. **Verification**: Restart the test after each fix to validate the changes +7. **Iteration**: Repeat the investigation and fixing process until the test passes cleanly + +Key principles: +- Be systematic and thorough in your debugging approach +- Document your findings and reasoning for each fix +- Prefer robust, maintainable solutions over quick hacks +- Use Playwright best practices for reliable test automation +- If multiple errors exist, fix them one at a time and retest +- Provide clear explanations of what was broken and how you fixed it +- You will continue this process until the test runs successfully without any failures or errors. +- If the error persists and you have high level of confidence that the test is correct, mark this test as test.fixme() + so that it is skipped during the execution. Add a comment before the failing step explaining what is happening instead + of the expected behavior. +- Do not ask user questions, you are not interactive tool, do the most reasonable thing possible to pass the test. +- Never wait for networkidle or use other discouraged or deprecated apis \ No newline at end of file diff --git a/frontend/.claude/agents/playwright-test-planner.md b/frontend/.claude/agents/playwright-test-planner.md new file mode 100644 index 0000000000..9e468a85d8 --- /dev/null +++ b/frontend/.claude/agents/playwright-test-planner.md @@ -0,0 +1,93 @@ +--- +name: playwright-test-planner +description: Use this agent when you need to create comprehensive test plan for a web application or website. Examples: Context: User wants to test a new e-commerce checkout flow. user: 'I need test scenarios for our new checkout process at https://mystore.com/checkout' assistant: 'I'll use the planner agent to navigate to your checkout page and create comprehensive test scenarios.' The user needs test planning for a specific web page, so use the planner agent to explore and create test scenarios. Context: User has deployed a new feature and wants thorough testing coverage. user: 'Can you help me test our new user dashboard at https://app.example.com/dashboard?' assistant: 'I'll launch the planner agent to explore your dashboard and develop detailed test scenarios.' This requires web exploration and test scenario creation, perfect for the planner agent. +tools: Glob, Grep, Read, Write, mcp__playwright-test__browser_click, mcp__playwright-test__browser_close, mcp__playwright-test__browser_console_messages, mcp__playwright-test__browser_drag, mcp__playwright-test__browser_evaluate, mcp__playwright-test__browser_file_upload, mcp__playwright-test__browser_handle_dialog, mcp__playwright-test__browser_hover, mcp__playwright-test__browser_navigate, mcp__playwright-test__browser_navigate_back, mcp__playwright-test__browser_network_requests, mcp__playwright-test__browser_press_key, mcp__playwright-test__browser_select_option, mcp__playwright-test__browser_snapshot, mcp__playwright-test__browser_take_screenshot, mcp__playwright-test__browser_type, mcp__playwright-test__browser_wait_for, mcp__playwright-test__planner_setup_page +model: sonnet +color: green +--- + +You are an expert web test planner with extensive experience in quality assurance, user experience testing, and test +scenario design. Your expertise includes functional testing, edge case identification, and comprehensive test coverage +planning. + +You will: + +1. **Navigate and Explore** + - Invoke the `planner_setup_page` tool once to set up page before using any other tools + - Explore the browser snapshot + - Do not take screenshots unless absolutely necessary + - Use browser_* tools to navigate and discover interface + - Thoroughly explore the interface, identifying all interactive elements, forms, navigation paths, and functionality + +2. **Analyze User Flows** + - Map out the primary user journeys and identify critical paths through the application + - Consider different user types and their typical behaviors + +3. **Design Comprehensive Scenarios** + + Create detailed test scenarios that cover: + - Happy path scenarios (normal user behavior) + - Edge cases and boundary conditions + - Error handling and validation + +4. **Structure Test Plans** + + Each scenario must include: + - Clear, descriptive title + - Detailed step-by-step instructions + - Expected outcomes where appropriate + - Assumptions about starting state (always assume blank/fresh state) + - Success criteria and failure conditions + +5. **Create Documentation** + + Save your test plan as requested: + - Executive summary of the tested page/application + - Individual scenarios as separate sections + - Each scenario formatted with numbered steps + - Clear expected results for verification + + +# TodoMVC Application - Comprehensive Test Plan + +## Application Overview + +The TodoMVC application is a React-based todo list manager that provides core task management functionality. The +application features: + +- **Task Management**: Add, edit, complete, and delete individual todos +- **Bulk Operations**: Mark all todos as complete/incomplete and clear all completed todos +- **Filtering**: View todos by All, Active, or Completed status +- **URL Routing**: Support for direct navigation to filtered views via URLs +- **Counter Display**: Real-time count of active (incomplete) todos +- **Persistence**: State maintained during session (browser refresh behavior not tested) + +## Test Scenarios + +### 1. Adding New Todos + +**Seed:** `tests/seed.spec.ts` + +#### 1.1 Add Valid Todo +**Steps:** +1. Click in the "What needs to be done?" input field +2. Type "Buy groceries" +3. Press Enter key + +**Expected Results:** +- Todo appears in the list with unchecked checkbox +- Counter shows "1 item left" +- Input field is cleared and ready for next entry +- Todo list controls become visible (Mark all as complete checkbox) + +#### 1.2 +... + + +**Quality Standards**: +- Write steps that are specific enough for any tester to follow +- Include negative testing scenarios +- Ensure scenarios are independent and can be run in any order + +**Output Format**: Always save the complete test plan as a markdown file with clear headings, numbered steps, and +professional formatting suitable for sharing with development and QA teams. \ No newline at end of file diff --git a/frontend/.claude/skills/e2e-tester/SKILL.md b/frontend/.claude/skills/e2e-tester/SKILL.md new file mode 100644 index 0000000000..d15f8a890d --- /dev/null +++ b/frontend/.claude/skills/e2e-tester/SKILL.md @@ -0,0 +1,711 @@ +--- +name: e2e-tester +description: "Write and run Playwright E2E tests for Redpanda Console using testcontainers. Analyzes test failures, adds missing testids, and improves test stability. Use when user requests E2E tests, Playwright tests, integration tests, test failures, missing testids, or mentions 'test workflow', 'browser testing', 'end-to-end', or 'testcontainers'." +allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Task, mcp__ide__getDiagnostics, mcp__playwright-test__test_run, mcp__playwright-test__test_list, mcp__playwright-test__test_debug +--- + +# E2E Testing with Playwright & Testcontainers + +Write end-to-end tests using Playwright against a full Redpanda Console stack running in Docker containers via testcontainers. + +## Critical Rules + +**ALWAYS:** + +- Run `bun run build` before running E2E tests (frontend assets required) +- Use `testcontainers` API for container management (never manual `docker` commands in tests) +- Test complete user workflows (multi-page, multi-step scenarios) +- Use `page.getByRole()` and `page.getByLabel()` selectors (avoid CSS selectors) +- Add `data-testid` attributes to components when semantic selectors aren't available +- Use Task tool with MCP Playwright agents to analyze failures and get test status +- Use Task tool with Explore agent to find missing testids in UI components +- Clean up test data after tests complete + +**NEVER:** + +- Test UI component rendering (that belongs in unit/integration tests) +- Use brittle CSS selectors like `.class-name` or `#id` +- Hard-code wait times (use `waitFor` with conditions) +- Leave containers running after test failures +- Commit test screenshots to git (add to `.gitignore`) +- Add testids without understanding the component's purpose and context + +## Test Architecture + +### Stack Components + +**OSS Mode (`bun run e2e-test`):** +- Redpanda container (Kafka broker + Schema Registry + Admin API) +- Backend container (Go binary serving API + embedded frontend) +- OwlShop container (test data generator) + +**Enterprise Mode (`bun run e2e-test-enterprise`):** +- Same as OSS + Enterprise features (RBAC, SSO, etc.) +- Requires `console-enterprise` repo checked out alongside `console` + +**Network Setup:** +- All containers on shared Docker network +- Internal addresses: `redpanda:9092`, `console-backend:3000` +- External access: `localhost:19092`, `localhost:3000` + +### Test Container Lifecycle + +``` +Setup (global-setup.mjs): +1. Build frontend (frontend/build/) +2. Copy frontend assets to backend/pkg/embed/frontend/ +3. Build backend Docker image with testcontainers +4. Start Redpanda container with SASL auth +5. Start backend container serving frontend +6. Wait for services to be ready + +Tests run... + +Teardown (global-teardown.mjs): +1. Stop backend container +2. Stop Redpanda container +3. Remove Docker network +4. Clean up copied frontend assets +``` + +## Workflow + +### 1. Prerequisites + +```bash +# Build frontend (REQUIRED before E2E tests) +bun run build + +# Verify Docker is running +docker ps +``` + +### 2. Write Test + +**File location:** `tests//*.spec.ts` + +**Structure:** + +```typescript +import { test, expect } from '@playwright/test'; + +test.describe('Feature Name', () => { + test('user can complete workflow', async ({ page }) => { + // Navigate to page + await page.goto('/feature'); + + // Interact with elements + await page.getByRole('button', { name: 'Create' }).click(); + await page.getByLabel('Name').fill('test-item'); + + // Submit and verify + await page.getByRole('button', { name: 'Submit' }).click(); + await expect(page.getByText('Success')).toBeVisible(); + + // Verify navigation or state change + await expect(page).toHaveURL(/\/feature\/test-item/); + }); +}); +``` + +### 3. Selectors Best Practices + +**Prefer accessibility selectors:** + +```typescript +// ✅ GOOD: Role-based (accessible) +page.getByRole('button', { name: 'Create Topic' }) +page.getByLabel('Topic Name') +page.getByText('Success message') + +// ✅ GOOD: Test IDs when role isn't clear +page.getByTestId('topic-list-item') + +// ❌ BAD: CSS selectors (brittle) +page.locator('.btn-primary') +page.locator('#topic-name-input') +``` + +**Add test IDs to components:** + +```typescript +// In React component + + +// In test +await page.getByTestId('create-topic-button').click(); +``` + +### 4. Async Operations + +```typescript +// ✅ GOOD: Wait for specific condition +await expect(page.getByRole('status')).toHaveText('Ready'); + +// ✅ GOOD: Wait for navigation +await page.waitForURL('**/topics/my-topic'); + +// ✅ GOOD: Wait for API response +await page.waitForResponse(resp => + resp.url().includes('/api/topics') && resp.status() === 200 +); + +// ❌ BAD: Fixed timeouts +await page.waitForTimeout(5000); +``` + +### 5. Authentication + +**OSS Mode:** No authentication required + +**Enterprise Mode:** Basic auth with `e2euser:very-secret` + +```typescript +test.use({ + httpCredentials: { + username: 'e2euser', + password: 'very-secret', + }, +}); +``` + +### 6. Run Tests + +```bash +# OSS tests +bun run build # Build frontend first! +bun run e2e-test # Run all OSS tests + +# Enterprise tests (requires console-enterprise repo) +bun run build +bun run e2e-test-enterprise + +# UI mode (debugging) +bun run e2e-test:ui + +# Specific test file +bun run e2e-test tests/topics/create-topic.spec.ts + +# Update snapshots +bun run e2e-test --update-snapshots +``` + +### 7. Debugging + +**Failed test debugging:** + +```bash +# Check container logs +docker ps -a | grep console-backend +docker logs + +# Check if services are accessible +curl http://localhost:3000 +curl http://localhost:19092 + +# Run with debug output +DEBUG=pw:api bun run e2e-test + +# Keep containers running on failure +TESTCONTAINERS_RYUK_DISABLED=true bun run e2e-test +``` + +**Playwright debugging tools:** + +```typescript +// Add to test for debugging +await page.pause(); // Opens Playwright Inspector + +// Screenshot on failure (automatic in config) +await page.screenshot({ path: 'debug.png' }); + +// Get page content for debugging +console.log(await page.content()); +``` + +## Common Patterns + +### Multi-Step Workflows + +```typescript +test('user creates, configures, and tests topic', async ({ page }) => { + // Step 1: Navigate and create + await page.goto('/topics'); + await page.getByRole('button', { name: 'Create Topic' }).click(); + + // Step 2: Fill form + await page.getByLabel('Topic Name').fill('test-topic'); + await page.getByLabel('Partitions').fill('3'); + await page.getByRole('button', { name: 'Create' }).click(); + + // Step 3: Verify creation + await expect(page.getByText('Topic created successfully')).toBeVisible(); + await expect(page).toHaveURL(/\/topics\/test-topic/); + + // Step 4: Configure topic + await page.getByRole('button', { name: 'Configure' }).click(); + await page.getByLabel('Retention Hours').fill('24'); + await page.getByRole('button', { name: 'Save' }).click(); + + // Step 5: Verify configuration + await expect(page.getByText('Configuration saved')).toBeVisible(); +}); +``` + +### Testing Forms + +```typescript +test('form validation works correctly', async ({ page }) => { + await page.goto('/create-topic'); + + // Submit empty form - should show errors + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByText('Name is required')).toBeVisible(); + + // Fill valid data - should succeed + await page.getByLabel('Topic Name').fill('valid-topic'); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByText('Success')).toBeVisible(); +}); +``` + +### Testing Data Tables + +```typescript +test('user can filter and sort topics', async ({ page }) => { + await page.goto('/topics'); + + // Filter + await page.getByPlaceholder('Search topics').fill('test-'); + await expect(page.getByRole('row')).toHaveCount(3); // Header + 2 results + + // Sort + await page.getByRole('columnheader', { name: 'Name' }).click(); + const firstRow = page.getByRole('row').nth(1); + await expect(firstRow).toContainText('test-topic-a'); +}); +``` + +### API Interactions + +```typescript +test('creating topic triggers backend API', async ({ page }) => { + // Listen for API call + const apiPromise = page.waitForResponse( + resp => resp.url().includes('/api/topics') && resp.status() === 201 + ); + + // Trigger action + await page.goto('/topics'); + await page.getByRole('button', { name: 'Create Topic' }).click(); + await page.getByLabel('Name').fill('api-test-topic'); + await page.getByRole('button', { name: 'Create' }).click(); + + // Verify API was called + const response = await apiPromise; + const body = await response.json(); + expect(body.name).toBe('api-test-topic'); +}); +``` + +## Testcontainers Setup + +### Frontend Asset Copy (Required) + +The backend Docker image needs frontend assets embedded at build time: + +```typescript +// In global-setup.mjs +async function buildBackendImage(isEnterprise) { + // Copy frontend build to backend embed directory + const frontendBuildDir = resolve(__dirname, '../build'); + const embedDir = join(backendDir, 'pkg/embed/frontend'); + await execAsync(`cp -r "${frontendBuildDir}"/* "${embedDir}"/`); + + // Build Docker image using testcontainers + // Docker doesn't allow referencing files outside build context, + // so we temporarily copy the Dockerfile into the build context + const tempDockerfile = join(backendDir, '.dockerfile.e2e.tmp'); + await execAsync(`cp "${dockerfilePath}" "${tempDockerfile}"`); + + try { + await GenericContainer + .fromDockerfile(backendDir, '.dockerfile.e2e.tmp') + .build(imageTag, { deleteOnExit: false }); + } finally { + await execAsync(`rm -f "${tempDockerfile}"`).catch(() => {}); + await execAsync(`find "${embedDir}" -mindepth 1 ! -name '.gitignore' -delete`).catch(() => {}); + } +} +``` + +### Container Configuration + +**Backend container:** +```typescript +const backend = await new GenericContainer(imageTag) + .withNetwork(network) + .withNetworkAliases('console-backend') + .withExposedPorts({ container: 3000, host: 3000 }) + .withBindMounts([{ + source: configPath, + target: '/etc/console/config.yaml' + }]) + .withCommand(['--config.filepath=/etc/console/config.yaml']) + .start(); +``` + +**Redpanda container:** +```typescript +const redpanda = await new GenericContainer('redpandadata/redpanda:v25.2.1') + .withNetwork(network) + .withNetworkAliases('redpanda') + .withExposedPorts( + { container: 19_092, host: 19_092 }, // Kafka + { container: 18_081, host: 18_081 }, // Schema Registry + { container: 9644, host: 19_644 } // Admin API + ) + .withEnvironment({ RP_BOOTSTRAP_USER: 'e2euser:very-secret' }) + .withHealthCheck({ + test: ['CMD-SHELL', "rpk cluster health | grep -E 'Healthy:.+true' || exit 1"], + interval: 15_000, + retries: 5 + }) + .withWaitStrategy(Wait.forHealthCheck()) + .start(); +``` + +## CI Integration + +### GitHub Actions Setup + +```yaml +e2e-test: + runs-on: ubuntu-latest-8 + steps: + - uses: actions/checkout@v5 + - uses: oven-sh/setup-bun@v2 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Build frontend + run: | + REACT_APP_CONSOLE_GIT_SHA=$(echo $GITHUB_SHA | cut -c 1-6) + bun run build + + - name: Install Playwright browsers + run: bun run install:chromium + + - name: Run E2E tests + run: bun run e2e-test + + - name: Upload test report + if: failure() + uses: actions/upload-artifact@v4 + with: + name: playwright-report + path: frontend/playwright-report/ +``` + +## Test ID Management + +### Finding Missing Test IDs + +Use the Task tool with Explore agent to systematically find missing testids: + +``` +Use Task tool with: +subagent_type: Explore +prompt: Search through [feature] UI components and identify all interactive + elements (buttons, inputs, links, selects) missing data-testid attributes. + List with file:line, element type, purpose, and suggested testid name. +``` + +**Example output:** +``` +schema-list.tsx:207 - button - "Edit compatibility" - schema-edit-compatibility-btn +schema-list.tsx:279 - button - "Create new schema" - schema-create-new-btn +schema-details.tsx:160 - button - "Edit compatibility" - schema-details-edit-compatibility-btn +``` + +### Adding Test IDs + +**Naming Convention:** +- Use kebab-case: `data-testid="feature-action-element"` +- Be specific: Include feature name + action + element type +- For dynamic items: Use template literals `data-testid={\`item-delete-\${id}\`}` + +**Examples:** + +```tsx +// ✅ GOOD: Specific button action + + +// ✅ GOOD: Form input with context + + +// ✅ GOOD: Table row with dynamic ID + + {schema.name} + + +// ✅ GOOD: Delete button in list +} + onClick={() => deleteSchema(schema.name)} +/> + +// ❌ BAD: Too generic + + +// ❌ BAD: Using CSS classes as identifiers + +``` + +**Where to Add:** +1. **Primary actions**: Create, Save, Delete, Edit, Submit, Cancel buttons +2. **Navigation**: Links to detail pages, breadcrumbs +3. **Forms**: All input fields, selects, checkboxes, radio buttons +4. **Lists/Tables**: Row identifiers, action buttons within rows +5. **Dialogs/Modals**: Open/close buttons, form elements inside +6. **Search/Filter**: Search inputs, filter dropdowns, clear buttons + +**Process:** +1. Use Task/Explore to find missing testids in target feature +2. Read the component file to understand context +3. Add `data-testid` following naming convention +4. Update tests to use new testids +5. Run tests to verify selectors work + +## Analyzing Test Failures + +### Using MCP Playwright Agents + +**Check Test Status:** +```typescript +// Use mcp__playwright-test__test_list to see all tests +// Use mcp__playwright-test__test_run to get detailed results +// Use mcp__playwright-test__test_debug to analyze specific failures +``` + +### Reading Playwright Logs + +**Common failure patterns and fixes:** + +#### 1. Element Not Found +``` +Error: locator.click: Target closed +Error: Timeout 30000ms exceeded waiting for locator +``` + +**Analysis steps:** +1. Check if element has correct testid/role +2. Verify element is visible (not hidden/collapsed) +3. Check for timing issues (element loads async) +4. Look for dynamic content that changes selector + +**Fix:** +```typescript +// ❌ BAD: Element might not be loaded +await page.getByRole('button', { name: 'Create' }).click(); + +// ✅ GOOD: Wait for element to be visible +await expect(page.getByRole('button', { name: 'Create' })).toBeVisible(); +await page.getByRole('button', { name: 'Create' }).click(); + +// ✅ BETTER: Add testid for stability +await page.getByTestId('create-button').click(); +``` + +#### 2. Selector Ambiguity +``` +Error: strict mode violation: locator('button') resolved to 3 elements +``` + +**Analysis:** +- Multiple elements match the selector +- Need more specific selector or testid + +**Fix:** +```typescript +// ❌ BAD: Multiple "Edit" buttons on page +await page.getByRole('button', { name: 'Edit' }).click(); + +// ✅ GOOD: More specific with testid +await page.getByTestId('schema-edit-compatibility-btn').click(); + +// ✅ GOOD: Scope within container +await page.getByRole('region', { name: 'Schema Details' }) + .getByRole('button', { name: 'Edit' }).click(); +``` + +#### 3. Timing/Race Conditions +``` +Error: expect(locator).toHaveText() +Expected string: "Success" +Received string: "Loading..." +``` + +**Analysis:** +- Test assertion ran before UI updated +- Need to wait for specific state + +**Fix:** +```typescript +// ❌ BAD: Doesn't wait for state change +await page.getByRole('button', { name: 'Save' }).click(); +expect(page.getByText('Success')).toBeVisible(); + +// ✅ GOOD: Wait for the expected state +await page.getByRole('button', { name: 'Save' }).click(); +await expect(page.getByText('Success')).toBeVisible({ timeout: 5000 }); +``` + +#### 4. Navigation Issues +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED +``` + +**Analysis:** +- Backend/frontend not running +- Wrong URL or port + +**Fix:** +```bash +# Check containers are running +docker ps | grep console-backend + +# Check container logs +docker logs + +# Verify port mapping +curl http://localhost:3000 + +# Check testcontainer state file +cat .testcontainers-state.json +``` + +### Systematic Failure Analysis Workflow + +**When tests fail:** + +1. **Get Test Results** + ``` + Use mcp__playwright-test__test_run or check console output + Identify which tests failed and error messages + ``` + +2. **Analyze Error Patterns** + - Selector not found → Missing/wrong testid or element not visible + - Strict mode violation → Need more specific selector + - Timeout → Element loads async, need waitFor + - Connection refused → Container/service not running + +3. **Find Missing Test IDs** + ``` + Use Task tool with Explore agent to find missing testids in the + components related to failed tests + ``` + +4. **Add Test IDs** + - Read component file + - Add `data-testid` to problematic elements + - Follow naming convention + - Format with biome + +5. **Update Tests** + - Replace brittle selectors with stable testids + - Add proper wait conditions + - Verify with test run + +6. **Verify Fixes** + ``` + Run specific test file to verify fix + Run full suite to ensure no regressions + ``` + +## Troubleshooting + +### Container Fails to Start + +```bash +# Check if frontend build exists +ls frontend/build/ + +# Check if Docker image built successfully +docker images | grep console-backend + +# Check container logs +docker logs + +# Verify Docker network +docker network ls | grep testcontainers +``` + +### Test Timeout Issues + +```typescript +// Increase timeout for slow operations +test('slow operation', async ({ page }) => { + test.setTimeout(60000); // 60 seconds + + await page.goto('/slow-page'); + await expect(page.getByText('Loaded')).toBeVisible({ timeout: 30000 }); +}); +``` + +### Port Already in Use + +```bash +# Find and kill process using port 3000 +lsof -ti:3000 | xargs kill -9 + +# Or use different ports in test config +``` + +## Quick Reference + +**Test types:** +- E2E tests (`*.spec.ts`): Complete user workflows, browser interactions +- Integration tests (`*.test.tsx`): Component + API, no browser +- Unit tests (`*.test.ts`): Pure logic, utilities + +**Commands:** +```bash +bun run build # Build frontend (REQUIRED first!) +bun run e2e-test # Run OSS E2E tests +bun run e2e-test-enterprise # Run Enterprise E2E tests +bun run e2e-test:ui # Playwright UI mode (debugging) +``` + +**Selector priority:** +1. `getByRole()` - Best for accessibility +2. `getByLabel()` - For form inputs +3. `getByText()` - For content verification +4. `getByTestId()` - When semantic selectors aren't clear +5. CSS selectors - Avoid if possible + +**Wait strategies:** +- `waitForURL()` - Navigation complete +- `waitForResponse()` - API call finished +- `waitFor()` with `expect()` - Element state changed +- Never use fixed `waitForTimeout()` unless absolutely necessary + +## Output + +After completing work: + +1. Confirm frontend build succeeded +2. Verify all E2E tests pass +3. Note any new test IDs added to components +4. Mention cleanup of test containers +5. Report test execution time and coverage \ No newline at end of file diff --git a/frontend/.mcp.json b/frontend/.mcp.json new file mode 100644 index 0000000000..d9dfc1253b --- /dev/null +++ b/frontend/.mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "playwright-test": { + "command": "npx", + "args": [ + "playwright", + "run-test-mcp-server" + ] + } + } +} \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 78b271e19c..52e2b56bd1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,6 +18,7 @@ "e2e-test": "playwright test -c playwright.config.ts tests/console/", "e2e-test-enterprise": "playwright test tests/console-enterprise/ -c playwright.enterprise.config.ts", "e2e-test:ui": "playwright test tests/console/ -c playwright.config.ts --ui", + "e2e-test-enterprise:ui": "playwright test -c playwright.enterprise.config.ts tests/console-enterprise/ --ui", "test:ci": "bun run test:unit && bun run test:integration", "test": "bun run test:ci", "test:unit": "TZ=GMT vitest run --config=vitest.config.unit.mts", diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index 6b66984c81..7334e24ecd 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -52,6 +52,8 @@ export default defineConfig({ name: 'chromium', use: { ...devices['Desktop Chrome'], + // Grant clipboard permissions for tests + permissions: ['clipboard-read', 'clipboard-write'], // Use prepared auth state. // storageState: 'playwright/.auth/user.json', }, diff --git a/frontend/specs/README.md b/frontend/specs/README.md new file mode 100644 index 0000000000..6a06f0ee78 --- /dev/null +++ b/frontend/specs/README.md @@ -0,0 +1,5 @@ +# Test Plans + +This directory contains markdown test plans created by the Playwright planner agent. + +Each file represents a comprehensive test plan for a specific feature or user flow. diff --git a/frontend/specs/topics.md b/frontend/specs/topics.md new file mode 100644 index 0000000000..c3f1beda81 --- /dev/null +++ b/frontend/specs/topics.md @@ -0,0 +1,455 @@ +# Topics E2E Test Plan + +## Overview + +E2E tests for the Topics page in Redpanda Console, covering topic management, message operations, and configuration viewing. + +**Total Tests:** 40 tests across 6 spec files +**Seed:** `tests/seed.spec.ts` + +## Routes + +- `/topics` - Topic list page +- `/topics/:topicName` - Topic details page with tabs +- `/topics/:topicName/produce-record` - Produce message page + +## Test Files + +### 1. Topic List - Basic Operations (`topic-list.spec.ts`) + +**6 tests** covering list viewing, search, and filtering operations. + +#### 1.1 View Topics List +- Navigate to `/topics` +- Verify page elements visible: + - Create topic button (testId: `create-topic-button`) + - Search input (testId: `search-field-input`) + - Show internal topics checkbox (testId: `show-internal-topics-checkbox`) + - Topics table (testId: `topics-table`) + +#### 1.2 Search Topics - Exact Match +- Create test topic with unique name +- Search for the exact topic name +- Verify topic is visible in filtered results +- Search for non-existent topic +- Verify original topic is hidden + +#### 1.3 Search Topics - Regex Pattern +- Create 3 topics: 2 with same prefix, 1 different +- Apply regex pattern matching prefix (e.g., `^regex-test.*`) +- Verify matching topics visible +- Verify non-matching topic hidden + +#### 1.4 Clear Search Filter +- Create test topic +- Apply search filter that hides the topic +- Clear the search input +- Verify topic becomes visible again + +#### 1.5 Toggle Show Internal Topics +- Navigate to topics list +- Uncheck "Show internal topics" checkbox +- Verify internal topics (e.g., `_schemas`) hidden +- Check the checkbox +- Verify internal topics visible + +#### 1.6 Persist Internal Topics Setting +- Check "Show internal topics" checkbox +- Verify `_schemas` topic visible +- Reload page +- Verify setting persisted (checkbox still checked, `_schemas` visible) +- Uncheck checkbox and reload +- Verify setting persisted (checkbox unchecked, `_schemas` hidden) + +--- + +### 2. Topic Creation (`topic-creation.spec.ts`) + +**7 tests** covering topic creation flows and validation. + +#### 2.1 Create Topic with Default Settings +- Navigate to `/topics` +- Click create topic button (testId: `create-topic-button`) +- Verify modal opens, topic name field focused +- Fill topic name (testId: `topic-name`) +- Click create button (testId: `onOk-button`) +- Close success modal (testId: `create-topic-success__close-button`) +- Verify topic appears in list (testId: `topic-link-{topicName}`) + +#### 2.2 Create Topic with Custom Configuration +- Open create topic modal +- Fill topic name +- Set partitions to 6 (placeholder: `/partitions/i`) +- Click create +- Close success modal +- Navigate to topic configuration tab +- Verify configuration page loads (testId: `config-group-table`) + +#### 2.3 Validate Empty Topic Name +- Open create topic modal +- Leave topic name empty +- Verify create button disabled (testId: `onOk-button`) +- Click cancel to close modal + +#### 2.4 Validate Invalid Topic Name Characters +- Open create topic modal +- Enter invalid topic name with spaces and special chars +- If button enabled, click shows validation error +- If button disabled, verify it's disabled +- Modal remains open + +#### 2.5 Validate Replication Factor +- Open create topic modal +- Enter topic name +- Try setting replication factor to 999 (placeholder: `/replication/i`) +- Verify validation error appears (if field is enabled) +- Cancel modal + +#### 2.6 Cancel Topic Creation +- Open create topic modal +- Fill some values +- Click Cancel button +- Verify modal closes +- Verify topic not created + +#### 2.7 Create and Verify in Multiple Views +- Create topic through modal +- Verify in topics list +- Navigate to topic details +- Verify URL matches `/topics/{topicName}` +- Verify topic name displayed +- Navigate back to list +- Verify topic still visible + +--- + +### 3. Topic Details - Navigation and Tabs (`topic-navigation.spec.ts`) + +**5 tests** covering topic details navigation and tab functionality. + +#### 3.1 Navigate to Topic Details +- Create test topic +- Navigate to topics list +- Click topic link (testId: `topic-link-{topicName}`) +- Verify URL changes to `/topics/{topicName}` +- Verify topic name displayed +- Verify tabs visible (role: `tablist`) + +#### 3.2 View Messages Tab (Default) +- Create test topic +- Click topic link +- Verify tablist visible +- Verify Messages tab content visible +- Verify message-related elements present + +#### 3.3 Navigate to Tab via URL Hash +- Create test topic +- Navigate directly to `/topics/{topicName}#configuration` +- Verify configuration tab active (testId: `config-group-table`) +- Navigate to `/topics/{topicName}#partitions` +- Verify partitions content visible + +#### 3.4 View Configuration Tab with Grouped Settings +- Create test topic +- Navigate to configuration tab +- Verify config groups visible in expected order: + - Retention, Compaction, Replication, Tiered Storage + - Write Caching, Iceberg, Schema Registry and Validation + - Message Handling, Compression, Storage Internals +- Verify at least "Retention" group present +- Verify groups maintain order + +#### 3.5 Navigate Back via Breadcrumb +- Create test topic +- Navigate to topic details +- Click "Topics" breadcrumb link +- Verify returns to `/topics` (with optional trailing slash and query params) +- Verify topic visible in list + +--- + +### 4. Produce Messages (`topic-messages-production.spec.ts`) + +**7 tests** covering message production operations. + +#### 4.1 Produce Simple Text Message +- Create test topic +- Produce message via helper +- Navigate to messages tab +- Verify message content visible + +#### 4.2 Produce Message with Key *(skipped)* +- Create test topic +- Navigate to produce page +- Fill key editor (testId: `produce-key-editor`) +- Fill value editor (testId: `produce-value-editor`) +- Click produce button (testId: `produce-button`) +- Verify message produced + +#### 4.3 Produce Multiple Messages in Sequence +- Create test topic +- Produce 3 messages sequentially via UI +- Each message: navigate to produce, fill editor, click produce +- Verify each message appears after production +- Navigate to messages tab +- Verify all 3 messages visible + +#### 4.4 Produce Large Message +- Create test topic +- Navigate to produce page +- Generate 30KB+ content +- Paste into value editor via clipboard +- Click produce +- Verify "Message size exceeds display limit" warning +- Expand message row +- Verify warning about performance degradation +- Click "Load anyway" button (testId: `load-anyway-button`) +- Verify payload content visible (testId: `payload-content`) + +#### 4.5 Navigate to Produce Page +- Create test topic +- Navigate to produce page +- Verify produce button visible (testId: `produce-button`) +- Verify value editor visible (testId: `produce-value-editor`) +- Verify key editor visible (testId: `produce-key-editor`) +- Verify heading indicates produce/publish + +#### 4.6 Handle Empty Message Production +- Create test topic +- Navigate to produce page +- Click in value editor but don't enter text +- Click produce button +- Verify no crash occurs (wait 2 seconds) + +#### 4.7 Clear Editor Between Produces +- Create test topic +- Navigate to produce page, produce first message +- Navigate to produce page again +- Clear editor (Ctrl+A or Meta+A, then Backspace) +- Produce second message +- Navigate to messages tab +- Verify both messages exist + +--- + +### 5. View and Filter Messages (`topic-messages-filtering.spec.ts`) + +**8 tests** covering message viewing and filtering operations. + +#### 5.1 Expand Message to View Details +- Create topic and produce message +- Navigate to messages tab +- Verify message content visible +- Click expand button (label: "Collapse row") +- Verify expanded details visible (testId: `payload-content`) +- Verify metadata visible (Offset/Partition/Timestamp) + +#### 5.2 Search Message Content +- Create topic and produce 2 messages (one with keyword, one without) +- Navigate to messages tab +- Find search input (placeholder: `/search|filter/i`) +- Enter search term and press Enter +- Verify matching message visible +- (Behavior depends on implementation for non-matching) + +#### 5.3 Filter Messages by Partition *(skipped)* +- Create topic and produce message +- Look for partition filter dropdown +- Select partition 0 +- Verify messages filter to selected partition + +#### 5.4 Filter Messages by Offset +- Create topic and produce 3 messages +- Navigate to messages tab +- Find offset input (placeholder: `/offset/i`) +- Set start offset to 1 (skip first message) +- Press Enter and wait +- Verify filtered messages visible + +#### 5.5 Clear All Filters +- Create topic and produce message +- Apply search filter +- Look for clear/reset button (role: `button`, name: `/clear|reset/i`) +- Click clear button +- Verify message becomes visible again + +#### 5.6 Handle Empty Topic +- Create empty topic (no messages) +- Navigate to messages tab +- Verify empty state message visible (text: `/No messages|empty/i`) +- Verify produce button still available + +#### 5.7 Handle Rapid Filter Changes +- Create topic and produce message +- Navigate to messages tab +- Rapidly change search terms multiple times +- Clear and enter final search term +- Verify handles gracefully without errors +- Verify message displays correctly + +#### 5.8 Preserve Filters in URL Parameters +- Create topic and produce message +- Navigate to messages tab +- Enter search term in quick search and press Enter +- Verify URL contains filter parameter (e.g., `q=test-search`) +- Reload page +- Verify URL still contains parameter +- Verify search input has the value +- (Uses testId: `message-quick-search-input`) + +--- + +### 6. Message Actions and Export (`topic-messages-actions.spec.ts`) + +**7 tests** covering message actions like copy, export, and viewing metadata. + +**Note:** Tests use `permissions: ['clipboard-write', 'clipboard-read']` + +#### 6.1 Copy Message Value to Clipboard +- Create topic and produce message +- Navigate to messages tab +- Expand first message +- Click copy value button (role: `button`, name: `/copy value/i`) +- Verify clipboard content matches message value +- Verify success toast visible: "Value copied to clipboard" + +#### 6.2 Export Single Message as JSON +- Create topic and produce message +- Navigate to messages tab +- Expand first message +- Click "Download Record" +- JSON format selected by default +- Click save in dialog (role: `dialog`, name: `/save message/i`) +- Verify download with `.json` extension +- Save and verify file content contains message + +#### 6.3 Export Single Message as CSV +- Create topic and produce message +- Navigate to messages tab +- Expand first message +- Click "Download Record" +- Select CSV format (testId: `csv_field`) +- Click "Save Messages" in dialog +- Verify download as `messages.csv` +- Verify file content contains message + +#### 6.4 Export Message with Special Characters +- Create topic and produce message with special chars (quotes, commas, emojis) +- Navigate to messages tab +- Expand message and export as JSON +- Verify special characters preserved in file + +#### 6.5 Open and Cancel Export Dialog +- Create topic and produce message +- Navigate to messages tab +- Expand message +- Click "Download Record" +- Verify dialog opens (role: `dialog`, name: `/save message/i`) +- Click Cancel button +- Verify dialog closes + +#### 6.6 Handle Large Payload Export +- Create topic +- Navigate to produce page and create 30KB+ message +- Verify "Message size exceeds display limit" warning +- Expand message row +- Click "Load anyway" button (testId: `load-anyway-button`) +- Export message as JSON +- Verify file size > 1KB +- Verify payload content loads + +#### 6.7 View Message Metadata +- Create topic and produce message +- Navigate to messages tab +- Expand first message +- Verify metadata visible: + - Offset/offset (case insensitive) + - Partition/partition + - Timestamp/timestamp +- Verify payload content visible (testId: `payload-content`) + +--- + +## Implementation Details + +### Test Utilities + +All tests use the `TopicPage` Page Object Model: + +```typescript +import { TopicPage } from '../utils/TopicPage'; + +const topicPage = new TopicPage(page); + +// High-level operations +await topicPage.createTopic(topicName); +await topicPage.deleteTopic(topicName); +await topicPage.produceMessage(topicName, message); + +// Navigation +await topicPage.goToTopicsList(); +await topicPage.goToTopicDetails(topicName); +await topicPage.goToProduceRecord(topicName); + +// List operations +await topicPage.searchTopics(searchTerm); +await topicPage.toggleInternalTopics(checked); +await topicPage.verifyTopicInList(topicName); +``` + +### Test IDs Used + +**Topic List:** +- `create-topic-button` - Create topic button +- `search-field-input` - Search input field +- `show-internal-topics-checkbox` - Internal topics toggle +- `topics-table` - Topics data table +- `topic-link-{topicName}` - Dynamic topic link +- `delete-topic-button-{topicName}` - Delete button per topic +- `delete-topic-confirm-button` - Confirm delete button + +**Topic Creation:** +- `topic-name` - Topic name input field +- `onOk-button` - Create/submit button +- `create-topic-success__close-button` - Close success modal + +**Topic Details:** +- `config-group-table` - Configuration groups table +- `produce-record-button` - Produce button in details +- Use `role='tablist'` for tabs + +**Produce Messages:** +- `produce-button` - Produce message button +- `produce-value-editor` - Value editor (Monaco) +- `produce-key-editor` - Key editor (Monaco) +- `load-anyway-button` - Load large message button +- `payload-content` - Message payload display + +**Messages Tab:** +- `message-quick-search-input` - Quick search input +- `data-table-cell` - Table cells +- Use `aria-label="Collapse row"` for expand buttons + +**Export:** +- `csv_field` - CSV format selection +- Use `role='dialog'` with `name=/save message/i` for export dialog + +### Cleanup + +All tests use `TopicPage.deleteTopic()` in teardown to clean up created topics. + +### Skipped Tests + +Some tests are marked as `test.skip()`: +- Produce message with key - Needs stable key editor interaction +- Filter messages by partition - Needs better select control handling + +### Notes + +- Tests create topics with unique names using `Date.now()` timestamps +- Tests verify both UI state and data consistency +- URL parameter preservation is tested for search filters +- Internal topics (`_schemas`) are used to test visibility toggle +- Large message tests use 30KB+ content to trigger size warnings +- Special characters testing includes quotes, commas, and emojis +- All tests are self-contained with setup and teardown diff --git a/frontend/src/components/layout/header.tsx b/frontend/src/components/layout/header.tsx index cab9dd65a9..3fe67b4ce5 100644 --- a/frontend/src/components/layout/header.tsx +++ b/frontend/src/components/layout/header.tsx @@ -70,6 +70,7 @@ const AppPageHeader = observer(() => { fontSize="xl" fontWeight={700} mr={2} + role="heading" {...(lastBreadcrumb.options?.canBeTruncated ? { wordBreak: 'break-all', diff --git a/frontend/src/components/pages/admin/admin-debug-bundle-progress.tsx b/frontend/src/components/pages/admin/admin-debug-bundle-progress.tsx index 5a9e799459..87afa2ac44 100644 --- a/frontend/src/components/pages/admin/admin-debug-bundle-progress.tsx +++ b/frontend/src/components/pages/admin/admin-debug-bundle-progress.tsx @@ -51,19 +51,23 @@ export default class AdminPageDebugBundleProgress extends PageComponent { render() { return ( - + Collect environment data that can help debug and diagnose issues with a Redpanda cluster, a broker, or the - machine it’s running on. This will bundle the collected data into a ZIP file. + machine it's running on. This will bundle the collected data into a ZIP file. - {api.isDebugBundleInProgress && Generating bundle...} + {api.isDebugBundleInProgress && Generating bundle...} {api.isDebugBundleExpired && ( - Your previous bundle has expired and cannot be downloaded. + + Your previous bundle has expired and cannot be downloaded. + + )} + {api.isDebugBundleError && ( + Your debug bundle was not generated. )} - {api.isDebugBundleError && Your debug bundle was not generated.} {api.canDownloadDebugBundle && ( - + Debug bundle complete: @@ -79,6 +83,7 @@ export default class AdminPageDebugBundleProgress extends PageComponent { {api.isDebugBundleInProgress ? ( ) : ( - )} diff --git a/frontend/src/components/pages/admin/admin-debug-bundle.tsx b/frontend/src/components/pages/admin/admin-debug-bundle.tsx index 27a353a345..a440ecf402 100644 --- a/frontend/src/components/pages/admin/admin-debug-bundle.tsx +++ b/frontend/src/components/pages/admin/admin-debug-bundle.tsx @@ -72,10 +72,10 @@ const getSizeUnitLabel = (unitValue: number): string => const getTimeUnitLabel = (unitValue: number): string => TIME_UNITS.find((unit) => unit.value === unitValue)?.label || ''; -const Header = () => ( - +const Header: FC<{ mode?: 'default' | 'advanced' }> = ({ mode = 'default' }) => ( + Collect environment data that can help debug and diagnose issues with a Redpanda cluster, a broker, or the machine - it’s running on. This will bundle the collected data into a ZIP file. + it's running on. This will bundle the collected data into a ZIP file. ); @@ -156,7 +156,6 @@ export class AdminDebugBundle extends PageComponent { return ( -
{(api.canDownloadDebugBundle || api.isDebugBundleExpired) && ( Latest debug bundle: @@ -344,10 +343,12 @@ const NewDebugBundleForm: FC<{ return ( +
{advancedForm && ( or + - ); + ), }, - size: Number.POSITIVE_INFINITY, - }, - { - header: 'Partitions', - accessorKey: 'partitionCount', - enableResizing: true, - cell: ({ row: { original: topic } }) => topic.partitionCount, - }, - { - header: 'Replicas', - accessorKey: 'replicationFactor', - }, - { - header: 'CleanupPolicy', - accessorKey: 'cleanupPolicy', - }, - { - header: 'Size', - accessorKey: 'logDirSummary.totalSizeBytes', - cell: ({ row: { original: topic } }) => renderLogDirSummary(topic.logDirSummary), - }, - { - id: 'action', - header: '', - cell: ({ row: { original: record } }) => ( - - - - - - ), - }, - ]} - data={topics} - onPaginationChange={onPaginationChange(paginationParams, ({ pageSize, pageIndex }) => { - uiSettings.topicList.pageSize = pageSize; - editQuery((query) => { - query.page = String(pageIndex); - query.pageSize = String(pageSize); - }); - })} - pagination={paginationParams} - sorting={true} - /> + ]} + data={topics} + onPaginationChange={onPaginationChange(paginationParams, ({ pageSize, pageIndex }) => { + uiSettings.topicList.pageSize = pageSize; + editQuery((query) => { + query.page = String(pageIndex); + query.pageSize = String(pageSize); + }); + })} + pagination={paginationParams} + sorting={true} + /> + ); }; diff --git a/frontend/src/utils/create-auto-modal.tsx b/frontend/src/utils/create-auto-modal.tsx index adc0631611..4d7e718027 100644 --- a/frontend/src/utils/create-auto-modal.tsx +++ b/frontend/src/utils/create-auto-modal.tsx @@ -161,6 +161,7 @@ export default function createAutoModal(options: { {response}