Skip to content

Commit

Permalink
Merge pull request #100 from CrisisCleanup/layout-tests
Browse files Browse the repository at this point in the history
Layout tests
  • Loading branch information
hueachilles committed Jan 24, 2024
2 parents fdc93e0 + 9ef5ddb commit 93b4adc
Show file tree
Hide file tree
Showing 108 changed files with 5,905 additions and 1,324 deletions.
1 change: 1 addition & 0 deletions .maestro/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.png
14 changes: 14 additions & 0 deletions .maestro/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Target app
`MAESTRO_APP_ID=com.crisiscleanup.demo maestro test auth-tests`

[Specify device](https://maestro.mobile.dev/advanced/specify-a-device)
`maestro --device emulator-5554 test auth-tests`

List devices

- Android `adb devices`
- iOS `xcrun simctl list devices booted`

Full test command
`MAESTRO_APP_ID=com.crisiscleanup.demo.debug maestro --device emulator-5554 test auth-tests`
`MAESTRO_APP_ID=com.crisiscleanup.dev maestro --device device-uuid-from-list test auth-tests`
52 changes: 52 additions & 0 deletions .maestro/advanced-techniques.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[Cross platform techniques](https://blog.mobile.dev/best-practices-for-cross-platform-maestro-ui-testing-for-android-and-ios-98d1c471a838)

## Platform specific init scripts

Specify platform specific IDs.

In a test.yaml

```yaml
- runScript:
when:
platform: iOS
file: ios/init.js

#... more runScripts (for other platforms)

- tapOn:
id: ${output.wallpapers.wallpaperItem}
index: 0
```
ios/init.js
```js
output.wallpapers = {
wallpaperItem: 'imageItem',
}
```

## Run platform specific flows

In a test.yaml this runs `Date.yaml` only on iOS. `Date.yaml` is expected to specify tests.

```yaml
- runFlow:
when:
platform: iOS
file: Date.yaml
```
See further down page on how to test platform share window.
## Inline platform specific tests
```yaml
- runFlow:
when:
platform: Android
commands:
- assertVisible:
id: "setWallpaperIconButton"
```
12 changes: 12 additions & 0 deletions .maestro/screenshot-tests/auth-screens.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Auth screenshots
appId: ${MAESTRO_APP_ID}
tags:
- auth
- screenshots
---
- clearState
- launchApp
- extendedWaitUntil:
visible:
id: loginHeaderText
- takeScreenshot: AuthRoot
File renamed without changes.
85 changes: 85 additions & 0 deletions app-sandbox/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import com.google.samples.apps.nowinandroid.NiaBuildType

plugins {
id("nowinandroid.android.application")
id("nowinandroid.android.application.compose")
id("nowinandroid.android.application.flavors")
id("nowinandroid.android.hilt")
}

android {
defaultConfig {
applicationId = "com.crisiscleanup.sandbox"
versionCode = 1
versionName = "0.0.1"

vectorDrawables {
useSupportLibrary = true
}
}

buildTypes {
val debug by getting {
applicationIdSuffix = NiaBuildType.DEBUG.applicationIdSuffix
}
val release by getting {
applicationIdSuffix = NiaBuildType.RELEASE.applicationIdSuffix
}
}

packaging {
resources {
excludes.add("/META-INF/{AL2.0,LGPL2.1}")
}
}
namespace = "com.crisiscleanup.sandbox"
}

dependencies {
implementation(project(":feature:caseeditor"))

implementation(project(":core:appnav"))
implementation(project(":core:common"))
implementation(project(":core:commoncase"))
implementation(project(":core:data"))
implementation(project(":core:designsystem"))
implementation(project(":core:network"))
implementation(project(":core:model"))
implementation(project(":core:ui"))

androidTestImplementation(libs.androidx.navigation.testing)
androidTestImplementation(libs.accompanist.testharness)
androidTestImplementation(kotlin("test"))
debugImplementation(libs.androidx.compose.ui.testManifest)
debugImplementation(project(":ui-test-hilt-manifest"))

implementation(libs.kotlinx.serialization.json)

implementation(libs.accompanist.systemuicontroller)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.core.splashscreen)
implementation(libs.androidx.compose.runtime)
implementation(libs.androidx.lifecycle.runtimeCompose)
implementation(libs.androidx.compose.runtime.tracing)
implementation(libs.androidx.compose.material3.windowSizeClass)
implementation(libs.androidx.hilt.navigation.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.window.manager)
implementation(libs.androidx.profileinstaller)

implementation(libs.coil.kt)

implementation(libs.kotlinx.coroutines.playservices)
implementation(libs.playservices.maps)
}

// androidx.test is forcing JUnit, 4.12. This forces it to use 4.13
configurations.configureEach {
resolutionStrategy {
force(libs.junit4)
// Temporary workaround for https://issuetracker.google.com/174733673
force("org.objenesis:objenesis:2.6")
}
}
26 changes: 26 additions & 0 deletions app-sandbox/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:name=".SandboxApplication"
android:icon="@mipmap/ic_launcher"
android:label="cc-sandbox"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:targetApi="31">
<profileable
android:shell="true"
tools:targetApi="31" />

<activity
android:name=".SandboxActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.crisiscleanup.sandbox

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.core.view.WindowCompat
import com.crisiscleanup.core.designsystem.theme.CrisisCleanupTheme
import com.google.android.gms.maps.MapsInitializer
import dagger.hilt.android.AndroidEntryPoint

@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@AndroidEntryPoint
class SandboxActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MapsInitializer.initialize(this, MapsInitializer.Renderer.LATEST) {}

// Turn off the decor fitting system windows, which allows us to handle insets,
// including IME animations
WindowCompat.setDecorFitsSystemWindows(window, false)

setContent {
CrisisCleanupTheme {
SandboxApp(
windowSizeClass = calculateWindowSizeClass(this),
)
}
}
}
}
93 changes: 93 additions & 0 deletions app-sandbox/src/main/java/com/crisiscleanup/sandbox/SandboxApp.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.crisiscleanup.sandbox

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.crisiscleanup.core.designsystem.component.CrisisCleanupBackground
import com.crisiscleanup.core.designsystem.component.CrisisCleanupTextButton
import com.crisiscleanup.core.designsystem.theme.listItemSpacedBy
import com.crisiscleanup.sandbox.navigation.SandboxNavHost
import com.crisiscleanup.sandbox.navigation.chipsRoute
import com.crisiscleanup.sandbox.navigation.navigateToBottomNav
import com.crisiscleanup.sandbox.navigation.navigateToCheckboxes
import com.crisiscleanup.sandbox.navigation.navigateToChips

