Skip to content

Commit

Permalink
Merge pull request #531 from igorescodro/alkaa-multiplatform
Browse files Browse the repository at this point in the history
πŸ€–πŸ Enable Alkaa to be multiplatform
  • Loading branch information
igorescodro authored Sep 1, 2023
2 parents a9c6f33 + 0dd67be commit 2726164
Show file tree
Hide file tree
Showing 296 changed files with 3,022 additions and 1,838 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/android_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- name: Run instrumented tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 24
api-level: 27
profile: Galaxy Nexus
disable-animations: true
disk-size: 2000M
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ out/
# Gradle files
.gradle/
build/
*(org.gradle.api.file.Directory*

# Local configuration file (sdk path, etc)
local.properties
Expand Down
21 changes: 13 additions & 8 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ plugins {
android {
defaultConfig {
applicationId = "com.escodro.alkaa"
versionCode = AlkaaVersions.versionCode
versionName = AlkaaVersions.versionName
versionCode = Integer.parseInt(libs.versions.version.code.get())
versionName = libs.versions.version.name.get()

compileSdk = AlkaaVersions.compileSdk
minSdk = AlkaaVersions.minSdk
targetSdk = AlkaaVersions.targetSdk
compileSdk = Integer.parseInt(libs.versions.android.sdk.compile.get())
minSdk = Integer.parseInt(libs.versions.android.sdk.min.get())
targetSdk = Integer.parseInt(libs.versions.android.sdk.target.get())
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

setProperty("archivesBaseName", "${parent?.name}-$versionName")
Expand Down Expand Up @@ -57,8 +57,8 @@ android {
setDynamicFeatures(setOf(":features:tracker"))

compileOptions {
sourceCompatibility = AlkaaVersions.javaCompileVersion
targetCompatibility = AlkaaVersions.javaCompileVersion
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

buildFeatures {
Expand Down Expand Up @@ -106,17 +106,20 @@ dependencies {
implementation(projects.libraries.splitInstall)
implementation(projects.libraries.designsystem)
implementation(projects.libraries.navigation)
implementation(projects.libraries.coroutines)
implementation(projects.data.local)
implementation(projects.data.datastore)
implementation(projects.data.repository)
implementation(projects.domain)
implementation(projects.features.task)
implementation(projects.features.alarm)
implementation(projects.features.category)
implementation(projects.features.preference)
implementation(projects.features.search)
implementation(projects.features.glance)

implementation(projects.domain)
implementation(projects.shared)

implementation(platform(libs.compose.bom))

implementation(libs.logcat)
Expand All @@ -130,6 +133,7 @@ dependencies {

implementation(libs.bundles.compose)
implementation(libs.kotlinx.collections.immutable)
implementation(libs.kotlinx.datetime)

androidTestUtil(libs.test.orchestrator)

Expand All @@ -138,6 +142,7 @@ dependencies {

androidTestImplementation(projects.libraries.test)
androidTestImplementation(libs.koin.test)
androidTestImplementation(libs.test.rules)
androidTestImplementation(libs.bundles.composetest) {
exclude(group = "androidx.core", module = "core-ktx")
exclude(group = "androidx.fragment", module = "fragment")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import com.escodro.alkaa.navigation.NavGraph
import com.escodro.alkaa.util.WindowSizeClassFake
import com.escodro.category.presentation.semantics.ColorKey
import com.escodro.designsystem.AlkaaTheme
import com.escodro.local.provider.DaoProvider
import com.escodro.local.dao.CategoryDao
import com.escodro.test.rule.DisableAnimationsRule
import kotlinx.coroutines.test.runTest
import org.junit.Before
Expand All @@ -28,7 +28,7 @@ import com.escodro.category.R as CategoryR

internal class CategoryFlowTest : KoinTest {

private val daoProvider: DaoProvider by inject()
private val categoryDao: CategoryDao by inject()

@get:Rule
val composeTestRule = createComposeRule()
Expand All @@ -42,7 +42,7 @@ internal class CategoryFlowTest : KoinTest {
fun setup() {
runTest {
// Clean all existing categories
daoProvider.getCategoryDao().cleanTable()
categoryDao.cleanTable()
}

composeTestRule.setContent {
Expand Down
61 changes: 37 additions & 24 deletions app/src/androidTest/java/com/escodro/alkaa/NotificationFlowTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.escodro.alkaa

import android.Manifest
import android.app.Notification
import androidx.annotation.StringRes
import androidx.compose.ui.test.ExperimentalTestApi
Expand All @@ -9,13 +10,16 @@ import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
import com.escodro.alkaa.fake.FAKE_TASK
import com.escodro.alkaa.navigation.NavGraph
import com.escodro.alkaa.util.WindowSizeClassFake
import com.escodro.core.extension.getNotificationManager
import com.escodro.core.extension.toLocalDateTime
import com.escodro.domain.usecase.alarm.ScheduleAlarm
import com.escodro.local.Task
import com.escodro.local.dao.TaskDao
import com.escodro.local.model.AlarmInterval
import com.escodro.local.model.Task
import com.escodro.local.provider.DaoProvider
import com.escodro.test.rule.DisableAnimationsRule
import kotlinx.coroutines.test.runTest
import org.junit.After
Expand All @@ -28,12 +32,11 @@ import java.util.Calendar
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import com.escodro.alarm.R as AlarmR
import com.escodro.designsystem.R as DesignSystemR

@OptIn(ExperimentalTestApi::class)
internal class NotificationFlowTest : KoinTest {

private val daoProvider: DaoProvider by inject()
private val taskDao: TaskDao by inject()

private val scheduleAlarm: ScheduleAlarm by inject()

Expand All @@ -43,13 +46,16 @@ internal class NotificationFlowTest : KoinTest {
@get:Rule
val disableAnimationsRule = DisableAnimationsRule()

@get:Rule
val runtimePermissionRule = GrantPermissionRule.grant(Manifest.permission.POST_NOTIFICATIONS)

private val context = InstrumentationRegistry.getInstrumentation().targetContext

@Before
fun setup() {
// Clean all existing tasks and categories
runTest {
daoProvider.getTaskDao().cleanTable()
taskDao.cleanTable()
}
composeTestRule.setContent {
NavGraph(windowSizeClass = WindowSizeClassFake.Phone)
Expand Down Expand Up @@ -102,7 +108,7 @@ internal class NotificationFlowTest : KoinTest {
composeTestRule.onNodeWithText(name).assertIsDisplayed()
composeTestRule
.onNodeWithContentDescription(
string(DesignSystemR.string.back_arrow_cd),
"Back",
useUnmergedTree = true,
)
.assertIsDisplayed()
Expand All @@ -114,8 +120,8 @@ internal class NotificationFlowTest : KoinTest {
val task = insertTask(name = "Hi, I'm a PC")
val updatedTitle = "Hi, I'm a Mac"

val updatedTask = task.copy(title = updatedTitle)
daoProvider.getTaskDao().updateTask(updatedTask)
val updatedTask = task.copy(task_title = updatedTitle)
taskDao.updateTask(updatedTask)

// Wait until the notification is launched
val notificationManager = context.getNotificationManager()
Expand All @@ -132,8 +138,8 @@ internal class NotificationFlowTest : KoinTest {
// Insert a task and updated it as "completed"
val task = insertTask(name = "Shhh! I wasn't here!")

val updatedTask = task.copy(completed = true)
daoProvider.getTaskDao().updateTask(updatedTask)
val updatedTask = task.copy(task_is_completed = true)
taskDao.updateTask(updatedTask)

// Wait for 7 seconds
val notificationManager = context.getNotificationManager()
Expand All @@ -160,9 +166,9 @@ internal class NotificationFlowTest : KoinTest {
composeTestRule.waitUntilDoesNotExist(hasText(name))

// Validate the task is now updated as "completed"
val task = daoProvider.getTaskDao().getTaskById(id)
val task = taskDao.getTaskById(id)

assertTrue(task!!.completed)
assertTrue(task!!.task_is_completed)
}

@Test
Expand Down Expand Up @@ -222,24 +228,31 @@ internal class NotificationFlowTest : KoinTest {
id: Long = 15L,
name: String,
calendar: Calendar = Calendar.getInstance(),
): Task =
with(Task(id = id, title = name)) {
calendar.add(Calendar.SECOND, 1)
dueDate = calendar
daoProvider.getTaskDao().insertTask(this)
scheduleAlarm(this.id, this.dueDate!!)
): Task {
val dueDate = calendar.apply { add(Calendar.SECOND, 3) }.toLocalDateTime()
return with(FAKE_TASK.copy(task_id = id, task_title = name, task_due_date = dueDate)) {
taskDao.insertTask(this)
scheduleAlarm(this.task_id, this.task_due_date!!)
this
}
}

private fun insertRepeatingTask(name: String) = runTest {
with(Task(id = 1000, title = name)) {
val dueDate = Calendar.getInstance().apply { add(Calendar.SECOND, 1) }.toLocalDateTime()

with(
FAKE_TASK.copy(
task_id = 1000,
task_title = name,
task_due_date = dueDate,
task_is_repeating = true,
task_alarm_interval = AlarmInterval.HOURLY,
),
) {
val calendar = Calendar.getInstance()
calendar.add(Calendar.SECOND, 2)
dueDate = calendar
isRepeating = true
alarmInterval = AlarmInterval.HOURLY
daoProvider.getTaskDao().insertTask(this)
scheduleAlarm(this.id, this.dueDate!!)
taskDao.insertTask(this)
scheduleAlarm(this.task_id, this.task_due_date!!)
}
}
}
20 changes: 10 additions & 10 deletions app/src/androidTest/java/com/escodro/alkaa/SearchFlowTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import com.escodro.alkaa.fake.FAKE_TASKS
import com.escodro.alkaa.navigation.NavGraph
import com.escodro.alkaa.util.WindowSizeClassFake
import com.escodro.designsystem.AlkaaTheme
import com.escodro.local.provider.DaoProvider
import com.escodro.local.dao.TaskDao
import com.escodro.test.rule.DisableAnimationsRule
import kotlinx.coroutines.test.runTest
import org.junit.Before
Expand All @@ -28,7 +28,7 @@ import com.escodro.search.R as SearchR
@OptIn(ExperimentalTestApi::class)
internal class SearchFlowTest : KoinTest {

private val daoProvider: DaoProvider by inject()
private val taskDao: TaskDao by inject()

@get:Rule
val composeTestRule = createComposeRule()
Expand All @@ -42,10 +42,10 @@ internal class SearchFlowTest : KoinTest {
fun setup() {
runTest {
// Clean all existing tasks
daoProvider.getTaskDao().cleanTable()
taskDao.cleanTable()

// Add some fake tasks
FAKE_TASKS.forEach { task -> daoProvider.getTaskDao().insertTask(task) }
FAKE_TASKS.forEach { task -> taskDao.insertTask(task) }
}

composeTestRule.setContent {
Expand All @@ -64,7 +64,7 @@ internal class SearchFlowTest : KoinTest {
with(composeTestRule) {
FAKE_TASKS.forEach { task ->
// Validate all tasks are shown
onNodeWithText(text = task.title, useUnmergedTree = true).assertExists()
onNodeWithText(text = task.task_title, useUnmergedTree = true).assertExists()
}
}
}
Expand All @@ -73,17 +73,17 @@ internal class SearchFlowTest : KoinTest {
fun test_onlyMatchingQueryIsShown() {
with(composeTestRule) {
// Type the first task as query and validate it is shown in the list
val query = FAKE_TASKS.first().title
val query = FAKE_TASKS.first().task_title
onNode(hasSetTextAction()).performTextInput(query)
onAllNodesWithText(text = query, useUnmergedTree = true)[1].assertExists()

// Wait until the other second item is no longer visible
waitUntilDoesNotExist(hasText(FAKE_TASKS[1].title))
waitUntilDoesNotExist(hasText(FAKE_TASKS[1].task_title))

// Drop the first task and validate others are not shown
FAKE_TASKS.drop(1).forEach { task ->
// Validate all tasks are shown
onNodeWithText(text = task.title, useUnmergedTree = true).assertDoesNotExist()
onNodeWithText(text = task.task_title, useUnmergedTree = true).assertDoesNotExist()
}
}
}
Expand All @@ -94,11 +94,11 @@ internal class SearchFlowTest : KoinTest {
onNode(hasSetTextAction()).performTextInput("query")

// Wait until the first task is not visible
waitUntilDoesNotExist(hasText(FAKE_TASKS[0].title))
waitUntilDoesNotExist(hasText(FAKE_TASKS[0].task_title))

FAKE_TASKS.forEach { task ->
// Validate all tasks are shown
onNodeWithText(text = task.title, useUnmergedTree = true).assertDoesNotExist()
onNodeWithText(text = task.task_title, useUnmergedTree = true).assertDoesNotExist()
}

onNodeWithContentDescription(string(SearchR.string.search_cd_empty_list)).assertExists()
Expand Down
Loading

0 comments on commit 2726164

Please sign in to comment.