Skip to content

chore: styling and missing unit tests#265

Merged
HardMax71 merged 8 commits intomainfrom
chore/useless-files
Mar 4, 2026
Merged

chore: styling and missing unit tests#265
HardMax71 merged 8 commits intomainfrom
chore/useless-files

Conversation

@HardMax71
Copy link
Copy Markdown
Owner

@HardMax71 HardMax71 commented Mar 4, 2026


Summary by cubic

Adds Prettier formatting and stricter checks to the frontend, and fills in missing unit tests while polishing UI and accessibility. This improves CI reliability, code consistency, and test coverage.

  • Refactors

    • Added .prettierrc/.prettierignore and applied formatting across Svelte/TS; new npm scripts: format and format:check.
    • CI/pre-commit run format:check, svelte-check with --fail-on-warnings, and verify the production build; added a prettier-frontend hook.
    • Tightened linting (button-has-type now an error) and fixed a11y issues (labels, aria-expanded, keyboard handling).
    • Unified loading and empty states: replaced DaisyUI spinners with Spinner, added Spinner in NotificationCenter/UsersTable, and cleaned up table/empty-state styling.
    • Expanded unit tests with new suites for EditorToolbar and ScriptActions, plus broad updates across admin/editor components.
  • Dependencies

    • Added prettier and prettier-plugin-svelte to dev dependencies.

Written for commit f178f2e. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Tabbed Settings UI with organized theme, notifications, and editor controls
    • Redesigned Home hero and new features grid
    • Improved authentication flow and redirects for protected pages
  • Improvements

    • Space + Enter keyboard support for notifications; Escape closes modals
    • More spinners/loading indicators across the UI
    • Stronger form validation for user and script creation
    • Accessibility enhancements (ARIA labels, table semantics)
  • Code Quality

    • Format validation added to CI and Prettier pre-commit checks; stricter linting rules

Copilot AI review requested due to automatic review settings March 4, 2026 21:43
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 4, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds Prettier formatting and production-build verification to frontend CI and pre-commit checks; introduces Prettier config and scripts; raises svelte button rule to error; many frontend components and tests were reformatted, with targeted functional changes to auth initialization, modal/key handling, notification stream lifecycle, accessibility, and Settings tab UI.

Changes

