Add tests and documentation updates for log preview and regex tester hooks
- Add useLogPreview.test.ts with comprehensive test coverage - Add useRegexTester.test.ts with comprehensive test coverage - Update Docs/Tasks.md and Docs/Web-Development.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
126
frontend/src/hooks/__tests__/useLogPreview.test.ts
Normal file
126
frontend/src/hooks/__tests__/useLogPreview.test.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { renderHook, act } from "@testing-library/react";
|
||||
import { ApiError } from "../../api/client";
|
||||
import { useLogPreview } from "../useLogPreview";
|
||||
|
||||
vi.mock("../../api/config", () => ({
|
||||
previewLog: vi.fn(),
|
||||
}));
|
||||
|
||||
import { previewLog } from "../../api/config";
|
||||
|
||||
describe("useLogPreview", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("returns initial state with preview and loading false", () => {
|
||||
const { result } = renderHook(() => useLogPreview());
|
||||
|
||||
expect(result.current.preview).toBeNull();
|
||||
expect(result.current.loading).toBe(false);
|
||||
expect(result.current.error).toBeNull();
|
||||
});
|
||||
|
||||
it("sets preview on successful run", async () => {
|
||||
const mockResponse = {
|
||||
lines: [{ line: "test", matched: true, groups: [] }],
|
||||
total_lines: 1,
|
||||
matched_count: 1,
|
||||
regex_error: null,
|
||||
};
|
||||
vi.mocked(previewLog).mockResolvedValue(mockResponse);
|
||||
|
||||
const { result } = renderHook(() => useLogPreview());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.run({
|
||||
log_path: "/var/log/test.log",
|
||||
fail_regex: "pattern",
|
||||
num_lines: 100,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.preview).toEqual(mockResponse);
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
it("sets error for normal errors via handleFetchError", async () => {
|
||||
vi.mocked(previewLog).mockRejectedValue(new Error("Network error"));
|
||||
|
||||
const { result } = renderHook(() => useLogPreview());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.run({
|
||||
log_path: "/var/log/test.log",
|
||||
fail_regex: "pattern",
|
||||
num_lines: 100,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.error).toBe("Network error");
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
it("ignores auth errors (401) via handleFetchError", async () => {
|
||||
vi.mocked(previewLog).mockRejectedValue(new ApiError(401, "Unauthorized"));
|
||||
|
||||
const { result } = renderHook(() => useLogPreview());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.run({
|
||||
log_path: "/var/log/test.log",
|
||||
fail_regex: "pattern",
|
||||
num_lines: 100,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
it("ignores auth errors (403) via handleFetchError", async () => {
|
||||
vi.mocked(previewLog).mockRejectedValue(new ApiError(403, "Forbidden"));
|
||||
|
||||
const { result } = renderHook(() => useLogPreview());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.run({
|
||||
log_path: "/var/log/test.log",
|
||||
fail_regex: "pattern",
|
||||
num_lines: 100,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
it("sets loading to false in finally block", async () => {
|
||||
vi.mocked(previewLog).mockResolvedValue({
|
||||
lines: [],
|
||||
total_lines: 0,
|
||||
matched_count: 0,
|
||||
regex_error: null,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useLogPreview());
|
||||
|
||||
expect(result.current.loading).toBe(false);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.run({
|
||||
log_path: "/var/log/test.log",
|
||||
fail_regex: "pattern",
|
||||
num_lines: 100,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
});
|
||||
103
frontend/src/hooks/__tests__/useRegexTester.test.ts
Normal file
103
frontend/src/hooks/__tests__/useRegexTester.test.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { renderHook, act } from "@testing-library/react";
|
||||
import { ApiError } from "../../api/client";
|
||||
import { useRegexTester } from "../useRegexTester";
|
||||
|
||||
vi.mock("../../api/config", () => ({
|
||||
testRegex: vi.fn(),
|
||||
}));
|
||||
|
||||
import { testRegex } from "../../api/config";
|
||||
|
||||
describe("useRegexTester", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("returns initial state with result and testing false", () => {
|
||||
const { result } = renderHook(() => useRegexTester());
|
||||
|
||||
expect(result.current.result).toBeNull();
|
||||
expect(result.current.testing).toBe(false);
|
||||
expect(result.current.error).toBeNull();
|
||||
});
|
||||
|
||||
it("sets result on successful test", async () => {
|
||||
const mockResponse = { matched: true, groups: ["host"], error: null };
|
||||
vi.mocked(testRegex).mockResolvedValue(mockResponse);
|
||||
|
||||
const { result } = renderHook(() => useRegexTester());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.test({ log_line: "test", fail_regex: "pattern" });
|
||||
});
|
||||
|
||||
expect(result.current.result).toEqual(mockResponse);
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(result.current.testing).toBe(false);
|
||||
});
|
||||
|
||||
it("sets error for normal errors via handleFetchError", async () => {
|
||||
vi.mocked(testRegex).mockRejectedValue(new Error("Network error"));
|
||||
|
||||
const { result } = renderHook(() => useRegexTester());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.test({ log_line: "test", fail_regex: "pattern" });
|
||||
});
|
||||
|
||||
expect(result.current.error).toBe("Network error");
|
||||
expect(result.current.testing).toBe(false);
|
||||
});
|
||||
|
||||
it("ignores auth errors (401) via handleFetchError", async () => {
|
||||
vi.mocked(testRegex).mockRejectedValue(new ApiError(401, "Unauthorized"));
|
||||
|
||||
const { result } = renderHook(() => useRegexTester());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.test({ log_line: "test", fail_regex: "pattern" });
|
||||
});
|
||||
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(result.current.testing).toBe(false);
|
||||
});
|
||||
|
||||
it("ignores auth errors (403) via handleFetchError", async () => {
|
||||
vi.mocked(testRegex).mockRejectedValue(new ApiError(403, "Forbidden"));
|
||||
|
||||
const { result } = renderHook(() => useRegexTester());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.test({ log_line: "test", fail_regex: "pattern" });
|
||||
});
|
||||
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(result.current.testing).toBe(false);
|
||||
});
|
||||
|
||||
it("sets testing to false in finally block", async () => {
|
||||
vi.mocked(testRegex).mockResolvedValue({
|
||||
matched: false,
|
||||
groups: [],
|
||||
error: null,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useRegexTester());
|
||||
|
||||
expect(result.current.testing).toBe(false);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.test({
|
||||
log_line: "test",
|
||||
fail_regex: "pattern",
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.testing).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -4,11 +4,13 @@
|
||||
|
||||
import { useCallback, useState } from "react";
|
||||
import { previewLog } from "../api/config";
|
||||
import { handleFetchError } from "../utils/fetchError";
|
||||
import type { LogPreviewRequest, LogPreviewResponse } from "../types/config";
|
||||
|
||||
export interface UseLogPreviewResult {
|
||||
preview: LogPreviewResponse | null;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
run: (req: LogPreviewRequest) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -18,25 +20,20 @@ export interface UseLogPreviewResult {
|
||||
export function useLogPreview(): UseLogPreviewResult {
|
||||
const [preview, setPreview] = useState<LogPreviewResponse | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const run = useCallback(async (req: LogPreviewRequest): Promise<void> => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const resp = await previewLog(req);
|
||||
setPreview(resp);
|
||||
setError(null);
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof Error) {
|
||||
setPreview({
|
||||
lines: [],
|
||||
total_lines: 0,
|
||||
matched_count: 0,
|
||||
regex_error: err.message,
|
||||
});
|
||||
}
|
||||
handleFetchError(err, setError, "Log preview failed");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return { preview, loading, run };
|
||||
return { preview, loading, error, run };
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
|
||||
import { useCallback, useState } from "react";
|
||||
import { testRegex } from "../api/config";
|
||||
import { handleFetchError } from "../utils/fetchError";
|
||||
import type { RegexTestRequest, RegexTestResponse } from "../types/config";
|
||||
|
||||
export interface UseRegexTesterResult {
|
||||
result: RegexTestResponse | null;
|
||||
testing: boolean;
|
||||
error: string | null;
|
||||
test: (req: RegexTestRequest) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -18,20 +20,20 @@ export interface UseRegexTesterResult {
|
||||
export function useRegexTester(): UseRegexTesterResult {
|
||||
const [result, setResult] = useState<RegexTestResponse | null>(null);
|
||||
const [testing, setTesting] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const test = useCallback(async (req: RegexTestRequest): Promise<void> => {
|
||||
setTesting(true);
|
||||
try {
|
||||
const resp = await testRegex(req);
|
||||
setResult(resp);
|
||||
setError(null);
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof Error) {
|
||||
setResult({ matched: false, groups: [], error: err.message });
|
||||
}
|
||||
handleFetchError(err, setError, "Regex test failed");
|
||||
} finally {
|
||||
setTesting(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return { result, testing, test };
|
||||
return { result, testing, error, test };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user