Skip to content

Commit 2000fa8

Browse files
committed
updates
1 parent 128ef88 commit 2000fa8

2 files changed

Lines changed: 200 additions & 1 deletion

File tree

auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@ fun FirebaseAuthScreen(
111111
authUI: FirebaseAuthUI = FirebaseAuthUI.getInstance(),
112112
emailLink: String? = null,
113113
mfaConfiguration: MfaConfiguration = MfaConfiguration(),
114-
authenticatedContent: (@Composable (state: AuthState, uiContext: AuthSuccessUiContext) -> Unit)? = null,
115114
customMethodPickerLayout: (@Composable (List<AuthProvider>, (AuthProvider) -> Unit) -> Unit)? = null,
116115
emailContent: (@Composable (EmailAuthContentState) -> Unit)? = null,
117116
phoneContent: (@Composable (PhoneAuthContentState) -> Unit)? = null,
118117
mfaEnrollmentContent: (@Composable (MfaEnrollmentContentState) -> Unit)? = null,
119118
mfaChallengeContent: (@Composable (MfaChallengeContentState) -> Unit)? = null,
119+
authenticatedContent: (@Composable (state: AuthState, uiContext: AuthSuccessUiContext) -> Unit)? = null,
120120
) {
121121
// Set FirebaseUI version
122122
LaunchedEffect(authUI.auth) {
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
* Copyright 2025 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
* express or implied. See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
package com.firebase.ui.auth.ui.screens
16+
17+
import android.content.Context
18+
import androidx.compose.material3.Text
19+
import androidx.compose.ui.Modifier
20+
import androidx.compose.ui.platform.testTag
21+
import androidx.compose.ui.test.assertIsDisplayed
22+
import androidx.compose.ui.test.junit4.createComposeRule
23+
import androidx.compose.ui.test.onNodeWithTag
24+
import androidx.test.core.app.ApplicationProvider
25+
import com.firebase.ui.auth.FirebaseAuthUI
26+
import com.firebase.ui.auth.configuration.authUIConfiguration
27+
import com.firebase.ui.auth.configuration.auth_provider.AuthProvider
28+
import com.google.firebase.FirebaseApp
29+
import com.google.firebase.FirebaseOptions
30+
import org.junit.After
31+
import org.junit.Before
32+
import org.junit.Rule
33+
import org.junit.Test
34+
import org.junit.runner.RunWith
35+
import org.robolectric.RobolectricTestRunner
36+
import org.robolectric.annotation.Config
37+
38+
/**
39+
* Tests that [FirebaseAuthScreen] correctly forwards each customization slot to the
40+
* appropriate sub-screen.
41+
*
42+
* These tests cover the fix for the API gap where slots such as [customMethodPickerLayout],
43+
* [emailContent], and [phoneContent] were accepted by sub-screens but never reachable through
44+
* the high-level [FirebaseAuthScreen] composable.
45+
*/
46+
@RunWith(RobolectricTestRunner::class)
47+
@Config(manifest = Config.NONE, sdk = [34])
48+
class FirebaseAuthScreenSlotsTest {
49+
50+
@get:Rule
51+
val composeTestRule = createComposeRule()
52+
53+
private lateinit var context: Context
54+
private lateinit var authUI: FirebaseAuthUI
55+
56+
@Before
57+
fun setUp() {
58+
context = ApplicationProvider.getApplicationContext()
59+
FirebaseAuthUI.clearInstanceCache()
60+
FirebaseApp.getApps(context).forEach { it.delete() }
61+
FirebaseApp.initializeApp(
62+
context,
63+
FirebaseOptions.Builder()
64+
.setApiKey("fake-api-key")
65+
.setApplicationId("fake-app-id")
66+
.setProjectId("fake-project-id")
67+
.build()
68+
)
69+
authUI = FirebaseAuthUI.getInstance()
70+
}
71+
72+
@After
73+
fun tearDown() {
74+
FirebaseAuthUI.clearInstanceCache()
75+
FirebaseApp.getApps(context).forEach {
76+
try { it.delete() } catch (_: Exception) {}
77+
}
78+
}
79+
80+
// =============================================================================================
81+
// customMethodPickerLayout slot tests
82+
// =============================================================================================
83+
84+
@Test
85+
fun `customMethodPickerLayout is rendered when provided`() {
86+
val configuration = authUIConfiguration {
87+
context = this@FirebaseAuthScreenSlotsTest.context
88+
providers {
89+
provider(AuthProvider.Email(emailLinkActionCodeSettings = null, passwordValidationRules = emptyList()))
90+
provider(AuthProvider.Phone(defaultNumber = null, defaultCountryCode = null, allowedCountries = null))
91+
}
92+
}
93+
94+
composeTestRule.setContent {
95+
FirebaseAuthScreen(
96+
configuration = configuration,
97+
authUI = authUI,
98+
onSignInSuccess = {},
99+
onSignInFailure = {},
100+
onSignInCancelled = {},
101+
customMethodPickerLayout = { _, _ ->
102+
Text(
103+
text = "Custom Picker",
104+
modifier = Modifier.testTag("custom_method_picker")
105+
)
106+
}
107+
)
108+
}
109+
110+
composeTestRule.onNodeWithTag("custom_method_picker").assertIsDisplayed()
111+
}
112+
113+
@Test
114+
fun `default method picker renders when customMethodPickerLayout is null`() {
115+
val configuration = authUIConfiguration {
116+
context = this@FirebaseAuthScreenSlotsTest.context
117+
providers {
118+
provider(AuthProvider.Email(emailLinkActionCodeSettings = null, passwordValidationRules = emptyList()))
119+
provider(AuthProvider.Phone(defaultNumber = null, defaultCountryCode = null, allowedCountries = null))
120+
}
121+
}
122+
123+
composeTestRule.setContent {
124+
FirebaseAuthScreen(
125+
configuration = configuration,
126+
authUI = authUI,
127+
onSignInSuccess = {},
128+
onSignInFailure = {},
129+
onSignInCancelled = {}
130+
)
131+
}
132+
133+
composeTestRule.onNodeWithTag("AuthMethodPicker LazyColumn").assertIsDisplayed()
134+
}
135+
136+
// =============================================================================================
137+
// emailContent slot tests
138+
// =============================================================================================
139+
140+
@Test
141+
fun `emailContent slot is rendered when provided`() {
142+
val configuration = authUIConfiguration {
143+
context = this@FirebaseAuthScreenSlotsTest.context
144+
providers {
145+
provider(AuthProvider.Email(emailLinkActionCodeSettings = null, passwordValidationRules = emptyList()))
146+
}
147+
}
148+
149+
composeTestRule.setContent {
150+
FirebaseAuthScreen(
151+
configuration = configuration,
152+
authUI = authUI,
153+
onSignInSuccess = {},
154+
onSignInFailure = {},
155+
onSignInCancelled = {},
156+
emailContent = { _ ->
157+
Text(
158+
text = "Custom Email UI",
159+
modifier = Modifier.testTag("custom_email_slot")
160+
)
161+
}
162+
)
163+
}
164+
165+
composeTestRule.onNodeWithTag("custom_email_slot").assertIsDisplayed()
166+
}
167+
168+
// =============================================================================================
169+
// phoneContent slot tests
170+
// =============================================================================================
171+
172+
@Test
173+
fun `phoneContent slot is rendered when provided`() {
174+
val configuration = authUIConfiguration {
175+
context = this@FirebaseAuthScreenSlotsTest.context
176+
providers {
177+
provider(AuthProvider.Phone(defaultNumber = null, defaultCountryCode = null, allowedCountries = null))
178+
}
179+
}
180+
181+
composeTestRule.setContent {
182+
FirebaseAuthScreen(
183+
configuration = configuration,
184+
authUI = authUI,
185+
onSignInSuccess = {},
186+
onSignInFailure = {},
187+
onSignInCancelled = {},
188+
phoneContent = { _ ->
189+
Text(
190+
text = "Custom Phone UI",
191+
modifier = Modifier.testTag("custom_phone_slot")
192+
)
193+
}
194+
)
195+
}
196+
197+
composeTestRule.onNodeWithTag("custom_phone_slot").assertIsDisplayed()
198+
}
199+
}

0 commit comments

Comments
 (0)