Skip to content

Commit

Permalink
Add react-native-test-library package (#43068)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #43068

This diff adds `react-native-test-library` package.
It contains native module and native component example, and targets both the new and the old architecture. It has structure similar to many OSS React Native libraries, and is supposed to be used to test the integration with third-party libraries.

It is integrated with RNTester as the **OSS Library Example** screen.

{F1457510909}

**Change Background** tests native commands.
**Set Opacity** tests native props.
**Get Random Number** tests native module.

Changelog: [Internal]

Reviewed By: RSNara

Differential Revision: D50793835
  • Loading branch information
dmytrorykun authored and facebook-github-bot committed Apr 8, 2024
1 parent 3a15af7 commit 7ac29e4
Show file tree
Hide file tree
Showing 59 changed files with 2,076 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ project.xcworkspace
/packages/react-native/template/android/app/build/
/packages/react-native/template/android/build/
/packages/react-native-popup-menu-android/android/build/
/packages/react-native-test-library/android/build/

# Buck
.buckd
Expand Down
24 changes: 24 additions & 0 deletions packages/react-native-test-library/OSSLibraryExample.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

require 'json'

package = JSON.parse(File.read(File.join(__dir__, 'package.json')))

Pod::Spec.new do |s|
s.name = 'OSSLibraryExample'
s.version = package['version']
s.summary = package['description']
s.description = package['description']
s.homepage = package['homepage']
s.license = package['license']
s.platforms = min_supported_versions
s.author = 'Meta Platforms, Inc. and its affiliates'
s.source = { :git => package['repository']['url'], :tag => "#{s.version}" }

s.source_files = 'ios/**/*.{h,m,mm,cpp}'

install_modules_dependencies(s)
end
9 changes: 9 additions & 0 deletions packages/react-native-test-library/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## Important
This package is for testing only. It is a subject to frequent change. It does not represent the recomended structure for React native libraries. It should not be used as a referece for such purposes.

## Building
```
yarn install
yarn build
npx react-native codegen
```
35 changes: 35 additions & 0 deletions packages/react-native-test-library/android/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

plugins {
id("com.facebook.react")
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
}

android {
compileSdk = libs.versions.compileSdk.get().toInt()
buildToolsVersion = libs.versions.buildTools.get()
namespace = "com.facebook.react.osslibraryexample"

defaultConfig {
minSdk = libs.versions.minSdk.get().toInt()
targetSdk = libs.versions.targetSdk.get().toInt()
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

kotlinOptions { jvmTarget = "17" }
}

dependencies {
// Build React Native from source
implementation(project(":packages:react-native:ReactAndroid"))
}
4 changes: 4 additions & 0 deletions packages/react-native-test-library/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

# We want to have more fine grained control on the Java version for
# ReactAndroid, therefore we disable RGNP Java version alignment mechanism
react.internal.disableJavaVersionAlignment=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GenerateModuleJavaSpec.js
*
* @nolint
*/

package com.facebook.fbreact.specs;

import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
import javax.annotation.Nonnull;

public abstract class NativeSampleModuleSpec extends ReactContextBaseJavaModule implements TurboModule {
public static final String NAME = "NativeSampleModule";

public NativeSampleModuleSpec(ReactApplicationContext reactContext) {
super(reactContext);
}

@Override
public @Nonnull String getName() {
return NAME;
}

@ReactMethod(isBlockingSynchronousMethod = true)
@DoNotStrip
public abstract double getRandomNumber();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaDelegate.js
*/

package com.facebook.react.viewmanagers;

import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.BaseViewManagerDelegate;
import com.facebook.react.uimanager.BaseViewManagerInterface;

public class SampleNativeComponentManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & SampleNativeComponentManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
public SampleNativeComponentManagerDelegate(U viewManager) {
super(viewManager);
}
@Override
public void setProperty(T view, String propName, @Nullable Object value) {
switch (propName) {
case "opacity":
mViewManager.setOpacity(view, value == null ? 0f : ((Double) value).floatValue());
break;
case "values":
mViewManager.setValues(view, (ReadableArray) value);
break;
default:
super.setProperty(view, propName, value);
}
}

@Override
public void receiveCommand(T view, String commandName, ReadableArray args) {
switch (commandName) {
case "changeBackgroundColor":
mViewManager.changeBackgroundColor(view, args.getString(0));
break;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaInterface.js
*/

package com.facebook.react.viewmanagers;

import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableArray;

public interface SampleNativeComponentManagerInterface<T extends View> {
void setOpacity(T view, float value);
void setValues(T view, @Nullable ReadableArray value);
void changeBackgroundColor(T view, String color);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.reactnative.osslibraryexample

import com.facebook.fbreact.specs.NativeSampleModuleSpec
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.module.annotations.ReactModule

@ReactModule(name = NativeSampleModuleSpec.NAME)
public class NativeSampleModule(reactContext: ReactApplicationContext?) :
ReactContextBaseJavaModule(reactContext) {

override fun getName(): String = NAME

private companion object {
const val NAME = "NativeSampleModule"
}

@ReactMethod
public fun getRandomNumber(): Int {
return (0..99).random()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.reactnative.osslibraryexample

import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager

public class OSSLibraryExamplePackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
listOf(NativeSampleModule(reactContext))

override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
listOf(SampleNativeComponentViewManager())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.reactnative.osslibraryexample

import android.annotation.SuppressLint
import android.graphics.Color
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.common.MapBuilder
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.uimanager.SimpleViewManager
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.ViewProps
import com.facebook.react.uimanager.annotations.ReactProp
import com.facebook.react.viewmanagers.SampleNativeComponentManagerInterface

/** Legacy View manager (non Fabric compatible) for {@link SampleNativeView} components. */
@ReactModule(name = SampleNativeComponentViewManager.REACT_CLASS)
internal class SampleNativeComponentViewManager :
SimpleViewManager<SampleNativeView>(), SampleNativeComponentManagerInterface<SampleNativeView> {

override fun getName(): String = REACT_CLASS

// @ReactProp(name = ViewProps.OPACITY, defaultFloat = 1f)
override fun setOpacity(view: SampleNativeView, opacity: Float) {
super.setOpacity(view, opacity)
}

@SuppressLint("BadMethodUse-android.view.View.setBackgroundColor")
@ReactProp(name = ViewProps.COLOR)
fun setColor(view: SampleNativeView, color: String) {
view.setBackgroundColor(Color.parseColor(color))
}

@ReactProp(name = "cornerRadius")
fun setCornerRadius(view: SampleNativeView, cornerRadius: Float) {
view.setCornerRadius(cornerRadius)
}

override fun createViewInstance(reactContext: ThemedReactContext): SampleNativeView =
SampleNativeView(reactContext)

@SuppressLint("BadMethodUse-android.view.View.setBackgroundColor")
override fun changeBackgroundColor(view: SampleNativeView, color: String) {
view.setBackgroundColor(Color.parseColor(color))
}

override fun getExportedViewConstants(): Map<String, Any> = mapOf("PI" to 3.14)

override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {
return MapBuilder.builder<String, Any>()
.put(
"onColorChanged",
MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of("bubbled", "onColorChanged", "captured", "onColorChangedCapture")))
.put(
"topIntArrayChanged",
MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of(
"bubbled", "topIntArrayChanged", "captured", "topIntArrayChangedCapture")))
.build()
}

@SuppressLint("BadMethodUse-android.view.View.setBackgroundColor")
override fun receiveCommand(view: SampleNativeView, commandId: String, args: ReadableArray?) {
if (commandId.contentEquals("changeBackgroundColor")) {
val sentColor: Int = Color.parseColor(args?.getString(0))
view.setBackgroundColor(sentColor)
}
}

@SuppressLint("BadMethodUse-android.view.View.setBackgroundColor")
@Suppress("DEPRECATION") // We intentionally want to test against the legacy API here.
override fun receiveCommand(view: SampleNativeView, commandId: Int, args: ReadableArray?) {
when (commandId) {
COMMAND_CHANGE_BACKGROUND_COLOR -> {
val sentColor: Int = Color.parseColor(args?.getString(0))
view.setBackgroundColor(sentColor)
}
}
}

override fun getCommandsMap(): Map<String, Int> =
mapOf("changeBackgroundColor" to COMMAND_CHANGE_BACKGROUND_COLOR)

companion object {
const val REACT_CLASS = "SampleNativeComponent"
const val COMMAND_CHANGE_BACKGROUND_COLOR = 42
}

@ReactProp(name = "values")
override fun setValues(view: SampleNativeView, value: ReadableArray?) {
val values = mutableListOf<Int>()
value?.toArrayList()?.forEach { values.add((it as Double).toInt()) }
view.emitOnArrayChangedEvent(values)
}
}
Loading

0 comments on commit 7ac29e4

Please sign in to comment.