Skip to content

Commit

Permalink
Squashed changes, moved Validation to a separate branch
Browse files Browse the repository at this point in the history
  • Loading branch information
timothyfroehlich committed Sep 12, 2023
1 parent 1e1e1cb commit 82cceca
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 1 deletion.
52 changes: 52 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,58 @@ jobs:
name: designcompose_m2repo
path: build/designcompose_m2repo/

# These tests run on the local JVM and don't need the rust code,
# so it makes sense to put them in a seperate job
roborazzi:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1
with:
egress-policy: audit

- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v3.5.2

- name: Set up Java
uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0
with:
distribution: "temurin"
java-version: "17"

- name: Validate Roborazzi
uses: gradle/gradle-build-action@ef76a971e2fa3f867b617efd72f2fbd72cf6f8bc # v2.8.0
with:
# Upload in the dependency-review workflow
dependency-graph: generate
arguments: verifyRoborazziDebug

- uses: actions/upload-artifact@v3
if: ${{ always() }}
with:
name: screenshot-diff
path: |
**/src/testDebug/roborazzi
retention-days: 30

- uses: actions/upload-artifact@v3
if: ${{ always() }}
with:
name: screenshot-diff-reports
path: |
**/build/reports
retention-days: 30

- uses: actions/upload-artifact@v3
if: ${{ always() }}
with:
name: screenshot-diff-test-results
path: |
**/build/test-results
retention-days: 30

