Skip to content

Commit

Permalink
React Native 66 (#7305)
Browse files Browse the repository at this point in the history
* RN 65

React Native upgrade + babel unit tests running as expected

* RN66

- Normal unit tests working
- Upgrade to RN66.
- Move jest to jest config file.
- Use babel-test transformer to make unit tests working
- e2e tests that can run as unit wont work.

* disable running e2es as units

* use Hermes + Fix Reanimated

* update reanimated and use babel plugin

* Enable coverage

* Upgrade jest and babel to 27

* enable JS e2e add animatable to transform ignore

* use babel jest as transformer instead of the react native one

* update android to 30

* Fix overlay insets and use non deprecated methods

* Kotlin convert

* tmp status

* Update Detox to support iOS 15

* Fix e2e

* Revert "tmp status"

This reverts commit aff2b87.

* prevent ReactRootViews from having ids

* status bar utils static fields

* Squashed commit of the following:

commit 5959638
Author: Ward Abbass <warda@wix.com>
Date:   Wed Oct 27 13:04:00 2021 +0300

    Keyboard demo playground  (#7331)

    Adding a simple demo that can be used to demonstrate Keyboard show/dismiss when showing/dismissing modal when clicking on submit

    Co-authored-by: Yogev Ben David <yogev132@gmail.com>

* wait for stack/modal to be shown to send didAppear

this happens since RN 64

* Fix tests

* Ensure modal is not already presented

* use 0.66.2

Co-authored-by: svbutko <svbutko@hotmail.com>
Co-authored-by: Yogev Ben David <yogev132@gmail.com>
  • Loading branch information
3 people authored Nov 8, 2021
1 parent 9647520 commit 5136a2e
Show file tree
Hide file tree
Showing 23 changed files with 216 additions and 182 deletions.
1 change: 1 addition & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module.exports = function (api) {
return {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
'react-native-reanimated/plugin',
'@babel/plugin-proposal-export-namespace-from',
'@babel/plugin-proposal-export-default-from',
],
Expand Down
2 changes: 1 addition & 1 deletion e2e/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"globalSetup": "./global-setup.js",
"globalTeardown": "./global-teardown.js",
"setupTestFrameworkScriptFile" : "./init.js",
"setupFilesAfterEnv" : ["./init.js"],
"testEnvironment": "node",
"bail": true,
"verbose": true,
Expand Down
8 changes: 0 additions & 8 deletions e2e/init.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
const detox = require('detox');
const config = require('../package.json').detox;
const exec = require('shell-utils').exec;
const adapter = require('detox/runners/jest/adapter');
require('detox-testing-library-rnn-adapter').extendDetox();

jest.setTimeout(300000);
jasmine.getEnv().addReporter(adapter);

beforeAll(async () => {
await detox.init(config, { launchApp: false });
});

afterAll(async () => {
await adapter.afterAll();
await detox.cleanup();
});

beforeEach(async () => {
await adapter.beforeEach();
});
40 changes: 40 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module.exports = {
preset: 'react-native',
transformIgnorePatterns: [
'node_modules/(?!(@react-native|react-native|react-native-ui-lib|react-native-animatable)/)',
],
transform: {
'\\.[jt]sx?$': 'babel-jest',
},
roots: [
'<rootDir>/lib/src/',
'<rootDir>/playground/src/',
'<rootDir>/integration/',
'<rootDir>/scripts/',
'<rootDir>/e2e/',
],
setupFilesAfterEnv: ['./jest-setup.js'],
testPathIgnorePatterns: ['/node_modules/'],
moduleNameMapper: {
'react-native-navigation/Mock': '<rootDir>/lib/src/Mock',
'react-native-navigation': '<rootDir>/lib/src',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/playground/img/layouts@2x.png',
},
collectCoverageFrom: [
'lib/src/**/*.ts',
'lib/src/**/*.tsx',
'integration/**/*.js',
'!lib/dist/index.js',
'!lib/dist/Navigation.js',
'!lib/dist/adapters/**/*',
'!lib/dist/interfaces/**/*',
'!lib/dist/**/*.test.*',
'!integration/**/*.test.*',
'!integration/*.test.*',
'!e2e/**/*test.js',
],
resetMocks: true,
resetModules: true,
coverageReporters: ['json', 'lcov', 'text', 'html'],
};
26 changes: 14 additions & 12 deletions lib/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,29 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

def DEFAULT_COMPILE_SDK_VERSION = 29
def DEFAULT_MIN_SDK_VERSION = 19
def DEFAULT_TARGET_SDK_VERSION = 29
def kotlinVersion = rootProject.ext.get("RNNKotlinVersion")
def kotlinStdlib = safeExtGet('RNNKotlinStdlib', 'kotlin-stdlib-jdk8')
def kotlinCoroutinesCore = safeExtGet('RNNKotlinCoroutinesCore', '1.4.3')
def safeExtGetFallbackLowerBound(prop, fallback) {
Math.max(safeExtGet(prop,fallback),fallback)
}

def DEFAULT_COMPILE_SDK_VERSION = 30
def DEFAULT_MIN_SDK_VERSION = 21
def DEFAULT_TARGET_SDK_VERSION = 30
def DEFAULT_KOTLIN_VERSION = "1.5.31"
def DEFAULT_KOTLIN_STDLIB = 'kotlin-stdlib-jdk8'
def kotlinVersion = safeExtGet("RNNKotlinVersion", DEFAULT_KOTLIN_VERSION)
def kotlinStdlib = safeExtGet('RNNKotlinStdlib',DEFAULT_KOTLIN_STDLIB )
def kotlinCoroutinesCore = safeExtGet('RNNKotlinCoroutinesCore', '1.5.2')
android {
compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
compileSdkVersion safeExtGetFallbackLowerBound('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)

defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
versionCode 1
versionName "1.0"
minSdkVersion safeExtGetFallbackLowerBound('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
targetSdkVersion safeExtGetFallbackLowerBound('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
}
buildTypes {
release {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ModalFrameLayout(context: ReactContext) : FrameLayout(context) {
addView(modalContentLayout, MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT)
.apply {
val translucent = context.currentActivity?.window?.let {
StatusBarUtils.isTranslucent(context.currentActivity?.window)
StatusBarUtils.isTranslucent(it)
} ?: false
topMargin = if (translucent) 0 else StatusBarUtils.getStatusBarHeight(context)
})
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.reactnativenavigation.utils

import android.content.Context
import android.os.Build
import android.view.Window
import android.view.WindowManager

object StatusBarUtils {
private const val STATUS_BAR_HEIGHT_M = 24
private const val STATUS_BAR_HEIGHT_L = 25
private var statusBarHeight = -1
@JvmStatic
fun saveStatusBarHeight(height: Int) {
statusBarHeight = height
}
@JvmStatic
fun getStatusBarHeight(context: Context): Int {
if (statusBarHeight > 0) {
return statusBarHeight
}
val resources = context.resources
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
statusBarHeight = if (resourceId > 0) resources.getDimensionPixelSize(resourceId) else UiUtils.dpToPx(
context,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) STATUS_BAR_HEIGHT_M else STATUS_BAR_HEIGHT_L
)
return statusBarHeight
}
@JvmStatic
fun getStatusBarHeightDp(context: Context): Int {
return UiUtils.pxToDp(context, getStatusBarHeight(context).toFloat())
.toInt()
}
@JvmStatic
fun isTranslucent(window: Window): Boolean {
val lp = window.attributes
return lp != null && lp.flags and WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.reactnativenavigation.views.component.ComponentLayout;

import androidx.annotation.NonNull;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

Expand Down Expand Up @@ -137,13 +138,13 @@ public void applyBottomInset() {

@Override
protected WindowInsetsCompat applyWindowInsets(ViewController<?> view, WindowInsetsCompat insets) {
ViewCompat.onApplyWindowInsets(view.getView(), insets.replaceSystemWindowInsets(
insets.getSystemWindowInsetLeft(),
insets.getSystemWindowInsetTop(),
final WindowInsetsCompat.Builder builder = new WindowInsetsCompat.Builder();
final WindowInsetsCompat finalInsets = builder.setSystemWindowInsets(Insets.of(insets.getSystemWindowInsetLeft(),
Math.max(insets.getSystemWindowInsetTop() - getTopInset(), 0),
insets.getSystemWindowInsetRight(),
Math.max(insets.getSystemWindowInsetBottom() - getBottomInset(), 0)
));
return insets;
Math.max(insets.getSystemWindowInsetBottom() - getBottomInset(), 0))).build();
ViewCompat.onApplyWindowInsets(view.getView(), finalInsets);
return finalInsets;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,12 @@ public void onCancel() {
}

private void onShowModalEnd(ViewController<?> toAdd, @Nullable ViewController<?> toRemove, CommandListener listener) {
toAdd.onViewDidAppear();
if (toRemove != null && toAdd.resolveCurrentOptions(defaultOptions).modal.presentationStyle != ModalPresentationStyle.OverCurrentContext) {
toRemove.detachView();
}
toAdd.addOnAppearedListener(()->{
toAdd.onViewDidAppear();
if (toRemove != null && toAdd.resolveCurrentOptions(defaultOptions).modal.presentationStyle != ModalPresentationStyle.OverCurrentContext) {
toRemove.detachView();
}
});
listener.onSuccess(toAdd.getId());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.view.View;
import android.view.ViewGroup;

import com.facebook.react.ReactRootView;
import com.reactnativenavigation.options.ButtonOptions;
import com.reactnativenavigation.options.Options;
import com.reactnativenavigation.options.StackAnimationOptions;
Expand Down Expand Up @@ -175,9 +176,7 @@ public void push(ViewController<?> child, CommandListener listener) {
presenter.getAdditionalPushAnimations(this, child, resolvedOptions),
() -> onPushAnimationComplete(child, toRemove, listener));
} else {
child.onViewDidAppear();
getView().removeView(toRemove.getView());
listener.onSuccess(child.getId());
onPushAnimationComplete(child, toRemove, listener);
}
} else {
listener.onSuccess(child.getId());
Expand All @@ -191,8 +190,10 @@ public void destroy() {
}

private void onPushAnimationComplete(ViewController<?> toAdd, ViewController<?> toRemove, CommandListener listener) {
toAdd.onViewDidAppear();
if (!peek().equals(toRemove)) getView().removeView(toRemove.getView());
toAdd.addOnAppearedListener(() -> {
toAdd.onViewDidAppear();
if (!peek().equals(toRemove)) getView().removeView(toRemove.getView());
});
listener.onSuccess(toAdd.getId());
}

Expand Down Expand Up @@ -421,12 +422,19 @@ private void addInitialChild(StackLayout stackLayout) {
if (isEmpty()) return;
ViewController<?> childController = peek();
ViewGroup child = childController.getView();
child.setId(CompatUtils.generateViewId());
setChildId(child);
childController.addOnAppearedListener(this::startChildrenBellowTopChild);
stackLayout.addView(child, 0, matchParentWithBehaviour(new StackBehaviour(this)));
presenter.applyInitialChildLayoutOptions(resolveCurrentOptions());
}

private void setChildId(ViewGroup child) {
//From RN > 64 we can't set id to child that is ReactRootView
//see:https://github.com/facebook/react-native/blob/main/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java#L676
if (!(child instanceof ReactRootView))
child.setId(CompatUtils.generateViewId());
}

private void startChildrenBellowTopChild() {
ArrayList<ViewController<?>> children = new ArrayList<>(getChildControllers());
for (int i = children.size() - 2; i >= 0; i--) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.facebook.react.common.LifecycleState;
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
import com.reactnativenavigation.NavigationApplication;
import com.facebook.hermes.reactexecutor.HermesExecutorFactory;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand Down Expand Up @@ -44,7 +45,7 @@ protected ReactInstanceManager createReactInstanceManager() {
.setJSMainModulePath(getJSMainModuleName())
.setUseDeveloperSupport(getUseDeveloperSupport())
.setRedBoxHandler(getRedBoxHandler())
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
.setJavaScriptExecutorFactory(new HermesExecutorFactory())
.setUIImplementationProvider(getUIImplementationProvider())
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
.setDevBundleDownloadListener(getDevBundleDownloadListener());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class ModalPresenterTest extends BaseTest {

@Override
public void beforeEach() {
super.beforeEach();
Activity activity = newActivity();
ChildControllersRegistry childRegistry = new ChildControllersRegistry();

Expand Down Expand Up @@ -210,6 +211,7 @@ public void dismissModal_previousViewIsAddedAtIndex0() {
uut.setRootLayout(spy);

uut.showModal(modal1, root, new CommandListenerAdapter());
idleMainLooper();
uut.dismissModal(modal1, root, root, new CommandListenerAdapter());

verify(spy).addView(root.getView(), 0);
Expand Down Expand Up @@ -237,6 +239,7 @@ public void dismissModal_previousModalIsAddedBackToHierarchy() {
verify(modal1).onViewWillAppear();

uut.showModal(modal2, modal1, new CommandListenerAdapter());
idleMainLooper();
assertThat(modal1.getView().getParent()).isNull();

Shadows.shadowOf(Looper.getMainLooper()).idle();
Expand All @@ -253,6 +256,7 @@ public void dismissModal_previousControllerIsNotAddedIfDismissedModalIsNotTop()

uut.showModal(modal1, root, new CommandListenerAdapter());
uut.showModal(modal2, modal1, new CommandListenerAdapter());
idleMainLooper();
assertThat(modal1.getView().getParent()).isNull();
assertThat(root.getView().getParent()).isNull();

Expand Down
Loading

0 comments on commit 5136a2e

Please sign in to comment.