Skip to content

Commit

Permalink
test: implement UI tests for SignInScreen and SignUpScreen
Browse files Browse the repository at this point in the history
  • Loading branch information
francelu committed Oct 13, 2024
1 parent 3219c6f commit b27beb7
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 109 deletions.
Original file line number Diff line number Diff line change
@@ -1,133 +1,116 @@
package com.android.periodpals.ui.authentication

import androidx.activity.compose.setContent
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.matcher.IntentMatchers.toPackage
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.periodpals.MainActivity
import com.kaspersky.kaspresso.testcases.api.testcase.TestCase
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class SignInTest : TestCase() {
@get:Rule val composeTestRule = createAndroidComposeRule<MainActivity>()
class SignInScreenTest {

@Before
fun setUp() {
Intents.init()
}

@After
fun tearDown() {
Intents.release()
}
@get:Rule val composeTestRule = createComposeRule()

@Test
fun checkComponentsAreDisplayed() {
// TODO: Check when logo is imported and designed
// composeTestRule.onNodeWithTag("loginAppLogo").assertIsDisplayed()
fun signInScreen_displaysCorrectUI() {
// Set the content to the SignInScreen
composeTestRule.setContent { SignInScreen() }

// Check if the welcome text is displayed
composeTestRule.onNodeWithTag("signInScreen").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInBackground").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInTitle").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInTitle").assertTextEquals("Welcome to PeriodPals")
composeTestRule.onNodeWithTag("signInInstruction").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInInstruction").assertTextEquals("Sign in to your account")
composeTestRule.onNodeWithTag("signInEmail").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInPassword").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInPasswordVisibility").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInPasswordVisibility").assertHasClickAction()
composeTestRule.onNodeWithTag("signInButton").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInButton").assertHasClickAction()
composeTestRule.onNodeWithTag("signInOrText").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInOrText").assertTextEquals("Or continue with")
composeTestRule.onNodeWithTag("signInGoogleButton").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInGoogleButton").assertHasClickAction()
composeTestRule.onNodeWithTag("signInNotRegistered").assertIsDisplayed()
composeTestRule.onNodeWithTag("signInNotRegistered").assertIsDisplayed().assertHasClickAction()
}

// TODO: Implement the test for Supabase login
@Test
fun validEmailAndPassword() {
composeTestRule.activity.setContent { SignInScreen() }
fun signInScreen_emailValidation_emptyEmail_showsError() {
composeTestRule.setContent { SignInScreen() }

// Click on the sign in button with empty fields
composeTestRule.onNodeWithTag("signInButton").performClick()

// Verify that the error message for email is displayed
composeTestRule.onNodeWithTag("signInEmailError").assertTextEquals("Email cannot be empty")
}

@Test
fun signInScreen_emailValidation_invalidEmail_showsError() {
composeTestRule.setContent { SignInScreen() }

// Enter an invalid email
composeTestRule.onNodeWithTag("signInEmail").performTextInput("invalidEmail")

// Click on the sign in button
composeTestRule.onNodeWithTag("signInButton").performClick()

// Verify that the error message for email is displayed
composeTestRule.onNodeWithTag("signInEmailError").assertTextEquals("Email must contain @")
}

@Test
fun signInScreen_passwordValidation_emptyPassword_showsError() {
composeTestRule.setContent { SignInScreen() }

// Enter a valid email
composeTestRule.onNodeWithTag("signInEmail").performTextInput("test@example.com")

composeTestRule.onNodeWithTag("signInEmail").performTextInput("valid@example.com")
composeTestRule.onNodeWithTag("signInPassword").performTextInput("validPassword")
// Click on the sign in button with empty password
composeTestRule.onNodeWithTag("signInButton").performClick()

// Check if the toast message "Login Successful" is displayed
// Verify that the error message for password is displayed
composeTestRule
.onNodeWithTag("signInPasswordError")
.assertTextEquals("Password cannot be empty")
}

// TODO: Implement the test for Supabase login
// @Test
// fun invalidEmail() {
// composeTestRule.activity.setContent { SignInScreen() }
//
// composeTestRule.onNodeWithTag("signInEmail").performTextInput("invalid-email")
// composeTestRule.onNodeWithTag("signInPassword").performTextInput("validPassword")
// composeTestRule.onNodeWithTag("signInButton").performClick()
//
// // Add assertions to verify error message for invalid email
// }

// TODO: Implement with supabase
// @Test
// fun invalidPassword() {
// composeTestRule.activity.setContent { SignInScreen() }
//
// composeTestRule.onNodeWithTag("loginUsername").performTextInput("valid@example.com")
// composeTestRule.onNodeWithTag("loginPassword").performTextInput("invalid")
// composeTestRule.onNodeWithTag("loginButton").performClick()
//
// // Add assertions to verify error message for invalid email
// }
@Test
fun signInScreen_signIn_successfulLogin() {
composeTestRule.setContent { SignInScreen() }

// Enter valid email and password
composeTestRule.onNodeWithTag("signInEmail").performTextInput("test@example.com")
composeTestRule.onNodeWithTag("signInPassword").performTextInput("ValidPassword123")

// Click on the sign in button
composeTestRule.onNodeWithTag("signInButton").performClick()

// Check for a successful login Toast (mocking would be required here)
// Currently, you can't test Toast directly; you can use dependency injection or other methods
}

@Test
fun googleSignInReturnsValidActivityResult() {
composeTestRule.activity.setContent { SignInScreen() }
fun signInScreen_signIn_failsInvalidLogin() {
composeTestRule.setContent { SignInScreen() }

composeTestRule.onNodeWithTag("signInGoogleButton").performClick()
composeTestRule.waitForIdle()
intended(toPackage("com.google.android.gms"))
// Enter valid email and an invalid password
composeTestRule.onNodeWithTag("signInEmail").performTextInput("test@example.com")
composeTestRule.onNodeWithTag("signInPassword").performTextInput("InvalidPassword")

// Click on the sign in button
composeTestRule.onNodeWithTag("signInButton").performClick()

// Check for a failed login Toast (mocking would be required here)
// You can set up your test to verify that the error message or Toast appears.
}

// TODO: Implement the test for Supabase login

// @Test
// fun supabaseLogInRetursValidActivityResult() {
// // Set up the test environment
// composeTestRule.setContent { SignInScreen() }
//
// // Mock Supabase authentication
// val mockSupabaseClient = mockk<SupabaseClient>()
// every { mockSupabaseClient.auth.signInWithPassword(any(), any()) } returns AuthResponse(
// user = User(id = "testUserId"),
// session = Session(accessToken = "testAccessToken")
// )
//
// // Perform the login action
// composeTestRule.onNodeWithTag("loginUsername").performTextInput("testUser")
// composeTestRule.onNodeWithTag("loginPassword").performTextInput("testPassword")
// composeTestRule.onNodeWithTag("loginButton").performClick()
//
// // Verify the result
// composeTestRule.waitForIdle()
// verify { mockSupabaseClient.auth.signInWithPassword("testUser", "testPassword") }
// assertTrue(mockSupabaseClient.auth.currentSession != null)
// }

// TODO: tests for toast messages ?
@Test
fun signInScreen_navigatesToSignUp() {
composeTestRule.setContent { SignInScreen() }

// Click on the "Not registered yet? Sign up here!" text
composeTestRule.onNodeWithTag("signInNotRegistered").performClick()

// Check for a navigation action (mocking would be required here)
// You would verify that the navigation to the sign-up screen is triggered.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package com.android.periodpals.ui.authentication

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import org.junit.Rule
import org.junit.Test

class SignUpScreenTest {

@get:Rule val composeTestRule = createComposeRule()

@Test
fun signUpScreen_displaysCorrectUI() {
composeTestRule.setContent { SignUpScreen() }

// Assert visibility of UI elements
composeTestRule.onNodeWithTag("signUpScreen").assertIsDisplayed()
composeTestRule.onNodeWithTag("signUpBackground").assertIsDisplayed()
composeTestRule.onNodeWithTag("signUpTitle").assertIsDisplayed()
composeTestRule.onNodeWithTag("signUpInstruction").assertIsDisplayed()
composeTestRule.onNodeWithTag("signUpEmail").assertIsDisplayed()
composeTestRule.onNodeWithTag("signUpPassword").assertIsDisplayed()
composeTestRule.onNodeWithTag("signUpPasswordVisibility").assertIsDisplayed()
composeTestRule.onNodeWithTag("signUpConfirmText").assertIsDisplayed()
composeTestRule.onNodeWithTag("signUpConfirmPassword").assertIsDisplayed()
composeTestRule.onNodeWithTag("signUpConfirmVisibility").assertIsDisplayed()
composeTestRule.onNodeWithTag("signUpButton").assertIsDisplayed()
}

@Test
fun signUpScreen_emailValidation_emptyEmail_showsError() {
composeTestRule.setContent { SignUpScreen() }

// Attempt to sign up with an empty email
composeTestRule.onNodeWithTag("signUpButton").performClick()

// Assert the error message is displayed
composeTestRule.onNodeWithTag("signUpEmailError").assertTextEquals("Email cannot be empty")
}

@Test
fun signUpScreen_emailValidation_invalidEmail_showsError() {
composeTestRule.setContent { SignUpScreen() }

// Input an invalid email
composeTestRule.onNodeWithTag("signUpEmail").performTextInput("invalidEmail")
composeTestRule.onNodeWithTag("signUpButton").performClick()

// Assert the error message is displayed
composeTestRule.onNodeWithTag("signUpEmailError").assertTextEquals("Email must contain @")
}

@Test
fun signUpScreen_passwordValidation_emptyPassword_showsError() {
composeTestRule.setContent { SignUpScreen() }

// Input an email and attempt to sign up with an empty password
composeTestRule.onNodeWithTag("signUpEmail").performTextInput("test@example.com")
composeTestRule.onNodeWithTag("signUpButton").performClick()

// Assert the error message is displayed
composeTestRule
.onNodeWithTag("signUpPasswordError")
.assertTextEquals("Password cannot be empty")
}

@Test
fun signUpScreen_passwordValidation_passwordTooShort_showsError() {
composeTestRule.setContent { SignUpScreen() }

composeTestRule.onNodeWithTag("signUpEmail").performTextInput("test@example.com")
composeTestRule.onNodeWithTag("signUpPassword").performTextInput("short")
composeTestRule.onNodeWithTag("signUpConfirmPassword").performTextInput("short")
composeTestRule.onNodeWithTag("signUpButton").performClick()

composeTestRule
.onNodeWithTag("signUpPasswordError")
.assertTextEquals("Password must be at least 8 characters long")
}

@Test
fun signUpScreen_passwordValidation_passwordNoCapital_showsError() {
composeTestRule.setContent { SignUpScreen() }

composeTestRule.onNodeWithTag("signUpEmail").performTextInput("test@example.com")
composeTestRule.onNodeWithTag("signUpPassword").performTextInput("password")
composeTestRule.onNodeWithTag("signUpConfirmPassword").performTextInput("password")
composeTestRule.onNodeWithTag("signUpButton").performClick()

composeTestRule
.onNodeWithTag("signUpPasswordError")
.assertTextEquals("Password must contain at least one capital letter")
}

@Test
fun signUpScreen_passwordValidation_passwordNoMinuscule_showsError() {
composeTestRule.setContent { SignUpScreen() }

composeTestRule.onNodeWithTag("signUpEmail").performTextInput("test@example.com")
composeTestRule.onNodeWithTag("signUpPassword").performTextInput("PASSWORD")
composeTestRule.onNodeWithTag("signUpConfirmPassword").performTextInput("PASSWORD")
composeTestRule.onNodeWithTag("signUpButton").performClick()

composeTestRule
.onNodeWithTag("signUpPasswordError")
.assertTextEquals("Password must contain at least one lower case letter")
}

@Test
fun signUpScreen_passwordValidation_passwordNoNumber_showsError() {
composeTestRule.setContent { SignUpScreen() }

composeTestRule.onNodeWithTag("signUpEmail").performTextInput("test@example.com")
composeTestRule.onNodeWithTag("signUpPassword").performTextInput("Password")
composeTestRule.onNodeWithTag("signUpConfirmPassword").performTextInput("Password")
composeTestRule.onNodeWithTag("signUpButton").performClick()

composeTestRule
.onNodeWithTag("signUpPasswordError")
.assertTextEquals("Password must contain at least one number")
}

@Test
fun signUpScreen_passwordValidation_passwordNoSpecial_showsError() {
composeTestRule.setContent { SignUpScreen() }

composeTestRule.onNodeWithTag("signUpEmail").performTextInput("test@example.com")
composeTestRule.onNodeWithTag("signUpPassword").performTextInput("Passw0rd")
composeTestRule.onNodeWithTag("signUpConfirmPassword").performTextInput("Passw0rd")
composeTestRule.onNodeWithTag("signUpButton").performClick()

composeTestRule
.onNodeWithTag("signUpPasswordError")
.assertTextEquals("Password must contain at least one special character")
}

@Test
fun signUpScreen_passwordValidation_passwordsDoNotMatch_showsError() {
composeTestRule.setContent { SignUpScreen() }

// Input an email and mismatched passwords
composeTestRule.onNodeWithTag("signUpEmail").performTextInput("test@example.com")
composeTestRule.onNodeWithTag("signUpPassword").performTextInput("Password123")
composeTestRule.onNodeWithTag("signUpConfirmPassword").performTextInput("Password456")
composeTestRule.onNodeWithTag("signUpButton").performClick()

// Assert the error message is displayed
composeTestRule.onNodeWithTag("signUpConfirmError").assertTextEquals("Passwords do not match")
}

@Test
fun signUpScreen_signUp_successfulRegistration() {
composeTestRule.setContent { SignUpScreen() }

// Input valid data and perform sign up
composeTestRule.onNodeWithTag("signUpEmail").performTextInput("test@example.com")
composeTestRule.onNodeWithTag("signUpPassword").performTextInput("ValidPassword123!")
composeTestRule.onNodeWithTag("signUpConfirmPassword").performTextInput("ValidPassword123!")
composeTestRule.onNodeWithTag("signUpButton").performClick()

// You can assert here for a visual change or a Toast message if possible
// Since Toast can't be tested directly, consider an alternative for future testing
// TODO: Supabase integration for account creation
}
}
5 changes: 1 addition & 4 deletions app/src/main/java/com/android/periodpals/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.android.periodpals.ui.authentication.SignUpScreen
import com.android.periodpals.ui.theme.PeriodPalsAppTheme
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
Expand All @@ -31,9 +30,7 @@ class MainActivity : ComponentActivity() {
PeriodPalsAppTheme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
// TODO: Uncomment the following line
// CountriesList()
SignUpScreen()
CountriesList()
}
}
}
Expand Down
Loading

0 comments on commit b27beb7

Please sign in to comment.