🐛 Invitations to a team can be sent to existing members without displaying any error (#10489)

* 🐛 Fix team invitations can be sent to existing members without displaying any error

*  Add tests
This commit is contained in:
Luis de Dios 2026-06-30 15:39:59 +02:00 committed by GitHub
parent 8823f7ac4d
commit 28afe223f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 94 additions and 2 deletions

View File

@ -0,0 +1 @@
{"~:total": 2}

View File

@ -0,0 +1,86 @@
import { test, expect } from "@playwright/test";
import DashboardPage from "../pages/DashboardPage";
test.beforeEach(async ({ page }) => {
await DashboardPage.init(page);
});
test("Open invite members modal from invitations section", async ({
page,
}) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamInvitationsEmpty();
await dashboardPage.goToSecondTeamInvitationsSection();
await expect(page.getByRole("button", { name: "Invite people" })).toBeVisible();
await page.getByRole("button", { name: "Invite people" }).click();
await expect(page.getByText("Invite members to the team")).toBeVisible();
});
test("Invite a new member by email", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamInvitationsEmpty();
await DashboardPage.mockRPC(
page,
"create-team-invitations",
"dashboard/create-team-invitations.json",
{ method: "POST" },
);
await dashboardPage.goToSecondTeamInvitationsSection();
await page.getByRole("button", { name: "Invite people" }).click();
await expect(page.getByText("Invite members to the team")).toBeVisible();
const emailInput = page.getByRole("textbox", { name: "Emails, comma separated" });
await emailInput.fill("newmember@example.com");
await emailInput.press("Enter");
await page.getByRole("button", { name: "Send invitation" }).click();
await expect(page.getByText("Invitation sent successfully")).toBeVisible();
await expect(
page.getByText("Invite members to the team"),
).not.toBeVisible();
});
test("Show warning when inviting an existing member", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamInvitationsEmpty();
await dashboardPage.goToSecondTeamInvitationsSection();
await page.getByRole("button", { name: "Invite people" }).click();
await expect(page.getByText("Invite members to the team")).toBeVisible();
const emailInput = page.getByRole("textbox", { name: "Emails, comma separated" });
await emailInput.fill("foo@example.com");
await emailInput.press("Enter");
await expect(
page.getByText(
"Some members are already on the team. We'll invite the rest.",
),
).toBeVisible();
});
test("Disable send button when all entered emails are existing members", async ({
page,
}) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamInvitationsEmpty();
await dashboardPage.goToSecondTeamInvitationsSection();
await page.getByRole("button", { name: "Invite people" }).click();
await expect(page.getByText("Invite members to the team")).toBeVisible();
const emailInput = page.getByRole("textbox", { name: "Emails, comma separated" });
await emailInput.fill("foo@example.com");
await emailInput.press("Enter");
const sendButton = page.getByRole("button", { name: "Send invitation" });
await expect(sendButton).toBeDisabled();
});

View File

@ -459,7 +459,7 @@
(into [] (distinct) (conj coll item)))
(mf/defc multi-input
[{:keys [form label class name trim valid-item-fn caution-item-fn on-submit] :as props}]
[{:keys [form label class trim valid-item-fn caution-item-fn on-submit] :as props}]
(let [form (or form (mf/use-ctx form-ctx))
input-name (get props :name)
touched? (get-in @form [:touched input-name])
@ -610,6 +610,7 @@
[:div {:class klass}
[:input {:id (name input-name)
:name (name input-name)
:class in-klass
:type "text"
:auto-focus auto-focus?

View File

@ -168,10 +168,13 @@
::mf/register-as :invite-members
::mf/props :obj}
[{:keys [team origin invite-email]}]
(let [members (get team :members)
(let [teams (mf/deref refs/teams)
perms (get team :permissions)
team-id (get team :id)
members (get-in teams [team-id :members])
roles (mf/with-memo [perms]
(get-available-roles perms))
@ -824,6 +827,7 @@
[:div {:class (stl/css :empty-invitations-buttons)}
[:a
{:class (stl/css :btn-empty-invitations)
:role "button"
:on-click on-invite-member
:data-testid "invite-member"}
(tr "dashboard.invite-profile")]]