Supported regression testing compose renderer

commit_hash:410042befdd81c5ba1812cf29b68b69001e68c69
This commit is contained in:
burstein
2026-04-14 12:27:07 +03:00
parent 981a7eae70
commit 4acdbd9b78
15 changed files with 156 additions and 45 deletions
+4
View File
@@ -2009,8 +2009,11 @@
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/font/ComposeFontFamilyProvider.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/font/ComposeFontFamilyProvider.kt",
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/font/RobotoFlexTypefaceProvider.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/font/RobotoFlexTypefaceProvider.kt",
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/font/YandexSansCondensedTypefaceProvider.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/font/YandexSansCondensedTypefaceProvider.kt",
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/regression/RegressionComposeViewCreator.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/regression/RegressionComposeViewCreator.kt",
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/regression/RegressionDiv2ViewCreator.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/regression/RegressionDiv2ViewCreator.kt",
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/regression/RegressionDivActionHandler.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/regression/RegressionDivActionHandler.kt",
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/regression/RegressionSwitchingViewCreator.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/regression/RegressionSwitchingViewCreator.kt",
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/regression/ScenarioJson.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/regression/ScenarioJson.kt",
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/screenshot/ComposeImageLoadingTracker.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/screenshot/ComposeImageLoadingTracker.kt",
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/screenshot/DivAssetReader.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/screenshot/DivAssetReader.kt",
"client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/screenshot/DivComposeScreenshotActivity.kt":"divkit/public/client/android/divkit-demo-app/src/main/java/com/yandex/divkit/demo/screenshot/DivComposeScreenshotActivity.kt",
@@ -17599,6 +17602,7 @@
"client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/ScenarioActivity.kt":"divkit/public/client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/ScenarioActivity.kt",
"client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/ScenarioListAdapter.kt":"divkit/public/client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/ScenarioListAdapter.kt",
"client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/ScenarioLogDelegate.kt":"divkit/public/client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/ScenarioLogDelegate.kt",
"client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/ScenarioViewCreator.kt":"divkit/public/client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/ScenarioViewCreator.kt",
"client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/SliderActivity.kt":"divkit/public/client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/SliderActivity.kt",
"client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/data/AssetScenariosDataSource.kt":"divkit/public/client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/data/AssetScenariosDataSource.kt",
"client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/data/DataSourceBindings.kt":"divkit/public/client/android/divkit-regression-testing/src/main/java/com/yandex/divkit/regression/data/DataSourceBindings.kt",
@@ -731,7 +731,7 @@
"items": [
{
"type": "settings_item_title",
"text": "Compose Renderer by default"
"text": "Compose Renderer (Demo and testing)"
},
{
"type": "setting_switch_state",
@@ -18,7 +18,9 @@ import com.yandex.divkit.demo.div.editor.NaiveSSLContext
import com.yandex.divkit.demo.div.histogram.DemoHistogramConfiguration
import com.yandex.divkit.demo.div.histogram.LoggingHistogramBridge
import com.yandex.divkit.demo.div.video.DemoVideoCustomImageCache
import com.yandex.divkit.demo.regression.RegressionComposeViewCreator
import com.yandex.divkit.demo.regression.RegressionDiv2ViewCreator
import com.yandex.divkit.demo.regression.RegressionSwitchingViewCreator
import com.yandex.divkit.demo.settings.FlagPreferenceProvider
import com.yandex.divkit.demo.settings.Preferences
import com.yandex.divkit.demo.utils.DivkitDemoUriHandler
@@ -111,9 +113,12 @@ internal object Container {
val flagPreferenceProvider by lazy { FlagPreferenceProvider(context) }
val regressionComponent by lazy {
val div2ViewCreator = RegressionDiv2ViewCreator(context)
val composeViewCreator = RegressionComposeViewCreator(context)
`Yatagan$RegressionComponent`.builder().create(
context = context,
viewCreator = RegressionDiv2ViewCreator(context)
div2ViewCreator = div2ViewCreator,
scenarioViewCreator = RegressionSwitchingViewCreator(div2ViewCreator, composeViewCreator),
)
}
@@ -25,6 +25,9 @@ class DivkitApplication : Application(), HasRegressionTesting {
override val regressionComponent: RegressionComponent
get() = Container.regressionComponent
override val isComposeRendererEnabled: Boolean
get() = Container.preferences.useComposeRenderer
override fun onCreate() {
super.onCreate()
@@ -0,0 +1,46 @@
package com.yandex.divkit.demo.regression
import android.app.Activity
import android.content.Context
import android.view.View
import androidx.compose.ui.platform.ComposeView
import com.yandex.div.compose.DivComposeConfiguration
import com.yandex.div.compose.DivContext
import com.yandex.div.compose.DivView as ComposeDivView
import com.yandex.div.data.DivParsingEnvironment
import com.yandex.div.json.ParsingErrorLogger
import com.yandex.div2.DivData
import com.yandex.divkit.demo.font.ComposeFontFamilyProvider
import com.yandex.divkit.demo.screenshot.DivAssetReader
import org.json.JSONObject
class RegressionComposeViewCreator(context: Context) {
private val assetReader = DivAssetReader(context)
fun createView(
activity: Activity,
scenarioPath: String,
onBound: (View) -> Unit,
) {
val (templatesJson, cardJson) = assetReader.readScenarioJson(scenarioPath)
val divData = parseDivData(templatesJson, cardJson)
val composeDivContext = DivContext(
baseContext = activity,
configuration = DivComposeConfiguration(
fontFamilyProvider = ComposeFontFamilyProvider(activity),
)
)
val composeView = ComposeView(composeDivContext).apply {
setContent { ComposeDivView(data = divData) }
}
onBound(composeView)
}
private fun parseDivData(templatesJson: JSONObject?, cardJson: JSONObject): DivData {
val environment = DivParsingEnvironment(ParsingErrorLogger.LOG).apply {
if (templatesJson != null) parseTemplates(templatesJson)
}
return DivData(environment, cardJson)
}
}
@@ -22,7 +22,6 @@ import com.yandex.divkit.demo.utils.DivkitDemoUriHandler
import com.yandex.divkit.demo.utils.lifecycleOwner
import com.yandex.divkit.regression.Div2ViewCreator
import com.yandex.divkit.regression.ScenarioLogDelegate
import org.json.JSONObject
import java.util.concurrent.Executors
class RegressionDiv2ViewCreator(context: Context) : Div2ViewCreator {
@@ -42,17 +41,9 @@ class RegressionDiv2ViewCreator(context: Context) : Div2ViewCreator {
logDelegate: ScenarioLogDelegate,
onBound: (Div2View) -> Unit
) {
val divContext = createContext(activity, parent, logDelegate)
val divJson = assetReader.read(scenarioPath)
when {
divJson.has("card") -> {
val templateJson = parseTemplates(divJson)
val cardJson = parseCard(divJson)
Div2ViewFactory(divContext, templateJson).createAndBindViewByConfig(cardJson, onBound)
}
else -> Div2ViewFactory(divContext).createAndBindViewByConfig(divJson, onBound)
}
val divContext = createDiv2Context(activity, parent, logDelegate)
val (templatesJson, cardJson) = assetReader.readScenarioJson(scenarioPath)
Div2ViewFactory(divContext, templatesJson).createAndBindViewByConfig(cardJson, onBound)
}
override fun createDiv2ViewSync(
@@ -61,20 +52,12 @@ class RegressionDiv2ViewCreator(context: Context) : Div2ViewCreator {
parent: ViewGroup,
logDelegate: ScenarioLogDelegate,
): Div2View {
val divContext = createContext(activity, parent, logDelegate)
val divJson = assetReader.read(scenarioPath)
return when {
divJson.has("card") -> {
val templateJson = parseTemplates(divJson)
val cardJson = parseCard(divJson)
Div2ViewFactory(divContext, templateJson).createAndBindViewSync(cardJson)
}
else -> Div2ViewFactory(divContext).createAndBindViewSync(divJson)
}
val divContext = createDiv2Context(activity, parent, logDelegate)
val (templatesJson, cardJson) = assetReader.readScenarioJson(scenarioPath)
return Div2ViewFactory(divContext, templatesJson).createAndBindViewSync(cardJson)
}
private fun createContext(
private fun createDiv2Context(
activity: Activity,
parent: ViewGroup,
logDelegate: ScenarioLogDelegate
@@ -105,15 +88,4 @@ class RegressionDiv2ViewCreator(context: Context) : Div2ViewCreator {
}
}
private fun parseTemplates(
divJson: JSONObject,
): JSONObject? {
return divJson.optJSONObject("templates")
}
private fun parseCard(
divJson: JSONObject,
): JSONObject {
return divJson.getJSONObject("card")
}
}
@@ -0,0 +1,28 @@
package com.yandex.divkit.demo.regression
import android.app.Activity
import android.view.View
import android.view.ViewGroup
import com.yandex.divkit.demo.Container
import com.yandex.divkit.regression.ScenarioLogDelegate
import com.yandex.divkit.regression.ScenarioViewCreator
class RegressionSwitchingViewCreator(
private val div2ViewCreator: RegressionDiv2ViewCreator,
private val composeViewCreator: RegressionComposeViewCreator,
) : ScenarioViewCreator {
override fun createView(
activity: Activity,
scenarioPath: String,
parent: ViewGroup,
logDelegate: ScenarioLogDelegate,
onBound: (View) -> Unit,
) {
if (Container.preferences.useComposeRenderer) {
composeViewCreator.createView(activity, scenarioPath, onBound)
} else {
div2ViewCreator.createDiv2ViewByConfig(activity, scenarioPath, parent, logDelegate, onBound)
}
}
}
@@ -0,0 +1,17 @@
package com.yandex.divkit.demo.regression
import com.yandex.divkit.demo.screenshot.DivAssetReader
import org.json.JSONObject
internal data class ScenarioJson(
val templatesJson: JSONObject?,
val cardJson: JSONObject,
)
internal fun DivAssetReader.readScenarioJson(scenarioPath: String): ScenarioJson {
val divJson = read(scenarioPath)
return ScenarioJson(
templatesJson = divJson.optJSONObject("templates"),
cardJson = divJson.getJSONObject("card"),
)
}
@@ -33,5 +33,5 @@
<string name="load_patch">Load patch</string>
<string name="load_div_json">Load another div json</string>
<string name="close_all_tooltips">Close all tooltips</string>
<string name="compose_renderer">Compose Renderer (Demo)</string>
<string name="compose_renderer">Compose Renderer (Demo and testing)</string>
</resources>
@@ -16,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy
import com.yandex.div.internal.Assert
import com.yandex.divkit.regression.databinding.RegressionActivityBinding
import com.yandex.divkit.regression.di.provideDiv2ViewCreator
import com.yandex.divkit.regression.di.provideIsComposeRendererEnabled
import kotlinx.coroutines.flow.FlowCollector
private const val TAG_FILTER_MENU_ID = 1
@@ -38,7 +39,7 @@ class RegressionActivity : AppCompatActivity() {
binding = RegressionActivityBinding.inflate(layoutInflater)
setSupportActionBar(binding.regressionToolbar)
binding.toolbarLayout.title = getString(R.string.regression_label)
updateToolbarTitle()
val config: Configuration = resources.configuration
val icon = if (config.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
R.drawable.ic_back_rtl
@@ -79,6 +80,16 @@ class RegressionActivity : AppCompatActivity() {
}
}
override fun onResume() {
super.onResume()
updateToolbarTitle()
}
private fun updateToolbarTitle() {
val suffix = if (provideIsComposeRendererEnabled()) " (Compose)" else ""
binding.toolbarLayout.title = getString(R.string.regression_label) + suffix
}
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
if (menu == null) return super.onPrepareOptionsMenu(menu)
val tagFilterSubMenu = menu.findItem(TAG_FILTER_MENU_ID).subMenu
@@ -17,7 +17,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.yandex.divkit.regression.data.Scenario
import com.yandex.divkit.regression.databinding.ScenarioActivityBinding
import com.yandex.divkit.regression.di.provideDiv2ViewCreator
import com.yandex.divkit.regression.di.provideScenarioViewCreator
import com.yandex.divkit.regression.di.provideScenariosRepository
import com.yandex.divkit.regression.utils.shortMessage
@@ -31,7 +31,7 @@ private const val INVALID_POSITION = -1
class ScenarioActivity : AppCompatActivity(), MetadataBottomSheet.ScenarioHost {
private lateinit var binding: ScenarioActivityBinding
private val repository by lazy(LazyThreadSafetyMode.NONE) { provideScenariosRepository() }
private val div2ViewCreator by lazy(LazyThreadSafetyMode.NONE) { provideDiv2ViewCreator() }
private val scenarioViewCreator by lazy(LazyThreadSafetyMode.NONE) { provideScenarioViewCreator() }
private val logging = mutableListOf<String>()
private val logDelegate = ScenarioLogDelegate { message -> logging += message }
@@ -135,7 +135,7 @@ class ScenarioActivity : AppCompatActivity(), MetadataBottomSheet.ScenarioHost {
}
}
binding.singleContainer.isVisible = true
div2ViewCreator.createDiv2ViewByConfig(
scenarioViewCreator.createView(
this,
"regression_test_data/${scenario.file}",
binding.singleContainer,
@@ -0,0 +1,15 @@
package com.yandex.divkit.regression
import android.app.Activity
import android.view.View
import android.view.ViewGroup
fun interface ScenarioViewCreator {
fun createView(
activity: Activity,
scenarioPath: String,
parent: ViewGroup,
logDelegate: ScenarioLogDelegate,
onBound: (View) -> Unit,
)
}
@@ -2,4 +2,5 @@ package com.yandex.divkit.regression.di
interface HasRegressionTesting {
val regressionComponent: RegressionComponent
val isComposeRendererEnabled: Boolean get() = false
}
@@ -2,9 +2,15 @@ package com.yandex.divkit.regression.di
import android.content.Context
internal fun Context.provideRegressionComponent() =
(applicationContext as HasRegressionTesting).regressionComponent
internal fun Context.provideHasRegressionTesting() =
applicationContext as HasRegressionTesting
internal fun Context.provideRegressionComponent() = provideHasRegressionTesting().regressionComponent
internal fun Context.provideScenariosRepository() = provideRegressionComponent().scenariosRepository
internal fun Context.provideDiv2ViewCreator() = provideRegressionComponent().div2ViewCreator
internal fun Context.provideScenarioViewCreator() = provideRegressionComponent().scenarioViewCreator
internal fun Context.provideIsComposeRendererEnabled() = provideHasRegressionTesting().isComposeRendererEnabled
@@ -2,6 +2,7 @@ package com.yandex.divkit.regression.di
import android.content.Context
import com.yandex.divkit.regression.Div2ViewCreator
import com.yandex.divkit.regression.ScenarioViewCreator
import com.yandex.divkit.regression.data.DataSourceBindings
import com.yandex.divkit.regression.data.ScenariosRepository
import com.yandex.yatagan.BindsInstance
@@ -14,12 +15,14 @@ interface RegressionComponent {
val scenariosRepository: ScenariosRepository
val div2ViewCreator: Div2ViewCreator
val scenarioViewCreator: ScenarioViewCreator
@Component.Builder
interface Factory {
fun create(
@BindsInstance context: Context,
@BindsInstance viewCreator: Div2ViewCreator
@BindsInstance div2ViewCreator: Div2ViewCreator,
@BindsInstance scenarioViewCreator: ScenarioViewCreator,
): RegressionComponent
}
}