Skip to content

Commit

Permalink
feat: react-native android support (#777)
Browse files Browse the repository at this point in the history
  • Loading branch information
hugomrdias authored May 21, 2021
1 parent b215efd commit b4ae6be
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 6 deletions.
3 changes: 2 additions & 1 deletion md/github-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ jobs:
- uses: actions/checkout@v2
- uses: microsoft/playwright-github-action@v1
- run: npm install
- run: npx aegir test -t browser -t webworker --bail --cov
- run: npx aegir test -t browser --bail --cov
- run: npx aegir test -t webworker --bail
- uses: codecov/codecov-action@v1
test-firefox:
needs: check
Expand Down
94 changes: 94 additions & 0 deletions md/react-native.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# React Native Setup

## Boring and heavy way for all OSes

Go to https://reactnative.dev/docs/environment-setup click in "React Native CLI Quickstart" and follow instructions.

If you don't want to fill your system with the full android studio or XCode follow the instructions below but be aware that there are dragons ahead!

## Android

```bash
brew install --cask adoptopenjdk/openjdk/adoptopenjdk8
export ANDROID_SDK_ROOT="~/android-sdk"
touch ~/.android/repositories.cfg
```

Download `cmdline-tool` from [https://developer.android.com/studio#cmdline-tools](https://developer.android.com/studio#cmdline-tools) and extract to `~/android-sdk/cmdline-tools/latest`

```bash

~/android-sdk/cmdline-tools/latest/bin/sdkmanager --update
~/android-sdk/cmdline-tools/latest/bin/sdkmanager "platform-tools" "platforms;android-29" "build-tools;29.0.2" "system-images;android-29;default;x86_64"

// in your .zshrc or similar add sdk to PATH
PATH=$PATH:$ANDROID_SDK_ROOT/emulator
PATH=$PATH:$ANDROID_SDK_ROOT/tools
PATH=$PATH:$ANDROID_SDK_ROOT/tools/bin
PATH=$PATH:$ANDROID_SDK_ROOT/platform-tools
export PATH
```
Now all the tools are in the `$PATH` , no need for absolute paths anymore.

### Some examples

You normally dont need to run any of these

```bash
# install new platforms, build tools and system images
sdkmanager --update
sdkmanager "platforms;android-29" "build-tools;29.0.2" "system-images;android-29;default;x86_64"

# create an avd
avdmanager create avd -n aegir-android -d pixel --package "system-images;android-29;default;x86_64"

# delete avd
avdmanager delete avd -n aegir-android

# manually run the emulator
emulator @aegir-android

# list avds
emulator -list-avds

# redirect port trafic
adb -s emulator-5554 reverse tcp:3000 tcp:3000
adb reverse --list
adb reverse --remove-all
```
> If the internal aegir AVD changes SDK versions you might need to run the `sdkmanager` above to update and install the new SDK versions in your system.

### emulator acceleration (optional)

[https://developer.android.com/studio/run/emulator-acceleration#vm-mac](https://developer.android.com/studio/run/emulator-acceleration#vm-mac)

### Aegir config
Android needs special attention for networks settings ([docs](https://developer.android.com/studio/run/emulator-networking)). The most common change is to use the special address `10.0.2.2` to redirect trafic to your local loopback interface `127.0.0.1`.

```js
module.exports = {
test: {
async before (options) {
let echoServer = new EchoServer()
await echoServer.start()
const { address, port } = echoServer.server.address()
let hostname = address // address will normally be 127.0.0.1

if(options.runner === 'react-native-android') {
hostname = '10.0.2.2'
}

return {
echoServer,
env: { ECHO_SERVER : format({ protocol: 'http:', hostname, port })}
}
},
async after (options, before) {
await before.echoServer.stop()
}
}
}


```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
"polka": "^0.5.2",
"premove": "^3.0.1",
"proper-lockfile": "^4.1.2",
"react-native-test-runner": "^5.0.0",
"read-pkg-up": "^7.0.1",
"semver": "^7.3.5",
"simple-git": "^2.37.0",
Expand Down
2 changes: 1 addition & 1 deletion src/cmds/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ module.exports = {
alias: 't',
describe: 'In which target environment to execute the tests',
type: 'array',
choices: ['node', 'browser', 'webworker', 'electron-main', 'electron-renderer'],
choices: ['node', 'browser', 'webworker', 'electron-main', 'electron-renderer', 'react-native-android', 'react-native-ios'],
default: userConfig.test.target
},
watch: {
Expand Down
14 changes: 13 additions & 1 deletion src/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const pmap = require('p-map')
const node = require('./node')
const browser = require('./browser')
const electron = require('./electron')
const rn = require('./react-native')

/**
* @typedef {import("execa").Options} ExecaOptions
Expand Down Expand Up @@ -71,8 +72,19 @@ const TASKS = [
* @param {TestOptions & GlobalOptions} ctx
*/
enabled: (ctx) => ctx.target.includes('electron-renderer')
},
{
title: 'Test React Native Android',
/**
* @param {TestOptions & GlobalOptions} opts
* @param {ExecaOptions} execaOptions
*/
task: (opts, execaOptions) => rn({ ...opts, runner: 'react-native-android' }, execaOptions),
/**
* @param {TestOptions & GlobalOptions} ctx
*/
enabled: (ctx) => ctx.target.includes('react-native-android')
}

]

module.exports = {
Expand Down
101 changes: 101 additions & 0 deletions src/test/react-native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
'use strict'
const path = require('path')
const execa = require('execa')
const merge = require('merge-options')

/**
* @typedef {import("execa").Options} ExecaOptions
* @typedef {import('../types').TestOptions} TestOptions
* @typedef {import('../types').GlobalOptions} GlobalOptions
*/

/**
*
* @param {TestOptions & GlobalOptions} argv
* @param {ExecaOptions} execaOptions
*/
module.exports = async (argv, execaOptions) => {
const AVDName = 'aegir-android-29'
const extra = argv['--'] ? argv['--'] : []
const emulator = process.env.CI ? [] : ['--emulator', AVDName]
const forwardOptions = /** @type {string[]} */([
...extra,
argv.timeout && `--timeout=${argv.timeout}`,
argv.grep && `--grep=${argv.grep}`,
argv.bail && '--bail'
].filter(Boolean))
const files = argv.files.length > 0
? argv.files
: [
'**/*.spec.{js,ts}',
'test/browser.{js,ts}'
]

// before hook
const before = await argv.fileConfig.test.before(argv)
const beforeEnv = before && before.env ? before.env : {}

await checkAndroidEnv()

if (!await checkAvd(AVDName)) {
await execa('avdmanager', [
'create',
'avd',
'-n', AVDName,
'-d', 'pixel',
'--package', 'system-images;android-29;default;x86_64'
])
}

// run pw-test
await execa('rn-test',
[
...files,
'--platform', argv.runner === 'react-native-android' ? 'android' : 'ios',
...emulator,
'--reset-cache',
...forwardOptions
],
merge(
{
env: {
AEGIR_RUNNER: argv.runner,
NODE_ENV: process.env.NODE_ENV || 'test',
...beforeEnv
},
preferLocal: true,
localDir: path.join(__dirname, '../..'),
stdio: 'inherit'
},
execaOptions
)
)

// after hook
await argv.fileConfig.test.after(argv, before)
}

/**
* Check for avd
*
* @param {string} name
*/
async function checkAvd (name) {
const avd = await execa('emulator', ['-list-avds'])

return avd.stdout.split('\n').includes(name)
}

async function checkAndroidEnv () {
if (!process.env.ANDROID_SDK_ROOT) {
throw new Error('ANDROID_SDK_ROOT is not set')
}

try {
await execa('emulator', ['-help'])
// await execa('sdkmanager')
await execa('avdmanager', ['list'])
} catch (err) {
throw new Error(`"Command ${err.path}" is not available, you need to properly setup your android environment.`)
}
}
4 changes: 2 additions & 2 deletions src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ interface TestOptions {
/**
* In which target environment to execute the tests
*/
target: Array<'node' | 'browser' | 'webworker' | 'electron-main' | 'electron-renderer'>
target: Array<'node' | 'browser' | 'webworker' | 'electron-main' | 'electron-renderer' | 'react-native-android' | 'react-native-ios'>
/**
* Watch files for changes and rerun tests
*/
Expand Down Expand Up @@ -203,7 +203,7 @@ interface TestOptions {
/**
* Runner enviroment
*/
runner: 'node' | 'browser' | 'webworker' | 'electron-main' | 'electron-renderer'
runner: 'node' | 'browser' | 'webworker' | 'electron-main' | 'electron-renderer' | 'react-native-android' | 'react-native-ios'
/**
* Browser options
*/
Expand Down
2 changes: 1 addition & 1 deletion test/utils/echo-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('echo server spec', () => {

before(async () => {
await echo.start()
const { port, address } = /** @type {import('node:net').AddressInfo} */(echo.server.address())
const { port, address } = /** @type {import('net').AddressInfo} */(echo.server.address())
url = format({ protocol: 'http:', hostname: address, port })
})

Expand Down

0 comments on commit b4ae6be

Please sign in to comment.