602 lines
21 KiB
TypeScript
602 lines
21 KiB
TypeScript
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
import { screen, fireEvent, cleanup } from "@testing-library/react";
|
|
import type { Branch } from "@/lib/types/http";
|
|
import type { UseRemoteRepositoriesResult } from "@/hooks/domains/integrations/use-remote-repositories";
|
|
import { RemoteRepoChip } from "./task-create-dialog-remote-repo-chip";
|
|
import {
|
|
githubSite,
|
|
makeAccessible,
|
|
noopBranch,
|
|
noopRemove,
|
|
renderInProvider,
|
|
renderRemoteRepoChip,
|
|
row,
|
|
} from "./task-create-dialog-remote-repo-chip-test-support";
|
|
|
|
const TRIGGER_TID = "remote-repo-chip-trigger";
|
|
const INPUT_TID = "remote-repo-input";
|
|
const ALREADY_ADDED_MARKER = "already-added-repository-marker";
|
|
const FULL_NAME = "acme/site";
|
|
const URL_ACME_SITE = "https://github.com/acme/site";
|
|
afterEach(() => {
|
|
cleanup();
|
|
});
|
|
describe("RemoteRepoChip — write paths", () => {
|
|
it("keeps the committed URL visible and exposes an actionable resolution retry", () => {
|
|
const onRetry = vi.fn();
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row({ url: URL_ACME_SITE, branch: "main" })}
|
|
branches={[{ name: "main", type: "remote" }]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible()}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
resolutionError={new Error("GitHub rate limit exceeded")}
|
|
onRetry={onRetry}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByTestId("remote-repo-chip").getAttribute("data-remote-url")).toBe(
|
|
URL_ACME_SITE,
|
|
);
|
|
expect(screen.getByTestId("remote-repo-chip-wrapper").className).toContain("flex-col");
|
|
expect(screen.getByTestId("remote-repo-chip").className).toContain("inline-flex");
|
|
const alert = screen.getByRole("alert");
|
|
expect(alert.className).toContain("max-w-full");
|
|
expect(alert.textContent).toContain("GitHub rate limit exceeded");
|
|
const retryButton = screen.getByRole("button", { name: /retry remote repository resolution/i });
|
|
expect(retryButton.getAttribute("data-size")).toBe("default");
|
|
expect(retryButton.className).toContain("h-7");
|
|
expect(retryButton.className).toContain("pointer:coarse");
|
|
fireEvent.click(retryButton);
|
|
expect(onRetry).toHaveBeenCalledOnce();
|
|
});
|
|
});
|
|
|
|
describe("RemoteRepoChip — custom provider URL input", () => {
|
|
it("accepts a custom provider URL only when the provider registry matches it", () => {
|
|
const onURLChange = vi.fn();
|
|
const accessibleRepos = {
|
|
...makeAccessible(),
|
|
matchesURL: (url: string) => url.includes("bitbucket.example.test/bitbucket/"),
|
|
} as unknown as UseRemoteRepositoriesResult;
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={accessibleRepos}
|
|
onURLChange={onURLChange}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
fireEvent.change(screen.getByTestId(INPUT_TID), {
|
|
target: { value: "https://bitbucket.example.test/bitbucket/projects/PLATFORM/repos/web" },
|
|
});
|
|
fireEvent.keyDown(screen.getByTestId(INPUT_TID), { key: "Enter" });
|
|
|
|
expect(onURLChange).toHaveBeenCalledWith(
|
|
"https://bitbucket.example.test/bitbucket/projects/PLATFORM/repos/web",
|
|
"paste",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("RemoteRepoChip — picker selection write paths", () => {
|
|
it("picker selection writes URL + picker metadata (incl. default_branch) via onURLChange", () => {
|
|
const accessibleRepos = makeAccessible({
|
|
repos: [githubSite({ default_branch: "trunk" })],
|
|
});
|
|
const onURLChange = vi.fn();
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={accessibleRepos}
|
|
onURLChange={onURLChange}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
fireEvent.click(screen.getByText(FULL_NAME));
|
|
expect(onURLChange).toHaveBeenCalledWith(
|
|
URL_ACME_SITE,
|
|
"picker",
|
|
expect.objectContaining({
|
|
provider: "github",
|
|
fullName: FULL_NAME,
|
|
defaultBranch: "trunk",
|
|
}),
|
|
);
|
|
});
|
|
it("selects an Azure DevOps repository with provider metadata", () => {
|
|
const accessibleRepos = makeAccessible({
|
|
repos: [
|
|
{
|
|
provider: "azure_devops",
|
|
owner: "Platform",
|
|
name: "api",
|
|
full_name: "Platform/api",
|
|
default_branch: "main",
|
|
private: true,
|
|
},
|
|
],
|
|
});
|
|
const onURLChange = vi.fn();
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={accessibleRepos}
|
|
onURLChange={onURLChange}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
fireEvent.click(screen.getByRole("button", { name: /Platform\/api/i }));
|
|
expect(onURLChange).toHaveBeenCalledWith(
|
|
"https://dev.azure.com/acme/Platform/_git/api",
|
|
"picker",
|
|
expect.objectContaining({ provider: "azure_devops", fullName: "Platform/api" }),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("RemoteRepoChip — removal write path", () => {
|
|
it("calls onRemove when the X button is clicked", () => {
|
|
const onRemove = vi.fn();
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row({ url: URL_ACME_SITE })}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible()}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={onRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId("remote-chip-remove"));
|
|
expect(onRemove).toHaveBeenCalledOnce();
|
|
});
|
|
});
|
|
describe("RemoteRepoChip — already added marker", () => {
|
|
it("marks a provider repository selected in another row and still selects it", () => {
|
|
const onURLChange = vi.fn();
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible({
|
|
repos: [githubSite()],
|
|
})}
|
|
selectedRepositoryIdentities={["github:id:acme/site"]}
|
|
onURLChange={onURLChange}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
const marker = screen.getByTestId(ALREADY_ADDED_MARKER);
|
|
expect(marker.getAttribute("aria-label")).toBe("Already added");
|
|
expect(marker.classList).toContain("text-primary");
|
|
expect(screen.queryByText("Already added")).toBeNull();
|
|
fireEvent.click(screen.getByText(FULL_NAME).closest("button") as HTMLButtonElement);
|
|
expect(onURLChange).toHaveBeenCalledOnce();
|
|
});
|
|
it("does not mark an identical provider id from a different provider", () => {
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible({
|
|
repos: [
|
|
{
|
|
provider: "gitlab",
|
|
owner: "acme",
|
|
name: "site",
|
|
full_name: FULL_NAME,
|
|
default_branch: "main",
|
|
private: false,
|
|
},
|
|
],
|
|
})}
|
|
selectedRepositoryIdentities={["github:id:acme/site"]}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
expect(screen.queryByTestId(ALREADY_ADDED_MARKER)).toBeNull();
|
|
});
|
|
it("marks an option from a normalized pasted URL identity", () => {
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible({
|
|
repos: [githubSite()],
|
|
})}
|
|
selectedRepositoryIdentities={["url:github:acme/site"]}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
expect(screen.getByTestId(ALREADY_ADDED_MARKER)).toBeTruthy();
|
|
});
|
|
});
|
|
describe("RemoteRepoChip — unified search", () => {
|
|
it("uses ordinary text as repository search without committing it on blur", () => {
|
|
const onURLChange = vi.fn();
|
|
const search = vi.fn();
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible({ search })}
|
|
onURLChange={onURLChange}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
const input = screen.getByTestId(INPUT_TID) as HTMLInputElement;
|
|
fireEvent.change(input, { target: { value: "acme" } });
|
|
fireEvent.blur(input);
|
|
expect(search).toHaveBeenLastCalledWith("acme");
|
|
expect(input.getAttribute("aria-invalid")).toBeNull();
|
|
expect(screen.queryByRole("alert")).toBeNull();
|
|
expect(onURLChange).not.toHaveBeenCalled();
|
|
});
|
|
it("picker click after searching commits only the selected repository", () => {
|
|
const accessibleRepos = makeAccessible({
|
|
repos: [githubSite()],
|
|
});
|
|
const onURLChange = vi.fn();
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={accessibleRepos}
|
|
onURLChange={onURLChange}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
const input = screen.getByTestId(INPUT_TID) as HTMLInputElement;
|
|
fireEvent.change(input, { target: { value: "acme" } });
|
|
const option = screen.getByText(FULL_NAME).closest("button") as HTMLButtonElement;
|
|
fireEvent.blur(input, { relatedTarget: option });
|
|
fireEvent.click(option);
|
|
expect(onURLChange).toHaveBeenCalledTimes(1);
|
|
expect(onURLChange).toHaveBeenCalledWith(
|
|
URL_ACME_SITE,
|
|
"picker",
|
|
expect.objectContaining({
|
|
provider: "github",
|
|
fullName: FULL_NAME,
|
|
defaultBranch: "main",
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
describe("RemoteRepoChip — picker focus", () => {
|
|
it("does not commit a typed URL on blur when focus moves to a repository option", () => {
|
|
const accessibleRepos = makeAccessible({
|
|
repos: [githubSite()],
|
|
});
|
|
const onURLChange = vi.fn();
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={accessibleRepos}
|
|
onURLChange={onURLChange}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
const input = screen.getByTestId(INPUT_TID) as HTMLInputElement;
|
|
fireEvent.change(input, { target: { value: URL_ACME_SITE } });
|
|
const option = screen.getByText(FULL_NAME).closest("button") as HTMLButtonElement;
|
|
fireEvent.blur(input, { relatedTarget: option });
|
|
fireEvent.click(option);
|
|
expect(onURLChange).toHaveBeenCalledTimes(1);
|
|
expect(onURLChange).toHaveBeenCalledWith(
|
|
URL_ACME_SITE,
|
|
"picker",
|
|
expect.objectContaining({
|
|
provider: "github",
|
|
fullName: FULL_NAME,
|
|
defaultBranch: "main",
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
describe("RemoteRepoChip — branch pill", () => {
|
|
it("is disabled when the URL is empty", () => {
|
|
renderRemoteRepoChip();
|
|
const branchTrigger = screen.getByTestId("remote-branch-chip-trigger") as HTMLButtonElement;
|
|
expect(branchTrigger.disabled).toBe(true);
|
|
});
|
|
it("enables once URL is present and branches load", () => {
|
|
const branches: Branch[] = [
|
|
{ name: "main", type: "remote", remote: "origin" },
|
|
{ name: "develop", type: "remote", remote: "origin" },
|
|
];
|
|
renderRemoteRepoChip({ row: row({ url: URL_ACME_SITE }), branches });
|
|
const branchTrigger = screen.getByTestId("remote-branch-chip-trigger") as HTMLButtonElement;
|
|
expect(branchTrigger.disabled).toBe(false);
|
|
});
|
|
|
|
it("is enabled when the row already has a branch even if branch options haven't loaded yet", () => {
|
|
renderRemoteRepoChip({
|
|
row: row({ url: URL_ACME_SITE, branch: "trunk" }),
|
|
branchesLoading: true,
|
|
});
|
|
const branchTrigger = screen.getByTestId("remote-branch-chip-trigger") as HTMLButtonElement;
|
|
expect(branchTrigger.disabled).toBe(false);
|
|
expect(branchTrigger.textContent).toContain("trunk");
|
|
});
|
|
});
|
|
|
|
describe("RemoteRepoChip — option layout", () => {
|
|
it("never renders an option description line, even when the repo has a description", () => {
|
|
const accessibleRepos = makeAccessible({
|
|
repos: [githubSite({ description: "The acme corporate website" })],
|
|
});
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={accessibleRepos}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
expect(screen.queryByTestId("remote-repo-option-description")).toBeNull();
|
|
expect(screen.queryByText("The acme corporate website")).toBeNull();
|
|
expect(screen.getByText(FULL_NAME)).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe("RemoteRepoChip — picker loading state", () => {
|
|
it("renders an inline spinner while the initial fetch is loading and no repos are yet available", () => {
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible({ loading: true })}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
const loadingNode = screen.getByTestId("remote-repo-picker-loading");
|
|
expect(loadingNode.textContent).toContain("Loading repositories");
|
|
expect(loadingNode.parentElement?.className).toContain("h-56");
|
|
});
|
|
|
|
it("does NOT render the spinner once repos have loaded (even if loading flips true again later)", () => {
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible({
|
|
loading: true,
|
|
repos: [githubSite()],
|
|
})}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
expect(screen.queryByTestId("remote-repo-picker-loading")).toBeNull();
|
|
expect(screen.getByText(FULL_NAME)).toBeTruthy();
|
|
});
|
|
|
|
it("does not render a loading spinner with the GitHub connection banner", () => {
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible({ unavailable: true, loading: true })}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
expect(screen.getByText(/Connect a source control provider/i)).toBeTruthy();
|
|
expect(screen.queryByTestId("remote-repo-picker-loading")).toBeNull();
|
|
});
|
|
|
|
it("shows only the connection banner for invalid URL input when GitHub is unavailable", () => {
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible({ unavailable: true })}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
const input = screen.getByTestId(INPUT_TID) as HTMLInputElement;
|
|
fireEvent.change(input, { target: { value: "https://bitbucket.org/acme/api" } });
|
|
fireEvent.keyDown(input, { key: "Enter" });
|
|
|
|
expect(screen.getByText(/Connect a source control provider/i)).toBeTruthy();
|
|
expect(screen.queryByRole("alert")).toBeNull();
|
|
expect(input.getAttribute("aria-invalid")).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("RemoteRepoChip — popover content", () => {
|
|
it.each([
|
|
"git@github.com:acme/api.git",
|
|
"git@gitlab.com:acme/api.git",
|
|
"git@ssh.dev.azure.com:v3/acme/project/api",
|
|
])("shows the Enter hint for supported SCP remote %s", (remoteURL) => {
|
|
renderRemoteRepoChip();
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
fireEvent.change(screen.getByTestId(INPUT_TID), { target: { value: remoteURL } });
|
|
|
|
expect(screen.getByText(/press Enter to submit it/i)).toBeTruthy();
|
|
});
|
|
|
|
it("renders one top-level input for both repository search and GitHub URLs", () => {
|
|
renderRemoteRepoChip();
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
const input = screen.getByTestId(INPUT_TID) as HTMLInputElement;
|
|
expect(input.placeholder).toBe("Search repositories or paste a remote URL");
|
|
expect(screen.queryByTestId("remote-repo-search")).toBeNull();
|
|
expect(screen.queryByTestId("remote-paste-url-input")).toBeNull();
|
|
});
|
|
|
|
it("portals and constrains the repo picker so dialog overflow cannot clip it", () => {
|
|
renderInProvider(
|
|
<div data-testid="clipping-host" className="overflow-hidden">
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible()}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>
|
|
</div>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
const content = screen.getByTestId("remote-repo-popover-content");
|
|
expect(screen.getByTestId("clipping-host").contains(content)).toBe(false);
|
|
expect(content.className).toContain("max-w-[calc(100vw-2rem)]");
|
|
expect(content.className).toContain("max-h-[min(420px,calc(100vh-12rem))]");
|
|
expect(content.className).toContain("overflow-hidden");
|
|
});
|
|
|
|
it("renders the provider settings banner when no integration is available", () => {
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible({ unavailable: true })}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
expect(screen.getByText(/Connect a source control provider/i)).toBeTruthy();
|
|
const link = screen.getByRole("link", { name: /settings/i }) as HTMLAnchorElement;
|
|
expect(link.getAttribute("href")).toBe("/settings/integrations");
|
|
});
|
|
|
|
it("renders 'private' badge next to private repo options", () => {
|
|
const accessibleRepos = makeAccessible({
|
|
repos: [
|
|
{
|
|
provider: "github",
|
|
owner: "acme",
|
|
name: "secret",
|
|
full_name: "acme/secret",
|
|
default_branch: "main",
|
|
private: true,
|
|
},
|
|
],
|
|
});
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row()}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={accessibleRepos}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
fireEvent.click(screen.getByTestId(TRIGGER_TID));
|
|
expect(screen.getByText(/private/i)).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe("RemoteRepoChip — trigger label", () => {
|
|
it("displays picker label (owner/name) when row has picker metadata", () => {
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row({
|
|
url: URL_ACME_SITE,
|
|
source: "picker",
|
|
provider: "github",
|
|
fullName: FULL_NAME,
|
|
})}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible()}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
expect(screen.getByTestId(TRIGGER_TID).textContent).toContain(FULL_NAME);
|
|
});
|
|
|
|
it("displays the raw URL when source is 'paste'", () => {
|
|
renderInProvider(
|
|
<RemoteRepoChip
|
|
row={row({ url: "https://github.com/foo/bar", source: "paste" })}
|
|
branches={[]}
|
|
branchesLoading={false}
|
|
accessibleRepos={makeAccessible()}
|
|
onURLChange={vi.fn()}
|
|
onBranchChange={noopBranch}
|
|
onRemove={noopRemove}
|
|
/>,
|
|
);
|
|
expect(screen.getByTestId(TRIGGER_TID).textContent).toContain("github.com/foo/bar");
|
|
});
|
|
});
|
|
|
|
describe("RemoteRepoChip checkout gear visibility", () => {
|
|
it("does not offer checkout options before a repository is selected", () => {
|
|
renderRemoteRepoChip({ onOptionsChange: vi.fn() });
|
|
expect(screen.queryByTestId("repository-options-trigger")).toBeNull();
|
|
});
|
|
it("offers checkout options for a selected repository", () => {
|
|
renderRemoteRepoChip({ row: row({ url: URL_ACME_SITE }), onOptionsChange: vi.fn() });
|
|
expect(screen.getByTestId("repository-options-trigger")).toBeTruthy();
|
|
});
|
|
});
|