Skip to content

Commit 47a3903

Browse files
richkzadmarkushiromtsn
authored
Modifier.sentryTag uses Modifier.Node (#4029)
* Modifier.sentryTag uses Modifier.Node * Update Changelog * Add UI test for SentryModifier * Make sentrymodifier a robolectric test * Remove redundant dep --------- Co-authored-by: Markus Hintersteiner <markus.hintersteiner@sentry.io> Co-authored-by: Roman Zavarnitsyn <rom4ek93@gmail.com>
1 parent 63342b7 commit 47a3903

File tree

5 files changed

+107
-6
lines changed

5 files changed

+107
-6
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Fixes
6+
7+
- (Jetpack Compose) Modifier.sentryTag now uses Modifier.Node ([#4029](https://github.com/getsentry/sentry-java/pull/4029))
8+
- This allows Composables that use this modifier to be skippable
9+
310
## 7.21.0
411

512
### Fixes

buildSrc/src/main/java/Config.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ object Config {
201201
val javaFaker = "com.github.javafaker:javafaker:1.0.2"
202202
val msgpack = "org.msgpack:msgpack-core:0.9.8"
203203
val leakCanaryInstrumentation = "com.squareup.leakcanary:leakcanary-android-instrumentation:2.14"
204+
val composeUiTestJunit4 = "androidx.compose.ui:ui-test-junit4:$composeVersion"
204205
}
205206

206207
object QualityPlugins {

sentry-compose/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ kotlin {
6060
implementation(Config.TestLibs.mockitoKotlin)
6161
implementation(Config.TestLibs.mockitoInline)
6262
implementation(Config.Libs.composeNavigation)
63+
implementation(Config.TestLibs.robolectric)
64+
implementation(Config.TestLibs.androidxRunner)
65+
implementation(Config.TestLibs.androidxJunit)
66+
implementation(Config.TestLibs.androidxTestRules)
67+
implementation(Config.TestLibs.composeUiTestJunit4)
6368
}
6469
}
6570
}

sentry-compose/src/androidMain/kotlin/io/sentry/compose/SentryModifier.kt

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package io.sentry.compose
22

33
import androidx.compose.ui.Modifier
4+
import androidx.compose.ui.node.ModifierNodeElement
5+
import androidx.compose.ui.node.SemanticsModifierNode
6+
import androidx.compose.ui.platform.InspectorInfo
7+
import androidx.compose.ui.semantics.SemanticsConfiguration
8+
import androidx.compose.ui.semantics.SemanticsModifier
49
import androidx.compose.ui.semantics.SemanticsPropertyKey
5-
import androidx.compose.ui.semantics.semantics
10+
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
611

712
public object SentryModifier {
813

@@ -19,11 +24,35 @@ public object SentryModifier {
1924
)
2025

2126
@JvmStatic
22-
public fun Modifier.sentryTag(tag: String): Modifier {
23-
return semantics(
24-
properties = {
25-
this[SentryTag] = tag
27+
public fun Modifier.sentryTag(tag: String): Modifier =
28+
this then SentryTagModifierNodeElement(tag)
29+
30+
private data class SentryTagModifierNodeElement(val tag: String) :
31+
ModifierNodeElement<SentryTagModifierNode>(), SemanticsModifier {
32+
33+
override val semanticsConfiguration: SemanticsConfiguration =
34+
SemanticsConfiguration().also {
35+
it[SentryTag] = tag
2636
}
27-
)
37+
38+
override fun create(): SentryTagModifierNode = SentryTagModifierNode(tag)
39+
40+
override fun update(node: SentryTagModifierNode) {
41+
node.tag = tag
42+
}
43+
44+
override fun InspectorInfo.inspectableProperties() {
45+
name = "sentryTag"
46+
properties["tag"] = tag
47+
}
48+
}
49+
50+
private class SentryTagModifierNode(var tag: String) :
51+
Modifier.Node(),
52+
SemanticsModifierNode {
53+
54+
override fun SemanticsPropertyReceiver.applySemantics() {
55+
this[SentryTag] = tag
56+
}
2857
}
2958
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package io.sentry.compose
2+
3+
import android.app.Application
4+
import android.content.ComponentName
5+
import androidx.activity.ComponentActivity
6+
import androidx.compose.foundation.layout.Box
7+
import androidx.compose.ui.Modifier
8+
import androidx.compose.ui.test.SemanticsMatcher
9+
import androidx.compose.ui.test.junit4.createComposeRule
10+
import androidx.test.core.app.ApplicationProvider
11+
import androidx.test.ext.junit.runners.AndroidJUnit4
12+
import io.sentry.compose.SentryModifier.sentryTag
13+
import org.junit.Rule
14+
import org.junit.Test
15+
import org.junit.rules.TestWatcher
16+
import org.junit.runner.Description
17+
import org.junit.runner.RunWith
18+
import org.robolectric.Shadows
19+
import org.robolectric.annotation.Config
20+
21+
@RunWith(AndroidJUnit4::class)
22+
@Config(sdk = [30])
23+
class SentryModifierComposeTest {
24+
25+
companion object {
26+
private const val TAG_VALUE = "ExampleTagValue"
27+
}
28+
29+
// workaround for robolectric tests with composeRule
30+
// from https://github.com/robolectric/robolectric/pull/4736#issuecomment-1831034882
31+
@get:Rule(order = 1)
32+
val addActivityToRobolectricRule = object : TestWatcher() {
33+
override fun starting(description: Description?) {
34+
super.starting(description)
35+
val appContext: Application = ApplicationProvider.getApplicationContext()
36+
Shadows.shadowOf(appContext.packageManager).addActivityIfNotPresent(
37+
ComponentName(
38+
appContext.packageName,
39+
ComponentActivity::class.java.name
40+
)
41+
)
42+
}
43+
}
44+
45+
@get:Rule(order = 2)
46+
val rule = createComposeRule()
47+
48+
@Test
49+
fun sentryModifierAppliesTag() {
50+
rule.setContent {
51+
Box(modifier = Modifier.sentryTag(TAG_VALUE))
52+
}
53+
rule.onNode(
54+
SemanticsMatcher(TAG_VALUE) {
55+
it.config.find { (key, _) -> key.name == SentryModifier.TAG }?.value == TAG_VALUE
56+
}
57+
).assertExists()
58+
}
59+
}

0 commit comments

Comments
 (0)