The synthetic insertedOrg passed to afterOrgCreated on the new-org branch carried id/slug/createdAt but not name, so the Stripe Connect account was created with display_name: undefined. Adds TEST_ORG_CONFIG.name to the synthetic payload.
293 lines
7.6 KiB
TypeScript
293 lines
7.6 KiB
TypeScript
import {
|
|
AppEnv,
|
|
invitation,
|
|
member,
|
|
type OrgConfig,
|
|
organizations,
|
|
user,
|
|
} from "@autumn/shared";
|
|
import type { DrizzleCli } from "@server/db/initDrizzle.js";
|
|
import {
|
|
createHardcodedKey,
|
|
createKey,
|
|
} from "@server/internal/dev/api-keys/apiKeyUtils.js";
|
|
import chalk from "chalk";
|
|
import { and, eq, inArray } from "drizzle-orm";
|
|
import { clearOrgDbOnly } from "@tests/utils/setup/clearOrg.js";
|
|
import { setupOrg } from "@tests/utils/setup/setupOrg.js";
|
|
import { afterOrgCreated } from "@server/utils/authUtils/afterOrgCreated.js";
|
|
|
|
const TEST_ORG_CONFIG = {
|
|
id: "org_2sWv2S8LJ9iaTjLI6UtNsfL88Kt",
|
|
slug: "unit-test-org",
|
|
name: "Unit Test Org",
|
|
createdAt: new Date(1738583937426).toISOString(),
|
|
created_at: 1738583937426,
|
|
};
|
|
|
|
export const TEST_ORG_PUBLISHABLE_KEY = "am_pk_test_3DoBu1cmlgxWqEXYiKaBKOPHqsu";
|
|
|
|
// Synthetic inviter pinned to the test org; satisfies invitation.inviter_id
|
|
// NOT-NULL FK without needing a real human user in a fresh worktree branch.
|
|
const TEST_INVITER_USER = {
|
|
id: "user_setup_test_inviter",
|
|
name: "Setup Test Inviter",
|
|
email: "setup-test-inviter@autumn.test",
|
|
};
|
|
|
|
const TEAM_INVITE_EMAILS = [
|
|
"ayush@useautumn.com",
|
|
"jy@useautumn.com",
|
|
"tanvir@useautumn.com",
|
|
"charlie@useautumn.com",
|
|
"owen@useautumn.com",
|
|
];
|
|
|
|
/**
|
|
* Creates a test organization in the database and generates an API key
|
|
*/
|
|
export async function createTestOrg({
|
|
db,
|
|
}: {
|
|
db: DrizzleCli;
|
|
}): Promise<string> {
|
|
console.log(
|
|
chalk.magentaBright(
|
|
"\n================ Creating Test Organization ================\n",
|
|
),
|
|
);
|
|
|
|
const TEST_API_KEY = process.env.UNIT_TEST_AUTUMN_SECRET_KEY;
|
|
|
|
// Check if org already exists
|
|
const existingOrg = await db.query.organizations.findFirst({
|
|
where: eq(organizations.id, TEST_ORG_CONFIG.id),
|
|
});
|
|
|
|
if (existingOrg) {
|
|
console.log(
|
|
chalk.yellowBright(
|
|
`Test organization '${TEST_ORG_CONFIG.slug}' already exists.`,
|
|
),
|
|
);
|
|
|
|
await afterOrgCreated({
|
|
org: { ...existingOrg, slug: TEST_ORG_CONFIG.slug } as any,
|
|
user: TEST_INVITER_USER as any,
|
|
createStripeAccount: !existingOrg.test_stripe_connect?.default_account_id,
|
|
pkey: TEST_ORG_PUBLISHABLE_KEY,
|
|
});
|
|
|
|
await seedTeamInvites({ db });
|
|
await clearOrgDbOnly({ db, orgId: TEST_ORG_CONFIG.id, env: AppEnv.Sandbox });
|
|
await setupOrg({ orgId: TEST_ORG_CONFIG.id, env: AppEnv.Sandbox });
|
|
|
|
if (TEST_API_KEY) {
|
|
const { key, alreadyExists } = await createHardcodedKey({
|
|
db,
|
|
env: AppEnv.Sandbox,
|
|
name: "Unit Test Key",
|
|
orgId: TEST_ORG_CONFIG.id,
|
|
hardcodedKey: TEST_API_KEY,
|
|
meta: {
|
|
createdBy: "setup-test-script",
|
|
createdAt: new Date().toISOString(),
|
|
},
|
|
});
|
|
console.log(
|
|
chalk.greenBright(
|
|
alreadyExists
|
|
? "✅ API key already exists in database"
|
|
: "✅ Created API key for existing organization",
|
|
),
|
|
);
|
|
return key;
|
|
}
|
|
|
|
// No hardcoded key in env; generate a fresh one for the existing org.
|
|
const generated = await createKey({
|
|
db,
|
|
env: AppEnv.Sandbox,
|
|
name: "Unit Test Key",
|
|
orgId: TEST_ORG_CONFIG.id,
|
|
prefix: "am_sk_test_",
|
|
meta: {
|
|
createdBy: "setup-test-script",
|
|
createdAt: new Date().toISOString(),
|
|
autogenerated: true,
|
|
},
|
|
});
|
|
console.log(
|
|
chalk.greenBright(
|
|
"✅ Generated fresh API key (UNIT_TEST_AUTUMN_SECRET_KEY unset)",
|
|
),
|
|
);
|
|
return generated;
|
|
}
|
|
|
|
// Create the test organization
|
|
const org = {
|
|
id: TEST_ORG_CONFIG.id,
|
|
slug: TEST_ORG_CONFIG.slug,
|
|
name: TEST_ORG_CONFIG.name,
|
|
createdAt: new Date(TEST_ORG_CONFIG.created_at),
|
|
created_at: TEST_ORG_CONFIG.created_at,
|
|
stripe_connected: false,
|
|
default_currency: "usd",
|
|
config: {} as OrgConfig,
|
|
onboarded: true,
|
|
};
|
|
|
|
await db.insert(organizations).values(org);
|
|
|
|
console.log(
|
|
chalk.greenBright(
|
|
`✅ Created test organization: ${TEST_ORG_CONFIG.slug} (${TEST_ORG_CONFIG.id})`,
|
|
),
|
|
);
|
|
|
|
const insertedOrg = {
|
|
id: TEST_ORG_CONFIG.id,
|
|
slug: TEST_ORG_CONFIG.slug,
|
|
name: TEST_ORG_CONFIG.name,
|
|
createdAt: new Date(TEST_ORG_CONFIG.created_at),
|
|
};
|
|
await afterOrgCreated({
|
|
org: insertedOrg as any,
|
|
user: TEST_INVITER_USER as any,
|
|
createStripeAccount: true,
|
|
pkey: TEST_ORG_PUBLISHABLE_KEY,
|
|
});
|
|
|
|
await seedTeamInvites({ db });
|
|
await clearOrgDbOnly({ db, orgId: TEST_ORG_CONFIG.id, env: AppEnv.Sandbox });
|
|
await setupOrg({ orgId: TEST_ORG_CONFIG.id, env: AppEnv.Sandbox });
|
|
|
|
// Create API key for the new org
|
|
if (TEST_API_KEY) {
|
|
const { key, alreadyExists } = await createHardcodedKey({
|
|
db,
|
|
env: AppEnv.Sandbox,
|
|
name: "Unit Test Key",
|
|
orgId: TEST_ORG_CONFIG.id,
|
|
hardcodedKey: TEST_API_KEY,
|
|
meta: {
|
|
createdBy: "setup-test-script",
|
|
createdAt: new Date().toISOString(),
|
|
},
|
|
});
|
|
console.log(
|
|
chalk.greenBright(
|
|
alreadyExists
|
|
? "✅ API key already exists in database"
|
|
: "✅ Created API key for test organization",
|
|
),
|
|
);
|
|
return key;
|
|
}
|
|
|
|
const generated = await createKey({
|
|
db,
|
|
env: AppEnv.Sandbox,
|
|
name: "Unit Test Key",
|
|
orgId: TEST_ORG_CONFIG.id,
|
|
prefix: "am_sk_test_",
|
|
meta: {
|
|
createdBy: "setup-test-script",
|
|
createdAt: new Date().toISOString(),
|
|
autogenerated: true,
|
|
},
|
|
});
|
|
console.log(
|
|
chalk.greenBright(
|
|
"✅ Generated fresh API key (UNIT_TEST_AUTUMN_SECRET_KEY unset)",
|
|
),
|
|
);
|
|
return generated;
|
|
}
|
|
|
|
export { TEST_ORG_CONFIG };
|
|
|
|
// Per-email: insert a member row if a user already exists, otherwise insert
|
|
// an invitation row. Both paths skip if a matching member/invitation already
|
|
// targets this org+email — safe to re-run. Note: better-auth does NOT auto-
|
|
// accept invitations on sign-in. Invitees must visit /accept?id=<inv_id> (or
|
|
// equivalent UI) after signing in to finish joining the org.
|
|
async function seedTeamInvites({ db }: { db: DrizzleCli }): Promise<void> {
|
|
const { generateId } = await import("@server/utils/genUtils.js");
|
|
|
|
// Ensure a synthetic inviter exists so invitation.inviter_id FK resolves.
|
|
await db
|
|
.insert(user)
|
|
.values({
|
|
id: TEST_INVITER_USER.id,
|
|
name: TEST_INVITER_USER.name,
|
|
email: TEST_INVITER_USER.email,
|
|
emailVerified: true,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
})
|
|
.onConflictDoNothing();
|
|
|
|
const existingUsers = await db
|
|
.select()
|
|
.from(user)
|
|
.where(inArray(user.email, TEAM_INVITE_EMAILS));
|
|
const userByEmail = new Map(existingUsers.map((u) => [u.email, u]));
|
|
|
|
const existingMembers = await db
|
|
.select()
|
|
.from(member)
|
|
.where(eq(member.organizationId, TEST_ORG_CONFIG.id));
|
|
const membershipUserIds = new Set(existingMembers.map((m) => m.userId));
|
|
|
|
const existingInvitesForOrg = await db
|
|
.select()
|
|
.from(invitation)
|
|
.where(
|
|
and(
|
|
eq(invitation.organizationId, TEST_ORG_CONFIG.id),
|
|
inArray(invitation.email, TEAM_INVITE_EMAILS),
|
|
),
|
|
);
|
|
const inviteEmails = new Set(existingInvitesForOrg.map((i) => i.email));
|
|
|
|
let membersCreated = 0;
|
|
let invitesCreated = 0;
|
|
const expiresAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
|
|
|
|
for (const email of TEAM_INVITE_EMAILS) {
|
|
const existingUser = userByEmail.get(email);
|
|
if (existingUser) {
|
|
if (membershipUserIds.has(existingUser.id)) continue;
|
|
await db.insert(member).values({
|
|
id: generateId("mem"),
|
|
organizationId: TEST_ORG_CONFIG.id,
|
|
userId: existingUser.id,
|
|
role: "owner",
|
|
createdAt: new Date(),
|
|
});
|
|
membersCreated++;
|
|
} else {
|
|
if (inviteEmails.has(email)) continue;
|
|
await db.insert(invitation).values({
|
|
id: generateId("inv"),
|
|
organizationId: TEST_ORG_CONFIG.id,
|
|
email,
|
|
role: "owner",
|
|
status: "pending",
|
|
createdAt: new Date(),
|
|
expiresAt,
|
|
inviterId: TEST_INVITER_USER.id,
|
|
});
|
|
invitesCreated++;
|
|
}
|
|
}
|
|
|
|
console.log(
|
|
chalk.greenBright(
|
|
`✅ Team seed: ${membersCreated} member(s) + ${invitesCreated} invitation(s) for ${TEAM_INVITE_EMAILS.length} email(s)`,
|
|
),
|
|
);
|
|
}
|