From ec7f4cea5ca5153798457aab10a5293cb078f8a7 Mon Sep 17 00:00:00 2001 From: Daniel Jette Date: Sun, 7 Jan 2024 17:16:42 -0500 Subject: [PATCH] ISSUE-88: Update documentation --- CHANGELOG.md | 2 + .../ComposeContainerNotFoundException.kt | 2 +- .../scenario/LaunchComposableTestActivity.kt | 2 +- .../fullscreen/FullscreenCaptureMethod.kt | 2 +- Library/build.gradle | 1 + .../testify/ScreenshotRuleLifecycleTest.kt | 2 +- .../scenario/ScenarioRuleAnnotationTest.kt | 2 +- .../ScenarioRuleAssertExpectedDeviceTest.kt | 2 +- .../scenario/ScenarioRuleExceptionTest.kt | 2 +- .../scenario/ScenarioTestRuleLifecycleTest.kt | 2 +- .../ScreenshotScenarioLifecycleTest.kt | 6 +- .../ScreenshotScenarioRuleDefaultTest.kt | 2 +- .../main/java/dev/testify/ScreenshotRule.kt | 3 +- .../dev/testify/core/TestifyConfiguration.kt | 2 +- .../exception/IllegalScenarioException.kt | 2 +- .../exception/MissingAssertSameException.kt | 2 +- ...esourceConfigurationOnScenarioException.kt | 2 +- .../exception/ScenarioRequiredException.kt | 2 +- .../java/dev/testify/core/logic/AssertSame.kt | 6 +- .../internal/helpers/EspressoHelper.kt | 2 +- .../internal/helpers/ResourceWrapper.kt | 2 +- .../scenario/ScreenshotScenarioRule.kt | 45 ++-- .../java/dev/testify/ScreenshotRuleTest.kt | 2 +- .../testify/core/exception/ErrorCauseTest.kt | 2 +- .../internal/helpers/ResourceWrapperTest.kt | 2 +- .../scenario/ScreenshotScenarioRuleTest.kt | 2 +- Samples/Flix/FlixLibrary/README.md | 2 +- Samples/Legacy/build.gradle | 1 + .../sample/ScreenshotRuleExampleTests.kt | 3 +- .../TestingResourcesCounterExampleTest.kt | 1 - .../ScenarioFullscreenCaptureExampleTest.kt | 6 +- .../ScenarioMainActivityScreenshotTest.kt | 7 +- .../ScreenshotScenarioRuleExampleTests.kt | 12 +- ...ScenarioClientDetailsViewScreenshotTest.kt | 2 +- ...cenarioClientListActivityScreenshotTest.kt | 2 +- .../ScenarioComposableScreenshotTest.kt | 2 +- .../ScenarioComposeActivityScreenshotTest.kt | 2 +- ...cenarioComposeRuleInteropScreenshotTest.kt | 4 +- docs/docs/extensions/compose/2-test.md | 56 +++++ .../extensions/compose/3-compose-test-rule.md | 69 ++++-- .../extensions/compose/4-resource-wrapping.md | 74 ++++++- docs/docs/extensions/fullscreen/2-test.md | 36 +++ docs/docs/get-started/3-write-a-test.md | 60 ++++- docs/docs/get-started/5-update-baseline.md | 12 +- docs/docs/get-started/6-verify-tests.md | 145 +++++++++++- docs/docs/get-started/8-use-gradle-plugin.md | 209 ++++++++++-------- docs/docs/recipes/1-view-provider.md | 43 +++- docs/docs/recipes/10-orientation.md | 43 +++- docs/docs/recipes/11-layout-inspector.md | 44 +++- docs/docs/recipes/12-capture-method.md | 95 ++++++-- docs/docs/recipes/13-software-rendering.md | 41 +++- docs/docs/recipes/14-exclude-regions.md | 52 ++++- docs/docs/recipes/15-keyboard-focus.md | 46 +++- docs/docs/recipes/16-custom-bitmap.md | 102 ++++++++- docs/docs/recipes/17-custom-capture.md | 23 -- docs/docs/recipes/17-custom-compare.md | 88 ++++++++ docs/docs/recipes/19-multi-user.md | 7 +- docs/docs/recipes/2-locale.md | 77 +++++-- docs/docs/recipes/20-gmd.md | 77 ++++--- docs/docs/recipes/21-library-projects.md | 23 +- docs/docs/recipes/3-font-scale.md | 45 +++- docs/docs/recipes/4-tolerance.md | 45 +++- docs/docs/recipes/5-testify-layout-library.md | 41 +++- docs/docs/recipes/6-intents.md | 39 ++++ docs/docs/recipes/7-layout-resource.md | 30 +++ docs/docs/recipes/8-espresso.md | 43 +++- docs/docs/recipes/9-java.md | 35 ++- docs/docusaurus.config.js | 4 +- 68 files changed, 1518 insertions(+), 333 deletions(-) delete mode 100644 docs/docs/recipes/17-custom-capture.md create mode 100644 docs/docs/recipes/17-custom-compare.md diff --git a/CHANGELOG.md b/CHANGELOG.md index cd3962e7..f853e6af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ ### Legacy Sample +#### Added + - Added tests demonstrating the usage of ScreenshotScenarioRule. ### Flix Sample diff --git a/Ext/Compose/src/main/java/dev/testify/compose/exception/ComposeContainerNotFoundException.kt b/Ext/Compose/src/main/java/dev/testify/compose/exception/ComposeContainerNotFoundException.kt index 7e2f24fb..81614582 100644 --- a/Ext/Compose/src/main/java/dev/testify/compose/exception/ComposeContainerNotFoundException.kt +++ b/Ext/Compose/src/main/java/dev/testify/compose/exception/ComposeContainerNotFoundException.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Ext/Compose/src/main/java/dev/testify/compose/scenario/LaunchComposableTestActivity.kt b/Ext/Compose/src/main/java/dev/testify/compose/scenario/LaunchComposableTestActivity.kt index 3b97315a..08fcc159 100644 --- a/Ext/Compose/src/main/java/dev/testify/compose/scenario/LaunchComposableTestActivity.kt +++ b/Ext/Compose/src/main/java/dev/testify/compose/scenario/LaunchComposableTestActivity.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/FullscreenCaptureMethod.kt b/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/FullscreenCaptureMethod.kt index 41ac34b0..9d44de49 100644 --- a/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/FullscreenCaptureMethod.kt +++ b/Ext/Fullscreen/src/main/java/dev/testify/capture/fullscreen/FullscreenCaptureMethod.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2022 ndtp + * Copyright (c) 2022-2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/build.gradle b/Library/build.gradle index 37b46fdd..d163595a 100644 --- a/Library/build.gradle +++ b/Library/build.gradle @@ -36,6 +36,7 @@ android { multiDexEnabled = true kotlinOptions { allWarningsAsErrors = true + freeCompilerArgs = [ "-Xcontext-receivers" ] } } diff --git a/Library/src/androidTest/java/dev/testify/ScreenshotRuleLifecycleTest.kt b/Library/src/androidTest/java/dev/testify/ScreenshotRuleLifecycleTest.kt index 473b03a9..62807a29 100644 --- a/Library/src/androidTest/java/dev/testify/ScreenshotRuleLifecycleTest.kt +++ b/Library/src/androidTest/java/dev/testify/ScreenshotRuleLifecycleTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Modified work copyright (c) 2022 ndtp + * Modified work copyright (c) 2022-2024 ndtp * Original work copyright (c) 2021 Shopify Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleAnnotationTest.kt b/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleAnnotationTest.kt index ca71fbb3..6923e99f 100644 --- a/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleAnnotationTest.kt +++ b/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleAnnotationTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleAssertExpectedDeviceTest.kt b/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleAssertExpectedDeviceTest.kt index 9d60b141..c76c0c11 100644 --- a/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleAssertExpectedDeviceTest.kt +++ b/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleAssertExpectedDeviceTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleExceptionTest.kt b/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleExceptionTest.kt index 906d130e..5d62aa6c 100644 --- a/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleExceptionTest.kt +++ b/Library/src/androidTest/java/dev/testify/scenario/ScenarioRuleExceptionTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/androidTest/java/dev/testify/scenario/ScenarioTestRuleLifecycleTest.kt b/Library/src/androidTest/java/dev/testify/scenario/ScenarioTestRuleLifecycleTest.kt index 914c5854..d716921d 100644 --- a/Library/src/androidTest/java/dev/testify/scenario/ScenarioTestRuleLifecycleTest.kt +++ b/Library/src/androidTest/java/dev/testify/scenario/ScenarioTestRuleLifecycleTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/androidTest/java/dev/testify/scenario/ScreenshotScenarioLifecycleTest.kt b/Library/src/androidTest/java/dev/testify/scenario/ScreenshotScenarioLifecycleTest.kt index 76bf3f75..8749c7c6 100644 --- a/Library/src/androidTest/java/dev/testify/scenario/ScreenshotScenarioLifecycleTest.kt +++ b/Library/src/androidTest/java/dev/testify/scenario/ScreenshotScenarioLifecycleTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2022 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -70,8 +70,8 @@ class ScreenshotScenarioLifecycleTest { } assertEquals(6, observer.log.size) - assertEquals("applyConfiguration", observer.log[0]) - assertEquals("beforeAssertSame", observer.log[1]) + assertEquals("beforeAssertSame", observer.log[0]) + assertEquals("applyConfiguration", observer.log[1]) assertEquals("beforeInitializeView", observer.log[2]) assertEquals("afterInitializeView", observer.log[3]) assertEquals("beforeScreenshot", observer.log[4]) diff --git a/Library/src/androidTest/java/dev/testify/scenario/ScreenshotScenarioRuleDefaultTest.kt b/Library/src/androidTest/java/dev/testify/scenario/ScreenshotScenarioRuleDefaultTest.kt index a982d40c..bd0fb906 100644 --- a/Library/src/androidTest/java/dev/testify/scenario/ScreenshotScenarioRuleDefaultTest.kt +++ b/Library/src/androidTest/java/dev/testify/scenario/ScreenshotScenarioRuleDefaultTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/main/java/dev/testify/ScreenshotRule.kt b/Library/src/main/java/dev/testify/ScreenshotRule.kt index f045ce50..b1f2d3c9 100644 --- a/Library/src/main/java/dev/testify/ScreenshotRule.kt +++ b/Library/src/main/java/dev/testify/ScreenshotRule.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Modified work copyright (c) 2022 ndtp + * Modified work copyright (c) 2022-2024 ndtp * Original work copyright (c) 2019 Shopify Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -398,7 +398,6 @@ open class ScreenshotRule @JvmOverloads constructor( /** * The [Statement] to be executed by the [ScreenshotStatement]. */ - @VisibleForTesting internal var statement: Statement? = null /** diff --git a/Library/src/main/java/dev/testify/core/TestifyConfiguration.kt b/Library/src/main/java/dev/testify/core/TestifyConfiguration.kt index 8687c1a0..a7304ef9 100644 --- a/Library/src/main/java/dev/testify/core/TestifyConfiguration.kt +++ b/Library/src/main/java/dev/testify/core/TestifyConfiguration.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2022 ndtp + * Copyright (c) 2022-2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/main/java/dev/testify/core/exception/IllegalScenarioException.kt b/Library/src/main/java/dev/testify/core/exception/IllegalScenarioException.kt index 39c10eff..e41cd88e 100644 --- a/Library/src/main/java/dev/testify/core/exception/IllegalScenarioException.kt +++ b/Library/src/main/java/dev/testify/core/exception/IllegalScenarioException.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/main/java/dev/testify/core/exception/MissingAssertSameException.kt b/Library/src/main/java/dev/testify/core/exception/MissingAssertSameException.kt index 73004710..61e58c3b 100644 --- a/Library/src/main/java/dev/testify/core/exception/MissingAssertSameException.kt +++ b/Library/src/main/java/dev/testify/core/exception/MissingAssertSameException.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Modified work copyright (c) 2022 ndtp + * Modified work copyright (c) 2022-2024 ndtp * Original work copyright (c) 2020 Shopify Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/Library/src/main/java/dev/testify/core/exception/NoResourceConfigurationOnScenarioException.kt b/Library/src/main/java/dev/testify/core/exception/NoResourceConfigurationOnScenarioException.kt index 2a77ef02..d1c7bfb8 100644 --- a/Library/src/main/java/dev/testify/core/exception/NoResourceConfigurationOnScenarioException.kt +++ b/Library/src/main/java/dev/testify/core/exception/NoResourceConfigurationOnScenarioException.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/main/java/dev/testify/core/exception/ScenarioRequiredException.kt b/Library/src/main/java/dev/testify/core/exception/ScenarioRequiredException.kt index b80b7868..dc4766c0 100644 --- a/Library/src/main/java/dev/testify/core/exception/ScenarioRequiredException.kt +++ b/Library/src/main/java/dev/testify/core/exception/ScenarioRequiredException.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/main/java/dev/testify/core/logic/AssertSame.kt b/Library/src/main/java/dev/testify/core/logic/AssertSame.kt index 97472fc3..833cbfba 100644 --- a/Library/src/main/java/dev/testify/core/logic/AssertSame.kt +++ b/Library/src/main/java/dev/testify/core/logic/AssertSame.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2023-2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -173,7 +173,7 @@ internal fun assertSame( if (TestifyFeatures.GenerateDiffs.isEnabled(activity)) { HighContrastDiff - .create(configuration.exclusionRects) // TODO: Test me + .create(configuration.exclusionRects) .name(outputFileName) .baseline(baselineBitmap) .current(currentBitmap) @@ -181,7 +181,7 @@ internal fun assertSame( .generate(context = activity) } if (isRecordMode) { - TestInstrumentationRegistry.instrumentationPrintln( // TODO: Test me + TestInstrumentationRegistry.instrumentationPrintln( "\n\t✓ " + "Recording baseline for ${description.name}".cyan() ) } else { diff --git a/Library/src/main/java/dev/testify/internal/helpers/EspressoHelper.kt b/Library/src/main/java/dev/testify/internal/helpers/EspressoHelper.kt index 1ec35267..006be149 100644 --- a/Library/src/main/java/dev/testify/internal/helpers/EspressoHelper.kt +++ b/Library/src/main/java/dev/testify/internal/helpers/EspressoHelper.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2022 ndtp + * Copyright (c) 2022-2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/main/java/dev/testify/internal/helpers/ResourceWrapper.kt b/Library/src/main/java/dev/testify/internal/helpers/ResourceWrapper.kt index 91b7feca..5c5e833a 100644 --- a/Library/src/main/java/dev/testify/internal/helpers/ResourceWrapper.kt +++ b/Library/src/main/java/dev/testify/internal/helpers/ResourceWrapper.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Modified work copyright (c) 2022 ndtp + * Modified work copyright (c) 2022-2024 ndtp * Original work copyright (c) 2020 Shopify Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt b/Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt index cedd3f50..40fbdf04 100644 --- a/Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt +++ b/Library/src/main/java/dev/testify/scenario/ScreenshotScenarioRule.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -56,7 +56,6 @@ import dev.testify.core.exception.ScreenshotIsDifferentException import dev.testify.core.logic.AssertionState import dev.testify.core.logic.ScreenshotLifecycleHost import dev.testify.core.logic.ScreenshotLifecycleObserver -import dev.testify.internal.extensions.TestInstrumentationRegistry.instrumentationPrintln import dev.testify.internal.extensions.isInvokedFromPlugin import dev.testify.internal.helpers.ActivityProvider import dev.testify.internal.helpers.closeSoftKeyboard @@ -68,6 +67,9 @@ import org.junit.rules.TestRule import org.junit.rules.TestWatcher import org.junit.runner.Description import org.junit.runners.model.Statement +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract /** * ScreenshotScenarioRule is one of the main entry point for Testify. @@ -189,7 +191,7 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( * @ScreenshotInstrumentation * @Test * fun default() { - * launchActivity().use { scenario -> + * launchActivity().use { scenario -> * rule * .withScenario(scenario) * .assertSame() @@ -217,7 +219,7 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( * @ScreenshotInstrumentation * @Test * fun default() { - * launchActivity().use { scenario -> + * launchActivity().use { scenario -> * rule * .withScenario(scenario) * .setViewModifications { harnessRoot -> @@ -247,7 +249,7 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( * @ScreenshotInstrumentation * @Test * fun setScreenshotViewProvider() { - * launchActivity().use { scenario -> + * launchActivity().use { scenario -> * rule * .withScenario(scenario) * .setScreenshotViewProvider { @@ -273,7 +275,7 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( * @ScreenshotInstrumentation * @Test * fun testConfigure() { - * launchActivity().use { scenario -> + * launchActivity().use { scenario -> * rule * .withScenario(scenario) * .configure { @@ -344,7 +346,6 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( testClass: Class<*>, methodAnnotations: Collection? ) { - instrumentationPrintln("apply") val classAnnotations = testClass.annotations.asList() assertForScreenshotInstrumentationAnnotation( methodName, @@ -454,7 +455,6 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( */ @CallSuper override fun beforeAssertSame() { - instrumentationPrintln("beforeAssertSame") getInstrumentation().registerActivityProvider(this) // Called after configuration has been set @@ -477,7 +477,7 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( * @ScreenshotInstrumentation * @Test * fun default() { - * launchActivity().use { scenario -> + * launchActivity().use { scenario -> * rule * .configure { * exactness = 0.95f @@ -494,6 +494,20 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( throw ScenarioRequiredException() } + scenario?.let { + assertSame(it) + } ?: throw ScenarioRequiredException() + } + + context (ActivityScenario<*>) + @JvmName("assertSameContext") + fun assertSame() { + assertSame(this@ActivityScenario) + } + + private fun assertSame(scenario: ActivityScenario<*>) { + this.scenario = scenario + addScreenshotObserver(this) try { @@ -533,9 +547,6 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( * Called by the [ScreenshotStatement] before each test method is executed. */ protected fun evaluateBeforeEach() { - - instrumentationPrintln("evaluateBeforeEach") - getInstrumentation()?.run { reporter?.identifySession(this) } @@ -555,8 +566,6 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( * Called by the [ScreenshotStatement] after each test method is executed. */ protected fun evaluateAfterEach() { - instrumentationPrintln("evaluateAfterEach") - /** * Only throw the MissingAssertSameException if the test is a screenshot test. * This allows the user to run the test as a normal JUnit test without having to call assertSame. @@ -610,3 +619,11 @@ open class ScreenshotScenarioRule @JvmOverloads constructor( notifyObservers { it.applyConfiguration(getActivity(), configuration) } } } + +@OptIn(ExperimentalContracts::class) +inline fun , A : Activity> T.test(block: T.(T) -> Unit) { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + this.block(this) +} diff --git a/Library/src/test/java/dev/testify/ScreenshotRuleTest.kt b/Library/src/test/java/dev/testify/ScreenshotRuleTest.kt index 03768859..4dcf487b 100644 --- a/Library/src/test/java/dev/testify/ScreenshotRuleTest.kt +++ b/Library/src/test/java/dev/testify/ScreenshotRuleTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2023-2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/test/java/dev/testify/core/exception/ErrorCauseTest.kt b/Library/src/test/java/dev/testify/core/exception/ErrorCauseTest.kt index 22ccced6..53444578 100644 --- a/Library/src/test/java/dev/testify/core/exception/ErrorCauseTest.kt +++ b/Library/src/test/java/dev/testify/core/exception/ErrorCauseTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Modified work copyright (c) 2022 ndtp + * Modified work copyright (c) 2022-2024 ndtp * Original work copyright (c) 2021 Shopify Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/Library/src/test/java/dev/testify/internal/helpers/ResourceWrapperTest.kt b/Library/src/test/java/dev/testify/internal/helpers/ResourceWrapperTest.kt index 62ee70ac..be00ff81 100644 --- a/Library/src/test/java/dev/testify/internal/helpers/ResourceWrapperTest.kt +++ b/Library/src/test/java/dev/testify/internal/helpers/ResourceWrapperTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2023-2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Library/src/test/java/dev/testify/scenario/ScreenshotScenarioRuleTest.kt b/Library/src/test/java/dev/testify/scenario/ScreenshotScenarioRuleTest.kt index 8bbc977c..250a14c6 100644 --- a/Library/src/test/java/dev/testify/scenario/ScreenshotScenarioRuleTest.kt +++ b/Library/src/test/java/dev/testify/scenario/ScreenshotScenarioRuleTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Samples/Flix/FlixLibrary/README.md b/Samples/Flix/FlixLibrary/README.md index fb06d5c8..3628a9cd 100644 --- a/Samples/Flix/FlixLibrary/README.md +++ b/Samples/Flix/FlixLibrary/README.md @@ -15,7 +15,7 @@ buildscript { mavenCentral() } dependencies { - classpath "dev.testify:plugin:2.0.0-beta04" + classpath "dev.testify:plugin:2.0.0" } } ``` diff --git a/Samples/Legacy/build.gradle b/Samples/Legacy/build.gradle index c7606246..ead24f1f 100644 --- a/Samples/Legacy/build.gradle +++ b/Samples/Legacy/build.gradle @@ -57,6 +57,7 @@ android { kotlinOptions { jvmTarget = "1.8" + freeCompilerArgs = [ "-Xcontext-receivers" ] } composeOptions { kotlinCompilerExtensionVersion "${versions.compose.compilerExt}" diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/ScreenshotRuleExampleTests.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/ScreenshotRuleExampleTests.kt index e5786c21..318ad426 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/ScreenshotRuleExampleTests.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/ScreenshotRuleExampleTests.kt @@ -164,6 +164,7 @@ class ScreenshotRuleExampleTests { .setEspressoActions { onView(withId(R.id.edit_text)).perform(typeText("Testify")) } + .setCompareMethod { _, _ -> true } .assertSame() } @@ -234,7 +235,6 @@ class ScreenshotRuleExampleTests { .assertSame() } - private fun ScreenshotRule.setupExactness(): ScreenshotRule { return this .setScreenshotViewProvider { @@ -302,6 +302,7 @@ class ScreenshotRuleExampleTests { fun setOrientation() { rule .setOrientation(requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE) + .configure { pauseForInspection = true } .assertSame() } diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/TestingResourcesCounterExampleTest.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/TestingResourcesCounterExampleTest.kt index 160fc60a..bdf2011b 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/TestingResourcesCounterExampleTest.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/TestingResourcesCounterExampleTest.kt @@ -43,7 +43,6 @@ import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test -import org.mockito.Mockito.spy import java.util.Locale /** diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScenarioFullscreenCaptureExampleTest.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScenarioFullscreenCaptureExampleTest.kt index 12dddce0..7cd37f7a 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScenarioFullscreenCaptureExampleTest.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScenarioFullscreenCaptureExampleTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,7 +38,9 @@ import org.junit.Test class ScenarioFullscreenCaptureExampleTest { - @get:Rule val rule = ScreenshotScenarioRule(configuration = TestifyConfiguration(exactness = 0.95f)) + @get:Rule val rule = ScreenshotScenarioRule( + configuration = TestifyConfiguration(exactness = 0.95f) + ) @ScreenshotInstrumentation @Test diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScenarioMainActivityScreenshotTest.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScenarioMainActivityScreenshotTest.kt index 60133be3..5da077a9 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScenarioMainActivityScreenshotTest.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScenarioMainActivityScreenshotTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,6 +28,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import dev.testify.annotation.ScreenshotInstrumentation import dev.testify.sample.MainActivity import dev.testify.scenario.ScreenshotScenarioRule +import dev.testify.scenario.test import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -40,8 +41,8 @@ class ScenarioMainActivityScreenshotTest { @ScreenshotInstrumentation @Test fun default() { - launchActivity().use { scenario -> - rule.withScenario(scenario).assertSame() + launchActivity().test { + rule.assertSame() } } } diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScreenshotScenarioRuleExampleTests.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScreenshotScenarioRuleExampleTests.kt index 3263dd4a..97f322ef 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScreenshotScenarioRuleExampleTests.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/ScreenshotScenarioRuleExampleTests.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -178,11 +178,11 @@ class ScreenshotScenarioRuleExampleTests { /** * Demonstrates Testify's ability to interoperate with Espresso actions. * - * [ScreenshotRule.setEspressoActions] accepts a lambda of type [EspressoActions] in which you - * may define any number of Espresso actions. These actions are executed after the activity is - * fully inflated and any view modifications have been applied. Testify will synchronize with - * the Espresso event loop and ensure that all Espresso actions are complete before capturing - * a screenshot. + * You can use Espresso actions on the Activity provided by the [ActivityScenario] that you provide + * to [ScreenshotScenarioRule.withScenario]. + * + * Testify will synchronize with the Espresso event loop and ensure that all Espresso actions are + * complete before capturing a screenshot. * * Note that it's not generally recommended to use complex Espresso actions with your screenshot * tests. Espresso test are an order of magnitude slower to run and are more susceptible to diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/clients/details/ScenarioClientDetailsViewScreenshotTest.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/clients/details/ScenarioClientDetailsViewScreenshotTest.kt index a66c5810..5f0192ee 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/clients/details/ScenarioClientDetailsViewScreenshotTest.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/clients/details/ScenarioClientDetailsViewScreenshotTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/clients/index/ScenarioClientListActivityScreenshotTest.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/clients/index/ScenarioClientListActivityScreenshotTest.kt index 7044f4c5..a148d585 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/clients/index/ScenarioClientListActivityScreenshotTest.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/clients/index/ScenarioClientListActivityScreenshotTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposableScreenshotTest.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposableScreenshotTest.kt index ee4a4f00..17c5ac10 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposableScreenshotTest.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposableScreenshotTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeActivityScreenshotTest.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeActivityScreenshotTest.kt index 61eac72c..7a001ffa 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeActivityScreenshotTest.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeActivityScreenshotTest.kt @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 ndtp + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeRuleInteropScreenshotTest.kt b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeRuleInteropScreenshotTest.kt index ec7ddeb3..4ad7c5e1 100644 --- a/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeRuleInteropScreenshotTest.kt +++ b/Samples/Legacy/src/androidTest/java/dev/testify/sample/scenario/compose/ScenarioComposeRuleInteropScreenshotTest.kt @@ -1,8 +1,7 @@ /* * The MIT License (MIT) * - * Modified work copyright (c) 2022 ndtp - * Original work copyright (c) 2021 Shopify Inc. + * Copyright (c) 2024 ndtp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -42,7 +41,6 @@ import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performScrollTo import androidx.compose.ui.test.performTextInput import androidx.compose.ui.unit.dp -import dev.testify.ComposableScreenshotRule import dev.testify.ComposableTestActivity import dev.testify.annotation.ScreenshotInstrumentation import dev.testify.compose.scenario.ComposableScreenshotScenarioRule diff --git a/docs/docs/extensions/compose/2-test.md b/docs/docs/extensions/compose/2-test.md index edabded2..00a19cbb 100644 --- a/docs/docs/extensions/compose/2-test.md +++ b/docs/docs/extensions/compose/2-test.md @@ -10,6 +10,62 @@ The `ComposeView` provided by `ComposableTestActivity` is defined with `WRAP_CON If necessary, you can access the root view with the identifier `dev.testify.compose.R.id.compose_container`. +## ComposableScreenshotScenarioRule + +As [ActivityTestRule is deprecated](https://developer.android.com/reference/androidx/test/rule/ActivityTestRule), the Android SDK now recommends the usage of [`ActivityScenario`](https://developer.android.com/reference/androidx/test/core/app/ActivityScenario) as the modern alternative. Testify provides `ComposableScreenshotScenarioRule` which works in conjunction with `ActivityScenario` to easily add screenshot tests to scenario-based UI tests. + +`ComposableScreenshotScenarioRule` is more flexible than the older `ComposableScreenshotRule` as it no longer requires you to couple the rule's instantiatiation with a specific Activity subclass. This allows the flexibility of testing multiple different activities in the same test class. + +Screenshot test integration with `ActivityScenario` is achieved via the `withScenario()` function. An active instance of a scenario must be provided to Testify prior to calling `assertSame()`. Typically, this is done by passing the scaneario instance returned by [`ActivityScenario.launch`](https://developer.android.com/reference/androidx/test/core/app/ActivityScenario#launch(java.lang.Class%3CA%3E)) to the `ScreenshotScenarioRule` instance within a `use {}` block. + +:::tip + +To enable [Android Studio Plugin](set-up-intellij-plugin) integration with your tests, each test method should be annotated with the `@ScreenshotInstrumentation` annotation. + +::: + +```kotlin +import androidx.test.core.app.launchActivity +import dev.testify.ComposableTestActivity +import dev.testify.annotation.ScreenshotInstrumentation +import dev.testify.compose.scenario.ComposableScreenshotScenarioRule +import org.junit.Rule +import org.junit.Test + +class ComposableScreenshotTest { + + @get:Rule val rule = ComposableScreenshotScenarioRule() + + @ScreenshotInstrumentation + @Test + fun default() { + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .setCompose { + Text(text = "Hello, Testify!") + } + .assertSame() + } + } +} +``` + +:::tip + +The helper extension method `launchComposableTestActivity` is provided to simplify the launching of the provided `ComposableTestActivity` test harness activity. + +::: + +## ComposableScreenshotRule + +:::caution + +[ActivityTestRule is deprecated](https://developer.android.com/reference/androidx/test/rule/ActivityTestRule) + +Use **androidx.test.core.app.ActivityScenario** instead with [**ComposableScreenshotScenarioRule**](#screenshotscenariorule). + +::: ### Example diff --git a/docs/docs/extensions/compose/3-compose-test-rule.md b/docs/docs/extensions/compose/3-compose-test-rule.md index 78194e21..c9ebc2be 100644 --- a/docs/docs/extensions/compose/3-compose-test-rule.md +++ b/docs/docs/extensions/compose/3-compose-test-rule.md @@ -1,3 +1,6 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Interoperability with ComposeTestRule @@ -12,6 +15,9 @@ You have access to the `ComposeRule` instance through the `setComposeActions()` ### Example + + + ```kotlin class ComposableScreenshotTest { @get:Rule @@ -20,22 +26,59 @@ class ComposableScreenshotTest { @ScreenshotInstrumentation @Test fun default() { - rule - .setCompose { - var text by remember { mutableStateOf("") } - TextField( - value = text, - onValueChange = { text = it }, - modifier = Modifier.testTag("field") - ) - } - .setComposeActions { composeTestRule -> - composeTestRule.onNodeWithTag("field").performTextInput("testify") - } - .assertSame() + rule + .setCompose { + var text by remember { mutableStateOf("") } + TextField( + value = text, + onValueChange = { text = it }, + modifier = Modifier.testTag("field") + ) + } + .setComposeActions { composeTestRule -> + composeTestRule.onNodeWithTag("field").performTextInput("testify") + } + .assertSame() } } ``` + + + +```kotlin +class ComposableScreenshotTest { + @get:Rule + val rule = ComposableScreenshotRule(composeTestRule = createAndroidComposeRule(ComposableTestActivity::class.java)) + + @ScreenshotInstrumentation + @Test + fun default() { + launchComposableTestActivity().use { scenario -> + rule + .withScenario(scenario) + .setCompose { + var text by remember { mutableStateOf("") } + TextField( + value = text, + onValueChange = { text = it }, + modifier = Modifier.testTag("field") + ) + } + .setComposeActions { composeTestRule -> + composeTestRule.onNodeWithTag("field").performTextInput("testify") + } + .assertSame() + } + } +} +``` + + + + + + + diff --git a/docs/docs/extensions/compose/4-resource-wrapping.md b/docs/docs/extensions/compose/4-resource-wrapping.md index 09057387..dc49645f 100644 --- a/docs/docs/extensions/compose/4-resource-wrapping.md +++ b/docs/docs/extensions/compose/4-resource-wrapping.md @@ -1,3 +1,6 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Testing with different Locales and Font Scales ## Locales @@ -8,6 +11,9 @@ When using `ComposableScreenshotRule`, you can invoke the `setLocale()` method t ### Example + + + ```kotlin // In the res/values/strings.xml file @@ -27,6 +33,36 @@ When using `ComposableScreenshotRule`, you can invoke the `setLocale()` method t .assertSame() } ``` + + + + +```kotlin + + // In the res/values/strings.xml file + // A short example + + // In the res/values-fr/strings.xml file + // Un petit exemple + + @ScreenshotInstrumentation + @Test + fun localeFrance() { + launchComposableTestActivity().use { scenario -> + rule + .withScenario(scenario) + .setCompose { + Text(stringResource(R.string.example)) + } + .setLocale(Locale.FRANCE) + .assertSame() + } + } +``` + + + + ## Font Scale @@ -36,6 +72,8 @@ See [Font size and display size](https://support.google.com/accessibility/androi To modify the font scale in a single test, use the `setFontScale()` method. + + ```kotlin @@ -43,11 +81,39 @@ To modify the font scale in a single test, use the `setFontScale()` method. @Test fun largeFontScale() { rule - Text( - text = "Test", - fontSize = 16.sp - ) + .setCompose { + Text( + text = "Test", + fontSize = 16.sp + ) + } .setFontScale(3.0f) .assertSame() } ``` + + + + +```kotlin + @ScreenshotInstrumentation + @Test + fun largeFontScale() { + launchComposableTestActivity().use { scenario -> + rule + .withScenario(scenario) + .setCompose { + Text( + text = "Test", + fontSize = 16.sp + ) + } + .setFontScale(3.0f) + .assertSame() + } + } +``` + + + + diff --git a/docs/docs/extensions/fullscreen/2-test.md b/docs/docs/extensions/fullscreen/2-test.md index 6b6bb562..05a3bddb 100644 --- a/docs/docs/extensions/fullscreen/2-test.md +++ b/docs/docs/extensions/fullscreen/2-test.md @@ -1,3 +1,6 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Write a full-screen screenshot test In order to capture the full device screen, you must set the capture method on `ScreenshotRule` to `fullscreenCapture()`. @@ -12,6 +15,9 @@ It is frequently desirable to exclude these elements from the comparison. Testif ### Example + + + ```kotlin class FullscreenCaptureTest { @@ -29,3 +35,33 @@ class FullscreenCaptureTest { } } ``` + + + + +```kotlin +class FullscreenCaptureTest { + + @get:Rule + val rule = ScreenshotScenarioRule( + configuration = TestifyConfiguration(exactness = 0.95f) // Allow a 5% variation in color + ) + + @ScreenshotInstrumentation + @Test + fun fullscreen() { + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .captureFullscreen() // Set the fullscreen capture method + .configure { + excludeSystemUi() // Exclude the navigation bar and status bar areas from the comparison + } + .assertSame() + } + } +} +``` + + + \ No newline at end of file diff --git a/docs/docs/get-started/3-write-a-test.md b/docs/docs/get-started/3-write-a-test.md index c0a9ba1c..e189d358 100644 --- a/docs/docs/get-started/3-write-a-test.md +++ b/docs/docs/get-started/3-write-a-test.md @@ -1,6 +1,56 @@ # Write a test -Testify is a subclass of Android's [`ActivityTestRule`](https://developer.android.com/reference/androidx/test/rule/ActivityTestRule.html). The testing framework launches the activity under test before each test method annotated with [`@Test`](https://junit.org/junit4/javadoc/latest/org/junit/Test.html) and before any method annotated with [`@Before`](http://junit.sourceforge.net/javadoc/org/junit/Before.html). +Testify provides two main entrypoints as JUnit4 [`TestRule`](https://junit.org/junit4/javadoc/4.12/org/junit/rules/TestRule.html) subclasses. + +The classic implementation of Testify uses `ScreenshotTestRule`. While starting in Testify 2.1.0, you have access to the newer `ScreenshotScenarioRule`. Both rules provide similar functionality. + +## ScreenshotScenarioRule + +As [ActivityTestRule is deprecated](https://developer.android.com/reference/androidx/test/rule/ActivityTestRule), the Android SDK now recommends the usage of [`ActivityScenario`](https://developer.android.com/reference/androidx/test/core/app/ActivityScenario) as the modern alternative. Testify provides `ScreenshotScenarioRule` which works in conjunction with `ActivityScenario` to easily add screenshot tests to scenario-based UI tests. + +`ScreenshotScenarioRule` is more flexible than the older `ScreenshotTestRule` as it no longer requires you to couple the rule's instantiatiation with a specific Activity subclass. This allows the flexibility of testing multiple different activities in the same test class. + +Screenshot test integration with `ActivityScenario` is achieved via the `withScenario()` function. An active instance of a scenario must be provided to Testify prior to calling `assertSame()`. Typically, this is done by passing the scaneario instance returned by [`ActivityScenario.launch`](https://developer.android.com/reference/androidx/test/core/app/ActivityScenario#launch(java.lang.Class%3CA%3E)) to the `ScreenshotScenarioRule` instance within a `use {}` block. + +:::tip + +To enable [Android Studio Plugin](set-up-intellij-plugin) integration with your tests, each test method should be annotated with the `@ScreenshotInstrumentation` annotation. + +::: + +```kotlin +import androidx.test.core.app.launchActivity +import dev.testify.MainActivity +import dev.testify.annotation.ScreenshotInstrumentation +import org.junit.Rule +import org.junit.Test + +class MainActivityScreenshotTest { + + @get:Rule val rule = ScreenshotScenarioRule() + + @ScreenshotInstrumentation + @Test + fun default() { + launchActivity().use { scenario -> + screenshotRule.withScenario(scenario).assertSame() + } + } +} +``` + +## ScreenshotTestRule + +:::caution + +[ActivityTestRule is deprecated](https://developer.android.com/reference/androidx/test/rule/ActivityTestRule) + +Use **androidx.test.core.app.ActivityScenario** instead with [**ScreenshotScenarioRule**](#screenshotscenariorule). + +::: + + +`ScreenshotTestRule` is a subclass of Android's [`ActivityTestRule`](https://developer.android.com/reference/androidx/test/rule/ActivityTestRule.html). The testing framework launches the activity under test before each test method annotated with [`@Test`](https://junit.org/junit4/javadoc/latest/org/junit/Test.html) and before any method annotated with [`@Before`](http://junit.sourceforge.net/javadoc/org/junit/Before.html). Each screenshot test method must be annotated with the `@ScreenshotInstrumentation` annotation. @@ -10,7 +60,7 @@ Within your test method, you can configure the `Activity` as needed and call `as @RunWith(AndroidJUnit4::class) class MainActivityScreenshotTest { - @get:Rule var rule = ScreenshotRule(MainActivity::class.java) + @get:Rule val rule = ScreenshotRule(MainActivity::class.java) @ScreenshotInstrumentation @Test @@ -20,3 +70,9 @@ class MainActivityScreenshotTest { } ``` +## Jetpack Compose + +Using Jetpack Compose in your application? Check out the [Jetpack Compose Extension for Android Testify](../category/jetpack-compose) + +--- + diff --git a/docs/docs/get-started/5-update-baseline.md b/docs/docs/get-started/5-update-baseline.md index acb56609..949b25c0 100644 --- a/docs/docs/get-started/5-update-baseline.md +++ b/docs/docs/get-started/5-update-baseline.md @@ -6,8 +6,8 @@ Testify works by referencing a PNG baseline found in your `androidTest/assets` d Run all the screenshot tests in your app and update the local baseline. -```bash -./gradlew screenshotRecord +```shell-session +$ ./gradlew app:screenshotRecord ``` ## Pull images from the device @@ -15,8 +15,8 @@ Run all the screenshot tests in your app and update the local baseline. Copy images from the `app_images` directory on your emulator to your local `androidTest/assets` directory. -```bash -./gradlew screenshotPull +```shell-session +$ ./gradlew app:screenshotPull ``` ## Record a new baseline using Testify settings @@ -27,7 +27,7 @@ instruct Testify to generate new baselines. There are two options. ### Enable record mode in Testify settings -Just set `recordMode = true` in the `testify` block inside `build.gradle` file: +To enable record mode, you can also set `recordMode = true` in the `testify` block inside your `build.gradle` file: ```groovy testify { @@ -47,5 +47,5 @@ val screenshotRule = ScreenshotRule(ClientListActivity::class.java) screenshotRule.setRecordModeEnabled(true) ``` -With `ScreenshotRule` record mode could be enabled only for specific test and disabled for all +With `ScreenshotRule` record mode can be enabled only for a specific test and disabled for all others. \ No newline at end of file diff --git a/docs/docs/get-started/6-verify-tests.md b/docs/docs/get-started/6-verify-tests.md index e9564dcb..aef2bfd3 100644 --- a/docs/docs/get-started/6-verify-tests.md +++ b/docs/docs/get-started/6-verify-tests.md @@ -1,7 +1,146 @@ # Verify the tests -Run all the screenshot tests in your app and fail if any differences from the baseline are detected. +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; -```bash -./gradlew screenshotTest +export const Swatch = ({children, color}) => ( + + {children} + +); + +You can use Android Studio's built-in test runner to run your tests. Or, you can invoke the gradle task `screenshotTest` to run all the screenshot tests in your app. The test will fail if any differences from the baseline are detected. + +```shell-session +$ ./gradlew app:screenshotTest +``` + +## Test failures + +By default, Testify will use a strict binary comparison. This means that any difference in the binary value used for any of the pixels will be considered a failure. You may wish to adjust the matching tolerance through the use of the `exactness` tolerance. A value of less than `1.0f` will result in a more leniant comparison which will exclude visually similar pixels. For more information on Testify's tolerance implementation, please read the blog post [_Accounting for platform differences_](../../blog/platform-differences). + +### Tolerance + +To adjust the tolerance, configure the `exactness` value on the rule or you can use the `@BitmapComparisonExactness`. + + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun setExactness() { + rule + .configure { exactness = 0.95f } + .assertSame() +} +``` + + + + +```kotlin +import dev.testify.annotation.BitmapComparisonExactness + +@ScreenshotInstrumentation +@BitmapComparisonExactness(exactness = 0.95f) +@Test +fun setExactness() { + rule.assertSame() +} +``` + + + + +### Exclusions + +In addition to adjusting the tolerance, you can also exclude certain parts of the screen from comparion. You can define _exclusion rects_ which Testify will ignore when comparing images. + +```kotlin +@ScreenshotInstrumentation +@Test +fun exclusions() { + rule + .configure { + defineExclusionRects { rootView, exclusionRects -> + val card = rootView.findViewById(R.id.info_card) + exclusionRects.add(card.boundingBox) + } + } + .assertSame() +} +``` + +## Diagnosing Differences + +When a test fails, it can sometimes be difficult to determine the cause. You can enable the _GenerateDiffs_ feature which will write a companion image for your screenshot test which can help you more easily identify which areas of your test have triggered the screenshot failure. + +The generated file will be created in the same directory as your baseline images. Diff files can be pulled from the device using `./gradlew app:screenshotPull`. + +-       Black pixels are identical between the baseline and test image +-       Grey pixels have been excluded from the comparison +-       Yellow pixels are different, but within the Exactness threshold +-       Red pixels are different + +This feature can be enabled by adding the `testify-generate-diffs` tag to the `AndroidManifest.xml` file in your `androidTest` target: + +```xml + + + + + + +``` + +Alternatively, you can enable/disable diffs programmatically: + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun generateDiffs() { + TestifyFeatures.GenerateDiffs.setEnabled(true) + rule.assertSame() +} ``` + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun generateDiffs() { + rule + .withExperimentalFeatureEnabled(TestifyFeatures.GenerateDiffs) + .assertSame() +} +``` + + + + + +## Additional Testing Scenarios + +For additional examples and advanced testing scenarios, please check out [Testify Recipes](../category/recipes). + +Testify is built on top of [Android Instrumented Tests](https://developer.android.com/training/testing/instrumented-tests) and so you can also you any of Android's built-in instrumentation test running mechanisms to verify your tests. + +You can: + +- [Test from Android Studio](https://developer.android.com/studio/test) +- [Test from the command line](https://developer.android.com/studio/test/command-line) diff --git a/docs/docs/get-started/8-use-gradle-plugin.md b/docs/docs/get-started/8-use-gradle-plugin.md index d81cda84..b0f7224c 100644 --- a/docs/docs/get-started/8-use-gradle-plugin.md +++ b/docs/docs/get-started/8-use-gradle-plugin.md @@ -10,48 +10,64 @@ Applying the Testify Gradle Plugin to your projects automatically configures and Testify supports the following configuration options: -#### autoImplementLibrary - Automatically add the `dev.testify:testify` dependency to your `androidTest` configuration. Defaults to `true`. +
+
autoImplementLibrary
+
+ Automatically add the dev.testify:testify dependency to your androidTest configuration. Defaults to true +
+
baselineSourceDir
-#### baselineSourceDir - The directory on the client host machine that contain the original baseline images under version control. This value defaults to the `src/androidTest/assets` directory. +
The directory on the client host machine that contain the original baseline images under version control. This value defaults to the src/androidTest/assets directory.
-#### installAndroidTestTask - The Gradle task used to install the Android Test APK. In most cases, this value is automatically inferred from the project configuration and is typically `installDebugAndroidTest`. +
installAndroidTestTask
-#### installTask - The Gradle task used to install the Application Under Test APK. In most cases, this value is automatically inferred from the project configuration and is typically `installDebug`. +
The Gradle task used to install the Android Test APK. In most cases, this value is automatically inferred from the project configuration and is typically installDebugAndroidTest.
-#### isRecordMode - Indicates that screenshotTest/screenshotRecord should never fail and always record new baseline images. Default is `false`. +
installTask
-#### moduleName - The name of the module under test. This value is inferred automatically and should not normally be modified by the user. +
The Gradle task used to install the Application Under Test APK. In most cases, this value is automatically inferred from the project configuration and is typically installDebug.
-#### pullWaitTime - The length of time to sleep in milliseconds after pulling files from the device. Used to allow time for the local file system to complete write operations. Defaults to 0. +
isRecordMode
-#### rootDestinationDirectory - The root directory containing the screenshots on the test device. Used when pulling files from the device. This value is automatically set. +
Indicates that screenshotTest/screenshotRecord should never fail and always record new baseline images. Default is false.
-#### screenshotAnnotation - The annotation used by ScreenshotTestTask as an argument to `adb shell am instrument` to filter tests being run. See https://developer.android.com/studio/test/command-line#run-tests-with-adb. Defaults to `dev.testify.annotation.ScreenshotInstrumentation` +
moduleName
-#### targetPackageId - The package ID for the APK under test. For a typical application, testify requires two APKs: the target apk under test, and a test apk containing your tests. e.g. `com.testify.example` +
The name of the module under test. This value is inferred automatically and should not normally be modified by the user.
-#### testPackageId - The package ID for the test APK. For a typical application, testify requires two APKs: the target apk under test, and a test apk containing your tests. e.g. `com.testify.example.test` +
pullWaitTime
-#### testRunner - The AndroidJUnitRunner to use when running your instrumented tests. In most cases, this is inferred from your project configuration automatically and is typically `androidx.test.runner.AndroidJUnitRunner`. See https://developer.android.com/training/testing/instrumented-tests#set-testing +
The length of time to sleep in milliseconds after pulling files from the device. Used to allow time for the local file system to complete write operations. Defaults to 0.
-#### useSdCard - Instructs Testify to write screenshots to the SDCARD directory. See https://ndtp.github.io/android-testify/docs/recipes/sdcard#configuring-the-gradle-plugin-to-write-to-the-sdcard. Defaults to false. +
rootDestinationDirectory
-#### useTestStorage - Instructs Testify to save screenshots to the Test Storage. See https://developer.android.com/reference/androidx/test/services/storage/TestStorage. Defaults to false. +
The root directory containing the screenshots on the test device. Used when pulling files from the device. This value is automatically set.
+
screenshotAnnotation
+ +
The annotation used by ScreenshotTestTask as an argument to adb shell am instrument to filter tests being run. See https://developer.android.com/studio/test/command-line#run-tests-with-adb. Defaults to dev.testify.annotation.ScreenshotInstrumentation
+ +
targetPackageId
+ +
The package ID for the APK under test. For a typical application, testify requires two APKs: the target apk under test, and a test apk containing your tests. e.g. com.testify.example
+ +
testPackageId
+ +
The package ID for the test APK. For a typical application, testify requires two APKs: the target apk under test, and a test apk containing your tests. e.g. com.testify.example.test
+ +
testRunner
+ +
The AndroidJUnitRunner to use when running your instrumented tests. In most cases, this is inferred from your project configuration automatically and is typically androidx.test.runner.AndroidJUnitRunner. See https://developer.android.com/training/testing/instrumented-tests#set-testing
+ +
useSdCard
+ +
Instructs Testify to write screenshots to the SDCARD directory. See https://ndtp.github.io/android-testify/docs/recipes/sdcard#configuring-the-gradle-plugin-to-write-to-the-sdcard. Defaults to false.
+ +
useTestStorage
+ +
Instructs Testify to save screenshots to the Test Storage. See https://developer.android.com/reference/androidx/test/services/storage/TestStorage. Defaults to false.
+ +
### Command-line properties @@ -60,52 +76,66 @@ They can be set from the command line using the `-P` / `--project-prop` environm See https://docs.gradle.org/current/userguide/project_properties.html -#### device +
+
device
-Index of the Testify Device to target for the command. Use `./gradlew testifyDevices` to see a list of eligible devices. +
Index of the Testify Device to target for the command. Use ./gradlew testifyDevices to see a list of eligible devices.
-#### reportFileName +
reportFileName
-Override the default file name used locally when copying the file. +
Override the default file name used locally when copying the file.
-#### reportPath +
reportPath
-Override the default path to copy the report file to. +
Override the default path to copy the report file to.
-#### shardCount, shardIndex +
shardCount, shardIndex
+
+ If you need to parallelize the execution of your tests, sharing them across multiple devices to make them run faster, you can split them into groups, or shards. The test runner supports splitting a single test suite into multiple shards, so you can easily run tests belonging to the same shard together as a group. Each shard is identified by an index number. + When running tests, use the -PshardCount option to specify the number of separate shards to create and the -PshardIndex option to specify which shard to run. -**shardCount** specifies the total number of shards into which the test suite is divided; **shardIndex** identifies the specific shard to be executed, with an index ranging from 0 to `shardCount` - 1. +
+
shardCount
+
Specifies the total number of shards into which the test suite is divided
+
shardIndex
+
Identifies the specific shard to be executed, with an index ranging from 0 to `shardCount` - 1.
+
+
-If you need to parallelize the execution of your tests, sharing them across multiple devices to make them run faster, you can split them into groups, or shards. The test runner supports splitting a single test suite into multiple shards, so you can easily run tests belonging to the same shard together as a group. Each shard is identified by an index number. -When running tests, use the `-PshardCount` option to specify the number of separate shards to create and the `-PshardIndex` option to specify which shard to run. +
testClass
-#### testClass +
+Run all tests in the specified class. Class name should be fully qualified. -Run all tests in the specified class. Class name should be fully qualified. + ```shell-session -```console + ./gradlew FlixSample:screenshotTest -PtestClass=dev.testify.samples.flix.ui.common.composables.CreditStripScreenshotTest -./gradlew FlixSample:screenshotTest -PtestClass=dev.testify.samples.flix.ui.common.composables.CreditStripScreenshotTest + ``` -``` +
-#### testName +
testName
-Run the specific test case. Must be used in conjunction with `testClass`. +
+ Run the specific test case. Must be used in conjunction with testClass. -```console + ```shell-session -./gradlew FlixSample:screenshotTest -PtestName=longCreditStrip -PtestClass=dev.testify.samples.flix.ui.common.composables.CreditStripScreenshotTest + ./gradlew FlixSample:screenshotTest -PtestName=longCreditStrip -PtestClass=dev.testify.samples.flix.ui.common.composables.CreditStripScreenshotTest -``` + ``` +
-#### user +
user
-Specify the user ID for multi-user testing. See https://source.android.com/docs/devices/admin/multi-user-testing +
Specify the user ID for multi-user testing. See https://source.android.com/docs/devices/admin/multi-user-testing
-#### verbose +
verbose
-Print verbose console output. Useful for debugging purposes. +
Print verbose console output. Useful for debugging purposes.
+ +
## Core Tasks @@ -114,8 +144,8 @@ Print verbose console output. Useful for debugging purposes. Run all the screenshot tests in your app and fail if any differences from the baseline are detected. -```console -~/: ./gradlew FlixSample:screenshotTest +```shell-session +$ ./gradlew FlixSample:screenshotTest > Task :FlixSample:deviceLocale @@ -196,8 +226,8 @@ BUILD SUCCESSFUL in 13s Run all the screenshot tests in your app and update the local baseline. -```console -~/: ./gradlew FlixSample:screenshotRecord +```shell-session +$ ./gradlew FlixSample:screenshotRecord > Task :FlixSample:deviceLocale @@ -257,50 +287,49 @@ Remove any existing screenshot test images from the device dev.testify.samples.flix.ComposableScreenshotTest: ✓ Recording baseline for ComposableScreenshotTest_default. + dev.testify.samples.flix.ui.common.composables.CastMemberScreenshotTest: ✓ Recording baseline for CastMemberScreenshotTest_default. + dev.testify.samples.flix.ui.common.composables.CreditStripScreenshotTest: ✓ Recording baseline for CreditStripScreenshotTest_longCreditStrip. - ✓ Recording baseline for CreditStripScreenshotTest_emptyCreditStrip. - ✓ Recording baseline for CreditStripScreenshotTest_default. + dev.testify.samples.flix.ui.common.composables.GenreStripScreenshotTest: ✓ Recording baseline for GenreStripScreenshotTest_lotsOfGenres. - ✓ Recording baseline for GenreStripScreenshotTest_default. + dev.testify.samples.flix.ui.common.composables.MetaDataScreenshotTest: ✓ Recording baseline for MetaDataScreenshotTest_onlyCertification. - ✓ Recording baseline for MetaDataScreenshotTest_onlyReleaseDate. - ✓ Recording baseline for MetaDataScreenshotTest_onlyRuntime. - ✓ Recording baseline for MetaDataScreenshotTest_default. + dev.testify.samples.flix.ui.common.composables.MoviePosterScreenshotTest: ✓ Recording baseline for MoviePosterScreenshotTest_default. - ✓ Recording baseline for MoviePosterScreenshotTest_nullPosterUrlImpliesLoading. + dev.testify.samples.flix.ui.common.composables.OverviewTextScreenshotTest: ✓ Recording baseline for OverviewTextScreenshotTest_longText. - ✓ Recording baseline for OverviewTextScreenshotTest_default. + dev.testify.samples.flix.ui.common.composables.PrimaryTitleScreenshotTest: ✓ Recording baseline for PrimaryTitleScreenshotTest_longText. - ✓ Recording baseline for PrimaryTitleScreenshotTest_default. + dev.testify.samples.flix.ui.common.composables.SecondaryTitleScreenshotTest: ✓ Recording baseline for SecondaryTitleScreenshotTest_longText. - ✓ Recording baseline for SecondaryTitleScreenshotTest_default. + dev.testify.samples.flix.ui.moviedetails.MovieDetailsScreenshotTest: ✓ Recording baseline for MovieDetailsScreenshotTest_default. @@ -309,8 +338,6 @@ Time: 7.65 OK (20 tests) - - > Task :FlixSample:screenshotPull ------------------------------------------------------------ @@ -367,8 +394,8 @@ BUILD SUCCESSFUL in 20s Copy images from the remote directory on your emulator to your local `androidTest/assets` directory. -```console -~/: ./gradlew FlixSample:screenshotPull +```shell-session +$ ./gradlew FlixSample:screenshotPull > Task :FlixSample:screenshotPull @@ -420,8 +447,8 @@ BUILD SUCCESSFUL in 4s Clear any baseline images that may be remaining on your emulator. -```console -~/: ./gradlew FlixSample:screenshotClear +```shell-session +$ ./gradlew FlixSample:screenshotClear > Task :FlixSample:screenshotClear @@ -474,7 +501,7 @@ You can customize the destination path and file name for the report file by prov Example: -```console +```shell-session ./gradlew FlixSample:reportPull -PreportPath="/user/testify/" -PreportFileName="my-report.yml" ``` @@ -482,8 +509,8 @@ Example: Print the test result report to the console. -```console -~/: ./gradlew FlixSample:reportShow +```shell-session +$ ./gradlew FlixSample:reportShow > Task :FlixSample:reportShow @@ -514,8 +541,8 @@ Print the test result report to the console Displays the locale currently set on the device -```console -~/: ./gradlew FlixSample:deviceLocale +```shell-session +$ ./gradlew FlixSample:deviceLocale > Task :FlixSample:deviceLocale ------------------------------------------------------------ @@ -528,8 +555,8 @@ Displays the locale currently set on the device Displays the time zone currently set on the device. -```console -~/: ./gradlew FlixSample:deviceTimeZone +```shell-session +$ ./gradlew FlixSample:deviceTimeZone > Task :FlixSample:deviceTimeZone ------------------------------------------------------------ @@ -542,8 +569,8 @@ Displays the time zone currently set on the device Disables the soft keyboard on the device. The soft keyboard can interfere with your screenshots, so it's good to turn it off. -```console -~/: ./gradlew FlixSample:disableSoftKeyboard +```shell-session +$ ./gradlew FlixSample:disableSoftKeyboard > Task :FlixSample:disableSoftKeyboard ------------------------------------------------------------ @@ -557,8 +584,8 @@ Disables the soft keyboard on the device Hides passwords fully on the device. -```console -~/: ./gradlew FlixSample:hidePasswords +```shell-session +$ ./gradlew FlixSample:hidePasswords > Task :FlixSample:hidePasswords ------------------------------------------------------------ @@ -571,8 +598,8 @@ Hides passwords fully on the device Displays the connected devices. -```console -~/: ./gradlew FlixSample:testifyDevices +```shell-session +$ ./gradlew FlixSample:testifyDevices > Task :FlixSample:testifyDevices ------------------------------------------------------------ @@ -589,8 +616,8 @@ Displays Testify devices Displays the Testify output key for the current device. Testify uses the key as the baseline for the given device. -```console -~/: ./gradlew FlixSample:testifyKey +```shell-session +$ ./gradlew FlixSample:testifyKey > Task :FlixSample:testifyKey ------------------------------------------------------------ @@ -604,8 +631,8 @@ Displays the Testify output key for the current device Testify infers several project properties. You can view these properties with the `testifySettings` command. -```console -~/: ./gradlew FlixSample:testifySettings +```shell-session +$ ./gradlew FlixSample:testifySettings > Task :FlixSample:testifySettings @@ -644,8 +671,8 @@ BUILD SUCCESSFUL in 845ms Displays the Testify plugin version -```console -~/: ./gradlew FlixSample:testifyVersion +```shell-session +$ ./gradlew FlixSample:testifyVersion > Task :FlixSample:testifyVersion ------------------------------------------------------------ diff --git a/docs/docs/recipes/1-view-provider.md b/docs/docs/recipes/1-view-provider.md index 9a189a7a..62541aed 100644 --- a/docs/docs/recipes/1-view-provider.md +++ b/docs/docs/recipes/1-view-provider.md @@ -1,19 +1,48 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Taking a screenshot of an area less than that of the entire Activity It is often desirable to capture only a portion of your screen or to capture a single `View`. -For these cases, you can use the `setScreenshotViewProvider` on `ScreenshotRule` to specify which `View` to capture. +For these cases, you can use the `setScreenshotViewProvider` to specify which `View` to capture. + +Using `setScreenshotViewProvider`, you must return a `View` reference which will be used by Testify to narrow the bitmap to only that View. -Using `ScreenshotRule.setScreenshotViewProvider`, you must return a `View` reference which will be used by Testify to narrow the bitmap to only that View. + + ```kotlin - @TestifyLayout(R.layout.view_client_details) - @ScreenshotInstrumentation - @Test - fun default() { +@TestifyLayout(R.layout.view_client_details) +@ScreenshotInstrumentation +@Test +fun default() { + rule + .setScreenshotViewProvider { + it.findViewById(R.id.info_card) + } + .assertSame() +} +``` + + + + +```kotlin +@TestifyLayout(R.layout.view_client_details) +@ScreenshotInstrumentation +@Test +fun default() { + launchActivity().use { scenario -> rule + .withScenario(scenario) .setScreenshotViewProvider { it.findViewById(R.id.info_card) } .assertSame() } -``` \ No newline at end of file +} +``` + + + + diff --git a/docs/docs/recipes/10-orientation.md b/docs/docs/recipes/10-orientation.md index a2055439..e649e656 100644 --- a/docs/docs/recipes/10-orientation.md +++ b/docs/docs/recipes/10-orientation.md @@ -1,14 +1,45 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Changing the orientation of the screen -Use the `setOrientation` method to select between portrait and landscape mode. +Use the `orientation` configuration to select between portrait and landscape mode. +Testify will use the orientation of the screen as the key for the baseline images. For example, the baseline images for portrait screenshots taken on a Pixel 3a device will be written to the `29-1080x2220@440dp-en_US` directory, while a landscape screenshot taken on the same device will be written to `29-2220x1080@440dp-en_US`. + + + ```kotlin - @TestifyLayout(R.layout.view_client_details) - @ScreenshotInstrumentation - @Test - fun setOrientation() { +@TestifyLayout(R.layout.view_client_details) +@ScreenshotInstrumentation +@Test +fun setOrientation() { + rule + .configure { + orientation = SCREEN_ORIENTATION_LANDSCAPE + } + .assertSame() +} +``` + + + + +```kotlin +@TestifyLayout(R.layout.view_client_details) +@ScreenshotInstrumentation +@Test +fun setOrientation() { + launchActivity().use { scenario -> rule - .setOrientation(requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE) + .withScenario(scenario) + .configure { + orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } .assertSame() } +} ``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/11-layout-inspector.md b/docs/docs/recipes/11-layout-inspector.md index 69f4034c..7192168c 100644 --- a/docs/docs/recipes/11-layout-inspector.md +++ b/docs/docs/recipes/11-layout-inspector.md @@ -1,13 +1,45 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OpenNew from '@site/static/img/open_new.svg'; + # Debugging with the Layout Inspector -You may use Android Studio's [Layout Inspector](https://developer.android.com/studio/debug/layout-inspector) in conjunction with your screenshot test. It can sometimes be useful to pause your test so that you can capture the layout hierarchy for further debugging in Android Studio. In order to do so, invoke the `setLayoutInspectionModeEnabled` method on the test rule. This will pause the test after all ViewModifications have been applied and prior to the screenshot being taken. The test is paused for 5 minutes, allowing plenty of time to capture the layout. +You may use Android Studio's [Layout Inspector ](https://developer.android.com/studio/debug/layout-inspector) in conjunction with your screenshot test. It can sometimes be useful to pause your test so that you can capture the layout hierarchy for further debugging in Android Studio. In order to do so, set the `pauseForInspection` configuration property on the test rule to true. This will pause the test after all ViewModifications have been applied and prior to the screenshot being taken. The test is paused for 5 minutes, allowing plenty of time to capture the layout. + +:::danger +**This property is intended for debugging and diagnosis only.** + +Do not enable this permanently on your tests as it will dramatically increase your test runtime. +::: + + + ```kotlin - @ScreenshotInstrumentation - @Test - fun testDefault() { +@ScreenshotInstrumentation +@Test +fun testDefault() { + rule + .configure { pauseForInspection = true } + .assertSame() +} +``` + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun testDefault() { + launchActivity().use { scenario -> rule - .setLayoutInspectionModeEnabled(true) - .assertSame() + .withScenario(scenario) + .configure { pauseForInspection = true } + .assertSame() } +} ``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/12-capture-method.md b/docs/docs/recipes/12-capture-method.md index 369c0cd1..b537dc5d 100644 --- a/docs/docs/recipes/12-capture-method.md +++ b/docs/docs/recipes/12-capture-method.md @@ -1,30 +1,99 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OpenNew from '@site/static/img/open_new.svg'; + # Selecting an alternative capture method -Testify provides three bitmap capture method. Each method will capture slightly different results based primarily on API level. +Testify provides three built-in bitmap capture methods. Each method will capture slightly different results based primarily on API level. In addition, a [Fullscreen Capture Method](../category/fullscreen-capture-method) is provided as an optional extension. + +The three standard capture methods available are: -The three capture methods available are: +1. **DrawingCache**: Pulls the view's drawing cache bitmap using the deprecated [View.getDrawingCache ](https://developer.android.com/reference/android/view/View#getDrawingCache()) (deprecated in API level 28). +2. **Canvas**: Render the view (and all of its children) to a given Canvas, using [View.draw ](https://developer.android.com/reference/android/view/View#draw(android.graphics.Canvas)) +3. **PixelCopy**: Use Android's recommended [PixelCopy ](https://developer.android.com/reference/android/view/PixelCopy) API to capture the full screen, including elevation. -(1) Canvas: Render the view (and all of its children) to a given Canvas, using [View.draw](https://developer.android.com/reference/android/view/View#draw(android.graphics.Canvas)) -(2) DrawingCache: Pulls the view's drawing cache bitmap using the deprecated [View.getDrawingCache](https://developer.android.com/reference/android/view/View#getDrawingCache()) -(3) PixelCopy: Use Android's recommended [PixelCopy](https://developer.android.com/reference/android/view/PixelCopy) API to capture the full screen, including elevation. +:::caution For legacy compatibility reasons, `DrawingCache` mode is the default Testify capture method. +The default will change to `PixelCopy` in a future release. + +::: + +In addition, capture methods are extensible. -If you wish to select an alternative capture method, you can enable the experimental feature either in code, or in your manifest. -Available features can be found in [TestifyFeatures](https://github.com/ndtp/android-testify/blob/230607acc598afe7d54f9618d55fdecd0da83800/Library/src/main/java/dev/testify/TestifyFeatures.kt#L30) +4. **Fullscreen**: The Testify [Fullscreen Capture Method](../category/fullscreen-capture-method) can be used to capture UI elements presented outside of your root view. This includes elements rendered in a different Window such as dialogs, alerts, notifications, or overlays. + +## Code Configuration + +To configure a custom capture method, provide a function that conforms to the `CaptureMethod` signature. A `CaptureMethod` returns a [`Bitmap` ](https://developer.android.com/reference/android/graphics/Bitmap) from the provided [`Activity`](https://developer.android.com/reference/android/app/Activity) and [`View`](https://developer.android.com/reference/android/view/View). -**Code:** ```kotlin - @ScreenshotInstrumentation - @Test - fun testDefault() { +typealias CaptureMethod = (activity: Activity, targetView: View?) -> Bitmap? +```` + +:::tip + +See [_Customizing the captured bitmap_](custom-bitmap) for an example of how to provide your own `CaptureMethod`. + +::: + +Or, you can specify one of the provided methods from the `dev.testify.core.processor.capture` package: + +- `::canvasCapture`: Canvas +- `::createBitmapFromDrawingCache`: DrawingCache +- `::pixelCopyCapture`: PixelCopy + + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun testDefault() { + rule + .configure { + captureMethod = ::canvasCapture + } + .assertSame() +} +``` + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun testDefault() { + launchActivity().use { scenario -> rule - .withExperimentalFeatureEnabled(TestifyFeatures.CanvasCapture) + .withScenario(scenario) + .configure { + captureMethod = ::canvasCapture + } .assertSame() } +} ``` -**Manifest:** + + + +## Manifest Configuration + +:::danger + +**testify-pixelcopy-capture** and **testify-canvas-capture** are deprecated and will be removed in a future version. + +::: + +Alternatively, you can also select an alternative capture method in your manifest. + +- **testify-pixelcopy-capture**: PixelCopy capture method +- **testify-canvas-capture**: Canvas capture method + + ```xml diff --git a/docs/docs/recipes/13-software-rendering.md b/docs/docs/recipes/13-software-rendering.md index 76681f59..f0637613 100644 --- a/docs/docs/recipes/13-software-rendering.md +++ b/docs/docs/recipes/13-software-rendering.md @@ -1,15 +1,48 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Force software rendering In some instances it may be desirable to use the software renderer, not Android's default hardware renderer. Differences in GPU hardware from device to device (and emulators running on different architectures) may cause flakiness in rendering. Please read more about [Hardware acceleration](https://developer.android.com/guide/topics/graphics/hardware-accel.html) for more information. +:::caution +**Software rendering is not recommended.** + +The software rendering pipeline on Android does not produce the same results as the default hardware rendering and can omit shadows, elevation and other advanced features. If you're having difficulty with flaky or inconsistent rendering, it is recommended that you consider the options presented in [Accounting for platform differences](../../blog/platform-differences). +::: + + + + ```kotlin - @ScreenshotInstrumentation - @Test - fun default() { +@ScreenshotInstrumentation +@Test +fun default() { + rule + .setUseSoftwareRenderer(true) + .assertSame() +} +``` + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun default() { + launchActivity().use { scenario -> rule - .setUseSoftwareRenderer(true) + .withScenario(scenario) + .configure { + useSoftwareRenderer = true + } .assertSame() } +} ``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/14-exclude-regions.md b/docs/docs/recipes/14-exclude-regions.md index c881da6f..9949f6d8 100644 --- a/docs/docs/recipes/14-exclude-regions.md +++ b/docs/docs/recipes/14-exclude-regions.md @@ -1,20 +1,54 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Excluding a region from the comparison -For some Views, it may be impossible to guarantee a stable, consistent rendering. For instance, if the content is dynamic or randomized. -For this reason, Testify provides the option to specify a series of rectangles to exclude from the comparison. -All pixels in these rectangles are ignored and only pixels not contained will be compared. +For some Views, it may be impossible to guarantee a stable, consistent rendering. For instance, if the content is dynamic or randomized. For this reason, Testify provides the option to specify a series of rectangles to exclude from the comparison. All pixels in these rectangles are ignored and only pixels not contained will be compared. + +:::caution + +This comparison mechanism is slower than the default. -Note that this comparison mechanism is slower than the default. +::: + + + ```kotlin - @ScreenshotInstrumentation - @Test - fun default() { - rule - .defineExclusionRects { rootView, exclusionRects -> +@ScreenshotInstrumentation +@Test +fun default() { + rule + .configure { + defineExclusionRects { rootView, exclusionRects -> val card = rootView.findViewById(R.id.info_card) exclusionRects.add(card.boundingBox) } + } + .assertSame() +} +``` + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun default() { + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .configure { + defineExclusionRects { rootView, exclusionRects -> + val card = rootView.findViewById(R.id.info_card) + exclusionRects.add(card.boundingBox) + } + } .assertSame() } +} ``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/15-keyboard-focus.md b/docs/docs/recipes/15-keyboard-focus.md index 8b74d2e4..3001d819 100644 --- a/docs/docs/recipes/15-keyboard-focus.md +++ b/docs/docs/recipes/15-keyboard-focus.md @@ -1,16 +1,48 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OpenNew from '@site/static/img/open_new.svg'; + # Placing the keyboard focus on a specific view -It's possible that users can navigate your app using a keyboard, because the Android system enables most of the necessary behaviors by default. -In order to place the keyboard focus on a specific View, use the `setFocusTarget` method. +As users can navigate your app using a keyboard (by pressing the `TAB` key, for example), it may be desirable to place the keyboard focus on a specific `View` prior to taking a screenshot. + +See [_Support keyboard navigation_ ](https://developer.android.com/training/keyboard-input/navigation) for more information about keyboard navigation on Android. + +In order to place the keyboard focus on a specific `View`, configure the `focusTargetId` property. -See https://developer.android.com/training/keyboard-input/navigation + + + ```kotlin - @ScreenshotInstrumentation - @Test - fun default() { +@ScreenshotInstrumentation +@Test +fun default() { + rule + .configure { + focusTargetId = R.id.fab + } + .assertSame() +} +``` + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun default() { + launchActivity().use { scenario -> rule - .setFocusTarget(enabled = true, focusTargetId = R.id.fab) + .withScenario(scenario) + .configure { + focusTargetId = R.id.fab + } .assertSame() } +} ``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/16-custom-bitmap.md b/docs/docs/recipes/16-custom-bitmap.md index 7973b12e..3c691715 100644 --- a/docs/docs/recipes/16-custom-bitmap.md +++ b/docs/docs/recipes/16-custom-bitmap.md @@ -1,18 +1,88 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OpenNew from '@site/static/img/open_new.svg'; + # Customizing the captured bitmap -Testify provides the `setCaptureMethod()` on `ScreenshotRule` which can be used to override the default mechanism for creating a bitmap -from the Activity under test. You can use `setCaptureMethod()` to provide your own implementation of `CaptureMethod`. The only requirement -for `CaptureMethod` is that you return an `android.graphics.Bitmap` instance. You can use any method you want to create a bitmap. You can -also use the provided `ScreenshotUtility` to capture a bitmap and then modify it to your liking. +In some instances, it may be useful to modify or customize the captured Bitmap. For example, you may wish to annotate the screenshot with certain diagnostic information, print the name of the test, or add a watermark. + +You can leverage the `TestifyConfiguration.captureMethod` configuration function property for this purpose. + +To configure a custom capture method, provide a function that conforms to the `CaptureMethod` signature. A `CaptureMethod` returns a [`Bitmap` ](https://developer.android.com/reference/android/graphics/Bitmap) from the provided [`Activity`](https://developer.android.com/reference/android/app/Activity) and [`View`](https://developer.android.com/reference/android/view/View). + +```kotlin +typealias CaptureMethod = (activity: Activity, targetView: View?) -> Bitmap? +```` + +:::tip + +Testify provides [3 built-in capture methods](capture-method) as well as a [Fullscreen capture method extension](../category/fullscreen-capture-method) which may provide the functionality you need without requiring you to write your own. + +::: + +Within the body of the `CaptureMethod`, you can use any mechanism you'd like to create or modify the `Bitmap`. The only requirement is that you return a valid `Bitmap`. Testify provides a variety of useful helper functions, classes and extension methods that you can use to build your own capture method. + +### Available *ScreenshotUtility* helper functions + +- **createBitmapFromActivity**: Capture a `Bitmap` from the given `Activity` and save it to the screenshots directory. +- **deleteBitmap**: Delete the `File` specified by `Destination`. +- **loadBaselineBitmapForComparison**: Load a baseline `Bitmap` from the androidTest assets directory. +- **loadBitmapFromFile**: Decode the file specified by a path into a `Bitmap`. +- **preferredBitmapOptions**: The default, preferred `BitmapFactory.Options` to use when decoding a `Bitmap`. +- **saveBitmapToDestination**: Write the given `Bitmap` to the `Destination` file. + +### Wordmark example + +In this example, we add the wordmark _Testify_ and the test name to the bottom of the captured image. We use the ScreenshotUtility function `createBitmapFromDrawingCache()` to capture a `Bitmap` from the provided activity. The, we wrap the `Bitmap` in a [`Canvas`](https://developer.android.com/reference/android/graphics/Canvas) and use the canvas' `drawText` method to render text on the bitmap. + +| | +|---| + + + ```kotlin @ScreenshotInstrumentation @Test fun captureMethodExample() { rule - .setCaptureMethod { activity, targetView -> + .configure { + captureMethod = { activity, targetView -> + /* Return a Bitmap */ + createBitmapFromDrawingCache(activity, targetView).apply { + /* Wrap the Bitmap in a Canvas so we can draw on it */ + Canvas(this).apply { + /* Add a wordmark to the captured image */ + val textPaint = Paint().apply { + color = Color.BLACK + textSize = 50f + isAntiAlias = true + } + this.drawText( + "<>", + 50f, + 2000f, + textPaint + ) + } + } + } + } + .assertSame() +} +``` + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun captureMethodExample() { + launchActivity().use { scenario -> + fun customCaptureMethod(activity: Activity, targetView: View?): Bitmap = /* Return a Bitmap */ - ScreenshotUtility().createBitmapFromView(activity, targetView).apply { + createBitmapFromDrawingCache(activity, targetView).apply { /* Wrap the Bitmap in a Canvas so we can draw on it */ Canvas(this).apply { /* Add a wordmark to the captured image */ @@ -21,10 +91,24 @@ fun captureMethodExample() { textSize = 50f isAntiAlias = true } - this.drawText("<>", 50f, 2000f, textPaint) + this.drawText( + "<>", + 50f, + 2000f, + textPaint + ) } } - } - .assertSame() + + rule + .withScenario(scenario) + .configure { + captureMethod = ::customCaptureMethod + } + .assertSame() + } } ``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/17-custom-capture.md b/docs/docs/recipes/17-custom-capture.md deleted file mode 100644 index fec04aa3..00000000 --- a/docs/docs/recipes/17-custom-capture.md +++ /dev/null @@ -1,23 +0,0 @@ -# Providing a custom comparison method - -You can customize the algorithm used to compare the captured bitmap against the baseline by using the `setCompareMethod()` on `ScreenshotRule`. - -`setCompareMethod()` is provided with the baseline and current bitmaps and expects a boolean result. If you return true, the bitmaps are -considered to be the same and the comparison succeeds. If you return false, the bitmaps are considered different and the comparison fails. - -You can use this to define a variety of custom comparison algorithms such as allowing a tolerance of excluding certain values from the comparison. - -```kotlin -@ScreenshotInstrumentation -@Test -fun ignoreDifferences() { - rule - .setViewModifications { - // Set background to a random color - val color = "#${Integer.toHexString(Random.nextInt(0, 16581375)).padStart(6, '0')}" - it.setBackgroundColor(Color.parseColor(color)) - } - .setCompareMethod { _, _ -> true } - .assertSame() -} -``` diff --git a/docs/docs/recipes/17-custom-compare.md b/docs/docs/recipes/17-custom-compare.md new file mode 100644 index 00000000..14ce6eab --- /dev/null +++ b/docs/docs/recipes/17-custom-compare.md @@ -0,0 +1,88 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Providing a custom comparison method + +There are many scenarios where + + + +You can leverage the `TestifyConfiguration.compareMethod` configuration function property for this purpose. + +To configure a custom capture method, provide a function that conforms to the `CompareMethod` signature. + +`CompareMethod` is called with the baseline and current bitmaps and expects a boolean result. If you return true, the bitmaps are considered to be the same and the comparison succeeds. If you return false, the bitmaps are considered different and the comparison fails. + +```kotlin +typealias CompareMethod = (baselineBitmap: Bitmap, currentBitmap: Bitmap) -> Boolean + +```` + +:::tip + +Before writing your own comparison method, consider that Testify provides multiple built-in mechanisms to customize the comparison of bitmaps. You can easily [_increase the matching tolerance_](tolerance) or [_exclude a region from the comparison_](exclude-regions). + +Please also see [_Accounting for platform differences_](../../blog/platform-differences) for more insight into handling unintended differences in your rendering. + +::: + + +You can customize the algorithm used to compare the captured bitmap against the baseline and use this to define a variety of custom comparison algorithms such as allowing a tolerance, or excluding certain values from the comparison. + +### Ignore differences example + +In this example, we build a very simple `ComporeMethod`, `ignoreDifferences()`, which will ignore all differences found in your images. + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun ignoreDifferences() { + + /** + * Define a simple comparison method that ignores all differences between the bitmaps by always returning true + */ + fun ignoreDifferences(baselineBitmap: Bitmap, currentBitmap: Bitmap) = true + + rule + .setViewModifications { + // Set background to a random color + val color = "#${Integer.toHexString(Random.nextInt(0, 16581375)).padStart(6, '0')}" + it.setBackgroundColor(Color.parseColor(color)) + } + .configure { compareMethod = ::ignoreDifferences } + .assertSame() +} +``` + + + + +```kotlin +@ScreenshotInstrumentation +@Test +fun ignoreDifferences() { + + /** + * Define a simple comparison method that ignores all differences between the bitmaps by always returning true + */ + fun ignoreDifferences(baselineBitmap: Bitmap, currentBitmap: Bitmap) = true + + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .setViewModifications { + // Set background to a random color + val color = "#${Integer.toHexString(Random.nextInt(0, 16581375)).padStart(6, '0')}" + it.setBackgroundColor(Color.parseColor(color)) + } + .configure { compareMethod = ::ignoreDifferences } + .assertSame() + } +} +``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/19-multi-user.md b/docs/docs/recipes/19-multi-user.md index 6b5d0543..2bafb430 100644 --- a/docs/docs/recipes/19-multi-user.md +++ b/docs/docs/recipes/19-multi-user.md @@ -7,7 +7,7 @@ Testify provides support for emulators running in multi-user configuration. ## Background -[This page ](https://source.android.com/docs/devices/admin/multi-user-testing) describes important aspects of testing multiple users on the Android platform. For information about implementing multi-user support, see [Supporting Multiple Users ](https://source.android.com/docs/devices/admin/multi-user). +[_Testing Multiple Users_ ](https://source.android.com/docs/devices/admin/multi-user-testing) describes important aspects of testing multiple users on the Android platform. For information about implementing multi-user support, see [_Supporting Multiple Users_ ](https://source.android.com/docs/devices/admin/multi-user). ## Automatic user selection @@ -19,9 +19,8 @@ Testify automatically reads and writes files to the currently running user. The You may optionally configure the Gradle Plugin to pull screenshots from a different user. You can override the user by specifying the `user=` argument. -``` -./gradlew app:screenshotPull -Puser=10 - +```shell-session +$ ./gradlew app:screenshotPull -Puser=10 ``` diff --git a/docs/docs/recipes/2-locale.md b/docs/docs/recipes/2-locale.md index a336d88f..33f5509d 100644 --- a/docs/docs/recipes/2-locale.md +++ b/docs/docs/recipes/2-locale.md @@ -1,14 +1,51 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OpenNew from '@site/static/img/open_new.svg'; + # Changing the Locale in a test ## API 24+ It is often desirable to test your View or Activity in multiple locales. Testify allows you to dynamically change the locale on a per-test basis. -To begin, if you are targeting an emulator running Android API 24 or higher, your activity under test must implement the [TestifyResourcesOverride](https://github.com/ndtp/android-testify/blob/230607acc598afe7d54f9618d55fdecd0da83800/Library/src/main/java/dev/testify/resources/TestifyResourcesOverride.kt) interface. This allows Testify to attach a new `Context` with the appropriate locale loaded. It is highly recommended that you employ a _test harness activity_ for this purpose. Please see the [TestHarnessActivity](https://github.com/ndtp/android-testify/blob/230607acc598afe7d54f9618d55fdecd0da83800/Samples/Legacy/src/androidTest/java/dev/testify/sample/test/TestLocaleHarnessActivity.kt) in the provided Sample. +Please read this excellent [blog post ](https://proandroiddev.com/change-language-programmatically-at-runtime-on-android-5e6bc15c758) if you want to better understand how to dynamically adjust Locale in your app. Note that the Testify locale override support is intended for instrumentation testing only and does not provide a suitable solution for your production application. -With an Activity which implements `TestifyResourcesOverride`, you can now invoke the [setLocale](https://github.com/ndtp/android-testify/blob/230607acc598afe7d54f9618d55fdecd0da83800/Library/src/main/java/dev/testify/ScreenshotRule.kt#L269) method on the `ScreenshotTestRule`. `setLocale` accepts any valid [Locale](https://docs.oracle.com/javase/7/docs/api/java/util/Locale.html) instance. +To begin, if you are targeting an emulator running Android API 24 or higher, your activity under test must implement the [TestifyResourcesOverride](https://github.com/ndtp/android-testify/blob/main/Library/src/main/java/dev/testify/resources/TestifyResourcesOverride.kt) interface. This allows Testify to attach a new `Context` with the appropriate locale loaded. It is highly recommended that you employ a _test harness activity_ for this purpose. Please see the [TestLocaleHarnessActivity](https://github.com/ndtp/android-testify/blob/main/Samples/Legacy/src/androidTest/java/dev/testify/sample/test/TestLocaleHarnessActivity.kt) in the provided Sample. + +_Example Test Harness Activity_ +```kotlin +open class TestHarnessActivity : AppCompatActivity(), TestifyResourcesOverride { + + /** + * This is required to correctly support dynamic Locale changes + * + * See [TestingResourceConfigurationsExampleTest] + */ + override fun attachBaseContext(newBase: Context?) { + super.attachBaseContext(newBase?.wrap()) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(FrameLayout(this).apply { + layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + id = R.id.harness_root + }) + } +} +``` + +### ActivityTestRule vs. ActivityScenarioRule + +With an Activity which implements `TestifyResourcesOverride`, and if you are using `ScreenshotRule` (a subclass of `ActivityTestRule`), you can configure the `locale` field on method on the `ScreenshotTestRule`. `TestifyConfiguration.locale` can be set to any valid [java.util.Locale ](https://docs.oracle.com/javase/7/docs/api/java/util/Locale.html) instance. + +If you are using `ScreenshotScenarioRule` (which works in conjunction with `ActivityScenarioRule`), you must use the `overrideResourceConfiguration` helper method. This method must be called before the activity is launched. + + + + -_Example Test:_ ```kotlin class TestLocaleActivityTest { @@ -23,32 +60,39 @@ class TestLocaleActivityTest { @Test fun testLocaleFrance() { rule - .setLocale(Locale.FRANCE) + .configure { + locale = Locale.FRANCE + } .assertSame() } } ``` -_Example Test Harness Activity_ + + + ```kotlin -open class TestHarnessActivity : AppCompatActivity(), TestifyResourcesOverride { +class MainActivityScreenshotTest { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) + @get:Rule val rule = ScreenshotScenarioRule() - setContentView(FrameLayout(this).apply { - layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) - id = R.id.harness_root - }) - } + @ScreenshotInstrumentation + @TestifyLayout(R.layout.view_client_details) + @Test + fun testLocaleFrance() { + overrideResourceConfiguration(locale = Locale.FRANCE) - override fun attachBaseContext(newBase: Context?) { - super.attachBaseContext(newBase?.wrap()) + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .assertSame() + } } } ``` -Please read this excellent [blog post](https://proandroiddev.com/change-language-programmatically-at-runtime-on-android-5e6bc15c758) if you want to better understand how to dynamically adjust Locale in your app. Note that the Testify locale override support is intended for instrumentation testing only and does not provide a suitable solution for your production application. + + ## API 23 or lower @@ -57,6 +101,7 @@ On lower API levels, a test harness activity is not required. You are not requir To test with a provided locale, invoke the `setLocale` method on `ScreenshotRule` _Example Test:_ + ```kotlin class MainActivityScreenshotTest { diff --git a/docs/docs/recipes/20-gmd.md b/docs/docs/recipes/20-gmd.md index b9af522d..6b6125b7 100644 --- a/docs/docs/recipes/20-gmd.md +++ b/docs/docs/recipes/20-gmd.md @@ -1,4 +1,6 @@ import OpenNew from '@site/static/img/open_new.svg'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # Configuring Testify to run on Gradle managed device @@ -7,10 +9,7 @@ Starting from API levels This feature improves testing experience by delegating the task of starting, shutting down and managing emulator to the Gradle. -When using Gradle managed device user must -use [Test storage service ](https://developer.android.com/reference/androidx/test/services/storage/TestStorage) -to save screenshots. Using this service Android Gradle Plugin would be able to save test output -including screenshots and diffs to the `build` folder +When using a Gradle Managed Device, you must use the [Test storage service ](https://developer.android.com/reference/androidx/test/services/storage/TestStorage) to save screenshots. Using this service, the Android Gradle Plugin will be able to save test output to your local `build` folder. ### Adding Gradle managed device configuration to build file @@ -49,14 +48,11 @@ dependencies { } ``` -With that changes applied couple of new Gradle tasks should be added to your project. Suppose, you -named your device `tester`, then `testerCheck` and `testDebugAndroidTest` tasks should be added to -your project. +With that changes applied, several new Gradle tasks will be added to your project. For a device named _**myDevice**_, then Gradle tasks `myDeviceCheck` and `myDeviceDebugAndroidTest` tasks will be added to your project. ### Configuring the Testify library -You also need to instruct Testify to use Test storage to store screenshots and diffs. This could be -done using Testify plugin configuration: +You also need to instruct Testify to use Test Storage to store screenshots and diffs. This is done using Testify plugin configuration by setting the `useTestStorage` Gradle property to `true` : ```groovy testify { @@ -66,35 +62,61 @@ testify { ### Running screenshot tests -To perform screenshot test verification run any of the new Gradle tasks, for -example `./gradlew testerDebugAndroidTest`. +To perform screenshot test verification, run any of the new Gradle tasks, for example `./gradlew app:myDeviceDebugAndroidTest`. -Because we need to run specific Gradle task to execute our tests using Gradle managed device, we -cannot use `screenshotPull` task. When execution completed go to the -module's `build/outputs/managed_device_android_test_additional_output/tester` folder to get recorded -screenshots or diffs. +Because we need to run specific Gradle tasks to execute our tests using the Gradle Managed Device, we cannot use `screenshotPull` task. When execution is completed, navigate to the module's `build/outputs/managed_device_android_test_additional_output/myDevice` folder to find the recorded screenshots or diffs. ### Updating baselines -Because we need to run specific Gradle task to execute our tests using Gradle managed device, we -cannot use `screenshotRecord` task. To generate new baseline there are two options: +Because we need to run specific Gradle tasks to execute our tests using the Gradle Managed Device, we cannot use `screenshotRecord` task. -- apply necessary setting to the `ScreenshotRule`: +To generate new baseline there are two options: + +1. Apply necessary configuration on the `ScreenshotRule`: + + + ```kotlin @get:Rule -var rule = ScreenshotRule(ClientListActivity::class.java) +val rule = ScreenshotRule(ClientListActivity::class.java) @ScreenshotInstrumentation @Test fun testMissingBaseline() { rule - .setRecordModeEnabled(true) + .configure { + isRecordMode = true + } .assertSame() } ``` -- or enable record mode in the `build.gradle` file: + + + +```kotlin +@get:Rule +var rule = ScreenshotScenarioRule() + +@ScreenshotInstrumentation +@Test +fun testMissingBaseline() { + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .configure { + isRecordMode = true + } + .assertSame() + } +} +``` + + + + +2. Enable record mode in the `build.gradle` file: ```groovy testify { @@ -102,11 +124,14 @@ testify { } ``` -Again we cannot use `screenshotPull` task. When execution completed go to the -module's `build/outputs/managed_device_android_test_additional_output/tester` and copy recorded -baseline into the `androidTest/assets/screenshots/` directory, for example: `androidTest/assets/screenshots/30-1080x1920@420dp-en_US` +:::tip + +As we cannot use `screenshotPull` task, when test execution is completed, the _Test Storage_ service will copy recorded files from the module's `build/outputs/managed_device_android_test_additional_output/myDevice` into your `androidTest/assets/screenshots/` directory. + +::: ### Sample -Please check -provided [sample ](https://github.com/ndtp/android-testify/tree/main/Samples/Gmd). \ No newline at end of file +Please check provided [sample ](https://github.com/ndtp/android-testify/tree/main/Samples/Gmd). + +--- diff --git a/docs/docs/recipes/21-library-projects.md b/docs/docs/recipes/21-library-projects.md index 139821dc..05645c97 100644 --- a/docs/docs/recipes/21-library-projects.md +++ b/docs/docs/recipes/21-library-projects.md @@ -1,6 +1,8 @@ +import OpenNew from '@site/static/img/open_new.svg'; + # Configuring Testify for Android Library Projects -An [Android library](https://developer.android.com/studio/projects/android-library) is structurally the same as an Android app module. It includes everything needed to build an app, including source code, resource files, and an Android manifest. So, it is often necessary to want to use screenshot testing with your library. +An [Android library ](https://developer.android.com/studio/projects/android-library) is structurally the same as an Android app module. It includes everything needed to build an app, including source code, resource files, and an Android manifest. So, it is often necessary to want to use screenshot testing with your library. However, instead of compiling into an APK that runs on a device, an Android library compiles into an Android Archive (AAR) file that you can use as a dependency for an Android app module. This means that Testify requires special configuration. The Testify Gradle Plugin is able to infer most configuration parameters for App modules, but for a Library module, some values must be specified in the `build.gradle` file. @@ -15,37 +17,36 @@ testify { } ``` -To find out what value to use for `applicationPackageId` and `testPackageId`, you can check the [_instrumentation_](https://source.android.com/docs/core/tests/development/instrumentation) name for your library by using the `pm list instrumentation` command on your emulator. +To find out what value to use for `applicationPackageId` and `testPackageId`, you can check the [_instrumentation_](https://source.android.com/docs/core/tests/development/instrumentation) name for your library by using the `pm list instrumentation` command on your emulator. For example, to check the instrumentation name of the _Flix Library_ sample project: -```bash -~>: ./gradlew FlixLibrary:installDebugAndroidTest +```shell-session +$ ./gradlew FlixLibrary:installDebugAndroidTest Installing APK 'FlixLibrary-debug-androidTest.apk' on 'Testify(AVD) - 10' for :FlixLibrary:debug-androidTest BUILD SUCCESSFUL in 1s 53 actionable tasks: 1 executed, 52 up-to-date -~>: adb shell pm list instrumentation +$ adb shell pm list instrumentation instrumentation:dev.testify.samples.flix.library.test/androidx.test.runner.AndroidJUnitRunner (target=dev.testify.samples.flix.library.test) ``` -#### Testify Configuration Values: +### Testify Configuration Values: - **testPackageId** : The `instrumentation` package reported by `pm list instrumentation`.
ex. `dev.testify.samples.flix.library.test` - - **applicationPackageId** : The `target` package reported by `pm list instrumentation`.
ex. `dev.testify.samples.flix.library.test` --- -### Sample +## Sample Please see the [Flix Library sample](https://github.com/ndtp/android-testify/tree/main/Samples/Flix/FlixLibrary) for an example of using Testify with a library project. -### More Information +## More Information -- [Create an Android library](https://developer.android.com/studio/projects/android-library) -- [Instrumentation tests](https://source.android.com/docs/core/tests/development/instrumentation) +- [Create an Android library ](https://developer.android.com/studio/projects/android-library) +- [Instrumentation tests ](https://source.android.com/docs/core/tests/development/instrumentation) --- diff --git a/docs/docs/recipes/3-font-scale.md b/docs/docs/recipes/3-font-scale.md index 72365b24..63539d36 100644 --- a/docs/docs/recipes/3-font-scale.md +++ b/docs/docs/recipes/3-font-scale.md @@ -1,11 +1,22 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OpenNew from '@site/static/img/open_new.svg'; + # Changing the font scale in a test Testify allows you to change the current Activity scaling factor for fonts, relative to the base density scaling. This allows you to simulate the impact of a user modifying the default font size on their device, such as tiny, large or huge. -:warning: Please note that, similar to changing the Locale (above), you are required to implement `TestifyResourcesOverride` when invoking `setFontScale()`. -See [Font size and display size](https://support.google.com/accessibility/android/answer/6006972?hl=en) +:::note +Similar to changing the `Locale`, you are required to implement `TestifyResourcesOverride` when configuring `fontScale`. See [_**Changing the Locale in a test**_](locale). +::: + +See [_Change text & display settings_ ](https://support.google.com/accessibility/android/answer/6006972?hl=en) _Example Test:_ + + + + ```kotlin class MainActivityScreenshotTest { @@ -16,8 +27,36 @@ class MainActivityScreenshotTest { @Test fun testHugeFontScale() { rule - .setFontScale(2.0f) + .configure { + fontScale = 2.0f + } .assertSame() } } ``` + + + + +```kotlin +class MainActivityScreenshotTest { + + @get:Rule val rule = ScreenshotScenarioRule() + + @ScreenshotInstrumentation + @TestifyLayout(R.layout.view_client_details) + @Test + fun testHugeFontScale() { + overrideResourceConfiguration(fontScale = 2.0f) + + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .assertSame() + } + } +} +``` + + + diff --git a/docs/docs/recipes/4-tolerance.md b/docs/docs/recipes/4-tolerance.md index 8c686566..06e21289 100644 --- a/docs/docs/recipes/4-tolerance.md +++ b/docs/docs/recipes/4-tolerance.md @@ -1,9 +1,22 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OpenNew from '@site/static/img/open_new.svg'; + # Increase the matching tolerance In some cases, the captured screenshot may inherently contain randomness. It may then be desirable to allow for an inexact matching. By default, Testify employs an exact, pixel-by-pixel matching algorithm. Alternatively, you may optionally reduce this exactness. -By providing a value less than 1 to `setExactness`, a test will be more tolerant to color differences. A value of less than 1 will enable the [_Delta E_](https://en.wikipedia.org/wiki/Color_difference#CIELAB_%CE%94E) comparison method. The Delta E algorithm will mathematically quantify the similarity between two different colors. It ignores differences between two pixels that the human eye would consider identical while still identifying differences in position, size or layout. +By providing a value less than 1 to `exactness`, a test will be more tolerant to color differences. A value of less than 1 will enable the [_Delta E_ ](https://en.wikipedia.org/wiki/Color_difference#CIELAB_%CE%94E) comparison method. The Delta E algorithm will mathematically quantify the similarity between two different colors. It ignores differences between two pixels that the human eye would consider identical while still identifying differences in position, size or layout. + +:::tip + +Please also see [_Accounting for platform differences_](../../blog/platform-differences) for more insight into handling unintended differences in your rendering. + +::: + + + ```kotlin @TestifyLayout(R.layout.view_client_details) @@ -11,7 +24,9 @@ By providing a value less than 1 to `setExactness`, a test will be more tolerant @Test fun setExactness() { rule - .setExactness(0.9f) + .configure { + exactness = 0.9f + } .setViewModifications { val r = Integer.toHexString(Random.nextInt(0, 25) + 230).padStart(2, '0') it.findViewById(R.id.info_card).setBackgroundColor(Color.parseColor("#${r}0000")) @@ -19,3 +34,29 @@ By providing a value less than 1 to `setExactness`, a test will be more tolerant .assertSame() } ``` + + + + +```kotlin + @TestifyLayout(R.layout.view_client_details) + @ScreenshotInstrumentation + @Test + fun setExactness() { + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .configure { + exactness = 0.9f + } + .setViewModifications { + val r = Integer.toHexString(Random.nextInt(0, 25) + 230).padStart(2, '0') + it.findViewById(R.id.info_card).setBackgroundColor(Color.parseColor("#${r}0000")) + } + .assertSame() + } + } +``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/5-testify-layout-library.md b/docs/docs/recipes/5-testify-layout-library.md index 5f6bf92d..59c520a3 100644 --- a/docs/docs/recipes/5-testify-layout-library.md +++ b/docs/docs/recipes/5-testify-layout-library.md @@ -1,9 +1,24 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OpenNew from '@site/static/img/open_new.svg'; + # Using @TestifyLayout with library projects The `TestifyLayout` annotation allows you to specify a layout resource to be automatically loaded into the host Activity for testing. -Unfortunately R fields are not constants in Android library projects and R.layout resource IDs cannot be used as annotations parameters. +Unfortunately [`R` ](https://developer.android.com/reference/android/R) fields are not constants in Android library projects and R.layout resource IDs cannot be used as annotations parameters. Instead, you can specify a fully qualified resource name of the form "package:type/entry" as the `layoutResName` argument on `TestifyLayout`. +:::caution + +Use of this parameter is discouraged because resource reflection makes it harder to perform build optimizations and compile-time verification of code. It is much more efficient to retrieve resources by identifier (e.g. `@TestifyLayout(layoutId = R.foo.bar)`) than by name (e.g. `@TestifyLayout(layoutResName = "package:foo/bar")`). + +This annotation parameter is provided to allow for loading of resources from Library projects, which may otherwise be impossible. + +::: + + + + ```kotlin class MainActivityScreenshotTest { @@ -17,3 +32,27 @@ class MainActivityScreenshotTest { } } ``` + + + + +```kotlin +class MainActivityScreenshotTest { + + @get:Rule var rule = ScreenshotScenarioRule() + + @TestifyLayout(layoutResName = "dev.testify.sample:layout/view_client_details") + @ScreenshotInstrumentation + @Test + fun default() { + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .assertSame() + } + } +} +``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/6-intents.md b/docs/docs/recipes/6-intents.md index 54874126..aed9274b 100644 --- a/docs/docs/recipes/6-intents.md +++ b/docs/docs/recipes/6-intents.md @@ -1,8 +1,17 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OpenNew from '@site/static/img/open_new.svg'; + # Passing Intent extras to the Activity under test Some activities may require a `Bundle` of additional information called _extras_. Extras can be used to provide extended information to the component. For example, if we have a action to send an e-mail message, we could also include extra pieces of data here to supply a subject, body, etc. To provide extras to your Activity, you can implement the `addIntentExtras` method on `ScreenshotRule` and pass a lambda that can add to the provided `Bundle`. +If you are using `ScreenshotScenarioRule`, you should use the built-in Intent support provided by [`ActivityScenarioRule`](https://developer.android.com/reference/androidx/test/ext/junit/rules/ActivityScenarioRule#ActivityScenarioRule(android.content.Intent)). + + + + ```kotlin class MainActivityScreenshotTest { @@ -19,3 +28,33 @@ class MainActivityScreenshotTest { } } ``` + + + + +```kotlin +class MainActivityScreenshotTest { + + @get:Rule val rule = ScreenshotScenarioRule() + + @ScreenshotInstrumentation + @Test + fun default() { + + val context = InstrumentationRegistry.getInstrumentation().targetContext + val intent = Intent(context, MainActivity::class.java).apply { + putExtra("TOOLBAR_TITLE", "addIntentExtras") + } + + launchActivity(intent).use { scenario -> + rule + .withScenario(scenario) + .assertSame() + } + + } +} +``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/7-layout-resource.md b/docs/docs/recipes/7-layout-resource.md index 92bb457a..621231e3 100644 --- a/docs/docs/recipes/7-layout-resource.md +++ b/docs/docs/recipes/7-layout-resource.md @@ -1,8 +1,14 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Specifying a layout resource programmatically As an alternative to using the `TestifyLayout` annotation, you may also specific a layout file to be loaded programmatically. You can pass a `R.layout.*` resource ID to `setTargetLayoutId` on the `ScreenshotRule`. + + + ```kotlin class MainActivityScreenshotTest { @@ -17,3 +23,27 @@ class MainActivityScreenshotTest { } } ``` + + + + +```kotlin +class MainActivityScreenshotTest { + + @get:Rule val rule = ScreenshotScenarioRule() + + @ScreenshotInstrumentation + @Test + fun default() { + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .setTargetLayoutId(R.layout.view_client_details) + .assertSame() + } + } +} +``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/8-espresso.md b/docs/docs/recipes/8-espresso.md index 24f213bf..ae2ff813 100644 --- a/docs/docs/recipes/8-espresso.md +++ b/docs/docs/recipes/8-espresso.md @@ -1,13 +1,27 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OpenNew from '@site/static/img/open_new.svg'; + # Use Espresso UI tests with Testify `ScreenshotRule.setEspressoActions` accepts a lambda of type `EspressoActions` in which you may define any number of Espresso actions. These actions are executed after the activity is fully inflated and any view modifications have been applied. Testify will synchronize with the Espresso event loop and ensure that all Espresso actions are complete before capturing a screenshot. +Please [check here ](https://developer.android.com/training/testing/espresso) for more information about Espresso testing. + +If you are using `ScreenshotScenarioRule`, you can use Espresso actions on the Activity provided by the `ActivityScenario` that you provide to `ScreenshotScenarioRule.withScenario`. Testify will synchronize with the Espresso event loop and ensure that all Espresso actions are complete before capturing a screenshot. + + +:::tip + Note that it's not generally recommended to use complex Espresso actions with your screenshot tests. Espresso test are an order of magnitude slower to run and are more susceptible to flakiness. -Please [check here](https://developer.android.com/training/testing/espresso) for more information about Espresso testing. +::: + + + ```kotlin class MainActivityScreenshotTest { @@ -25,3 +39,30 @@ class MainActivityScreenshotTest { } } ``` + + + + +```kotlin +class MainActivityScreenshotTest { + + @get:Rule val rule = ScreenshotScenarioRule() + + @TestifyLayout(R.layout.view_edit_text) + @ScreenshotInstrumentation + @Test + fun setEspressoActions() { + launchActivity().use { scenario -> + rule + .withScenario(scenario) + .setEspressoActions { + onView(withId(R.id.edit_text)).perform(typeText("Testify")) + } + .assertSame() + } + } +} +``` + + + \ No newline at end of file diff --git a/docs/docs/recipes/9-java.md b/docs/docs/recipes/9-java.md index 89a7ed8d..9465442f 100644 --- a/docs/docs/recipes/9-java.md +++ b/docs/docs/recipes/9-java.md @@ -1,10 +1,18 @@ # Writing a test in Java +Testify is fully backwards compatible with Java. + ```java +import org.junit.Rule; +import org.junit.Test; + +import dev.testify.ScreenshotRule; +import dev.testify.annotation.ScreenshotInstrumentation; + public class MainActivityScreenshotTest { @Rule - public ScreenshotRule rule = new ScreenshotRule<>(MainActivity.class); + public ScreenshotRule rule = new ScreenshotRule<>(MainActivity.class); @ScreenshotInstrumentation @Test @@ -13,3 +21,28 @@ public class MainActivityScreenshotTest { } } ``` + +The function `Configurable.makeConfigurable()` is provided as a convenience to more easily configure Testify from Java. + +```java +import org.junit.Rule; +import org.junit.Test; + +import dev.testify.ScreenshotRule; +import dev.testify.annotation.ScreenshotInstrumentation; + +public class MainActivityScreenshotTest { + + @Rule + public ScreenshotRule rule = new ScreenshotRule<>(MainActivity.class); + + @ScreenshotInstrumentation + @Test + public void testConfiguration() { + Configurable.makeConfigurable(rule) + .setExactness(0.95f) + .setCaptureMethod(PixelCopyCaptureKt::pixelCopyCapture) + .assertSame(); + } +} +``` \ No newline at end of file diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index c860a0bb..b64c72f7 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -2,7 +2,7 @@ // Note: type annotations allow type checking and IDEs autocompletion const lightCodeTheme = require('prism-react-renderer/themes/github'); -const darkCodeTheme = require('prism-react-renderer/themes/dracula'); +const darkCodeTheme = require('prism-react-renderer/themes/oceanicNext'); /** @type {import('@docusaurus/types').Config} */ const config = { @@ -165,7 +165,7 @@ const config = { prism: { theme: lightCodeTheme, darkTheme: darkCodeTheme, - additionalLanguages: ['kotlin', 'groovy', 'bash', 'java'], + additionalLanguages: ['kotlin', 'groovy', 'bash', 'java', 'shell-session'], }, }), };