mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-01-08 22:38:05 -05:00
Co-authored-by: openhands <openhands@all-hands.dev> Co-authored-by: Engel Nyst <enyst@users.noreply.github.com> Co-authored-by: Rohit Malhotra <rohitvinodmalhotra@gmail.com>
260 lines
6.8 KiB
TypeScript
260 lines
6.8 KiB
TypeScript
import { render, screen } from "@testing-library/react";
|
|
import { describe, expect, vi, beforeEach, it } from "vitest";
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { RepositorySelectionForm } from "../../../../src/components/features/home/repo-selection-form";
|
|
import OpenHands from "#/api/open-hands";
|
|
import { GitRepository } from "#/types/git";
|
|
|
|
// Create mock functions
|
|
const mockUseUserRepositories = vi.fn();
|
|
const mockUseCreateConversation = vi.fn();
|
|
const mockUseIsCreatingConversation = vi.fn();
|
|
const mockUseTranslation = vi.fn();
|
|
const mockUseAuth = vi.fn();
|
|
|
|
// Setup default mock returns
|
|
mockUseUserRepositories.mockReturnValue({
|
|
data: [],
|
|
isLoading: false,
|
|
isError: false,
|
|
});
|
|
|
|
mockUseCreateConversation.mockReturnValue({
|
|
mutate: vi.fn(),
|
|
isPending: false,
|
|
isSuccess: false,
|
|
});
|
|
|
|
mockUseIsCreatingConversation.mockReturnValue(false);
|
|
|
|
mockUseTranslation.mockReturnValue({ t: (key: string) => key });
|
|
|
|
mockUseAuth.mockReturnValue({
|
|
isAuthenticated: true,
|
|
isLoading: false,
|
|
providersAreSet: true,
|
|
user: {
|
|
id: 1,
|
|
login: "testuser",
|
|
avatar_url: "https://example.com/avatar.png",
|
|
name: "Test User",
|
|
email: "test@example.com",
|
|
company: "Test Company",
|
|
},
|
|
login: vi.fn(),
|
|
logout: vi.fn(),
|
|
});
|
|
|
|
vi.mock("#/hooks/mutation/use-create-conversation", () => ({
|
|
useCreateConversation: () => mockUseCreateConversation(),
|
|
}));
|
|
|
|
vi.mock("#/hooks/use-is-creating-conversation", () => ({
|
|
useIsCreatingConversation: () => mockUseIsCreatingConversation(),
|
|
}));
|
|
|
|
vi.mock("react-i18next", () => ({
|
|
useTranslation: () => mockUseTranslation(),
|
|
}));
|
|
|
|
vi.mock("#/context/auth-context", () => ({
|
|
useAuth: () => mockUseAuth(),
|
|
}));
|
|
|
|
vi.mock("#/hooks/use-debounce", () => ({
|
|
useDebounce: (value: string) => value,
|
|
}));
|
|
|
|
const mockOnRepoSelection = vi.fn();
|
|
const renderForm = () =>
|
|
render(<RepositorySelectionForm onRepoSelection={mockOnRepoSelection} />, {
|
|
wrapper: ({ children }) => (
|
|
<QueryClientProvider
|
|
client={
|
|
new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: false,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
>
|
|
{children}
|
|
</QueryClientProvider>
|
|
),
|
|
});
|
|
|
|
describe("RepositorySelectionForm", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("shows loading indicator when repositories are being fetched", () => {
|
|
const MOCK_REPOS: GitRepository[] = [
|
|
{
|
|
id: "1",
|
|
full_name: "user/repo1",
|
|
git_provider: "github",
|
|
is_public: true,
|
|
},
|
|
{
|
|
id: "2",
|
|
full_name: "user/repo2",
|
|
git_provider: "github",
|
|
is_public: true,
|
|
},
|
|
];
|
|
const retrieveUserGitRepositoriesSpy = vi.spyOn(
|
|
OpenHands,
|
|
"retrieveUserGitRepositories",
|
|
);
|
|
retrieveUserGitRepositoriesSpy.mockResolvedValue(MOCK_REPOS);
|
|
|
|
renderForm();
|
|
|
|
// Check if loading indicator is displayed
|
|
expect(screen.getByTestId("repo-dropdown-loading")).toBeInTheDocument();
|
|
expect(screen.getByText("HOME$LOADING_REPOSITORIES")).toBeInTheDocument();
|
|
});
|
|
|
|
it("shows dropdown when repositories are loaded", async () => {
|
|
const MOCK_REPOS: GitRepository[] = [
|
|
{
|
|
id: "1",
|
|
full_name: "user/repo1",
|
|
git_provider: "github",
|
|
is_public: true,
|
|
},
|
|
{
|
|
id: "2",
|
|
full_name: "user/repo2",
|
|
git_provider: "github",
|
|
is_public: true,
|
|
},
|
|
];
|
|
const retrieveUserGitRepositoriesSpy = vi.spyOn(
|
|
OpenHands,
|
|
"retrieveUserGitRepositories",
|
|
);
|
|
retrieveUserGitRepositoriesSpy.mockResolvedValue(MOCK_REPOS);
|
|
|
|
renderForm();
|
|
expect(await screen.findByTestId("repo-dropdown")).toBeInTheDocument();
|
|
});
|
|
|
|
it("shows error message when repository fetch fails", async () => {
|
|
const retrieveUserGitRepositoriesSpy = vi.spyOn(
|
|
OpenHands,
|
|
"retrieveUserGitRepositories",
|
|
);
|
|
retrieveUserGitRepositoriesSpy.mockRejectedValue(
|
|
new Error("Failed to load"),
|
|
);
|
|
|
|
renderForm();
|
|
|
|
expect(
|
|
await screen.findByTestId("repo-dropdown-error"),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByText("HOME$FAILED_TO_LOAD_REPOSITORIES"),
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it("should call the search repos API when searching a URL", async () => {
|
|
const MOCK_REPOS: GitRepository[] = [
|
|
{
|
|
id: "1",
|
|
full_name: "user/repo1",
|
|
git_provider: "github",
|
|
is_public: true,
|
|
},
|
|
{
|
|
id: "2",
|
|
full_name: "user/repo2",
|
|
git_provider: "github",
|
|
is_public: true,
|
|
},
|
|
];
|
|
|
|
const MOCK_SEARCH_REPOS: GitRepository[] = [
|
|
{
|
|
id: "3",
|
|
full_name: "kubernetes/kubernetes",
|
|
git_provider: "github",
|
|
is_public: true,
|
|
},
|
|
];
|
|
|
|
const searchGitReposSpy = vi.spyOn(OpenHands, "searchGitRepositories");
|
|
const retrieveUserGitRepositoriesSpy = vi.spyOn(
|
|
OpenHands,
|
|
"retrieveUserGitRepositories",
|
|
);
|
|
|
|
searchGitReposSpy.mockResolvedValue(MOCK_SEARCH_REPOS);
|
|
retrieveUserGitRepositoriesSpy.mockResolvedValue(MOCK_REPOS);
|
|
|
|
renderForm();
|
|
|
|
const input = await screen.findByTestId("repo-dropdown");
|
|
await userEvent.click(input);
|
|
|
|
for (const repo of MOCK_REPOS) {
|
|
expect(screen.getByText(repo.full_name)).toBeInTheDocument();
|
|
}
|
|
expect(
|
|
screen.queryByText(MOCK_SEARCH_REPOS[0].full_name),
|
|
).not.toBeInTheDocument();
|
|
|
|
expect(searchGitReposSpy).not.toHaveBeenCalled();
|
|
|
|
await userEvent.type(input, "https://github.com/kubernetes/kubernetes");
|
|
expect(searchGitReposSpy).toHaveBeenLastCalledWith(
|
|
"kubernetes/kubernetes",
|
|
3,
|
|
);
|
|
|
|
expect(
|
|
screen.getByText(MOCK_SEARCH_REPOS[0].full_name),
|
|
).toBeInTheDocument();
|
|
for (const repo of MOCK_REPOS) {
|
|
expect(screen.queryByText(repo.full_name)).not.toBeInTheDocument();
|
|
}
|
|
});
|
|
|
|
it("should call onRepoSelection when a searched repository is selected", async () => {
|
|
const MOCK_SEARCH_REPOS: GitRepository[] = [
|
|
{
|
|
id: "3",
|
|
full_name: "kubernetes/kubernetes",
|
|
git_provider: "github",
|
|
is_public: true,
|
|
},
|
|
];
|
|
|
|
const searchGitReposSpy = vi.spyOn(OpenHands, "searchGitRepositories");
|
|
searchGitReposSpy.mockResolvedValue(MOCK_SEARCH_REPOS);
|
|
|
|
renderForm();
|
|
|
|
const input = await screen.findByTestId("repo-dropdown");
|
|
|
|
await userEvent.type(input, "https://github.com/kubernetes/kubernetes");
|
|
expect(searchGitReposSpy).toHaveBeenLastCalledWith(
|
|
"kubernetes/kubernetes",
|
|
3,
|
|
);
|
|
|
|
const searchedRepo = screen.getByText(MOCK_SEARCH_REPOS[0].full_name);
|
|
expect(searchedRepo).toBeInTheDocument();
|
|
|
|
await userEvent.click(searchedRepo);
|
|
expect(mockOnRepoSelection).toHaveBeenCalledWith(
|
|
MOCK_SEARCH_REPOS[0].full_name,
|
|
);
|
|
});
|
|
});
|