Skip to content

Commit 98c091b

Browse files
committed
chore: Build RN example with detox.
1 parent 5ecdf31 commit 98c091b

File tree

7 files changed

+53
-58
lines changed

7 files changed

+53
-58
lines changed

.github/workflows/react-native.yml

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,9 @@ jobs:
2222
with:
2323
workspace_name: '@launchdarkly/react-native-client-sdk'
2424
workspace_path: packages/sdk/react-native
25-
detox-ios:
26-
# TODO: disable detox for now because it's unstable.
27-
if: false
28-
# macos-latest uses macos-12 and we need macos-14 to get xcode 15.
29-
# https://github.com/actions/runner-images/blob/main/README.md
30-
runs-on: macos-14
25+
26+
detox-android:
27+
runs-on: ubuntu-latest
3128
permissions:
3229
id-token: write
3330
contents: read
@@ -36,51 +33,51 @@ jobs:
3633
working-directory: packages/sdk/react-native/example
3734
steps:
3835
- uses: actions/checkout@v4
36+
3937
- name: Setup Node.js
4038
uses: actions/setup-node@v4
39+
40+
- name: Setup Java
41+
uses: actions/setup-java@v4
42+
with:
43+
cache: gradle
44+
distribution: temurin
45+
java-version: 17
46+
4147
- name: Install deps
4248
run: yarn workspaces focus
4349
- name: Build
4450
run: yarn workspaces foreach -pR --topological-dev --from 'react-native-example' run build
45-
- name: Install macOS dependencies
46-
run: |
47-
brew tap wix/brew
48-
brew install applesimutils
49-
env:
50-
HOMEBREW_NO_AUTO_UPDATE: 1
51-
HOMEBREW_NO_INSTALL_CLEANUP: 1
52-
53-
- name: Cache Detox build
54-
id: cache-detox-build
55-
uses: actions/cache@v4
56-
with:
57-
path: ios/build
58-
key: ${{ runner.os }}-detox-build
59-
restore-keys: |
60-
${{ runner.os }}-detox-build
61-
62-
- name: Detox rebuild framework cache
63-
run: yarn detox rebuild-framework-cache
6451

6552
- uses: ./actions/release-secrets
6653
name: 'Get mobile key'
6754
with:
68-
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}
55+
aws_assume_role: ${{ vars.AWS_ROLE_ARN_EXAMPLE }}
6956
ssm_parameter_pairs: '/sdk/detox/mobile-key = MOBILE_KEY'
7057

71-
- name: Set mobile key
72-
run: echo "MOBILE_KEY=$MOBILE_KEY" > .env
73-
74-
- name: Expo prebuild
75-
# HACK: Deleting ios/.xcode.env.local is needed to solve an xcode build issue with rn 0.73
76-
# https://github.com/facebook/react-native/issues/42112#issuecomment-1884536225
58+
- name: Enable KVM group perms (for performance)
7759
run: |
78-
export NO_FLIPPER=1
79-
yarn expo-prebuild
80-
rm -rf ./ios/.xcode.env.local
60+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
61+
sudo udevadm control --reload-rules
62+
sudo udevadm trigger --name-match=kvm
8163
8264
- name: Detox build
83-
run: yarn detox build --configuration ios.sim.release
65+
run: yarn detox build --configuration android.emu.release
66+
67+
- name: Get android emulator device name
68+
id: device
69+
run: node -e "console.log('AVD_NAME=' + require('./.detoxrc').devices.emulator.device.avdName)" >> $GITHUB_OUTPUT
8470

8571
- name: Detox test
86-
run: yarn detox test --configuration ios.sim.release --cleanup --headless --record-logs all --take-screenshots failing
72+
uses: reactivecircus/android-emulator-runner@a3dcdb348bb02349cd939d168a74e31a9094b7f0
73+
with:
74+
api-level: 31
75+
arch: x86_64
76+
avd-name: ${{ steps.device.outputs.AVD_NAME }}
77+
script: yarn detox test --configuration android.emu.release --headless --record-logs all
78+
79+
- name: Upload artifacts
80+
uses: actions/upload-artifact@v3
81+
with:
82+
name: detox-artifacts
83+
path: artifacts