Cohort / File(s) Summary
CI & Pre-commit
.github/workflows/frontend-ci.yml, .pre-commit-config.yaml
Add Prettier format check and production npm run build verification to frontend CI; add Prettier pre-commit hook and make svelte-check fail-on-warnings.
Prettier config & ignore
frontend/.prettierrc, frontend/.prettierignore
Add Prettier config (single quotes, tabWidth 4, printWidth 120, trailingComma, svelte plugin) and expanded ignore patterns.
Frontend scripts & deps
frontend/package.json
Add format and format:check scripts; add prettier, prettier-plugin-svelte, and sirv-cli; update check script to use --fail-on-warnings.
Lint rule
frontend/eslint.config.js
Elevate svelte/button-has-type from warn to error.
App & Auth flows
frontend/src/App.svelte, frontend/src/components/Header.svelte
Initialize auth on mount, add requireAuth flow and redirect behavior; refactor header/menu/logout flows and click-outside handling.
Notifications & Streams
frontend/src/components/NotificationCenter.svelte, frontend/src/lib/notifications/stream.svelte.ts
On auth change: load initial notifications, connect/disconnect SSE stream; update read-marking and keyboard handling; minor stream formatting changes.
Modal & Accessibility
frontend/src/components/Modal.svelte, frontend/src/components/Pagination.svelte, frontend/src/components/Spinner.svelte
Add Escape-key handling on modal backdrop; accessibility/aria-label improvements and Spinner usage for loading states; minor UI layout shifts.
Settings UI
frontend/src/routes/Settings.svelte
Large rewrite to tabbed UI, history caching, changed save/restore flows, and UI restructuring.
Admin tables & events
frontend/src/components/admin/events/..., frontend/src/routes/admin/...
Standardize table classes/headers, add scope/aria labels, keyboard handling (Enter/Space), modal content reflows and minor UX tweaks.
Users & Rate limits
frontend/src/components/admin/users/...
Add Spinner for loading states, require username, require password on create, adjust rate-limit calculation presentation (uses null-coalesce inline).
Editor components & tests
frontend/src/components/editor/..., frontend/src/components/editor/__tests__/*
Formatting and theme/config adjustments, new EditorToolbar tests and ScriptActions tests; CodeMirror listener signature and theming tweaks.
Stores, utils & formatters
frontend/src/lib/...
Mostly formatting/trailing-comma changes; small payload reformatting (pagination moved into POST body) and minor logic presentation changes.
Tests (widespread)
frontend/src/__tests__/*, frontend/src/components/**/__tests__/*, frontend/src/routes/**/__tests__/*
Mass reformatting and reorganization of tests, added EditorToolbar and ScriptActions test suites; most tests preserve behavior.
Cosmetic component edits
many frontend/src/components/*, frontend/src/routes/*
Extensive formatting, quote normalization to single quotes, minor DOM/layout reflows, and small accessibility/aria tweaks across numerous components.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App as App.svelte
    participant Auth as Auth Store
    participant Header as Header Component
    participant Notif as NotificationCenter

    User->>App: Load page
    activate App
    App->>Auth: initAuth onMount
    activate Auth
    Auth-->>App: authState
    deactivate Auth

    App->>Header: render(authState)
    Header-->>User: show nav/menu
    User->>Header: click Logout
    Header->>Auth: logout()
    activate Auth
    Auth-->>Header: cleared
    deactivate Auth
    Header->>App: navigate('/login')
    App-->>User: redirect to /login
    deactivate App
Loading
sequenceDiagram
    participant Auth as Auth Store
    participant Notif as NotificationCenter
    participant API as Backend (notifications)
    participant UI as Notification UI

    Auth->>Notif: auth changed (logged in)
    Notif->>API: fetch initial notifications (limit=20)
    API-->>Notif: initial list
    Notif->>API: open SSE stream (connect)
    API-->>Notif: SSE events (streaming)
    Notif->>UI: render notifications / badge count
    User->>UI: mark notification read (Enter/Space)
    UI->>Notif: markAsRead -> API
    Notif->>API: mark read
    API-->>Notif: ack
    Auth->>Notif: auth changed (logged out)
    Notif->>API: disconnect SSE
    Notif->>UI: clear notifications
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰 I hopped through lines both long and neat,

Prettier trimmed each trailing seat,
Auth woke up on mount today,
Notifications stream my way,
Tests aligned — a tidy feat!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore: styling and missing unit tests' is directly related to the PR's core changes: Prettier formatting configuration, styling adjustments, and new unit tests added throughout.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/useless-files

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Mar 4, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 83.91039% with 158 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
frontend/src/routes/admin/AdminUsers.svelte 44.11% 11 Missing and 8 partials ⚠️
...end/src/components/admin/events/EventsTable.svelte 64.28% 9 Missing and 6 partials ⚠️
frontend/src/routes/admin/AdminEvents.svelte 71.11% 10 Missing and 3 partials ⚠️
frontend/src/components/Header.svelte 89.00% 9 Missing and 2 partials ⚠️
frontend/src/main.ts 0.00% 11 Missing ⚠️
frontend/src/routes/Editor.svelte 69.69% 5 Missing and 5 partials ⚠️
...nd/src/components/admin/events/EventFilters.svelte 25.00% 6 Missing and 3 partials ⚠️
frontend/src/routes/Settings.svelte 90.10% 2 Missing and 7 partials ⚠️
...c/components/admin/events/UserOverviewModal.svelte 75.00% 0 Missing and 8 partials ⚠️
.../src/components/admin/users/RateLimitsModal.svelte 75.75% 5 Missing and 3 partials ⚠️
... and 23 more
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Flag Coverage Δ
backend-e2e 83.21% <ø> (-0.10%) ⬇️
backend-unit 67.91% <ø> (ø)
frontend-unit 86.48% <83.91%> (-0.38%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
frontend/src/App.svelte 0.00% <ø> (ø)
frontend/src/components/ErrorDisplay.svelte 100.00% <100.00%> (ø)
frontend/src/components/EventTypeIcon.svelte 100.00% <100.00%> (ø)
frontend/src/components/Footer.svelte 93.75% <100.00%> (+0.41%) ⬆️
...src/components/admin/events/EventStatsCards.svelte 73.33% <100.00%> (ø)
...d/src/components/admin/sagas/SagaStatsCards.svelte 92.85% <100.00%> (ø)
.../src/components/admin/users/DeleteUserModal.svelte 100.00% <100.00%> (ø)
...nd/src/components/admin/users/UserFormModal.svelte 96.77% <100.00%> (ø)
...ntend/src/components/admin/users/UsersTable.svelte 94.00% <100.00%> (+0.25%) ⬆️
...rontend/src/components/editor/EditorToolbar.svelte 100.00% <100.00%> (ø)
... and 55 more

... and 2 files with indirect coverage changes

Components Coverage Δ
Backend 90.07% <ø> (-0.09%) ⬇️
Frontend 86.48% <83.91%> (-0.38%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 146 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/src/components/Modal.svelte">

<violation number="1" location="frontend/src/components/Modal.svelte:36">
P2: This adds a second Escape listener while the window Escape listener already exists, which can invoke `onClose` twice for a single keypress.</violation>
</file>

<file name="frontend/src/components/admin/events/EventsTable.svelte">

<violation number="1" location="frontend/src/components/admin/events/EventsTable.svelte:39">
P2: Parent row keyboard handler captures Space/Enter from focused child buttons, so pressing Space on an inner action can trigger `onViewDetails` instead of only the child control.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread frontend/src/components/Modal.svelte
Comment thread frontend/src/components/admin/events/EventsTable.svelte Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR standardizes frontend formatting/styling, adds missing unit tests, and tightens CI quality gates (coverage, type-checking, formatting, and build verification).

Changes:

  • Introduces Prettier formatting (config + scripts + pre-commit + CI) and applies broad formatting cleanups across TS/Svelte/test files.
  • Adds/extends unit tests for editor/admin/notifications utilities and components; enforces Vitest coverage thresholds.
  • Improves UI consistency with new shared component classes (e.g., empty states/dividers) and minor UX/accessibility tweaks.

Reviewed changes

Copilot reviewed 135 out of 146 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
scripts/docker-cleanup.sh Removes the Docker cleanup helper script.
frontend/vitest.config.ts Adds global coverage thresholds for Vitest.
frontend/src/utils/meta.ts Reflows page meta strings for consistent formatting.
frontend/src/styles/components.css Adds shared utility classes (.divider, .empty-state, .mobile-card).
frontend/src/stores/userSettings.svelte.ts Formats exported store helpers into multi-line functions.
frontend/src/stores/theme.svelte.ts Formats dynamic imports/catch blocks and exported helpers.
frontend/src/stores/notificationStore.svelte.ts Formatting + minor style consistency in API calls and array ops.
frontend/src/stores/auth.svelte.ts Formatting + catch block expanded for clarity.
frontend/src/stores/tests/userSettings.test.ts Reformats parameterized tests and imports for readability.
frontend/src/stores/tests/notificationStore.test.ts Formatting updates to test structures and callbacks.
frontend/src/stores/tests/auth.test.ts Formatting updates; simplifies some expectations.
frontend/src/routes/admin/tests/AdminUsers.test.ts Formatting updates; adjusts assertions where native required prevents submit.
frontend/src/routes/admin/tests/AdminSettings.test.ts Formatting updates for mocks and async setup.
frontend/src/routes/admin/tests/AdminSagas.test.ts Formatting updates to expectations and removed blank lines.
frontend/src/routes/admin/tests/AdminLayout.test.ts Formatting updates for array callbacks.
frontend/src/routes/admin/tests/AdminExecutions.test.ts Formatting updates and helper signature simplification.
frontend/src/routes/admin/tests/AdminEvents.test.ts Formatting updates; updates “View details” accessible name expectations.
frontend/src/routes/admin/AdminSagas.svelte Import formatting + unwrapOr call formatting + minor handler style change.
frontend/src/routes/admin/AdminLayout.svelte Formats long class attributes into multi-line blocks.
frontend/src/routes/admin/AdminExecutions.svelte Refactors markup to shared table/form classes and adds empty-state usage.
frontend/src/routes/tests/Settings.test.ts Formatting updates to mocks and test data objects.
frontend/src/routes/tests/Register.test.ts Formatting updates to assertions and async flows.
frontend/src/routes/tests/Privacy.test.ts Formatting updates for callbacks/indentation.
frontend/src/routes/tests/Notifications.test.ts Formatting updates; consolidates some waitFor blocks.
frontend/src/routes/tests/Login.test.ts Formatting updates to async mocks and expectations.
frontend/src/routes/tests/Home.test.ts Formatting updates to parameterized test cases.
frontend/src/routes/tests/Editor.test.ts Formatting updates; minor expression parenthesization.
frontend/src/routes/Register.svelte Applies single-quote and formatting conventions; expands markup for readability.
frontend/src/routes/Notifications.svelte Formatting updates + keyboard handling tweak to support Space key.
frontend/src/routes/Login.svelte Applies single-quote and formatting conventions; expands markup for readability.
frontend/src/routes/Home.svelte Reformats feature config and markup blocks for consistency.
frontend/src/main.ts Fixes object literal formatting with trailing commas.
frontend/src/lib/notifications/stream.svelte.ts Import formatting + expands for await loop into block.
frontend/src/lib/notifications/tests/stream.test.ts Formatting updates for helpers and getter.
frontend/src/lib/formatters.ts Expands Intl options object formatting + adds trailing commas.
frontend/src/lib/editor/execution.svelte.ts Formatting updates; expands getters and ternary formatting.
frontend/src/lib/editor/tests/languages.test.ts Condenses it.each into a single call formatting style.
frontend/src/lib/editor/tests/execution.test.ts Formatting updates to parameterized tests and SSE helpers.
frontend/src/lib/api-interceptors.ts Formatting updates; expands mapped status message + joins pipeline.
frontend/src/lib/admin/stores/sagasStore.svelte.ts Import formatting + expands unwrapOr/API call formatting + filter formatting.
frontend/src/lib/admin/stores/executionsStore.svelte.ts Expands unwrapOr/API call formatting + interval cleanup formatting.
frontend/src/lib/admin/stores/eventsStore.svelte.ts Expands unwrapOr/API call formatting + replay/percent calc formatting.
frontend/src/lib/admin/stores/tests/sagasStore.test.ts Formatting updates to inline arrays.
frontend/src/lib/admin/stores/tests/executionsStore.test.ts Formatting updates to mock module exports.
frontend/src/lib/admin/stores/tests/eventsStore.test.ts Formatting updates; expands JSON.stringify calls and expectations.
frontend/src/lib/admin/sagas/sagaStates.ts Adds trailing commas for object entries.
frontend/src/lib/admin/sagas/tests/sagaStates.test.ts Import formatting + parameterized test formatting.
frontend/src/lib/admin/rate-limits/rateLimits.ts Adds trailing commas for object/array literals.
frontend/src/lib/admin/rate-limits/tests/rateLimits.test.ts Import formatting + expected object formatting.
frontend/src/lib/admin/pagination.svelte.ts Adds trailing commas + expands getters/setters for readability.
frontend/src/lib/admin/events/eventTypes.ts Adds trailing comma to EVENT_TYPES list.
frontend/src/lib/admin/events/tests/eventTypes.test.ts Formatting updates to expected arrays and parameterized tests.
frontend/src/lib/admin/constants.ts Adds trailing commas to exported constants.
frontend/src/lib/admin/tests/pagination.test.ts Removes stray blank line at end.
frontend/src/lib/admin/tests/constants.test.ts Import formatting + removes stray blank line at end.
frontend/src/lib/tests/user-settings.test.ts Formatting updates for mocks and expectations.
frontend/src/lib/tests/formatters.test.ts Formats Intl option objects and consolidates expectation formatting.
frontend/src/lib/tests/api-interceptors.test.ts Parameterized test formatting + adds parentheses for casts.
frontend/src/components/editor/tests/ScriptActions.test.ts Adds new unit tests for ScriptActions component.
frontend/src/components/editor/tests/SavedScripts.test.ts Formats inline script objects into multi-line literals.
frontend/src/components/editor/tests/ResourceLimits.test.ts Removes stray blank line.
frontend/src/components/editor/tests/OutputPanel.test.ts Formats test cases with nested objects.
frontend/src/components/editor/tests/LanguageSelect.test.ts Removes stray blank line + formats expectations.
frontend/src/components/editor/tests/EditorToolbar.test.ts Adds new unit tests for EditorToolbar component.
frontend/src/components/editor/tests/CodeMirrorEditor.test.ts Formats hoisted mocks and mock classes/options.
frontend/src/components/editor/ScriptActions.svelte Formats button markup blocks consistently.
frontend/src/components/editor/SavedScripts.svelte Formats toggle/list markup; minor layout changes.
frontend/src/components/editor/ResourceLimits.svelte Formats popover/button markup and handler expressions.
frontend/src/components/editor/LanguageSelect.svelte Formats menu markup and handlers; minor expression parenthesization.
frontend/src/components/editor/EditorToolbar.svelte Formats toolbar markup and attributes across lines.
frontend/src/components/editor/CodeMirrorEditor.svelte Switches to single quotes in CodeMirror theme selectors + formats dispatch calls.
frontend/src/components/admin/users/tests/UserFormModal.test.ts Updates test to satisfy new required fields on submit.
frontend/src/components/admin/users/tests/UserFilters.test.ts Formats advancedFilters setup and option mapping.
frontend/src/components/admin/users/tests/RateLimitsModal.test.ts Formats default rules mock data.
frontend/src/components/admin/users/tests/DeleteUserModal.test.ts Removes stray blank line.
frontend/src/components/admin/users/UsersTable.svelte Uses shared empty-state + adds spinner and improves table header semantics.
frontend/src/components/admin/users/UserFormModal.svelte Adds required constraints + formatting updates.
frontend/src/components/admin/users/UserFilters.svelte Formats bindables and expands markup blocks.
frontend/src/components/admin/users/DeleteUserModal.svelte Formatting updates + expands delete button markup.
frontend/src/components/admin/sagas/tests/SagaStatsCards.test.ts Formats hoisted mock component.
frontend/src/components/admin/sagas/tests/SagaFilters.test.ts Formats option mapping in assertions.
frontend/src/components/admin/sagas/tests/SagaDetailsModal.test.ts Formats formatter mocks.
frontend/src/components/admin/sagas/SagasTable.svelte Uses shared empty-state + improves table header semantics.
frontend/src/components/admin/sagas/SagaStatsCards.svelte Callback formatting for filters.
frontend/src/components/admin/sagas/SagaFilters.svelte Minor option attribute shorthand change + trailing comma cleanup.
frontend/src/components/admin/sagas/SagaDetailsModal.svelte Formats more blocks; minor markup layout changes.
frontend/src/components/admin/events/tests/UserOverviewModal.test.ts Formats helper signature and removes stray blank line.
frontend/src/components/admin/events/tests/ReplayProgressBanner.test.ts Formats nested session objects in tests.
frontend/src/components/admin/events/tests/ReplayPreviewModal.test.ts Formats preview fixtures and removes stray blank line.
frontend/src/components/admin/events/tests/EventsTable.test.ts Updates role name expectation for “View details for event”.
frontend/src/components/admin/events/tests/EventStatsCards.test.ts Formats parameterized tests and nested objects.
frontend/src/components/admin/events/tests/EventFilters.test.ts Formats option mapping in assertions.
frontend/src/components/admin/events/tests/EventDetailsModal.test.ts Formats helper signature and removes stray blank line.
frontend/src/components/admin/events/UserOverviewModal.svelte Formats profile/stats blocks for readability.
frontend/src/components/admin/events/ReplayProgressBanner.svelte Formats markup and conditional rendering blocks.
frontend/src/components/admin/events/ReplayPreviewModal.svelte Tightens copy + formats warning/footer buttons.
frontend/src/components/admin/events/EventStatsCards.svelte Formats conditional class expression across lines.
frontend/src/components/admin/events/EventFilters.svelte Formats markup and handlers; condenses button labels.
frontend/src/components/admin/events/EventDetailsModal.svelte Formats table cells and JSON preview; formats footer buttons.
frontend/src/components/admin/tests/FilterPanel.test.ts Formats parameterized tests.
frontend/src/components/admin/tests/AutoRefreshControl.test.ts Formats option mapping in assertion.
frontend/src/components/admin/FilterPanel.svelte Adds trailing commas + sets aria-expanded; formats buttons.
frontend/src/components/admin/AutoRefreshControl.svelte Adds trailing commas + formats select/button markup.
frontend/src/components/tests/Pagination.test.ts Formats parameterized tests and arrays.
frontend/src/components/tests/NotificationCenter.test.ts Formats hoisted getters, helpers, and parameterized tests.
frontend/src/components/tests/ModalWrapper.svelte Condenses prop destructuring for test wrapper.
frontend/src/components/tests/Header.test.ts Formats mocks/helpers and compresses long assertions.
frontend/src/components/tests/Footer.test.ts Formats external link filtering and assertions.
frontend/src/components/tests/EventTypeIcon.test.ts Fixes formatting/indentation in comparison assertion.
frontend/src/components/tests/ErrorDisplay.test.ts Fixes object literal formatting with trailing comma.
frontend/src/components/Spinner.svelte Formats prop destructuring; compacts SVG shape markup.
frontend/src/components/Pagination.svelte Adds aria-label for page size select; minor layout formatting.
frontend/src/components/NotificationCenter.svelte Uses shared Spinner component; formats async chaining and handlers.
frontend/src/components/Modal.svelte Adds Escape-key close handler on the backdrop/dialog container.
frontend/src/components/Footer.svelte Formats markup; keeps external link rel attributes explicit.
frontend/src/components/EventTypeIcon.svelte Normalizes iconMap keys; uses valid identifier keys for snake_case types.
frontend/src/components/ErrorDisplay.svelte Formats derived expressions and markup blocks for consistency.
frontend/src/tests/test-utils.ts Refactors factories/arrays formatting and improves readability.
frontend/src/App.svelte Normalizes quotes and route definitions; formatting cleanup.
frontend/package.json Adds Prettier scripts/deps; makes check fail on warnings.
frontend/eslint.config.js Makes svelte/button-has-type an error (stricter linting).
frontend/.prettierrc Adds Prettier configuration for the frontend (Svelte plugin).
frontend/.prettierignore Ignores build artifacts and generated API client files.
.pre-commit-config.yaml Adds Prettier check hook; aligns svelte-check with CI --fail-on-warnings.
.github/workflows/frontend-ci.yml Adds Prettier check + production build verification to CI.
Files not reviewed (1)
  • frontend/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread frontend/src/routes/Notifications.svelte
Comment thread frontend/src/components/Modal.svelte
Comment thread frontend/src/components/admin/FilterPanel.svelte
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Mar 4, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (12)
frontend/src/components/admin/events/__tests__/ReplayProgressBanner.test.ts (1)

1-2: ⚠️ Potential issue | 🟠 Major

Add afterEach(cleanup) to prevent cross-test DOM leakage.

beforeEach clears mocks, but DOM cleanup is missing, which violates the test standard and can cause state bleed across tests.

Suggested patch
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
@@
 describe('ReplayProgressBanner', () => {
     beforeEach(() => {
         vi.clearAllMocks();
     });
+
+    afterEach(() => {
+        cleanup();
+    });

As per coding guidelines: "Call cleanup() in Vitest afterEach, vi.clearAllMocks() in beforeEach".

Also applies to: 35-37

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/events/__tests__/ReplayProgressBanner.test.ts`
around lines 1 - 2, Tests are missing DOM cleanup between runs; import cleanup
from '@testing-library/svelte' and add afterEach(cleanup) alongside the existing
beforeEach setup (which should call vi.clearAllMocks()) so the DOM is torn down
after each test and prevents cross-test leakage; reference the test file's setup
where beforeEach and vi are used and add afterEach(cleanup) there, and ensure
the import list (render, screen, ...) includes cleanup.
frontend/src/lib/__tests__/user-settings.test.ts (1)

3-33: ⚠️ Potential issue | 🟠 Major

Hoist test mocks with vi.hoisted() before vi.mock() declarations.

Mock functions and objects are currently declared as top-level constants, then used in vi.mock() calls. Move all mock declarations into a vi.hoisted(() => ...) block to ensure they are properly hoisted and available to the mock factory functions.

Suggested pattern
-const mockGetUserSettings = vi.fn();
-const mockUpdateUserSettings = vi.fn();
+const { mockGetUserSettings, mockUpdateUserSettings, mockSetUserSettings, mockSetTheme, mockAuthStore } =
+    vi.hoisted(() => ({
+        mockGetUserSettings: vi.fn(),
+        mockUpdateUserSettings: vi.fn(),
+        mockSetUserSettings: vi.fn(),
+        mockSetTheme: vi.fn(),
+        mockAuthStore: { isAuthenticated: true as boolean | null },
+    }));
...
-const mockSetUserSettings = vi.fn();
...
-const mockSetTheme = vi.fn();
...
-const mockAuthStore = {
-    isAuthenticated: true as boolean | null,
-};

As per coding guidelines: frontend/src/**/__tests__/**/*.test.{ts,tsx} must hoist mocks with vi.hoisted() before vi.mock() declarations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/lib/__tests__/user-settings.test.ts` around lines 3 - 33, The
top-level mock variables (mockGetUserSettings, mockUpdateUserSettings,
mockSetUserSettings, mockSetTheme, mockAuthStore) are not hoisted and thus may
be undefined inside vi.mock factories; wrap all mock declarations in a
vi.hoisted(() => { ... }) block so they are created before any vi.mock() calls,
then update the existing vi.mock factories (the ones referencing
getUserSettingsApiV1UserSettingsGet, updateUserSettingsApiV1UserSettingsPut,
setUserSettings, setTheme, and authStore) to use those hoisted mocks (leave
factory bodies the same), ensuring you keep mock names unchanged so references
remain valid.
frontend/src/components/__tests__/Pagination.test.ts (1)

1-3: ⚠️ Potential issue | 🟡 Minor

Add cleanup() in afterEach to complete test isolation setup.

The file currently clears mocks in beforeEach (line 20) but lacks DOM cleanup between tests. Add afterEach to the vitest import, cleanup to the @testing-library/svelte import, and implement the afterEach hook as shown:

Proposed fix
-import { describe, it, expect, vi, beforeEach } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
@@
 describe('Pagination', () => {
     beforeEach(() => {
         vi.clearAllMocks();
     });
+
+    afterEach(() => {
+        cleanup();
+    });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/__tests__/Pagination.test.ts` around lines 1 - 3, Add
afterEach to the vitest import and import cleanup from
'@testing-library/svelte', then implement an afterEach hook that calls cleanup()
(and optionally vi.clearAllMocks() if you prefer clearing mocks there) to ensure
DOM is reset between tests; reference the existing beforeEach and use the
afterEach, cleanup, and vi.clearAllMocks symbols when making the change.
frontend/src/routes/Settings.svelte (1)

