From 7fc627d63939da2d1d8b76af3123b342fa59a57d Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Mon, 30 Mar 2026 01:25:40 +0900 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20compose=20=EB=B2=88=EB=93=A4?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A0=84?= =?UTF-8?q?=EC=9A=A9=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit compose 번들에 포함된 compose-ui-test, compose-ui-test-junit4, compose-ui-test-manifest, compose-ui-tooling을 제거하여 테스트 라이브러리가 runtime classpath에 유입되는 문제를 해결한다. 이 라이브러리들은 ComposePlugin과 AndroidTestPlugin에서 이미 올바른 configuration(testImpl, androidTestImpl, debugImpl)으로 추가되고 있으므로 번들에서 제거해도 영향이 없다. --- gradle/libs.versions.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 172e9c247..dd285fd93 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -230,10 +230,6 @@ compose = [ 'compose-material-icons-core', 'compose-material-icons-extended', 'compose-ui', - 'compose-ui-test', - 'compose-ui-test-junit4', - 'compose-ui-test-manifest', - 'compose-ui-tooling', 'compose-ui-tooling-preview', 'androidx-navigation-compose', ] From f4de51e30ce554985a97f4086ae4e81f0c7ed5b6 Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Mon, 30 Mar 2026 01:25:49 +0900 Subject: [PATCH 2/5] =?UTF-8?q?chore:=20androidTest=20=EC=9D=B8=ED=94=84?= =?UTF-8?q?=EB=9D=BC=20=EA=B5=AC=EC=B6=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - HiltTestRunner 추가 (WorkManager 테스트 초기화 포함) - testInstrumentationRunner를 HiltTestRunner로 변경 - work-testing 의존성 추가 - SmokeTest를 삭제된 SplashActivity 대신 HostActivity 기반으로 수정 --- app/build.gradle.kts | 2 + .../com/ku_stacks/ku_ring/HiltTestRunner.kt | 32 ++++++++++++++++ .../kotlin/com/ku_stacks/ku_ring/SmokeTest.kt | 37 +++++++++++++++---- 3 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 app/src/androidTest/kotlin/com/ku_stacks/ku_ring/HiltTestRunner.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 869408005..bada9e639 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -36,6 +36,7 @@ android { defaultConfig { applicationId = "com.ku_stacks.ku_ring" + testInstrumentationRunner = "com.ku_stacks.ku_ring.HiltTestRunner" javaCompileOptions { annotationProcessorOptions { @@ -116,6 +117,7 @@ dependencies { implementation(libs.play.services.auth) androidTestImplementation(libs.androidx.navigation.testing) androidTestImplementation(libs.androidx.espresso.intents) + androidTestImplementation(libs.androidx.work.testing) implementation(platform(libs.firebase.bom)) implementation(libs.firebase.crashlytics.ktx) } diff --git a/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/HiltTestRunner.kt b/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/HiltTestRunner.kt new file mode 100644 index 000000000..2284fab18 --- /dev/null +++ b/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/HiltTestRunner.kt @@ -0,0 +1,32 @@ +package com.ku_stacks.ku_ring + +import android.app.Application +import android.content.Context +import android.util.Log +import androidx.test.runner.AndroidJUnitRunner +import androidx.work.Configuration +import androidx.work.testing.SynchronousExecutor +import androidx.work.testing.WorkManagerTestInitHelper +import dagger.hilt.android.testing.CustomTestApplication + +@CustomTestApplication(KuRingTestApplication::class) +interface HiltTestApp + +open class KuRingTestApplication : Application(), Configuration.Provider { + override val workManagerConfiguration: Configuration + get() = Configuration.Builder() + .setMinimumLoggingLevel(Log.DEBUG) + .setExecutor(SynchronousExecutor()) + .build() + + override fun onCreate() { + super.onCreate() + WorkManagerTestInitHelper.initializeTestWorkManager(this, workManagerConfiguration) + } +} + +class HiltTestRunner : AndroidJUnitRunner() { + override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application { + return super.newApplication(cl, HiltTestApp_Application::class.java.name, context) + } +} diff --git a/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/SmokeTest.kt b/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/SmokeTest.kt index 760c23fa3..a6d1c9fc5 100644 --- a/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/SmokeTest.kt +++ b/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/SmokeTest.kt @@ -1,23 +1,44 @@ package com.ku_stacks.ku_ring import androidx.compose.ui.test.junit4.createAndroidComposeRule -import androidx.compose.ui.test.onNodeWithContentDescription import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.ku_stacks.ku_ring.splash.SplashActivity +import com.ku_stacks.ku_ring.navigation.Navigator +import com.ku_stacks.ku_ring.navigation.keys.SplashKey +import dagger.hilt.android.testing.HiltAndroidRule +import dagger.hilt.android.testing.HiltAndroidTest +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import javax.inject.Inject +@HiltAndroidTest @RunWith(AndroidJUnit4::class) class SmokeTest { - @get:Rule - val composeTestRule = createAndroidComposeRule() + @get:Rule(order = 0) + val hiltRule = HiltAndroidRule(this) + + @get:Rule(order = 1) + val composeTestRule = createAndroidComposeRule() + + @Inject + lateinit var navigator: Navigator + + @Before + fun setup() { + hiltRule.inject() + } + + @Test + fun 앱이_실행되면_HostActivity가_정상적으로_생성된다() { + assertTrue(composeTestRule.activity is HostActivity) + } @Test - fun testAppLaunch() { - composeTestRule - .onNodeWithContentDescription("스플래시 화면") - .assertExists() + fun 앱이_실행되면_초기_백스택에_SplashKey가_존재한다() { + assertEquals(SplashKey, navigator.backStack.first()) } } From 5819680fea0880d7358881adc7be796b823066db Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Mon, 30 Mar 2026 01:25:55 +0900 Subject: [PATCH 3/5] =?UTF-8?q?refactor:=20extractNavKey=EB=A5=BC=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B0=80=EB=8A=A5=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20companion=20object=EB=A1=9C=20=EC=B6=94?= =?UTF-8?q?=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 딥링크 Intent 파싱 로직을 companion object의 @VisibleForTesting 함수로 추출하여 단위 테스트가 가능하도록 한다. --- .../com/ku_stacks/ku_ring/HostActivity.kt | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/ku_stacks/ku_ring/HostActivity.kt b/app/src/main/java/com/ku_stacks/ku_ring/HostActivity.kt index 846e5b98e..192c03135 100644 --- a/app/src/main/java/com/ku_stacks/ku_ring/HostActivity.kt +++ b/app/src/main/java/com/ku_stacks/ku_ring/HostActivity.kt @@ -17,6 +17,7 @@ import com.ku_stacks.ku_ring.navigation.DeepLinkIntentFactory import com.ku_stacks.ku_ring.navigation.Navigator import com.ku_stacks.ku_ring.navigation.keys.MainHubKey import com.ku_stacks.ku_ring.navigation.keys.NoticeWebKey +import androidx.annotation.VisibleForTesting import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @@ -73,29 +74,35 @@ class HostActivity : ComponentActivity() { } } - private fun extractNavKey(intent: Intent): NavKey? { - // WebViewNotice가 Intent extras에 있으면 해당 화면으로 이동 - val webViewNotice = IntentCompat.getSerializableExtra( - intent, - WebViewNotice.EXTRA_KEY, - WebViewNotice::class.java, - ) - if (webViewNotice != null) { - return NoticeWebKey( - url = webViewNotice.url, - articleId = webViewNotice.articleId, - id = webViewNotice.id.toString(), - category = webViewNotice.category, - subject = webViewNotice.subject, + private fun extractNavKey(intent: Intent): NavKey? = + extractNavKeyFromIntent(intent) + + companion object { + @VisibleForTesting + internal fun extractNavKeyFromIntent(intent: Intent): NavKey? { + // WebViewNotice가 Intent extras에 있으면 해당 화면으로 이동 + val webViewNotice = IntentCompat.getSerializableExtra( + intent, + WebViewNotice.EXTRA_KEY, + WebViewNotice::class.java, ) - } + if (webViewNotice != null) { + return NoticeWebKey( + url = webViewNotice.url, + articleId = webViewNotice.articleId, + id = webViewNotice.id.toString(), + category = webViewNotice.category, + subject = webViewNotice.subject, + ) + } - // MainScreenRoute가 Intent extras에 있으면 해당 탭으로 이동 - val route = intent.getStringExtra(DeepLinkIntentFactory.INTENT_KEY_ROUTE) - if (route != null) { - return MainHubKey(startTab = route) - } + // MainScreenRoute가 Intent extras에 있으면 해당 탭으로 이동 + val route = intent.getStringExtra(DeepLinkIntentFactory.INTENT_KEY_ROUTE) + if (route != null) { + return MainHubKey(startTab = route) + } - return null + return null + } } } From dd37a0867e23961fa9bfc70445a901eb7239d88c Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Mon, 30 Mar 2026 01:26:03 +0900 Subject: [PATCH 4/5] =?UTF-8?q?test:=20Navigation3=20=EB=A7=88=EC=9D=B4?= =?UTF-8?q?=EA=B7=B8=EB=A0=88=EC=9D=B4=EC=85=98=20E2E=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=B0=8F=20=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit develop 브랜치 기준의 화면이동 스펙을 검증하는 테스트를 추가한다. - NavigatorTest: 백스택 동작 및 네비게이션 경로 검증 (16개) - ExtractNavKeyTest: 딥링크 Intent 파싱 로직 검증 (6개) - NavigationE2ETest: HostActivity 기반 E2E 네비게이션 경로 검증 (18개) - SmokeTest: 앱 실행 및 초기화 검증 (2개) --- .../ku_stacks/ku_ring/NavigationE2ETest.kt | 316 ++++++++++++++++++ .../ku_stacks/ku_ring/ExtractNavKeyTest.kt | 114 +++++++ core/navigation/build.gradle.kts | 1 + .../ku_ring/navigation/NavigatorTest.kt | 228 +++++++++++++ 4 files changed, 659 insertions(+) create mode 100644 app/src/androidTest/kotlin/com/ku_stacks/ku_ring/NavigationE2ETest.kt create mode 100644 app/src/test/java/com/ku_stacks/ku_ring/ExtractNavKeyTest.kt create mode 100644 core/navigation/src/test/java/com/ku_stacks/ku_ring/navigation/NavigatorTest.kt diff --git a/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/NavigationE2ETest.kt b/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/NavigationE2ETest.kt new file mode 100644 index 000000000..6674114e1 --- /dev/null +++ b/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/NavigationE2ETest.kt @@ -0,0 +1,316 @@ +package com.ku_stacks.ku_ring + +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.ku_stacks.ku_ring.navigation.Navigator +import com.ku_stacks.ku_ring.navigation.keys.ArchiveKey +import com.ku_stacks.ku_ring.navigation.keys.ClubDetailKey +import com.ku_stacks.ku_ring.navigation.keys.ClubSubscriptionKey +import com.ku_stacks.ku_ring.navigation.keys.EditDepartmentsKey +import com.ku_stacks.ku_ring.navigation.keys.EditSubscriptionKey +import com.ku_stacks.ku_ring.navigation.keys.FeedbackKey +import com.ku_stacks.ku_ring.navigation.keys.LibrarySeatKey +import com.ku_stacks.ku_ring.navigation.keys.MainHubKey +import com.ku_stacks.ku_ring.navigation.keys.NoticeWebKey +import com.ku_stacks.ku_ring.navigation.keys.NotificationKey +import com.ku_stacks.ku_ring.navigation.keys.OpenSourceKey +import com.ku_stacks.ku_ring.navigation.keys.SearchKey +import com.ku_stacks.ku_ring.navigation.keys.SplashKey +import dagger.hilt.android.testing.HiltAndroidRule +import dagger.hilt.android.testing.HiltAndroidTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import javax.inject.Inject + +/** + * Navigation3 마이그레이션 E2E 테스트. + * + * develop 브랜치 기준의 모든 화면이동 스펙이 현재 브랜치에서도 동일하게 동작하는지 검증한다. + * HostActivity + NavDisplay + Navigator 기반의 실제 앱 환경에서 테스트한다. + */ +@HiltAndroidTest +@RunWith(AndroidJUnit4::class) +class NavigationE2ETest { + + @get:Rule(order = 0) + val hiltRule = HiltAndroidRule(this) + + @get:Rule(order = 1) + val composeTestRule = createAndroidComposeRule() + + @Inject + lateinit var navigator: Navigator + + @Before + fun setup() { + hiltRule.inject() + } + + // --- 앱 실행 --- + + @Test + fun 앱이_실행되면_SplashKey가_초기_백스택에_존재한다() { + assertEquals(SplashKey, navigator.backStack.first()) + } + + // --- 공지 탭 네비게이션 --- + + @Test + fun 스플래시에서_메인허브로_이동하면_MainHubKey가_백스택에_존재한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + } + composeTestRule.waitForIdle() + + assertEquals(1, navigator.backStack.size) + assertEquals(MainHubKey(), navigator.backStack.first()) + } + + @Test + fun 공지_탭에서_검색으로_이동하면_SearchKey가_백스택_최상단에_위치한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(SearchKey) + } + composeTestRule.waitForIdle() + + assertEquals(2, navigator.backStack.size) + assertEquals(SearchKey, navigator.backStack.last()) + } + + @Test + fun 공지_탭에서_아카이브로_이동하면_ArchiveKey가_백스택_최상단에_위치한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(ArchiveKey) + } + composeTestRule.waitForIdle() + + assertEquals(2, navigator.backStack.size) + assertEquals(ArchiveKey, navigator.backStack.last()) + } + + @Test + fun 공지_탭에서_알림_목록으로_이동하면_NotificationKey가_백스택_최상단에_위치한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(NotificationKey) + } + composeTestRule.waitForIdle() + + assertEquals(2, navigator.backStack.size) + assertEquals(NotificationKey, navigator.backStack.last()) + } + + @Test + fun 공지_탭에서_공지_상세로_이동하면_NoticeWebKey가_백스택_최상단에_위치한다() { + val noticeKey = NoticeWebKey( + url = "https://kuring.com/notice/1", + articleId = "art1", + id = "1", + category = "학사", + subject = "테스트공지", + ) + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(noticeKey) + } + composeTestRule.waitForIdle() + + assertEquals(2, navigator.backStack.size) + assertEquals(noticeKey, navigator.backStack.last()) + } + + @Test + fun 공지_탭에서_학과_편집으로_이동하면_EditDepartmentsKey가_백스택_최상단에_위치한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(EditDepartmentsKey) + + assertEquals(2, navigator.backStack.size) + assertEquals(EditDepartmentsKey, navigator.backStack.last()) + } + } + + // --- 동아리 탭 네비게이션 --- + + @Test + fun 동아리_탭에서_구독_관리로_이동하면_ClubSubscriptionKey가_백스택_최상단에_위치한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(ClubSubscriptionKey) + } + composeTestRule.waitForIdle() + + assertEquals(2, navigator.backStack.size) + assertEquals(ClubSubscriptionKey, navigator.backStack.last()) + } + + @Test + fun 동아리_탭에서_동아리_상세로_이동하면_ClubDetailKey가_백스택_최상단에_위치한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(ClubDetailKey(clubId = 42)) + + assertEquals(2, navigator.backStack.size) + assertEquals(ClubDetailKey(clubId = 42), navigator.backStack.last()) + } + } + + // --- 설정 탭 네비게이션 --- + + @Test + fun 설정에서_오픈소스_화면으로_이동하면_OpenSourceKey가_백스택_최상단에_위치한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(OpenSourceKey) + } + composeTestRule.waitForIdle() + + assertEquals(2, navigator.backStack.size) + assertEquals(OpenSourceKey, navigator.backStack.last()) + } + + @Test + fun 설정에서_피드백_화면으로_이동하면_FeedbackKey가_백스택_최상단에_위치한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(FeedbackKey) + } + composeTestRule.waitForIdle() + + assertEquals(2, navigator.backStack.size) + assertEquals(FeedbackKey, navigator.backStack.last()) + } + + // --- 캠퍼스맵 탭 네비게이션 --- + + @Test + fun 캠퍼스맵에서_열람실_좌석으로_이동하면_LibrarySeatKey가_백스택_최상단에_위치한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(LibrarySeatKey) + } + composeTestRule.waitForIdle() + + assertEquals(2, navigator.backStack.size) + assertEquals(LibrarySeatKey, navigator.backStack.last()) + } + + // --- 중첩 네비게이션 --- + + @Test + fun 알림_목록에서_구독_편집으로_이동하면_올바른_백스택_순서가_유지된다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(NotificationKey) + navigator.navigate(EditSubscriptionKey) + } + composeTestRule.waitForIdle() + + assertEquals(3, navigator.backStack.size) + assertEquals(MainHubKey(), navigator.backStack[0]) + assertEquals(NotificationKey, navigator.backStack[1]) + assertEquals(EditSubscriptionKey, navigator.backStack[2]) + } + + @Test + fun 구독_편집에서_학과_편집으로_이동하면_올바른_백스택_순서가_유지된다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(EditSubscriptionKey) + navigator.navigate(EditDepartmentsKey) + + assertEquals(3, navigator.backStack.size) + assertEquals(EditSubscriptionKey, navigator.backStack[1]) + assertEquals(EditDepartmentsKey, navigator.backStack[2]) + } + } + + // --- 뒤로가기 --- + + @Test + fun 상세_화면에서_뒤로가기를_하면_이전_화면으로_복원된다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + navigator.navigate(SearchKey) + navigator.navigate(NoticeWebKey("url", "art1", "1", "일반", "제목")) + } + composeTestRule.waitForIdle() + assertEquals(3, navigator.backStack.size) + + composeTestRule.runOnUiThread { navigator.goBack() } + composeTestRule.waitForIdle() + assertEquals(SearchKey, navigator.backStack.last()) + + composeTestRule.runOnUiThread { navigator.goBack() } + composeTestRule.waitForIdle() + assertEquals(MainHubKey(), navigator.backStack.last()) + } + + @Test + fun 백스택에_항목이_하나만_남으면_뒤로가기가_실패한다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + } + composeTestRule.waitForIdle() + + composeTestRule.runOnUiThread { + val result = navigator.goBack() + assertEquals(false, result) + } + composeTestRule.waitForIdle() + + assertEquals(1, navigator.backStack.size) + assertEquals(MainHubKey(), navigator.backStack.first()) + } + + // --- 딥링크 --- + + @Test + fun FCM_콜드_스타트_시_pendingDeepLink가_스플래시_완료_후_적용된다() { + val noticeKey = NoticeWebKey( + url = "https://kuring.com/notice/fcm", + articleId = "fcm123", + id = "99", + category = "장학", + subject = "FCM딥링크테스트", + ) + + composeTestRule.runOnUiThread { + navigator.setPendingDeepLink(noticeKey) + navigator.replaceAll(MainHubKey()) + } + composeTestRule.waitForIdle() + + assertEquals(2, navigator.backStack.size) + assertEquals(MainHubKey(), navigator.backStack[0]) + assertEquals(noticeKey, navigator.backStack[1]) + } + + @Test + fun FCM_웜_스타트_시_직접_navigate하면_해당_화면이_백스택에_추가된다() { + composeTestRule.runOnUiThread { + navigator.replaceAll(MainHubKey()) + } + composeTestRule.waitForIdle() + + val noticeKey = NoticeWebKey( + url = "https://kuring.com/notice/warm", + articleId = "warm456", + id = "77", + category = "일반", + subject = "웜스타트딥링크", + ) + composeTestRule.runOnUiThread { + navigator.navigate(noticeKey) + } + composeTestRule.waitForIdle() + + assertEquals(2, navigator.backStack.size) + assertEquals(noticeKey, navigator.backStack.last()) + } +} diff --git a/app/src/test/java/com/ku_stacks/ku_ring/ExtractNavKeyTest.kt b/app/src/test/java/com/ku_stacks/ku_ring/ExtractNavKeyTest.kt new file mode 100644 index 000000000..343f1f4b3 --- /dev/null +++ b/app/src/test/java/com/ku_stacks/ku_ring/ExtractNavKeyTest.kt @@ -0,0 +1,114 @@ +package com.ku_stacks.ku_ring + +import android.app.Application +import android.content.Intent +import com.ku_stacks.ku_ring.domain.WebViewNotice +import com.ku_stacks.ku_ring.navigation.DeepLinkIntentFactory +import com.ku_stacks.ku_ring.navigation.keys.MainHubKey +import com.ku_stacks.ku_ring.navigation.keys.NoticeWebKey +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(application = Application::class) +class ExtractNavKeyTest { + + @Test + fun `빈 Intent를 전달하면 null을 반환한다`() { + val intent = Intent() + val result = HostActivity.extractNavKeyFromIntent(intent) + assertNull(result) + } + + @Test + fun `WebViewNotice가 포함된 Intent를 전달하면 NoticeWebKey를 반환한다`() { + val notice = WebViewNotice( + url = "https://kuring.com/notice/123", + articleId = "article123", + id = 42, + category = "학사", + subject = "긴급공지", + ) + val intent = Intent().apply { + putExtra(WebViewNotice.EXTRA_KEY, notice) + } + + val result = HostActivity.extractNavKeyFromIntent(intent) + + assertEquals( + NoticeWebKey( + url = "https://kuring.com/notice/123", + articleId = "article123", + id = "42", + category = "학사", + subject = "긴급공지", + ), + result, + ) + } + + @Test + fun `MainScreenRoute 문자열이 포함된 Intent를 전달하면 MainHubKey를 반환한다`() { + val intent = Intent().apply { + putExtra(DeepLinkIntentFactory.INTENT_KEY_ROUTE, "Calendar") + } + + val result = HostActivity.extractNavKeyFromIntent(intent) + + assertEquals(MainHubKey(startTab = "Calendar"), result) + } + + @Test + fun `WebViewNotice와 Route가 모두 포함되면 WebViewNotice가 우선 적용된다`() { + val notice = WebViewNotice( + url = "https://kuring.com/notice/1", + articleId = "art1", + id = 1, + category = "일반", + subject = "제목", + ) + val intent = Intent().apply { + putExtra(WebViewNotice.EXTRA_KEY, notice) + putExtra(DeepLinkIntentFactory.INTENT_KEY_ROUTE, "Calendar") + } + + val result = HostActivity.extractNavKeyFromIntent(intent) + + assertEquals( + NoticeWebKey( + url = "https://kuring.com/notice/1", + articleId = "art1", + id = "1", + category = "일반", + subject = "제목", + ), + result, + ) + } + + @Test + fun `Notice 탭 Route를 전달하면 Notice startTab의 MainHubKey를 반환한다`() { + val intent = Intent().apply { + putExtra(DeepLinkIntentFactory.INTENT_KEY_ROUTE, "Notice") + } + + val result = HostActivity.extractNavKeyFromIntent(intent) + + assertEquals(MainHubKey(startTab = "Notice"), result) + } + + @Test + fun `Club 탭 Route를 전달하면 Club startTab의 MainHubKey를 반환한다`() { + val intent = Intent().apply { + putExtra(DeepLinkIntentFactory.INTENT_KEY_ROUTE, "Club") + } + + val result = HostActivity.extractNavKeyFromIntent(intent) + + assertEquals(MainHubKey(startTab = "Club"), result) + } +} diff --git a/core/navigation/build.gradle.kts b/core/navigation/build.gradle.kts index 30a928573..e618b404a 100644 --- a/core/navigation/build.gradle.kts +++ b/core/navigation/build.gradle.kts @@ -2,6 +2,7 @@ import com.ku_stacks.ku_ring.buildlogic.dsl.setNameSpace plugins { kuring("feature") + kuringPrimitive("test") } android { diff --git a/core/navigation/src/test/java/com/ku_stacks/ku_ring/navigation/NavigatorTest.kt b/core/navigation/src/test/java/com/ku_stacks/ku_ring/navigation/NavigatorTest.kt new file mode 100644 index 000000000..0ed6c9478 --- /dev/null +++ b/core/navigation/src/test/java/com/ku_stacks/ku_ring/navigation/NavigatorTest.kt @@ -0,0 +1,228 @@ +package com.ku_stacks.ku_ring.navigation + +import com.ku_stacks.ku_ring.navigation.keys.ArchiveKey +import com.ku_stacks.ku_ring.navigation.keys.EditDepartmentsKey +import com.ku_stacks.ku_ring.navigation.keys.EditSubscriptionKey +import com.ku_stacks.ku_ring.navigation.keys.FeedbackKey +import com.ku_stacks.ku_ring.navigation.keys.MainHubKey +import com.ku_stacks.ku_ring.navigation.keys.NoticeWebKey +import com.ku_stacks.ku_ring.navigation.keys.NotificationKey +import com.ku_stacks.ku_ring.navigation.keys.SearchKey +import com.ku_stacks.ku_ring.navigation.keys.SplashKey +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class NavigatorTest { + + private lateinit var navigator: Navigator + + @Before + fun setup() { + navigator = Navigator() + } + + // --- 기본 백스택 동작 --- + + @Test + fun `Navigator가 생성되면 SplashKey가 초기 백스택에 존재한다`() { + assertEquals(1, navigator.backStack.size) + assertEquals(SplashKey, navigator.backStack.first()) + } + + @Test + fun `navigate를 호출하면 백스택에 해당 키가 추가된다`() { + navigator.navigate(MainHubKey()) + + assertEquals(2, navigator.backStack.size) + assertEquals(MainHubKey(), navigator.backStack.last()) + } + + @Test + fun `여러 화면을 순차적으로 navigate하면 올바른 순서로 백스택이 쌓인다`() { + navigator.navigate(MainHubKey()) + navigator.navigate(SearchKey) + navigator.navigate(NoticeWebKey("url", "art1", "1", "일반", "제목")) + + assertEquals(4, navigator.backStack.size) + assertEquals(SplashKey, navigator.backStack[0]) + assertEquals(MainHubKey(), navigator.backStack[1]) + assertEquals(SearchKey, navigator.backStack[2]) + assertEquals( + NoticeWebKey("url", "art1", "1", "일반", "제목"), + navigator.backStack[3], + ) + } + + @Test + fun `goBack을 호출하면 마지막 항목이 제거되고 true를 반환한다`() { + navigator.navigate(MainHubKey()) + navigator.navigate(SearchKey) + + val result = navigator.goBack() + + assertTrue(result) + assertEquals(2, navigator.backStack.size) + assertEquals(MainHubKey(), navigator.backStack.last()) + } + + @Test + fun `백스택에 항목이 하나만 남으면 goBack은 false를 반환한다`() { + val result = navigator.goBack() + + assertFalse(result) + assertEquals(1, navigator.backStack.size) + assertEquals(SplashKey, navigator.backStack.first()) + } + + @Test + fun `replaceAll을 호출하면 백스택이 새 키 하나로 교체된다`() { + navigator.navigate(MainHubKey()) + navigator.navigate(SearchKey) + + navigator.replaceAll(MainHubKey()) + + assertEquals(1, navigator.backStack.size) + assertEquals(MainHubKey(), navigator.backStack.first()) + } + + // --- 딥링크 --- + + @Test + fun `setPendingDeepLink 후 replaceAll하면 딥링크 키가 백스택에 추가된다`() { + val deepLinkKey = NoticeWebKey("url", "art1", "1", "일반", "제목") + navigator.setPendingDeepLink(deepLinkKey) + + navigator.replaceAll(MainHubKey()) + + assertEquals(2, navigator.backStack.size) + assertEquals(MainHubKey(), navigator.backStack[0]) + assertEquals(deepLinkKey, navigator.backStack[1]) + } + + @Test + fun `replaceAll 이후 pendingDeepLink는 소비되어 다음 replaceAll에 영향을 주지 않는다`() { + val deepLinkKey = NoticeWebKey("url", "art1", "1", "일반", "제목") + navigator.setPendingDeepLink(deepLinkKey) + + navigator.replaceAll(MainHubKey()) + navigator.replaceAll(MainHubKey()) + + assertEquals(1, navigator.backStack.size) + assertEquals(MainHubKey(), navigator.backStack.first()) + } + + // --- develop 브랜치 기준 네비게이션 경로 검증 --- + + @Test + fun `공지 탭에서 검색 화면으로 이동하면 SearchKey가 백스택 최상단에 위치한다`() { + navigator.replaceAll(MainHubKey()) + navigator.navigate(SearchKey) + + assertEquals(SearchKey, navigator.backStack.last()) + } + + @Test + fun `공지 탭에서 아카이브 화면으로 이동하면 ArchiveKey가 백스택 최상단에 위치한다`() { + navigator.replaceAll(MainHubKey()) + navigator.navigate(ArchiveKey) + + assertEquals(ArchiveKey, navigator.backStack.last()) + } + + @Test + fun `공지 탭에서 알림 목록으로 이동하면 NotificationKey가 백스택 최상단에 위치한다`() { + navigator.replaceAll(MainHubKey()) + navigator.navigate(NotificationKey) + + assertEquals(NotificationKey, navigator.backStack.last()) + } + + @Test + fun `공지 탭에서 공지 상세로 이동하면 NoticeWebKey가 백스택 최상단에 위치한다`() { + navigator.replaceAll(MainHubKey()) + val noticeKey = NoticeWebKey("https://example.com", "article1", "1", "일반", "공지제목") + navigator.navigate(noticeKey) + + assertEquals(noticeKey, navigator.backStack.last()) + } + + @Test + fun `공지 탭에서 학과 편집으로 이동하면 EditDepartmentsKey가 백스택 최상단에 위치한다`() { + navigator.replaceAll(MainHubKey()) + navigator.navigate(EditDepartmentsKey) + + assertEquals(EditDepartmentsKey, navigator.backStack.last()) + } + + @Test + fun `알림 목록에서 구독 편집으로 이동하면 올바른 백스택 순서가 유지된다`() { + navigator.replaceAll(MainHubKey()) + navigator.navigate(NotificationKey) + navigator.navigate(EditSubscriptionKey) + + assertEquals(3, navigator.backStack.size) + assertEquals(EditSubscriptionKey, navigator.backStack.last()) + } + + @Test + fun `구독 편집에서 학과 편집으로 이동하면 올바른 백스택 순서가 유지된다`() { + navigator.replaceAll(MainHubKey()) + navigator.navigate(EditSubscriptionKey) + navigator.navigate(EditDepartmentsKey) + + assertEquals(3, navigator.backStack.size) + assertEquals(EditDepartmentsKey, navigator.backStack.last()) + } + + @Test + fun `상세 화면에서 뒤로가기를 하면 이전 화면으로 복원된다`() { + navigator.replaceAll(MainHubKey()) + navigator.navigate(SearchKey) + navigator.navigate(NoticeWebKey("url", "a", "1", "c", "s")) + + navigator.goBack() + assertEquals(SearchKey, navigator.backStack.last()) + + navigator.goBack() + assertEquals(MainHubKey(), navigator.backStack.last()) + } + + @Test + fun `설정에서 피드백 화면으로 이동 후 뒤로가기하면 메인 허브로 돌아간다`() { + navigator.replaceAll(MainHubKey()) + navigator.navigate(FeedbackKey) + + assertEquals(FeedbackKey, navigator.backStack.last()) + navigator.goBack() + assertEquals(MainHubKey(), navigator.backStack.last()) + } + + @Test + fun `FCM 콜드 스타트 시 pendingDeepLink가 스플래시 완료 후 적용된다`() { + val noticeKey = NoticeWebKey("https://kuring.com/notice", "art123", "42", "학사", "긴급공지") + navigator.setPendingDeepLink(noticeKey) + + navigator.replaceAll(MainHubKey()) + + assertEquals(2, navigator.backStack.size) + assertEquals(MainHubKey(), navigator.backStack[0]) + assertEquals(noticeKey, navigator.backStack[1]) + } + + @Test + fun `웜 스타트 시 직접 navigate하면 해당 화면이 백스택에 추가된다`() { + navigator.replaceAll(MainHubKey()) + + val noticeKey = NoticeWebKey("https://kuring.com/notice", "art456", "99", "장학", "장학금안내") + navigator.navigate(noticeKey) + + assertEquals(2, navigator.backStack.size) + assertEquals(noticeKey, navigator.backStack.last()) + } +} From 6fb1a482e34458d007077a84fcc1908235c2faed Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Mon, 30 Mar 2026 01:34:23 +0900 Subject: [PATCH 5/5] =?UTF-8?q?chore:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=EB=A5=BC=20=EA=B1=B4?= =?UTF-8?q?=EA=B5=AD=EB=8C=80=ED=95=99=EA=B5=90=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EA=B8=B0=EB=B0=98=20=EC=9C=A0=EC=9D=98?= =?UTF-8?q?=EB=AF=B8=ED=95=9C=20=EA=B0=92=EC=9C=BC=EB=A1=9C=20=EA=B5=90?= =?UTF-8?q?=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NoticeWebKey, WebViewNotice 등의 테스트 파라미터를 실제 건국대학교 공지사항 URL 형식과 카테고리(학사, 장학, 일반 등)에 맞는 값으로 교체한다. --- .../ku_stacks/ku_ring/NavigationE2ETest.kt | 40 +++++++----- .../ku_stacks/ku_ring/ExtractNavKeyTest.kt | 32 +++++----- .../ku_ring/navigation/NavigatorTest.kt | 64 +++++++++++++++---- 3 files changed, 93 insertions(+), 43 deletions(-) diff --git a/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/NavigationE2ETest.kt b/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/NavigationE2ETest.kt index 6674114e1..5a78e822f 100644 --- a/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/NavigationE2ETest.kt +++ b/app/src/androidTest/kotlin/com/ku_stacks/ku_ring/NavigationE2ETest.kt @@ -108,11 +108,11 @@ class NavigationE2ETest { @Test fun 공지_탭에서_공지_상세로_이동하면_NoticeWebKey가_백스택_최상단에_위치한다() { val noticeKey = NoticeWebKey( - url = "https://kuring.com/notice/1", - articleId = "art1", - id = "1", + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=5a206c73", + articleId = "5a206c73", + id = "20240315001", category = "학사", - subject = "테스트공지", + subject = "2024학년도 1학기 수강신청 안내", ) composeTestRule.runOnUiThread { navigator.replaceAll(MainHubKey()) @@ -153,10 +153,10 @@ class NavigationE2ETest { fun 동아리_탭에서_동아리_상세로_이동하면_ClubDetailKey가_백스택_최상단에_위치한다() { composeTestRule.runOnUiThread { navigator.replaceAll(MainHubKey()) - navigator.navigate(ClubDetailKey(clubId = 42)) + navigator.navigate(ClubDetailKey(clubId = 1)) assertEquals(2, navigator.backStack.size) - assertEquals(ClubDetailKey(clubId = 42), navigator.backStack.last()) + assertEquals(ClubDetailKey(clubId = 1), navigator.backStack.last()) } } @@ -237,7 +237,15 @@ class NavigationE2ETest { composeTestRule.runOnUiThread { navigator.replaceAll(MainHubKey()) navigator.navigate(SearchKey) - navigator.navigate(NoticeWebKey("url", "art1", "1", "일반", "제목")) + navigator.navigate( + NoticeWebKey( + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=7b3e9f12", + articleId = "7b3e9f12", + id = "20240401005", + category = "일반", + subject = "2024학년도 건국대학교 학생생활관 입사 안내", + ) + ) } composeTestRule.waitForIdle() assertEquals(3, navigator.backStack.size) @@ -273,11 +281,11 @@ class NavigationE2ETest { @Test fun FCM_콜드_스타트_시_pendingDeepLink가_스플래시_완료_후_적용된다() { val noticeKey = NoticeWebKey( - url = "https://kuring.com/notice/fcm", - articleId = "fcm123", - id = "99", + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=a1c2d3e4", + articleId = "a1c2d3e4", + id = "20240520012", category = "장학", - subject = "FCM딥링크테스트", + subject = "2024학년도 2학기 국가장학금 신청 안내", ) composeTestRule.runOnUiThread { @@ -299,11 +307,11 @@ class NavigationE2ETest { composeTestRule.waitForIdle() val noticeKey = NoticeWebKey( - url = "https://kuring.com/notice/warm", - articleId = "warm456", - id = "77", - category = "일반", - subject = "웜스타트딥링크", + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=f5e6d7c8", + articleId = "f5e6d7c8", + id = "20240601003", + category = "취창업", + subject = "2024 건국대학교 취업박람회 참가 신청 안내", ) composeTestRule.runOnUiThread { navigator.navigate(noticeKey) diff --git a/app/src/test/java/com/ku_stacks/ku_ring/ExtractNavKeyTest.kt b/app/src/test/java/com/ku_stacks/ku_ring/ExtractNavKeyTest.kt index 343f1f4b3..00486b8bb 100644 --- a/app/src/test/java/com/ku_stacks/ku_ring/ExtractNavKeyTest.kt +++ b/app/src/test/java/com/ku_stacks/ku_ring/ExtractNavKeyTest.kt @@ -27,11 +27,11 @@ class ExtractNavKeyTest { @Test fun `WebViewNotice가 포함된 Intent를 전달하면 NoticeWebKey를 반환한다`() { val notice = WebViewNotice( - url = "https://kuring.com/notice/123", - articleId = "article123", - id = 42, + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=5a206c73", + articleId = "5a206c73", + id = 20240315, category = "학사", - subject = "긴급공지", + subject = "2024학년도 1학기 수강신청 안내", ) val intent = Intent().apply { putExtra(WebViewNotice.EXTRA_KEY, notice) @@ -41,11 +41,11 @@ class ExtractNavKeyTest { assertEquals( NoticeWebKey( - url = "https://kuring.com/notice/123", - articleId = "article123", - id = "42", + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=5a206c73", + articleId = "5a206c73", + id = "20240315", category = "학사", - subject = "긴급공지", + subject = "2024학년도 1학기 수강신청 안내", ), result, ) @@ -65,11 +65,11 @@ class ExtractNavKeyTest { @Test fun `WebViewNotice와 Route가 모두 포함되면 WebViewNotice가 우선 적용된다`() { val notice = WebViewNotice( - url = "https://kuring.com/notice/1", - articleId = "art1", - id = 1, + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=7b3e9f12", + articleId = "7b3e9f12", + id = 20240401, category = "일반", - subject = "제목", + subject = "2024학년도 건국대학교 학생생활관 입사 안내", ) val intent = Intent().apply { putExtra(WebViewNotice.EXTRA_KEY, notice) @@ -80,11 +80,11 @@ class ExtractNavKeyTest { assertEquals( NoticeWebKey( - url = "https://kuring.com/notice/1", - articleId = "art1", - id = "1", + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=7b3e9f12", + articleId = "7b3e9f12", + id = "20240401", category = "일반", - subject = "제목", + subject = "2024학년도 건국대학교 학생생활관 입사 안내", ), result, ) diff --git a/core/navigation/src/test/java/com/ku_stacks/ku_ring/navigation/NavigatorTest.kt b/core/navigation/src/test/java/com/ku_stacks/ku_ring/navigation/NavigatorTest.kt index 0ed6c9478..22c4d5721 100644 --- a/core/navigation/src/test/java/com/ku_stacks/ku_ring/navigation/NavigatorTest.kt +++ b/core/navigation/src/test/java/com/ku_stacks/ku_ring/navigation/NavigatorTest.kt @@ -47,16 +47,20 @@ class NavigatorTest { fun `여러 화면을 순차적으로 navigate하면 올바른 순서로 백스택이 쌓인다`() { navigator.navigate(MainHubKey()) navigator.navigate(SearchKey) - navigator.navigate(NoticeWebKey("url", "art1", "1", "일반", "제목")) + val noticeKey = NoticeWebKey( + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=5a206c73", + articleId = "5a206c73", + id = "20240315001", + category = "학사", + subject = "2024학년도 1학기 수강신청 안내", + ) + navigator.navigate(noticeKey) assertEquals(4, navigator.backStack.size) assertEquals(SplashKey, navigator.backStack[0]) assertEquals(MainHubKey(), navigator.backStack[1]) assertEquals(SearchKey, navigator.backStack[2]) - assertEquals( - NoticeWebKey("url", "art1", "1", "일반", "제목"), - navigator.backStack[3], - ) + assertEquals(noticeKey, navigator.backStack[3]) } @Test @@ -95,7 +99,13 @@ class NavigatorTest { @Test fun `setPendingDeepLink 후 replaceAll하면 딥링크 키가 백스택에 추가된다`() { - val deepLinkKey = NoticeWebKey("url", "art1", "1", "일반", "제목") + val deepLinkKey = NoticeWebKey( + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=a1c2d3e4", + articleId = "a1c2d3e4", + id = "20240520012", + category = "장학", + subject = "2024학년도 2학기 국가장학금 신청 안내", + ) navigator.setPendingDeepLink(deepLinkKey) navigator.replaceAll(MainHubKey()) @@ -107,7 +117,13 @@ class NavigatorTest { @Test fun `replaceAll 이후 pendingDeepLink는 소비되어 다음 replaceAll에 영향을 주지 않는다`() { - val deepLinkKey = NoticeWebKey("url", "art1", "1", "일반", "제목") + val deepLinkKey = NoticeWebKey( + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=a1c2d3e4", + articleId = "a1c2d3e4", + id = "20240520012", + category = "장학", + subject = "2024학년도 2학기 국가장학금 신청 안내", + ) navigator.setPendingDeepLink(deepLinkKey) navigator.replaceAll(MainHubKey()) @@ -146,7 +162,13 @@ class NavigatorTest { @Test fun `공지 탭에서 공지 상세로 이동하면 NoticeWebKey가 백스택 최상단에 위치한다`() { navigator.replaceAll(MainHubKey()) - val noticeKey = NoticeWebKey("https://example.com", "article1", "1", "일반", "공지제목") + val noticeKey = NoticeWebKey( + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=7b3e9f12", + articleId = "7b3e9f12", + id = "20240401005", + category = "일반", + subject = "2024학년도 건국대학교 학생생활관 입사 안내", + ) navigator.navigate(noticeKey) assertEquals(noticeKey, navigator.backStack.last()) @@ -184,7 +206,15 @@ class NavigatorTest { fun `상세 화면에서 뒤로가기를 하면 이전 화면으로 복원된다`() { navigator.replaceAll(MainHubKey()) navigator.navigate(SearchKey) - navigator.navigate(NoticeWebKey("url", "a", "1", "c", "s")) + navigator.navigate( + NoticeWebKey( + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=c4d5e6f7", + articleId = "c4d5e6f7", + id = "20240410008", + category = "학생", + subject = "2024학년도 동아리 등록 및 지원금 신청 안내", + ) + ) navigator.goBack() assertEquals(SearchKey, navigator.backStack.last()) @@ -205,7 +235,13 @@ class NavigatorTest { @Test fun `FCM 콜드 스타트 시 pendingDeepLink가 스플래시 완료 후 적용된다`() { - val noticeKey = NoticeWebKey("https://kuring.com/notice", "art123", "42", "학사", "긴급공지") + val noticeKey = NoticeWebKey( + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=e8f9a0b1", + articleId = "e8f9a0b1", + id = "20240601001", + category = "학사", + subject = "2024학년도 1학기 기말고사 시간표 안내", + ) navigator.setPendingDeepLink(noticeKey) navigator.replaceAll(MainHubKey()) @@ -219,7 +255,13 @@ class NavigatorTest { fun `웜 스타트 시 직접 navigate하면 해당 화면이 백스택에 추가된다`() { navigator.replaceAll(MainHubKey()) - val noticeKey = NoticeWebKey("https://kuring.com/notice", "art456", "99", "장학", "장학금안내") + val noticeKey = NoticeWebKey( + url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=b2c3d4e5", + articleId = "b2c3d4e5", + id = "20240715003", + category = "장학", + subject = "2024학년도 교내 성적우수 장학금 선발 안내", + ) navigator.navigate(noticeKey) assertEquals(2, navigator.backStack.size)