Made each other 

!!
How ,
and
The app
Automation Setup
Script once
Happy developers
Optimisation
Time
User experience
Pro’s and cons
Menu
Conversational
" #
User interface
The app
" #
User interface
After install
$ %
onBoarding
The app
Movie
The app
The app
Automation Setup
Script once
Happy developers
Optimisation
Time
User experience
Pro’s and cons
Menu
Appium + Appium Desktop
webdriver.io
CucumberJS
multiple-cucumber-html-report
Amsterdam 2017
Automation Setup
Detox versus Appium
London 2018
The app
Automation Setup
Script once
Happy developers
Optimisation
Time
User experience
Pro’s and cons
Menu
Script once
AccessibilityLabels (98%)
XPath (2%)
HyBrid solution
Testproperties
Implementation
Platform specific
Code
Testproperties
/**
* If we have a test build, add a unique test id for iOS and Android
*
* @param {string} id
*
* @return {object|*}
*/
function testProperties(id) {
if (IS_AUTOMATION_BUILD) {
return {
accessibilityLabel: `test-${id}`,
};
}
return null;
}
Implementation
import React, { Component } from 'react';
import { View } from ‘react-native';
import { testProperties } from './config/automation/TestProperties';
class MultipleChoice extends Component {
// Some code
render() {
const { options } = this.props;
return (
<View
style={styles.container}
{…testProperties('Select menu')}
>
// The select implementation
</View>
);
}
}
AccessiBility laBel(s)
Platform specific
function testProperties(id) {
if (IS_AUTOMATION_BUILD) {
if (IS_IOS) {
return {
testID: `test-${id}`,
};
}
return {
accessibilityLabel: `test-${id}`,
};
}
return null;
}
AccessiBility laBel
Platform specific
function testProperties(id) {
if (IS_AUTOMATION_BUILD) {
if (IS_IOS) {
return {
testID: `test-${id}`,
};
}
return {
accessibilityLabel: `test-${id}`,
};
}
return null;
}
Script once
AccessibilityLabels (98%)
XPath (2%)
HyBrid solution
Testproperties
Implementation
Platform specific
Code
The app
Automation Setup
Script once
Happy developers
Optimisation
Time
User experience
Pro’s and cons
Menu
Happy developers
Why?
Remove flakiness
Fix inconsistent testdata problem
Test errors / delays / edge cases
Speed up manual and automated tests
With ng-apimock
How
Ng-apimock
Happy developers
Why?
Remove flakiness
Fix inconsistent testdata problem
Test errors / delays / edge cases
Speed up manual and automated tests
With ng-apimock
How
The app
Automation Setup
Script once
Happy developers
Optimisation
Time
User experience
Pro’s and cons
Menu
Animations
Test strategy
Shortcuts
Parallel execution
Optimisation
Animations
onBoarding
Each bubble takes 500 ms to show
Min 15 bubbles => 7,5 sec
Max 25 bubbles => 12,5 sec
Bubble delay is 800 ms
Between 19 (15*800+7,5) and 32 sec (25*800+12,5) animations
What?!
Remove animations
import { AppRegistry } from 'react-native';
import App from './app/App';
import { setupAutomation } from './app/config/automation/TestProperties';
// Run the automation setup
setupAutomation();
AppRegistry.registerComponent('Tele2CustomerApp', () => App);
Remove animations
const stubs = require('stubs');
/**
* Setup the app for a specific automation build
*/
function setupAutomation() {
if (!IS_AUTOMATION_BUILD) {
return;
}
// Disable the yellow box
console.disableYellowBox = true;
disableAnimations();
}
/**
* Disable all animations
*/
function disableAnimations() {
const AnimatedTiming = Animated.timing;
stubs(Animated, 'timing', (...props) => {
props[1].duration = 0;
props[1].delay = 0;
return AnimatedTiming(...props);
});
}
Result
Animations + real services No animation + mocking
15 sec!40 sec!
Remove animations
const stubs = require('stubs');
/**
* Setup the app for a specific automation build
*/
function setupAutomation() {
if (!IS_AUTOMATION_BUILD) {
return;
}
// Disable the yellow box
console.disableYellowBox = true;
disableAnimations();
}
/**
* Disable all animations
*/
function disableAnimations() {
const AnimatedTiming = Animated.timing;
stubs(Animated, 'timing', (...props) => {
props[1].duration = 0;
props[1].delay = 0;
return AnimatedTiming(...props);
});
}
Animations
onBoarding
Each bubble takes 500 ms to show
Min 15 bubbles => 7,5 sec
Max 25 bubbles => 12,5 sec
Bubble delay is 800 ms
Between 19 (15*800+7,5) and 32 sec (25*800+12,5) animations
What?!
Animations
Test strategy
Shortcuts
Parallel execution
Optimisation
Test strategy
Real devices
Platforms: iOS && Android
Devices: High- && Mid- && Budget-range
Platform tests: High && mid risk, proof only once
All device tests: High risk, test on all
With CucumberJS Tags
How?
CucumBerJS tags
Feature: View invoices
Background: Open account settings
Given I launch the new awesome Tele2 app
@os-specific
Scenario: As an user I want to see my not paid and paid bills
Given I'm logged in to open my invoices
Then I would like to see my unpaid bills
| text |
| Januari 2018 € 359,02 Deze factuur wordt op 01 februari afgeschreven. |
And I would like to see my paid bills
| text |
| December 2017 € 66,12 |
| November 2017 € 112,12 |
Scenario: As an user I want to be able to download or share my invoice
Given I'm logged in to open my invoices
When I select the first invoice
Then I would see the PDF of the invoice
When I press the download button
Then the download and share options are shown
CucumBerJS tags
Feature: Onboarding
Background: Open the app
Given I launch the new awesome Tele2 app
And I want to start with the onboarding
@all-devices
Scenario: As a customer I want to onboard with an existing MijnTele2 account
When I select Jazeker!
And I submit my credentials in the login form
Then the pincode bubble would be visible
When I submit valid pincodes
And I agree with the terms and conditions
Then I am redirected the home screen
Test strategy
Real devices
Platforms: iOS && Android
Devices: High- && Mid- && Budget-range
Extensive tests: High && mid risk, proof only once
Default tests: Hi risk, test on all
With CucumberJS Tags
How?
Animations
Test strategy
Shortcuts
Parallel execution
Optimisation
95%Behind onBoarding
So….
Shortcuts
Behind onBoarding
So….
Or
$ %
Best test feature
Or Do some
Shortcuts
$ %
Best test feature
Or Do some
&
magic?
Magic with
Shortcuts
&
magic?
Magic with
'
For 5 features
Shortcuts
Reconsider deeplinking
' + ( = ) = *
Testlink screen
import TestLinkScreen from './TestLinkScreen';
/**
* Create the test link stack if it's a mocked build
*
* @return {*}
*/
function testLinkStack() {
if (MOCKED_ENVIRONMENTS.includes(ENVIRONMENT)) {
return {
[TEST_LINK_SCREEN]: {
screen: TestLinkScreen,
},
};
}
return {};
}
Reconsider deeplinking
' + ( = ) = *
95%Behind onBoarding
So….
Shortcuts
Optimisation
Animations
Test strategy
Shortcuts
Parallel execution
Parallel execution
Not
… each scenario on each (
… all (( have the same ⚡
… all (( start with same scenario at same ⏱
… same API response on all ((
Prevent
Ng-apimock
Mockserver
Ng-apimock
Mockserver
Post: api/version/login
"Content-Type": "application/json",
"Accept": “application/json"
response:
{
"status": 200,
"firstName": "Wim",
"lastName": “Selles"
}
Ng-apimock
Mockserver
weBdriver.io
PUT:
headers: {
'Content-Type': ‘application/json'
},
method: 'PUT',
body: {
identifier: 'token',
scenario: 'unauthorised'
}
Ng-apimock
Mockserver
weBdriver.io
The idea
Mockserver
weBdriver.io
IDFV: 51A82F08-CCAC-410F
The idea
Mockserver
weBdriver.io
IDFV: 51A82F08-CCAC-410F
The idea
Mockserver
weBdriver.io
PUT:
headers: {
'Content-Type': ‘application/json’,
ngapimockid: '51A82F08-CCAC-410F'
},
method: 'PUT',
body: {
identifier: 'token',
scenario: 'unauthorised'
}
IDFV: 51A82F08-CCAC-410F
response:
{
"status": 401,
“message": “unauthorised"
}
The idea
Mockserver
weBdriver.io
PUT:
headers: {
'Content-Type': ‘application/json’,
ngapimockid: '51A82F08-CCAC-410F'
},
method: 'PUT',
body: {
identifier: 'token',
scenario: 'unauthorised'
}
IDFV: 51A82F08-CCAC-410F
Post: api/version/login
"Content-Type": "application/json",
"Accept": “application/json”,
ngapimockid: '51A82F08-CCAC-410F'
/**
* This is a part from our `TestProperties`-file.
*/
import { getUniqueID } from 'react-native-device-info';
/**
* If it is an automation build, then add a new header for the API calls
*
* @return {Object}
*
* For iOS it will return something like: FCDBD8EF-62FC-4ECB-B2F5-92C9E79AC7F9
* For Android it will return something like: dd96dec43fb81c97
*/
function uniqueAutomationApiHeaderId() {
if (IS_AUTOMATION_BUILD) {
return {
ngapimockid: getUniqueID(),
};
}
return {};
}
app method
/**
* This is the config-file we use for calling all the API’s.
* Below you will see a part of the config to attach the headers
* to all API calls
*/
import { uniqueAutomationApiHeaderId } from './automation/TestProperties';
const apiConfig = create({
baseURL: BASE_URL,
headers: {
...API_HEADERS,
...uniqueAutomationApiHeaderId(),
},
});
Header
Testlink screen
/**
* Executes the api call with the provided information.
*
* @param {string} httpMethod PUT|DELETE|POST|GET
* @param {string} urlSuffix Which path to httpMethod the data to
* @param {Object} options The data that needs to be httpMethod
* @param {string} errorMessage The error that needs to be shown
*
* @return {Promise} The promise.
*
* @private
*/
function execute(httpMethod, urlSuffix, options, errorMessage) {
const data = {
headers: {
'Content-Type': 'application/json',
ngapimockid: device.uniqueID,
},
method: httpMethod,
};
if (options !== undefined) {
data.body = JSON.stringify(options);
}
return handleRequest(urlSuffix, data, errorMessage);
}
Set state
headers: {
'Content-Type': ‘application/json’,
ngapimockid: '51A82F08-CCAC-410F'
},
method: 'PUT',
body: {
identifier: 'token',
scenario: 'unauthorised'
}
response:
{
"status": 401,
“message": “unauthorised"
}
The idea
Mockserver
weBdriver.io
PUT:
headers: {
'Content-Type': ‘application/json’,
ngapimockid: '51A82F08-CCAC-410F'
},
method: 'PUT',
body: {
identifier: 'token',
scenario: 'unauthorised'
}
IDFV: 51A82F08-CCAC-410F
Post: api/version/login
"Content-Type": "application/json",
"Accept": “application/json”,
ngapimockid: '51A82F08-CCAC-410F'
Parallel execution
Not
… each scenario on each (
… all (( have the same ⚡
… all (( start with same scenario at same ⏱
… same API response on all ((
Prevent
Optimisation
Animations
Test strategy
Shortcuts
Parallel execution
The app
Automation Setup
Script once
Happy developers
Optimisation
Time
User experience
Pro’s and cons
Menu
time
per scenario
Mocking: ~4 API calls (4 x 2 sec.) ~ 8 sec.
Animations: ~ 9 sec.
Deeplinking/Testlinkscreen: ~15 sec.
Currently 65 scenario’s
Average savings
time
per scenario
Mocking: ~4 API calls (4 x 2 sec.) ~ 8 sec.
Animations: ~ 9 sec.
Deeplinking/Testlinkscreen: ~15 sec.
Currently 65 scenario’s
Average savings
Ooooops!
Something went wrong!
You just saved more than
30 min
on total execution time!
Please revert! Proceed!
time
per scenario
Mocking: ~4 API calls (4 x 2 sec.) ~ 8 sec.
Animations: ~ 9 sec.
Deeplinking/Testlinkscreen: ~15 sec.
Currently 65 scenario’s
Average savings
!!
Ooooops!
Something went wrong again!
Execution time on 4 parallel devices
in the cloud is only
15% higher
in comparison to local execution time
on 1 device. We expected more!
Please revert! Proceed!
time
per scenario
Mocking: ~4 API calls (4 x 2 sec.) ~ 8 sec.
Animations: ~ 9 sec.
Deeplinking/Testlinkscreen: ~15 sec.
Currently 65 scenario’s
Average savings
The app
Automation Setup
Script once
Happy developers
Optimisation
Time
User experience
Pro’s and cons
Menu
User experience
How?
Automate comparing images
Core:
• Comparison:
• ResembleJS (https://github.com/HuddleEng/Resemble.js)
• Logic:
• WebdriverIO element selection
• Appium understanding (UI-hierarchy)
• Experience from the past with my protractor-image-comparison module
HOW-2-USE
// wdio.conf.js
exports.config = {
// ...
plugins: {
'wdio-native-app-compare': {
baselineFolder: '.dist/image-compare/baseline',
screenshotPath: '.dist/image-compare/screenshots',
// See Options for more options
// ..
},
},
// ...
};
HOW-2-USE
/**
* Save element
*/
// Default
device.saveElement(device.element('~your-accessibility-id'), 'name-of-your-file');
// Shorthand
device.saveElement($('~your-accessibility-id'), 'name-of-your-file');
/**
* Save screen
*/
device.saveScreen(‘name-of-your-file');
HOW-2-USE
/**
* Compare element
*/
expect(
device.compareElement(
$('~your-accessibility-id'),
'name-of-your-file',
{
// .. options here
},
).misMatchPercentage
).toEqual(0);
/**
* Compare screen
*/
expect(
device.compareScreen(
'name-of-your-file',
{
// .. options here
},
).misMatchPercentage
).toEqual(0);
React Native
0.54
React Native
0.57
- . /
React Native
0.54
React Native
0.57
- . /
- . /
Report
Module
https://github.com/wswebcreation/wdio-native-app-compare
Module
https://github.com/wswebcreation/wdio-native-app-compare
User experience
The app
Automation Setup
Script once
Happy developers
Optimisation
Time
User experience
Pro’s and cons
Menu
Pro’s and cons
Pro’s
Increase quality
Speed up development
Test what really needs to be tested
Speed up execution time
Cons
No real services tested (automated)
App is not a production app
Developers often debug app for seeing
no animations.
(use the wrong build 0)
The app
Automation Setup
Script once
Happy developers
Optimisation
Time
User experience
Pro’s and cons
Menu
I hope we have some time left, so are there any
questions?
Can you show everybody my contact details?
I hope we have some time left, so are there any
questions?
Thank you very much!
Sure!
Contact
1: Wim Selles - Sr. Solutions Architect
2: Sauce Labs
3: @wswebcreation
4: wswebcreation.nl
4: gitHub.com/wswebcreation
5 Goodbye! 5

How React Native, Appium and me made each other shine @ContinuousDeliveryAmsterdam MeetUp 18-09-2019