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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions src/components/issues/IssueFilters.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { render, screen, fireEvent } from "@testing-library/react";

Check failure on line 1 in src/components/issues/IssueFilters.test.tsx

View workflow job for this annotation

GitHub Actions / ESLint

'fireEvent' is defined but never used
import { describe, it, expect, vi } from "vitest";
import { IssueFilters } from "./IssueFilters";
import React from "react";

// Mock next/navigation
vi.mock("next/navigation", () => ({
useRouter: () => ({
push: vi.fn(),
}),
useSearchParams: () => new URLSearchParams(),
}));

// Mock Select components from shadcn/radix
// We need to mock them because they rely on Context which is hard to test in isolation without full DOM
// But for this test, we care about the structure we returned in IssueFilters.tsx.
// However, since we are using the actual Shadcn components which use Radix, they might not render standard <select> elements.
// The IssueFilters component uses <SelectTrigger> which renders a button. We added aria-label to it.

describe("IssueFilters Accessibility", () => {
const mockMachines = [
{ initials: "TZ", name: "Twilight Zone" },
{ initials: "MM", name: "Medieval Madness" },
];

it("renders status filter group with accessibility attributes", () => {
render(<IssueFilters machines={mockMachines} />);

// Check status group container
const statusGroup = screen.getByRole("group", { name: "Filter by status" });
expect(statusGroup).toBeInTheDocument();

// Check toggle buttons
const openButton = screen.getByRole("button", { name: "Open" });
const closedButton = screen.getByRole("button", { name: "Closed" });

// Initial state (assuming query params are empty/default): Open is active
// Wait, the component defaults to Open if status is NOT "resolved".
expect(openButton).toHaveAttribute("aria-pressed", "true");
expect(closedButton).toHaveAttribute("aria-pressed", "false");
});

it("renders select triggers with accessible labels", () => {
render(<IssueFilters machines={mockMachines} />);

// We added aria-label to SelectTrigger.
// Shadcn SelectTrigger renders a button.

// Severity
const severityTrigger = screen.getByRole("combobox", { name: "Filter by Severity" });
expect(severityTrigger).toBeInTheDocument();

// Priority
const priorityTrigger = screen.getByRole("combobox", { name: "Filter by Priority" });
expect(priorityTrigger).toBeInTheDocument();

// Machine
const machineTrigger = screen.getByRole("combobox", { name: "Filter by Machine" });
expect(machineTrigger).toBeInTheDocument();
});
});
14 changes: 10 additions & 4 deletions src/components/issues/IssueFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,17 @@ export function IssueFilters({
return (
<div className="flex flex-wrap items-center gap-3">
{/* Status Toggle (Open/Closed) */}
<div className="flex items-center rounded-md border border-input bg-transparent p-1">
<div
className="flex items-center rounded-md border border-input bg-transparent p-1"
role="group"
aria-label="Filter by status"
>
<Button
variant={currentFilters.status !== "resolved" ? "secondary" : "ghost"}
size="sm"
onClick={() => updateFilter("status", null)} // Default (null) is Open
className="h-7 px-3 text-xs"
aria-pressed={currentFilters.status !== "resolved"}
>
Open
</Button>
Expand All @@ -68,6 +73,7 @@ export function IssueFilters({
size="sm"
onClick={() => updateFilter("status", "resolved")}
className="h-7 px-3 text-xs"
aria-pressed={currentFilters.status === "resolved"}
>
Closed
</Button>
Expand All @@ -78,7 +84,7 @@ export function IssueFilters({
value={currentFilters.severity ?? "all"}
onValueChange={(val) => updateFilter("severity", val)}
>
<SelectTrigger className="w-[140px] h-9 text-sm">
<SelectTrigger aria-label="Filter by Severity" className="w-[140px] h-9 text-sm">
<SelectValue placeholder="Severity" />
</SelectTrigger>
<SelectContent>
Expand All @@ -94,7 +100,7 @@ export function IssueFilters({
value={currentFilters.priority ?? "all"}
onValueChange={(val) => updateFilter("priority", val)}
>
<SelectTrigger className="w-[140px] h-9 text-sm">
<SelectTrigger aria-label="Filter by Priority" className="w-[140px] h-9 text-sm">
<SelectValue placeholder="Priority" />
</SelectTrigger>
<SelectContent>
Expand All @@ -111,7 +117,7 @@ export function IssueFilters({
value={currentFilters.machine ?? "all"}
onValueChange={(val) => updateFilter("machine", val)}
>
<SelectTrigger className="w-[160px] h-9 text-sm">
<SelectTrigger aria-label="Filter by Machine" className="w-[160px] h-9 text-sm">
<SelectValue placeholder="Machine" />
</SelectTrigger>
<SelectContent>
Expand Down
Loading