mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 15:15:24 +00:00
feat: finish the ai plugin (B18)
This commit is contained in:
1 parent
6b4d1432ab
commit
21937a6b02
193 files changed
+23429
-4244
No files matched your search
@@ -17,7 +17,8 @@ const api = vi.hoisted(() => ({
|
||||
}));
|
||||
|
||||
vi.mock("../../src/frontend/ai-api", () => api);
|
||||
vi.mock("react-i18next", () => ({
|
||||
vi.mock("react-i18next", async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
vi.mock("sonner", () => ({
|
||||
|
||||
@@ -57,6 +57,11 @@ describe(`${manifest.id} activate`, () => {
|
||||
expect(app.registered.actions()).toEqual([]);
|
||||
});
|
||||
|
||||
it("registers the providers list as its custom settings field", async () => {
|
||||
rendered = await renderWithApp(plugin, { manifest, locales });
|
||||
expect(rendered.registered.settingsComponents()).toEqual(["providers"]);
|
||||
});
|
||||
|
||||
it("adds the assistant tab once AI is on for the user", async () => {
|
||||
rendered = await renderWithApp(plugin, { manifest, locales });
|
||||
await waitFor(() => expect(rendered!.registered.tabs()).toEqual(["ai"]));
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { renderHook, waitFor, act } from "@testing-library/react";
|
||||
|
||||
const getAiStatus = vi.fn();
|
||||
vi.mock("../../src/frontend/ai-api", () => ({ getAiStatus }));
|
||||
|
||||
const { useAiAvailability, notifyAiStatusChanged } =
|
||||
await import("../../src/frontend/use-ai-availability");
|
||||
|
||||
beforeEach(() => {
|
||||
getAiStatus.mockReset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("useAiAvailability", () => {
|
||||
it("starts hidden and unloaded before the status answers", () => {
|
||||
getAiStatus.mockReturnValue(new Promise(() => {}));
|
||||
const { result } = renderHook(() => useAiAvailability());
|
||||
expect(result.current).toEqual({
|
||||
globallyEnabled: false,
|
||||
userEnabled: false,
|
||||
loaded: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("reports both gates open when the admin and the user enabled it", async () => {
|
||||
getAiStatus.mockResolvedValue({
|
||||
globallyEnabled: true,
|
||||
enabled: true,
|
||||
allowReadOnlyCommands: false,
|
||||
});
|
||||
const { result } = renderHook(() => useAiAvailability());
|
||||
await waitFor(() => expect(result.current.loaded).toBe(true));
|
||||
expect(result.current.globallyEnabled).toBe(true);
|
||||
expect(result.current.userEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps userEnabled false when the user has not opted in", async () => {
|
||||
getAiStatus.mockResolvedValue({
|
||||
globallyEnabled: true,
|
||||
enabled: false,
|
||||
allowReadOnlyCommands: false,
|
||||
});
|
||||
const { result } = renderHook(() => useAiAvailability());
|
||||
await waitFor(() => expect(result.current.loaded).toBe(true));
|
||||
expect(result.current.globallyEnabled).toBe(true);
|
||||
expect(result.current.userEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("the admin kill switch wins over the user opt-in", async () => {
|
||||
getAiStatus.mockResolvedValue({
|
||||
globallyEnabled: false,
|
||||
enabled: true,
|
||||
allowReadOnlyCommands: true,
|
||||
});
|
||||
const { result } = renderHook(() => useAiAvailability());
|
||||
await waitFor(() => expect(result.current.loaded).toBe(true));
|
||||
expect(result.current.globallyEnabled).toBe(false);
|
||||
expect(result.current.userEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("treats a failed status call as off", async () => {
|
||||
getAiStatus.mockRejectedValue(new Error("boom"));
|
||||
const { result } = renderHook(() => useAiAvailability());
|
||||
await waitFor(() => expect(result.current.loaded).toBe(true));
|
||||
expect(result.current.globallyEnabled).toBe(false);
|
||||
expect(result.current.userEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("re-reads the status when notified", async () => {
|
||||
getAiStatus.mockResolvedValue({
|
||||
globallyEnabled: true,
|
||||
enabled: true,
|
||||
allowReadOnlyCommands: false,
|
||||
});
|
||||
const { result } = renderHook(() => useAiAvailability());
|
||||
await waitFor(() => expect(result.current.globallyEnabled).toBe(true));
|
||||
|
||||
getAiStatus.mockResolvedValue({
|
||||
globallyEnabled: false,
|
||||
enabled: true,
|
||||
allowReadOnlyCommands: false,
|
||||
});
|
||||
act(() => notifyAiStatusChanged());
|
||||
await waitFor(() => expect(result.current.globallyEnabled).toBe(false));
|
||||
expect(result.current.userEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("also re-reads on the older hiddenRailTabsChanged event", async () => {
|
||||
getAiStatus.mockResolvedValue({
|
||||
globallyEnabled: true,
|
||||
enabled: false,
|
||||
allowReadOnlyCommands: false,
|
||||
});
|
||||
const { result } = renderHook(() => useAiAvailability());
|
||||
await waitFor(() => expect(result.current.loaded).toBe(true));
|
||||
|
||||
getAiStatus.mockResolvedValue({
|
||||
globallyEnabled: true,
|
||||
enabled: true,
|
||||
allowReadOnlyCommands: false,
|
||||
});
|
||||
act(() => window.dispatchEvent(new Event("hiddenRailTabsChanged")));
|
||||
await waitFor(() => expect(result.current.userEnabled).toBe(true));
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user