Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build-logic/plugins/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,9 @@ gradlePlugin {
id = libs.plugins.wire.versionizer.get().pluginId
implementationClass = "AppVersionPlugin"
}
register("androidTestLibraryConventionPlugin") {
id = libs.plugins.wire.android.test.library.get().pluginId
implementationClass = "AndroidTestLibraryConventionPlugin"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
import com.android.build.api.dsl.AndroidSourceSet
import com.android.build.gradle.LibraryExtension
import com.wire.android.gradle.configureCompose
import com.wire.android.gradle.configureKotlinAndroid
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.get

class AndroidTestLibraryConventionPlugin : Plugin<Project> {
override fun apply(target: Project): Unit = with(target) {
with(pluginManager) {
apply("com.android.library")
apply("org.jetbrains.kotlin.android")
}

extensions.configure<LibraryExtension> {
namespace = "com.wire.android.tests.${target.name.replace("-", "_")}"

configureKotlinAndroid(this)
defaultConfig.targetSdk = AndroidSdk.target
configureCompose(this)

defaultConfig {
defaultConfig {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments.putAll(
mapOf(
"clearPackageData" to "true",
"force-queryable" to "true"
)
)
}

// This enables us to share some code between UI and Unit tests!
fun AndroidSourceSet.includeCommonTestSourceDir() = java {
srcDir("src/commonTest/kotlin")
}
sourceSets["test"].includeCommonTestSourceDir()
sourceSets["androidTest"].includeCommonTestSourceDir()

testOptions {
execution = "ANDROIDX_TEST_ORCHESTRATOR"
animationsDisabled = true
unitTests.isReturnDefaultValues = true
unitTests.isIncludeAndroidResources = true
}
}

buildTypes {
// submodules using this plugin can skip minification, since the app will do it
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
}
}
2 changes: 1 addition & 1 deletion build-logic/plugins/src/test/resources/version.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ VersionCode: 100018802
VersionName: 4.8.2-18802
Revision: e53642019
Buildtime: 2024-08-21 19:32:06
Application-name: com.wire
Application-name: com.wire
2 changes: 1 addition & 1 deletion docs/adr/0006-enterprise-login-supporting-both-flows.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 5. Simplified enterprise login
# 6. Simplified enterprise login

Date: 2025-01-23

Expand Down
36 changes: 36 additions & 0 deletions docs/adr/0007-introducing-uiautomator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# 7. Introducing UIAutomator for integrated testing

Date: 2025-05-06

## Status

Accepted

## Context

QA wants to migrate from Appium to a new framework to run tests and being closed to the source code that we are testing.
The tests nowadays are running on an emulator with an apk. After meeting the QA we evaluated options, Espresso and UIAutomator.

## Decision

UIAutomator seems to be the best option for us, as it is a framework that is already in the Android SDK and it is more flexible than Espresso, this last one is more limited to the app under test because of mocks and stubs.
We will create a new module(s) for testing purposes, and we will use the UIAutomator framework to run the tests, common logic can be extracted and shared between tests modules in case we want to parallelize the tests in the future.


## Consequences

The new structure of the project will be as follows:
```
wire-android
├── app
│ ├── ...
├── core
│ ├── ...
├── features
│ ├── ...
├── tests
│ ├── ...
│ ├── testsCore
│ ├── testsSupport
└── build.gradle.kts
```
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ screenshot = { id = "com.android.compose.screenshot", version.ref = "screenshot"
# Home-made convention plugins defined in build-logic
wire-android-application = { id = "com.wire.android.application" }
wire-android-library = { id = "com.wire.android.library" }
wire-android-test-library = { id = "com.wire.android.test.library" }
wire-hilt = { id = "com.wire.android.hilt" }
wire-kover = { id = "com.wire.android.kover" }
wire-versionizer = { id = "com.wire.android.versionizer" }
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pluginManagement {
}

// Include all the existent modules in the project
val basePathModules = setOf("features", "core")
val basePathModules = setOf("features", "core", "tests")
val ignorableModules = setOf("buildSrc", "kalium")
rootDir
.walk()
Expand Down
1 change: 1 addition & 0 deletions tests/testsCore/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
24 changes: 24 additions & 0 deletions tests/testsCore/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
plugins {
id(libs.plugins.wire.android.test.library.get().pluginId)
}

android {
sourceSets {
getByName("androidTest") {
kotlin.srcDirs("src/androidTest/kotlin")
kotlin.srcDirs(project(":tests:testsSupport").file("src/androidTest/kotlin"))
}
}
}

dependencies {
val composeBom = platform(libs.compose.bom)
implementation(composeBom)
implementation(libs.compose.ui)

androidTestImplementation(libs.androidx.test.runner)
androidTestImplementation(libs.androidx.test.extJunit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(libs.androidx.test.uiAutomator)
androidTestImplementation(project(":tests:testsSupport"))
}
Empty file.
4 changes: 4 additions & 0 deletions tests/testsCore/lint-baseline.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 8.5.2" type="baseline" client="gradle" dependencies="false" name="AGP (8.5.2)" variant="all" version="8.5.2">

</issues>
21 changes: 21 additions & 0 deletions tests/testsCore/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.tests.core.login

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.uiautomator.UiDevice
import com.wire.android.tests.core.login.pages.LoginPage
import com.wire.android.tests.support.UiAutomatorSetup
import com.wire.android.tests.support.suite.RC
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

/*
This test works on the following conditions:
1) The dev/staging app is installed on the device/emulator.
*/
@RunWith(AndroidJUnit4::class)
@RC
class LoginTest {
private lateinit var device: UiDevice

@Before
fun setUp() {
device = UiAutomatorSetup.start(UiAutomatorSetup.APP_DEV)
}

@Test
fun openTheAppAndShouldSeeEmailFieldAndLoginNextButtonWhenValid() {
LoginPage(device)
.tapOnEmailField()
.typeEmail("tester@wire.com")
.shouldEnableTheLoginButtonWhenValid()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.tests.core.login.pages

import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject
import androidx.test.uiautomator.UiSelector
import com.wire.android.tests.support.TIMEOUT_IN_MILLISECONDS
import org.junit.Assert.assertTrue

data class LoginPage(private val device: UiDevice) {

fun tapOnEmailField(): LoginPage {
val emailSsoCodeField = device.findObject(UiSelector().resourceId("userIdentifierInput"))
emailSsoCodeField.waitForExists(TIMEOUT_IN_MILLISECONDS)
emailSsoCodeField.click()
return this
}

fun typeEmail(email: String): LoginPage {
val emailSsoCodeField: UiObject = device.findObject(UiSelector().resourceId("userIdentifierInput"))
emailSsoCodeField.waitForExists(TIMEOUT_IN_MILLISECONDS)
emailSsoCodeField.setText(email)
return this
}

fun shouldEnableTheLoginButtonWhenValid(): LoginPage {
val loginButton = device.findObject(UiSelector().resourceId("loginButton"))
loginButton.waitForExists(TIMEOUT_IN_MILLISECONDS)
assertTrue("LoginButton not found or not enabled", loginButton.isClickable)
return this
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Wire
* Copyright (C) 2025 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.tests.core.registration

// TODO: Add tests for registration
31 changes: 31 additions & 0 deletions tests/testsCore/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Wire
~ Copyright (C) 2024 Wire Swiss GmbH
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see http://www.gnu.org/licenses/.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />

<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
</intent>
</queries>

</manifest>
1 change: 1 addition & 0 deletions tests/testsSupport/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
10 changes: 10 additions & 0 deletions tests/testsSupport/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
plugins {
id(libs.plugins.wire.android.test.library.get().pluginId)
}

dependencies {
androidTestImplementation(libs.androidx.test.runner)
androidTestImplementation(libs.androidx.test.extJunit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(libs.androidx.test.uiAutomator)
}
Empty file.
4 changes: 4 additions & 0 deletions tests/testsSupport/lint-baseline.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 8.5.2" type="baseline" client="gradle" dependencies="false" name="AGP (8.5.2)" variant="all" version="8.5.2">

</issues>
Loading
Loading