1 // Copyright 2015-present 650 Industries. All rights reserved. 2 package host.exp.exponent 3 4 import android.Manifest 5 import android.content.Intent 6 import android.net.Uri 7 import androidx.test.InstrumentationRegistry 8 import androidx.test.espresso.Espresso 9 import androidx.test.espresso.IdlingResource 10 import androidx.test.espresso.assertion.ViewAssertions 11 import androidx.test.espresso.matcher.ViewMatchers 12 import androidx.test.rule.GrantPermissionRule 13 import androidx.test.uiautomator.By 14 import androidx.test.uiautomator.Until 15 import host.exp.exponent.annotations.ExpoAlwaysPassThroughFilter 16 import host.exp.exponent.annotations.ExpoSdkVersionTest 17 import host.exp.exponent.annotations.ExpoTestSuiteTest 18 import host.exp.exponent.generated.ExponentBuildConstants 19 import host.exp.exponent.kernel.KernelConfig 20 import host.exp.exponent.utils.* 21 import org.json.JSONException 22 import org.json.JSONObject 23 import org.junit.* 24 import org.junit.rules.RuleChain 25 import org.junit.runner.RunWith 26 import org.junit.runners.MethodSorters 27 28 @RunWith(ExpoTestRunner::class) 29 @FixMethodOrder(MethodSorters.NAME_ASCENDING) 30 class TestSuiteTests : BaseTestClass() { 31 private lateinit var loadingScreenIdlingResource: IdlingResource 32 private lateinit var elapsedTimeIdlingResource: ElapsedTimeIdlingResource 33 private lateinit var jsTestRunnerIdlingResource: JSTestRunnerIdlingResource 34 35 @Before beforenull36 fun before() { 37 loadingScreenIdlingResource = LoadingScreenIdlingResource() 38 elapsedTimeIdlingResource = ElapsedTimeIdlingResource() 39 jsTestRunnerIdlingResource = JSTestRunnerIdlingResource() 40 Espresso.registerIdlingResources( 41 loadingScreenIdlingResource, 42 elapsedTimeIdlingResource, 43 jsTestRunnerIdlingResource 44 ) 45 KernelConfig.FORCE_UNVERSIONED_PUBLISHED_EXPERIENCES = false 46 } 47 48 @After afternull49 fun after() { 50 Espresso.unregisterIdlingResources( 51 loadingScreenIdlingResource, 52 elapsedTimeIdlingResource, 53 jsTestRunnerIdlingResource 54 ) 55 KernelConfig.FORCE_UNVERSIONED_PUBLISHED_EXPERIENCES = false 56 } 57 58 private var haveContactsBeenAdded = false ensureContactsAddednull59 private fun ensureContactsAdded() { 60 if (haveContactsBeenAdded) { 61 return 62 } 63 haveContactsBeenAdded = true 64 TestContacts.add(InstrumentationRegistry.getTargetContext()) 65 } 66 runTestSuiteTestnull67 private fun runTestSuiteTest(testSuiteUriString: String, shouldAddDeepLink: Boolean) { 68 var testSuiteUri = Uri.parse(testSuiteUriString) 69 ensureContactsAdded() 70 if (shouldAddDeepLink) { 71 val deepLink = TestConfig.get().toString() 72 testSuiteUri = Uri.withAppendedPath(testSuiteUri, "/--/$deepLink") 73 } 74 75 // Launch the app 76 val context = InstrumentationRegistry.getContext() 77 val intent = Intent(Intent.ACTION_VIEW, testSuiteUri) 78 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 79 context.startActivity(intent) 80 81 // Wait for the app to appear 82 uiDevice.wait(Until.hasObject(By.pkg("host.exp.exponent").depth(0)), LAUNCH_TIMEOUT.toLong()) 83 84 // Need this to wait on idling resources 85 Espresso.onView(ExponentMatchers.withTestId("test_suite_container")) 86 .check(ViewAssertions.matches(ViewMatchers.isEnabled())) 87 val result = jsTestRunnerIdlingResource.testResult 88 try { 89 val jsonObject = JSONObject(result) 90 val numFailed = jsonObject.getInt("failed") 91 if (jsonObject.has("results")) { 92 testReporterRule.logTestInfo(jsonObject.getString("results")) 93 } 94 if (jsonObject.has("failures")) { 95 testReporterRule.logTestInfo(jsonObject.getString("failures")) 96 } 97 if (numFailed > 0) { 98 throw AssertionError("$numFailed JS test(s) failed") 99 } 100 } catch (e: JSONException) { 101 throw AssertionError("JSON error $e") 102 } 103 } 104 105 private val testReporterRule = TestReporterRule() 106 107 @Rule 108 @JvmField 109 val chain: RuleChain = RuleChain.outerRule(testReporterRule).around(RetryTestRule(2)) 110 111 @Rule 112 @JvmField 113 val permissionRule: GrantPermissionRule = GrantPermissionRule.grant( 114 Manifest.permission.SYSTEM_ALERT_WINDOW, Manifest.permission.READ_CONTACTS, 115 Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, 116 Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, 117 Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR 118 ) 119 120 @Test 121 @ExpoTestSuiteTest 122 @ExpoSdkVersionTest("UNVERSIONED") sdkUnversionedTestSuitenull123 fun sdkUnversionedTestSuite() { 124 if (!isCurrentTestSuiteAvailable) { 125 return 126 } 127 KernelConfig.FORCE_UNVERSIONED_PUBLISHED_EXPERIENCES = true 128 runTestSuiteTest(ExponentBuildConstants.TEST_APP_URI, true) 129 } 130 131 @Test 132 @ExpoAlwaysPassThroughFilter junitIsSillyAndWillFailIfThereIsntOneTestRunPerFilenull133 fun junitIsSillyAndWillFailIfThereIsntOneTestRunPerFile() { 134 } 135 136 companion object { 137 @BeforeClass 138 @JvmStatic beforeClassnull139 fun beforeClass() { 140 BaseTestClass.beforeClass() 141 142 // Press home 143 uiDevice.pressHome() 144 val launcherPackage = uiDevice.launcherPackageName 145 uiDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT.toLong()) 146 } 147 148 val isCurrentTestSuiteAvailable: Boolean 149 get() = ExponentBuildConstants.TEST_APP_URI != "" 150 } 151 } 152