packages/sdk/react-native/example/.detoxrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ module.exports = {
5050
emulator: {
5151
type: 'android.emulator',
5252
device: {
53-
avdName: 'Pixel_3a_API_33_arm64-v8a',
53+
avdName: 'Pixel_4_API_30',
5454
},
5555
},
5656
},

packages/sdk/react-native/example/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ ios
3939
android
4040

4141
!yarn.lock
42+
43+
# detox
44+
artifacts

packages/sdk/react-native/example/app.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
},
2626
"web": {
2727
"favicon": "./assets/favicon.png"
28-
}
28+
},
29+
"plugins": ["@config-plugins/detox"]
2930
}
3031
}

packages/sdk/react-native/example/e2e/starter.test.ts

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,35 @@
11
import { by, device, element, expect, waitFor } from 'detox';
22

3-
describe('Example', () => {
3+
describe('given the example application', () => {
44
beforeAll(async () => {
55
await device.launchApp({
66
newInstance: true,
77
launchArgs: {
8-
detoxURLBlacklistRegex: '\\("^https://clientstream.launchdarkly.com/meval"\\)',
8+
// Detox will wait for HTTP requests to complete. This prevents detox from waiting for
9+
// requests matching this URL to complete.
10+
detoxURLBlacklistRegex: '\\("^https://clientstream.launchdarkly.com/meval.*"\\)',
911
},
1012
});
1113
});
1214

13-
// For speed, all tests are sequential and dependent.
14-
// beforeEach(async () => {
15-
// await device.reloadReactNative();
16-
// });
17-
18-
afterAll(async () => {
19-
await device.terminateApp();
20-
});
21-
22-
test('app loads and renders correctly', async () => {
15+
it('loads and renders correctly with default values', async () => {
2316
await expect(element(by.text(/welcome to launchdarkly/i))).toBeVisible();
24-
await expect(element(by.text(/my-boolean-flag-1: false/i))).toBeVisible();
17+
await expect(element(by.text(/sample-feature: false/i))).toBeVisible();
2518
});
2619

27-
test('identify', async () => {
20+
it('can identify and evaluate with non-default values', async () => {
2821
await element(by.id('userKey')).typeText('test-user');
2922
await element(by.text(/identify/i)).tap();
3023

31-
await waitFor(element(by.text(/my-boolean-flag-1: true/i)))
24+
await waitFor(element(by.text(/sample-feature: true/i)))
3225
.toBeVisible()
3326
.withTimeout(2000);
3427
});
3528

36-
test('variation', async () => {
37-
await element(by.id('flagKey')).replaceText('my-boolean-flag-2');
29+
it('can set a flag and has defaults for a non-existent flag', async () => {
30+
await element(by.id('flagKey')).replaceText('not-found-flag');
3831

39-
await waitFor(element(by.text(/my-boolean-flag-2: true/i)))
32+
await waitFor(element(by.text(/not-found-flag: false/i)))
4033
.toBeVisible()
4134
.withTimeout(2000);
4235
});

packages/sdk/react-native/example/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
},
3232
"devDependencies": {
3333
"@babel/core": "^7.20.0",
34+
"@config-plugins/detox": "^8.0.0",
3435
"@types/detox": "^18.1.0",
3536
"@types/jest": "^29.5.11",
3637
"@types/node": "^20.10.5",

packages/sdk/react-native/example/src/welcome.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ConnectionMode } from '@launchdarkly/js-client-sdk-common';
55
import { useBoolVariation, useLDClient } from '@launchdarkly/react-native-client-sdk';
66

77
export default function Welcome() {
8-
const [flagKey, setFlagKey] = useState('my-boolean-flag-1');
8+
const [flagKey, setFlagKey] = useState('sample-feature');
99
const [userKey, setUserKey] = useState('');
1010
const flagValue = useBoolVariation(flagKey, false);
1111
const ldc = useLDClient();

0 commit comments

Comments
 (0)