diff --git a/.github/workflows/jest-detox.yml b/.github/workflows/jest-detox.yml new file mode 100644 index 0000000..7c3aa7d --- /dev/null +++ b/.github/workflows/jest-detox.yml @@ -0,0 +1,102 @@ +name: Jest + Detox + +on: + push: + branches: [main] + paths: + ["generic-reporter/jest/detox/**", ".github/workflows/jest-detox.yml"] + pull_request: + paths: + ["generic-reporter/jest/detox/**", ".github/workflows/jest-detox.yml"] + workflow_dispatch: + +jobs: + android: + permissions: + contents: read + runs-on: ubuntu-latest + timeout-minutes: 60 + defaults: + run: + working-directory: generic-reporter/jest/detox + env: + CURRENTS_PROJECT_ID: X7niCl + HAS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY != '' }} + CURRENTS_CI_BUILD_ID: ${{ github.repository }}-detox-${{ github.run_id }}-${{ github.run_attempt }} + + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-node@v6 + with: + node-version: 24 + cache: npm + cache-dependency-path: generic-reporter/jest/detox/package-lock.json + + - uses: actions/setup-java@v6 + with: + distribution: temurin + java-version: 17 + + - uses: gradle/actions/setup-gradle@v6 + + - run: npm ci + + - name: Build the app + run: npx detox build --configuration android.att.release + + - name: Enable KVM for the emulator + working-directory: . + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Run the tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 34 + target: google_apis + arch: x86_64 + disable-animations: true + working-directory: generic-reporter/jest/detox + script: npx detox test --configuration android.att.release --retries 1 --headless + + # A pull_request run checks out a merge commit GitHub creates, so without + # this step Currents shows "Merge into " as the commit message. + # `currents upload` reads the COMMIT_INFO_* variables before git. + - name: Use the pull request commit for Currents + if: ${{ !cancelled() && github.event_name == 'pull_request' }} + env: + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + HEAD_REF: ${{ github.event.pull_request.head.ref }} + run: | + git fetch --depth=1 origin "$HEAD_SHA" + # A random delimiter: a commit message line equal to a fixed one would end the + # value early and add the lines after it as variables. + delimiter="EOF_$(openssl rand -hex 16)" + { + echo "COMMIT_INFO_SHA=$HEAD_SHA" + echo "COMMIT_INFO_BRANCH=$HEAD_REF" + echo "COMMIT_INFO_AUTHOR=$(git log -1 --format=%an "$HEAD_SHA")" + echo "COMMIT_INFO_EMAIL=$(git log -1 --format=%ae "$HEAD_SHA")" + echo "COMMIT_INFO_MESSAGE<<$delimiter" + git log -1 --format=%B "$HEAD_SHA" + echo "$delimiter" + } >> "$GITHUB_ENV" + + # Runs after `detox test` exits, when Detox has finished writing the + # videos and logs. + - name: Upload the results to Currents + # Pull requests from forks get no secrets and skip the upload. + if: ${{ !cancelled() && env.HAS_RECORD_KEY == 'true' }} + env: + CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }} + run: npx currents upload + + - name: Keep the Detox artifacts + if: ${{ !cancelled() }} + uses: actions/upload-artifact@v7 + with: + name: detox-artifacts + path: generic-reporter/jest/detox/artifacts diff --git a/README.md b/README.md index 0313195..dd38513 100644 --- a/README.md +++ b/README.md @@ -8,20 +8,20 @@ Examples demonstrating Playwright integration with Currents, including sharding, ### CI -| Example | Description | -| :-------------------------------------------------------- | :-------------------------------------------------------------------- | -| [**AWS CodeBuild**](playwright/ci/aws-codebuild/) | Run Playwright tests in AWS CodeBuild | -| [**Azure DevOps**](playwright/ci/azure-devops/) | Integration with Azure DevOps pipelines | -| [**Buildkite**](playwright/ci/buildkite/) | Run Playwright tests in Buildkite | -| [**CircleCI**](playwright/ci/circleci/) | Run Playwright tests in CircleCI | -| [**GitHub Actions**](playwright/ci/github-actions/) | Comprehensive GitHub Actions workflow | -| [**GitHub Actions — Basic Setup**](playwright/ci/github-actions/setup-ci/) | Standard CI setup with sharding and reporting | -| [**GitHub Actions — Orchestration**](playwright/ci/github-actions/orchestration/) | Optimized parallel execution with load balancing | -| [**GitHub Actions — Rerun Failed**](playwright/ci/github-actions/rerun-failed/) | Rerun only failed tests from a previous build | -| [**GitHub Actions — Visual Testing**](playwright/ci/github-actions/argos/) | Integration with Argos for visual regression testing | -| [**GitLab CI**](gitlab/) | Playwright + Currents on GitLab CI ([source on GitLab](https://gitlab.com/currents.dev/gitlab-playwright-currents)) | -| [**Jenkins**](playwright/ci/jenkins/jenkins-last-failed/) | Advanced Jenkins setup with Docker, Sharding, and "Last Failed" rerun | -| [**Nx Monorepo**](playwright/ci/nx/) | Playwright in an Nx workspace | +| Example | Description | +| :-------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------ | +| [**AWS CodeBuild**](playwright/ci/aws-codebuild/) | Run Playwright tests in AWS CodeBuild | +| [**Azure DevOps**](playwright/ci/azure-devops/) | Integration with Azure DevOps pipelines | +| [**Buildkite**](playwright/ci/buildkite/) | Run Playwright tests in Buildkite | +| [**CircleCI**](playwright/ci/circleci/) | Run Playwright tests in CircleCI | +| [**GitHub Actions**](playwright/ci/github-actions/) | Comprehensive GitHub Actions workflow | +| [**GitHub Actions — Basic Setup**](playwright/ci/github-actions/setup-ci/) | Standard CI setup with sharding and reporting | +| [**GitHub Actions — Orchestration**](playwright/ci/github-actions/orchestration/) | Optimized parallel execution with load balancing | +| [**GitHub Actions — Rerun Failed**](playwright/ci/github-actions/rerun-failed/) | Rerun only failed tests from a previous build | +| [**GitHub Actions — Visual Testing**](playwright/ci/github-actions/argos/) | Integration with Argos for visual regression testing | +| [**GitLab CI**](gitlab/) | Playwright + Currents on GitLab CI ([source on GitLab](https://gitlab.com/currents.dev/gitlab-playwright-currents)) | +| [**Jenkins**](playwright/ci/jenkins/jenkins-last-failed/) | Advanced Jenkins setup with Docker, Sharding, and "Last Failed" rerun | +| [**Nx Monorepo**](playwright/ci/nx/) | Playwright in an Nx workspace | ### Features @@ -52,8 +52,9 @@ Examples demonstrating Cypress integration with Currents. Examples for other test runners using Currents' generic reporters. -| Example | Description | -| :------------------------------------------------------------------- | :-------------------------------------- | -| [**Jest**](generic-reporter/jest/github-actions/) | Reporting Jest results to Currents | -| [**JUnit XML**](generic-reporter/junit/junit-xml/) | Uploading generic JUnit XML reports | -| [**Node.js / JUnit**](generic-reporter/junit/nodejs-github-actions/) | Node.js project reporting JUnit results | +| Example | Description | +| :------------------------------------------------------------------- | :------------------------------------------------------------------- | +| [**Jest**](generic-reporter/jest/github-actions/) | Reporting Jest results to Currents | +| [**Detox + Jest**](generic-reporter/jest/detox/) | React Native Detox tests with videos, screenshots, steps and retries | +| [**JUnit XML**](generic-reporter/junit/junit-xml/) | Uploading generic JUnit XML reports | +| [**Node.js / JUnit**](generic-reporter/junit/nodejs-github-actions/) | Node.js project reporting JUnit results | diff --git a/generic-reporter/jest/detox/.detoxrc.js b/generic-reporter/jest/detox/.detoxrc.js new file mode 100644 index 0000000..60eedd0 --- /dev/null +++ b/generic-reporter/jest/detox/.detoxrc.js @@ -0,0 +1,43 @@ +/** @type {Detox.DetoxConfig} */ +module.exports = { + testRunner: { + args: { + $0: "jest", + config: "e2e/jest.config.js", + }, + jest: { + setupTimeout: 240000, + }, + }, + artifacts: { + plugins: { + // Logs also make Detox write detox.trace.json, which currents upload sends with the run. + log: "all", + screenshot: "failing", + video: "failing", + }, + }, + apps: { + "android.release": { + type: "android.apk", + binaryPath: "android/app/build/outputs/apk/release/app-release.apk", + build: + "cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release", + }, + }, + devices: { + emulator: { + type: "android.emulator", + device: { avdName: process.env.DETOX_AVD_NAME || "Pixel_7_API_34" }, + }, + // An emulator that is already running, such as the one CI starts. + attached: { + type: "android.attached", + device: { adbName: ".*" }, + }, + }, + configurations: { + "android.emu.release": { device: "emulator", app: "android.release" }, + "android.att.release": { device: "attached", app: "android.release" }, + }, +}; diff --git a/generic-reporter/jest/detox/.gitignore b/generic-reporter/jest/detox/.gitignore new file mode 100644 index 0000000..26115f5 --- /dev/null +++ b/generic-reporter/jest/detox/.gitignore @@ -0,0 +1,79 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +**/.xcode.env.local + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml +*.hprof +.cxx/ +*.keystore +!debug.keystore +.kotlin/ + +# node.js +# +node_modules/ +npm-debug.log +yarn-error.log + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/ + +**/fastlane/report.xml +**/fastlane/Preview.html +**/fastlane/screenshots +**/fastlane/test_output + +# Bundle artifact +*.jsbundle + +# Ruby / CocoaPods +**/Pods/ +/vendor/bundle/ + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* + +# testing +/coverage + +# Yarn +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Detox and Currents output +artifacts/ +.currents/ diff --git a/generic-reporter/jest/detox/.watchmanconfig b/generic-reporter/jest/detox/.watchmanconfig new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/generic-reporter/jest/detox/.watchmanconfig @@ -0,0 +1 @@ +{} diff --git a/generic-reporter/jest/detox/App.tsx b/generic-reporter/jest/detox/App.tsx new file mode 100644 index 0000000..80aa177 --- /dev/null +++ b/generic-reporter/jest/detox/App.tsx @@ -0,0 +1,96 @@ +import { useState } from "react"; +import { Button, StyleSheet, Text, TextInput, View } from "react-native"; +import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context"; + +const PASSWORD = "currents"; + +function App() { + const [user, setUser] = useState(null); + + return ( + + + {user ? ( + setUser(null)} /> + ) : ( + + )} + + + ); +} + +function Login({ onLogin }: { onLogin: (email: string) => void }) { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(false); + + const submit = () => { + if (email && password === PASSWORD) { + onLogin(email); + } else { + setError(true); + } + }; + + return ( + + Sign in + + + {error && ( + + Wrong email or password + + )} +