From e49babb9e72811c719e1a334cdcc3a3b09425a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Pe=C3=B1a?= Date: Thu, 30 Jul 2026 11:05:24 +0200 Subject: [PATCH] fix(ui): stabilize SAML ACS URL field (#12236) --- ui/changelog.d/saml-acs-url-field.fixed.md | 1 + .../saml/saml-config-form.test.tsx | 84 +++++++++++++++++++ .../integrations/saml/saml-config-form.tsx | 20 ++--- 3 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 ui/changelog.d/saml-acs-url-field.fixed.md create mode 100644 ui/components/integrations/saml/saml-config-form.test.tsx diff --git a/ui/changelog.d/saml-acs-url-field.fixed.md b/ui/changelog.d/saml-acs-url-field.fixed.md new file mode 100644 index 0000000000..4b68c0319a --- /dev/null +++ b/ui/changelog.d/saml-acs-url-field.fixed.md @@ -0,0 +1 @@ +SAML ACS URL field remains visible while generating the callback URL from the email domain diff --git a/ui/components/integrations/saml/saml-config-form.test.tsx b/ui/components/integrations/saml/saml-config-form.test.tsx new file mode 100644 index 0000000000..afb1972573 --- /dev/null +++ b/ui/components/integrations/saml/saml-config-form.test.tsx @@ -0,0 +1,84 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { renderToString } from "react-dom/server"; +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; + +import { + RUNTIME_CONFIG_SCRIPT_ID, + type RuntimePublicConfig, +} from "@/lib/runtime-config.shared"; + +import { SamlConfigForm } from "./saml-config-form"; + +vi.mock("@/actions/integrations", () => ({ + createSamlConfig: vi.fn(), + updateSamlConfig: vi.fn(), +})); + +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), + useToast: () => ({ toast: vi.fn() }), +})); + +const runtimeConfig: RuntimePublicConfig = { + sentryDsn: null, + sentryEnvironment: null, + googleTagManagerId: null, + apiBaseUrl: "https://api.example.com/api/v1", + apiDocsUrl: null, + posthogEnabled: false, + posthogKey: null, + posthogHost: null, + reoDevClientId: null, + cloudEnabled: false, + cloudBillingEnabled: false, + stripePublishableKey: null, + stripePublishableKeyV2: null, +}; + +beforeAll(() => { + const runtimeConfigScript = document.createElement("script"); + runtimeConfigScript.id = RUNTIME_CONFIG_SCRIPT_ID; + runtimeConfigScript.type = "application/json"; + runtimeConfigScript.textContent = JSON.stringify(runtimeConfig); + document.head.append(runtimeConfigScript); +}); + +afterAll(() => { + document.getElementById(RUNTIME_CONFIG_SCRIPT_ID)?.remove(); +}); + +describe("SamlConfigForm", () => { + it("keeps the ACS field container while generating the URL", async () => { + // Given + const serverHtml = renderToString(); + const user = userEvent.setup(); + const container = document.body.appendChild(document.createElement("div")); + container.innerHTML = serverHtml; + render(, { + container, + hydrate: true, + }); + + const acsGuidance = screen.getByText( + "Enter your email domain above to generate the ACS URL.", + ); + const acsField = acsGuidance.parentElement; + + expect(acsField).toHaveClass("h-10", "w-full"); + expect( + screen.queryByRole("button", { name: "Copy ACS URL" }), + ).not.toBeInTheDocument(); + + // When + await user.type(screen.getByLabelText("Email Domain*"), "example.com"); + + // Then + const acsUrl = screen.getByText( + "https://api.example.com/api/v1/accounts/saml/example.com/acs/", + ); + + expect(acsUrl.parentElement).toBe(acsField); + expect(screen.getByRole("button", { name: "Copy ACS URL" })).toBeVisible(); + }); +}); diff --git a/ui/components/integrations/saml/saml-config-form.tsx b/ui/components/integrations/saml/saml-config-form.tsx index 82d5fccfd5..2dbf1a2ab2 100644 --- a/ui/components/integrations/saml/saml-config-form.tsx +++ b/ui/components/integrations/saml/saml-config-form.tsx @@ -316,17 +316,15 @@ export const SamlConfigForm = ({ ACS URL: - {acsUrl ? ( - - ) : ( -

- Enter your email domain above to generate the ACS URL. -

- )} +