mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-10 22:41:41 +00:00
feat: add useOnboarding hook with query and mutation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
715e134a66
commit
f4303f5e22
2 changed files with 155 additions and 0 deletions
|
|
@ -0,0 +1,126 @@
|
|||
import { getOnboardingCredentials, claimOnboardingToken } from "@/components/networking";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { renderHook, waitFor, act } from "@testing-library/react";
|
||||
import React, { ReactNode } from "react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { useOnboardingCredentials, useClaimOnboardingToken } from "./useOnboarding";
|
||||
|
||||
vi.mock("@/components/networking", () => ({
|
||||
getOnboardingCredentials: vi.fn(),
|
||||
claimOnboardingToken: vi.fn(),
|
||||
}));
|
||||
|
||||
const mockUseUIConfig = vi.fn();
|
||||
vi.mock("@/app/(dashboard)/hooks/uiConfig/useUIConfig", () => ({
|
||||
useUIConfig: () => mockUseUIConfig(),
|
||||
}));
|
||||
|
||||
const mockCredentialsResponse = { token: "mock.jwt.token", login_url: "http://example.com/login" };
|
||||
|
||||
describe("useOnboardingCredentials", () => {
|
||||
let queryClient: QueryClient;
|
||||
|
||||
beforeEach(() => {
|
||||
queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
vi.clearAllMocks();
|
||||
mockUseUIConfig.mockReturnValue({ isLoading: false });
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: { children: ReactNode }) =>
|
||||
React.createElement(QueryClientProvider, { client: queryClient }, children);
|
||||
|
||||
it("fetches credentials when inviteId is provided and UIConfig is loaded", async () => {
|
||||
(getOnboardingCredentials as any).mockResolvedValue(mockCredentialsResponse);
|
||||
|
||||
const { result } = renderHook(() => useOnboardingCredentials("invite-123"), { wrapper });
|
||||
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
||||
|
||||
expect(result.current.data).toEqual(mockCredentialsResponse);
|
||||
expect(getOnboardingCredentials).toHaveBeenCalledWith("invite-123");
|
||||
expect(getOnboardingCredentials).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("does not fetch when inviteId is null", async () => {
|
||||
const { result } = renderHook(() => useOnboardingCredentials(null), { wrapper });
|
||||
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
expect(getOnboardingCredentials).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not fetch while UIConfig is loading", async () => {
|
||||
mockUseUIConfig.mockReturnValue({ isLoading: true });
|
||||
|
||||
const { result } = renderHook(() => useOnboardingCredentials("invite-123"), { wrapper });
|
||||
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
expect(getOnboardingCredentials).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("exposes error state when fetch fails", async () => {
|
||||
const error = new Error("Invalid invite");
|
||||
(getOnboardingCredentials as any).mockRejectedValue(error);
|
||||
|
||||
const { result } = renderHook(() => useOnboardingCredentials("bad-invite"), { wrapper });
|
||||
|
||||
await waitFor(() => expect(result.current.isError).toBe(true));
|
||||
|
||||
expect(result.current.error).toEqual(error);
|
||||
});
|
||||
});
|
||||
|
||||
describe("useClaimOnboardingToken", () => {
|
||||
let queryClient: QueryClient;
|
||||
|
||||
beforeEach(() => {
|
||||
queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
vi.clearAllMocks();
|
||||
mockUseUIConfig.mockReturnValue({ isLoading: false });
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: { children: ReactNode }) =>
|
||||
React.createElement(QueryClientProvider, { client: queryClient }, children);
|
||||
|
||||
it("calls claimOnboardingToken with correct params", async () => {
|
||||
(claimOnboardingToken as any).mockResolvedValue({ success: true });
|
||||
|
||||
const { result } = renderHook(() => useClaimOnboardingToken(), { wrapper });
|
||||
|
||||
act(() => {
|
||||
result.current.mutate({
|
||||
accessToken: "acc-token",
|
||||
inviteId: "invite-123",
|
||||
userId: "user-456",
|
||||
password: "secret",
|
||||
});
|
||||
});
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
||||
|
||||
expect(claimOnboardingToken).toHaveBeenCalledWith("acc-token", "invite-123", "user-456", "secret");
|
||||
});
|
||||
|
||||
it("exposes error state when mutation fails", async () => {
|
||||
const error = new Error("Claim failed");
|
||||
(claimOnboardingToken as any).mockRejectedValue(error);
|
||||
|
||||
const { result } = renderHook(() => useClaimOnboardingToken(), { wrapper });
|
||||
|
||||
act(() => {
|
||||
result.current.mutate({
|
||||
accessToken: "acc-token",
|
||||
inviteId: "invite-123",
|
||||
userId: "user-456",
|
||||
password: "secret",
|
||||
});
|
||||
});
|
||||
|
||||
await waitFor(() => expect(result.current.isError).toBe(true));
|
||||
|
||||
expect(result.current.error).toEqual(error);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import { claimOnboardingToken, getOnboardingCredentials } from "@/components/networking";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { useUIConfig } from "../uiConfig/useUIConfig";
|
||||
import { createQueryKeys } from "../common/queryKeysFactory";
|
||||
|
||||
const onboardingKeys = createQueryKeys("onboarding");
|
||||
|
||||
export const useOnboardingCredentials = (inviteId: string | null) => {
|
||||
const { isLoading: isUIConfigLoading } = useUIConfig();
|
||||
return useQuery({
|
||||
queryKey: onboardingKeys.detail(inviteId ?? ""),
|
||||
queryFn: async () => await getOnboardingCredentials(inviteId!),
|
||||
enabled: Boolean(inviteId) && !isUIConfigLoading,
|
||||
});
|
||||
};
|
||||
|
||||
export interface ClaimTokenParams {
|
||||
accessToken: string;
|
||||
inviteId: string;
|
||||
userId: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export const useClaimOnboardingToken = () => {
|
||||
return useMutation({
|
||||
mutationFn: async ({ accessToken, inviteId, userId, password }: ClaimTokenParams) =>
|
||||
await claimOnboardingToken(accessToken, inviteId, userId, password),
|
||||
});
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue