Skip to content

Write & Run Screenshot Tests

akshay-at-yml edited this page Aug 25, 2022 · 16 revisions

Shot and Showkase

Writing shot tests and using showkase in test classes are explained in the individual sections.
This section will briefly show how to combine them with the below two appraoches.

Showkase Generated Tests.

In this approach, test class will implement ShowkaseScreenshotTest interface.
The test class must be abstract, and must be annotated with the @ShowkaseScreenshot as shown below. Showkase will autogenerate tests for each of the Previews / Colors / Typography available in the showkase browser.

onScreenshot of ShowkaseScreenshotTest will provide a bitmap for each of the component in the showkase browser, which is then recorded or compared using Shot's compareScreenshot method.

@ShowkaseScreenshot(rootShowkaseClass = DesignModule::class)
abstract class DesignTests : ShowkaseScreenshotTest, ScreenshotTest {
    @get:Rule
    override val composeTestRule: ComposeContentTestRule = createComposeRule()

    override fun onScreenshot(
        id: String,
        name: String,
        group: String,
        styleName: String?,
        screenshotType: ShowkaseScreenshotType,
        screenshotBitmap: Bitmap
    ) {
        compareScreenshot(screenshotBitmap, "${group}_${name}")
    }
}

Using Showkase Metadata

In the above approach if we want to run tests for dark theme / light theme or different locales, different emulators must be instantiated, and screenshots for each of them must be saved in different directories. Reason, the tests are autogenerated and can not be modified.

In such cases this approach would be helpful, which will allow you to run tests on multiple configurations, but single emulator. Refer this file for more info

Use Showkase.getMetadata().componentList which are the @Previews of the UI components. Each component from this list is called in ComposeContentTestRule, which can then be recorded by shot.

We can use TestParameterInjector by Google to inject multiple parameters for a single test.
In our example, we are injecting list of components from showkase and list of themes.

@RunWith(TestParameterInjector::class)
class ShotTests : ScreenshotTest {

    object Previews : TestParameter.TestParameterValuesProvider {
        override fun provideValues(): List<ComponentPreview> =
            Showkase.getMetadata().componentList.map(::ComponentPreview)
    }

    @Test
    fun tests(
        @TestParameter(valuesProvider = Previews::class)
        componentPreview: ComponentPreview
        @TestParameter(value = ["light", "dark"])
        uiMode: String
    ) {
        composeTestRule.setContent {
            CompositionLocalProvider(// Provide different themes / Locales here based on test parameters) {
                componentPreview.content() // This is our @Preview
            }
        }
        // Use the shot method to record the compose 
        compareScreenshot(composeTestRule, "name for each preview")
    }
}

Running Tests

Use the shot gradle commands to record and verify the tests. More details here.

Paparazzi and Showkase

Writing Tests

Paparazzi + Showkase tests are more similar to Shot + Showkase using Showkase Metadata.

Please refer this unit test class

Writing Paparazzi tests and using showkase in test classes are explained in the individual sections.

Note : Add showkase test dependencies as testImplementation. Paparazzi tests are unit tests.

Running Tests

To run Paparazzi + Showkase tests, run the same gradle tasks from Paparazzi. Look for more details here.