Skip to content

Commit

Permalink
Merge pull request #92 from KakaoCup/tablayout-text-check
Browse files Browse the repository at this point in the history
feat(tablayout): add count and selector by title
  • Loading branch information
Vacxe authored Jul 14, 2023
2 parents e776557 + 7c7dfcb commit 56e23fc
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 13 deletions.
7 changes: 0 additions & 7 deletions detekt-config.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
complexity:
StringLiteralDuplication:
active: true
excludes: [ '**/test/**', '**/*Test.kt', '**/*Spec.kt' ]
threshold: 5
ignoreAnnotation: true
excludeStringsWithLessThan5Characters: true
ignoreStringsRegex: '$^'
ComplexMethod:
active: true
ignoreSingleWhenExpression: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
package io.github.kakaocup.kakao.tabs

import android.view.View
import androidx.annotation.StringRes
import androidx.test.espresso.PerformException
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.util.HumanReadables
import io.github.kakaocup.kakao.common.actions.BaseActions
import com.google.android.material.tabs.TabLayout

Expand All @@ -32,6 +35,74 @@ interface TabLayoutActions : BaseActions {
})
}

/**
* Selects tab at given text
*
* @param text to be selected
*/
@Suppress("CollapsibleIfStatements")
fun selectTabByText(text: String) {
view.perform(object : ViewAction {
override fun getDescription() = "Selects the tab with text: $text"

override fun getConstraints() = ViewMatchers.isAssignableFrom(TabLayout::class.java)

override fun perform(uiController: UiController, view: View) {
if (view is TabLayout) {
if (!selectTabByText(view, text)) {
throw PerformException.Builder()
.withActionDescription(description)
.withViewDescription(HumanReadables.describe(view))
.withCause(
RuntimeException("Tab with text $text not found")
)
.build()
}
}
}
})
}

/**
* Selects tab at given text
*
* @param text to be selected
*/
fun selectTabByText(@StringRes resId: Int) {
view.perform(object : ViewAction {
override fun getDescription() = "Selects the tab with string resId: $resId"

override fun getConstraints() = ViewMatchers.isAssignableFrom(TabLayout::class.java)

override fun perform(uiController: UiController, view: View) {
if (view is TabLayout) {
val text = view.resources.getText(resId)
if (!selectTabByText(view, text)) {
throw PerformException.Builder()
.withActionDescription(description)
.withViewDescription(HumanReadables.describe(view))
.withCause(
RuntimeException("Tab with text $text not found")
)
.build()
}
}
}
})
}

private fun selectTabByText(tabLayout: TabLayout, tabText: CharSequence): Boolean {
for (i in 0 until tabLayout.tabCount) {
tabLayout.getTabAt(i)?.let { tab ->
if (tab.text == tabText) {
tab.select()
return true
}
}
}
return false
}

/**
* Returns the currently selected tab position
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

package io.github.kakaocup.kakao.tabs

import androidx.test.espresso.ViewAssertion
import androidx.annotation.StringRes
import io.github.kakaocup.kakao.common.assertions.BaseAssertions
import com.google.android.material.tabs.TabLayout

Expand All @@ -16,17 +16,123 @@ interface TabLayoutAssertions : BaseAssertions {
* @param index tab index to be checked
*/
fun isTabSelected(index: Int) {
view.check(ViewAssertion { view, notFoundException ->
view.check { view, notFoundException ->
notFoundException?.let { throw AssertionError(it) }
if (view is TabLayout) {
if (view.selectedTabPosition != index) {
throw AssertionError(
"Expected selected item index is $index," +
" but actual is ${view.selectedTabPosition}"
" but actual is ${view.selectedTabPosition}"
)
}
} else {
notFoundException?.let { throw AssertionError(it) }
throw AssertionError("Expected TabLayout, but got $view")
}
})
}
}

/**
* Checks if TabLayout have selected tab with given text
*
* @param text tab title to be checked
*/

