Skip to content

Commit d1b5522

Browse files
committed
[Jetsnack] Add tests
1 parent 125f6da commit d1b5522

File tree

4 files changed

+132
-13
lines changed

4 files changed

+132
-13
lines changed

Jetsnack/app/build.gradle

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ android {
7373
composeOptions {
7474
kotlinCompilerExtensionVersion Libs.AndroidX.Compose.version
7575
}
76+
77+
packagingOptions {
78+
// Multiple dependency bring these files in. Exclude them to enable
79+
// our test APK to build (has no effect on our AARs)
80+
excludes += "/META-INF/AL2.0"
81+
excludes += "/META-INF/LGPL2.1"
82+
}
7683
}
7784

7885
dependencies {
@@ -98,4 +105,12 @@ dependencies {
98105

99106
implementation Libs.Accompanist.coil
100107
implementation Libs.Accompanist.insets
108+
109+
androidTestImplementation Libs.JUnit.junit
110+
androidTestImplementation Libs.AndroidX.Test.runner
111+
androidTestImplementation Libs.AndroidX.Test.espressoCore
112+
androidTestImplementation Libs.AndroidX.Test.rules
113+
androidTestImplementation Libs.AndroidX.Test.Ext.junit
114+
androidTestImplementation Libs.Coroutines.test
115+
androidTestImplementation Libs.AndroidX.Compose.uiTest
101116
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2021 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.jetsnack
18+
19+
import androidx.activity.OnBackPressedDispatcher
20+
import androidx.compose.ui.test.assertIsDisplayed
21+
import androidx.compose.ui.test.junit4.createAndroidComposeRule
22+
import androidx.compose.ui.test.onNodeWithTag
23+
import androidx.compose.ui.test.onNodeWithText
24+
import androidx.compose.ui.test.performClick
25+
import com.example.jetsnack.ui.JetsnackApp
26+
import com.example.jetsnack.ui.MainActivity
27+
import com.example.jetsnack.ui.home.HomeSectionTag
28+
import org.junit.Before
29+
import org.junit.Rule
30+
import org.junit.Test
31+
32+
class AppTest {
33+
34+
@get:Rule
35+
val composeTestRule = createAndroidComposeRule<MainActivity>()
36+
37+
@Before
38+
fun setUp() {
39+
composeTestRule.setContent {
40+
JetsnackApp(OnBackPressedDispatcher())
41+
}
42+
}
43+
44+
@Test
45+
fun app_launches() {
46+
// Check app launches at the correct destination
47+
composeTestRule.onNodeWithText("HOME").assertIsDisplayed()
48+
composeTestRule.onNodeWithText("Android's picks").assertIsDisplayed()
49+
}
50+
51+
@Test
52+
fun app_canNavigateToAllScreens() {
53+
// Check app launches at HOME
54+
composeTestRule.onNodeWithText("HOME").assertIsDisplayed()
55+
composeTestRule.onNodeWithText("Android's picks").assertIsDisplayed()
56+
57+
// Navigate to Search
58+
composeTestRule.onNodeWithTag(HomeSectionTag.SEARCH.toString()).performClick()
59+
composeTestRule.onNodeWithText("SEARCH").assertIsDisplayed()
60+
composeTestRule.onNodeWithText("Categories").assertIsDisplayed()
61+
62+
// Navigate to Cart
63+
composeTestRule.onNodeWithTag(HomeSectionTag.CART.toString()).performClick()
64+
composeTestRule.onNodeWithText("MY CART").assertIsDisplayed()
65+
composeTestRule.onNodeWithText("Order (3 items)").assertIsDisplayed()
66+
67+
// Navigate to Profile
68+
composeTestRule.onNodeWithTag(HomeSectionTag.PROFILE.toString()).performClick()
69+
composeTestRule.onNodeWithText("PROFILE").assertIsDisplayed()
70+
composeTestRule.onNodeWithText("Profile").assertIsDisplayed()
71+
}
72+
}

Jetsnack/app/src/main/java/com/example/jetsnack/ui/home/Home.kt

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.example.jetsnack.ui.home
1818

1919
import androidx.annotation.FloatRange
2020
import androidx.annotation.StringRes
21+
import androidx.annotation.VisibleForTesting
2122
import androidx.compose.animation.Crossfade
2223
import androidx.compose.animation.animateColorAsState
2324
import androidx.compose.animation.core.Animatable
@@ -61,6 +62,7 @@ import androidx.compose.ui.layout.MeasureScope
6162
import androidx.compose.ui.layout.Placeable
6263
import androidx.compose.ui.layout.layoutId
6364
import androidx.compose.ui.platform.LocalConfiguration
65+
import androidx.compose.ui.platform.testTag
6466
import androidx.compose.ui.res.stringResource
6567
import androidx.compose.ui.tooling.preview.Preview
6668
import androidx.compose.ui.unit.Dp
@@ -73,7 +75,8 @@ import com.example.jetsnack.ui.components.JetsnackSurface
7375
import com.example.jetsnack.ui.home.cart.Cart
7476
import com.example.jetsnack.ui.home.search.Search
7577
import com.example.jetsnack.ui.theme.JetsnackTheme
76-
import com.google.accompanist.insets.navigationBarsPadding
78+
import dev.chrisbanes.accompanist.insets.ProvideWindowInsets
79+
import dev.chrisbanes.accompanist.insets.navigationBarsPadding
7780

7881
@Composable
7982
fun Home(onSnackSelected: (Long) -> Unit) {
@@ -164,6 +167,7 @@ private fun JetsnackBottomNav(
164167
selected = selected,
165168
onSelected = { onSectionSelected(section) },
166169
animSpec = springSpec,
170+
testTag = section.tag,
167171
modifier = BottomNavigationItemPadding
168172
.clip(BottomNavIndicatorShape)
169173
)
@@ -256,10 +260,13 @@ fun JetsnackBottomNavigationItem(
256260
selected: Boolean,
257261
onSelected: () -> Unit,
258262
animSpec: AnimationSpec<Float>,
263+
testTag: HomeSectionTag,
259264
modifier: Modifier = Modifier
260265
) {
261266
Box(
262-
modifier = modifier.selectable(selected = selected, onClick = onSelected),
267+
modifier = modifier
268+
.selectable(selected = selected, onClick = onSelected)
269+
.testTag(testTag.toString()),
263270
contentAlignment = Alignment.Center
264271
) {
265272
// Animate the icon/text positions within the item based on selection
@@ -353,22 +360,30 @@ private val BottomNavigationItemPadding = Modifier.padding(horizontal = 16.dp, v
353360

354361
private enum class HomeSections(
355362
@StringRes val title: Int,
356-
val icon: ImageVector
363+
val icon: ImageVector,
364+
val tag: HomeSectionTag
357365
) {
358-
Feed(R.string.home_feed, Icons.Outlined.Home),
359-
Search(R.string.home_search, Icons.Outlined.Search),
360-
Cart(R.string.home_cart, Icons.Outlined.ShoppingCart),
361-
Profile(R.string.home_profile, Icons.Outlined.AccountCircle)
366+
Feed(R.string.home_feed, Icons.Outlined.Home, HomeSectionTag.FEED),
367+
Search(R.string.home_search, Icons.Outlined.Search, HomeSectionTag.SEARCH),
368+
Cart(R.string.home_cart, Icons.Outlined.ShoppingCart, HomeSectionTag.CART),
369+
Profile(R.string.home_profile, Icons.Outlined.AccountCircle, HomeSectionTag.PROFILE)
370+
}
371+
372+
@VisibleForTesting
373+
enum class HomeSectionTag {
374+
FEED, SEARCH, CART, PROFILE
362375
}
363376

364377
@Preview
365378
@Composable
366379
private fun JsetsnackBottomNavPreview() {
367-
JetsnackTheme {
368-
JetsnackBottomNav(
369-
currentSection = HomeSections.Feed,
370-
onSectionSelected = { },
371-
items = HomeSections.values().toList()
372-
)
380+
ProvideWindowInsets {
381+
JetsnackTheme {
382+
JetsnackBottomNav(
383+
currentSection = HomeSections.Feed,
384+
onSectionSelected = { },
385+
items = HomeSections.values().toList()
386+
)
387+
}
373388
}
374389
}

Jetsnack/buildSrc/src/main/java/com/example/jetsnack/buildsrc/Dependencies.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ object Libs {
5959
const val animation = "androidx.compose.animation:animation:${version}"
6060
const val tooling = "androidx.compose.ui:ui-tooling:${version}"
6161
const val iconsExtended = "androidx.compose.material:material-icons-extended:$version"
62+
const val uiTest = "androidx.compose.ui:ui-test-junit4:$version"
6263
}
6364

6465
object Activity {
@@ -74,5 +75,21 @@ object Libs {
7475
const val constraintLayoutCompose =
7576
"androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha03"
7677
}
78+
79+
object Test {
80+
private const val version = "1.2.0"
81+
const val runner = "androidx.test:runner:$version"
82+
const val rules = "androidx.test:rules:$version"
83+
object Ext {
84+
private const val version = "1.1.2-rc01"
85+
const val junit = "androidx.test.ext:junit-ktx:$version"
86+
}
87+
const val espressoCore = "androidx.test.espresso:espresso-core:3.2.0"
88+
}
89+
}
90+
91+
object JUnit {
92+
private const val version = "4.13"
93+
const val junit = "junit:junit:$version"
7794
}
7895
}

0 commit comments

Comments
 (0)