91-96: ⚠️ Potential issue | 🟠 Major

Guard can race auth initialization before settings load.

This mount-time check reads authStore.isAuthenticated immediately without awaiting initialization. If auth verification is in progress, settings can be skipped for an eventually authenticated user.

🔒 Suggested fix
-    onMount(() => {
-        if (!authStore.isAuthenticated) {
-            return;
-        }
-        loadSettings();
-    });
+    onMount(() => {
+        void (async () => {
+            await authStore.waitForInit();
+            if (!authStore.isAuthenticated) return;
+            await loadSettings();
+        })();
+    });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/routes/Settings.svelte` around lines 91 - 96, The onMount check
reads authStore.isAuthenticated immediately and can race auth initialization;
change the onMount handler to wait for auth initialization or reactively
subscribe to authStore and call loadSettings once authStore.isAuthenticated
becomes true (or when an authStore.isInitialized flag flips), instead of
skipping loadSettings on the immediate check—update the onMount block, the
authStore access, and ensure loadSettings is invoked when the store updates
(e.g., via authStore.subscribe or an awaitable init method) so authenticated
users always load settings.
frontend/src/components/__tests__/Spinner.test.ts (1)

1-3: ⚠️ Potential issue | 🟡 Minor

Add required Vitest lifecycle hooks for test cleanup and mock management.

The suite is missing the standardized beforeEach and afterEach hooks required by project test conventions. Multiple render() calls throughout the tests (lines 10, 26, 33, 47, 52, 59, 69, 80, 89, 97) need proper cleanup between test runs.

🔧 Suggested patch
-import { describe, it, expect } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
 import Spinner from '$components/Spinner.svelte';
 
 describe('Spinner', () => {
+    beforeEach(() => {
+        vi.clearAllMocks();
+    });
+
+    afterEach(() => {
+        cleanup();
+    });
+
     const getSpinner = () => screen.getByRole('status');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/__tests__/Spinner.test.ts` around lines 1 - 3, Add
