Skip to content

Commit

Permalink
📐 Implement resize
Browse files Browse the repository at this point in the history
  • Loading branch information
viktor-rasevych-criteo committed Dec 4, 2023
1 parent 7ba3f24 commit 9cb87fc
Show file tree
Hide file tree
Showing 30 changed files with 1,119 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ import androidx.test.filters.FlakyTest
import androidx.test.rule.ActivityTestRule
import com.criteo.publisher.CriteoBannerView
import com.criteo.publisher.CriteoUtil
import com.criteo.publisher.DependencyProvider
import com.criteo.publisher.MraidData
import com.criteo.publisher.MraidPosition
import com.criteo.publisher.R
import com.criteo.publisher.TestAdUnits
import com.criteo.publisher.adview.MraidResizeCustomClosePosition
import com.criteo.publisher.adview.MraidState
import com.criteo.publisher.adview.Redirection
import com.criteo.publisher.callMraidObjectBlocking
Expand Down Expand Up @@ -83,6 +86,7 @@ class MraidBannerFunctionalTest {
private lateinit var onExpanded: CountDownLatch
private lateinit var onHidden: CountDownLatch
private lateinit var onDefault: CountDownLatch
private lateinit var onResized: CountDownLatch

@Before
fun setUp() {
Expand All @@ -92,6 +96,7 @@ class MraidBannerFunctionalTest {
onExpanded = CountDownLatch(1)
onHidden = CountDownLatch(1)
onDefault = CountDownLatch(1)
resetResizeCounter()

givenInitializedSdk(validBannerAdUnit)
bannerView = whenLoadingABanner(validBannerAdUnit)!!
Expand All @@ -105,12 +110,7 @@ class MraidBannerFunctionalTest {
onExpanded.await()
mockedDependenciesRule.waitForIdleState()

assertThat(getCurrentState()).isEqualTo(MraidState.EXPANDED)
assertThat(getWebView().parent).isNotNull
assertThat(getWebView().parent).isNotEqualTo(bannerView)
assertThat(bannerView.childCount).isEqualTo(1)
assertThat(bannerView.getChildAt(0).id).isEqualTo(R.id.adWebViewPlaceholder)
assertThat((getWebView().parent as ViewGroup).id).isEqualTo(R.id.adWebViewDialogContainer)
assertExpandedCorrectly()
}

@Test
Expand Down Expand Up @@ -138,18 +138,110 @@ class MraidBannerFunctionalTest {
onDefault.await()
mockedDependenciesRule.waitForIdleState()

assertClosedCorrectly(originalLayoutParams)
}

private fun assertClosedCorrectly(originalLayoutParams: ViewGroup.LayoutParams?) {
assertThat(getCurrentState()).isEqualTo(MraidState.DEFAULT)
assertThat(getWebView().parent).isEqualTo(bannerView)
assertThat(getWebView().layoutParams).isEqualTo(originalLayoutParams)
}

@Test
@FlakyTest(detail = "Flakiness comes from UI and concurrency")
fun whenExpandFromResizedState_ShouldMoveWebViewToDialogAndUpdateState() {
setResizeProperties(100, 100, 0, 0, MraidResizeCustomClosePosition.CENTER, true)
resize()

onResized.await()
mockedDependenciesRule.waitForIdleState()

expand()

onExpanded.await()
mockedDependenciesRule.waitForIdleState()

assertExpandedCorrectly()
}

@Test
@FlakyTest(detail = "Flakiness comes from UI and concurrency")
fun whenOpen_ShouldDelegateToRedirection() {
open()
mockedDependenciesRule.waitForIdleState()

verify(redirection).redirect(eq("https://www.criteo.com"), eq(activityRule.activity.componentName), any())
verify(redirection).redirect(
eq("https://www.criteo.com"),
eq(activityRule.activity.componentName),
any()
)
}

@Test
@FlakyTest(detail = "Flakiness comes from UI and concurrency")
fun whenResize_shouldMoveViewAboveAllViewsWithProperParamsAndUpdateState() {
val originalPosition = getCurrentPosition()

setResizeProperties(100, 100, 20, 20, MraidResizeCustomClosePosition.CENTER, true)
resize()

onResized.await()
mockedDependenciesRule.waitForIdleState()

assertThat(getCurrentState()).isEqualTo(MraidState.RESIZED)
val currentPosition = getCurrentPosition()
assertThat(currentPosition.width).isEqualTo(100)
assertThat(currentPosition.height).isEqualTo(100)
assertThat(currentPosition.x).isEqualTo(originalPosition.x + 20)
assertThat(currentPosition.y).isEqualTo(originalPosition.y + 20)
assertThat(getWebView().parent).isNotEqualTo(bannerView)
assertThat(bannerView.getChildAt(0).id).isEqualTo(R.id.adWebViewPlaceholder)
}

@Test
@FlakyTest(detail = "Flakiness comes from UI and concurrency")
fun whenResizeAndThenResizeWithDifferentParameter_shouldMoveViewAboveAllViewsWithProperParamsAndUpdateState() {
val originalPosition = getCurrentPosition()

setResizeProperties(100, 100, 15, 15, MraidResizeCustomClosePosition.CENTER, true)
resize()

onResized.await()
mockedDependenciesRule.waitForIdleState()

resetResizeCounter()
setResizeProperties(150, 150, 10, 10, MraidResizeCustomClosePosition.TOP_CENTER, false)
resize()

onResized.await()
mockedDependenciesRule.waitForIdleState()

assertThat(getCurrentState()).isEqualTo(MraidState.RESIZED)
val currentPosition = getCurrentPosition()
assertThat(currentPosition.width).isEqualTo(150)
assertThat(currentPosition.height).isEqualTo(150)
assertThat(currentPosition.x).isEqualTo(originalPosition.x + 15 + 10)
assertThat(currentPosition.y).isEqualTo(originalPosition.y + 15 + 10)

assertThat(getWebView().parent).isNotEqualTo(bannerView)
assertThat(bannerView.getChildAt(0).id).isEqualTo(R.id.adWebViewPlaceholder)
}

@Test
@FlakyTest(detail = "Flakiness comes from UI and concurrency")
fun whenResizeAndThenClose_ShouldMoveBackToOriginalContainer() {
val originalLayoutParams = getWebView().layoutParams
setResizeProperties(100, 100, 0, 0, MraidResizeCustomClosePosition.CENTER, true)
resize()

onResized.await()
mockedDependenciesRule.waitForIdleState()

close()
onDefault.await()
mockedDependenciesRule.waitForIdleState()

assertClosedCorrectly(originalLayoutParams)
}

private fun givenInitializedSdk(vararg preloadedAdUnits: AdUnit) {
Expand Down Expand Up @@ -189,6 +281,15 @@ class MraidBannerFunctionalTest {
waitForBids()
}

private fun assertExpandedCorrectly() {
assertThat(getCurrentState()).isEqualTo(MraidState.EXPANDED)
assertThat(getWebView().parent).isNotNull
assertThat(getWebView().parent).isNotEqualTo(bannerView)
assertThat(bannerView.childCount).isEqualTo(1)
assertThat(bannerView.getChildAt(0).id).isEqualTo(R.id.adWebViewPlaceholder)
assertThat((getWebView().parent as ViewGroup).id).isEqualTo(R.id.adWebViewDialogContainer)
}

private fun expand() {
getWebView().callMraidObjectBlocking("expand()")
}
Expand All @@ -197,13 +298,51 @@ class MraidBannerFunctionalTest {
getWebView().callMraidObjectBlocking("close()")
}

private fun setResizeProperties(
width: Int,
height: Int,
offsetX: Int,
offsetY: Int,
customClosePosition: MraidResizeCustomClosePosition,
allowOffscreen: Boolean
) {
getWebView().callMraidObjectBlocking(buildString {
append("setResizeProperties")
append("(")
append("{")
append("width:")
append(width)
append(", height:")
append(height)
append(", offsetX:")
append(offsetX)
append(", offsetY:")
append(offsetY)
append(", customClosePosition:")
append("\"")
append(customClosePosition.value)
append("\"")
append(", allowOffscreen:")
append(allowOffscreen)
append("}")
append(")")
})
}

private fun resize() {
getWebView().callMraidObjectBlocking("resize()")
}

private fun open() {
getWebView().callMraidObjectBlocking("open(\"https://www.criteo.com\")")
}

private fun getCurrentState() = getWebView().getJavascriptResultBlocking("window.mraid.getState()")
.toMraidState()

private fun getCurrentPosition() = getWebView().getJavascriptResultBlocking("window.mraid.getCurrentPosition()")
.toMraidPosition()

private fun getWebView(): WebView {
return bannerView.adWebView
}
Expand All @@ -217,18 +356,28 @@ class MraidBannerFunctionalTest {
onReady.countDown()
}

fun resetResizeCounter() {
onResized = CountDownLatch(1)
}

@JavascriptInterface
fun onStateChange(newState: String) {
when (newState.toMraidState()) {
MraidState.LOADING -> Unit
MraidState.DEFAULT -> onDefault.countDown()
MraidState.EXPANDED -> onExpanded.countDown()
MraidState.HIDDEN -> onHidden.countDown()
MraidState.RESIZED -> onResized.countDown()
}
}

private fun String.toMraidState(): MraidState {
val unquotedState = this.replace("\"", "")
return MraidState.values().first { it.stringValue == unquotedState }
}

private fun String.toMraidPosition(): MraidPosition = DependencyProvider.getInstance()
.provideMoshi()
.adapter(MraidPosition::class.java)
.fromJson(this)!!
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package com.criteo.publisher.interstitial
import androidx.test.rule.ActivityTestRule
import com.criteo.publisher.adview.MraidActionResult
import com.criteo.publisher.adview.MraidPlacementType
import com.criteo.publisher.adview.MraidResizeActionResult
import com.criteo.publisher.adview.MraidResizeCustomClosePosition
import com.criteo.publisher.adview.MraidState
import com.criteo.publisher.concurrent.RunOnUiThreadExecutor
import com.criteo.publisher.mock.MockedDependenciesRule
Expand Down Expand Up @@ -91,6 +93,24 @@ class CriteoInterstitialMraidControllerTest {
verify(callbackMock).invoke(argThat { this is MraidActionResult.Error })
}

@Test
fun doResize_ShouldCallbackError() {
val callbackMock = mock<(result: MraidResizeActionResult) -> Unit>()

criteoInterstitialMraidController.doResize(
100.0,
100.0,
0.0,
0.0,
MraidResizeCustomClosePosition.CENTER,
true,
callbackMock
)
mockedDependenciesRule.waitForIdleState()

verify(callbackMock).invoke(argThat { this is MraidResizeActionResult.Error })
}

@Test
fun doClose_givenLoadingState_ShouldCallbackError() {
val callbackMock = mock<(result: MraidActionResult) -> Unit>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ import com.criteo.publisher.concurrent.RunOnUiThreadExecutor
import com.criteo.publisher.concurrent.ThreadingUtil
import com.criteo.publisher.mock.MockedDependenciesRule
import com.criteo.publisher.test.activity.DummyActivity
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
import org.mockito.kotlin.atLeast
import org.mockito.kotlin.atLeastOnce
import org.mockito.kotlin.atMost
import org.mockito.kotlin.eq
import org.mockito.kotlin.lastValue
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
Expand Down Expand Up @@ -57,8 +62,14 @@ class ViewPositionTrackerTest {

private lateinit var viewPositionTracker: ViewPositionTracker

@Captor private lateinit var xCaptor: ArgumentCaptor<Int>
@Captor private lateinit var yCaptor: ArgumentCaptor<Int>
@Captor private lateinit var widthCaptor: ArgumentCaptor<Int>
@Captor private lateinit var heightCaptor: ArgumentCaptor<Int>

@Before
fun setUp() {
MockitoAnnotations.openMocks(this)
listener = mock()
uiHelper = UiHelper(activityRule)
viewPositionTracker = ViewPositionTracker(runOnUiThreadExecutor, deviceUtil)
Expand All @@ -74,12 +85,22 @@ class ViewPositionTrackerTest {
val outWindowLocation = IntArray(2)
view.getLocationInWindow(outWindowLocation)

val expectedX = deviceUtil.pixelToDp(outWindowLocation[0])
val expectedY = deviceUtil.pixelToDp(outWindowLocation[1] - deviceUtil.getTopSystemBarHeight(view))
val expectedWidth = deviceUtil.pixelToDp(view.width)
val expectedHeight = deviceUtil.pixelToDp(view.height)

verify(listener, atLeastOnce()).onPositionChange(
eq(deviceUtil.pxToDp(outWindowLocation[0])),
eq(deviceUtil.pxToDp(outWindowLocation[1])),
eq(deviceUtil.pxToDp(view.width)),
eq(deviceUtil.pxToDp(view.height))
xCaptor.capture(),
yCaptor.capture(),
widthCaptor.capture(),
heightCaptor.capture()
)

assertThat(xCaptor.lastValue).isEqualTo(expectedX)
assertThat(yCaptor.lastValue).isEqualTo(expectedY)
assertThat(widthCaptor.lastValue).isEqualTo(expectedWidth)
assertThat(heightCaptor.lastValue).isEqualTo(expectedHeight)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,11 @@ internal object BannerLogMessage {
level = Log.ERROR,
throwable = throwable
)

@JvmStatic
fun onBannerFailedToResize(bannerView: CriteoBannerView?, throwable: Throwable) = LogMessage(
message = "BannerView(${bannerView?.bannerAdUnit}) failed to resize",
level = Log.ERROR,
throwable = throwable
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class CriteoBannerAdWebViewFactory {
criteo: Criteo?,
parentContainer: CriteoBannerView
): CriteoBannerAdWebView {
return CriteoBannerAdWebView(context, attrs, bannerAdUnit, criteo, parentContainer)
return CriteoBannerAdWebView(context, attrs, bannerAdUnit, criteo, parentContainer).also {
it.id = R.id.bannerAdWebView
}
}
}
Loading

0 comments on commit 9cb87fc

Please sign in to comment.