Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/actions/androidapp-road-test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -414,5 +414,6 @@ runs:
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ inputs.e2e-artifact-name }}-${{ inputs.flavor }}-android
path: apps/AndroidApp/artifacts
if-no-files-found: ignore
path: apps/AndroidApp/e2e-artifacts
if-no-files-found: warn
retention-days: 5
3 changes: 3 additions & 0 deletions apps/AndroidApp/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
.externalNativeBuild
.cxx
local.properties

# Detox E2E artifacts (logcat, screenshots, failure diagnostics)
/e2e-artifacts
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
'use strict';

const { resolveAndroidDetoxDevice } = require('./detox-android-emulator-device.cjs');
const { getDetoxArtifactsConfig } = require('./detox-artifacts-config.cjs');

/**
* Shared Detox artifacts, minus video.
*
* The shared helper enables video for iOS simulators, where Detox records
* host-side via `simctl io recordVideo`. On Android it would record with
* `adb shell screenrecord`, writing into the emulator userdata partition —
* the partition androidapp-road-test already documents as ENOSPC-prone
* ("Do not set disk-size — a large userdata partition fails when the runner
* is low on disk after Gradle/NDK builds"). Logcat, screenshots and the
* UI hierarchy give us what we need without that risk.
*
* @returns {import('detox').DetoxArtifactsConfig}
*/
function buildAndroidArtifactsConfig() {
const shared = getDetoxArtifactsConfig();

return {
...shared,
plugins: {
...shared.plugins,
video: { enabled: false },
},
};
}

/**
* Detox Android emulator release config for AndroidApp (native Gradle consumer).
Expand Down Expand Up @@ -41,6 +67,7 @@ function createAndroidAppEmulatorReleaseDetoxConfig({
setupTimeout: 300000,
},
},
artifacts: buildAndroidArtifactsConfig(),
behavior: {
cleanup: {
// CI owns emulator lifecycle via android-emulator-runner.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const assert = require('node:assert/strict');
const test = require('node:test');

const {
getDetoxArtifactsConfig,
} = require('./detox-artifacts-config.cjs');
const {
createAndroidAppEmulatorReleaseDetoxConfig,
} = require('./detox-rc-androidapp-emulator-release.cjs');

test('writes artifacts where CI uploads from, matching the iOS convention', () => {
const config = createAndroidAppEmulatorReleaseDetoxConfig({
gradleFlavor: 'expo56',
});

assert.equal(config.artifacts.rootDir, 'e2e-artifacts');
assert.equal(config.artifacts.rootDir, getDetoxArtifactsConfig().rootDir);
});

test('captures logcat only for failed tests', () => {
const config = createAndroidAppEmulatorReleaseDetoxConfig({
gradleFlavor: 'expo56',
});

// Detox shorthand: record the log plugin, keep it only for failing tests.
assert.equal(config.artifacts.plugins.log, 'failing');
});

test('captures a screenshot when a test finishes failing', () => {
const config = createAndroidAppEmulatorReleaseDetoxConfig({
gradleFlavor: 'expo56',
});

assert.equal(
config.artifacts.plugins.screenshot.keepOnlyFailedTestsArtifacts,
true
);
assert.equal(config.artifacts.plugins.screenshot.takeWhen.testDone, true);
});

test('keeps video off on Android', () => {
const config = createAndroidAppEmulatorReleaseDetoxConfig({
gradleFlavor: 'expo56',
});

// The shared helper enables video for iOS simulators (simctl, host-side).
// On Android it would be `adb shell screenrecord` writing into the emulator
// userdata partition — the partition the road-test action already documents
// as ENOSPC-prone ("Do not set disk-size ... low on disk after Gradle/NDK
// builds"). Keep it off here; iOS is unaffected.
assert.equal(config.artifacts.plugins.video.enabled, false);
assert.equal(getDetoxArtifactsConfig().plugins.video.enabled, true);
});

test('inherits the remaining shared artifact plugins', () => {
const config = createAndroidAppEmulatorReleaseDetoxConfig({
gradleFlavor: 'expo56',
});

assert.equal(
config.artifacts.plugins.uiHierarchy,
getDetoxArtifactsConfig().plugins.uiHierarchy
);
});

test('keeps the existing app and device wiring intact', () => {
const config = createAndroidAppEmulatorReleaseDetoxConfig({
gradleFlavor: 'expo56',
detoxConfiguration: 'android.emu.release.expo56',
jestConfigPath: 'e2e/jest.config.expo56.cjs',
});

assert.equal(
config.apps['android.release'].binaryPath,
'app/build/outputs/apk/expo56/release/app-expo56-release.apk'
);
assert.equal(config.apps['android.release'].launchTimeout, 300000);
assert.equal(config.behavior.cleanup.shutdownDevice, false);
assert.ok(config.configurations['android.emu.release.expo56']);
});
Loading