Vitest lifecycle hooks to ensure test isolation: import beforeEach and afterEach
from 'vitest' (and import cleanup from '@testing-library/svelte' if not already)
in Spinner.test.ts, then add a beforeEach that calls vi.restoreAllMocks() and
vi.clearAllMocks() and an afterEach that calls cleanup() to ensure every
render() of Spinner is cleaned up between tests; reference the existing
render/screen/Spinner usages so hooks run for all tests in this file.
frontend/src/components/editor/OutputPanel.svelte (1)

10-18: ⚠️ Potential issue | 🟡 Minor

Use interface Props for $props() instead of an inline object shape.

Lines 10–18 use an inline object type annotation, which violates the project's convention of extracting prop types to a named interface.

Proposed fix
+    interface Props {
+        phase: ExecutionPhase;
+        result: ExecutionResult | null;
+        error: string | null;
+    }
+
     let {
         phase,
         result,
         error,
-    }: {
-        phase: ExecutionPhase;
-        result: ExecutionResult | null;
-        error: string | null;
-    } = $props();
+    }: Props = $props();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/editor/OutputPanel.svelte` around lines 10 - 18,
Extract the inline prop type into a named interface called Props and use that
for the $props() annotation: create interface Props { phase: ExecutionPhase;
result: ExecutionResult | null; error: string | null; } and then change the
destructuring from the inline annotation to use Props (i.e., let { phase,
result, error }: Props = $props()). Update any imports/exports if needed and
ensure ExecutionPhase and ExecutionResult types remain referenced correctly.
frontend/src/components/admin/events/ReplayProgressBanner.svelte (1)

18-23: ⚠️ Potential issue | 🟠 Major

Add an explicit accessible name to the icon-only close button.

The button is icon-only; title is not a reliable accessible name. Add aria-label so screen readers consistently announce the action.

Suggested patch
         <button
             type="button"
             onclick={onClose}
+            aria-label="Close replay progress banner"
             class="absolute top-2 right-2 p-1 hover:bg-blue-100 dark:hover:bg-blue-800 rounded-lg transition-colors"
             title="Close"
         >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/events/ReplayProgressBanner.svelte` around
lines 18 - 23, The icon-only close button in the ReplayProgressBanner.svelte
component relies on title for accessibility; add an explicit accessible name by
adding an aria-label (e.g., aria-label="Close" or a localized equivalent) to the
<button> that uses onclick={onClose}, so screen readers consistently announce
the action instead of relying on title alone.
frontend/src/routes/admin/AdminUsers.svelte (1)

151-189: ⚠️ Potential issue | 🟠 Major

Ensure savingUser is reset on all failure paths.

At Line 160, savingUser is set to true, but it’s only reset at Line 185. If any awaited call throws before that point, the modal can stay stuck in a loading/disabled state.