@Composable
fun SandboxApp(
windowSizeClass: WindowSizeClass,
appState: SandboxAppState = rememberAppState(
windowSizeClass = windowSizeClass,
),
) {
CrisisCleanupBackground {
Box(Modifier.fillMaxSize()) {
val snackbarHostState = remember { SnackbarHostState() }

Scaffold(
containerColor = Color.Transparent,
contentColor = MaterialTheme.colorScheme.onBackground,
contentWindowInsets = WindowInsets(0, 0, 0, 0),
snackbarHost = { SnackbarHost(snackbarHostState) },
topBar = {},
bottomBar = {},
) { padding ->
Column(
Modifier
.fillMaxSize()
.padding(padding)
.consumeWindowInsets(padding)
.windowInsetsPadding(WindowInsets.safeDrawing),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
SandboxNavHost(
appState.navController,
chipsRoute,
)
}
}
}
}
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun RootRoute(navController: NavController) {
Column {
Spacer(Modifier.weight(1f))
FlowRow(
horizontalArrangement = listItemSpacedBy,
verticalArrangement = listItemSpacedBy,
maxItemsInEachRow = 6,
) {
CrisisCleanupTextButton(text = "Bottom nav") {
navController.navigateToBottomNav()
}
CrisisCleanupTextButton(text = "Checkboxes") {
navController.navigateToCheckboxes()
}
CrisisCleanupTextButton(text = "Chips") {
navController.navigateToChips()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.crisiscleanup.sandbox

import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.CoroutineScope

@Composable
fun rememberAppState(
windowSizeClass: WindowSizeClass,
coroutineScope: CoroutineScope = rememberCoroutineScope(),
navController: NavHostController = rememberNavController(),
): SandboxAppState {
return remember(navController, coroutineScope, windowSizeClass) {
SandboxAppState(navController, coroutineScope, windowSizeClass)
}
}

@Stable
class SandboxAppState(
val navController: NavHostController,
val coroutineScope: CoroutineScope,
val windowSizeClass: WindowSizeClass,
) {
fun onBack() {
navController.popBackStack()
}
}
Loading

0 comments on commit 93b4adc

Please sign in to comment.