Skip to content

Commit

Permalink
Modifier.sentryTag uses Modifier.Node (#4029)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
3 people authored Feb 6, 2025
1 parent 63342b7 commit 47a3903
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 6 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## Unreleased

### Fixes

- (Jetpack Compose) Modifier.sentryTag now uses Modifier.Node ([#4029](https://github.com/getsentry/sentry-java/pull/4029))
- This allows Composables that use this modifier to be skippable

## 7.21.0

### Fixes
Expand Down
1 change: 1 addition & 0 deletions buildSrc/src/main/java/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ object Config {
val javaFaker = "com.github.javafaker:javafaker:1.0.2"
val msgpack = "org.msgpack:msgpack-core:0.9.8"
val leakCanaryInstrumentation = "com.squareup.leakcanary:leakcanary-android-instrumentation:2.14"
val composeUiTestJunit4 = "androidx.compose.ui:ui-test-junit4:$composeVersion"
}

object QualityPlugins {
Expand Down
5 changes: 5 additions & 0 deletions sentry-compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ kotlin {
implementation(Config.TestLibs.mockitoKotlin)
implementation(Config.TestLibs.mockitoInline)
implementation(Config.Libs.composeNavigation)
implementation(Config.TestLibs.robolectric)
implementation(Config.TestLibs.androidxRunner)
implementation(Config.TestLibs.androidxJunit)
implementation(Config.TestLibs.androidxTestRules)
implementation(Config.TestLibs.composeUiTestJunit4)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package io.sentry.compose

import androidx.compose.ui.Modifier
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.node.SemanticsModifierNode
import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.semantics.SemanticsConfiguration
import androidx.compose.ui.semantics.SemanticsModifier
import androidx.compose.ui.semantics.SemanticsPropertyKey
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.SemanticsPropertyReceiver

public object SentryModifier {

Expand All @@ -19,11 +24,35 @@ public object SentryModifier {
)

@JvmStatic
public fun Modifier.sentryTag(tag: String): Modifier {
return semantics(
properties = {
this[SentryTag] = tag
public fun Modifier.sentryTag(tag: String): Modifier =
this then SentryTagModifierNodeElement(tag)

private data class SentryTagModifierNodeElement(val tag: String) :
ModifierNodeElement<SentryTagModifierNode>(), SemanticsModifier {

override val semanticsConfiguration: SemanticsConfiguration =
SemanticsConfiguration().also {
it[SentryTag] = tag
}
)

override fun create(): SentryTagModifierNode = SentryTagModifierNode(tag)

override fun update(node: SentryTagModifierNode) {
node.tag = tag
}

override fun InspectorInfo.inspectableProperties() {
name = "sentryTag"
properties["tag"] = tag
}
}

private class SentryTagModifierNode(var tag: String) :
Modifier.Node(),
SemanticsModifierNode {

override fun SemanticsPropertyReceiver.applySemantics() {
this[SentryTag] = tag
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.sentry.compose

import android.app.Application
import android.content.ComponentName
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Box
import androidx.compose.ui.Modifier
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.sentry.compose.SentryModifier.sentryTag
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestWatcher
import org.junit.runner.Description
import org.junit.runner.RunWith
import org.robolectric.Shadows
import org.robolectric.annotation.Config

@RunWith(AndroidJUnit4::class)
@Config(sdk = [30])
class SentryModifierComposeTest {

companion object {
private const val TAG_VALUE = "ExampleTagValue"
}

// workaround for robolectric tests with composeRule
// from https://github.com/robolectric/robolectric/pull/4736#issuecomment-1831034882
@get:Rule(order = 1)
val addActivityToRobolectricRule = object : TestWatcher() {
override fun starting(description: Description?) {
super.starting(description)
val appContext: Application = ApplicationProvider.getApplicationContext()
Shadows.shadowOf(appContext.packageManager).addActivityIfNotPresent(
ComponentName(
appContext.packageName,
ComponentActivity::class.java.name
)
)
}
}

@get:Rule(order = 2)
val rule = createComposeRule()

@Test
fun sentryModifierAppliesTag() {
rule.setContent {
Box(modifier = Modifier.sentryTag(TAG_VALUE))
}
rule.onNode(
SemanticsMatcher(TAG_VALUE) {
it.config.find { (key, _) -> key.name == SentryModifier.TAG }?.value == TAG_VALUE
}
).assertExists()
}
}

0 comments on commit 47a3903

Please sign in to comment.