1 package host.exp.exponent.utils 2 3 import android.content.Intent 4 import android.net.Uri 5 import android.os.Build 6 import androidx.test.InstrumentationRegistry 7 import androidx.test.espresso.Espresso 8 import androidx.test.espresso.assertion.ViewAssertions 9 import androidx.test.espresso.matcher.ViewMatchers 10 import androidx.test.uiautomator.By 11 import androidx.test.uiautomator.UiDevice 12 import androidx.test.uiautomator.Until 13 import host.exp.exponent.generated.ExponentBuildConstants 14 import host.exp.exponent.kernel.ExponentUrls 15 import okhttp3.MediaType 16 import okhttp3.OkHttpClient 17 import okhttp3.Request 18 import okhttp3.RequestBody 19 import org.json.JSONException 20 import org.json.JSONObject 21 import java.io.IOException 22 import java.util.* 23 24 object TestServerUtils { 25 private const val LAUNCH_TIMEOUT = 5000 26 27 private val JSON = MediaType.parse("application/json; charset=utf-8") 28 private val isTestServerAvailable: Boolean 29 get() = ExponentBuildConstants.TEST_SERVER_URL != "TODO" 30 31 @Throws(Exception::class) 32 fun runFixtureTest(device: UiDevice, fixtureName: String) { 33 if (!isTestServerAvailable) { 34 return 35 } 36 37 // Get a fixture server 38 val fixtureServer = getFixtureServerInstance(fixtureName) 39 40 // Launch the app 41 val context = InstrumentationRegistry.getContext() 42 val intent = Intent(Intent.ACTION_VIEW, Uri.parse(fixtureServer!!.manifestServerUrl)).apply { 43 addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 44 } 45 context.startActivity(intent) 46 47 // Wait for the app to appear 48 device.wait(Until.hasObject(By.pkg("host.exp.exponent").depth(0)), LAUNCH_TIMEOUT.toLong()) 49 50 // Need this to wait on idling resources 51 Espresso.onView(ExponentMatchers.withTestId("test_container")) 52 .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) 53 for (event in fixtureServer.testEvents) { 54 event.waitForCompleted(device, fixtureServer.manifestServerUrl) 55 } 56 } 57 58 @Throws(IOException::class) 59 private fun httpRequest(request: Request): String { 60 val client = OkHttpClient() 61 val response = client.newCall(request).execute() 62 if (!response.isSuccessful) { 63 throw IOException("Unexpected code $response") 64 } 65 return response.body()!!.string() 66 } 67 68 private fun getFixtureServerInstance(fixtureName: String): FixtureServerInstance? { 69 try { 70 val request = Request.Builder() 71 .url(ExponentBuildConstants.TEST_SERVER_URL + "/start-fixture-server?fixtureName=" + fixtureName) 72 .build() 73 val responseJson = JSONObject(httpRequest(request)) 74 val manifestServerUrl = responseJson.getString("manifestServerUrl") 75 val jsonTestEvents = responseJson.getJSONArray("testEvents") 76 val testEvents: MutableList<TestEvent> = ArrayList() 77 for (i in 0 until jsonTestEvents.length()) { 78 val jsonTestEvent = jsonTestEvents.getJSONObject(i) 79 testEvents.add( 80 TestEvent( 81 jsonTestEvent.getString("type"), 82 jsonTestEvent.getString("data"), 83 jsonTestEvent.getInt("testEventId") 84 ) 85 ) 86 } 87 return FixtureServerInstance(manifestServerUrl, testEvents) 88 } catch (e: IOException) { 89 e.printStackTrace() 90 } catch (e: JSONException) { 91 e.printStackTrace() 92 } 93 return null 94 } 95 96 @Throws(Exception::class) 97 fun reportTestResult(success: Boolean, testName: String?, logs: String?) { 98 if (!isTestServerAvailable) { 99 return 100 } 101 val jsonBody = JSONObject().apply { 102 put("testRunId", ExponentBuildConstants.TEST_RUN_ID) 103 put("testName", testName) 104 put("success", success) 105 put("logs", logs) 106 put("deviceName", Build.MODEL) 107 put("systemVersion", Build.VERSION.RELEASE) 108 } 109 val request = Request.Builder() 110 .url(ExponentBuildConstants.TEST_SERVER_URL + "/report-test-result") 111 .post(RequestBody.create(JSON, jsonBody.toString())) 112 .build() 113 httpRequest(request) 114 } 115 116 class TestEvent(private val type: String, private val data: String, private val testEventId: Int) { 117 @Throws(Exception::class) 118 fun waitForCompleted(device: UiDevice, manifestUrl: String) { 119 if (type == "findTextOnScreen") { 120 ExpoConditionWatcher.waitForText(device, data) 121 } 122 try { 123 val request = Request.Builder() 124 .url(ExponentUrls.toHttp(manifestUrl) + "/finished-test-event") 125 .addHeader("test-event-id", testEventId.toString()) 126 .build() 127 httpRequest(request) 128 } catch (e: RuntimeException) { 129 } catch (e: IOException) { 130 } 131 } 132 } 133 134 class FixtureServerInstance(val manifestServerUrl: String, val testEvents: List<TestEvent>) 135 } 136