Skip to content

Commit f5c9e4c

Browse files
committed
feat: initialize e2etest project with Detox integration and automated build workflows
1 parent ee83de3 commit f5c9e4c

95 files changed

Lines changed: 8164 additions & 10 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Example/e2etest/.detoxrc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
require('ts-node/register/transpile-only');
2+
3+
module.exports = require('./.detoxrc.ts').default;

Example/e2etest/.detoxrc.ts

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import { execSync } from 'node:child_process';
2+
3+
function detectIosSimulatorType() {
4+
if (process.env.DETOX_IOS_DEVICE_TYPE) {
5+
return process.env.DETOX_IOS_DEVICE_TYPE;
6+
}
7+
8+
if (process.platform !== 'darwin') {
9+
return 'iPhone 14';
10+
}
11+
12+
try {
13+
const output = execSync('xcrun simctl list devices available', {
14+
stdio: ['ignore', 'pipe', 'ignore'],
15+
}).toString();
16+
17+
const lines = output
18+
.split('\n')
19+
.map(line => line.trim())
20+
.filter(Boolean);
21+
22+
const preferredPrefixes = ['iPhone 17', 'iPhone 16', 'iPhone 15', 'iPhone 14'];
23+
24+
for (const prefix of preferredPrefixes) {
25+
const line = lines.find(item => item.startsWith(prefix) && item.includes('('));
26+
if (line) {
27+
return line.split(' (')[0];
28+
}
29+
}
30+
31+
const fallbackLine = lines.find(
32+
item => item.startsWith('iPhone ') && item.includes('('),
33+
);
34+
if (fallbackLine) {
35+
return fallbackLine.split(' (')[0];
36+
}
37+
} catch {
38+
// fall through to default
39+
}
40+
41+
return 'iPhone 14';
42+
}
43+
44+
function detectAndroidAvdName() {
45+
if (process.env.DETOX_AVD_NAME) {
46+
return process.env.DETOX_AVD_NAME;
47+
}
48+
49+
if (process.platform !== 'darwin' && process.platform !== 'linux') {
50+
return 'Pixel_3a_API_33_arm64-v8a';
51+
}
52+
53+
try {
54+
const output = execSync('emulator -list-avds', {
55+
stdio: ['ignore', 'pipe', 'ignore'],
56+
}).toString();
57+
const avds = output
58+
.split('\n')
59+
.map(line => line.trim())
60+
.filter(Boolean);
61+
if (avds.length > 0) {
62+
return avds[0];
63+
}
64+
} catch {
65+
// fall through to default
66+
}
67+
68+
return 'Pixel_3a_API_33_arm64-v8a';
69+
}
70+
71+
const iosSimulatorType = detectIosSimulatorType();
72+
const androidAvdName = detectAndroidAvdName();
73+
const iosSimulatorArch = process.arch === 'arm64' ? 'arm64' : 'x86_64';
74+
const iosBuildBase =
75+
'xcodebuild -workspace ios/AwesomeProject.xcworkspace -UseNewBuildSystem=NO -scheme AwesomeProject -sdk iphonesimulator -destination "generic/platform=iOS Simulator" -derivedDataPath ios/build';
76+
77+
const config = {
78+
logger: {
79+
level: process.env.CI ? 'debug' : undefined,
80+
},
81+
testRunner: {
82+
args: {
83+
config: 'e2e/jest.config.js',
84+
maxWorkers: process.env.CI ? 2 : undefined,
85+
_: ['e2e'],
86+
},
87+
},
88+
artifacts: {
89+
plugins: {
90+
log: process.env.CI ? 'failing' : undefined,
91+
screenshot: process.env.CI ? 'failing' : undefined,
92+
},
93+
},
94+
apps: {
95+
'ios.debug': {
96+
type: 'ios.app',
97+
binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/AwesomeProject.app',
98+
build: `${iosBuildBase} -configuration Debug ARCHS=${iosSimulatorArch} ONLY_ACTIVE_ARCH=YES`,
99+
start: 'scripts/start-rn.sh ios',
100+
},
101+
'ios.release': {
102+
type: 'ios.app',
103+
binaryPath:
104+
'ios/build/Build/Products/Release-iphonesimulator/AwesomeProject.app',
105+
build:
106+
`export RCT_NO_LAUNCH_PACKAGER=true && ${iosBuildBase} -configuration Release ARCHS=${iosSimulatorArch} ONLY_ACTIVE_ARCH=YES -quiet`,
107+
},
108+
'android.debug': {
109+
type: 'android.apk',
110+
binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
111+
build:
112+
'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug',
113+
start: 'scripts/start-rn.sh android',
114+
reversePorts: [8081],
115+
},
116+
'android.release': {
117+
type: 'android.apk',
118+
binaryPath: 'android/app/build/outputs/apk/release/app-release.apk',
119+
build:
120+
'cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release',
121+
},
122+
},
123+
devices: {
124+
simulator: {
125+
type: 'ios.simulator',
126+
device: {
127+
type: iosSimulatorType,
128+
},
129+
},
130+
attached: {
131+
type: 'android.attached',
132+
device: {
133+
adbName: '.*',
134+
},
135+
},
136+
emulator: {
137+
type: 'android.emulator',
138+
device: {
139+
avdName: androidAvdName,
140+
},
141+
},
142+
},
143+
configurations: {
144+
'ios.sim.debug': {
145+
device: 'simulator',
146+
app: 'ios.debug',
147+
},
148+
'ios.sim.release': {
149+
device: 'simulator',
150+
app: 'ios.release',
151+
},
152+
'android.att.debug': {
153+
device: 'attached',
154+
app: 'android.debug',
155+
},
156+
'android.att.release': {
157+
device: 'attached',
158+
app: 'android.release',
159+
},
160+
'android.emu.debug': {
161+
device: 'emulator',
162+
app: 'android.debug',
163+
},
164+
'android.emu.release': {
165+
device: 'emulator',
166+
app: 'android.release',
167+
},
168+
},
169+
};
170+
171+
export default config;

