Skip to content

Commit 95f7d5d

Browse files
author
“Akshay
committed
[SDK-16] BCIT EM
Introduced new Test like for inapp. 1. Instead of campaign trigger, this test updates the user with `isPremium:true` value. Based on this, a live campaign (assumed to be running endlessly on server) will have this user eligible. 2. Hardcoded PlacementID value is used. 3. EmbeddedTestActivity and its corresponding xml is now updated to be able to manually test the functionality as well.
1 parent fbf54f7 commit 95f7d5d

File tree

4 files changed

+531
-21
lines changed

4 files changed

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

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)