import { describe, expect, it } from "vite-plus/test"; import { changeRequestWebUrl, resolveLinkPullRequestInput } from "./LinkPullRequestDialog"; const project = { host: "github.com", repository: "acme/web", webUrl: (number: number) => changeRequestWebUrl("github", "github.com", "acme/web", number),}; describe("resolveLinkPullRequestInput", () => { it.each([ ["https://bitbucket.org/acme/web/pull-requests/42", "bitbucket.org"], ["https://github.acme.test/acme/web/pull/42", "github.acme.test"], ["https://git.acme.test/acme/web/-/merge_requests/42", "git.acme.test"], ])("links supported host URL %s without a thread project", (url, host) => { expect( resolveLinkPullRequestInput({ reference: ` ${url} `, project: null, hasProject: (candidate) => candidate.host === host, }), ).toEqual({ link: { host, repository: "acme/web", number: 42, url } }); }); it("validates the full Azure repository when resolving a browser URL", () => { const hasProject = (reference: { host: string; repository: string }) => reference.host === "dev.azure.com" && reference.repository === "org-a/project/_git/web"; expect( resolveLinkPullRequestInput({ reference: "https://dev.azure.com/org-a/project/_git/web/pullrequest/42", project: null, hasProject, }), ).toMatchObject({ link: { repository: "org-a/project/_git/web", number: 42 } }); expect( resolveLinkPullRequestInput({ reference: "https://dev.azure.com/org-b/project/_git/web/pullrequest/42", project: null, hasProject, }), ).toMatchObject({ error: expect.stringContaining("org-b/project/_git/web") }); }); it("resolves bare Azure numbers into canonical browser URLs", () => { expect( resolveLinkPullRequestInput({ reference: "#42", project: { host: "ssh.dev.azure.com", repository: "v3/org/project/web", webUrl: (number) => changeRequestWebUrl("azure-devops", "ssh.dev.azure.com", "v3/org/project/web", number), }, hasProject: () => true, }), ).toMatchObject({ link: { host: "dev.azure.com", repository: "org/project/_git/web", number: 42, url: "https://dev.azure.com/org/project/_git/web/pullrequest/42", }, }); }); it("returns null for input that is not a reference", () => { expect( resolveLinkPullRequestInput({ reference: "hello", project, hasProject: () => true }), ).toBeNull(); }); it("resolves a bare number against the thread's own repository", () => { expect( resolveLinkPullRequestInput({ reference: "#42", project, hasProject: () => true }), ).toEqual({ link: { host: "github.com", repository: "acme/web", number: 42, url: "https://github.com/acme/web/pull/42", }, }); }); it("links a URL from another repository on a host with a project", () => { expect( resolveLinkPullRequestInput({ reference: "https://github.com/acme/api/pull/7", project, hasProject: (reference) => reference.host === "github.com", }), ).toEqual({ link: { host: "github.com", repository: "acme/api", number: 7, url: "https://github.com/acme/api/pull/7", }, }); }); it("refuses a URL on a host nothing is checked out from", () => { const result = resolveLinkPullRequestInput({ reference: "https://gitlab.com/acme/api/-/merge_requests/7", project, hasProject: () => false, }); expect(result).toMatchObject({ error: expect.stringContaining("gitlab.com") }); }); it("asks for a URL when a bare number has no project to resolve against", () => { expect( resolveLinkPullRequestInput({ reference: "12", project: null, hasProject: () => true }), ).toMatchObject({ error: expect.stringContaining("full URL") }); }); it("accepts a checkout command as a reference", () => { expect( resolveLinkPullRequestInput({ reference: "gh pr checkout https://github.com/acme/web/pull/3", project, hasProject: () => true, }), ).toMatchObject({ link: { number: 3, repository: "acme/web" } }); });}); describe("changeRequestWebUrl", () => { it("knows the four hosts and nothing else", () => { expect(changeRequestWebUrl("gitlab", "gitlab.com", "g/sub/repo", 5)).toBe( "https://gitlab.com/g/sub/repo/-/merge_requests/5", ); expect(changeRequestWebUrl("unknown", "x", "a/b", 1)).toBeNull(); });});
import { describe, expect, it } from "vite-plus/test";
import { changeRequestWebUrl, resolveLinkPullRequestInput } from "./LinkPullRequestDialog";
const project = {
host: "github.com",
repository: "acme/web",
webUrl: (number: number) => changeRequestWebUrl("github", "github.com", "acme/web", number),
};
describe("resolveLinkPullRequestInput", () => {
it.each([
["https://bitbucket.org/acme/web/pull-requests/42", "bitbucket.org"],
["https://github.acme.test/acme/web/pull/42", "github.acme.test"],
["https://git.acme.test/acme/web/-/merge_requests/42", "git.acme.test"],
])("links supported host URL %s without a thread project", (url, host) => {
expect(
resolveLinkPullRequestInput({
reference: ` ${url} `,
project: null,
hasProject: (candidate) => candidate.host === host,
}),
).toEqual({ link: { host, repository: "acme/web", number: 42, url } });
});
it("validates the full Azure repository when resolving a browser URL", () => {
const hasProject = (reference: { host: string; repository: string }) =>
reference.host === "dev.azure.com" && reference.repository === "org-a/project/_git/web";
expect(
resolveLinkPullRequestInput({
reference: "https://dev.azure.com/org-a/project/_git/web/pullrequest/42",
project: null,
hasProject,
}),
).toMatchObject({ link: { repository: "org-a/project/_git/web", number: 42 } });
expect(
resolveLinkPullRequestInput({
reference: "https://dev.azure.com/org-b/project/_git/web/pullrequest/42",
project: null,
hasProject,
}),
).toMatchObject({ error: expect.stringContaining("org-b/project/_git/web") });
});
it("resolves bare Azure numbers into canonical browser URLs", () => {
expect(
resolveLinkPullRequestInput({
reference: "#42",
project: {
host: "ssh.dev.azure.com",
repository: "v3/org/project/web",
webUrl: (number) =>
changeRequestWebUrl("azure-devops", "ssh.dev.azure.com", "v3/org/project/web", number),
},
hasProject: () => true,
}),
).toMatchObject({
link: {
host: "dev.azure.com",
repository: "org/project/_git/web",
number: 42,
url: "https://dev.azure.com/org/project/_git/web/pullrequest/42",
},
});
});
it("returns null for input that is not a reference", () => {
expect(
resolveLinkPullRequestInput({ reference: "hello", project, hasProject: () => true }),
).toBeNull();
});
it("resolves a bare number against the thread's own repository", () => {
expect(
resolveLinkPullRequestInput({ reference: "#42", project, hasProject: () => true }),
).toEqual({
link: {
host: "github.com",
repository: "acme/web",
number: 42,
url: "https://github.com/acme/web/pull/42",
},
});
});
it("links a URL from another repository on a host with a project", () => {
expect(
resolveLinkPullRequestInput({
reference: "https://github.com/acme/api/pull/7",
project,
hasProject: (reference) => reference.host === "github.com",
}),
).toEqual({
link: {
host: "github.com",
repository: "acme/api",
number: 7,
url: "https://github.com/acme/api/pull/7",
},
});
});
it("refuses a URL on a host nothing is checked out from", () => {
const result = resolveLinkPullRequestInput({
reference: "https://gitlab.com/acme/api/-/merge_requests/7",
project,
hasProject: () => false,
});
expect(result).toMatchObject({ error: expect.stringContaining("gitlab.com") });
});
it("asks for a URL when a bare number has no project to resolve against", () => {
expect(
resolveLinkPullRequestInput({ reference: "12", project: null, hasProject: () => true }),
).toMatchObject({ error: expect.stringContaining("full URL") });
});
it("accepts a checkout command as a reference", () => {
expect(
resolveLinkPullRequestInput({
reference: "gh pr checkout https://github.com/acme/web/pull/3",
project,
hasProject: () => true,
}),
).toMatchObject({ link: { number: 3, repository: "acme/web" } });
});
});
describe("changeRequestWebUrl", () => {
it("knows the four hosts and nothing else", () => {
expect(changeRequestWebUrl("gitlab", "gitlab.com", "g/sub/repo", 5)).toBe(
"https://gitlab.com/g/sub/repo/-/merge_requests/5",
);
expect(changeRequestWebUrl("unknown", "x", "a/b", 1)).toBeNull();
});
});