Testing Mobile Apps on iOS and Android can look like this:
I.setLandscapeOrientation();
I.fillField('#text', 'a new text');
I.see('a new text', '#textValue');
I.dontSeeElement('#createdAndVisibleText');
I.click({ ios: '#GoButton', android: 'Button' });
I.waitForElement('#createdAndVisibleText', 20);
I.seeElement('#createdAndVisibleText');
I.runOnAndroid(() => {
I.click('Save');
I.see('Text Saved', '#message');
});
I.runOnIOS(() => {
I.click('SAVE');
I.see('SAVED!');
});
CodeceptJS provides next features over standard Detox:
- Unified API. The same test can be executed in Appium or Detox. Unified API helps different teams to use the same syntax and easy port tests from one engine to another.
- Interactive pause. When starting/stopping an application takes a long time, debugging and writing tests can be hard.
CodeceptJS solves this by pausing an execution and letting you try different commands and locators. With this feature a test can be writtern during one running session.
- One Test For Android and IOS. When application differs on Android and IOS you can provide corresponding system-related locators for both systems. When needed a different code can be executed for Android and IOS keeping it inside the same test.
API
Table of Contents
Detox
Extends Helper
This is a wrapper on top of Detox library, aimied to unify testing experience for CodeceptJS framework.
Detox provides a grey box testing for mobile applications, playing especially good for React Native apps.
Detox plays quite differently from Appium. To establish detox testing you need to build a mobile application in a special way to inject Detox code.
This why Detox is grey box testing solution, so you need an access to application source code, and a way to build and execute it on emulator.
Comparing to Appium, Detox runs faster and more stable but requires an additional setup for build.
Setup
-
Install and configure Detox for iOS and Android
-
Build an application using detox build
command.
-
Install CodeceptJS and detox-helper:
npm i @codeceptjs/detox-helper --save
Detox configuration is required in package.json
under detox
section.
If you completed step 1 and step 2 you should have a configuration similar this:
"detox": {
"configurations": {
"ios.sim.debug": {
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/example.app",
"build": "xcodebuild -project ios/example.xcodeproj -scheme example -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
"type": "ios.simulator",
"name": "iPhone 7"
}
}
}
Configuration
Besides Detox configuration, CodeceptJS should also be configured to use Detox.
In codecept.conf.js
enable Detox helper:
helpers: {
Detox: {
require: '@codeceptjs/detox',
configuration: '<detox-configuration-name>',
}
}
It's important to specify a package name under require
section and current detox configuration taken from package.json
.
Options:
configuration
- a detox configuration name. Required.reloadReactNative
- should be enabled for React Native applications.reuse
- reuse application for tests. By default, Detox reinstalls and relaunches app.registerGlobals
- (default: true) Register Detox helper functions by
, element
, expect
, waitFor
globally.
Parameters
saveScreenshot
Saves a screenshot to the output dir
I.saveScreenshot('main-window.png');
Parameters
relaunchApp
Relaunches an application.
I.relaunchApp();
launchApp
Launches an application. If application instance already exists, use relaunchApp.
I.launchApp();
installApp
Installs a configured application.
Application is installed by default.
I.installApp();
shakeDevice
Shakes the device.
I.shakeDevice();
goBack
Goes back on Android
I.goBack();
setLandscapeOrientation
Switches device to landscape orientation
I.setLandscapeOrientation();
setPortraitOrientation
Switches device to portrait orientation
I.setPortraitOrientation();
runOnIOS
Execute code only on iOS
I.runOnIOS(() => {
I.click('Button');
I.see('Hi, IOS');
});
Parameters
fn
a function which will be executed on iOS
runOnAndroid
Execute code only on Android
I.runOnAndroid(() => {
I.click('Button');
I.see('Hi, Android');
});
Parameters
fn
a function which will be executed on android
tap
Taps on an element.
Element can be located by its text or id or accessibility id.
The second parameter is a context element to narrow the search.
Same as click
I.tap('Login');
I.tap('~nav-1');
I.tap('#user');
I.tap('Login', '#nav');
I.tap({ ios: 'Save', android: 'SAVE' }, '#main');
Parameters
multiTap
Multi taps on an element.
Element can be located by its text or id or accessibility id.
Set the number of taps in second argument.
Optionally define the context element by third argument.
I.multiTap('Login', 2);
I.multiTap('~nav', 2);
I.multiTap('#user', 2);
I.multiTap('Update', 2, '#menu');
Parameters
locator
(string | object) element to locatenum
int number of tapscontext
(string | object) context element (optional, default null
)
longPress
Taps an element and holds for a requested time.
I.longPress('Login', 2);
I.longPress('~nav', 1);
I.longPress('Update', 2, '#menu');
Parameters
locator
(string | object) element to locatesec
num number of seconds to hold tapcontext
(string | object) context element (optional, default null
)
click
Clicks on an element.
Element can be located by its text or id or accessibility id
The second parameter is a context (id | type | accessibility id) to narrow the search.
Same as tap
I.click('Login');
I.click('~nav-1');
I.click('#user');
I.click('Login', '#nav');
I.click({ ios: 'Save', android: 'SAVE' }, '#main');
Parameters
clickAtPoint
Performs click on element with horizontal and vertical offset.
An element is located by text, id, accessibility id.
I.clickAtPoint('Save', 10, 10);
I.clickAtPoint('~save', 10, 10);
Parameters
locator
(string | object)x
int horizontal offset (optional, default 0
)y
int vertical offset (optional, default 0
)
see
Checks text to be visible.
Use second parameter to narrow down the search.
I.see('Record created');
I.see('Record updated', '#message');
I.see('Record deleted', '~message');
Parameters
text
string to check visibilitycontext
(string | object) element inside which to search for text (optional, default null
)
dontSee
Checks text not to be visible.
Use second parameter to narrow down the search.
I.dontSee('Record created');
I.dontSee('Record updated', '#message');
I.dontSee('Record deleted', '~message');
Parameters
text
string to check invisibilitycontext
(string | object) element in which to search for text (optional, default null
)
seeElement
Checks for visibility of an element.
Use second parameter to narrow down the search.
I.seeElement('~edit');
I.seeElement('~edit', '#menu');
Parameters
dontSeeElement
Checks that element is not visible.
Use second parameter to narrow down the search.
I.dontSeeElement('~edit');
I.dontSeeElement('~edit', '#menu');
Parameters
seeElementExists
Checks for existence of an element. An element can be visible or not.
Use second parameter to narrow down the search.
I.seeElementExists('~edit');
I.seeElementExists('~edit', '#menu');
Parameters
dontSeeElementExists
Checks that element not exists.
Use second parameter to narrow down the search.
I.dontSeeElementExist('~edit');
I.dontSeeElementExist('~edit', '#menu');
Parameters
fillField
Fills in text field in an app.
A field can be located by text, accessibility id, id.
I.fillField('Username', 'davert');
I.fillField('~name', 'davert');
I.fillField({ android: 'NAME', ios: 'name' }, 'davert');
Parameters
clearField
Clears a text field.
A field can be located by text, accessibility id, id.
I.clearField('~name');
Parameters
appendField
Appends text into the field.
A field can be located by text, accessibility id, id.
I.appendField('name', 'davert');
Parameters
scrollUp
Scrolls to the top of an element.
I.scrollUp('#container');
Parameters
scrollDown
Scrolls to the bottom of an element.
I.scrollDown('#container');
Parameters
scrollLeft
Scrolls to the left of an element.
I.scrollLeft('#container');
Parameters
scrollRight
Scrolls to the right of an element.
I.scrollRight('#container');
Parameters
swipeUp
Performs a swipe up inside an element.
Can be slow
or fast
swipe.
I.swipeUp('#container');
Parameters
locator
(string | object) an element on which to perform swipespeed
string a speed to perform: slow
or fast
. (optional, default 'slow'
)
swipeDown
Performs a swipe up inside an element.
Can be slow
or fast
swipe.
I.swipeUp('#container');
Parameters
locator
(string | object) an element on which to perform swipespeed
string a speed to perform: slow
or fast
. (optional, default 'slow'
)
swipeLeft
Performs a swipe up inside an element.
Can be slow
or fast
swipe.
I.swipeUp('#container');
Parameters
locator
(string | object) an element on which to perform swipespeed
string a speed to perform: slow
or fast
. (optional, default 'slow'
)
swipeRight
Performs a swipe up inside an element.
Can be slow
or fast
swipe.
I.swipeUp('#container');
Parameters
locator
(string | object) an element on which to perform swipespeed
string a speed to perform: slow
or fast
. (optional, default 'slow'
)
wait
Waits for number of seconds
I.wait(2);
Parameters
sec
int number of seconds to wait
waitForElement
Waits for an element to exist on page.
I.waitForElement('#message', 1);
Parameters
locator
(string | object) an element to wait forsec
int number of seconds to wait, 5 by default (optional, default 5
)
waitForElementVisible
Waits for an element to be visible on page.
I.waitForElementVisible('#message', 1);
Parameters
locator
(string | object) an element to wait forsec
int number of seconds to wait (optional, default 5
)
waitToHide
Waits an elment to become not visible.
I.waitToHide('#message', 2);
Parameters
locator
(string | object) an element to wait forsec
int number of seconds to wait (optional, default 5
)