sergio-sastre / ComposablePreviewScanner

A library to help auto-generate screenshot tests from Composable Previews with any screenshot testing library: JVM-based (i.e. Paparazzi, Roborazzi) as well as Instrumentation-based (i.e. Shot, Dropshots, Android-Testify, etc.)
MIT License
96 stars 1 forks source link

Split out device settings such as width, height #7

Open yschimke opened 3 weeks ago

yschimke commented 3 weeks ago
java.lang.IllegalArgumentException: failed to parse qualifiers 'w-1dp-h-1dp'. See https://developer.android.com/guide/topics/resources/providing-resources.html#QualifierRules for expected format.
    at org.robolectric.res.Qualifiers.parse(Qualifiers.java:35)
    at org.robolectric.res.Qualifiers.parse(Qualifiers.java:28)
    at org.robolectric.android.Bootstrap.applyQualifiers(Bootstrap.java:93)
    at org.robolectric.shadows.ShadowDisplayManager.createDisplayInfo(ShadowDisplayManager.java:193)
    at org.robolectric.shadows.ShadowDisplayManager.createDisplayInfo(ShadowDisplayManager.java:162)
    at org.robolectric.shadows.ShadowDisplayManager.changeDisplay(ShadowDisplayManager.java:226)
    at org.robolectric.RuntimeEnvironment.setQualifiers(RuntimeEnvironment.java:197)

Because in AndroidComposablePreviewInfoMapper

device="id:wearos_large_round" implies a bunch of other settings, which aren't currently applied.

Seems preferable for the library to handle this, rather than each app adopting.

sergio-sastre commented 3 weeks ago

@yschimke Thanks for the suggestion! If I understood it right, this is also somehow related to #6 right?

It is definitely sth I want to do, but the “device” preview value is the hardest to map due to the string parsing, and all its options, so to speak.

I’ll likely support other preview info values first, before diving into this, or initially provide support for preview predefined devices that are already available in Paparazzi & Roborazzi, which should be straightforward.

yschimke commented 3 weeks ago

I ended up applying the qualifiers and then querying them via InstrumentationRegistry. Perhaps that avoids parsing config files?

yschimke commented 3 weeks ago

Yep, it's similar issue. If 6 is done, I don't need this. Actually for file naming, but can achieve in other ways.

sergio-sastre commented 3 weeks ago

I ended up applying the qualifiers and then querying them via InstrumentationRegistry. Perhaps that avoids parsing config files?

Interesting. Could you share a code snippet? That would help 😊

yschimke commented 3 weeks ago

closed PR here https://github.com/android/wear-os-samples/pull/1126/files#diff-4b70e4b273d07b2d520241a25769c3b3b36ecb00b427e43e5027bcbc90b9c363

A few relevant things I needed to do for my case

Apply a device clip

           recordOptions = RoborazziOptions.RecordOptions(
                applyDeviceCrop = true,
            ),

Grab the device string and then apply via known values, because of this issue

    fun applyFor(preview: ComposablePreview<AndroidPreviewInfo>) {
        val device = when (preview.previewInfo.device) {
            "id:wearos_large_round" -> RobolectricDeviceQualifiers.WearOSLargeRound
            "id:wearos_small_round" -> RobolectricDeviceQualifiers.WearOSSmallRound
            "id:wearos_square" -> RobolectricDeviceQualifiers.WearOSSquare
            else -> null
        }
        if (device != null) {
            RuntimeEnvironment.setQualifiers(device)
        }
        RuntimeEnvironment.setFontScale(preview.previewInfo.fontScale)
    }

Apply and then grab the size and font scale for the filename

   @GraphicsMode(GraphicsMode.Mode.NATIVE)
    @Config(sdk = [33])
    @Test
    fun snapshot() {
        println("snapshot " + preview.methodName)
        RobolectricPreviewInfosApplier.applyFor(preview)

        val context = InstrumentationRegistry.getInstrumentation().context
        val width = context.resources.configuration.screenWidthDp

        val fontScale =
            if (preview.previewInfo.fontScale != 1.0f) "_${preview.previewInfo.fontScale}" else ""
        val device = if (context.resources.configuration.isScreenRound) "${width}dp" else "square"
        captureRoboImage(
            filePath = "src/test/screenshots/${this.javaClass.simpleName}_${preview.methodName}_$device$fontScale.png",
            roborazziOptions = RoborazziOptionsMapper.createFor(preview),
        ) {
            AppScaffold {
                preview()
            }
        }
    }
yschimke commented 3 weeks ago

Previews are like

@RoborazziConfig(comparisonThreshold = 0.02f)
@WearPreviewDevices
@WearPreviewFontScales
@Composable
fun ListScreenPreview() {
    ListScreen()
}
sergio-sastre commented 3 weeks ago

Yep, it's similar issue. If 6 is done, I don't need this. Actually for file naming, but can achieve in other ways.

FYI For file naming there is already a utility you might benefit from: AndroidPreviewScreenshotIdBuilder

0.1.2 includes some improvements in that component