Example/e2etest/.eslintrc.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
root: true,
3+
extends: '@react-native',
4+
};

Example/e2etest/.gitignore

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# OSX
2+
#
3+
.DS_Store
4+
5+
# Xcode
6+
#
7+
build/
8+
*.pbxuser
9+
!default.pbxuser
10+
*.mode1v3
11+
!default.mode1v3
12+
*.mode2v3
13+
!default.mode2v3
14+
*.perspectivev3
15+
!default.perspectivev3
16+
xcuserdata
17+
*.xccheckout
18+
*.moved-aside
19+
DerivedData
20+
*.hmap
21+
*.ipa
22+
*.xcuserstate
23+
ios/.xcode.env.local
24+
25+
# Android/IntelliJ
26+
#
27+
build/
28+
.idea
29+
.gradle
30+
local.properties
31+
*.iml
32+
*.hprof
33+
.kotlin/
34+
35+
# node.js
36+
#
37+
node_modules/
38+
npm-debug.log
39+
yarn-error.log
40+
41+
# BUCK
42+
buck-out/
43+
\.buckd/
44+
*.keystore
45+
!debug.keystore
46+
47+
# fastlane
48+
#
49+
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
50+
# screenshots whenever they are needed.
51+
# For more information about the recommended setup visit:
52+
# https://docs.fastlane.tools/best-practices/source-control/
53+
54+
**/fastlane/report.xml
55+
**/fastlane/Preview.html
56+
**/fastlane/screenshots
57+
**/fastlane/test_output
58+
59+
# Bundle artifact
60+
*.jsbundle
61+
62+
# Ruby / CocoaPods
63+
/ios/Pods/
64+
/vendor/bundle/
65+
66+
# react-native-update
67+
.update
68+
.pushy
69+
# react-native-update
70+
.cresc.token
71+
.cresc.temp
72+
.e2e-artifacts/
73+
artifacts/
74+
.detox/
75+
coverage/
76+
android/app/.cxx/
77+
*.xcresult
78+
result*.xml

Example/e2etest/.prettierrc.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
arrowParens: 'avoid',
3+
singleQuote: true,
4+
trailingComma: 'all',
5+
};

Example/e2etest/.watchmanconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

Example/e2etest/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# e2etest
2+
3+
`e2etest` 是专门给 Detox 用的 React Native example,不承担手工演示职责。
4+
5+
验证链路固定为:
6+
7+
- 本地 `react-native-update-cli` 生成全量包、`diff` 和 Android `pdiff`
8+
- 本地 Bun server 提供 `checkUpdate` 接口和静态产物
9+
- App 侧 `Pushy` client 直接指向本地 endpoint
10+
- `checkUpdate + silentAndNow` 触发自动下载和切包
11+
12+
常用命令:
13+
14+
```sh
15+
bun install
16+
detox build --configuration ios.sim.release
17+
E2E_PLATFORM=ios detox test --configuration ios.sim.release
18+
```
19+
20+
```sh
21+
bun install
22+
detox build --configuration android.emu.release
23+
E2E_PLATFORM=android detox test --configuration android.emu.release --headless --record-logs all
24+
```
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @format
3+
*/
4+
5+
import 'react-native';
6+
import React from 'react';
7+
import App from '../App';
8+
9+
// Note: test renderer must be required after react-native.
10+
import renderer from 'react-test-renderer';
11+
12+
it('renders correctly', () => {
13+
renderer.create(<App />);
14+
});

Example/e2etest/android/app/_BUCK

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# To learn about Buck see [Docs](https://buckbuild.com/).
2+
# To run your application with Buck:
3+
# - install Buck
4+
# - `npm start` - to start the packager
5+
# - `cd android`
6+
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7+
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8+
# - `buck install -r android/app` - compile, install and run application
9+
#
10+
11+
load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
12+
13+
lib_deps = []
14+
15+
create_aar_targets(glob(["libs/*.aar"]))
16+
17+
create_jar_targets(glob(["libs/*.jar"]))
18+
19+
android_library(
20+
name = "all-libs",
21+
exported_deps = lib_deps,
22+
)
23+
24+
android_library(
25+
name = "app-code",
26+
srcs = glob([
27+
"src/main/java/**/*.java",
28+
]),
29+
deps = [
30+
":all-libs",
31+
":build_config",
32+
":res",
33+
],
34+
)
35+
36+
android_build_config(
37+
name = "build_config",
38+
package = "com.awesomeproject",
39+
)
40+
41+
android_resource(
42+
name = "res",
43+
package = "com.awesomeproject",
44+
res = "src/main/res",
45+
)
46+
47+
android_binary(
48+
name = "app",
49+
keystore = "//android/keystores:debug",
50+
manifest = "src/main/AndroidManifest.xml",
51+
package_type = "debug",
52+
deps = [
53+
":app-code",
54+
],
55+
)

0 commit comments

Comments
 (0)