diff --git a/package.json b/package.json index 3f850c503e..51adda7972 100644 --- a/package.json +++ b/package.json @@ -7,16 +7,18 @@ "clean": "lerna run clean", "circularDepCheck": "lerna run circularDepCheck", "test": "lerna run test", - "fix": "run-s fix:lerna fix:android fix:clang fix:swift", + "fix": "run-s fix:lerna fix:android fix:clang fix:swift fix:kotlin", "fix:lerna": "lerna run fix", "fix:android": "run-s 'java:format fix' java:pmd", "fix:clang": "run-s 'clang:format fix'", "fix:swift": "run-s 'swift:lint fix'", - "lint": "run-s lint:lerna lint:android lint:clang lint:swift", + "fix:kotlin": "npx ktlint --relative --format '!**/node_modules/**'", + "lint": "run-s lint:lerna lint:android lint:clang lint:swift lint:kotlin", "lint:lerna": "lerna run lint", "lint:android": "run-s 'java:format lint' java:pmd", "lint:clang": "run-s 'clang:format lint'", "lint:swift": "run-s 'swift:lint lint'", + "lint:kotlin": "npx ktlint --relative '!**/node_modules/**'", "java:format": "./scripts/google-java-format.sh", "java:pmd": "./scripts/pmd.sh", "clang:format": "./scripts/clang-format.sh", @@ -27,6 +29,7 @@ }, "devDependencies": { "@expo/swiftlint": "^0.57.1", + "@naturalcycles/ktlint": "^1.13.0", "@sentry/cli": "2.40.0", "clang-format": "^1.8.0", "downlevel-dts": "^0.11.0", diff --git a/packages/core/RNSentryAndroidTester/app/src/androidTest/java/io/sentry/react/RNSentryModuleImplTest.kt b/packages/core/RNSentryAndroidTester/app/src/androidTest/java/io/sentry/react/RNSentryModuleImplTest.kt index d314420758..09fdb3155c 100644 --- a/packages/core/RNSentryAndroidTester/app/src/androidTest/java/io/sentry/react/RNSentryModuleImplTest.kt +++ b/packages/core/RNSentryAndroidTester/app/src/androidTest/java/io/sentry/react/RNSentryModuleImplTest.kt @@ -19,7 +19,6 @@ import org.junit.runners.JUnit4 @RunWith(JUnit4::class) class RNSentryModuleImplTest { - private lateinit var module: RNSentryModuleImpl private lateinit var context: Context @@ -35,12 +34,13 @@ class RNSentryModuleImplTest { fun fetchNativeDeviceContextsWithNullContext() { val options = SentryAndroidOptions() val scope = Scope(options) - val promise = PromiseImpl({ - assertEquals(1, it.size) - assertEquals(null, it[0]) - }, { - fail("Promise was rejected unexpectedly") - }) + val promise = + PromiseImpl({ + assertEquals(1, it.size) + assertEquals(null, it[0]) + }, { + fail("Promise was rejected unexpectedly") + }) module.fetchNativeDeviceContexts(promise, options, null, scope) } @@ -50,12 +50,13 @@ class RNSentryModuleImplTest { val options = NotAndroidSentryOptions() val scope = Scope(options) - val promise = PromiseImpl({ - assertEquals(1, it.size) - assertEquals(null, it[0]) - }, { - fail("Promise was rejected unexpectedly") - }) + val promise = + PromiseImpl({ + assertEquals(1, it.size) + assertEquals(null, it[0]) + }, { + fail("Promise was rejected unexpectedly") + }) module.fetchNativeDeviceContexts(promise, options, context, scope) } @@ -69,17 +70,18 @@ class RNSentryModuleImplTest { scope.addBreadcrumb(Breadcrumb("Breadcrumb2-RN").apply { origin = "react-native" }) scope.addBreadcrumb(Breadcrumb("Breadcrumb2-RN").apply { origin = "react-native" }) - val promise = PromiseImpl({ - assertEquals(1, it.size) - assertEquals(true, it[0] is WritableMap) - val actual = it[0] as WritableMap - val breadcrumbs = actual.getArray("breadcrumbs") - assertEquals(2, breadcrumbs?.size()) - assertEquals("Breadcrumb2-Native", breadcrumbs?.getMap(0)?.getString("message")) - assertEquals("Breadcrumb3-Native", breadcrumbs?.getMap(1)?.getString("message")) - }, { - fail("Promise was rejected unexpectedly") - }) + val promise = + PromiseImpl({ + assertEquals(1, it.size) + assertEquals(true, it[0] is WritableMap) + val actual = it[0] as WritableMap + val breadcrumbs = actual.getArray("breadcrumbs") + assertEquals(2, breadcrumbs?.size()) + assertEquals("Breadcrumb2-Native", breadcrumbs?.getMap(0)?.getString("message")) + assertEquals("Breadcrumb3-Native", breadcrumbs?.getMap(1)?.getString("message")) + }, { + fail("Promise was rejected unexpectedly") + }) module.fetchNativeDeviceContexts(promise, options, context, scope) } diff --git a/packages/core/RNSentryAndroidTester/app/src/androidTest/java/io/sentry/rnsentryandroidtester/RNSentryMapConverterTest.kt b/packages/core/RNSentryAndroidTester/app/src/androidTest/java/io/sentry/rnsentryandroidtester/RNSentryMapConverterTest.kt index 0f7b9fc456..6424399bdf 100644 --- a/packages/core/RNSentryAndroidTester/app/src/androidTest/java/io/sentry/rnsentryandroidtester/RNSentryMapConverterTest.kt +++ b/packages/core/RNSentryAndroidTester/app/src/androidTest/java/io/sentry/rnsentryandroidtester/RNSentryMapConverterTest.kt @@ -1,24 +1,23 @@ package io.sentry.rnsentryandroidtester +import android.content.Context import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.facebook.react.bridge.Arguments import com.facebook.soloader.SoLoader import io.sentry.react.RNSentryMapConverter -import org.junit.Assert.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import android.content.Context; -import org.junit.Before import java.math.BigDecimal import java.math.BigInteger class Unknown - @RunWith(AndroidJUnit4::class) class MapConverterTest { - @Before fun setUp() { val context: Context = InstrumentationRegistry.getInstrumentation().targetContext @@ -103,7 +102,7 @@ class MapConverterTest { @Test fun convertsMapWithUnknownValueKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("unknown" to Unknown())) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putNull("unknown") assertEquals(expectedMap, actualMap) } @@ -111,7 +110,7 @@ class MapConverterTest { @Test fun convertsMapWithNullKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("null" to null)) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putNull("null") assertEquals(expectedMap, actualMap) } @@ -119,7 +118,7 @@ class MapConverterTest { @Test fun convertsMapWithBooleanKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("boolean" to true)) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putBoolean("boolean", true) assertEquals(expectedMap, actualMap) } @@ -127,7 +126,7 @@ class MapConverterTest { @Test fun convertsMapWithDoubleKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("double" to Double.MAX_VALUE)) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putDouble("double", Double.MAX_VALUE) assertEquals(expectedMap, actualMap) } @@ -135,7 +134,7 @@ class MapConverterTest { @Test fun convertsMapWithIntegerKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("integer" to Integer.MAX_VALUE)) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putInt("integer", Integer.MAX_VALUE) assertEquals(expectedMap, actualMap) } @@ -143,7 +142,7 @@ class MapConverterTest { @Test fun convertsMapWithByteKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("byte" to Byte.MAX_VALUE)) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putInt("byte", Byte.MAX_VALUE.toInt()) assertEquals(expectedMap, actualMap) } @@ -151,7 +150,7 @@ class MapConverterTest { @Test fun convertsMapWithShortKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("short" to Short.MAX_VALUE)) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putInt("short", Short.MAX_VALUE.toInt()) assertEquals(expectedMap, actualMap) } @@ -159,7 +158,7 @@ class MapConverterTest { @Test fun convertsMapWithFloatKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("float" to Float.MAX_VALUE)) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putDouble("float", Float.MAX_VALUE.toDouble()) assertEquals(expectedMap, actualMap) } @@ -167,7 +166,7 @@ class MapConverterTest { @Test fun convertsMapWithLongKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("long" to Long.MAX_VALUE)) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putDouble("long", Long.MAX_VALUE.toDouble()) assertEquals(expectedMap, actualMap) } @@ -175,7 +174,7 @@ class MapConverterTest { @Test fun convertsMapWithInBigDecimalKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("big_decimal" to BigDecimal.TEN)) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putDouble("big_decimal", BigDecimal.TEN.toDouble()) assertEquals(expectedMap, actualMap) } @@ -183,7 +182,7 @@ class MapConverterTest { @Test fun convertsMapWithBigIntKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("big_int" to BigInteger.TEN)) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putDouble("big_int", BigInteger.TEN.toDouble()) assertEquals(expectedMap, actualMap) } @@ -191,7 +190,7 @@ class MapConverterTest { @Test fun convertsMapWithStringKey() { val actualMap = RNSentryMapConverter.convertToWritable(mapOf("string" to "string")) - val expectedMap = Arguments.createMap(); + val expectedMap = Arguments.createMap() expectedMap.putString("string", "string") assertEquals(expectedMap, actualMap) } @@ -304,26 +303,32 @@ class MapConverterTest { @Test fun convertsComplexMapCorrectly() { - val actual = RNSentryMapConverter.convertToWritable(mapOf( - "integer" to Integer.MAX_VALUE, - "string" to "string1", - "map" to mapOf( - "integer" to Integer.MAX_VALUE, - "string" to "string2", - "map" to mapOf( - "integer" to Integer.MAX_VALUE, - "string" to "string3" - ) - ), - "list" to listOf( - Integer.MAX_VALUE, + val actual = + RNSentryMapConverter.convertToWritable( mapOf( "integer" to Integer.MAX_VALUE, - "string" to "string4", + "string" to "string1", + "map" to + mapOf( + "integer" to Integer.MAX_VALUE, + "string" to "string2", + "map" to + mapOf( + "integer" to Integer.MAX_VALUE, + "string" to "string3", + ), + ), + "list" to + listOf( + Integer.MAX_VALUE, + mapOf( + "integer" to Integer.MAX_VALUE, + "string" to "string4", + ), + "string5", + ), ), - "string5", - ), - )) + ) val expectedMap1 = Arguments.createMap() val expectedMap2 = Arguments.createMap() diff --git a/packages/core/RNSentryAndroidTester/app/src/test/java/com/swmansion/rnscreens/ScreenStackFragment.kt b/packages/core/RNSentryAndroidTester/app/src/test/java/com/swmansion/rnscreens/ScreenStackFragment.kt index 4113126fc8..6233d2dac9 100644 --- a/packages/core/RNSentryAndroidTester/app/src/test/java/com/swmansion/rnscreens/ScreenStackFragment.kt +++ b/packages/core/RNSentryAndroidTester/app/src/test/java/com/swmansion/rnscreens/ScreenStackFragment.kt @@ -2,6 +2,6 @@ package com.swmansion.rnscreens import androidx.fragment.app.Fragment -class ScreenStackFragment(contentLayoutId: Int) : Fragment(contentLayoutId) { - -} \ No newline at end of file +class ScreenStackFragment( + contentLayoutId: Int, +) : Fragment(contentLayoutId) diff --git a/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/react/RNSentryModuleImplTest.kt b/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/react/RNSentryModuleImplTest.kt index b181625138..adffbf78ad 100644 --- a/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/react/RNSentryModuleImplTest.kt +++ b/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/react/RNSentryModuleImplTest.kt @@ -23,15 +23,18 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.mockito.ArgumentCaptor import org.mockito.Captor -import org.mockito.Mockito.* -import org.mockito.MockitoAnnotations import org.mockito.MockedStatic +import org.mockito.Mockito.any +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.anyString +import org.mockito.Mockito.mock import org.mockito.Mockito.mockStatic +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations import org.mockito.kotlin.whenever @RunWith(JUnit4::class) class RNSentryModuleImplTest { - private lateinit var module: RNSentryModuleImpl private lateinit var promise: Promise private lateinit var logger: ILogger @@ -76,7 +79,7 @@ class RNSentryModuleImplTest { // Verify a warning log is emitted verify(logger, org.mockito.kotlin.times(1)).log( SentryLevel.WARNING, - "Invalid app start data: app not launched in foreground." + "Invalid app start data: app not launched in foreground.", ) // Verify the promise is resolved with null @@ -103,10 +106,13 @@ class RNSentryModuleImplTest { @Test fun `when the spotlight option is enabled, the spotlight SentryAndroidOption is set to true and the default url is used`() { - val options = JavaOnlyMap.of( - "spotlight", true, - "defaultSidecarUrl", "http://localhost:8969/teststream" - ) + val options = + JavaOnlyMap.of( + "spotlight", + true, + "defaultSidecarUrl", + "http://localhost:8969/teststream", + ) val actualOptions = SentryAndroidOptions() module.getSentryAndroidOptions(actualOptions, options, logger) assert(actualOptions.isEnableSpotlight) @@ -140,16 +146,20 @@ class RNSentryModuleImplTest { @Test fun `beforeBreadcrumb callback filters out Sentry DSN requests breadcrumbs`() { val options = SentryAndroidOptions() - val rnOptions = JavaOnlyMap.of( - "dsn", "https://abc@def.ingest.sentry.io/1234567", - "devServerUrl", "http://localhost:8081", - ) + val rnOptions = + JavaOnlyMap.of( + "dsn", + "https://abc@def.ingest.sentry.io/1234567", + "devServerUrl", + "http://localhost:8081", + ) module.getSentryAndroidOptions(options, rnOptions, logger) - val breadcrumb = Breadcrumb().apply { - type = "http" - setData("url", "https://def.ingest.sentry.io/1234567") - } + val breadcrumb = + Breadcrumb().apply { + type = "http" + setData("url", "https://def.ingest.sentry.io/1234567") + } val result = options.beforeBreadcrumb?.execute(breadcrumb, mock()) @@ -160,16 +170,20 @@ class RNSentryModuleImplTest { fun `beforeBreadcrumb callback filters out dev server breadcrumbs`() { val mockDevServerUrl = "http://localhost:8081" val options = SentryAndroidOptions() - val rnOptions = JavaOnlyMap.of( - "dsn", "https://abc@def.ingest.sentry.io/1234567", - "devServerUrl", mockDevServerUrl, - ) + val rnOptions = + JavaOnlyMap.of( + "dsn", + "https://abc@def.ingest.sentry.io/1234567", + "devServerUrl", + mockDevServerUrl, + ) module.getSentryAndroidOptions(options, rnOptions, logger) - val breadcrumb = Breadcrumb().apply { - type = "http" - setData("url", mockDevServerUrl) - } + val breadcrumb = + Breadcrumb().apply { + type = "http" + setData("url", mockDevServerUrl) + } val result = options.beforeBreadcrumb?.execute(breadcrumb, mock()) @@ -179,16 +193,20 @@ class RNSentryModuleImplTest { @Test fun `beforeBreadcrumb callback does not filter out non dev server or dsn breadcrumbs`() { val options = SentryAndroidOptions() - val rnOptions = JavaOnlyMap.of( - "dsn", "https://abc@def.ingest.sentry.io/1234567", - "devServerUrl", "http://localhost:8081", - ) + val rnOptions = + JavaOnlyMap.of( + "dsn", + "https://abc@def.ingest.sentry.io/1234567", + "devServerUrl", + "http://localhost:8081", + ) module.getSentryAndroidOptions(options, rnOptions, logger) - val breadcrumb = Breadcrumb().apply { - type = "http" - setData("url", "http://testurl.com/service") - } + val breadcrumb = + Breadcrumb().apply { + type = "http" + setData("url", "http://testurl.com/service") + } val result = options.beforeBreadcrumb?.execute(breadcrumb, mock()) @@ -200,10 +218,11 @@ class RNSentryModuleImplTest { val options = SentryAndroidOptions() module.getSentryAndroidOptions(options, JavaOnlyMap(), logger) - val breadcrumb = Breadcrumb().apply { - type = "http" - setData("url", "http://testurl.com/service") - } + val breadcrumb = + Breadcrumb().apply { + type = "http" + setData("url", "http://testurl.com/service") + } val result = options.beforeBreadcrumb?.execute(breadcrumb, mock()) @@ -216,10 +235,11 @@ class RNSentryModuleImplTest { val rnOptions = JavaOnlyMap.of("dsn", "https://abc@def.ingest.sentry.io/1234567") module.getSentryAndroidOptions(options, rnOptions, logger) - val breadcrumb = Breadcrumb().apply { - type = "http" - setData("url", "http://testurl.com/service") - } + val breadcrumb = + Breadcrumb().apply { + type = "http" + setData("url", "http://testurl.com/service") + } val result = options.beforeBreadcrumb?.execute(breadcrumb, mock()) @@ -232,10 +252,11 @@ class RNSentryModuleImplTest { val rnOptions = JavaOnlyMap.of("devServerUrl", "http://localhost:8081") module.getSentryAndroidOptions(options, rnOptions, logger) - val breadcrumb = Breadcrumb().apply { - type = "http" - setData("url", "http://testurl.com/service") - } + val breadcrumb = + Breadcrumb().apply { + type = "http" + setData("url", "http://testurl.com/service") + } val result = options.beforeBreadcrumb?.execute(breadcrumb, mock()) diff --git a/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryBreadcrumbTest.kt b/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryBreadcrumbTest.kt index e2eceab44a..c85fc9e5f9 100644 --- a/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryBreadcrumbTest.kt +++ b/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryBreadcrumbTest.kt @@ -10,20 +10,28 @@ import org.junit.runners.JUnit4 @RunWith(JUnit4::class) class RNSentryBreadcrumbTest { - @Test fun generatesSentryBreadcrumbFromMap() { - val testData = JavaOnlyMap.of( - "test", "data", - ) - val map = JavaOnlyMap.of( - "level", "error", - "category", "testCategory", - "origin", "testOrigin", - "type", "testType", - "message", "testMessage", - "data", testData, - ) + val testData = + JavaOnlyMap.of( + "test", + "data", + ) + val map = + JavaOnlyMap.of( + "level", + "error", + "category", + "testCategory", + "origin", + "testOrigin", + "type", + "testType", + "message", + "testMessage", + "data", + testData, + ) val actual = RNSentryBreadcrumb.fromMap(map) assertEquals(SentryLevel.ERROR, actual.level) assertEquals("testCategory", actual.category) @@ -35,9 +43,11 @@ class RNSentryBreadcrumbTest { @Test fun reactNativeForMissingOrigin() { - val map = JavaOnlyMap.of( - "message", "testMessage", - ) + val map = + JavaOnlyMap.of( + "message", + "testMessage", + ) val actual = RNSentryBreadcrumb.fromMap(map) assertEquals("testMessage", actual.message) assertEquals("react-native", actual.origin) @@ -50,50 +60,57 @@ class RNSentryBreadcrumbTest { assertEquals(null, actual) } - @Test fun nullForNonNavigationCategory() { - val map = JavaOnlyMap.of( - "category", "unknown" - ) + val map = + JavaOnlyMap.of( + "category", + "unknown", + ) val actual = RNSentryBreadcrumb.getCurrentScreenFrom(map) assertEquals(null, actual) } - @Test fun nullForMissingData() { - val map = JavaOnlyMap.of( - "category", "navigation" - ) + val map = + JavaOnlyMap.of( + "category", + "navigation", + ) val actual = RNSentryBreadcrumb.getCurrentScreenFrom(map) assertEquals(null, actual) } - @Test fun nullForNonStringDataToKey() { - val map = JavaOnlyMap.of( - "category", "unknown", - "data", mapOf( - "to" to 123, - ), - ) + val map = + JavaOnlyMap.of( + "category", + "unknown", + "data", + mapOf( + "to" to 123, + ), + ) val actual = RNSentryBreadcrumb.getCurrentScreenFrom(map) assertEquals(null, actual) } @Test fun screenNameForValidNavigationBreadcrumb() { - val map = JavaOnlyMap.of( - "category", "navigation", - "data", JavaOnlyMap.of( - "to", "newScreen", - ), - ) + val map = + JavaOnlyMap.of( + "category", + "navigation", + "data", + JavaOnlyMap.of( + "to", + "newScreen", + ), + ) val actual = RNSentryBreadcrumb.getCurrentScreenFrom(map) assert(actual is String) assertEquals("newScreen", actual) } - } diff --git a/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReactFragmentLifecycleTracerTest.kt b/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReactFragmentLifecycleTracerTest.kt index 1dca319f15..d7599ea274 100644 --- a/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReactFragmentLifecycleTracerTest.kt +++ b/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReactFragmentLifecycleTracerTest.kt @@ -25,18 +25,17 @@ import org.mockito.kotlin.whenever @RunWith(JUnit4::class) class RNSentryReactFragmentLifecycleTracerTest { - private var mockUIManager: MockedStatic? = null @After fun after() { - mockUIManager?.close(); + mockUIManager?.close() } @Test fun tracerAddsListenerForValidRNScreenFragment() { - val mockEventDispatcher = mock(); - mockUIManager(mockEventDispatcher); + val mockEventDispatcher = mock() + mockUIManager(mockEventDispatcher) callOnFragmentViewCreated(mock(), mockScreenViewWithReactContext()) verify(mockEventDispatcher, times(1)).addListener(any()) @@ -44,8 +43,8 @@ class RNSentryReactFragmentLifecycleTracerTest { @Test fun tracerDoesNotAddListenerForGenericFragment() { - val mockEventDispatcher = mock(); - mockUIManager(mockEventDispatcher); + val mockEventDispatcher = mock() + mockUIManager(mockEventDispatcher) callOnFragmentViewCreated(mock(), mockScreenViewWithReactContext()) verify(mockEventDispatcher, times(0)).addListener(any()) @@ -53,8 +52,8 @@ class RNSentryReactFragmentLifecycleTracerTest { @Test fun tracerDoesNotAddListenerForViewWithoutChild() { - val mockEventDispatcher = mock(); - mockUIManager(mockEventDispatcher); + val mockEventDispatcher = mock() + mockUIManager(mockEventDispatcher) callOnFragmentViewCreated(mock(), mockScreenViewWithoutChild()) verify(mockEventDispatcher, times(0)).addListener(any()) @@ -62,8 +61,8 @@ class RNSentryReactFragmentLifecycleTracerTest { @Test fun tracerDoesNotAddListenerForViewWithoutReactContext() { - val mockEventDispatcher = mock(); - mockUIManager(mockEventDispatcher); + val mockEventDispatcher = mock() + mockUIManager(mockEventDispatcher) callOnFragmentViewCreated(mock(), mockScreenViewWithGenericContext()) verify(mockEventDispatcher, times(0)).addListener(any()) @@ -71,8 +70,8 @@ class RNSentryReactFragmentLifecycleTracerTest { @Test fun tracerDoesNotAddListenerForViewWithNoId() { - val mockEventDispatcher = mock(); - mockUIManager(mockEventDispatcher); + val mockEventDispatcher = mock() + mockUIManager(mockEventDispatcher) callOnFragmentViewCreated(mock(), mockScreenViewWithNoId()) verify(mockEventDispatcher, times(0)).addListener(any()) @@ -80,12 +79,15 @@ class RNSentryReactFragmentLifecycleTracerTest { @Test fun tracerDoesNotAddListenerForViewWithoutEventDispatcher() { - mockUIManagerToReturnNullEventDispatcher(); + mockUIManagerToReturnNullEventDispatcher() callOnFragmentViewCreated(mock(), mockScreenViewWithGenericContext()) } - private fun callOnFragmentViewCreated(mockFragment: Fragment, mockView: View) { + private fun callOnFragmentViewCreated( + mockFragment: Fragment, + mockView: View, + ) { createSutWith().onFragmentViewCreated( mock(), mockFragment, @@ -101,51 +103,56 @@ class RNSentryReactFragmentLifecycleTracerTest { return RNSentryReactFragmentLifecycleTracer( buildInfo, mock(), - logger + logger, ) } private fun mockScreenViewWithReactContext(): View { - val screenMock: View = mock() { - whenever(it.id).thenReturn(123) - whenever(it.context).thenReturn(mock()) - } - val mockView = mock { - whenever(it.childCount).thenReturn(1) - whenever(it.getChildAt(0)).thenReturn(screenMock) - } - return mockView; + val screenMock: View = + mock { + whenever(it.id).thenReturn(123) + whenever(it.context).thenReturn(mock()) + } + val mockView = + mock { + whenever(it.childCount).thenReturn(1) + whenever(it.getChildAt(0)).thenReturn(screenMock) + } + return mockView } private fun mockScreenViewWithGenericContext(): View { - val screenMock: View = mock() { - whenever(it.id).thenReturn(123) - whenever(it.context).thenReturn(mock()) - } - val mockView = mock { - whenever(it.childCount).thenReturn(1) - whenever(it.getChildAt(0)).thenReturn(screenMock) - } - return mockView; + val screenMock: View = + mock { + whenever(it.id).thenReturn(123) + whenever(it.context).thenReturn(mock()) + } + val mockView = + mock { + whenever(it.childCount).thenReturn(1) + whenever(it.getChildAt(0)).thenReturn(screenMock) + } + return mockView } private fun mockScreenViewWithNoId(): View { - val screenMock: View = mock() { - whenever(it.id).thenReturn(-1) - whenever(it.context).thenReturn(mock()) - } - val mockView = mock { - whenever(it.childCount).thenReturn(1) - whenever(it.getChildAt(0)).thenReturn(screenMock) - } - return mockView; + val screenMock: View = + mock { + whenever(it.id).thenReturn(-1) + whenever(it.context).thenReturn(mock()) + } + val mockView = + mock { + whenever(it.childCount).thenReturn(1) + whenever(it.getChildAt(0)).thenReturn(screenMock) + } + return mockView } - private fun mockScreenViewWithoutChild(): View { - return mock { + private fun mockScreenViewWithoutChild(): View = + mock { whenever(it.childCount).thenReturn(0) } - } private fun mockUIManager(mockEventDispatcher: EventDispatcher) { mockUIManager = mockStatic(UIManagerHelper::class.java) diff --git a/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReplayBreadcrumbConverterTest.kt b/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReplayBreadcrumbConverterTest.kt index 257aea123f..d05d50655b 100644 --- a/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReplayBreadcrumbConverterTest.kt +++ b/packages/core/RNSentryAndroidTester/app/src/test/java/io/sentry/rnsentryandroidtester/RNSentryReplayBreadcrumbConverterTest.kt @@ -4,7 +4,6 @@ import io.sentry.Breadcrumb import io.sentry.SentryLevel import io.sentry.react.RNSentryReplayBreadcrumbConverter import io.sentry.rrweb.RRWebBreadcrumbEvent -import io.sentry.rrweb.RRWebEventType import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @@ -12,7 +11,6 @@ import org.junit.runners.JUnit4 @RunWith(JUnit4::class) class RNSentryReplayBreadcrumbConverterTest { - @Test fun convertNavigationBreadcrumb() { val converter = RNSentryReplayBreadcrumbConverter() @@ -54,7 +52,7 @@ class RNSentryReplayBreadcrumbConverterTest { val testBreadcrumb = Breadcrumb() testBreadcrumb.type = "navigation" testBreadcrumb.category = "app.lifecycle" - testBreadcrumb.setData("state", "foreground"); + testBreadcrumb.setData("state", "foreground") val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent assertRRWebBreadcrumbDefaults(actual) @@ -67,7 +65,7 @@ class RNSentryReplayBreadcrumbConverterTest { val testBreadcrumb = Breadcrumb() testBreadcrumb.type = "navigation" testBreadcrumb.category = "app.lifecycle" - testBreadcrumb.setData("state", "background"); + testBreadcrumb.setData("state", "background") val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent assertRRWebBreadcrumbDefaults(actual) @@ -77,7 +75,7 @@ class RNSentryReplayBreadcrumbConverterTest { @Test fun doesNotConvertSentryEventBreadcrumb() { val converter = RNSentryReplayBreadcrumbConverter() - val testBreadcrumb = Breadcrumb(); + val testBreadcrumb = Breadcrumb() testBreadcrumb.category = "sentry.event" val actual = converter.convert(testBreadcrumb) assertEquals(null, actual) @@ -86,7 +84,7 @@ class RNSentryReplayBreadcrumbConverterTest { @Test fun doesNotConvertSentryTransactionBreadcrumb() { val converter = RNSentryReplayBreadcrumbConverter() - val testBreadcrumb = Breadcrumb(); + val testBreadcrumb = Breadcrumb() testBreadcrumb.category = "sentry.transaction" val actual = converter.convert(testBreadcrumb) assertEquals(null, actual) @@ -102,9 +100,13 @@ class RNSentryReplayBreadcrumbConverterTest { testBreadcrumb.message = "this won't be used for replay" testBreadcrumb.setData( "path", - arrayListOf(mapOf( - "element" to "element4", - "file" to "file4"))) + arrayListOf( + mapOf( + "element" to "element4", + "file" to "file4", + ), + ), + ) val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent assertRRWebBreadcrumbDefaults(actual) @@ -112,10 +114,14 @@ class RNSentryReplayBreadcrumbConverterTest { assertEquals("ui.tap", actual.category) assertEquals(1, actual.data?.keys?.size) assertEquals( - arrayListOf(mapOf( - "element" to "element4", - "file" to "file4")), - actual.data?.get("path")) + arrayListOf( + mapOf( + "element" to "element4", + "file" to "file4", + ), + ), + actual.data?.get("path"), + ) } @Test @@ -132,33 +138,47 @@ class RNSentryReplayBreadcrumbConverterTest { @Test fun doesNotConvertPathWithValuesMissingNameAndLevel() { - val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(arrayListOf(mapOf( - "element" to "element4", - "file" to "file4"))) + val actual = + RNSentryReplayBreadcrumbConverter.getTouchPathMessage( + arrayListOf( + mapOf( + "element" to "element4", + "file" to "file4", + ), + ), + ) assertEquals(null, actual) } @Test fun doesConvertValidPathExample1() { - val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(listOf( - mapOf("label" to "label0"), - mapOf("name" to "name1"), - mapOf("name" to "item2", "label" to "label2"), - mapOf("name" to "item3", "label" to "label3", "element" to "element3"), - mapOf("name" to "item4", "label" to "label4", "file" to "file4"), - mapOf("name" to "item5", "label" to "label5", "element" to "element5", "file" to "file5"))) + val actual = + RNSentryReplayBreadcrumbConverter.getTouchPathMessage( + listOf( + mapOf("label" to "label0"), + mapOf("name" to "name1"), + mapOf("name" to "item2", "label" to "label2"), + mapOf("name" to "item3", "label" to "label3", "element" to "element3"), + mapOf("name" to "item4", "label" to "label4", "file" to "file4"), + mapOf("name" to "item5", "label" to "label5", "element" to "element5", "file" to "file5"), + ), + ) assertEquals("label3(element3) > label2 > name1 > label0", actual) } @Test fun doesConvertValidPathExample2() { - val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(listOf( - mapOf("name" to "item2", "label" to "label2"), - mapOf("name" to "item3", "label" to "label3", "element" to "element3"), - mapOf("name" to "item4", "label" to "label4", "file" to "file4"), - mapOf("name" to "item5", "label" to "label5", "element" to "element5", "file" to "file5"), - mapOf("label" to "label6"), - mapOf("name" to "name7"))) + val actual = + RNSentryReplayBreadcrumbConverter.getTouchPathMessage( + listOf( + mapOf("name" to "item2", "label" to "label2"), + mapOf("name" to "item3", "label" to "label3", "element" to "element3"), + mapOf("name" to "item4", "label" to "label4", "file" to "file4"), + mapOf("name" to "item5", "label" to "label5", "element" to "element5", "file" to "file5"), + mapOf("label" to "label6"), + mapOf("name" to "name7"), + ), + ) assertEquals("label5(element5, file5) > label4(file4) > label3(element3) > label2", actual) } diff --git a/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/MainActivity.kt b/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/MainActivity.kt index ccf3c1560d..c80e9fb355 100644 --- a/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/MainActivity.kt +++ b/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/MainActivity.kt @@ -17,8 +17,7 @@ class MainActivity : ReactActivity() { * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] */ - override fun createReactActivityDelegate(): ReactActivityDelegate = - DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) + override fun createReactActivityDelegate(): ReactActivityDelegate = DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(null) diff --git a/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/MainApplication.kt b/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/MainApplication.kt index 680d7c72ac..07747f085c 100644 --- a/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/MainApplication.kt +++ b/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/MainApplication.kt @@ -13,12 +13,12 @@ import com.facebook.react.soloader.OpenSourceMergedSoMapping import com.facebook.soloader.SoLoader import io.sentry.Hint import io.sentry.SentryEvent -import io.sentry.SentryLevel import io.sentry.SentryOptions.BeforeSendCallback import io.sentry.android.core.SentryAndroid - -class MainApplication() : Application(), ReactApplication { +class MainApplication : + Application(), + ReactApplication { override val reactNativeHost: ReactNativeHost = object : DefaultReactNativeHost(this) { override fun getPackages(): List = @@ -28,7 +28,9 @@ class MainApplication() : Application(), ReactApplication { } override fun getJSMainModuleName(): String = "index" + override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG + override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED } @@ -55,21 +57,22 @@ class MainApplication() : Application(), ReactApplication { options.dsn = "https://1df17bd4e543fdb31351dee1768bb679@o447951.ingest.sentry.io/5428561" options.isDebug = true - options.beforeSend = BeforeSendCallback { event: SentryEvent, hint: Hint? -> - // React native internally throws a JavascriptException - // Since we catch it before that, we don't want to send this one - // because we would send it twice - try { - val ex = event.exceptions!![0] - if (null != ex && ex.type!!.contains("JavascriptException")) { - return@BeforeSendCallback null + options.beforeSend = + BeforeSendCallback { event: SentryEvent, hint: Hint? -> + // React native internally throws a JavascriptException + // Since we catch it before that, we don't want to send this one + // because we would send it twice + try { + val ex = event.exceptions!![0] + if (null != ex && ex.type!!.contains("JavascriptException")) { + return@BeforeSendCallback null + } + } catch (ignored: Throwable) { + // We do nothing } - } catch (ignored: Throwable) { - // We do nothing - } - event - } + event + } } } } diff --git a/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/NativePlatformSampleModule.kt b/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/NativePlatformSampleModule.kt index 6d7a6782b7..b2b0d4a25c 100644 --- a/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/NativePlatformSampleModule.kt +++ b/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/NativePlatformSampleModule.kt @@ -3,13 +3,12 @@ package io.sentry.reactnative.sample import com.facebook.fbreact.specs.NativePlatformSampleModuleSpec import com.facebook.react.bridge.ReactApplicationContext -class NativePlatformSampleModule(reactContext: ReactApplicationContext) : NativePlatformSampleModuleSpec(reactContext) { - +class NativePlatformSampleModule( + reactContext: ReactApplicationContext, +) : NativePlatformSampleModuleSpec(reactContext) { override fun getName() = NAME - override fun crashOrString(): String { - throw RuntimeException("JVM Crash in NativePlatformSampleModule.crashOrString()") - } + override fun crashOrString(): String = throw RuntimeException("JVM Crash in NativePlatformSampleModule.crashOrString()") companion object { const val NAME = "NativePlatformSampleModule" diff --git a/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/TurboSamplePackage.kt b/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/TurboSamplePackage.kt index ff2a5d3e64..3e51ffb59b 100644 --- a/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/TurboSamplePackage.kt +++ b/samples/react-native/android/app/src/main/java/io/sentry/reactnative/sample/TurboSamplePackage.kt @@ -11,29 +11,28 @@ class TurboSamplePackage : TurboReactPackage() { @Nullable override fun getModule( name: String, - reactApplicationContext: ReactApplicationContext - ): NativeModule? { - return if (name == NativePlatformSampleModule.NAME) { + reactApplicationContext: ReactApplicationContext, + ): NativeModule? = + if (name == NativePlatformSampleModule.NAME) { NativePlatformSampleModule(reactApplicationContext) } else { null } - } - override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { - return ReactModuleInfoProvider { + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = + ReactModuleInfoProvider { val moduleInfos: MutableMap = HashMap() - moduleInfos[NativePlatformSampleModule.NAME] = ReactModuleInfo( - NativePlatformSampleModule.NAME, - NativePlatformSampleModule.NAME, - false, // canOverrideExistingModule - false, // needsEagerInit - true, // hasConstants - false, // isCxxModule - true // isTurboModule - ) + moduleInfos[NativePlatformSampleModule.NAME] = + ReactModuleInfo( + NativePlatformSampleModule.NAME, + NativePlatformSampleModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + true, // isTurboModule + ) moduleInfos } - } } diff --git a/yarn.lock b/yarn.lock index 9b94e71247..30ddd80da8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5120,6 +5120,15 @@ __metadata: languageName: node linkType: hard +"@naturalcycles/ktlint@npm:^1.13.0": + version: 1.13.0 + resolution: "@naturalcycles/ktlint@npm:1.13.0" + bin: + ktlint: resources/ktlint + checksum: de8c75dd59993117ba04236adde7377d559349dda6cdfa94ef35c7ebe35b3671631eda7b442aca317eb7844f8f4e71b35d05c317d9537c8b74e80332ba984e00 + languageName: node + linkType: hard + "@nicolo-ribaudo/chokidar-2@npm:2.1.8-no-fsevents.3": version: 2.1.8-no-fsevents.3 resolution: "@nicolo-ribaudo/chokidar-2@npm:2.1.8-no-fsevents.3" @@ -24296,6 +24305,7 @@ __metadata: resolution: "sentry-react-native@workspace:." dependencies: "@expo/swiftlint": ^0.57.1 + "@naturalcycles/ktlint": ^1.13.0 "@sentry/cli": 2.40.0 clang-format: ^1.8.0 downlevel-dts: ^0.11.0