-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathMyComposePreviewTester.kt
119 lines (109 loc) · 4.68 KB
/
MyComposePreviewTester.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package com.google.samples.apps.nowinandroid
import android.content.Context
import android.content.res.Configuration
import androidx.activity.ComponentActivity
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.unit.Density
import androidx.test.core.app.ApplicationProvider
import com.github.takahirom.roborazzi.ComposePreviewTester
import com.github.takahirom.roborazzi.ExperimentalRoborazziApi
import com.github.takahirom.roborazzi.captureRoboImage
import com.google.samples.apps.nowinandroid.core.ui.DelayedPreview
import org.robolectric.RuntimeEnvironment
import org.robolectric.Shadows
import org.robolectric.shadows.ShadowDisplay
import sergio.sastre.composable.preview.scanner.android.AndroidComposablePreviewScanner
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.android.screenshotid.AndroidPreviewScreenshotIdBuilder
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
import sergio.sastre.composable.preview.scanner.core.preview.getAnnotation
import kotlin.math.roundToInt
@OptIn(ExperimentalRoborazziApi::class)
class MyComposePreviewTester : ComposePreviewTester<AndroidPreviewInfo> {
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
override fun options(): ComposePreviewTester.Options {
val testLifecycleOptions = ComposePreviewTester.Options.JUnit4TestLifecycleOptions(
testRuleFactory = { composeTestRule }
)
return super.options().copy(testLifecycleOptions = testLifecycleOptions)
}
override fun previews(): List<ComposablePreview<AndroidPreviewInfo>> {
val options = options()
return AndroidComposablePreviewScanner()
.scanPackageTrees(*options.scanOptions.packages.toTypedArray())
.includeAnnotationInfoForAllOf(DelayedPreview::class.java)
.getPreviews()
}
override fun test(preview: ComposablePreview<AndroidPreviewInfo>) {
val delay = preview.getAnnotation<DelayedPreview>()?.delay ?: 0L
val previewScannerFileName =
AndroidPreviewScreenshotIdBuilder(preview).build()
val fileName =
if (delay == 0L) previewScannerFileName else "${previewScannerFileName}_delay$delay"
val filePath = "$fileName.png"
preview.myApplyToRobolectricConfiguration()
composeTestRule.activityRule.scenario.recreate()
composeTestRule.apply {
try {
if (delay != 0L) {
mainClock.autoAdvance = false
}
setContent {
ApplyToCompositionLocal(preview) {
preview()
}
}
if (delay != 0L) {
mainClock.advanceTimeBy(delay)
}
onRoot().captureRoboImage(filePath = filePath)
} finally {
mainClock.autoAdvance = true
}
}
}
}
@Composable
fun ApplyToCompositionLocal(
preview: ComposablePreview<AndroidPreviewInfo>,
content: @Composable () -> Unit
) {
val fontScale = preview.previewInfo.fontScale
val density = LocalDensity.current
val customDensity =
Density(density = density.density, fontScale = density.fontScale * fontScale)
CompositionLocalProvider(LocalDensity provides customDensity) {
content()
}
}
fun ComposablePreview<AndroidPreviewInfo>.myApplyToRobolectricConfiguration() {
val preview = this
// ナイトモード
when (preview.previewInfo.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
Configuration.UI_MODE_NIGHT_YES -> RuntimeEnvironment.setQualifiers("+night")
Configuration.UI_MODE_NIGHT_NO -> RuntimeEnvironment.setQualifiers("+notnight")
else -> { /* do nothing */
}
}
// 画面サイズ
if (preview.previewInfo.widthDp != -1 && preview.previewInfo.heightDp != -1) {
setDisplaySize(preview.previewInfo.widthDp, preview.previewInfo.heightDp)
}
}
private fun setDisplaySize(widthDp: Int, heightDp: Int) {
val context = ApplicationProvider.getApplicationContext<Context>()
val display = ShadowDisplay.getDefaultDisplay()
val density = context.resources.displayMetrics.density
widthDp.let {
val widthPx = (widthDp * density).roundToInt()
Shadows.shadowOf(display).setWidth(widthPx)
}
heightDp.let {
val heightPx = (heightDp * density).roundToInt()
Shadows.shadowOf(display).setHeight(heightPx)
}
}