diff --git a/ui/litellm-dashboard/src/components/team/EditMembership.integration.test.tsx b/ui/litellm-dashboard/src/components/team/EditMembership.integration.test.tsx index d542b19f718..45800a18ff8 100644 --- a/ui/litellm-dashboard/src/components/team/EditMembership.integration.test.tsx +++ b/ui/litellm-dashboard/src/components/team/EditMembership.integration.test.tsx @@ -227,15 +227,40 @@ describe("EditMembership submit payload", () => { expect(submitted().role).toBe("admin"); }); - it("blocks submission when the email is not an address", async () => { - renderEdit(orgMemberConfig, { user_id: "u1", user_email: "a@b.com", role: "user" }); + it.each(["john_example.com#EXT#@tenant.onmicrosoft.com", "john#tag@example.com"])( + "saves budget and limit edits for %s", + async (user_email) => { + renderEdit(teamMemberConfig, { ...cappedMember, user_email }); - fireEvent.change(screen.getByLabelText("Email"), { target: { value: "not-an-email" } }); - save(); + fireEvent.change(screen.getByLabelText("Team Member Budget (USD)"), { target: { value: "25" } }); + fireEvent.change(screen.getByLabelText("Team Member TPM Limit"), { target: { value: "100" } }); + fireEvent.change(screen.getByLabelText("Team Member RPM Limit"), { target: { value: "10" } }); + save(); - expect(await screen.findByText("Please enter a valid email!")).toBeInTheDocument(); - expect(onSubmit).not.toHaveBeenCalled(); - }); + await waitFor(() => expect(onSubmit).toHaveBeenCalledOnce()); + const expectedChanges = { + user_id: "u1", + user_email, + max_budget_in_team: "25", + tpm_limit: "100", + rpm_limit: "10", + }; + expect(submitted()).toEqual(expect.objectContaining(expectedChanges)); + }, + ); + + it.each(["not-an-email", "john@@example.com", "john tag@example.com", "john@example#com"])( + "blocks submission for an invalid address: %s", + async (user_email) => { + renderEdit(orgMemberConfig, { user_id: "u1", user_email: "a@b.com", role: "user" }); + + fireEvent.change(screen.getByLabelText("Email"), { target: { value: user_email } }); + save(); + + expect(await screen.findByText("Please enter a valid email!")).toBeInTheDocument(); + expect(onSubmit).not.toHaveBeenCalled(); + }, + ); it("blocks submission when no role is selected", async () => { renderEdit(orgMemberConfig, { user_id: "u1", user_email: "a@b.com", role: "" }); diff --git a/ui/litellm-dashboard/src/components/team/EditMembership.tsx b/ui/litellm-dashboard/src/components/team/EditMembership.tsx index 3e6cb7d1284..4aaeb42da98 100644 --- a/ui/litellm-dashboard/src/components/team/EditMembership.tsx +++ b/ui/litellm-dashboard/src/components/team/EditMembership.tsx @@ -48,7 +48,8 @@ interface MemberModalProps { const ROLE_REQUIRED_MESSAGE = "Please select a role!"; -const isEmailish = (value: string): boolean => value === "" || z.email().safeParse(value).success; +const isEmailish = (value: string): boolean => + value === "" || z.email({ pattern: z.regexes.html5Email }).safeParse(value).success; const memberFieldSchema = z.union([z.string(), z.number(), z.null(), z.array(z.string())]).optional();