Skip to content

Commit

Permalink
SpeziViews (#140)
Browse files Browse the repository at this point in the history
# SpeziViews

## ♻️ Current situation & Problem
*Link any open issues or pull requests (PRs) related to this PR. Please
ensure that all non-trivial PRs are first tracked and discussed in an
existing GitHub issue or discussion.*


## ⚙️ Release Notes 
*Add a bullet point list summary of the feature and possible migration
guides if this is a breaking change so this section can be added to the
release notes.*
*Include code snippets that provide examples of the feature implemented
or links to the documentation if it appends or changes the public
interface.*


## 📚 Documentation
*Please ensure that you properly document any additions in conformance
to [Spezi Documentation
Guide](https://github.com/StanfordSpezi/.github/blob/main/DOCUMENTATIONGUIDE.md).*
*You can use this section to describe your solution, but we encourage
contributors to document your reasoning and changes using in-line
documentation.*


## ✅ Testing
*Please ensure that the PR meets the testing requirements set by CodeCov
and that new functionality is appropriately tested.*
*This section describes important information about the tests and why
some elements might not be testable.*


## 📝 Code of Conduct & Contributing Guidelines 

By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md).
  • Loading branch information
pauljohanneskraft authored Nov 24, 2024
1 parent 11ae70a commit f5ee17f
Show file tree
Hide file tree
Showing 58 changed files with 2,355 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package edu.stanford.bdh.engagehf.contact.data

import com.google.firebase.firestore.DocumentSnapshot
import edu.stanford.spezi.core.design.component.StringResource
import edu.stanford.spezi.core.design.views.personalinfo.PersonNameComponents
import edu.stanford.spezi.modules.contact.model.Contact
import edu.stanford.spezi.modules.contact.model.ContactOption
import edu.stanford.spezi.modules.contact.model.PersonNameComponents
import edu.stanford.spezi.modules.contact.model.call
import edu.stanford.spezi.modules.contact.model.email
import javax.inject.Inject
Expand All @@ -19,11 +19,12 @@ class ContactDocumentToContactMapper @Inject constructor() {
}
val components = contactName.split(", ")
val nameComponents = components.firstOrNull()?.split(" ")
val personNameComponents = PersonNameComponents(
givenName = nameComponents?.getOrNull(0),
familyName = nameComponents?.drop(1)
?.joinToString(" ") // assigning everything besides given name here
)
val personNameComponents =
PersonNameComponents(
givenName = nameComponents?.getOrNull(0),
familyName = nameComponents?.drop(1)
?.joinToString(" ") // assigning everything besides given name here
)
val title = components.lastOrNull()
val contactEmail = document.getString(CONTACT_EMAIL_FIELD)
val phone = document.getString(CONTACT_PHONE_FIELD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ import edu.stanford.spezi.core.design.theme.Spacings
import edu.stanford.spezi.core.design.theme.SpeziTheme
import edu.stanford.spezi.core.design.theme.TextStyles
import edu.stanford.spezi.core.design.theme.ThemePreviews
import edu.stanford.spezi.core.design.views.personalinfo.PersonNameComponents
import edu.stanford.spezi.core.notification.R
import edu.stanford.spezi.modules.contact.ContactComposable
import edu.stanford.spezi.modules.contact.model.Contact
import edu.stanford.spezi.modules.contact.model.ContactOption
import edu.stanford.spezi.modules.contact.model.PersonNameComponents
import edu.stanford.spezi.modules.contact.model.call
import edu.stanford.spezi.modules.contact.model.email
import edu.stanford.spezi.modules.contact.model.website
Expand Down Expand Up @@ -109,8 +109,14 @@ private class ContactUiStateProvider : PreviewParameterProvider<ContactScreenVie
ContactScreenViewModel.UiState.Error("An error occurred"),
ContactScreenViewModel.UiState.ContactLoaded(
contact = Contact(
name = PersonNameComponents(givenName = "Leland", familyName = "Stanford"),
image = ImageResource.Vector(Icons.Default.AccountBox),
name = PersonNameComponents(
givenName = "Leland",
familyName = "Stanford"
),
image = ImageResource.Vector(
Icons.Default.AccountBox,
StringResource(edu.stanford.spezi.modules.contact.R.string.profile_picture)
),
title = StringResource("University Founder"),
description = StringResource(
"""Leland Stanford (March 9, 1824 – June 21, 1893) was an American industrialist and politician."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package edu.stanford.bdh.engagehf.contact.data
import com.google.common.truth.Truth.assertThat
import com.google.firebase.firestore.DocumentSnapshot
import edu.stanford.spezi.core.design.component.StringResource
import edu.stanford.spezi.modules.contact.model.PersonNameComponents
import edu.stanford.spezi.core.design.views.personalinfo.PersonNameComponents
import io.mockk.every
import io.mockk.mockk
import org.junit.Test
Expand Down
1 change: 1 addition & 0 deletions core/design/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ dependencies {

debugImplementation(libs.compose.ui.tooling)
debugImplementation(libs.compose.ui.test.manifest)
implementation(kotlin("reflect"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package edu.stanford.spezi.core.design.personalInfo

import androidx.compose.ui.test.junit4.createComposeRule
import com.google.common.truth.Truth.assertThat
import edu.stanford.spezi.core.design.personalInfo.composables.NameFieldsTestComposable
import edu.stanford.spezi.core.design.personalInfo.simulators.NameFieldsTestSimulator
import edu.stanford.spezi.core.design.views.personalinfo.PersonNameComponents
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class NameFieldsTest {

@get:Rule
val composeTestRule = createComposeRule()

val nameBuilder = PersonNameComponents.Builder()

@Before
fun init() {
composeTestRule.setContent {
NameFieldsTestComposable(nameBuilder)
}
}

@Test
fun testNameFields() {
val givenName = "Leland"
val familyName = "Stanford"

nameFields {
assertTextExists("First Name")
assertTextExists("Last Name")

enterText(PersonNameComponents.Builder::givenName, givenName)
enterText(PersonNameComponents.Builder::familyName, familyName)

assertTextExists("First Name")
assertTextExists("Last Name")

assertThat(nameBuilder.givenName).isEqualTo(givenName)
assertThat(nameBuilder.familyName).isEqualTo(familyName)
}
}

private fun nameFields(block: NameFieldsTestSimulator.() -> Unit) {
NameFieldsTestSimulator(composeTestRule).apply(block)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package edu.stanford.spezi.core.design.personalInfo

import androidx.compose.ui.test.junit4.createComposeRule
import edu.stanford.spezi.core.design.personalInfo.composables.UserProfileTestComposable
import edu.stanford.spezi.core.design.personalInfo.simulators.UserProfileTestSimulator
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class UserProfileTest {

@get:Rule
val composeTestRule = createComposeRule()

@Before
fun init() {
composeTestRule.setContent {
UserProfileTestComposable()
}
}

@Test
fun testUserProfile() {
userProfile {
assertUserInitialsExists(true, "PS")
assertUserInitialsExists(true, "LS")
waitUntilUserInitialsDisappear("LS")
assertImageExists("Person")
}
}

private fun userProfile(block: UserProfileTestSimulator.() -> Unit) {
UserProfileTestSimulator(composeTestRule).apply(block)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package edu.stanford.spezi.core.design.personalInfo.composables

import androidx.compose.foundation.layout.Column
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import edu.stanford.spezi.core.design.views.personalinfo.PersonNameComponents
import edu.stanford.spezi.core.design.views.personalinfo.fields.NameFieldRow

@Composable
fun NameFieldsTestComposable(nameBuilder: PersonNameComponents.Builder) {
Column {
NameFieldRow("First Name", nameBuilder, PersonNameComponents.Builder::givenName) {
Text("enter your first name")
}

HorizontalDivider()

NameFieldRow("Last Name", nameBuilder, PersonNameComponents.Builder::familyName) {
Text("enter your last name")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package edu.stanford.spezi.core.design.personalInfo.composables

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Person
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import edu.stanford.spezi.core.design.component.ImageResource
import edu.stanford.spezi.core.design.component.StringResource
import edu.stanford.spezi.core.design.views.personalinfo.PersonNameComponents
import edu.stanford.spezi.core.design.views.personalinfo.UserProfileComposable
import kotlinx.coroutines.delay
import kotlin.time.Duration.Companion.seconds

@Composable
fun UserProfileTestComposable() {
Column {
UserProfileComposable(
PersonNameComponents(
givenName = "Paul",
familyName = "Schmiedmayer"
),
Modifier.height(100.dp),
)
UserProfileComposable(
PersonNameComponents(
givenName = "Leland",
familyName = "Stanford"
),
Modifier.height(200.dp),
) {
delay(0.5.seconds)
ImageResource.Vector(Icons.Default.Person, StringResource("Person"))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package edu.stanford.spezi.core.design.personalInfo.simulators

import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performTextInput
import edu.stanford.spezi.core.design.views.personalinfo.PersonNameComponents
import edu.stanford.spezi.core.design.views.personalinfo.fields.NameTextFieldTestIdentifier
import edu.stanford.spezi.core.testing.onNodeWithIdentifier
import kotlin.reflect.KMutableProperty1

class NameFieldsTestSimulator(
private val composeTestRule: ComposeTestRule,
) {
fun assertTextExists(text: String) {
composeTestRule
.onNodeWithText(text)
.assertExists()
}

fun enterText(property: KMutableProperty1<PersonNameComponents.Builder, String?>, text: String) {
composeTestRule
.onNodeWithIdentifier(NameTextFieldTestIdentifier.TEXT_FIELD, property.name)
.performTextInput(text)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package edu.stanford.spezi.core.design.personalInfo.simulators

import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.onAllNodesWithContentDescription
import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onNodeWithText

class UserProfileTestSimulator(
private val composeTestRule: ComposeTestRule,
) {

fun assertUserInitialsExists(exists: Boolean, text: String) {
val node = composeTestRule
.onNodeWithText(text)
if (exists) {
node.assertExists()
} else {
node.assertDoesNotExist()
}
}

fun waitUntilUserInitialsDisappear(text: String, timeoutMillis: Long = 1_000) {
composeTestRule.waitUntil(timeoutMillis = timeoutMillis) {
composeTestRule.onAllNodesWithText(text)
.fetchSemanticsNodes().isEmpty()
}
}

fun assertImageExists(contentDescription: String) {
composeTestRule
.onAllNodesWithContentDescription(contentDescription)
.assertCountEquals(1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package edu.stanford.spezi.core.design.validation

import androidx.compose.ui.test.junit4.createComposeRule
import edu.stanford.spezi.core.design.validation.composables.FocusValidationRules
import edu.stanford.spezi.core.design.validation.simulators.FocusValidationRulesSimulator
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class FocusValidationRulesTest {

@get:Rule
val composeTestRule = createComposeRule()

@Before
fun init() {
composeTestRule.setContent {
FocusValidationRules()
}
}

@Test
fun testFocusValidationRules() {
focusValidationRules {
assertHasEngines(true)
assertInputValid(false)
assertPasswordMessageExists(false)
assertEmptyMessageExists(false)
clickValidateButton()
assertLastState(false)
assertPasswordMessageExists(true)
assertEmptyMessageExists(true)
enterEmail("[email protected]")
assertEmptyMessageExists(false)
assertPasswordMessageExists(true)
enterPassword("password")
assertEmptyMessageExists(false)
assertPasswordMessageExists(false)
}
}

private fun focusValidationRules(block: FocusValidationRulesSimulator.() -> Unit) {
FocusValidationRulesSimulator(composeTestRule).apply(block)
}
}
Loading

0 comments on commit f5ee17f

Please sign in to comment.