151 lines
5.7 KiB
TypeScript
151 lines
5.7 KiB
TypeScript
import { postgresTest } from "@internal/testcontainers";
|
|
import { type PrismaClient } from "@trigger.dev/database";
|
|
import slug from "slug";
|
|
import { describe, expect, vi } from "vitest";
|
|
import { ArchiveBranchService } from "~/services/archiveBranch.server";
|
|
import { UpsertBranchService } from "~/services/upsertBranch.server";
|
|
import { createTestOrgProjectWithMember, uniqueId } from "./fixtures/environmentVariablesFixtures";
|
|
|
|
vi.setConfig({ testTimeout: 60_000 });
|
|
|
|
async function createDevRoot(
|
|
prisma: PrismaClient,
|
|
projectId: string,
|
|
organizationId: string,
|
|
orgMemberId: string
|
|
) {
|
|
return prisma.runtimeEnvironment.create({
|
|
data: {
|
|
slug: "dev",
|
|
apiKey: uniqueId("tr_dev"),
|
|
pkApiKey: uniqueId("pk_dev"),
|
|
shortcode: uniqueId("sc"),
|
|
projectId,
|
|
organizationId,
|
|
type: "DEVELOPMENT",
|
|
orgMemberId,
|
|
maximumConcurrencyLimit: 17,
|
|
},
|
|
});
|
|
}
|
|
|
|
describe("UpsertBranchService — DEVELOPMENT parent", () => {
|
|
postgresTest(
|
|
"creates a child branch that inherits the parent's ownership",
|
|
async ({ prisma }) => {
|
|
const { organization, project, user, orgMember } =
|
|
await createTestOrgProjectWithMember(prisma);
|
|
const devRoot = await createDevRoot(prisma, project.id, organization.id, orgMember.id);
|
|
|
|
const result = await new UpsertBranchService(prisma).call(
|
|
{ type: "userMembership", userId: user.id },
|
|
{ projectId: project.id, env: "development", branchName: "my-feature" }
|
|
);
|
|
|
|
expect(result.success).toBe(true);
|
|
if (!result.success) return;
|
|
|
|
const { branch } = result;
|
|
expect(branch.type).toBe("DEVELOPMENT");
|
|
expect(branch.parentEnvironmentId).toBe(devRoot.id);
|
|
expect(branch.branchName).toBe("my-feature");
|
|
// The key dev-vs-preview divergence: dev branches MUST copy the parent's
|
|
// orgMemberId (preview parents have none).
|
|
expect(branch.orgMemberId).toBe(orgMember.id);
|
|
// Children inherit the parent's concurrency limit at creation.
|
|
expect(branch.maximumConcurrencyLimit).toBe(17);
|
|
expect(branch.slug).toBe(slug(`${devRoot.slug}-my-feature`));
|
|
}
|
|
);
|
|
|
|
postgresTest(
|
|
"is idempotent — upserting the same branch returns the existing row",
|
|
async ({ prisma }) => {
|
|
const { organization, project, user, orgMember } =
|
|
await createTestOrgProjectWithMember(prisma);
|
|
await createDevRoot(prisma, project.id, organization.id, orgMember.id);
|
|
const orgFilter = { type: "userMembership" as const, userId: user.id };
|
|
const options = { projectId: project.id, env: "development" as const, branchName: "dup" };
|
|
|
|
const first = await new UpsertBranchService(prisma).call(orgFilter, options);
|
|
const second = await new UpsertBranchService(prisma).call(orgFilter, options);
|
|
|
|
expect(first.success && second.success).toBe(true);
|
|
if (!first.success || !second.success) return;
|
|
expect(second.alreadyExisted).toBe(true);
|
|
expect(second.branch.id).toBe(first.branch.id);
|
|
}
|
|
);
|
|
|
|
postgresTest(
|
|
"rejects an invalid branch name without touching the database",
|
|
async ({ prisma }) => {
|
|
const { organization, project, user, orgMember } =
|
|
await createTestOrgProjectWithMember(prisma);
|
|
await createDevRoot(prisma, project.id, organization.id, orgMember.id);
|
|
|
|
const result = await new UpsertBranchService(prisma).call(
|
|
{ type: "userMembership", userId: user.id },
|
|
{ projectId: project.id, env: "development", branchName: "bad branch name!" }
|
|
);
|
|
|
|
expect(result.success).toBe(false);
|
|
}
|
|
);
|
|
});
|
|
|
|
describe("ArchiveBranchService — DEVELOPMENT", () => {
|
|
postgresTest(
|
|
"archives a dev branch and frees its slug/shortcode for reuse",
|
|
async ({ prisma }) => {
|
|
const { organization, project, user, orgMember } =
|
|
await createTestOrgProjectWithMember(prisma);
|
|
await createDevRoot(prisma, project.id, organization.id, orgMember.id);
|
|
const orgFilter = { type: "userMembership" as const, userId: user.id };
|
|
|
|
const created = await new UpsertBranchService(prisma).call(orgFilter, {
|
|
projectId: project.id,
|
|
env: "development",
|
|
branchName: "reuse-me",
|
|
});
|
|
expect(created.success).toBe(true);
|
|
if (!created.success) return;
|
|
const originalSlug = created.branch.slug;
|
|
|
|
const archived = await new ArchiveBranchService(prisma).call(orgFilter, {
|
|
environmentId: created.branch.id,
|
|
});
|
|
expect(archived.success).toBe(true);
|
|
if (!archived.success) return;
|
|
expect(archived.branch.archivedAt).not.toBeNull();
|
|
// Slug + shortcode are randomized on archive so the name can be reused.
|
|
expect(archived.branch.slug).not.toBe(originalSlug);
|
|
|
|
// The same branch name can now be created again (new row, deterministic slug).
|
|
const recreated = await new UpsertBranchService(prisma).call(orgFilter, {
|
|
projectId: project.id,
|
|
env: "development",
|
|
branchName: "reuse-me",
|
|
});
|
|
expect(recreated.success).toBe(true);
|
|
if (!recreated.success) return;
|
|
expect(recreated.branch.id).not.toBe(created.branch.id);
|
|
expect(recreated.branch.slug).toBe(originalSlug);
|
|
}
|
|
);
|
|
|
|
postgresTest("refuses to archive the default branch (the dev root)", async ({ prisma }) => {
|
|
const { organization, project, user, orgMember } = await createTestOrgProjectWithMember(prisma);
|
|
const devRoot = await createDevRoot(prisma, project.id, organization.id, orgMember.id);
|
|
|
|
const result = await new ArchiveBranchService(prisma).call(
|
|
{ type: "userMembership", userId: user.id },
|
|
{ environmentId: devRoot.id }
|
|
);
|
|
|
|
expect(result.success).toBe(false);
|
|
if (result.success) return;
|
|
expect(result.error).toBe("The default development branch cannot be archived.");
|
|
});
|
|
});
|