@@ -34,6 +34,7 @@ import {
3434 patchSecurityConfiguration ,
3535 SecurityConfiguration ,
3636 SecurityValidationResponse ,
37+ testSecurityConfiguration ,
3738 validateSecurityConfiguration ,
3839} from '../../../rest/securityConfigAPI' ;
3940import { getAuthConfig } from '../../../utils/AuthProvider.util' ;
@@ -48,6 +49,39 @@ jest.mock('../../../utils/ToastUtils', () => ({
4849 showSuccessToast : jest . fn ( ) ,
4950} ) ) ;
5051
52+ jest . mock ( '@openmetadata/ui-core-components' , ( ) => ( {
53+ Accordion : ( { children } : { children : React . ReactNode } ) => (
54+ < div data-testid = "accordion" > { children } </ div >
55+ ) ,
56+ AccordionItem : ( {
57+ children,
58+ id,
59+ } : {
60+ children : React . ReactNode ;
61+ id ?: string ;
62+ } ) => (
63+ < div data-id = { id } data-testid = "accordion-item" >
64+ { children }
65+ </ div >
66+ ) ,
67+ AccordionHeader : ( {
68+ children,
69+ ...rest
70+ } : React . PropsWithChildren < Record < string , unknown > > ) => (
71+ < button data-testid = "accordion-header" { ...rest } >
72+ { children }
73+ </ button >
74+ ) ,
75+ AccordionPanel : ( {
76+ children,
77+ ...rest
78+ } : React . PropsWithChildren < Record < string , unknown > > ) => (
79+ < div data-testid = "accordion-panel" { ...rest } >
80+ { children }
81+ </ div >
82+ ) ,
83+ } ) ) ;
84+
5185// Mock SSOUtils - use actual implementations where needed
5286jest . mock ( '../../../utils/SSOUtils' , ( ) => {
5387 const actual = jest . requireActual ( '../../../utils/SSOUtils' ) ;
@@ -205,6 +239,10 @@ const mockGetSecurityConfiguration =
205239 getSecurityConfiguration as jest . MockedFunction <
206240 typeof getSecurityConfiguration
207241 > ;
242+ const mockTestSecurityConfiguration =
243+ testSecurityConfiguration as jest . MockedFunction <
244+ typeof testSecurityConfiguration
245+ > ;
208246
209247const mockFetchAuthenticationConfig =
210248 fetchAuthenticationConfig as jest . MockedFunction <
@@ -1955,6 +1993,186 @@ describe('SSOConfigurationForm', () => {
19551993 } ) ;
19561994 } ) ;
19571995
1996+ describe ( 'Provider-specific Display Blocks' , ( ) => {
1997+ beforeEach ( ( ) => {
1998+ mockGetSecurityConfiguration . mockRejectedValue ( new Error ( 'No config' ) ) ;
1999+ } ) ;
2000+
2001+ it ( 'should render OIDC callback URL display for Google provider' , async ( ) => {
2002+ renderComponent ( { selectedProvider : AuthProvider . Google } ) ;
2003+
2004+ await waitFor ( ( ) => {
2005+ expect (
2006+ screen . getByTestId ( 'oidc-callback-url-display' )
2007+ ) . toBeInTheDocument ( ) ;
2008+ } ) ;
2009+
2010+ expect ( screen . getByTestId ( 'oidc-callback-url' ) ) . toBeInTheDocument ( ) ;
2011+ expect ( screen . getByTestId ( 'oidc-callback-url-copy' ) ) . toBeInTheDocument ( ) ;
2012+ } ) ;
2013+
2014+ it ( 'should render SAML ACS info banner with ACS URL and SP Entity ID' , async ( ) => {
2015+ renderComponent ( { selectedProvider : AuthProvider . Saml } ) ;
2016+
2017+ await waitFor ( ( ) => {
2018+ expect ( screen . getByTestId ( 'saml-acs-info-banner' ) ) . toBeInTheDocument ( ) ;
2019+ } ) ;
2020+
2021+ expect ( screen . getByTestId ( 'saml-acs-url' ) ) . toBeInTheDocument ( ) ;
2022+ expect ( screen . getByTestId ( 'saml-sp-entity-id' ) ) . toBeInTheDocument ( ) ;
2023+ } ) ;
2024+
2025+ it ( 'should not render OIDC callback display for SAML provider' , async ( ) => {
2026+ renderComponent ( { selectedProvider : AuthProvider . Saml } ) ;
2027+
2028+ await waitFor ( ( ) => {
2029+ expect ( screen . getByTestId ( 'saml-acs-info-banner' ) ) . toBeInTheDocument ( ) ;
2030+ } ) ;
2031+
2032+ expect (
2033+ screen . queryByTestId ( 'oidc-callback-url-display' )
2034+ ) . not . toBeInTheDocument ( ) ;
2035+ } ) ;
2036+
2037+ it ( 'should not render SAML banner for OIDC providers' , async ( ) => {
2038+ renderComponent ( { selectedProvider : AuthProvider . Okta } ) ;
2039+
2040+ await waitFor ( ( ) => {
2041+ expect (
2042+ screen . getByTestId ( 'oidc-callback-url-display' )
2043+ ) . toBeInTheDocument ( ) ;
2044+ } ) ;
2045+
2046+ expect (
2047+ screen . queryByTestId ( 'saml-acs-info-banner' )
2048+ ) . not . toBeInTheDocument ( ) ;
2049+ } ) ;
2050+
2051+ it ( 'should not render OIDC callback display for LDAP provider' , async ( ) => {
2052+ renderComponent ( { selectedProvider : AuthProvider . LDAP } ) ;
2053+
2054+ await waitFor ( ( ) => {
2055+ expect (
2056+ screen . getByTestId ( 'sso-configuration-form-card' )
2057+ ) . toBeInTheDocument ( ) ;
2058+ } ) ;
2059+
2060+ expect (
2061+ screen . queryByTestId ( 'oidc-callback-url-display' )
2062+ ) . not . toBeInTheDocument ( ) ;
2063+ expect (
2064+ screen . queryByTestId ( 'saml-acs-info-banner' )
2065+ ) . not . toBeInTheDocument ( ) ;
2066+ } ) ;
2067+ } ) ;
2068+
2069+ describe ( 'Advanced Fields Accordion' , ( ) => {
2070+ beforeEach ( ( ) => {
2071+ mockGetSecurityConfiguration . mockRejectedValue ( new Error ( 'No config' ) ) ;
2072+ } ) ;
2073+
2074+ it ( 'should render exactly one top-level Advanced Fields accordion when a provider is selected' , async ( ) => {
2075+ renderComponent ( { selectedProvider : AuthProvider . Google } ) ;
2076+
2077+ await waitFor ( ( ) => {
2078+ expect (
2079+ screen . getByTestId ( 'sso-advanced-fields-toggle' )
2080+ ) . toBeInTheDocument ( ) ;
2081+ } ) ;
2082+
2083+ expect (
2084+ screen . getAllByTestId ( 'sso-advanced-fields-toggle' )
2085+ ) . toHaveLength ( 1 ) ;
2086+ expect (
2087+ screen . getByTestId ( 'sso-advanced-fields-panel' )
2088+ ) . toBeInTheDocument ( ) ;
2089+ } ) ;
2090+
2091+ it ( 'should render the Advanced Fields accordion for SAML provider' , async ( ) => {
2092+ renderComponent ( { selectedProvider : AuthProvider . Saml } ) ;
2093+
2094+ await waitFor ( ( ) => {
2095+ expect (
2096+ screen . getByTestId ( 'sso-advanced-fields-toggle' )
2097+ ) . toBeInTheDocument ( ) ;
2098+ } ) ;
2099+ } ) ;
2100+
2101+ it ( 'should render the Advanced Fields accordion for LDAP provider' , async ( ) => {
2102+ renderComponent ( { selectedProvider : AuthProvider . LDAP } ) ;
2103+
2104+ await waitFor ( ( ) => {
2105+ expect (
2106+ screen . getByTestId ( 'sso-advanced-fields-toggle' )
2107+ ) . toBeInTheDocument ( ) ;
2108+ } ) ;
2109+ } ) ;
2110+ } ) ;
2111+
2112+ describe ( 'Test Login Flow' , ( ) => {
2113+ const mockSetCurrentUser = jest . fn ( ) ;
2114+
2115+ beforeEach ( ( ) => {
2116+ mockGetSecurityConfiguration . mockRejectedValue ( new Error ( 'No config' ) ) ;
2117+ mockUseApplicationStore . mockReturnValue ( {
2118+ setIsAuthenticated : mockSetIsAuthenticated ,
2119+ setAuthConfig : mockSetAuthConfig ,
2120+ setAuthorizerConfig : mockSetAuthorizerConfig ,
2121+ setCurrentUser : mockSetCurrentUser ,
2122+ currentUser : { email : 'admin@example.com' } ,
2123+ } as unknown as ApplicationStore ) ;
2124+ } ) ;
2125+
2126+ it ( 'should render Test Login button when a provider is selected' , async ( ) => {
2127+ renderComponent ( { selectedProvider : AuthProvider . Google } ) ;
2128+
2129+ await waitFor ( ( ) => {
2130+ expect ( screen . getByTestId ( 'test-login-button' ) ) . toBeInTheDocument ( ) ;
2131+ } ) ;
2132+ } ) ;
2133+
2134+ it ( 'should auto-fill adminPrincipals and principalDomain on success' , async ( ) => {
2135+ mockTestSecurityConfiguration . mockResolvedValue (
2136+ createAxiosResponse ( {
2137+ component : 'authentication' ,
2138+ status : VALIDATION_STATUS . SUCCESS ,
2139+ } )
2140+ ) ;
2141+
2142+ renderComponent ( { selectedProvider : AuthProvider . Google } ) ;
2143+
2144+ await waitFor ( ( ) => {
2145+ expect ( screen . getByTestId ( 'test-login-button' ) ) . toBeInTheDocument ( ) ;
2146+ } ) ;
2147+
2148+ fireEvent . click ( screen . getByTestId ( 'test-login-button' ) ) ;
2149+
2150+ await waitFor ( ( ) => {
2151+ expect ( mockTestSecurityConfiguration ) . toHaveBeenCalled ( ) ;
2152+ } ) ;
2153+ } ) ;
2154+
2155+ it ( 'should show error toast when test login fails' , async ( ) => {
2156+ const axiosError = {
2157+ response : { data : { errors : [ ] } } ,
2158+ } as unknown as AxiosError ;
2159+ mockTestSecurityConfiguration . mockRejectedValue ( axiosError ) ;
2160+
2161+ renderComponent ( { selectedProvider : AuthProvider . Google } ) ;
2162+
2163+ await waitFor ( ( ) => {
2164+ expect ( screen . getByTestId ( 'test-login-button' ) ) . toBeInTheDocument ( ) ;
2165+ } ) ;
2166+
2167+ fireEvent . click ( screen . getByTestId ( 'test-login-button' ) ) ;
2168+
2169+ await waitFor ( ( ) => {
2170+ expect ( mockTestSecurityConfiguration ) . toHaveBeenCalled ( ) ;
2171+ expect ( mockShowErrorToast ) . toHaveBeenCalled ( ) ;
2172+ } ) ;
2173+ } ) ;
2174+ } ) ;
2175+
19582176 describe ( 'Extract Field Name Utility' , ( ) => {
19592177 it ( 'should handle field name extraction from field IDs' , async ( ) => {
19602178 mockGetSecurityConfiguration . mockResolvedValue (
0 commit comments