Move Send Invitation Email checkbox into modal footer, add tests

Place the checkbox inline with the submit button (left-aligned,
vertically centered) in both the embedded and standalone forms.
Add Vitest tests verifying the /user/new payload shape: default true,
false when unchecked, in both form variants, plus an initial-state
check for the modal.
This commit is contained in:
Yuneng Jiang 2026-04-15 12:24:41 -07:00
parent 3ce67bacad
commit fde7c1087a
No known key found for this signature in database
2 changed files with 150 additions and 16 deletions

View File

@ -354,4 +354,126 @@ describe("CreateUserButton", () => {
expect(mockOrganizationMemberAddCall).not.toHaveBeenCalled();
});
});
describe("send invitation email toggle", () => {
it("should send send_invite_email true by default in embedded mode", async () => {
const user = userEvent.setup();
mockUserCreateCall.mockResolvedValue({ data: { user_id: "default-on-user" } });
renderWithProviders(
<CreateUserButton {...defaultProps} possibleUIRoles={{ proxy_user: { ui_label: "User", description: "" } }} isEmbedded />,
);
await user.type(screen.getByLabelText(/user email/i), "default@example.com");
await user.click(screen.getByRole("combobox", { name: /user role/i }));
await user.click(screen.getByText("User"));
await user.click(screen.getByRole("button", { name: /create user/i }));
await waitFor(() => {
expect(mockUserCreateCall).toHaveBeenCalledWith("token", null, expect.objectContaining({
send_invite_email: true,
}));
});
});
it("should send send_invite_email false when the checkbox is unchecked in embedded mode", async () => {
const user = userEvent.setup();
mockUserCreateCall.mockResolvedValue({ data: { user_id: "unchecked-user" } });
renderWithProviders(
<CreateUserButton {...defaultProps} possibleUIRoles={{ proxy_user: { ui_label: "User", description: "" } }} isEmbedded />,
);
await user.type(screen.getByLabelText(/user email/i), "off@example.com");
await user.click(screen.getByRole("combobox", { name: /user role/i }));
await user.click(screen.getByText("User"));
await user.click(screen.getByRole("checkbox", { name: /send invitation email/i }));
await user.click(screen.getByRole("button", { name: /create user/i }));
await waitFor(() => {
expect(mockUserCreateCall).toHaveBeenCalledWith("token", null, expect.objectContaining({
send_invite_email: false,
}));
});
});
it("should send send_invite_email true by default in standalone mode", async () => {
const user = userEvent.setup();
mockUserCreateCall.mockResolvedValue({ data: { user_id: "standalone-default-user" } });
mockInvitationCreateCall.mockResolvedValue({
id: "inv-default",
user_id: "standalone-default-user",
has_user_setup_sso: false,
} as any);
renderWithProviders(
<CreateUserButton {...defaultProps} possibleUIRoles={{ proxy_user: { ui_label: "User", description: "" } }} />,
);
await waitFor(() => {
expect(screen.getByRole("button", { name: /\+ invite user/i })).toBeInTheDocument();
});
await user.click(screen.getByRole("button", { name: /\+ invite user/i }));
const dialog = screen.getByRole("dialog", { name: /invite user/i });
await user.type(within(dialog).getByLabelText(/user email/i), "standalone-default@example.com");
await user.click(within(dialog).getByRole("combobox", { name: /global proxy role/i }));
await user.click(screen.getByText("User"));
await user.click(within(dialog).getByRole("button", { name: /invite user/i }));
await waitFor(() => {
expect(mockUserCreateCall).toHaveBeenCalledWith("token", null, expect.objectContaining({
send_invite_email: true,
}));
});
});
it("should send send_invite_email false when the checkbox is unchecked in standalone mode", async () => {
const user = userEvent.setup();
mockUserCreateCall.mockResolvedValue({ data: { user_id: "standalone-off-user" } });
mockInvitationCreateCall.mockResolvedValue({
id: "inv-off",
user_id: "standalone-off-user",
has_user_setup_sso: false,
} as any);
renderWithProviders(
<CreateUserButton {...defaultProps} possibleUIRoles={{ proxy_user: { ui_label: "User", description: "" } }} />,
);
await waitFor(() => {
expect(screen.getByRole("button", { name: /\+ invite user/i })).toBeInTheDocument();
});
await user.click(screen.getByRole("button", { name: /\+ invite user/i }));
const dialog = screen.getByRole("dialog", { name: /invite user/i });
await user.type(within(dialog).getByLabelText(/user email/i), "standalone-off@example.com");
await user.click(within(dialog).getByRole("combobox", { name: /global proxy role/i }));
await user.click(screen.getByText("User"));
await user.click(within(dialog).getByRole("checkbox", { name: /send invitation email/i }));
await user.click(within(dialog).getByRole("button", { name: /invite user/i }));
await waitFor(() => {
expect(mockUserCreateCall).toHaveBeenCalledWith("token", null, expect.objectContaining({
send_invite_email: false,
}));
});
});
it("should keep the checkbox checked by default when the modal is opened in standalone mode", async () => {
const user = userEvent.setup();
renderWithProviders(
<CreateUserButton {...defaultProps} possibleUIRoles={{ proxy_user: { ui_label: "User", description: "" } }} />,
);
await waitFor(() => {
expect(screen.getByRole("button", { name: /\+ invite user/i })).toBeInTheDocument();
});
await user.click(screen.getByRole("button", { name: /\+ invite user/i }));
const dialog = screen.getByRole("dialog", { name: /invite user/i });
expect(within(dialog).getByRole("checkbox", { name: /send invitation email/i })).toBeChecked();
});
});
});

View File

@ -225,15 +225,21 @@ export const CreateUserButton: React.FC<CreateuserProps> = ({
<Input.TextArea rows={4} placeholder="Enter metadata as JSON" />
</Form.Item>
<Form.Item
name="send_invite_email"
valuePropName="checked"
wrapperCol={{ offset: 8, span: 16 }}
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginTop: "10px",
}}
>
<Checkbox>Send invitation email</Checkbox>
</Form.Item>
<div style={{ textAlign: "right", marginTop: "10px" }}>
<Form.Item
name="send_invite_email"
valuePropName="checked"
style={{ marginBottom: 0 }}
>
<Checkbox>Send invitation email</Checkbox>
</Form.Item>
<Button htmlType="submit">Create User</Button>
</div>
</Form>
@ -370,15 +376,21 @@ export const CreateUserButton: React.FC<CreateuserProps> = ({
</AccordionBody>
</Accordion>
<Form.Item
name="send_invite_email"
valuePropName="checked"
wrapperCol={{ offset: 8, span: 16 }}
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginTop: "10px",
}}
>
<Checkbox>Send invitation email</Checkbox>
</Form.Item>
<div style={{ textAlign: "right", marginTop: "10px" }}>
<Form.Item
name="send_invite_email"
valuePropName="checked"
style={{ marginBottom: 0 }}
>
<Checkbox>Send invitation email</Checkbox>
</Form.Item>
<Button type="primary" icon={<UserAddOutlined />} htmlType="submit">
Invite User
</Button>