Skip to content

Commit 5ca0f6b

Browse files
authored
Merge pull request #960 from Iterable/SDK-16-BCIT-EM
BCIT - EM Local
2 parents fbf54f7 + cc6b556 commit 5ca0f6b

File tree

4 files changed

+467
-26
lines changed

4 files changed

+467
-26
lines changed
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
package com.iterable.integration.tests
2+
3+
import android.content.Intent
4+
import android.util.Log
5+
import androidx.lifecycle.Lifecycle
6+
import androidx.test.core.app.ActivityScenario
7+
import androidx.test.ext.junit.runners.AndroidJUnit4
8+
import androidx.test.platform.app.InstrumentationRegistry
9+
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry
10+
import androidx.test.runner.lifecycle.Stage
11+
import androidx.test.uiautomator.UiDevice
12+
import androidx.test.uiautomator.UiSelector
13+
import androidx.test.uiautomator.By
14+
import com.iterable.iterableapi.IterableApi
15+
import com.iterable.iterableapi.IterableEmbeddedMessage
16+
import com.iterable.integration.tests.activities.EmbeddedMessageTestActivity
17+
import com.iterable.iterableapi.ui.embedded.IterableEmbeddedView
18+
import com.iterable.iterableapi.ui.embedded.IterableEmbeddedViewType
19+
import org.awaitility.Awaitility
20+
import org.json.JSONObject
21+
import org.junit.After
22+
import org.junit.Assert
23+
import org.junit.Before
24+
import org.junit.Test
25+
import org.junit.runner.RunWith
26+
import java.util.concurrent.TimeUnit
27+
28+
@RunWith(AndroidJUnit4::class)
29+
class EmbeddedMessageIntegrationTest : BaseIntegrationTest() {
30+
31+
companion object {
32+
private const val TAG = "EmbeddedMessageIntegrationTest"
33+
private const val TEST_PLACEMENT_ID = TestConstants.TEST_EMBEDDED_PLACEMENT_ID
34+
}
35+
36+
private lateinit var uiDevice: UiDevice
37+
private lateinit var mainActivityScenario: ActivityScenario<MainActivity>
38+
39+
@Before
40+
override fun setUp() {
41+
Log.d(TAG, "🔧 Test setup starting...")
42+
43+
uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
44+
45+
// Call super.setUp() to initialize SDK with BaseIntegrationTest's config
46+
// This sets test mode flag and initializes SDK with test handlers (including urlHandler)
47+
super.setUp()
48+
49+
Log.d(TAG, "🔧 Base setup complete, SDK initialized with test handlers")
50+
51+
// Disable in-app auto display and clear existing messages BEFORE launching app
52+
// This prevents in-app messages from obscuring the embedded message test screen
53+
Log.d(TAG, "🔧 Disabling in-app auto display and clearing existing messages...")
54+
IterableApi.getInstance().inAppManager.setAutoDisplayPaused(true)
55+
Log.d(TAG, "✅ In-app auto display paused")
56+
57+
// Clear all existing in-app messages
58+
IterableApi.getInstance().inAppManager.messages.forEach {
59+
Log.d(TAG, "Clearing existing in-app message: ${it.messageId}")
60+
IterableApi.getInstance().inAppManager.removeMessage(it)
61+
}
62+
Log.d(TAG, "✅ All in-app messages cleared")
63+
64+
Log.d(TAG, "🔧 MainActivity will skip initialization due to test mode flag")
65+
66+
// Now launch the app flow with custom handlers already configured
67+
launchAppAndNavigateToEmbeddedTesting()
68+
}
69+
70+
@After
71+
override fun tearDown() {
72+
super.tearDown()
73+
}
74+
75+
private fun launchAppAndNavigateToEmbeddedTesting() {
76+
// Step 1: Launch MainActivity (the home page)
77+
Log.d(TAG, "🔧 Step 1: Launching MainActivity...")
78+
val mainIntent = Intent(InstrumentationRegistry.getInstrumentation().targetContext, MainActivity::class.java)
79+
mainActivityScenario = ActivityScenario.launch(mainIntent)
80+
81+
// Wait for MainActivity to be ready
82+
Awaitility.await()
83+
.atMost(5, TimeUnit.SECONDS)
84+
.pollInterval(500, TimeUnit.MILLISECONDS)
85+
.until {
86+
val state = mainActivityScenario.state
87+
Log.d(TAG, "🔧 MainActivity state: $state")
88+
state == Lifecycle.State.RESUMED
89+
}
90+
91+
Log.d(TAG, "🔧 MainActivity is ready!")
92+
93+
// Step 2: Click the "Embedded Messages" button to navigate to EmbeddedMessageTestActivity
94+
Log.d(TAG, "🔧 Step 2: Clicking 'Embedded Messages' button...")
95+
val embeddedButton = uiDevice.findObject(UiSelector().resourceId("com.iterable.integration.tests:id/btnEmbeddedMessages"))
96+
if (embeddedButton.exists()) {
97+
embeddedButton.click()
98+
Log.d(TAG, "🔧 Clicked Embedded Messages button successfully")
99+
} else {
100+
Log.e(TAG, "❌ Embedded Messages button not found!")
101+
Assert.fail("Embedded Messages button not found in MainActivity")
102+
}
103+
104+
// Step 3: Wait for EmbeddedMessageTestActivity to load
105+
Log.d(TAG, "🔧 Step 3: Waiting for EmbeddedMessageTestActivity to load...")
106+
Thread.sleep(2000) // Give time for navigation
107+
108+
Log.d(TAG, "🔧 App navigation complete: Now on EmbeddedMessageTestActivity!")
109+
}
110+
111+
@Test
112+
fun testEmbeddedMessageMVP() {
113+
// Step 1: Ensure user is signed in
114+
Log.d(TAG, "📧 Step 1: Ensuring user is signed in...")
115+
val userSignedIn = testUtils.ensureUserSignedIn(TestConstants.TEST_USER_EMAIL)
116+
Assert.assertTrue("User should be signed in", userSignedIn)
117+
Log.d(TAG, "✅ User signed in successfully: ${TestConstants.TEST_USER_EMAIL}")
118+
119+
// Step 2: Preliminary check - verify view is ready with placement ID
120+
Log.d(TAG, "🔍 Step 2: Checking view readiness with placement ID...")
121+
var viewReady = false
122+
InstrumentationRegistry.getInstrumentation().runOnMainSync {
123+
val activity = ActivityLifecycleMonitorRegistry.getInstance()
124+
.getActivitiesInStage(Stage.RESUMED)
125+
.firstOrNull() as? EmbeddedMessageTestActivity
126+
127+
activity?.let {
128+
val fragmentContainer = it.findViewById<androidx.fragment.app.FragmentContainerView>(R.id.embedded_message_container)
129+
viewReady = fragmentContainer != null
130+
if (viewReady) {
131+
Log.d(TAG, "✅ View is ready with placementID - $TEST_PLACEMENT_ID")
132+
}
133+
}
134+
}
135+
Assert.assertTrue("FragmentContainerView should exist in EmbeddedMessageTestActivity", viewReady)
136+
137+
// Step 3: Update user properties to make user eligible
138+
Log.d(TAG, "📝 Step 3: Updating user properties (isPremium = true)...")
139+
val dataFields = JSONObject().apply {
140+
put("isPremium", true)
141+
}
142+
IterableApi.getInstance().updateUser(dataFields)
143+
Log.d(TAG, "✅ User properties updated")
144+
145+
// Step 4: Wait 5 seconds for backend to process and make user eligible
146+
Log.d(TAG, "⏳ Step 4: Waiting 5 seconds for backend to process user update...")
147+
Thread.sleep(3000)
148+
149+
// Step 5: Manually sync embedded messages
150+
Log.d(TAG, "🔄 Step 5: Syncing embedded messages...")
151+
IterableApi.getInstance().embeddedManager.syncMessages()
152+
153+
// Wait for sync to complete
154+
Thread.sleep(2000)
155+
156+
// Step 6: Get placement IDs and verify expected placement ID exists
157+
Log.d(TAG, "🔍 Step 6: Getting placement IDs...")
158+
val placementIds = IterableApi.getInstance().embeddedManager.getPlacementIds()
159+
Log.d(TAG, "📋 Found placement IDs: $placementIds")
160+
161+
Assert.assertTrue(
162+
"Placement ID $TEST_PLACEMENT_ID should exist, but found: $placementIds",
163+
placementIds.contains(TEST_PLACEMENT_ID)
164+
)
165+
Log.d(TAG, "✅ Placement ID $TEST_PLACEMENT_ID found")
166+
167+
// Step 7: Get messages for the placement ID
168+
Log.d(TAG, "📨 Step 7: Getting messages for placement ID $TEST_PLACEMENT_ID...")
169+
val messages = IterableApi.getInstance().embeddedManager.getMessages(TEST_PLACEMENT_ID)
170+
Assert.assertTrue("Should have at least 1 message for placement $TEST_PLACEMENT_ID", messages!!.isNotEmpty())
171+
172+
val message = messages.first()
173+
Log.d(TAG, "✅ Found message: ${message.metadata.messageId}")
174+
175+
// Step 8: Display message using IterableEmbeddedView
176+
Log.d(TAG, "🎨 Step 8: Displaying message using IterableEmbeddedView...")
177+
178+
InstrumentationRegistry.getInstrumentation().runOnMainSync {
179+
val activity = ActivityLifecycleMonitorRegistry.getInstance()
180+
.getActivitiesInStage(Stage.RESUMED)
181+
.firstOrNull() as? EmbeddedMessageTestActivity
182+
183+
if (activity != null) {
184+
val fragment = IterableEmbeddedView(IterableEmbeddedViewType.BANNER, message, null)
185+
activity.supportFragmentManager.beginTransaction()
186+
.replace(R.id.embedded_message_container, fragment)
187+
.commitNow()
188+
Log.d(TAG, "✅ Fragment added to FragmentManager")
189+
} else {
190+
Assert.fail("EmbeddedMessageTestActivity not found in RESUMED stage")
191+
}
192+
}
193+
194+
// Wait for fragment to be displayed
195+
Thread.sleep(1000)
196+
197+
// Step 9: Verify display - check fragment exists
198+
Log.d(TAG, "✅ Step 9: Verifying embedded message is displayed...")
199+
var isEmbeddedFragmentDisplayed = false
200+
201+
InstrumentationRegistry.getInstrumentation().runOnMainSync {
202+
val activity = ActivityLifecycleMonitorRegistry.getInstance()
203+
.getActivitiesInStage(Stage.RESUMED)
204+
.firstOrNull() as? EmbeddedMessageTestActivity
205+
206+
activity?.let { act ->
207+
val fragmentManager = act.supportFragmentManager
208+
fragmentManager.fragments.forEach { fragment ->
209+
if (fragment is IterableEmbeddedView) {
210+
isEmbeddedFragmentDisplayed = true
211+
Log.d(TAG, "✅ Found IterableEmbeddedView fragment")
212+
}
213+
}
214+
}
215+
}
216+
217+
Assert.assertTrue(
218+
"IterableEmbeddedView fragment should be displayed",
219+
isEmbeddedFragmentDisplayed
220+
)
221+
222+
Log.d(TAG, "✅ Embedded message is displayed, now interacting with button...")
223+
224+
// Step 10: Interact with button - find and click first button
225+
Log.d(TAG, "🎯 Step 10: Clicking button in the embedded message...")
226+
227+
// Try to find button by resource ID first
228+
val button = uiDevice.findObject(UiSelector().resourceId("com.iterable.iterableapi.ui:id/embedded_message_first_button"))
229+
230+
if (button.exists()) {
231+
button.click()
232+
Log.d(TAG, "✅ Clicked embedded message button")
233+
} else {
234+
// Try to find by button text if available
235+
val buttonText = message.elements?.buttons?.firstOrNull()?.title
236+
if (buttonText != null) {
237+
val buttonByText = uiDevice.findObject(By.text(buttonText))
238+
if (buttonByText != null) {
239+
buttonByText.click()
240+
Log.d(TAG, "✅ Clicked embedded message button by text: $buttonText")
241+
} else {
242+
Assert.fail("Button not found in the embedded message (tried resource ID and text: $buttonText)")
243+
}
244+
} else {
245+
Assert.fail("Button not found in the embedded message (tried resource ID, but no button text available)")
246+
}
247+
}
248+
249+
// Step 11: Verify URL handler was called
250+
Log.d(TAG, "🎯 Step 11: Verifying URL handler was called after button click...")
251+
252+
val urlHandlerCalled = waitForUrlHandler(timeoutSeconds = 3)
253+
Assert.assertTrue(
254+
"URL handler should have been called after clicking the button",
255+
urlHandlerCalled
256+
)
257+
258+
// Step 12: Verify the correct URL was handled
259+
val handledUrl = getLastHandledUrl()
260+
Log.d(TAG, "🎯 URL handler received: $handledUrl")
261+
262+
Assert.assertNotNull("Handled URL should not be null", handledUrl)
263+
Log.d(TAG, "✅ URL handler was called with URL: $handledUrl")
264+
265+
Log.d(TAG, "✅✅✅ Test completed successfully! All steps passed.")
266+
}
267+
}
268+

integration-tests/src/main/java/com/iterable/integration/tests/TestConstants.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ object TestConstants {
1515
const val TEST_PUSH_CAMPAIGN_ID = 14332358
1616
const val TEST_EMBEDDED_CAMPAIGN_ID = 14332359
1717

18+
// Test placement IDs
19+
const val TEST_EMBEDDED_PLACEMENT_ID = 2157L
20+
1821
// Test timeouts
1922
const val TIMEOUT_SECONDS = 5L
2023
const val POLL_INTERVAL_SECONDS = 1L

0 commit comments

Comments
 (0)