fun hasSelectedText(text: String) {
view.check { view, notFoundException ->
notFoundException?.let { throw AssertionError(it) }
if (view is TabLayout) {
checkTextOnPosition(view, view.selectedTabPosition, text)
} else {
throw AssertionError("Expected TabLayout, but got $view")
}
}
}

/**
* Checks if TabLayout have selected tab with given text
*
* @param resId reference to string id resource
*/

fun hasSelectedText(@StringRes resId: Int) {
view.check { view, notFoundException ->
notFoundException?.let { throw AssertionError(it) }
if (view is TabLayout) {
checkTextOnPosition(view, view.selectedTabPosition, view.resources.getText(resId))
} else {
throw AssertionError("Expected TabLayout, but got $view")
}
}
}

/**
* Checks if TabLayout have tab with given text with selected position
*
* @param text tab title to be checked
* @param position tab position, starts from 0
*/

fun hasText(text: String, position: Int) {
view.check { view, notFoundException ->
notFoundException?.let { throw AssertionError(it) }
if (view is TabLayout) {
checkTextOnPosition(view, position, text)
} else {
throw AssertionError("Expected TabLayout, but got $view")
}
}
}

/**
* Checks if TabLayout have selected tab with given text
*
* @param resId reference to string id resource
* @param position tab position, starts from 0
*/

fun hasText(@StringRes resId: Int, position: Int) {
view.check { view, notFoundException ->
notFoundException?.let { throw AssertionError(it) }
if (view is TabLayout) {
checkTextOnPosition(view, position, view.resources.getText(resId))
} else {
throw AssertionError("Expected TabLayout, but got $view")
}
}
}

@Suppress("ThrowsCount")
private fun checkTextOnPosition(tabLayout: TabLayout, tabPosition: Int, text: CharSequence) {
val tab = tabLayout.getTabAt(tabPosition) ?: throw AssertionError(
"Expected selected item (position $tabPosition) text is $text, but tab not selected"
)

if (tab.text != text) {
throw AssertionError(
"Expected selected item (position $tabPosition) text is $text," +
" but actual is ${tab.text ?: ""}"
)
}
}

/**
* Checks the number of tabs currently registered with the action bar
*
* @param count tabs
*/
fun hasTabCount(count: Int) {
view.check { view, notFoundException ->
notFoundException?.let { throw AssertionError(it) }
if (view is TabLayout) {
if (view.tabCount != count) {
throw AssertionError(
"Expected tabs currently registered with the action bar $count," +
" but actual is ${view.tabCount}"
)
}
} else {
throw AssertionError("Expected TabLayout, but got $view")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,23 @@ class TabLayoutTest {
fun testTabLayout() {
onScreen<TabLayoutActivityScreen> {
tabLayout {
hasTabCount(3)

isTabSelected(0)
assertEquals(0, getSelectedItem())

selectTab(1)

isTabSelected(1)
assertEquals(1, getSelectedItem())

selectTabByText("Tab3")
hasSelectedText("Tab3")
hasText("Tab3", 2)

selectTabByText(R.string.tab1)
hasSelectedText(R.string.tab1)
hasText(R.string.tab1, 0)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class TabLayoutActivity : AppCompatActivity() {
setContentView(R.layout.activity_tab_layout)

val tabLayout = findViewById<TabLayout>(R.id.tab_layout)
val tabs = listOf("Tab1", "Tab2")
val tabs = listOf("Tab1", "Tab2", "Tab3")
tabs.forEach { tab ->
tabLayout.addTab(tabLayout.newTab().setText(tab))
}
Expand Down
1 change: 1 addition & 0 deletions sample/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
<resources>
<string name="hint">This is the HINT!</string>
<string name="error">This is the ERROR!</string>
<string name="tab1">Tab1</string>
</resources>

0 comments on commit 56e23fc

Please sign in to comment.