Suggested fix
 async function saveUser(): Promise<void> {
@@
-    savingUser = true;
-
-    let result;
-
-    if (editingUser) {
-        const updateData: UserUpdate = {
-            username: userForm.username,
-            email: userForm.email || null,
-            role: userForm.role,
-            is_active: userForm.is_active,
-        };
-        if (userForm.password) updateData.password = userForm.password;
-        result = await updateUserApiV1AdminUsersUserIdPut({
-            path: { user_id: editingUser.user_id },
-            body: updateData,
-        });
-    } else {
-        result = await createUserApiV1AdminUsersPost({
-            body: {
-                username: userForm.username,
-                email: userForm.email,
-                password: userForm.password,
-                role: userForm.role,
-                is_active: userForm.is_active,
-            },
-        });
-    }
-
-    savingUser = false;
-
-    unwrap(result);
-    showUserModal = false;
-    await loadUsers();
+    savingUser = true;
+    try {
+        let result;
+
+        if (editingUser) {
+            const updateData: UserUpdate = {
+                username: userForm.username,
+                email: userForm.email || null,
+                role: userForm.role,
+                is_active: userForm.is_active,
+            };
+            if (userForm.password) updateData.password = userForm.password;
+            result = await updateUserApiV1AdminUsersUserIdPut({
+                path: { user_id: editingUser.user_id },
+                body: updateData,
+            });
+        } else {
+            result = await createUserApiV1AdminUsersPost({
+                body: {
+                    username: userForm.username,
+                    email: userForm.email,
+                    password: userForm.password,
+                    role: userForm.role,
+                    is_active: userForm.is_active,
+                },
+            });
+        }
+
+        unwrap(result);
+        showUserModal = false;
+        await loadUsers();
+    } finally {
+        savingUser = false;
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/routes/admin/AdminUsers.svelte` around lines 151 - 189, The
saveUser function sets savingUser = true but only clears it after awaited calls
succeed, so any thrown error leaves the UI stuck; wrap the API/unwrap/loadUsers
flow in a try/catch/finally inside saveUser (or at minimum use a finally block)
to ensure savingUser is set to false regardless of failures, keep
showUserModal=false and loadUsers/unwrap inside the successful path (try) and
handle or rethrow errors in catch, and reference saveUser, savingUser,
updateUserApiV1AdminUsersUserIdPut, createUserApiV1AdminUsersPost, unwrap,
showUserModal, and loadUsers to locate where to add the try/catch/finally.
frontend/src/components/admin/sagas/__tests__/SagaFilters.test.ts (1)

1-2: ⚠️ Potential issue | 🟠 Major

Add cleanup() in afterEach for this test suite.

The test file renders DOM elements via renderFilters() in multiple tests but lacks cleanup teardown. While vi.clearAllMocks() is correctly placed in beforeEach, the missing afterEach cleanup can cause test pollution.

Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
@@
 describe('SagaFilters', () => {
     beforeEach(() => vi.clearAllMocks());
+    afterEach(() => cleanup());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/sagas/__tests__/SagaFilters.test.ts` around
lines 1 - 2, Add a teardown step to this test suite by calling cleanup() in an
afterEach block so DOM rendered by renderFilters() is unmounted between tests;
keep the existing vi.clearAllMocks() in beforeEach and add afterEach(() =>
cleanup()) (or the equivalent cleanup import) near the top of the file to
prevent test pollution from leftover DOM nodes and listeners.
frontend/src/components/admin/__tests__/AutoRefreshControl.test.ts (1)

1-2: ⚠️ Potential issue | 🟠 Major

Add cleanup() in afterEach for consistent DOM teardown.

beforeEach clearing is present (line 30), but cleanup() teardown is missing.

Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
@@
 describe('AutoRefreshControl', () => {
     beforeEach(() => vi.clearAllMocks());
+    afterEach(() => cleanup());

As per coding guidelines: Call cleanup() in Vitest afterEach, vi.clearAllMocks() in beforeEach.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/__tests__/AutoRefreshControl.test.ts` around
lines 1 - 2, Import cleanup from '@testing-library/svelte' and add an afterEach
hook that calls cleanup() to ensure consistent DOM teardown; locate the existing
beforeEach and ensure it calls vi.clearAllMocks() (use vi.clearAllMocks() inside
beforeEach) so test mocks are reset, and reference the symbols import {
beforeEach, afterEach, vi } and the cleanup function to guide placement.
frontend/src/components/admin/sagas/__tests__/SagaStatsCards.test.ts (1)

1-2: ⚠️ Potential issue | 🟡 Minor

Add afterEach(cleanup) to complete test lifecycle hygiene.

This suite clears mocks in beforeEach but does not clean up rendered DOM. Tests calling render() and rerender() require cleanup between runs to prevent DOM leakage.

Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
@@
 describe('SagaStatsCards', () => {
     beforeEach(() => vi.clearAllMocks());
+    afterEach(() => cleanup());

Per coding guidelines: Call cleanup() in Vitest afterEach, vi.clearAllMocks() in beforeEach.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/sagas/__tests__/SagaStatsCards.test.ts` around
lines 1 - 2, The test suite is missing DOM cleanup between tests; import cleanup
from '@testing-library/svelte' and add afterEach(cleanup) alongside the existing
beforeEach(() => vi.clearAllMocks()) to ensure render()/rerender() calls don't
leak DOM between tests by invoking cleanup after each test.
frontend/src/routes/__tests__/Notifications.test.ts (1)

1-2: ⚠️ Potential issue | 🟡 Minor

Add afterEach(cleanup) to prevent cross-test DOM leakage.

The suite resets mocks in beforeEach, but does not clean rendered DOM between tests. Multiple render() calls across test cases can leave DOM artifacts.

Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen, waitFor } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, waitFor, cleanup } from '@testing-library/svelte';
@@
 describe('Notifications', () => {
     beforeEach(() => {
         vi.clearAllMocks();
@@
     });
+    afterEach(() => cleanup());

Per coding guidelines: Call cleanup() in Vitest afterEach, vi.clearAllMocks() in beforeEach.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/routes/__tests__/Notifications.test.ts` around lines 1 - 2, Add
a test-level cleanup step to avoid DOM leakage: call cleanup() in an afterEach
hook (afterEach(cleanup)) so every render from render() is removed between
tests, and ensure mocks are cleared in the beforeEach by calling
vi.clearAllMocks() (or add it if missing) alongside existing setup; locate the
test suite using describe/it/beforeEach imports in Notifications.test.ts and add
these lifecycle hooks.
🟡 Minor comments (23)
frontend/src/components/admin/events/__tests__/ReplayProgressBanner.test.ts-28-31 (1)

28-31: ⚠️ Potential issue | 🟡 Minor

Make the render helper async and await tick() after render.

The helper returns before Svelte microtasks flush. Per test conventions in this repo, it should await tick() and callers should await the helper.

Based on learnings: "Applies to frontend/src//tests//*.test.{ts,tsx} : Use await tick() after Svelte render, waitFor() for async state in Vitest".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/events/__tests__/ReplayProgressBanner.test.ts`
around lines 28 - 31, The render helper renderBanner currently returns
immediately after calling render(ReplayProgressBanner...), which means Svelte
microtasks may not have flushed; make renderBanner async, call render as before,
then await tick() before returning (preserving and returning the onClose vi.fn
and render result) so callers can await the helper and rely on flushed Svelte
state.
frontend/src/components/admin/events/__tests__/ReplayPreviewModal.test.ts-35-43 (1)

35-43: ⚠️ Potential issue | 🟡 Minor

Synchronize post-render assertions with await tick().

Project test rules require await tick() after Svelte render. Consider making renderModal async and awaiting it in tests to reduce timing flakes.

Suggested patch
 import { user } from '$test/test-utils';
+import { tick } from 'svelte';
@@
-function renderModal(overrides: Partial<{ preview: ReplayPreview | null; open: boolean }> = {}) {
+async function renderModal(overrides: Partial<{ preview: ReplayPreview | null; open: boolean }> = {}) {
@@
-    return { ...result, onClose, onConfirm };
+    await tick();
+    return { ...result, onClose, onConfirm };
 }
@@
-    it('renders nothing when closed', () => {
-        renderModal({ open: false });
+    it('renders nothing when closed', async () => {
+        await renderModal({ open: false });
@@
-    it('renders nothing visible when preview is null', () => {
-        renderModal({ preview: null });
+    it('renders nothing visible when preview is null', async () => {
+        await renderModal({ preview: null });

Based on learnings: “Use await tick() after Svelte render, waitFor() for async state in Vitest.”

Also applies to: 50-117

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/events/__tests__/ReplayPreviewModal.test.ts`
around lines 35 - 43, The tests are missing the required await tick() after
Svelte render which causes timing flakes; make renderModal async, call
render(ReplayPreviewModal, ...) then await tick(), and update tests to await
renderModal(...) so post-render assertions are synchronized; reference the
renderModal helper, the ReplayPreviewModal component, and the onClose/onConfirm
mock props when making these changes.
frontend/src/components/__tests__/Modal.test.ts-7-9 (1)

7-9: ⚠️ Potential issue | 🟡 Minor

Missing cleanup() call in afterEach hook.

The file includes vi.clearAllMocks() in beforeEach but lacks a corresponding afterEach hook with cleanup(). As per coding guidelines, Vitest tests must call cleanup() in afterEach to prevent test pollution and memory leaks.

🧹 Proposed fix to add cleanup
-import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
 import { render, screen, fireEvent } from '@testing-library/svelte';
+import { cleanup } from '@testing-library/svelte';
 import { user } from '$test/test-utils';
 import ModalWrapper from './ModalWrapper.svelte';

 describe('Modal', () => {
     beforeEach(() => {
         vi.clearAllMocks();
     });
+
+    afterEach(() => {
+        cleanup();
+    });

Based on learnings: "Call cleanup() in Vitest afterEach, vi.clearAllMocks() in beforeEach"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/__tests__/Modal.test.ts` around lines 7 - 9, Add an
afterEach hook that calls cleanup() to avoid test pollution; currently only
beforeEach runs vi.clearAllMocks(), so add afterEach(() => cleanup()) alongside
the existing beforeEach that invokes vi.clearAllMocks() in Modal.test.ts so DOM
and side effects are cleaned between tests.
frontend/src/components/Modal.svelte-29-37 (1)

29-37: ⚠️ Potential issue | 🟡 Minor

Avoid double-calling onClose on Escape.

Line 29 and Line 36 both handle Escape, so a single key press can invoke onClose() twice via bubbling + window listener. Keep only one Escape handler (prefer the window one) or stop propagation in the inner handler.

Suggested fix
 <svelte:window onkeydown={(e) => open && e.key === 'Escape' && onClose()} />

 {`#if` open}
     <div
         class="modal-backdrop"
         transition:fade={{ duration: 150 }}
         onclick={handleBackdropClick}
-        onkeydown={(e) => e.key === 'Escape' && onClose()}
         role="dialog"
         aria-modal="true"
         aria-labelledby="modal-title"
         tabindex="-1"
     >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/Modal.svelte` around lines 29 - 37, The Escape key is
handled twice: by the svelte:window onkeydown handler and by the modal div's
onkeydown, causing onClose() to run twice; fix by removing the inner
onkeydown={(e) => e.key === 'Escape' && onClose()} from the modal div (or
alternatively make the inner handler call e.stopPropagation() before invoking
onClose), ensuring only the svelte:window onkeydown triggers onClose; update
references in Modal.svelte where svelte:window onkeydown, the modal div
role="dialog" element, and handleBackdropClick/onClose are used.
frontend/src/lib/admin/stores/sagasStore.svelte.ts-1-1 (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Split mixed value/type import on Line 1.

This mixes a value import and a type-only import in one statement. Please split it into separate imports.

Suggested fix
-import { listSagasApiV1SagasGet, type SagaStatusResponse } from '$lib/api';
+import { listSagasApiV1SagasGet } from '$lib/api';
+import type { SagaStatusResponse } from '$lib/api';

As per coding guidelines: Use import type for type-only imports — never mix type and value imports in single import statement.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/lib/admin/stores/sagasStore.svelte.ts` at line 1, The import
currently mixes a value and a type: split the statement so the runtime import
for the API function (listSagasApiV1SagasGet) stays in a normal import and the
type-only import (SagaStatusResponse) uses an "import type" declaration; update
the top of the file to have one import for listSagasApiV1SagasGet and a separate
"import type { SagaStatusResponse }" import so the type-only symbol is not
imported as a runtime value.
frontend/src/lib/admin/sagas/__tests__/sagaStates.test.ts-6-13 (1)

6-13: ⚠️ Potential issue | 🟡 Minor

cancelled is missing from explicit “all expected states” coverage.

The suite claims full-state coverage but skips explicit cancelled assertions in these checks. That can let regressions slip through.

Suggested patch
         it('has all expected states', () => {
             expect(SAGA_STATES.created).toBeDefined();
             expect(SAGA_STATES.running).toBeDefined();
             expect(SAGA_STATES.compensating).toBeDefined();
             expect(SAGA_STATES.completed).toBeDefined();
             expect(SAGA_STATES.failed).toBeDefined();
             expect(SAGA_STATES.timeout).toBeDefined();
+            expect(SAGA_STATES.cancelled).toBeDefined();
         });

         it('has correct labels', () => {
             expect(SAGA_STATES.created.label).toBe('Created');
             expect(SAGA_STATES.running.label).toBe('Running');
+            expect(SAGA_STATES.compensating.label).toBe('Compensating');
             expect(SAGA_STATES.completed.label).toBe('Completed');
             expect(SAGA_STATES.failed.label).toBe('Failed');
+            expect(SAGA_STATES.timeout.label).toBe('Timeout');
+            expect(SAGA_STATES.cancelled.label).toBe('Cancelled');
         });

Also applies to: 24-29

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/lib/admin/sagas/__tests__/sagaStates.test.ts` around lines 6 -
13, The test "has all expected states" is missing an explicit assertion for
SAGA_STATES.cancelled; update the test(s) that enumerate expected states (the
block referencing
SAGA_STATES.created/running/compensating/completed/failed/timeout) to also
assert expect(SAGA_STATES.cancelled).toBeDefined(); and apply the same addition
to the other similar assertion block later in the file (the second occurrence
around the other test covering states) so the suite explicitly covers the
cancelled state.
frontend/src/lib/admin/sagas/__tests__/sagaStates.test.ts-1-3 (1)

1-3: ⚠️ Potential issue | 🟡 Minor

Add standard Vitest isolation hooks for this test file.

Please add beforeEach(() => vi.clearAllMocks()) and afterEach(() => cleanup()) to keep test isolation consistent as this suite evolves.

Suggested patch
-import { describe, it, expect } from 'vitest';
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+import { cleanup } from '@testing-library/svelte';
 import { SAGA_STATES, getSagaStateInfo } from '$lib/admin/sagas/sagaStates';

 describe('sagaStates', () => {
+    beforeEach(() => {
+        vi.clearAllMocks();
+    });
+
+    afterEach(() => {
+        cleanup();
+    });
+
     describe('SAGA_STATES', () => {
As per coding guidelines, "Call `cleanup()` in Vitest `afterEach`, `vi.clearAllMocks()` in `beforeEach`."

Also applies to: 4-5

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/lib/admin/sagas/__tests__/sagaStates.test.ts` around lines 1 -
3, Add Vitest isolation hooks to this test file: import beforeEach, afterEach,
and vi from 'vitest' (e.g. import { describe, it, expect, beforeEach, afterEach,
vi } from 'vitest') and import cleanup from '@testing-library/svelte'; then add
beforeEach(() => vi.clearAllMocks()) and afterEach(() => cleanup()) at the
top-level of the test file (the one importing SAGA_STATES and getSagaStateInfo)
so mocks and DOM are reset between tests.
frontend/src/routes/__tests__/Settings.test.ts-79-83 (1)

79-83: ⚠️ Potential issue | 🟡 Minor

Add explicit cleanup() and post-render tick() in test scaffolding.

Line 79 currently unstubs globals only. Add DOM cleanup in afterEach and await tick() after render to ensure proper test isolation and Svelte reactivity synchronization.

🔧 Proposed patch
-import { render, screen, waitFor } from '@testing-library/svelte';
+import { render, screen, waitFor, cleanup } from '@testing-library/svelte';
+import { tick } from 'svelte';
@@
-    afterEach(() => vi.unstubAllGlobals());
+    afterEach(() => {
+        cleanup();
+        vi.unstubAllGlobals();
+    });
@@
-    function renderSettings() {
-        return render(Settings);
+    async function renderSettings() {
+        const utils = render(Settings);
+        await tick();
+        return utils;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/routes/__tests__/Settings.test.ts` around lines 79 - 83, The
test teardown only calls vi.unstubAllGlobals() and the render helper returns
render(Settings) without awaiting Svelte microtasks; update the afterEach block
to also call cleanup() to unmount DOM between tests and change renderSettings()
to await render(Settings) followed by awaiting tick() so Svelte reactive updates
settle; reference the existing afterEach, vi.unstubAllGlobals(),
renderSettings(), and the Settings component when making these edits.
frontend/src/lib/admin/rate-limits/__tests__/rateLimits.test.ts-1-4 (1)

1-4: ⚠️ Potential issue | 🟡 Minor

Add the required Vitest isolation hooks in this test file.

This suite is missing the required beforeEach/afterEach pattern for mock reset and cleanup as per frontend test standards.

🔧 Suggested patch
-import { describe, it, expect } from 'vitest';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { cleanup } from '@testing-library/svelte';
 import type { EndpointGroup } from '$lib/api';
 import { getGroupColor, detectGroupFromEndpoint, createEmptyRule } from '$lib/admin/rate-limits/rateLimits';
 
 const EXPECTED_GROUPS: EndpointGroup[] = ['execution', 'admin', 'sse', 'websocket', 'auth', 'api', 'public'];
 
 describe('rateLimits', () => {
+    beforeEach(() => {
+        vi.clearAllMocks();
+    });
+
+    afterEach(() => {
+        cleanup();
+    });
+
     describe('getGroupColor', () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/lib/admin/rate-limits/__tests__/rateLimits.test.ts` around lines
1 - 4, Add Vitest isolation hooks to reset and restore mocks and cleanup between
tests: import beforeEach and afterEach (and vi if not already available) from
'vitest' alongside describe/it/expect, then add beforeEach(() => {
vi.resetAllMocks(); vi.clearAllMocks(); }) and afterEach(() => {
vi.restoreAllMocks(); }); if the test suite uses DOM testing-library utilities,
also call cleanup() from '@testing-library/svelte' in afterEach. Apply these
changes near the top of the file where describe/it/expect are imported — this
will ensure tests exercising getGroupColor, detectGroupFromEndpoint, and
createEmptyRule run in isolation.
frontend/src/lib/formatters.ts-59-78 (1)

59-78: ⚠️ Potential issue | 🟡 Minor

Guard formatDuration against non-finite inputs.

formatDuration(NaN) and formatDuration(Infinity) currently produce invalid output (e.g., "NaNh", "Infinityh") instead of returning 'N/A'. The issue occurs because NaN < 0 and Infinity < 0 both evaluate to false, bypassing the guard checks.

🛠️ Proposed fix
 export function formatDuration(seconds: number | null | undefined): string {
-    if (seconds === null || seconds === undefined) return 'N/A';
-    if (seconds < 0) return 'N/A';
+    if (seconds === null || seconds === undefined) return 'N/A';
+    if (!Number.isFinite(seconds) || seconds < 0) return 'N/A';
 
     if (seconds < 1) {
         return `${Math.round(seconds * 1000)}ms`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/lib/formatters.ts` around lines 59 - 78, formatDuration
currently returns strange strings for non-finite inputs (NaN, Infinity); add an
early guard that treats any non-finite numeric input as invalid by checking
Number.isFinite(seconds) (after the null/undefined check) and returning 'N/A'
when it fails, then proceed with existing logic; update the function around the
initial guards that include the null/undefined and negative checks to include
this finite-number check so NaN/Infinity don't flow into the later formatting
branches.
frontend/src/lib/formatters.ts-133-137 (1)

133-137: ⚠️ Potential issue | 🟡 Minor

Handle truncate boundary values for very small maxLength.

The current implementation fails for maxLength ≤ 2: it produces output exceeding the requested max length. For example, truncate('hello world', 2) returns a 13-character string instead of 2 characters. This occurs because str.slice(0, maxLength - 3) produces problematic results when maxLength < 3. While current usage in the codebase specifies maxLength = 12, the function should handle these edge cases gracefully.

🛠️ Proposed fix
 export function truncate(str: string | null | undefined, maxLength = 50): string {
-    if (!str) return '';
+    if (!str || maxLength <= 0) return '';
     if (str.length <= maxLength) return str;
+    if (maxLength <= 3) return '.'.repeat(maxLength);
     return `${str.slice(0, maxLength - 3)}...`;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/lib/formatters.ts` around lines 133 - 137, The truncate function
breaks for maxLength ≤ 2 because maxLength - 3 becomes negative; change the
logic in truncate(str, maxLength) so it always returns a string no longer than
maxLength: if str is falsy return '', if str.length <= maxLength return str,
else if maxLength <= 3 return str.slice(0, maxLength) (no ellipsis), otherwise
return `${str.slice(0, maxLength - 3)}...`. Update the behavior in the truncate
function to use these branches so the output length is never larger than
maxLength.
frontend/src/components/editor/__tests__/SavedScripts.test.ts-21-34 (1)

21-34: ⚠️ Potential issue | 🟡 Minor

Add standard test lifecycle hooks and await post-render tick.

This test file lacks beforeEach/afterEach hygiene hooks and does not await tick() after rendering, allowing mock state and DOM residue to leak between tests.

Add imports for afterEach, cleanup, and tick:

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { render, screen, cleanup } from '@testing-library/svelte';
+import { tick } from 'svelte';

Make renderScripts async and await tick() post-render:

-function renderScripts(scripts: SavedScriptResponse[] = []) {
+async function renderScripts(scripts: SavedScriptResponse[] = []) {
     const onload = vi.fn();
     const ondelete = vi.fn();
     const onrefresh = vi.fn();
     const result = render(SavedScripts, { props: { scripts, onload, ondelete, onrefresh } });
+    await tick();
     return { ...result, onload, ondelete, onrefresh };
 }

Add lifecycle hooks to the describe block and await renderScripts:

 describe('SavedScripts', () => {
+    beforeEach(() => {
+        vi.clearAllMocks();
+    });
+    afterEach(() => {
+        cleanup();
+    });
+
     async function renderAndExpand(scripts: SavedScriptResponse[] = []) {
-        const result = renderScripts(scripts);
+        const result = await renderScripts(scripts);
         await user.click(screen.getByRole('button', { name: /Show Saved Scripts/i }));
         return result;
     }

Update all direct renderScripts() calls throughout the describe block to await renderScripts().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/editor/__tests__/SavedScripts.test.ts` around lines
21 - 34, The tests leak DOM/mocks because renderScripts and callers don't await
the post-render tick and there's no test cleanup; import afterEach, cleanup and
tick from your test utils, make renderScripts async and await tick() after
calling render(...), add lifecycle hooks inside the describe block (use
afterEach(() => cleanup()) and optionally beforeEach to reset mocks if needed),
and update all renderScripts() and renderAndExpand() calls to await
renderScripts(...) so the DOM settles before interacting with it.
frontend/src/components/admin/events/__tests__/EventFilters.test.ts-9-21 (1)

9-21: ⚠️ Potential issue | 🟡 Minor

Align test lifecycle and render timing with repo test conventions.

This test file is missing cleanup() in an afterEach hook and does not await a post-render tick(), both required by the frontend test guidelines. The renderFilters helper must be async and await tick() after rendering; all test call sites must await the helper.

🛠️ Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
+import { tick } from 'svelte';
 import { user } from '$test/test-utils';
 import { EVENT_TYPES } from '$lib/admin/events/eventTypes';
 import type { EventFilter } from '$lib/api';

 import EventFilters from '$components/admin/events/EventFilters.svelte';

-function renderFilters(overrides: Partial<{ onApply: () => void; onClear: () => void; filters: EventFilter }> = {}) {
+async function renderFilters(
+    overrides: Partial<{ onApply: () => void; onClear: () => void; filters: EventFilter }> = {},
+) {
     const onApply = overrides.onApply ?? vi.fn();
     const onClear = overrides.onClear ?? vi.fn();
     const filters: EventFilter = overrides.filters ?? {};
     const result = render(EventFilters, { props: { filters, onApply, onClear } });
+    await tick();
     return { ...result, onApply, onClear };
 }

 describe('EventFilters', () => {
     beforeEach(() => {
         vi.clearAllMocks();
     });
+    afterEach(() => {
+        cleanup();
+    });

Update all test call sites to await renderFilters() (lines 23, 38, 44, 51, 57, 63).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/events/__tests__/EventFilters.test.ts` around
lines 9 - 21, Tests don't follow repo test lifecycle: make renderFilters async,
await render and then await tick() inside it (function name: renderFilters) and
update all tests that call it to use await renderFilters(); also add an
afterEach hook that calls cleanup() (and vi.clearAllMocks() can remain in
beforeEach) so the DOM is torn down between tests and post-render updates are
awaited per guidelines.
frontend/src/components/__tests__/Header.test.ts-78-103 (1)

78-103: ⚠️ Potential issue | 🟡 Minor

Add required test isolation hooks (vi.clearAllMocks and cleanup).

beforeEach/afterEach currently miss the repository-required cleanup pattern, which can leak mock and DOM state across tests.

Proposed fix
-import { render, screen, waitFor } from '@testing-library/svelte';
+import { render, screen, waitFor, cleanup } from '@testing-library/svelte';
@@
     beforeEach(() => {
+        vi.clearAllMocks();
         setAuth(false);
         mocks.mockThemeStore.value = 'auto';
@@
     afterEach(() => {
+        cleanup();
         Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: originalInnerWidth });
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/__tests__/Header.test.ts` around lines 78 - 103, The
tests lack required isolation: add vi.clearAllMocks() at the start of beforeEach
and call cleanup() in afterEach to reset mocked state and DOM between tests;
specifically update the beforeEach block (where setAuth, mocks.mockThemeStore,
vi.spyOn(router, 'goto'), and matchMedia are configured) to invoke
vi.clearAllMocks() before other setup, and update the afterEach block that
restores window.innerWidth to also call cleanup() to unmount DOM and listeners.
frontend/src/components/editor/__tests__/OutputPanel.test.ts-35-39 (1)

35-39: ⚠️ Potential issue | 🟡 Minor

Add afterEach(cleanup) for rendered component tests.

The test suite renders the component in 14+ test cases across multiple nested describe blocks. DOM cleanup is missing, which can cause test isolation issues. While vi.clearAllMocks() is correctly placed in beforeEach, the corresponding DOM cleanup in afterEach is required.

Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
@@
     beforeEach(() => {
         vi.clearAllMocks();
         vi.spyOn(toast, 'success');
         vi.spyOn(toast, 'error');
     });
+
+    afterEach(() => {
+        cleanup();
+    });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/editor/__tests__/OutputPanel.test.ts` around lines 35
- 39, Add DOM cleanup after each test in this suite by calling
afterEach(cleanup) alongside the existing beforeEach; import cleanup from
'@testing-library/react' at the top if not present, then add afterEach(cleanup)
in the same scope as the existing beforeEach block (where vi.clearAllMocks() and
vi.spyOn(toast, 'success'|'error') are set) to ensure rendered components are
unmounted between tests.
frontend/src/components/__tests__/Header.test.ts-66-74 (1)

66-74: ⚠️ Potential issue | 🟡 Minor

Add await tick() after render in interaction helpers.

These helpers call render(Header) immediately followed by user interaction without allowing Svelte effects to settle. Add await tick() after each render() call to ensure component state is ready before interaction.

Proposed fix
-import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { tick } from 'svelte';
 import { render, screen, waitFor } from '@testing-library/svelte';
 
     const openUserDropdown = async () => {
         render(Header);
+        await tick();
         await user.click(screen.getByRole('button', { name: 'User menu' }));
     };
 
     const openMobileMenu = async () => {
         render(Header);
+        await tick();
         await user.click(screen.getByRole('button', { name: 'Open menu' }));
     };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/__tests__/Header.test.ts` around lines 66 - 74, Both
helpers call render(Header) then interact immediately; add "await tick()" right
after each render(Header) in openUserDropdown and openMobileMenu so Svelte's
microtask queue settles before user.click, and ensure tick is imported from
'svelte' at the top of the test file if not already present.
frontend/src/components/editor/__tests__/CodeMirrorEditor.test.ts-108-112 (1)

108-112: ⚠️ Potential issue | 🟡 Minor

Add afterEach(cleanup) to prevent DOM leakage between tests.

This suite renders components via renderEditor() and clears mocks in beforeEach, but it missing testing-library cleanup. The test file uses render() multiple times (lines 114, 122, 134, 146, 157, 166, 173) which mounts components to the DOM and requires cleanup after each test.

Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, waitFor } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, waitFor, cleanup } from '@testing-library/svelte';
@@
     beforeEach(() => {
         vi.clearAllMocks();
         document.documentElement.classList.remove('dark');
     });
+
+    afterEach(() => {
+        cleanup();
+    });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/editor/__tests__/CodeMirrorEditor.test.ts` around
lines 108 - 112, The test suite is leaking DOM between tests because it never
calls testing-library's cleanup; import cleanup from '@testing-library/react'
and add an afterEach(cleanup) call in this file (alongside the existing
beforeEach that calls vi.clearAllMocks and removes the 'dark' class) so every
render created by renderEditor()/render() is unmounted and the DOM is reset
between tests (add the import and the afterEach invocation near the top of the
file where beforeEach is defined).
frontend/src/routes/admin/AdminSagas.svelte-3-3 (1)

3-3: ⚠️ Potential issue | 🟡 Minor

Split type-only import from value import.

Line 3 mixes a type and value in a single import statement. Type-only imports must be separated.

Suggested patch
-import { getSagaStatusApiV1SagasSagaIdGet, type SagaStatusResponse } from '$lib/api';
+import { getSagaStatusApiV1SagasSagaIdGet } from '$lib/api';
+import type { SagaStatusResponse } from '$lib/api';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/routes/admin/AdminSagas.svelte` at line 3, Split the mixed
import so value and type are separate: keep the runtime function
getSagaStatusApiV1SagasSagaIdGet in a regular import and move SagaStatusResponse
into a type-only import using the "import type" form; update the import lines
that reference getSagaStatusApiV1SagasSagaIdGet and SagaStatusResponse in
AdminSagas.svelte accordingly so the value import and the type-only import are
distinct.
frontend/src/components/admin/users/__tests__/UserFilters.test.ts-29-29 (1)

29-29: ⚠️ Potential issue | 🟡 Minor

Add afterEach(cleanup) to complete lifecycle hygiene.

This test suite clears mocks in beforeEach but is missing the corresponding afterEach(cleanup) call. Since the file renders a Svelte component multiple times across tests, cleanup must be called after each test to avoid DOM state leakage.

Add the import: import { cleanup } from '@testing-library/svelte'; and add the hook: afterEach(cleanup); after the beforeEach call on line 29.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/users/__tests__/UserFilters.test.ts` at line
29, The test suite currently calls vi.clearAllMocks() in beforeEach but never
performs DOM cleanup; add an import for cleanup from '@testing-library/svelte'
and register afterEach(cleanup) alongside the existing beforeEach to ensure
Svelte components are unmounted between tests; update the top-level imports to
include cleanup and add afterEach(cleanup); next to the existing beforeEach(()
=> vi.clearAllMocks()) so the test lifecycle runs cleanup after each test.
frontend/src/routes/__tests__/Register.test.ts-25-37 (1)

25-37: ⚠️ Potential issue | 🟡 Minor

Add cleanup() in afterEach and make renderRegister() async with await tick().

Frontend test lifecycle requires cleanup after each test and explicit tick handling for Svelte renders.

Proposed patch
-import { render, screen, waitFor } from '@testing-library/svelte';
+import { render, screen, waitFor, cleanup } from '@testing-library/svelte';
+import { tick } from 'svelte';
@@
 describe('Register', () => {
     beforeEach(() => {
         vi.clearAllMocks();
         mocks.registerApiV1AuthRegisterPost.mockResolvedValue({ data: {}, error: undefined });
         vi.spyOn(toast, 'success');
         vi.spyOn(toast, 'error');
         vi.spyOn(toast, 'warning');
         vi.spyOn(toast, 'info');
         vi.spyOn(meta, 'updateMetaTags');
     });
+
+    afterEach(() => cleanup());
 
-    function renderRegister() {
-        return render(Register);
+    async function renderRegister() {
+        const view = render(Register);
+        await tick();
+        return view;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/routes/__tests__/Register.test.ts` around lines 25 - 37, Tests
are missing teardown and proper async render handling: add an afterEach that
calls cleanup() and vi.clearAllMocks() (or similar) to restore DOM between
tests, and change renderRegister() to be async returning await render(Register)
followed by await tick() so Svelte updates settle; update references to the
existing beforeEach setup (mocks.registerApiV1AuthRegisterPost, vi.spyOn(...)
and meta.updateMetaTags) to remain unchanged, only adding the new afterEach and
making the renderRegister helper async with await tick() after render.
frontend/src/components/admin/users/__tests__/UsersTable.test.ts-21-21 (1)

21-21: ⚠️ Potential issue | 🟡 Minor

Add afterEach(cleanup) for test isolation.

beforeEach is correctly configured, but this suite should also cleanup mounted DOM after each test to ensure proper test isolation.

Proposed patch
-import { render, screen } from '@testing-library/svelte';
+import { render, screen, cleanup } from '@testing-library/svelte';
@@
 describe('UsersTable', () => {
     beforeEach(() => vi.clearAllMocks());
+    afterEach(() => cleanup());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/users/__tests__/UsersTable.test.ts` at line 21,
Add an afterEach(cleanup) call to this test suite to unmount DOM between tests:
locate the test file containing beforeEach(() => vi.clearAllMocks()) in
UsersTable.test.ts and add afterEach(() => cleanup()) (or afterEach(cleanup)
depending on your test utils import) near the top-level describe so the DOM is
cleaned up after each test; ensure cleanup is imported from the testing library
if not already.
frontend/src/routes/__tests__/Editor.test.ts-136-136 (1)

136-136: ⚠️ Potential issue | 🟡 Minor

Import and call cleanup() in afterEach to prevent cross-test DOM leakage.

Add cleanup to the import from @testing-library/svelte and call it in the afterEach hook before unstubbing globals.

Proposed patch
-import { render, screen, waitFor } from '@testing-library/svelte';
+import { render, screen, waitFor, cleanup } from '@testing-library/svelte';
@@
-afterEach(() => vi.unstubAllGlobals());
+afterEach(() => {
+    cleanup();
+    vi.unstubAllGlobals();
+});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/routes/__tests__/Editor.test.ts` at line 136, The test teardown
currently only calls vi.unstubAllGlobals() in afterEach; also import cleanup
from '@testing-library/svelte' and call cleanup() as the first step inside
afterEach (before vi.unstubAllGlobals()) to unmount Svelte components and
prevent DOM leakage between tests; update the import list to include cleanup and
modify the afterEach hook that references vi.unstubAllGlobals() to invoke
cleanup() first.
frontend/src/components/admin/sagas/__tests__/SagaStatsCards.test.ts-69-79 (1)

69-79: ⚠️ Potential issue | 🟡 Minor

Wait for DOM update after rerender to avoid flaky assertions.

The expectation runs immediately after rerender (Line 78). Use waitFor (or tick) to synchronize with async DOM updates.

Proposed fix
-import { render, screen } from '@testing-library/svelte';
+import { render, screen, waitFor } from '@testing-library/svelte';
@@
-    it('updates counts when sagas change', () => {
+    it('updates counts when sagas change', async () => {
         const { rerender } = renderCards([createMockSaga({ state: 'running' })]);
         expect(screen.getByText('1')).toBeInTheDocument();
-        rerender({
+        await rerender({
             sagas: [
                 createMockSaga({ saga_id: 's1', state: 'completed' }),
                 createMockSaga({ saga_id: 's2', state: 'completed' }),
             ],
         });
-        expect(screen.getByText('2')).toBeInTheDocument();
+        await waitFor(() => {
+            expect(screen.getByText('2')).toBeInTheDocument();
+        });
     });

Based on learnings: Use await tick() after Svelte render, waitFor() for async state in Vitest.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/sagas/__tests__/SagaStatsCards.test.ts` around
lines 69 - 79, The test "updates counts when sagas change" performs assertions
immediately after calling rerender which can be flaky; update the test to wait
for the DOM to reflect the new sagas by awaiting an async synchronization helper
(e.g., use waitFor from `@testing-library/svelte/`@testing-library/react or await
tick() if using Svelte's tick) after calling rerender({ sagas: [...] }) before
asserting screen.getByText('2'), keeping the existing helpers renderCards and
createMockSaga and the same assertions but wrapped in an async test function
that awaits the DOM update.

Comment thread frontend/src/routes/__tests__/Editor.test.ts
@HardMax71 HardMax71 merged commit 666d9e1 into main Mar 4, 2026
16 of 17 checks passed
@HardMax71 HardMax71 deleted the chore/useless-files branch March 4, 2026 22:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants