Skip to content

Commit fcb821e

Browse files
authored
chore: Build RN example with detox. (#558)
1 parent 7064b07 commit fcb821e

File tree

8 files changed

+117
-84
lines changed

8 files changed

+117
-84
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
name: sdk/react-native/example
2+
3+
# The example builds independently of react-native because of the duration of the build.
4+
# We limit it to only build under specific circumstances.
5+
# Additionally this does allow for scheduled builds of just the example, to handle changes in expo,
6+
# should they be desired.
7+
8+
on:
9+
push:
10+
branches: [main, 'feat/**']
11+
paths-ignore:
12+
- '**.md' #Do not need to run CI for markdown changes.
13+
pull_request:
14+
branches: [main, 'feat/**']
15+
paths:
16+
- 'packages/shared/common/**'
17+
- 'packages/shared/sdk-client/**'
18+
- 'packages/sdk/react-native/**'
19+
- 'packages/shared/mocks/**'
20+
21+
jobs:
22+
detox-android:
23+
runs-on: ubuntu-latest
24+
permissions:
25+
id-token: write
26+
contents: read
27+
defaults:
28+
run:
29+
working-directory: packages/sdk/react-native/example
30+
steps:
31+
- uses: actions/checkout@v4
32+
33+
- name: Setup Node.js
34+
uses: actions/setup-node@v4
35+
36+
- name: Install deps
37+
run: yarn workspaces focus
38+
- name: Build
39+
run: yarn workspaces foreach -pR --topological-dev --from 'react-native-example' run build
40+
41+
- uses: ./actions/release-secrets
42+
name: 'Get mobile key'
43+
with:
44+
aws_assume_role: ${{ vars.AWS_ROLE_ARN_EXAMPLES }}
45+
ssm_parameter_pairs: '/sdk/common/hello-apps/mobile-key = MOBILE_KEY,
46+
/sdk/common/hello-apps/boolean-flag-key = LAUNCHDARKLY_FLAG_KEY'
47+
48+
- name: Create .env file.
49+
run: echo "MOBILE_KEY=$MOBILE_KEY" > .env
50+
51+
- name: Enable KVM group perms (for performance)
52+
run: |
53+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
54+
sudo udevadm control --reload-rules
55+
sudo udevadm trigger --name-match=kvm
56+
57+
- name: Expo Prebuild
58+
run: npx expo prebuild
59+
60+
# Java setup is after checkout and expo prebuild so that it can locate the
61+
# gradle configuration.
62+
- name: Setup Java
63+
uses: actions/setup-java@v4
64+
with:
65+
distribution: temurin
66+
java-version: 17
67+
cache: 'gradle'
68+
69+
- name: Detox build
70+
run: yarn detox build --configuration android.emu.release
71+
72+
- name: Get android emulator device name
73+
id: device
74+
run: node -e "console.log('AVD_NAME=' + require('./.detoxrc').devices.emulator.device.avdName)" >> $GITHUB_OUTPUT
75+
76+
- name: Make space for the emulator.
77+
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
78+
with:
79+
android: false # We need android.
80+
81+
- name: Detox test
82+
uses: reactivecircus/android-emulator-runner@f0d1ed2dcad93c7479e8b2f2226c83af54494915
83+
with:
84+
api-level: 31
85+
arch: x86_64
86+
avd-name: ${{ steps.device.outputs.AVD_NAME }}
87+
working-directory: packages/sdk/react-native/example
88+
script: yarn detox test --configuration android.emu.release --headless --record-logs all
89+
90+
- name: Upload artifacts
91+
if: always()
92+
uses: actions/upload-artifact@v4
93+
with:
94+
name: detox-artifacts
95+
path: packages/sdk/react-native/example/artifacts

.github/workflows/react-native.yml

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -22,65 +22,3 @@ 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
31-
permissions:
32-
id-token: write
33-
contents: read
34-
defaults:
35-
run:
36-
working-directory: packages/sdk/react-native/example
37-
steps:
38-
- uses: actions/checkout@v4
39-
- name: Setup Node.js
40-
uses: actions/setup-node@v4
41-
- name: Install deps
42-
run: yarn workspaces focus
43-
- name: Build
44-
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
64-
65-
- uses: ./actions/release-secrets
66-
name: 'Get mobile key'
67-
with:
68-
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}
69-
ssm_parameter_pairs: '/sdk/detox/mobile-key = MOBILE_KEY'
70-
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
77-
run: |
78-
export NO_FLIPPER=1
79-
yarn expo-prebuild
80-
rm -rf ./ios/.xcode.env.local
81-
82-
- name: Detox build
83-
run: yarn detox build --configuration ios.sim.release
84-
85-
- name: Detox test
86-
run: yarn detox test --configuration ios.sim.release --cleanup --headless --record-logs all --take-screenshots failing

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: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,37 @@
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 () => {
28-
await element(by.id('userKey')).typeText('test-user');
20+
it('can identify and evaluate with non-default values', async () => {
21+
const featureFlagKey = process.env.LAUNCHDARKLY_FLAG_KEY ?? 'sample-feature';
22+
await element(by.id('userKey')).typeText('example-user-key');
23+
await element(by.id('flagKey')).replaceText(featureFlagKey);
2924
await element(by.text(/identify/i)).tap();
3025

31-
await waitFor(element(by.text(/my-boolean-flag-1: true/i)))
26+
await waitFor(element(by.text(new RegExp(`${featureFlagKey}: true`))))
3227
.toBeVisible()
3328
.withTimeout(2000);
3429
});
3530

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

39-
await waitFor(element(by.text(/my-boolean-flag-2: true/i)))
34+
await waitFor(element(by.text(/not-found-flag: false/i)))
4035
.toBeVisible()
4136
.withTimeout(2000);
4237
});

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)