Initial commit: HotDeal Alarm Android App

Features:
- Multi-site hot deal scraping (Ppomppu, Clien, Ruriweb, Coolenjoy)
- Site filter with color-coded badges
- Board display names (e.g., ppomppu8 -> 알리뽐뿌)
- Anti-bot protection with request delays and User-Agent rotation
- Keyword matching and notifications
- Material Design 3 UI
This commit is contained in:
sanjeok77
2026-03-04 01:29:34 +09:00
commit 25a349f273
84 changed files with 6455 additions and 0 deletions
@@ -0,0 +1,105 @@
package com.hotdeal.alarm
import androidx.compose.ui.test.*
import androidx.compose.ui.test.junit4.createComposeRule
import com.hotdeal.alarm.domain.model.HotDeal
import com.hotdeal.alarm.domain.model.SiteType
import com.hotdeal.alarm.presentation.components.DealItem
import org.junit.Rule
import org.junit.Test
/**
* DealItem 컴포넌트 UI 테스트
*/
class DealItemTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun `DealItem should display title correctly`() {
// Given
val deal = HotDeal(
id = "test_123",
siteName = "ppomppu",
boardName = "ppomppu",
title = "갤럭시 S24 울트라 핫딜",
url = "https://test.com",
createdAt = System.currentTimeMillis()
)
// When
composeTestRule.setContent {
DealItem(deal = deal, onClick = {})
}
// Then
composeTestRule.onNodeWithText("갤럭시 S24 울트라 핫딜").assertExists()
}
@Test
fun `DealItem should display site name`() {
// Given
val deal = HotDeal(
id = "test_123",
siteName = "ppomppu",
boardName = "ppomppu",
title = "Test Deal",
url = "https://test.com",
createdAt = System.currentTimeMillis()
)
// When
composeTestRule.setContent {
DealItem(deal = deal, onClick = {})
}
// Then
composeTestRule.onNodeWithText("뽐뿌").assertExists()
}
@Test
fun `DealItem should be clickable`() {
// Given
var clicked = false
val deal = HotDeal(
id = "test_123",
siteName = "ppomppu",
boardName = "ppomppu",
title = "Test Deal",
url = "https://test.com",
createdAt = System.currentTimeMillis()
)
// When
composeTestRule.setContent {
DealItem(deal = deal, onClick = { clicked = true })
}
// Then
composeTestRule.onNodeWithText("Test Deal").performClick()
assert(clicked)
}
@Test
fun `DealItem should show keyword match indicator when isKeywordMatch is true`() {
// Given
val deal = HotDeal(
id = "test_123",
siteName = "ppomppu",
boardName = "ppomppu",
title = "Test Deal",
url = "https://test.com",
createdAt = System.currentTimeMillis(),
isKeywordMatch = true
)
// When
composeTestRule.setContent {
DealItem(deal = deal, onClick = {})
}
// Then - 키워드 매칭 아이콘이 표시되어야 함
composeTestRule.onNodeWithContentDescription("키워드 매칭").assertExists()
}
}
@@ -0,0 +1,108 @@
package com.hotdeal.alarm
import androidx.compose.ui.test.*
import androidx.compose.ui.test.junit4.createComposeRule
import com.hotdeal.alarm.domain.model.Keyword
import com.hotdeal.alarm.domain.model.MatchMode
import com.hotdeal.alarm.presentation.settings.KeywordItem
import org.junit.Rule
import org.junit.Test
/**
* KeywordItem 컴포넌트 UI 테스트
*/
class KeywordItemTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun `KeywordItem should display keyword text`() {
// Given
val keyword = Keyword(
id = 1L,
keyword = "갤럭시",
isEnabled = true
)
// When
composeTestRule.setContent {
KeywordItem(
keyword = keyword,
onToggle = {},
onDelete = {}
)
}
// Then
composeTestRule.onNodeWithText("갤럭시").assertExists()
}
@Test
fun `KeywordItem should have toggle switch`() {
// Given
val keyword = Keyword(
id = 1L,
keyword = "test",
isEnabled = true
)
// When
composeTestRule.setContent {
KeywordItem(
keyword = keyword,
onToggle = {},
onDelete = {}
)
}
// Then
composeTestRule.onNodeWithText("test").assertExists()
}
@Test
fun `KeywordItem should have delete button`() {
// Given
val keyword = Keyword(
id = 1L,
keyword = "test",
isEnabled = true
)
// When
composeTestRule.setContent {
KeywordItem(
keyword = keyword,
onToggle = {},
onDelete = {}
)
}
// Then
composeTestRule.onNodeWithContentDescription("삭제").assertExists()
}
@Test
fun `KeywordItem toggle should call onToggle`() {
// Given
var toggled = false
val keyword = Keyword(
id = 1L,
keyword = "test",
isEnabled = true
)
// When
composeTestRule.setContent {
KeywordItem(
keyword = keyword,
onToggle = { toggled = true },
onDelete = {}
)
}
// Then - Switch를 찾아서 클릭
composeTestRule.onNode(isToggleable()).performClick()
assert(toggled)
}
}
@@ -0,0 +1,126 @@
package com.hotdeal.alarm
import androidx.compose.ui.test.*
import androidx.compose.ui.test.junit4.createComposeRule
import com.hotdeal.alarm.presentation.components.PermissionDialog
import org.junit.Rule
import org.junit.Test
/**
* PermissionDialog UI 테스트
*/
class PermissionDialogTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun `PermissionDialog should display title`() {
// Given
val title = "알림 권한 필요"
// When
composeTestRule.setContent {
PermissionDialog(
title = title,
message = "Test message",
onDismiss = {},
onOpenSettings = {}
)
}
// Then
composeTestRule.onNodeWithText(title).assertExists()
}
@Test
fun `PermissionDialog should display message`() {
// Given
val message = "핫딜 알림을 받으려면 알림 권한이 필요합니다."
// When
composeTestRule.setContent {
PermissionDialog(
title = "Test",
message = message,
onDismiss = {},
onOpenSettings = {}
)
}
// Then
composeTestRule.onNodeWithText(message).assertExists()
}
@Test
fun `PermissionDialog should have settings button`() {
// When
composeTestRule.setContent {
PermissionDialog(
title = "Test",
message = "Test message",
onDismiss = {},
onOpenSettings = {}
)
}
// Then
composeTestRule.onNodeWithText("설정 열기").assertExists()
}
@Test
fun `PermissionDialog should have cancel button`() {
// When
composeTestRule.setContent {
PermissionDialog(
title = "Test",
message = "Test message",
onDismiss = {},
onOpenSettings = {}
)
}
// Then
composeTestRule.onNodeWithText("취소").assertExists()
}
@Test
fun `PermissionDialog should call onOpenSettings when settings button clicked`() {
// Given
var settingsClicked = false
// When
composeTestRule.setContent {
PermissionDialog(
title = "Test",
message = "Test message",
onDismiss = {},
onOpenSettings = { settingsClicked = true }
)
}
// Then
composeTestRule.onNodeWithText("설정 열기").performClick()
assert(settingsClicked)
}
@Test
fun `PermissionDialog should call onDismiss when cancel button clicked`() {
// Given
var dismissed = false
// When
composeTestRule.setContent {
PermissionDialog(
title = "Test",
message = "Test message",
onDismiss = { dismissed = true },
onOpenSettings = {}
)
}
// Then
composeTestRule.onNodeWithText("취소").performClick()
assert(dismissed)
}
}