fix(#411): complete 2026-02-17 remediation sweep

Apply RLS context at task service boundaries, harden orchestrator/web integration and session startup behavior, re-enable targeted frontend tests, and lock vulnerable transitive dependencies so QA and security gates pass cleanly.
This commit is contained in:
Jason Woltje
2026-02-17 14:19:15 -06:00
parent 254f85369b
commit cab8d690ab
22 changed files with 605 additions and 744 deletions

View File

@@ -1,126 +1,55 @@
/**
* CalendarWidget Component Tests
* Following TDD principles
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { act, render, screen } from "@testing-library/react";
import { CalendarWidget } from "../CalendarWidget";
global.fetch = vi.fn() as typeof global.fetch;
async function finishWidgetLoad(): Promise<void> {
await act(async () => {
await vi.advanceTimersByTimeAsync(500);
});
}
describe("CalendarWidget", (): void => {
beforeEach((): void => {
vi.clearAllMocks();
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-02-01T08:00:00Z"));
});
it("should render loading state initially", (): void => {
vi.mocked(global.fetch).mockImplementation(
() =>
new Promise(() => {
// Intentionally never resolves to keep loading state
})
);
render(<CalendarWidget id="calendar-1" />);
expect(screen.getByText(/loading/i)).toBeInTheDocument();
afterEach((): void => {
vi.useRealTimers();
});
// TODO: Re-enable when CalendarWidget uses fetch API instead of setTimeout mock data
it.skip("should render upcoming events", async (): Promise<void> => {
const mockEvents = [
{
id: "1",
title: "Team Meeting",
startTime: new Date(Date.now() + 3600000).toISOString(),
endTime: new Date(Date.now() + 7200000).toISOString(),
},
{
id: "2",
title: "Project Review",
startTime: new Date(Date.now() + 86400000).toISOString(),
endTime: new Date(Date.now() + 90000000).toISOString(),
},
];
vi.mocked(global.fetch).mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve(mockEvents),
} as unknown as Response);
it("renders loading state initially", (): void => {
render(<CalendarWidget id="calendar-1" />);
await waitFor(() => {
expect(screen.getByText("Team Meeting")).toBeInTheDocument();
expect(screen.getByText("Project Review")).toBeInTheDocument();
});
expect(screen.getByText("Loading events...")).toBeInTheDocument();
});
// TODO: Re-enable when CalendarWidget uses fetch API instead of setTimeout mock data
it.skip("should handle empty event list", async (): Promise<void> => {
vi.mocked(global.fetch).mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve([]),
} as unknown as Response);
it("renders upcoming events after loading", async (): Promise<void> => {
render(<CalendarWidget id="calendar-1" />);
await waitFor(() => {
expect(screen.getByText(/no upcoming events/i)).toBeInTheDocument();
});
await finishWidgetLoad();
expect(screen.getByText("Upcoming Events")).toBeInTheDocument();
expect(screen.getByText("Team Standup")).toBeInTheDocument();
expect(screen.getByText("Project Review")).toBeInTheDocument();
expect(screen.getByText("Sprint Planning")).toBeInTheDocument();
});
// TODO: Re-enable when CalendarWidget uses fetch API instead of setTimeout mock data
it.skip("should handle API errors gracefully", async (): Promise<void> => {
vi.mocked(global.fetch).mockRejectedValueOnce(new Error("API Error"));
it("shows relative day labels", async (): Promise<void> => {
render(<CalendarWidget id="calendar-1" />);
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument();
});
await finishWidgetLoad();
expect(screen.getAllByText("Today").length).toBeGreaterThan(0);
expect(screen.getByText("Tomorrow")).toBeInTheDocument();
});
// TODO: Re-enable when CalendarWidget uses fetch API instead of setTimeout mock data
it.skip("should format event times correctly", async (): Promise<void> => {
const now = new Date();
const startTime = new Date(now.getTime() + 3600000); // 1 hour from now
const mockEvents = [
{
id: "1",
title: "Meeting",
startTime: startTime.toISOString(),
endTime: new Date(startTime.getTime() + 3600000).toISOString(),
},
];
vi.mocked(global.fetch).mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve(mockEvents),
} as unknown as Response);
it("shows event locations when present", async (): Promise<void> => {
render(<CalendarWidget id="calendar-1" />);
await waitFor(() => {
expect(screen.getByText("Meeting")).toBeInTheDocument();
// Should show time in readable format
});
});
await finishWidgetLoad();
// TODO: Re-enable when CalendarWidget uses fetch API and adds calendar-header test id
it.skip("should display current date", async (): Promise<void> => {
vi.mocked(global.fetch).mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve([]),
} as unknown as Response);
render(<CalendarWidget id="calendar-1" />);
await waitFor(() => {
// Widget should display current date or month
expect(screen.getByTestId("calendar-header")).toBeInTheDocument();
});
expect(screen.getByText("Zoom")).toBeInTheDocument();
expect(screen.getByText("Conference Room A")).toBeInTheDocument();
});
});

View File

@@ -1,138 +1,54 @@
/**
* TasksWidget Component Tests
* Following TDD principles
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { act, render, screen } from "@testing-library/react";
import { TasksWidget } from "../TasksWidget";
// Mock fetch for API calls
global.fetch = vi.fn() as typeof global.fetch;
async function finishWidgetLoad(): Promise<void> {
await act(async () => {
await vi.advanceTimersByTimeAsync(500);
});
}
describe("TasksWidget", (): void => {
beforeEach((): void => {
vi.clearAllMocks();
vi.useFakeTimers();
});
it("should render loading state initially", (): void => {
vi.mocked(global.fetch).mockImplementation(
() =>
new Promise(() => {
// Intentionally empty - creates a never-resolving promise for loading state
})
);
render(<TasksWidget id="tasks-1" />);
expect(screen.getByText(/loading/i)).toBeInTheDocument();
afterEach((): void => {
vi.useRealTimers();
});
// TODO: Re-enable when TasksWidget uses fetch API instead of setTimeout mock data
it.skip("should render task statistics", async (): Promise<void> => {
const mockTasks = [
{ id: "1", title: "Task 1", status: "IN_PROGRESS", priority: "HIGH" },
{ id: "2", title: "Task 2", status: "COMPLETED", priority: "MEDIUM" },
{ id: "3", title: "Task 3", status: "NOT_STARTED", priority: "LOW" },
];
vi.mocked(global.fetch).mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve(mockTasks),
} as unknown as Response);
it("renders loading state initially", (): void => {
render(<TasksWidget id="tasks-1" />);
await waitFor(() => {
expect(screen.getByText("3")).toBeInTheDocument(); // Total
expect(screen.getByText("1")).toBeInTheDocument(); // In Progress
expect(screen.getByText("1")).toBeInTheDocument(); // Completed
});
expect(screen.getByText("Loading tasks...")).toBeInTheDocument();
});
// TODO: Re-enable when TasksWidget uses fetch API instead of setTimeout mock data
it.skip("should render task list", async (): Promise<void> => {
const mockTasks = [
{ id: "1", title: "Complete documentation", status: "IN_PROGRESS", priority: "HIGH" },
{ id: "2", title: "Review PRs", status: "NOT_STARTED", priority: "MEDIUM" },
];
vi.mocked(global.fetch).mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve(mockTasks),
} as unknown as Response);
it("renders default summary stats", async (): Promise<void> => {
render(<TasksWidget id="tasks-1" />);
await waitFor(() => {
expect(screen.getByText("Complete documentation")).toBeInTheDocument();
expect(screen.getByText("Review PRs")).toBeInTheDocument();
});
await finishWidgetLoad();
expect(screen.getByText("Total")).toBeInTheDocument();
expect(screen.getByText("In Progress")).toBeInTheDocument();
expect(screen.getByText("Done")).toBeInTheDocument();
expect(screen.getByText("3")).toBeInTheDocument();
});
// TODO: Re-enable when TasksWidget uses fetch API instead of setTimeout mock data
it.skip("should handle empty task list", async (): Promise<void> => {
vi.mocked(global.fetch).mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve([]),
} as unknown as Response);
it("renders default task rows", async (): Promise<void> => {
render(<TasksWidget id="tasks-1" />);
await waitFor(() => {
expect(screen.getByText(/no tasks/i)).toBeInTheDocument();
});
await finishWidgetLoad();
expect(screen.getByText("Complete project documentation")).toBeInTheDocument();
expect(screen.getByText("Review pull requests")).toBeInTheDocument();
expect(screen.getByText("Update dependencies")).toBeInTheDocument();
});
// TODO: Re-enable when TasksWidget uses fetch API instead of setTimeout mock data
it.skip("should handle API errors gracefully", async (): Promise<void> => {
vi.mocked(global.fetch).mockRejectedValueOnce(new Error("API Error"));
it("shows due date labels for each task", async (): Promise<void> => {
render(<TasksWidget id="tasks-1" />);
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument();
});
});
await finishWidgetLoad();
// TODO: Re-enable when TasksWidget uses fetch API instead of setTimeout mock data
it.skip("should display priority indicators", async (): Promise<void> => {
const mockTasks = [
{ id: "1", title: "High priority task", status: "IN_PROGRESS", priority: "HIGH" },
];
vi.mocked(global.fetch).mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve(mockTasks),
} as unknown as Response);
render(<TasksWidget id="tasks-1" />);
await waitFor(() => {
expect(screen.getByText("High priority task")).toBeInTheDocument();
// Priority icon should be rendered (high priority = red)
});
});
// TODO: Re-enable when TasksWidget uses fetch API instead of setTimeout mock data
it.skip("should limit displayed tasks to 5", async (): Promise<void> => {
const mockTasks = Array.from({ length: 10 }, (_, i) => ({
id: String(i + 1),
title: `Task ${String(i + 1)}`,
status: "NOT_STARTED",
priority: "MEDIUM",
}));
vi.mocked(global.fetch).mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve(mockTasks),
} as unknown as Response);
render(<TasksWidget id="tasks-1" />);
await waitFor(() => {
const taskElements = screen.getAllByText(/Task \d+/);
expect(taskElements.length).toBeLessThanOrEqual(5);
});
expect(screen.getAllByText(/Due:/).length).toBe(3);
});
});