Skip to content

[WIP] E2E Test: Add tests for running real RN app #312

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
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
6 changes: 6 additions & 0 deletions __e2e__/TestApp/.buckconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

[android]
target = Google Inc.:Google APIs:23

[maven_repositories]
central = https://repo1.maven.org/maven2
5 changes: 5 additions & 0 deletions __e2e__/TestApp/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"globals": {
"__DEV__": true
}
}
70 changes: 70 additions & 0 deletions __e2e__/TestApp/.flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js

; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/

; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*

; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
.*/Libraries/react-native/React.js

; Ignore polyfills
.*/Libraries/polyfills/.*

; Ignore metro
.*/node_modules/metro/.*

[include]

[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow/
node_modules/react-native/flow-github/

[options]
emoji=true

esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable

module.system=haste
module.system.haste.use_name_reducers=true
# get basename
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
# strip .js or .js.flow suffix
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
# strip .ios suffix
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
module.system.haste.paths.blacklist=.*/__tests__/.*
module.system.haste.paths.blacklist=.*/__mocks__/.*
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*

munge_underscores=true

module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'

module.file_ext=.js
module.file_ext=.jsx
module.file_ext=.json
module.file_ext=.native.js

suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState

suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError

[version]
^0.86.0
1 change: 1 addition & 0 deletions __e2e__/TestApp/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pbxproj -text
59 changes: 59 additions & 0 deletions __e2e__/TestApp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# OSX
#
.DS_Store

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
project.xcworkspace

# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml

# node.js
#
node_modules/
npm-debug.log
yarn-error.log

# BUCK
buck-out/
\.buckd/
*.keystore

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/

*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots

# Bundle artifact
*.jsbundle

# Detox artifacts
artifacts/
1 change: 1 addition & 0 deletions __e2e__/TestApp/.watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
6 changes: 6 additions & 0 deletions __e2e__/TestApp/__e2e__/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"globals": {
"simctl": true,
"rndebugger": true
}
}
104 changes: 104 additions & 0 deletions __e2e__/TestApp/__e2e__/app.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { expect as dExpect, element, by, device } from 'detox';
import { delay } from '../../utils';

describe('Main', () => {
beforeEach(async () => {
const { client } = rndebugger;
await client.execute(() => (window.confirm = () => true));
await device.reloadReactNative();
await delay(500);
});

it('should open the app', async () => {
await dExpect(element(by.id('home'))).toBeVisible();
const title = await rndebugger.browserWindow.getTitle();
expect(title).toBe('React Native Debugger - Connected (port 8081)');
});

const delay200 = () => delay(200);
const delay500 = () => delay(500);

describe('Context Menu', () => {
it('should show AsyncStorage content as expected', async () => {
const { client } = rndebugger;
await client.execute(() => window.invokeDevMethod('showAsyncStorage')).then(delay200);
let logs = await client.getRenderProcessLogs();
// Print renderer process logs
expect(
logs.some(log => log.message.indexOf('[RNDebugger] No AsyncStorage content.') > -1)
).toBeTruthy();

await element(by.id('navigate-context-menu'))
.tap()
.then(delay200);

await client.execute(() => window.invokeDevMethod('showAsyncStorage')).then(delay200);
logs = await client.getRenderProcessLogs();
expect(logs.some(log => log.message.indexOf('[object Object]') > -1)).toBeTruthy();
});

it('should clear AsyncStorage as expected', async () => {
const { client } = rndebugger;

await element(by.id('navigate-context-menu'))
.tap()
.then(delay500);

await client.execute(() => window.invokeDevMethod('clearAsyncStorage')).then(delay500);
await client.execute(() => window.invokeDevMethod('showAsyncStorage')).then(delay200);
const logs = await client.getRenderProcessLogs();
expect(
logs.some(log => log.message.indexOf('[RNDebugger] No AsyncStorage content.') > -1)
).toBeTruthy();
});

it('should send Network request as expected if Network Inspsect enabled', async () => {
const { client } = rndebugger;

await element(by.id('navigate-context-menu'))
.tap()
.then(delay500);
await element(by.id('send-request'))
.tap()
.then(delay200);

await client.execute(() => window.invokeDevMethod('networkInspect')).then(delay200);
const logs = await client.getRenderProcessLogs();
expect(
logs.some(
log =>
// NOTE: https://github.com/electron/spectron/issues/282
log.message.indexOf('[RNDebugger]') > -1
)
).toBeTruthy();
});
});

describe('React DevTools', () => {
const waitingForReactConnect = client =>
client.waitUntilTextExists(
'#react-devtools-container > div > div:nth-child(1) > ul > li:nth-child(1)',
'Elements',
1000
);

it('should connected to React DevTools', async () => {
const { client } = rndebugger;
await waitingForReactConnect(client);
});

it('should reconnect to React DevTools if open the tab', async () => {
const { client } = rndebugger;
await waitingForReactConnect(client);
await rndebugger.webContents.send('toggle-devtools', 'react').then(delay500);

const logs = await client.getRenderProcessLogs();
expect(logs.some(log => log.message.indexOf('closing devtools') > -1)).toBeTruthy();

await rndebugger.webContents.send('toggle-devtools', 'react').then(() => delay(2000));

await client.getRenderProcessLogs();
await waitingForReactConnect(client);
});
});
});
4 changes: 4 additions & 0 deletions __e2e__/TestApp/__e2e__/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"setupTestFrameworkScriptFile": "./setup.js",
"testEnvironment": "node"
}
37 changes: 37 additions & 0 deletions __e2e__/TestApp/__e2e__/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* global jasmine device */

import childProcess from 'child_process';
import { promisify } from 'util';
import createApplication from '../../rndebugger';

/* eslint-disable import/no-unresolved */
const detox = require('detox');
const adapter = require('detox/runners/jest/adapter');
const { detox: config } = require('../package.json');

const exec = promisify(childProcess.exec);

global.simctl = {
pbcopy: (content, device = 'booted') => exec(`echo '${content}' | xcrun simctl pbcopy ${device}`),
};

jest.setTimeout(120000);
jasmine.getEnv().addReporter(adapter);

beforeAll(async () => {
global.rndebugger = createApplication('../../dist');
await rndebugger.start();
await detox.init(config, { initGlobals: false });
});

beforeEach(async () => {
await adapter.beforeEach();
});

afterAll(async () => {
if (rndebugger && rndebugger.isRunning()) {
await rndebugger.stop();
}
await adapter.afterAll();
await detox.cleanup();
});
55 changes: 55 additions & 0 deletions __e2e__/TestApp/android/app/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#

load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")

lib_deps = []

create_aar_targets(glob(["libs/*.aar"]))

create_jar_targets(glob(["libs/*.jar"]))

android_library(
name = "all-libs",
exported_deps = lib_deps,
)

android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)

android_build_config(
name = "build_config",
package = "com.testapp",
)

android_resource(
name = "res",
package = "com.testapp",
res = "src/main/res",
)

android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)
Loading