@@ -261,6 +261,132 @@ class MfaChallengeScreenTest {
261261 .assertIsEnabled()
262262 }
263263
264+ @Test
265+ fun `default UI shows VerificationCodeInputField for SMS factor` () {
266+ `when `(mockPhoneHint.factorId).thenReturn(" phone" )
267+ `when `(mockPhoneHint.phoneNumber).thenReturn(" +1234567890" )
268+ `when `(mockResolver.hints).thenReturn(listOf<MultiFactorInfo >(mockPhoneHint))
269+
270+ var capturedState: MfaChallengeContentState ? = null
271+
272+ composeTestRule.setContent {
273+ TestMfaChallengeScreen (
274+ resolver = mockResolver,
275+ onStateChange = { capturedState = it }
276+ )
277+ }
278+
279+ composeTestRule.waitForIdle()
280+
281+ // Verify SMS factor type is detected
282+ assertThat(capturedState?.factorType).isEqualTo(MfaFactor .Sms )
283+
284+ // Verify masked phone number is set correctly
285+ // +1234567890 is 11 chars: +1 (2) + 6 masked + 890 (3) = +1••••••890
286+ assertThat(capturedState?.maskedPhoneNumber).isEqualTo(" +1••••••890" )
287+
288+ // Verify that the verification code input works (via the state object that would be used by VerificationCodeInputField)
289+ assertThat(capturedState?.verificationCode).isEmpty()
290+ assertThat(capturedState?.isValid).isFalse()
291+ }
292+
293+ @Test
294+ fun `default UI shows VerificationCodeInputField for TOTP factor` () {
295+ `when `(mockTotpHint.factorId).thenReturn(" totp" )
296+ `when `(mockResolver.hints).thenReturn(listOf<MultiFactorInfo >(mockTotpHint))
297+
298+ composeTestRule.setContent {
299+ MfaChallengeScreen (
300+ resolver = mockResolver,
301+ auth = authUI.auth,
302+ onSuccess = {},
303+ onCancel = {},
304+ onError = {}
305+ )
306+ }
307+
308+ composeTestRule.waitForIdle()
309+
310+ // Verify the default UI is displayed with TOTP-specific title
311+ composeTestRule.onNodeWithText(stringProvider.mfaStepVerifyFactorTitle)
312+ .assertIsDisplayed()
313+
314+ // Verify VerificationCodeInputField is present
315+ composeTestRule.onNodeWithText(stringProvider.verifyAction)
316+ .assertIsDisplayed()
317+ .assertIsNotEnabled() // Should be disabled until code is entered
318+ }
319+
320+ @Test
321+ fun `default UI shows resend button for SMS factor` () {
322+ // Test SMS factor
323+ `when `(mockPhoneHint.factorId).thenReturn(" phone" )
324+ `when `(mockPhoneHint.phoneNumber).thenReturn(" +1234567890" )
325+ `when `(mockResolver.hints).thenReturn(listOf<MultiFactorInfo >(mockPhoneHint))
326+
327+ composeTestRule.setContent {
328+ MfaChallengeScreen (
329+ resolver = mockResolver,
330+ auth = authUI.auth,
331+ onSuccess = {},
332+ onCancel = {},
333+ onError = {}
334+ )
335+ }
336+
337+ composeTestRule.waitForIdle()
338+
339+ // Should show resend button for SMS
340+ composeTestRule.onNodeWithText(stringProvider.resendCode, substring = true )
341+ .assertIsDisplayed()
342+ }
343+
344+ @Test
345+ fun `default UI does not show resend button for TOTP factor` () {
346+ // Test TOTP factor
347+ `when `(mockTotpHint.factorId).thenReturn(" totp" )
348+ `when `(mockResolver.hints).thenReturn(listOf<MultiFactorInfo >(mockTotpHint))
349+
350+ composeTestRule.setContent {
351+ MfaChallengeScreen (
352+ resolver = mockResolver,
353+ auth = authUI.auth,
354+ onSuccess = {},
355+ onCancel = {},
356+ onError = {}
357+ )
358+ }
359+
360+ composeTestRule.waitForIdle()
361+
362+ // Should NOT show resend button for TOTP
363+ composeTestRule.onNodeWithText(stringProvider.resendCode, substring = true )
364+ .assertDoesNotExist()
365+ }
366+
367+ @Test
368+ fun `default UI displays masked phone number for SMS factor` () {
369+ `when `(mockPhoneHint.factorId).thenReturn(" phone" )
370+ `when `(mockPhoneHint.phoneNumber).thenReturn(" +1234567890" )
371+ `when `(mockResolver.hints).thenReturn(listOf<MultiFactorInfo >(mockPhoneHint))
372+
373+ var capturedState: MfaChallengeContentState ? = null
374+
375+ composeTestRule.setContent {
376+ TestMfaChallengeScreen (
377+ resolver = mockResolver,
378+ onStateChange = { capturedState = it }
379+ )
380+ }
381+
382+ composeTestRule.waitForIdle()
383+
384+ // Verify masked phone number is set correctly in the state
385+ // +1234567890 is 11 chars: +1 (2) + 6 masked + 890 (3) = +1••••••890
386+ assertThat(capturedState?.maskedPhoneNumber).isEqualTo(" +1••••••890" )
387+ assertThat(capturedState?.factorType).isEqualTo(MfaFactor .Sms )
388+ }
389+
264390 @Composable
265391 private fun TestMfaChallengeScreen (
266392 resolver : MultiFactorResolver ,
0 commit comments