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