########### Tutorial app
tutorial-app:
runs-on: ubuntu-latest
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,16 @@ To update the Design Switcher, temporarily set the `DISABLE_LIVE_MODE` flag in `

The Tutorial's DesignDoc is set to the main development Figma file, to assist in development of the app, but the committed serialized file is a separate file that presents a "welcome" page. This file's ID is `BX9UyUa5lkuSP3dEnqBdJf`. To update the file, fetch the `BX9UyUa5lkuSP3dEnqBdJf` file, then replace `reference-apps/tutorial/app/src/main/assets/figma/TutorialDoc_3z4xExq0INrL9vxPhj9tl7` with the serialized file. **The file name will remain the same**, the `TutorialDoc_3z4xExq0INrL9vxPhj9tl7` fill will contain the serialized `BX9UyUa5lkuSP3dEnqBdJf` file. The Tutorial app project has an AndroidIntegratedTest to ensure that the correct file is set, and it will be run as part of running the `./dev-scripts/test-all.sh` script.

## Roborazzi screenshot tests

[Roborazzi](https://github.com/takahirom/roborazzi) is a new framework that allows for screenshot testing of Android Apps on your local system. It uses [Robolectric](https://github.com/robolectric/robolectric), the standard unit testing framework for Android, to render DesignCompose locally, allowing screenshots to be generated. The screenshots won't be one-to-one with actual Android devices, but they'll be very close and stable enough for changes to be detected.

Roborazzi is implemented in .tests under `<package>/src/debugTest`. The tests themselves will run if you run `./gradlew test`, but screenshots will only be checked if you run `./gradlew verifyRoborazziDebug`. This command has been added to the `./dev-scripts/test-all.sh` command, so you don't need to run it separately if you run test-all.

If `verifyRoborazziDebug` fails then you can run `compareRoborazziDebug` to generate image diffs. If after reviewing these you determine that the change is acceptable you can regenerate the screenshots using `recordRoborazziDebug`. (Note that this will regenerate all images from all tests).

More info can be found in [Roborazzi's readme](https://github.com/takahirom/roborazzi#apply-roborazzi-gradle-plugin).

## Testing the standalone version of the Tutorial app

The Tutorial app is currently part of two projects: The root project in the root of the repository, and the tutorial project in `reference-apps/tutorial`. The root project is the one that contains the entire SDK and our apps and is where you typically develop. The second project is the one that users following the Tutorial are directed to use. It fetches DesignCompose from gMaven, which means that it builds much faster and doesn't compile rust code (and doesn't require the rust SDK to be installed). This means that the standalone Tutorial needs some extra configuration if you want the standalone Tutorial project to use any unpublished changes to the libraries and plugin.
Expand Down
2 changes: 1 addition & 1 deletion dev-scripts/test-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ cd "$GIT_ROOT/plugins" || exit
./gradlew build

cd "$GIT_ROOT" || exit
./gradlew build publishAllPublicationsToLocalDirRepository
./gradlew build publishAllPublicationsToLocalDirRepository verifyRoborazziDebug

if [[ $run_emulator_tests == 1 ]]; then
./gradlew tabletAtdApi30Check -Pandroid.testoptions.manageddevices.emulator.gpu=swiftshader_indirect
Expand Down
7 changes: 7 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ junit5 = "5.10.0"
truth = "1.1.5"
core = "1.10.1"
activityKtx = "1.7.2"
robolectric = "4.10.3"
roborazzi = "1.6.0-alpha-3"

[libraries]
accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", version.ref = "accompanist" }
Expand Down Expand Up @@ -108,9 +110,14 @@ google-truth = { module = "com.google.truth:truth", version.ref = "truth" }
junit-jupiter = {module = "org.junit.jupiter:junit-jupiter", version.ref = "junit5" }
androidx-core = { group = "androidx.core", name = "core", version.ref = "core" }
androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "activityKtx" }
robolectric = {module = "org.robolectric:robolectric", version.ref = "robolectric"}
roborazzi = {module = "io.github.takahirom.roborazzi:roborazzi", version.ref = "roborazzi"}
roborazzi-compose = {module = "io.github.takahirom.roborazzi:roborazzi-compose", version.ref = "roborazzi"}
roborazzi-junit = {module = "io.github.takahirom.roborazzi:roborazzi-junit-rule", version.ref = "roborazzi"}

[plugins]
designcompose = { id = "com.android.designcompose", version.ref = "designcompose" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
ktfmt = { id = "com.ncorti.ktfmt.gradle", version.ref = "ktfmt" }
strictVersionMatcher = { id = "com.google.android.gms.strict-version-matcher-plugin", version.ref = "android-gms-strictVersionMatcher" }
roborazzi = {id = "io.github.takahirom.roborazzi", version.ref = "roborazzi"}
10 changes: 10 additions & 0 deletions reference-apps/helloworld/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ plugins {
alias(libs.plugins.ksp)
id("designcompose.conventions.base")
alias(libs.plugins.designcompose)
alias(libs.plugins.roborazzi)
}

var applicationID = "com.android.designcompose.testapp.helloworld"
Expand Down Expand Up @@ -71,6 +72,7 @@ android {
}

packaging { resources { excludes.add("/META-INF/{AL2.0,LGPL2.1}") } }
testOptions { unitTests { isIncludeAndroidResources = true } } // For Roborazzi
}

dependencies {
Expand All @@ -88,6 +90,14 @@ dependencies {

debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation(libs.androidx.compose.ui.test.manifest)

testImplementation(libs.robolectric)
testImplementation(libs.roborazzi)
testImplementation(libs.roborazzi.compose)
testImplementation(libs.roborazzi.junit)
testImplementation(libs.androidx.test.espresso.core)
testImplementation(libs.androidx.compose.ui.test.junit4)

androidTestImplementation(libs.junit)
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
androidTestImplementation(libs.androidx.test.espresso.core)
Expand Down
56 changes: 56 additions & 0 deletions reference-apps/helloworld/src/testDebug/kotlin/RenderHelloWorld.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.android.designcompose.testapp.helloworld

import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.github.takahirom.roborazzi.RobolectricDeviceQualifiers
import com.github.takahirom.roborazzi.RoborazziRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
import org.robolectric.annotation.GraphicsMode

@RunWith(AndroidJUnit4::class)
// Enable Robolectric Native Graphics (RNG)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(qualifiers = RobolectricDeviceQualifiers.MediumTablet)
class RenderHelloWorld {
@get:Rule val composeTestRule = createAndroidComposeRule<ComponentActivity>()

@get:Rule
val roborazziRule =
RoborazziRule(
composeRule = composeTestRule,
captureRoot = composeTestRule.onRoot(),
options =
RoborazziRule.Options(
RoborazziRule.CaptureType.LastImage(),
outputDirectoryPath = "src/testDebug/roborazzi"
)
)

@Test
fun testHello() {
composeTestRule.setContent { HelloWorldDoc.mainFrame(name = "Testers!") }
composeTestRule.onNodeWithText("Testers!", substring = true).assertExists()
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 82cceca

Please sign in to comment.