I'm attempting to create an automated UI test suite for my React Native app with Expo. I have looked everywhere for good tutorials but when I get to the actual test writing portion, my tests never even run because of environment issues such as "Unexpected Identifier/Token" on import Icon from...
or other stupid issues that I cannot find any tutorials on how to fix them. I literally have spent a week trying to resolve these issues.
I am new to React Native and new to Jest/Detox/Expo
Here's my package.json
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"test": "node_modules/.bin/jest test/**/*.spec.js",
"eject": "expo eject"
},
"jest": {
"verbose": true,
"preset": "jest-expo"
},
"dependencies": {
"apsl-react-native-button": "^3.1.1",
"react": "16.5.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
"react-native-camera": "git+https://git@github.com/react-native-community/react-native-camera.git",
"react-native-camera-roll-picker": "^1.2.3",
"react-native-elements": "^1.0.0",
"react-native-fontawesome": "^6.0.1",
"react-native-is-iphonex": "^1.0.1",
"react-native-vector-icons": "^6.2.0",
"react-navigation": "^3.1.5"
},
"devDependencies": {
"babel-preset-expo": "^5.0.0",
"bunyan-debug-stream": "^2.0.0",
"detox": "^10.0.9",
"detox-expo-helpers": "^0.6.0",
"expo-detox-hook": "^1.0.10",
"jest-expo": "^32.0.0",
"react-native-testing-library": "^1.5.0",
"react-test-renderer": "^16.8.2",
"babel-jest": "^24.1.0",
"enzyme": "^3.9.0",
"@babel/core": "^7.3.3",
"@expo/vector-icons": "^9.0.0",
"expo": "^32.0.0",
"jest": "^24.1.0"
},
"private": true,
"detox": {
"test-runner": "jest",
"configurations": {
"ios.sim": {
"binaryPath": "bin/Exponent.app",
"type": "ios.simulator",
"name": "iPhone X"
}
}
}
}
Here are the errors I'm getting
ip-10-101-32-118:KitchenProject bob.dole$ detox test --loglevel trace
configuration="ios.sim" loglevel="trace" artifactsLocation="artifacts/ios.sim.2019-02-21 21-54-14Z" node_modules/.bin/jest "e2e" --config=e2e/config.json --maxWorkers=1 '--testNamePattern=^((?!:android:).)*$'
● Deprecation Warning:
Option "setupTestFrameworkScriptFile" was replaced by configuration "setupFilesAfterEnv", which supports multiple paths.
Please update your configuration.
Configuration Documentation:
https://jestjs.io/docs/configuration.html
FAIL e2e/RoomLayout.spec.js
● Test suite failed to run
/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/@expo/vector-icons/FontAwesome.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import glyphMap from './vendor/react-native-vector-icons/glyphmaps/FontAwesome.json';
^^^^^^^^
SyntaxError: Unexpected identifier
> 1 | import FontAwesomeI from 'react-native-vector-icons/FontAwesome'
| ^
2 | import React from 'react'
3 |
4 | export const FontAwesome = props => (
at ScriptTransformer._transformAndBuildScript (../node_modules/jest/node_modules/jest-runtime/build/ScriptTransformer.js:440:17)
at Object.<anonymous> (../Components/icons.js:1:1)
FAIL e2e/tests/components/RoomLayoutDetox.spec.js
● Test suite failed to run
/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/@expo/vector-icons/FontAwesome.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import glyphMap from './vendor/react-native-vector-icons/glyphmaps/FontAwesome.json';
^^^^^^^^
SyntaxError: Unexpected identifier
> 1 | import FontAwesomeI from 'react-native-vector-icons/FontAwesome'
| ^
2 | import React from 'react'
3 |
4 | export const FontAwesome = props => (
at ScriptTransformer._transformAndBuildScript (../node_modules/jest/node_modules/jest-runtime/build/ScriptTransformer.js:440:17)
at Object.<anonymous> (../Components/icons.js:1:1)
Test Suites: 2 failed, 2 total
Tests: 0 total
Snapshots: 0 total
Time: 0.827s
Ran all test suites matching /e2e/i with tests matching "^((?!:android:).)*$".
child_process.js:677
throw err;
^
Error: Command failed: node_modules/.bin/jest "e2e" --config=e2e/config.json --maxWorkers=1 '--testNamePattern=^((?!:android:).)*$'
at checkExecSyncError (child_process.js:637:11)
at Object.execSync (child_process.js:674:13)
at runJest (/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/detox/local-cli/detox-test.js:166:6)
at run (/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/detox/local-cli/detox-test.js:86:7)
at Object.<anonymous> (/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/detox/local-cli/detox-test.js:229:1)
at Module._compile (internal/modules/cjs/loader.js:738:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:749:10)
at Module.load (internal/modules/cjs/loader.js:630:32)
at tryModuleLoad (internal/modules/cjs/loader.js:570:12)
at Function.Module._load (internal/modules/cjs/loader.js:562:3)
Here's my component file RoomLayout.js
import React, { Component } from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import { LayoutButtons } from './LayoutButtons';
import { CameraLauncher } from './CameraLauncher';
import { CommentsLauncher } from './CommentsLauncher';
export class RoomLayout extends Component {
render() {
return (
<View>
<Text testID='roomLayoutText' style={styles.room}>
Room Layout{"\n"}
</Text>
<Text testID='infoText' style={styles.infoText}>
Take photos from opposite corners of the room{"\n"}
</Text>
<LayoutButtons />
</View>
);
}
}
const styles = StyleSheet.create({
view: {
marginTop: 80,
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center'
},
infoText: {
marginTop: -10,
fontWeight: 'normal',
textAlign: 'center',
fontSize: 12,
justifyContent: 'center',
alignSelf: 'center',
color: 'grey'
},
room: {
marginTop: 15,
fontWeight: 'bold',
textAlign: 'center',
lineHeight: 14,
fontSize: 15
}
});
Here's my RoomLayout.spec.js file
import React from 'react';
// import { RoomLayout } from '../Components/RoomLayout';
import { render } from 'react-native-testing-library';
describe('RoomLayout', () => {
// *** EDIT - I have removed this code ***
// beforeEach(async () => {
// const tree = render(<RoomLayout />);
//
// });
test('should have header and info text', async () => {
await element(by.text('Room Layout'));
await element(by.id('infoText'));
await element(by.id('infoText').and(by.text(' Take photos from opposite corners of the room')));
await expect(element(by.id('layoutButtonsReference'))).toBeVisible();
});
});
Setting up Detox with an Expo app. You're probably best placed to start with a clean app that you haven't done anything with yet. You’ll want to make sure you have followed the basic setup (step 1) for getting detox to work on your machine
Install the following devDependencies
Update the package.json
Add the following to your
package.json
file, this configures detox. You can choose the type of iPhone that you want.In the scripts section add the following:
This will allow us to run the detox test but using
npm run e2e
Setup your first test
Run the following to set up your first test
This will add a folder called
e2e
in your project. You will find three files inside itconfig.json
firstTest.spec.js
init.js
firstTest.spec.js
is a sample test. You will need to make the following changes to it.You also need to change the following line
to
Add the Expo Client to your project
Exponent.app
. It'll have a file icon but will still be a folder.bin
folder and putExponent.app
inside so it matches the binaryPath set above.Or alternatively you could use the following script, create a file and name it
setup.sh
in your project root directory, copy the contents and then run it (you will probably need to give it permission to run which you can do by runningchmod +x setup.sh
first, then you can run it using./setup.sh
).This script does the same as the above steps.
Run your first test
Start the packager with
expo start -c
Launch the simulator that you plan to use for your test (so if you picked an iPhone X, launch the iPhone X etc).
Then in your terminal you can run
npm run e2e
if you added the script or you can rundetox test
.What you will find is that your test will fail. This is ok and to be expected.
Now if you want to make your test pass you need to implement all of the test cases that exist in the
firstTest.spec.js
or you can scrap those and write your own.Links
Make your tests pass
If you want to make your tests pass you can update the following files and you should get 3 passing tests.
firstTest.spec.js
App.js