Świat technologii mobilnych od pewnego czasu przechodzi rewolucję – odchodzi się od natywnych aplikacji mobilnych. Jak zatem twórcy aplikacji mobilnych odpowiadają na potrzeby rynku? Czy osoby automatyzujące testy aplikacji mobilnych mają do dyspozycji narzędzia gotowe na technologie, takie jak React Native czy Flutter? Czy można uniknąć pisania oddzielnego kodu testów dla Androida i iOS-a?
W czasie wykładu, na przykładzie aplikacji stworzonej w oparciu o technologię React Native oraz narzędzia Detox, Adam przedstawił praktyczną implementację testów end-to-end oraz ich konfigurację z Continuous Integration.
3. Agenda
1. Introduction
2. Cross-platform frameworks for mobile development
3. UI testing approaches for hybrid apps
4. Detox guide for applying UI tests in React Native projects
4. Agenda
1. Introduction
2. Cross-platform frameworks for mobile development
3. UI testing approaches for hybrid apps
4. Detox guide for applying UI tests in React Native projects
5. Agenda
1. Introduction
2. Cross-platform frameworks for mobile development
3. UI testing approaches for hybrid apps
4. Detox guide for applying UI tests in React Native projects
6. Agenda
1. Introduction
2. Cross-platform frameworks for mobile development
3. UI testing approaches for hybrid apps
4. Detox guide for applying UI tests in React Native projects
16. The Native white Box Test
+ Fast
+ Easy setup
+ Wide range of open source
helpers
+ Compatible with Cloud Device
Farms
17. The Native white Box Test
+ Fast
+ Easy setup
+ Wide range of open source
helpers
+ Compatible with Cloud Device
Farms
− Different languages in project
repository
− Duplicated test code
19. The Cross Platform Black Box Test
+ Many supported languages
+ Wide community
+ Similar to Selenium
+ Single test code base
+ Compatible with Cloud Device
Farms
20. The Cross Platform Black Box Test
+ Many supported languages
+ Wide community
+ Similar to Selenium
+ Single test code base
+ Compatible with Cloud Device
Farms
− Slow
− Difficult debugging
− Lack of stability
22. The Cross Platform White Box Test
+ Fast
+ Easy setup
+ Single test code base
+ The same language as default
project one
+ Close integration with source
code
+ API designed for a specific
platform
23. The Cross Platform White Box Test
+ Fast
+ Easy setup
+ Single test code base
+ The same language as default
project one
+ Close integration with source
code
+ API designed for a specific
platform
− No way / difficult to integrate
with Cloud Device Farm
− No outspread community
− Often still not developed
enough
34. How to make apps testable?
<Text
style={styles.textStyle}>
{!this.state.clicked? defaultButtonText: "Polidea"}
</Text>
<Text
accessible= {true}
testID= {"ButtonText"}
accessibilityLabel= {"ButtonTextDesc"}
style={styles.textStyle}>
{!this.state.clicked? defaultButtonText: "Polidea"}
</Text>
35. How to make apps testable?
<Text
accessible= {true}
testID= {"ButtonText"}
accessibilityLabel= {"ButtonTextDesc"}
style={styles.textStyle}>
{!this.state.clicked? defaultButtonText: "Polidea"}
</Text>
36. How to write Test scripts - API Overview
Detox Object
Test plan
configuration
Device Object
Key events, Gestures,
Device settings
Matchers, Actions, Expectations
Finding Views, User’s actions, Validation
API
37. How to write Test scripts - Init script by example
38. How to write Test scripts - Init script by example
require('babel-polyfill');
39. How to write Test scripts - Init script by example
require('babel-polyfill');
const detox = require('detox');
40. How to write Test scripts - Init script by example
require('babel-polyfill');
const detox = require('detox');
const config = require('../package.json').detox;
before(async () => {
41. How to write Test scripts - Init script by example
require('babel-polyfill');
const detox = require('detox');
const config = require('../package.json').detox;
before(async () => {
await detox.init(config);
42. How to write Test scripts - Init script by example
require('babel-polyfill');
const detox = require('detox');
const config = require('../package.json').detox;
before(async () => {
await detox.init(config);
});
after(async () => {
43. How to write Test scripts - Init script by example
require('babel-polyfill');
const detox = require('detox');
const config = require('../package.json').detox;
before(async () => {
await detox.init(config);
});
after(async () => {
await detox.cleanup();
});
44. How to write Test scripts - Test class by example
45. How to write Test scripts - Test class by example
describe('Example', () => {
46. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
47. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await
48. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device
49. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
50. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor
51. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element
52. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText')))
53. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText'))).toBeVisible()
54. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText'))).toBeVisible().withTimeout(10000);
});
55. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText'))).toBeVisible().withTimeout(10000);
});
it
56. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText'))).toBeVisible().withTimeout(10000);
});
it ('should Press me text be morphed in Polidea title after click on button',async ()
=>{
57. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText'))).toBeVisible().withTimeout(10000);
});
it ('should Press me text be morphed in Polidea title after click on button',async ()
=>{
await element(by.id('ButtonText'))
58. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText'))).toBeVisible().withTimeout(10000);
});
it ('should Press me text be morphed in Polidea title after click on button',async ()
=>{
await element(by.id('ButtonText')).tap();
59. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText'))).toBeVisible().withTimeout(10000);
});
it ('should Press me text be morphed in Polidea title after click on button',async ()
=>{
await element(by.id('ButtonText')).tap();
await waitFor(element(by.text("Press Me")))
60. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText'))).toBeVisible().withTimeout(10000);
});
it ('should Press me text be morphed in Polidea title after click on button',async ()
=>{
await element(by.id('ButtonText')).tap();
await waitFor(element(by.text("Press Me"))).toNotExist()
61. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText'))).toBeVisible().withTimeout(10000);
});
it ('should Press me text be morphed in Polidea title after click on button',async ()
=>{
await element(by.id('ButtonText')).tap();
await waitFor(element(by.text("Press Me"))).toNotExist().withTimeout(2000);
62. How to write Test scripts - Test class by example
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
await waitFor(element(by.id('ButtonText'))).toBeVisible().withTimeout(10000);
});
it ('should Press me text be morphed in Polidea title after click on button',async ()
=>{
await element(by.id('ButtonText')).tap();
await waitFor(element(by.text("Press Me"))).toNotExist().withTimeout(2000);
await waitFor(element(by.text("Polidea"))).toBeVisible().withTimeout(100);
});
})
64. How to integrate With CI - Gitlab CI
detox_test:iOS: detox_test:android:
65. How to integrate With CI - Gitlab CI
detox_test:iOS:
stage: test
before_script:
detox_test:android:
stage: test
before_script:
66. How to integrate With CI - Gitlab CI
detox_test:iOS:
stage: test
before_script:
detox_test:android:
stage: test
before_script:
- adb connect pixel:5555; sh ./scripts/waitForDevice.sh
pixel
67. How to integrate With CI - Gitlab CI
detox_test:iOS:
stage: test
before_script:
- brew tap wix/brew
- brew install --HEAD applesimutils
- npm install -g detox-cli
- npm install -g react-native-cli
- npm install
detox_test:android:
stage: test
before_script:
- adb connect pixel:5555; sh ./scripts/waitForDevice.sh
pixel
- mkdir -p ./detox_node/
- npm install --prefix ./detox_node/ -g detox-cli
- npm install --prefix ./detox_node/ -g react-native-cli
- npm install
68. How to integrate With CI - Gitlab CI
detox_test:iOS:
stage: test
before_script:
- brew tap wix/brew
- brew install --HEAD applesimutils
- npm install -g detox-cli
- npm install -g react-native-cli
- npm install
script:
detox_test:android:
stage: test
before_script:
- adb connect pixel:5555; sh ./scripts/waitForDevice.sh
pixel
- mkdir -p ./detox_node/
- npm install --prefix ./detox_node/ -g detox-cli
- npm install --prefix ./detox_node/ -g react-native-cli
- npm install
script:
69. How to integrate With CI - Gitlab CI
detox_test:iOS:
stage: test
before_script:
- brew tap wix/brew
- brew install --HEAD applesimutils
- npm install -g detox-cli
- npm install -g react-native-cli
- npm install
script:
- react-native start --port 2137 &
detox_test:android:
stage: test
before_script:
- adb connect pixel:5555; sh ./scripts/waitForDevice.sh
pixel
- mkdir -p ./detox_node/
- npm install --prefix ./detox_node/ -g detox-cli
- npm install --prefix ./detox_node/ -g react-native-cli
- npm install
script:
- ./detox_node/bin/react-native start --port 2137 &
80. Key TAkeaways
● Cross platform apps can be tested with the same
frameworks as native ones
● For typical apps you can avoid code duplication and use
cross-platform frameworks
● Detox is a great tool for React Native UI testing