diff --git a/android/app/src/androidTest/java/com/testapp/IsolatedTest.kt b/android/app/src/androidTest/java/com/testapp/IsolatedTest.kt index 8ac5384..0d9da6b 100644 --- a/android/app/src/androidTest/java/com/testapp/IsolatedTest.kt +++ b/android/app/src/androidTest/java/com/testapp/IsolatedTest.kt @@ -1,7 +1,7 @@ package com.rnstorybookautoscreenshots -import android.graphics.Color import android.view.View +import android.view.ViewGroup import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.testapp.MainApplication @@ -9,11 +9,12 @@ import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertTrue import org.junit.Test import org.junit.runner.RunWith -import com.facebook.testing.screenshot.ViewHelpers import com.facebook.testing.screenshot.Screenshot import com.facebook.testing.screenshot.WindowAttachment -import org.junit.Assert.*; +import org.junit.Assert.* import com.facebook.react.interfaces.* +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit @RunWith(AndroidJUnit4::class) class IsolatedTest { @@ -29,19 +30,16 @@ class IsolatedTest { val surface = app.reactHost.createSurface(context, "SimpleTestComponent", null) assertEquals("SimpleTestComponent", surface.moduleName) - // TODO: we aren't 100% sure if prerender() and start() are being called the way we want it to. - // We probably want to create a ReactHost directly instead of taking it from the MainApplication... probably - // Also look up bridge-less mode. assertGoodTask(surface.prerender()) - assertNotNull(surface.view) - ViewHelpers.setupView(surface.view!!) - .setExactHeightPx(1000) - .setExactWidthPx(1000) - .layout() - + val view = surface.view!! + view.measure( + View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY) + ) + view.layout(0, 0, view.measuredWidth, view.measuredHeight) val ti = surface.start() assertGoodTask(ti) @@ -57,66 +55,39 @@ class IsolatedTest { val app = context.applicationContext as MainApplication val surface = app.reactHost.createSurface(context, "SimpleTestComponent", null) - val view = surface.view!! + val view = surface.view!! as ViewGroup var detacher: WindowAttachment.Detacher? = null + var startTask: TaskInterface? = null + val childrenMounted = CompletableFuture() try { instrumentation.runOnMainSync { view.setLayerType(View.LAYER_TYPE_SOFTWARE, null) - view.setBackgroundColor(Color.WHITE) detacher = WindowAttachment.dispatchAttach(view) app.reactHost.onHostResume(null) - ViewHelpers.setupView(view).setExactWidthPx(1080).setExactHeightPx(1920).layout() - surface.start() + view.measure( + View.MeasureSpec.makeMeasureSpec(1080, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(1920, View.MeasureSpec.EXACTLY) + ) + view.layout(0, 0, view.measuredWidth, view.measuredHeight) + startTask = surface.start() + // dispatchAttach gives the view a real Handler on the main Looper via AttachInfo, + // so view.post() routes to the main MessageQueue. Poll here (on the main thread, + // between Choreographer frames) until Fabric mounts the first child. + val check = object : Runnable { + override fun run() { + if (view.childCount > 0) childrenMounted.complete(view.childCount) + else view.postDelayed(this, 50) + } + } + view.post(check) } - val deadline = System.currentTimeMillis() + 30_000 - var hasChildren = false - while (!hasChildren && System.currentTimeMillis() < deadline) { - Thread.sleep(50) - instrumentation.runOnMainSync { hasChildren = view.childCount > 0 } - } - assertTrue("Timed out waiting for children", hasChildren) - } finally { - instrumentation.runOnMainSync { - surface.stop() - detacher?.detach() - } - } - } - - @Test - fun childCountScreenshotTest() { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val context = instrumentation.targetContext - val app = context.applicationContext as MainApplication - val surface = app.reactHost.createSurface(context, "SimpleTestComponent", null) - - val view = surface.view!! - var detacher: WindowAttachment.Detacher? = null - - try { - instrumentation.runOnMainSync { - view.setLayerType(View.LAYER_TYPE_SOFTWARE, null) - view.setBackgroundColor(Color.WHITE) - detacher = WindowAttachment.dispatchAttach(view) - app.reactHost.onHostResume(null) - ViewHelpers.setupView(view).setExactWidthPx(1080).setExactHeightPx(1920).layout() - surface.start() - } - - val deadline = System.currentTimeMillis() + 30_000 - var hasChildren = false - while (!hasChildren && System.currentTimeMillis() < deadline) { - Thread.sleep(50) - instrumentation.runOnMainSync { hasChildren = view.childCount > 0 } - } - assertTrue("Timed out waiting for children", hasChildren) - - instrumentation.runOnMainSync { - ViewHelpers.setupView(view).setExactWidthPx(1080).setExactHeightPx(1920).layout() - Screenshot.snap(view).setName("childCountReadyTest").record() - } + // start() fires on the bg executor. assertGoodTask blocks the test thread until + // it completes, keeping the main thread free for Choreographer and our check loop. + assertGoodTask(startTask!!) + val count = childrenMounted.get(5, TimeUnit.SECONDS) + assertTrue("Expected childCount > 0, but was $count", count > 0) } finally { instrumentation.runOnMainSync { surface.stop() @@ -126,7 +97,7 @@ class IsolatedTest { } } -fun assertGoodTask(ti : TaskInterface) { +fun assertGoodTask(ti: TaskInterface) { ti.waitForCompletion() assertFalse(ti.isFaulted()) assertTrue(ti.isCompleted()) diff --git a/android/app/src/androidTest/java/com/testapp/ScreenshotTest.kt b/android/app/src/androidTest/java/com/testapp/ScreenshotTest.kt index 1dffb5d..72e7754 100644 --- a/android/app/src/androidTest/java/com/testapp/ScreenshotTest.kt +++ b/android/app/src/androidTest/java/com/testapp/ScreenshotTest.kt @@ -10,7 +10,6 @@ import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.rule.GrantPermissionRule import com.facebook.testing.screenshot.Screenshot -import com.facebook.testing.screenshot.ViewHelpers import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -53,11 +52,12 @@ class ScreenshotTest { view.setBackgroundColor(Color.WHITE) view.setPadding(20, 20, 20, 20) - // Measure and layout the view - ViewHelpers.setupView(view) - .setExactWidthDp(300) - .setExactHeightDp(100) - .layout() + val density = view.resources.displayMetrics.density + view.measure( + android.view.View.MeasureSpec.makeMeasureSpec((300 * density).toInt(), android.view.View.MeasureSpec.EXACTLY), + android.view.View.MeasureSpec.makeMeasureSpec((100 * density).toInt(), android.view.View.MeasureSpec.EXACTLY) + ) + view.layout(0, 0, view.measuredWidth, view.measuredHeight) // Take screenshot Screenshot.snap(view)