RN0.84 (#4926)
* iOS * Android * update * RN -0.84 android * update for android * test update for hardcoded height - from 412 to 394 * revert test update * all tests were running on latest RN instead of the right onw * yarn change * pod install update to run only once * patch for codegen for Android webview * some minor changes in regex and iOS install script * regex update * test update for android * another test update for android * very flaky test removed * removal of rules * reverted the removed test * API 36 fix for button test * safety added to BridgeIdlingResource.kt
@@ -5,7 +5,6 @@
|
||||
env:
|
||||
REACT_NATIVE_VERSION: 0.83.0
|
||||
RCT_NEW_ARCH_ENABLED: 1
|
||||
REACT_NATIVE_COMPAT_TEST: true # Only set 'true' in jobs with the latest supported RN
|
||||
DETOX_DISABLE_POD_INSTALL: true
|
||||
DETOX_DISABLE_POSTINSTALL: true
|
||||
artifact_paths:
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
- label: ":android::react: RN .84 + Android: Demo app"
|
||||
command:
|
||||
- "nvm install"
|
||||
- "./scripts/demo-projects.android.sh"
|
||||
env:
|
||||
REACT_NATIVE_VERSION: 0.84.0
|
||||
RCT_NEW_ARCH_ENABLED: 1
|
||||
REACT_NATIVE_COMPAT_TEST: true
|
||||
DETOX_DISABLE_POD_INSTALL: true
|
||||
DETOX_DISABLE_POSTINSTALL: true
|
||||
artifact_paths:
|
||||
- "/Users/builder/uibuilder/work/coverage/**/*.lcov"
|
||||
- "/Users/builder/uibuilder/work/artifacts*.tar.gz"
|
||||
@@ -0,0 +1,13 @@
|
||||
- label: ":android::detox: RN .84 + Android: Tests app"
|
||||
command:
|
||||
- "nvm install"
|
||||
- "./scripts/ci.android.sh"
|
||||
env:
|
||||
REACT_NATIVE_VERSION: 0.84.0
|
||||
RCT_NEW_ARCH_ENABLED: 1
|
||||
DETOX_DISABLE_POD_INSTALL: true
|
||||
DETOX_DISABLE_POSTINSTALL: true
|
||||
artifact_paths:
|
||||
- "/Users/builder/uibuilder/work/coverage/**/*.lcov"
|
||||
- "/Users/builder/uibuilder/work/**/allure-report-*.html"
|
||||
- "/Users/builder/uibuilder/work/artifacts*.tar.gz"
|
||||
@@ -5,7 +5,6 @@
|
||||
env:
|
||||
REACT_NATIVE_VERSION: 0.83.0
|
||||
RCT_NEW_ARCH_ENABLED: 1
|
||||
REACT_NATIVE_COMPAT_TEST: true # Only set 'true' in jobs with the latest supported RN
|
||||
artifact_paths:
|
||||
- "/Users/builder/uibuilder/work/coverage/**/*.lcov"
|
||||
- "/Users/builder/uibuilder/work/artifacts*.tar.gz"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
- label: ":ios::react: RN .84 + iOS: Demo app"
|
||||
command:
|
||||
- "nvm install"
|
||||
- "./scripts/demo-projects.ios.sh"
|
||||
env:
|
||||
REACT_NATIVE_VERSION: 0.84.0
|
||||
RCT_NEW_ARCH_ENABLED: 1
|
||||
REACT_NATIVE_COMPAT_TEST: true
|
||||
artifact_paths:
|
||||
- "/Users/builder/uibuilder/work/coverage/**/*.lcov"
|
||||
- "/Users/builder/uibuilder/work/artifacts*.tar.gz"
|
||||
@@ -0,0 +1,11 @@
|
||||
- label: ":ios::detox: RN .84 + iOS: Tests app"
|
||||
command:
|
||||
- "nvm install"
|
||||
- "./scripts/ci.ios.sh"
|
||||
env:
|
||||
REACT_NATIVE_VERSION: 0.84.0
|
||||
RCT_NEW_ARCH_ENABLED: 1
|
||||
artifact_paths:
|
||||
- "/Users/builder/uibuilder/work/coverage/**/*.lcov"
|
||||
- "/Users/builder/uibuilder/work/**/allure-report-*.html"
|
||||
- "/Users/builder/uibuilder/work/artifacts*.tar.gz"
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
echo "steps:"
|
||||
|
||||
cat .buildkite/jobs/pipeline.android_demo_app_rn_83.yml
|
||||
cat .buildkite/jobs/pipeline.android_demo_app_rn_84.yml
|
||||
cat .buildkite/jobs/pipeline.android_rn_77.yml
|
||||
cat .buildkite/jobs/pipeline.android_rn_83.yml
|
||||
cat .buildkite/jobs/pipeline.ios_demo_app_rn_83.yml
|
||||
cat .buildkite/jobs/pipeline.android_rn_84.yml
|
||||
cat .buildkite/jobs/pipeline.ios_demo_app_rn_84.yml
|
||||
cat .buildkite/jobs/pipeline.ios_rn_77.yml
|
||||
cat .buildkite/jobs/pipeline.ios_rn_83.yml
|
||||
cat .buildkite/jobs/pipeline.ios_rn_84.yml
|
||||
cat .buildkite/pipeline.post_processing.yml
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
description: Rules to help Cursor write code that is more Detox idomatic
|
||||
globs: *.js
|
||||
alwaysApply: false
|
||||
---
|
||||
- Whenever an Error needs to be thrown, prefer throwing a DetoxRuntimeError with a proper message and hint.
|
||||
|
||||
- Minimize comments usage, especially in-line ones. Leave comments where things are exceptionally unclear for some reason.
|
||||
@@ -1,62 +0,0 @@
|
||||
---
|
||||
Description: Rules to help Cursor write unit tests code that aligns with the project's standards
|
||||
globs: *.test.js,*.test.ts
|
||||
alwaysApply: false
|
||||
---
|
||||
# Project Rules
|
||||
|
||||
## Jest Unit Testing
|
||||
|
||||
In Jest unit test files, **never perform mocking globally**. Instead, perform all mocks inside the `beforeEach()` section.
|
||||
|
||||
### Rationale
|
||||
- Keeps test setup centralized and visible
|
||||
- Ensures mocks are reset between tests
|
||||
- Makes test dependencies explicit
|
||||
- Prevents test pollution from global mocks
|
||||
|
||||
### Example
|
||||
|
||||
❌ **Don't do this:**
|
||||
```javascript
|
||||
const mockSleep = jest.fn().mockResolvedValue(undefined);
|
||||
jest.mock('../../../../utils/sleep', () => mockSleep);
|
||||
|
||||
describe('MyClass', () => {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
✅ **Do this instead:**
|
||||
```javascript
|
||||
describe('MyClass', () => {
|
||||
let mockSleep;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.mock('../../../../utils/sleep');
|
||||
mockSleep = require('../../../../utils/sleep');
|
||||
mockSleep.mockResolvedValue(undefined);
|
||||
|
||||
// ... other setup
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Alternatively, in cases where jest.mock() doesn't work well out of the box, this can be performed too:
|
||||
|
||||
```javascript
|
||||
beforeEach(() => {
|
||||
jest.mock('../../../../utils/sleep', () => jest.fn().mockResolvedValue(undefined));
|
||||
mockSleep = require('../../../../utils/sleep');
|
||||
});
|
||||
|
||||
// Or if the sleep js module actually exports an object:
|
||||
beforeEach(() => {
|
||||
jest.mock('../../../../utils/sleep', () => ({
|
||||
sleep: jest.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
mockSleep = require('../../../../utils/sleep');
|
||||
});
|
||||
```
|
||||
|
||||
Note: `jest.mock()` must still be called at the module level (for hoisting), but all mock configuration should happen in `beforeEach()`.
|
||||
@@ -49,6 +49,7 @@ jspm_packages
|
||||
################
|
||||
.idea
|
||||
.vscode
|
||||
.cursor
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
@@ -63,7 +63,7 @@ Detox was built from the ground up to support React Native projects.
|
||||
While Detox should work out of the box with any React Native version of the latest minor releases,
|
||||
the _official_ versions compatibility is provided according to the following:
|
||||
|
||||
- **RN `v0.77.x` - `v0.83.x`:** Fully compatible with React Native's ["New Architecture"](https://reactnative.dev/docs/the-new-architecture/landing-page).
|
||||
- **RN `v0.77.x` - `v0.84.x`:** Fully compatible with React Native's ["New Architecture"](https://reactnative.dev/docs/the-new-architecture/landing-page).
|
||||
Newer RN versions might work with Detox, but they've not been thoroughly tested by the Detox team yet.
|
||||
|
||||
Although we do not officially support older React Native versions, we do our best to keep Detox compatible with them.
|
||||
|
||||
@@ -14,7 +14,7 @@ fun ReactApplication.getInstanceManagerSafe(): ReactInstanceManager {
|
||||
|
||||
@SuppressLint("VisibleForTests")
|
||||
fun ReactApplication.getCurrentReactContext(): ReactContext? {
|
||||
return if (isFabricEnabled()) {
|
||||
return if (isFabricEnabled() || ReactNativeInfo.isNewArchitectureOnlyVersion()) {
|
||||
reactHost?.currentReactContext
|
||||
} else {
|
||||
getInstanceManagerSafe().currentReactContext
|
||||
|
||||
@@ -2,10 +2,16 @@ package com.wix.detox.reactnative
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.facebook.react.ReactApplication
|
||||
import com.facebook.react.bridge.ReactContext
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule
|
||||
import com.wix.detox.LaunchArgs
|
||||
import com.wix.detox.reactnative.idlingresources.ReactNativeIdlingResources
|
||||
import com.wix.detox.reactnative.reloader.ReactNativeReloaderFactory
|
||||
@@ -14,6 +20,7 @@ private const val LOG_TAG = "DetoxRNExt"
|
||||
|
||||
object ReactNativeExtension {
|
||||
private var rnIdlingResources: ReactNativeIdlingResources? = null
|
||||
private var backPressCallbackRegistered = false
|
||||
|
||||
fun initIfNeeded() {
|
||||
if (!ReactNativeInfo.isReactNativeApp()) {
|
||||
@@ -37,6 +44,7 @@ object ReactNativeExtension {
|
||||
awaitNewReactNativeContext(it, null)
|
||||
|
||||
enableOrDisableSynchronization(it)
|
||||
registerBackPressCallbackIfNeeded(applicationContext, it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +66,7 @@ object ReactNativeExtension {
|
||||
|
||||
(applicationContext as ReactApplication).let {
|
||||
clearIdlingResources()
|
||||
backPressCallbackRegistered = false
|
||||
|
||||
val previousReactContext = it.getCurrentReactContext()
|
||||
|
||||
@@ -65,6 +74,7 @@ object ReactNativeExtension {
|
||||
awaitNewReactNativeContext(it, previousReactContext)
|
||||
|
||||
enableOrDisableSynchronization(it)
|
||||
registerBackPressCallbackIfNeeded(applicationContext, it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +120,43 @@ object ReactNativeExtension {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On API 35+, the system routes back presses through [OnBackPressedDispatcher] instead of
|
||||
* calling [Activity.onBackPressed]. Older RN versions (< 0.83) don't register an
|
||||
* [OnBackPressedCallback], so the back press bypasses React Native's BackHandler entirely,
|
||||
* causing the activity to finish instead of letting JS handle it.
|
||||
*
|
||||
* This registers a callback that routes back presses through [ReactInstanceManager.onBackPressed],
|
||||
* restoring the expected behavior.
|
||||
*/
|
||||
private fun registerBackPressCallbackIfNeeded(context: Context, reactApp: ReactApplication) {
|
||||
if (backPressCallbackRegistered) return
|
||||
if (Build.VERSION.SDK_INT < 35) return
|
||||
if (ReactNativeInfo.isNewArchitectureOnlyVersion()) return
|
||||
|
||||
val activity = getRNActivity(context) as? ComponentActivity ?: return
|
||||
|
||||
val callback = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
try {
|
||||
val reactContext = reactApp.getCurrentReactContext()
|
||||
reactContext
|
||||
?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
||||
?.emit("hardwareBackPress", null)
|
||||
?: Log.w(LOG_TAG, "ReactContext is null, cannot emit hardwareBackPress")
|
||||
} catch (e: Exception) {
|
||||
Log.w(LOG_TAG, "Failed to emit hardwareBackPress", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backPressCallbackRegistered = true
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
activity.onBackPressedDispatcher.addCallback(activity, callback)
|
||||
Log.i(LOG_TAG, "Registered OnBackPressedCallback for legacy RN back press handling")
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadReactNativeInBackground(reactApplication: ReactApplication) {
|
||||
val rnReloader = ReactNativeReloaderFactory(InstrumentationRegistry.getInstrumentation(), reactApplication).create()
|
||||
rnReloader.reloadInBackground()
|
||||
|
||||
@@ -12,6 +12,13 @@ object ReactNativeInfo {
|
||||
@JvmStatic
|
||||
fun rnVersion() = rnVersion
|
||||
|
||||
@JvmStatic
|
||||
fun isNewArchitectureOnlyVersion(): Boolean {
|
||||
return rnVersion.run {
|
||||
major > 0 || (major == 0 && minor >= 84)
|
||||
}
|
||||
}
|
||||
|
||||
fun isReactNativeApp(): Boolean = try {
|
||||
Class.forName("com.facebook.react.ReactApplication")
|
||||
true
|
||||
|
||||
@@ -83,8 +83,8 @@ open class ReactNativeLoadingMonitor(
|
||||
reactContext != null && reactContext !== previousReactContext && reactContext.hasActiveReactInstance()
|
||||
|
||||
private fun subscribeAsyncRNContextHandler(onReactContextInitialized: () -> Any) {
|
||||
val isFabric = isFabricEnabled()
|
||||
if (isFabric) {
|
||||
val useNewArchitectureListener = isFabricEnabled() || ReactNativeInfo.isNewArchitectureOnlyVersion()
|
||||
if (useNewArchitectureListener) {
|
||||
// We do a casting for supporting RN 0.75 and above
|
||||
val host = rnApplication.reactHost as ReactHostImpl?
|
||||
host?.addReactInstanceEventListener(object : ReactInstanceEventListener {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.wix.detox.reactnative.idlingresources.bridge
|
||||
|
||||
import android.util.Log
|
||||
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener
|
||||
import com.facebook.react.bridge.ReactContext
|
||||
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
||||
import java.lang.reflect.InvocationHandler
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Proxy
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
/**
|
||||
@@ -16,16 +18,25 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||
* React Native's JS bridge.
|
||||
*
|
||||
*/
|
||||
class BridgeIdlingResource(private val reactContext: ReactContext) : DetoxIdlingResource(),
|
||||
NotThreadSafeBridgeIdleDebugListener {
|
||||
class BridgeIdlingResource(private val reactContext: ReactContext) : DetoxIdlingResource() {
|
||||
private val idleNow = AtomicBoolean(true)
|
||||
private val bridgeIdleListenerApi = BridgeIdleListenerApi(reactContext)
|
||||
|
||||
init {
|
||||
reactContext.catalystInstance.addBridgeIdleDebugListener(this)
|
||||
bridgeIdleListenerApi.attach(
|
||||
onBridgeIdle = {
|
||||
idleNow.set(true)
|
||||
notifyIdle()
|
||||
},
|
||||
onBridgeBusy = {
|
||||
idleNow.set(false)
|
||||
},
|
||||
onBridgeDestroyed = {}
|
||||
)
|
||||
}
|
||||
|
||||
fun onDetach() {
|
||||
reactContext.catalystInstance.removeBridgeIdleDebugListener(this)
|
||||
bridgeIdleListenerApi.detach()
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
@@ -48,19 +59,6 @@ class BridgeIdlingResource(private val reactContext: ReactContext) : DetoxIdling
|
||||
return ret
|
||||
}
|
||||
|
||||
override fun onTransitionToBridgeIdle() {
|
||||
idleNow.set(true)
|
||||
notifyIdle()
|
||||
}
|
||||
|
||||
override fun onTransitionToBridgeBusy() {
|
||||
idleNow.set(false)
|
||||
// Log.i(LOG_TAG, "JS Bridge transitions to busy.");
|
||||
}
|
||||
|
||||
override fun onBridgeDestroyed() {
|
||||
}
|
||||
|
||||
override fun onUnregistered() {
|
||||
super.onUnregistered()
|
||||
onDetach()
|
||||
@@ -70,3 +68,72 @@ class BridgeIdlingResource(private val reactContext: ReactContext) : DetoxIdling
|
||||
private const val LOG_TAG = "Detox"
|
||||
}
|
||||
}
|
||||
|
||||
private class BridgeIdleListenerApi(private val reactContext: ReactContext) {
|
||||
private var listenerProxy: Any? = null
|
||||
private var removeListenerMethod: Method? = null
|
||||
|
||||
fun attach(
|
||||
onBridgeIdle: () -> Unit,
|
||||
onBridgeBusy: () -> Unit,
|
||||
onBridgeDestroyed: () -> Unit,
|
||||
) {
|
||||
try {
|
||||
val listenerClass = Class.forName(BRIDGE_IDLE_LISTENER_CLASS_NAME)
|
||||
val catalystInstance = reactContext.catalystInstance
|
||||
val addListenerMethod = catalystInstance.javaClass.methods.firstOrNull { method ->
|
||||
method.name == ADD_LISTENER_METHOD && method.parameterTypes.contentEquals(arrayOf(listenerClass))
|
||||
} ?: run {
|
||||
Log.i(LOG_TAG, "RN bridge idle debug listener API is unavailable.")
|
||||
return
|
||||
}
|
||||
|
||||
val proxy = Proxy.newProxyInstance(
|
||||
listenerClass.classLoader,
|
||||
arrayOf(listenerClass),
|
||||
InvocationHandler { proxy, method, args ->
|
||||
when (method.name) {
|
||||
ON_BRIDGE_IDLE_METHOD -> onBridgeIdle()
|
||||
ON_BRIDGE_BUSY_METHOD -> onBridgeBusy()
|
||||
ON_BRIDGE_DESTROYED_METHOD -> onBridgeDestroyed()
|
||||
"equals" -> proxy === args?.firstOrNull()
|
||||
"hashCode" -> System.identityHashCode(proxy)
|
||||
"toString" -> "BridgeIdleListenerProxy"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
addListenerMethod.invoke(catalystInstance, proxy)
|
||||
listenerProxy = proxy
|
||||
removeListenerMethod = catalystInstance.javaClass.methods.firstOrNull { method ->
|
||||
method.name == REMOVE_LISTENER_METHOD && method.parameterTypes.contentEquals(arrayOf(listenerClass))
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Log.w(LOG_TAG, "Could not attach RN bridge idle debug listener.", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun detach() {
|
||||
val listener = listenerProxy ?: return
|
||||
val removeMethod = removeListenerMethod ?: return
|
||||
try {
|
||||
removeMethod.invoke(reactContext.catalystInstance, listener)
|
||||
} catch (e: Throwable) {
|
||||
Log.w(LOG_TAG, "Could not detach RN bridge idle debug listener.", e)
|
||||
} finally {
|
||||
listenerProxy = null
|
||||
removeListenerMethod = null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val LOG_TAG = "Detox"
|
||||
private const val BRIDGE_IDLE_LISTENER_CLASS_NAME =
|
||||
"com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener"
|
||||
private const val ADD_LISTENER_METHOD = "addBridgeIdleDebugListener"
|
||||
private const val REMOVE_LISTENER_METHOD = "removeBridgeIdleDebugListener"
|
||||
private const val ON_BRIDGE_IDLE_METHOD = "onTransitionToBridgeIdle"
|
||||
private const val ON_BRIDGE_BUSY_METHOD = "onTransitionToBridgeBusy"
|
||||
private const val ON_BRIDGE_DESTROYED_METHOD = "onBridgeDestroyed"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.wix.detox.reactnative.idlingresources.factory
|
||||
|
||||
import com.facebook.react.ReactApplication
|
||||
import com.wix.detox.reactnative.ReactNativeInfo
|
||||
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
||||
import com.wix.detox.reactnative.isFabricEnabled
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -9,7 +10,8 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
class DetoxIdlingResourceFactory(private val reactApplication: ReactApplication) {
|
||||
suspend fun create(): Map<IdlingResourcesName, DetoxIdlingResource> = withContext(Dispatchers.Main) {
|
||||
val strategy = if (isFabricEnabled()) {
|
||||
val useNewArchitectureStrategy = isFabricEnabled() || ReactNativeInfo.isNewArchitectureOnlyVersion()
|
||||
val strategy = if (useNewArchitectureStrategy) {
|
||||
FabricDetoxIdlingResourceFactoryStrategy(reactApplication)
|
||||
} else {
|
||||
OldArchitectureDetoxIdlingResourceFactoryStrategy(reactApplication)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.wix.detox.reactnative.idlingresources.uimodule.fabric
|
||||
|
||||
import android.os.SystemClock
|
||||
import android.view.Choreographer
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import com.facebook.react.bridge.ReactContext
|
||||
@@ -15,14 +16,51 @@ class FabricUIManagerIdlingResources(
|
||||
private val reactContext: ReactContext
|
||||
) : DetoxIdlingResource(), Choreographer.FrameCallback {
|
||||
|
||||
private var firstBusyTimestamp: Long = 0
|
||||
private var isSteadyState: Boolean = false
|
||||
|
||||
override fun checkIdle(): Boolean {
|
||||
return if (getViewCommandMountItemsSize() == 0 && getMountItemsSize() == 0) {
|
||||
val mountItemsCount = getMountItemsSize()
|
||||
val viewCommandMountItemsCount = getViewCommandMountItemsSize()
|
||||
|
||||
if (mountItemsCount == 0 && viewCommandMountItemsCount == 0) {
|
||||
firstBusyTimestamp = 0
|
||||
isSteadyState = false
|
||||
notifyIdle()
|
||||
true
|
||||
} else {
|
||||
Choreographer.getInstance().postFrameCallback(this)
|
||||
false
|
||||
return true
|
||||
}
|
||||
|
||||
// Once we've determined this is a steady-state (a stuck mount item that never
|
||||
// resolves), keep reporting idle as long as the count stays low.
|
||||
if (isSteadyState && mountItemsCount <= 1 && viewCommandMountItemsCount == 0) {
|
||||
notifyIdle()
|
||||
return true
|
||||
}
|
||||
|
||||
// Count increased beyond steady-state threshold — reset and treat as genuinely busy.
|
||||
if (isSteadyState) {
|
||||
isSteadyState = false
|
||||
firstBusyTimestamp = 0
|
||||
}
|
||||
|
||||
val now = SystemClock.uptimeMillis()
|
||||
if (firstBusyTimestamp == 0L) {
|
||||
firstBusyTimestamp = now
|
||||
}
|
||||
|
||||
// On API 36+, edge-to-edge enforcement can cause a single mount item to remain
|
||||
// permanently in the queue on older RN versions. If the count stays at 1 for over
|
||||
// 1.5s, treat it as a steady-state condition rather than a genuinely busy UI.
|
||||
if (now - firstBusyTimestamp >= BUSY_TOLERANCE_MS
|
||||
&& mountItemsCount <= 1
|
||||
&& viewCommandMountItemsCount == 0) {
|
||||
isSteadyState = true
|
||||
notifyIdle()
|
||||
return true
|
||||
}
|
||||
|
||||
Choreographer.getInstance().postFrameCallback(this)
|
||||
return false
|
||||
}
|
||||
|
||||
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
|
||||
@@ -78,4 +116,7 @@ class FabricUIManagerIdlingResources(
|
||||
return viewCommandMountItems.size
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val BUSY_TOLERANCE_MS = 1500L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.wix.detox.reactnative.reloader
|
||||
|
||||
import android.app.Instrumentation
|
||||
import com.facebook.react.ReactApplication
|
||||
import com.wix.detox.reactnative.ReactNativeInfo
|
||||
import com.wix.detox.reactnative.isFabricEnabled
|
||||
|
||||
class ReactNativeReloaderFactory(
|
||||
@@ -11,7 +12,8 @@ class ReactNativeReloaderFactory(
|
||||
|
||||
fun create(): ReactNativeReLoader {
|
||||
return when {
|
||||
isFabricEnabled() -> NewArchitectureNativeReLoader(instrumentation, rnApplication)
|
||||
isFabricEnabled() || ReactNativeInfo.isNewArchitectureOnlyVersion() ->
|
||||
NewArchitectureNativeReLoader(instrumentation, rnApplication)
|
||||
else -> OldArchReactNativeReLoader(instrumentation, rnApplication)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,4 +48,5 @@ ext.rnInfo = [
|
||||
isRN79OrHigher: rnMajorVer >= 79,
|
||||
isRN80OrHigher: rnMajorVer >= 80,
|
||||
isRN81OrHigher: rnMajorVer >= 81,
|
||||
isRN84OrHigher: rnMajorVer >= 84,
|
||||
]
|
||||
|
||||
@@ -275,6 +275,10 @@ class Element : NSObject {
|
||||
|
||||
@objc
|
||||
var value: String? {
|
||||
if let slider = view.dtx_sliderView {
|
||||
return slider.accessibilityValue
|
||||
}
|
||||
|
||||
return view.accessibilityValue
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
"jest-allure2-reporter": "^2.2.6",
|
||||
"metro-react-native-babel-preset": "0.76.8",
|
||||
"prettier": "^3.1.1",
|
||||
"react-native": "0.83.0",
|
||||
"react-native": "0.84.0",
|
||||
"react-native-codegen": "^0.0.8",
|
||||
"typescript": "^5.8.3",
|
||||
"wtfnode": "^0.9.1"
|
||||
|
||||
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 81 KiB |
@@ -701,7 +701,10 @@
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(OTHER_CFLAGS)",
|
||||
"-DFOLLY_NO_CONFIG",
|
||||
@@ -709,6 +712,7 @@
|
||||
"-DFOLLY_USE_LIBCPP=1",
|
||||
"-DFOLLY_CFG_NO_COROUTINES=1",
|
||||
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -717,6 +721,7 @@
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
||||
USE_HERMES = true;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -774,7 +779,10 @@
|
||||
"\"$(inherited)\"",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(OTHER_CFLAGS)",
|
||||
"-DFOLLY_NO_CONFIG",
|
||||
@@ -782,6 +790,7 @@
|
||||
"-DFOLLY_USE_LIBCPP=1",
|
||||
"-DFOLLY_CFG_NO_COROUTINES=1",
|
||||
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -789,6 +798,7 @@
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
||||
USE_HERMES = true;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
"@react-native-picker/picker": "^2.11.2",
|
||||
"@react-native-segmented-control/segmented-control": "^2.5.6",
|
||||
"moment": "^2.30.1",
|
||||
"react": "19.2.0",
|
||||
"react-native": "0.83.0",
|
||||
"react": "19.2.3",
|
||||
"react-native": "0.84.0",
|
||||
"react-native-launch-arguments": "^4.0.2",
|
||||
"react-native-permissions": "^5.2.1",
|
||||
"react-native-webview": "^13.13.1",
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const log = message => console.log(`[PATCH-WEBVIEW] ${message}`);
|
||||
|
||||
const testAppRoot = path.resolve(__dirname, '..');
|
||||
const reactNativePackageJsonPath = path.join(testAppRoot, 'node_modules/react-native/package.json');
|
||||
const webViewSpecPath = path.join(testAppRoot, 'node_modules/react-native-webview/src/RNCWebViewNativeComponent.ts');
|
||||
|
||||
if (!fs.existsSync(reactNativePackageJsonPath) || !fs.existsSync(webViewSpecPath)) {
|
||||
log('react-native or react-native-webview is missing, skipping.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const reactNativeVersion = JSON.parse(fs.readFileSync(reactNativePackageJsonPath, 'utf8')).version;
|
||||
const [major, minor] = reactNativeVersion.split('.').map(Number);
|
||||
if (major !== 0 || minor < 84) {
|
||||
log(`react-native@${reactNativeVersion} does not need the WebView patch, skipping.`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
let webViewSpec = fs.readFileSync(webViewSpecPath, 'utf8');
|
||||
const navigationTypeUnion = /navigationType:\s*\|?\s*'click'\s*\|\s*'formsubmit'\s*\|\s*'backforward'\s*\|\s*'reload'\s*\|\s*'formresubmit'\s*\|\s*'other';/g;
|
||||
|
||||
if (!navigationTypeUnion.test(webViewSpec)) {
|
||||
log('Spec already patched or changed, skipping.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
navigationTypeUnion.lastIndex = 0;
|
||||
log('Patching react-native-webview navigationType union → string for Android codegen compatibility...');
|
||||
webViewSpec = webViewSpec.replace(navigationTypeUnion, 'navigationType: string;');
|
||||
fs.writeFileSync(webViewSpecPath, webViewSpec, 'utf8');
|
||||
log('Done.');
|
||||
@@ -7,7 +7,7 @@ Detox was built from the ground up to support "classic" React Native projects.
|
||||
While Detox should work out of the box with any React Native version of the latest minor releases,
|
||||
the _official_ versions compatibility is provided according to the following:
|
||||
|
||||
- **RN `v0.77.x` - `v0.82.x`:** Fully compatible with React Native's ["New Architecture"](https://reactnative.dev/docs/the-new-architecture/landing-page).
|
||||
- **RN `v0.77.x` - `v0.84.x`:** Fully compatible with React Native's ["New Architecture"](https://reactnative.dev/docs/the-new-architecture/landing-page).
|
||||
Newer RN versions might work with Detox, but they've not been thoroughly tested by the Detox team yet.
|
||||
|
||||
Although we do not officially support older React Native versions, we do our best to keep Detox compatible with them.
|
||||
|
||||
@@ -228,10 +228,14 @@
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks.sh",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/React-Core-prebuilt/React.framework/React",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/ReactNativeDependencies/ReactNativeDependencies.framework/ReactNativeDependencies",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermesvm.framework/hermesvm",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactNativeDependencies.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermesvm.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -246,21 +250,15 @@
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
@@ -409,12 +407,19 @@
|
||||
LDPLUSPLUS = "";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
||||
USE_HERMES = true;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -462,11 +467,18 @@
|
||||
LD = "";
|
||||
LDPLUSPLUS = "";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
||||
USE_HERMES = true;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-async-storage/async-storage": "^2.1.0",
|
||||
"react": "19.2.0",
|
||||
"react-native": "0.83.0",
|
||||
"react": "19.2.3",
|
||||
"react-native": "0.84.0",
|
||||
"tslib": "^2.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -5,6 +5,5 @@ if [ ! -z ${REACT_NATIVE_VERSION} ]; then
|
||||
node scripts/change_react_native_version.js "detox/test" ${REACT_NATIVE_VERSION} "dependencies"
|
||||
node scripts/change_react_native_version.js "detox" ${REACT_NATIVE_VERSION} "devDependencies"
|
||||
|
||||
# Update lockfile for the new RN version
|
||||
yarn install --mode update-lockfile
|
||||
YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn install
|
||||
fi
|
||||
|
||||
@@ -23,6 +23,7 @@ mkdir -p coverage
|
||||
### E2E self-tests
|
||||
pushd detox/test
|
||||
|
||||
run_f "node scripts/patch-webview-codegen.js"
|
||||
run_f "yarn build:android-debug" # Workaround for asyncstorage issue https://github.com/react-native-async-storage/async-storage/issues/1216. Can be removed after fixing it
|
||||
run_f "yarn build:android"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Detox was built from the ground up to support "classic" React Native projects.
|
||||
While Detox should work out of the box with any React Native version of the latest minor releases,
|
||||
the _official_ versions compatibility is provided according to the following:
|
||||
|
||||
- **RN `v0.77.x` - `v0.82.x`:** Fully compatible with React Native's ["New Architecture"](https://reactnative.dev/docs/the-new-architecture/landing-page).
|
||||
- **RN `v0.77.x` - `v0.84.x`:** Fully compatible with React Native's ["New Architecture"](https://reactnative.dev/docs/the-new-architecture/landing-page).
|
||||
Newer RN versions might work with Detox, but they've not been thoroughly tested by the Detox team yet.
|
||||
|
||||
Although we do not officially support older React Native versions, we do our best to keep Detox compatible with them.
|
||||
|
||||
@@ -3966,10 +3966,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/assets-registry@npm:0.83.0":
|
||||
version: 0.83.0
|
||||
resolution: "@react-native/assets-registry@npm:0.83.0"
|
||||
checksum: 10/9c314a311739e5ea555155df54821f888f3c61de6bcd71db60a253b27aefb42116892d487efb57a5ba99998c9835e1b123019bfe4397c087d0bcef38bad43c8c
|
||||
"@react-native/assets-registry@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "@react-native/assets-registry@npm:0.84.0"
|
||||
checksum: 10/9f972a0e46494aafddbed140f3256615dd2d2675055b8a3dbe05ca0c30d2d89a7a960fbe6580e327a850d870203b8e89247adfd3ed629c0b54d905c6fd5dbcb3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4055,11 +4055,28 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/community-cli-plugin@npm:0.83.0":
|
||||
version: 0.83.0
|
||||
resolution: "@react-native/community-cli-plugin@npm:0.83.0"
|
||||
"@react-native/codegen@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "@react-native/codegen@npm:0.84.0"
|
||||
dependencies:
|
||||
"@react-native/dev-middleware": "npm:0.83.0"
|
||||
"@babel/core": "npm:^7.25.2"
|
||||
"@babel/parser": "npm:^7.25.3"
|
||||
hermes-parser: "npm:0.32.0"
|
||||
invariant: "npm:^2.2.4"
|
||||
nullthrows: "npm:^1.1.1"
|
||||
tinyglobby: "npm:^0.2.15"
|
||||
yargs: "npm:^17.6.2"
|
||||
peerDependencies:
|
||||
"@babel/core": "*"
|
||||
checksum: 10/1b81de2bcccbf570efb42cf8aaa4a551ececdc510ce9c9c2230f8eafdd0eeec25729307340993a769eca94c99e343499ba0aeec4427e3e7976914c01055732f7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/community-cli-plugin@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "@react-native/community-cli-plugin@npm:0.84.0"
|
||||
dependencies:
|
||||
"@react-native/dev-middleware": "npm:0.84.0"
|
||||
debug: "npm:^4.4.0"
|
||||
invariant: "npm:^2.2.4"
|
||||
metro: "npm:^0.83.3"
|
||||
@@ -4074,34 +4091,35 @@ __metadata:
|
||||
optional: true
|
||||
"@react-native/metro-config":
|
||||
optional: true
|
||||
checksum: 10/b0a664d828270c7be320c84b6f6f37dc08682d899157865cd8655f5bac99d2b990c9cc4dcaf57f4c284c698af41dd97bc4acd34fec5fc052f535c83a74cf0cb9
|
||||
checksum: 10/3d1d0fa6e5d904b9d3fc55c417e2f561daa8ace734ba0e4fd4cd6abb73967fe0756ec34f7a04b2f98b21eb834cffba869a79e26c57612c66c67054f6995d44b2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/debugger-frontend@npm:0.83.0":
|
||||
version: 0.83.0
|
||||
resolution: "@react-native/debugger-frontend@npm:0.83.0"
|
||||
checksum: 10/3f52e5400c24173f7619d35be95b6899f15e087e218d8ad580a5a931e908c2d0ef0e752619a73752bc5ed18f35a96fd38723c1967fa65f68e9f8cc6bd43972dc
|
||||
"@react-native/debugger-frontend@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "@react-native/debugger-frontend@npm:0.84.0"
|
||||
checksum: 10/93435f6bb8cc69195846a25453639eeaa6b261113fae8957e3c7f28c0302e25ea89fc757bf7bb971e2e5caa0672b228fbaddbf5ab2c844d2a6365522e3fa7edd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/debugger-shell@npm:0.83.0":
|
||||
version: 0.83.0
|
||||
resolution: "@react-native/debugger-shell@npm:0.83.0"
|
||||
"@react-native/debugger-shell@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "@react-native/debugger-shell@npm:0.84.0"
|
||||
dependencies:
|
||||
cross-spawn: "npm:^7.0.6"
|
||||
debug: "npm:^4.4.0"
|
||||
fb-dotslash: "npm:0.5.8"
|
||||
checksum: 10/51b61131b90a9e09f259a5999759b77d9384cf9b0f38e4c4da1b63a1a729126349f9d20f51d599e527ebe5430945e2e1ddde17d933aa30c0775e2437694db50f
|
||||
checksum: 10/5e29a717ce5384735f9db32fb3f073ec1bf53d7fd136780433befa04f0d31275ef5aaebc91e1e923518add0e77a70cfbcc9dc374b01a8bcf71944747d2f7bbde
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/dev-middleware@npm:0.83.0":
|
||||
version: 0.83.0
|
||||
resolution: "@react-native/dev-middleware@npm:0.83.0"
|
||||
"@react-native/dev-middleware@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "@react-native/dev-middleware@npm:0.84.0"
|
||||
dependencies:
|
||||
"@isaacs/ttlcache": "npm:^1.4.1"
|
||||
"@react-native/debugger-frontend": "npm:0.83.0"
|
||||
"@react-native/debugger-shell": "npm:0.83.0"
|
||||
"@react-native/debugger-frontend": "npm:0.84.0"
|
||||
"@react-native/debugger-shell": "npm:0.84.0"
|
||||
chrome-launcher: "npm:^0.15.2"
|
||||
chromium-edge-launcher: "npm:^0.2.0"
|
||||
connect: "npm:^3.6.5"
|
||||
@@ -4111,7 +4129,7 @@ __metadata:
|
||||
open: "npm:^7.0.3"
|
||||
serve-static: "npm:^1.16.2"
|
||||
ws: "npm:^7.5.10"
|
||||
checksum: 10/524df13d559e4593887b6183cedafb43ea0d6b07e4b04b527549efcce03e2809044937c7fc0c6483fc14fb237d74b0c706c2fd01825e3abb5a3cc009a27aba8b
|
||||
checksum: 10/ac061225f248821e2d90f201423e51b23431444ef76ea5bd5cc7a5467cee40fa6c780a1d80a0bb926cb9c25d79811eb1e4de663e42202fd3776a6ea43cda8ea4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4145,10 +4163,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/gradle-plugin@npm:0.83.0":
|
||||
version: 0.83.0
|
||||
resolution: "@react-native/gradle-plugin@npm:0.83.0"
|
||||
checksum: 10/dcd7a47b21629a78a6f079a16a87d85ed78214dd19efafb054e7718624774b07e8c10572d054b9e31ac80c96148127a40da164b44e04e8aa434cfb93ead258fc
|
||||
"@react-native/gradle-plugin@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "@react-native/gradle-plugin@npm:0.84.0"
|
||||
checksum: 10/161c956b010a63f495c6d5fbe90446f7f4b71a584e315b0e2244cc8084f43241445650e90ab816187071fff8253481156c20d94251620786ad5076a7bf9cf622
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4159,6 +4177,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/js-polyfills@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "@react-native/js-polyfills@npm:0.84.0"
|
||||
checksum: 10/5b2927aee2f7106cfe2531f9fce4ef1563c207223a34a6ec2aec886b475b78e507a8dd23a9e2c9a0afafbaff56a53e23dec93c6b4dc14b224d026bbed4304d97
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/metro-babel-transformer@npm:0.83.0":
|
||||
version: 0.83.0
|
||||
resolution: "@react-native/metro-babel-transformer@npm:0.83.0"
|
||||
@@ -4185,10 +4210,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/normalize-colors@npm:0.83.0":
|
||||
version: 0.83.0
|
||||
resolution: "@react-native/normalize-colors@npm:0.83.0"
|
||||
checksum: 10/84e3122bd0292ae9ee61a6d2997119196a5dc128ede7770a2a70e3b9de1b78f5f2a10b44dc683ce2652ad8f45767f249a74d1a86f7657a5dae7a377790512f68
|
||||
"@react-native/normalize-colors@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "@react-native/normalize-colors@npm:0.84.0"
|
||||
checksum: 10/038a4687c023b4799126efc4b2d8b91abdb806fdc90af5b749b552b2c311d7459893f6c583941c1baed1c906ab437804916da2cdfc666a431c98482ddb62672a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4199,9 +4224,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native/virtualized-lists@npm:0.83.0":
|
||||
version: 0.83.0
|
||||
resolution: "@react-native/virtualized-lists@npm:0.83.0"
|
||||
"@react-native/virtualized-lists@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "@react-native/virtualized-lists@npm:0.84.0"
|
||||
dependencies:
|
||||
invariant: "npm:^2.2.4"
|
||||
nullthrows: "npm:^1.1.1"
|
||||
@@ -4212,7 +4237,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10/b51a3c0c110b6d259b6cf25fa4d143b03cbd6b637e5b33ea07453c0aa12a061e2f861a67c1b4089f96817ef46a1bd3709ecae3133026e92b77979b96a08bff06
|
||||
checksum: 10/9a701e31a2912610fe6ba38d8d0aa255e559719f1c4a416073cef2b6c47ea0b9795fdef29738e9faeaaa670788a50d7a4f7db3704954b4a24e99111d16fedcc5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -10216,8 +10241,8 @@ __metadata:
|
||||
nyc: "npm:^15.1.0"
|
||||
p-iteration: "npm:^1.1.8"
|
||||
pngjs: "npm:^3.4.0"
|
||||
react: "npm:19.2.0"
|
||||
react-native: "npm:0.83.0"
|
||||
react: "npm:19.2.3"
|
||||
react-native: "npm:0.84.0"
|
||||
react-native-launch-arguments: "npm:^4.0.2"
|
||||
react-native-permissions: "npm:^5.2.1"
|
||||
react-native-webview: "npm:^13.13.1"
|
||||
@@ -10279,7 +10304,7 @@ __metadata:
|
||||
prettier: "npm:^3.1.1"
|
||||
promisify-child-process: "npm:^4.1.2"
|
||||
proper-lockfile: "npm:^3.0.2"
|
||||
react-native: "npm:0.83.0"
|
||||
react-native: "npm:0.84.0"
|
||||
react-native-codegen: "npm:^0.0.8"
|
||||
resolve-from: "npm:^5.0.0"
|
||||
sanitize-filename: "npm:^1.6.1"
|
||||
@@ -11743,8 +11768,8 @@ __metadata:
|
||||
detox: "workspace:*"
|
||||
fs-extra: "npm:^9.1.0"
|
||||
jest: "npm:^30.0.3"
|
||||
react: "npm:19.2.0"
|
||||
react-native: "npm:0.83.0"
|
||||
react: "npm:19.2.3"
|
||||
react-native: "npm:0.84.0"
|
||||
react-test-renderer: "npm:19.2.0"
|
||||
ts-jest: "npm:^29.4.0"
|
||||
tslib: "npm:^2.0.3"
|
||||
@@ -13814,10 +13839,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hermes-compiler@npm:0.14.0":
|
||||
version: 0.14.0
|
||||
resolution: "hermes-compiler@npm:0.14.0"
|
||||
checksum: 10/880a5570770a977731f98fe2bedf5b7079e2e851a16e08ec89aeaa1de552e885734de3be513bc5633e5415fd1ac497b7b630aab75a46c359a5d30a243a1dcf11
|
||||
"hermes-compiler@npm:250829098.0.7":
|
||||
version: 250829098.0.7
|
||||
resolution: "hermes-compiler@npm:250829098.0.7"
|
||||
checksum: 10/229cfee06c0e3205f93e1b8ac1782b852cd8ef190b4e3a2ad69f953b470facf0cca3c5986aa499a752802b714a82960d69b9a43dacaa056bd3998db7553b6c36
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -22230,18 +22255,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native@npm:0.83.0":
|
||||
version: 0.83.0
|
||||
resolution: "react-native@npm:0.83.0"
|
||||
"react-native@npm:0.84.0":
|
||||
version: 0.84.0
|
||||
resolution: "react-native@npm:0.84.0"
|
||||
dependencies:
|
||||
"@jest/create-cache-key-function": "npm:^29.7.0"
|
||||
"@react-native/assets-registry": "npm:0.83.0"
|
||||
"@react-native/codegen": "npm:0.83.0"
|
||||
"@react-native/community-cli-plugin": "npm:0.83.0"
|
||||
"@react-native/gradle-plugin": "npm:0.83.0"
|
||||
"@react-native/js-polyfills": "npm:0.83.0"
|
||||
"@react-native/normalize-colors": "npm:0.83.0"
|
||||
"@react-native/virtualized-lists": "npm:0.83.0"
|
||||
"@react-native/assets-registry": "npm:0.84.0"
|
||||
"@react-native/codegen": "npm:0.84.0"
|
||||
"@react-native/community-cli-plugin": "npm:0.84.0"
|
||||
"@react-native/gradle-plugin": "npm:0.84.0"
|
||||
"@react-native/js-polyfills": "npm:0.84.0"
|
||||
"@react-native/normalize-colors": "npm:0.84.0"
|
||||
"@react-native/virtualized-lists": "npm:0.84.0"
|
||||
abort-controller: "npm:^3.0.0"
|
||||
anser: "npm:^1.4.9"
|
||||
ansi-regex: "npm:^5.0.0"
|
||||
@@ -22250,8 +22275,7 @@ __metadata:
|
||||
base64-js: "npm:^1.5.1"
|
||||
commander: "npm:^12.0.0"
|
||||
flow-enums-runtime: "npm:^0.0.6"
|
||||
glob: "npm:^7.1.1"
|
||||
hermes-compiler: "npm:0.14.0"
|
||||
hermes-compiler: "npm:250829098.0.7"
|
||||
invariant: "npm:^2.2.4"
|
||||
jest-environment-node: "npm:^29.7.0"
|
||||
memoize-one: "npm:^5.0.0"
|
||||
@@ -22266,18 +22290,19 @@ __metadata:
|
||||
scheduler: "npm:0.27.0"
|
||||
semver: "npm:^7.1.3"
|
||||
stacktrace-parser: "npm:^0.1.10"
|
||||
tinyglobby: "npm:^0.2.15"
|
||||
whatwg-fetch: "npm:^3.0.0"
|
||||
ws: "npm:^7.5.10"
|
||||
yargs: "npm:^17.6.2"
|
||||
peerDependencies:
|
||||
"@types/react": ^19.1.1
|
||||
react: ^19.2.0
|
||||
react: ^19.2.3
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
bin:
|
||||
react-native: cli.js
|
||||
checksum: 10/78454fa89c2f5c8794d8d04c099c6d5f43f569696b6e04afb927181bcdcc73646921e428bd29b32a79c94678d572ec00c5d3355e7a43fa94d58065eed4ba78f2
|
||||
checksum: 10/f1ae3cd7f9581d0ee516bfbbdc705ea7099d025a5701d997bf21e0a158c630ab30edf03140e64128f33e1a99be7f607e53a9d4277723d73239e14a7cd7193eaf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -22382,10 +22407,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react@npm:19.2.0":
|
||||
version: 19.2.0
|
||||
resolution: "react@npm:19.2.0"
|
||||
checksum: 10/e13bcdb8e994c3cfa922743cb75ca8deb60531bf02f584d2d8dab940a8132ce8a2e6ef16f8ed7f372b4072e7a7eeff589b2812dabbedfa73e6e46201dac8a9d0
|
||||
"react@npm:19.2.3":
|
||||
version: 19.2.3
|
||||
resolution: "react@npm:19.2.3"
|
||||
checksum: 10/d16b7f35c0d35a56f63d9d1693819762e4abc479c57dd6310298920bed3820fcec7e17a99d44983416d8f5049143ea45b8005d3ab8324bae8973224400502b08
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||