Skip to content

Commit

Permalink
Merge pull request #1 from testfairy/feat-testfairy
Browse files Browse the repository at this point in the history
Added TestFairy code samples
  • Loading branch information
gmegidish authored Apr 18, 2021
2 parents 7bba99f + f213728 commit c026183
Show file tree
Hide file tree
Showing 15 changed files with 336 additions and 18 deletions.
4 changes: 4 additions & 0 deletions android/app/src/main/assets/user_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"appToken": "XXXX",
"serverEndpoint": "https://app.testfairy.com/services/"
}
3 changes: 3 additions & 0 deletions android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ MYAPP_RELEASE_STORE_FILE=sLSwagLab.keystore
MYAPP_RELEASE_KEY_ALIAS=sLSwagLab
MYAPP_RELEASE_STORE_PASSWORD=sl.swag.lab
MYAPP_RELEASE_KEY_PASSWORD=sl.swag.lab

org.gradle.daemon=true
org.gradle.jvmargs=-Xmx2560m
24 changes: 15 additions & 9 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -240,13 +240,13 @@ PODS:
- React-jsinspector (0.63.4)
- react-native-biometrics (2.1.4):
- React
- react-native-camera (3.40.0):
- react-native-camera (3.42.0):
- React-Core
- react-native-camera/RCT (= 3.40.0)
- react-native-camera/RN (= 3.40.0)
- react-native-camera/RCT (3.40.0):
- react-native-camera/RCT (= 3.42.0)
- react-native-camera/RN (= 3.42.0)
- react-native-camera/RCT (3.42.0):
- React-Core
- react-native-camera/RN (3.40.0):
- react-native-camera/RN (3.42.0):
- React-Core
- react-native-cameraroll (4.0.1):
- React
Expand Down Expand Up @@ -310,6 +310,8 @@ PODS:
- React-Core/RCTVibrationHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-TestFairy (2.46.0):
- React
- ReactCommon/turbomodule/core (0.63.4):
- DoubleConversion
- Folly (= 2020.01.13.00)
Expand Down Expand Up @@ -398,6 +400,7 @@ DEPENDENCIES:
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- React-TestFairy (from `../node_modules/react-native-testfairy`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
Expand Down Expand Up @@ -492,6 +495,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/Libraries/Text"
React-RCTVibration:
:path: "../node_modules/react-native/Libraries/Vibration"
React-TestFairy:
:path: "../node_modules/react-native-testfairy"
ReactCommon:
:path: "../node_modules/react-native/ReactCommon"
rn-fetch-blob:
Expand Down Expand Up @@ -523,7 +528,7 @@ SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
DoubleConversion: cde416483dac037923206447da6e1454df403714
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
Expand All @@ -534,7 +539,7 @@ SPEC CHECKSUMS:
Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7
FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd
Permission-Camera: 119b01de97a5b3edb637999e38476b68143b9d17
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
Expand All @@ -548,7 +553,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
react-native-biometrics: 9d3306e5d29c3bc4e6a3c912d759a94e76a2f683
react-native-camera: 35854c4f764a4a6cf61c1c3525888b92f0fe4b31
react-native-camera: cf8a153d33138dcc457172fc3c33fdf4e5d288d2
react-native-cameraroll: 60ba0068826eab1c8d43146191bafd4363ea58a7
react-native-geolocation-service: f33626f1ae12381ca2ae60f98b2f5edd676bf95a
react-native-safe-area-context: b6e0e284002381d2ff29fa4fff42b4d8282e3c94
Expand All @@ -563,6 +568,7 @@ SPEC CHECKSUMS:
React-RCTSettings: 60f0691bba2074ef394f95d4c2265ec284e0a46a
React-RCTText: 5c51df3f08cb9dedc6e790161195d12bac06101c
React-RCTVibration: ae4f914cfe8de7d4de95ae1ea6cc8f6315d73d9d
React-TestFairy: 15693dd36bd96cd84f49a1dab178c686c5b04e0b
ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398
Expand All @@ -580,4 +586,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: ecf2fe4af704ed5b9f0aff1236d36a0bad5aa8ad

COCOAPODS: 1.10.0
COCOAPODS: 1.10.1
4 changes: 4 additions & 0 deletions ios/SwagLabsMobileApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
8BE462ED410372C475645C48 /* libPods-SwagLabsMobileApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EBEFA1E655475B70E32A018C /* libPods-SwagLabsMobileApp.a */; };
9713E9B599EF4496856995C0 /* MuseoSans_500.otf in Resources */ = {isa = PBXBuildFile; fileRef = 65E91478319D4DA0B0365D2B /* MuseoSans_500.otf */; };
A25BEE6D6B6A4258A80BB927 /* MuseoSans_500_Italic.otf in Resources */ = {isa = PBXBuildFile; fileRef = 2052DCED8B4C41E7AACF5CB7 /* MuseoSans_500_Italic.otf */; };
EF07C9112629ACA000EA6846 /* user_data.json in Resources */ = {isa = PBXBuildFile; fileRef = EF07C9102629ACA000EA6846 /* user_data.json */; };
F4FB854CDEEB4B1C825CACC1 /* MuseoSans-100Italic.otf in Resources */ = {isa = PBXBuildFile; fileRef = 819AD89F4773427798EF4E6A /* MuseoSans-100Italic.otf */; };
F53CE61010514357AD30270B /* MuseoSans-300.otf in Resources */ = {isa = PBXBuildFile; fileRef = E9293998A145403EA14C7E77 /* MuseoSans-300.otf */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -79,6 +80,7 @@
EBEFA1E655475B70E32A018C /* libPods-SwagLabsMobileApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SwagLabsMobileApp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
EF07C9102629ACA000EA6846 /* user_data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = user_data.json; path = SwagLabsMobileApp/user_data.json; sourceTree = "<group>"; };
F2B1E54F0BDD40FCB5A8C7C1 /* FontAwesome5_Regular.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome5_Regular.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf"; sourceTree = "<group>"; };
F2D978234CE84D62BBA572F4 /* FontAwesome5_Brands.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome5_Brands.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Brands.ttf"; sourceTree = "<group>"; };
F5511BC1135A40D3A92934C6 /* Entypo.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Entypo.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Entypo.ttf"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -114,6 +116,7 @@
13B07FB61A68108700A75B9A /* Info.plist */,
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
13B07FB71A68108700A75B9A /* main.m */,
EF07C9102629ACA000EA6846 /* user_data.json */,
885771DD25342B1F009C30D4 /* enableSwiftSupport.swift */,
);
name = SwagLabsMobileApp;
Expand Down Expand Up @@ -308,6 +311,7 @@
9713E9B599EF4496856995C0 /* MuseoSans_500.otf in Resources */,
6CBE4FEB20B04F10A43B5D3E /* MuseoSans_700.otf in Resources */,
0B0306A6047848E39E8FFEEA /* MuseoSans_900.otf in Resources */,
EF07C9112629ACA000EA6846 /* user_data.json in Resources */,
378F62E24FE54B57B509945D /* MuseoSans-100.otf in Resources */,
F4FB854CDEEB4B1C825CACC1 /* MuseoSans-100Italic.otf in Resources */,
F53CE61010514357AD30270B /* MuseoSans-300.otf in Resources */,
Expand Down
4 changes: 4 additions & 0 deletions ios/SwagLabsMobileApp/user_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"appToken": "XXXX",
"serverEndpoint": "https://app.testfairy.com/services/"
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"android.test.sauce.emu": "wdio tests/e2e/config/wdio.android.sauce.emu.conf.js",
"android.test.rdc": "RDC=true wdio ./tests/e2e/config/wdio.android.rdc.conf.js",
"android.debug.build": "yarn react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res",
"android.debug.build.apk": "yarn android.debug.build && cd android && ./gradlew assembleDebug",
"android.espresso": "yarn android.debug.build && cd android && ./gradlew assembleDebug && ./gradlew assembleAndroidTest",
"ios.dev": "react-native run-ios",
"ios.release.sim.build": "react-native run-ios --configuration Release",
Expand Down Expand Up @@ -51,6 +52,7 @@
"react-native-screens": "^2.16.1",
"react-native-signature-canvas": "^3.3.0",
"react-native-splash-screen": "^3.2.0",
"react-native-testfairy": "^2.46.0",
"react-native-vector-icons": "^7.1.0",
"react-native-webview": "^11.0.2",
"react-navigation": "^4.4.3",
Expand Down
56 changes: 53 additions & 3 deletions src/js/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
* @flow strict-local
*/

import fs from 'react-native-fs';
import SplashScreen from 'react-native-splash-screen';
import QuickActions from 'react-native-quick-actions';
import TestFairy from 'react-native-testfairy';

import React, { Component } from 'react';
import { View, StyleSheet } from 'react-native';
import { View, StyleSheet, Platform } from 'react-native';
import NavigationContainer from './Router';
import SwagLabsStatusBar from './components/StatusBar';
import SplashScreen from 'react-native-splash-screen';
import QuickActions from 'react-native-quick-actions';
import { IS_IOS, SCREENS } from './config/Constants';

QuickActions.setShortcutItems([
Expand Down Expand Up @@ -37,6 +40,9 @@ QuickActions.setShortcutItems([

export default class App extends Component {
componentDidMount() {
this.initialzeTestFairy();

// Hide splash screen once the component mounts
SplashScreen.hide();
}

Expand All @@ -48,6 +54,50 @@ export default class App extends Component {
</View>
);
}

initialzeTestFairy() {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Launch a TestFairy session. The session url will be in the logs for you to navigate.
// Optionally, specify a private cloud endpoint if it applies to you.
//
// When TestFairy launches a session, these will be listened collected until the session is stopped or app is closed:
//
// - logs
// - crashes
// - video recording
// - http network events
// - feedbacks via forms launched when the users shakes their device
// - custom attributes set in the code w/ TestFairy.setAttribute()
// - events sent in the code w/ TestFairy.addEvent()
//
// and many others.
//
// All of this data will be available in your TestFairy web dashboard as well as the REST API.
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function parseAndInit(data) {
// Parse configuration
const TestFairyUserData = JSON.parse(data);

// We call stop to support hot-swap during development. This call will be ignored silently for the initial app launch.
TestFairy.stop();

// TestFairy.setServerEndpoint("https://your.privatecloud.example.com") // Private cloud only

TestFairy.setServerEndpoint(TestFairyUserData.serverEndpoint);
TestFairy.begin(TestFairyUserData.appToken);

// TestFairy.installFeedbackHandler(TestFairyUserData.appToken); // Swap this line with the above if you don't want to record a session but still need the shake gesture detection for the feedbacks.
}

if (Platform.OS === 'ios') {
fs.readFile(`${fs.MainBundlePath}/user_data.json`, { encoding: 'utf8' }).then(parseAndInit);
} else if (Platform.OS === 'android') {
fs.readFileAssets('user_data.json', 'utf8').then(parseAndInit);
}
}
}

const styles = StyleSheet.create({
Expand Down
13 changes: 12 additions & 1 deletion src/js/Router.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import QrCodeScanner from './screens/QrCodeScanner';
import DrawerLinks from './components/DrawerLinks';
import GeoLocation from './screens/GeoLocation';
import Drawing from './screens/Drawing';
import TestFairy from 'react-native-testfairy';

enableScreens();

Expand Down Expand Up @@ -94,7 +95,17 @@ const prefix = 'swaglabs://';
export default class NavigationContainer extends Component {
render() {
return (
<Router uriPrefix={ prefix }/>
<Router uriPrefix={ prefix } onNavigationStateChange={ this.onNavigationStateChange } />
);
}

onNavigationStateChange(previousState, newState, action) {
if (newState.routes.length > 0) {
let newScreen = newState.routes[0].routes[newState.routes[0].routes.length - 1];
if (newScreen) {
// This helps TestFairy to show curent screen name in the session timeline
TestFairy.setScreenName(newScreen.routeName);
}
}
}
}
4 changes: 4 additions & 0 deletions src/js/screens/CheckoutComplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Footer from '../components/Footer';
import ActionButton from '../components/ActionButton';
import SecondaryHeader from '../components/SecondaryHeader';
import { handleQuickActionsNavigation } from '../config/QuickActionsNavigation';
import TestFairy from 'react-native-testfairy';

export default class CheckoutComplete extends Component {
constructor(props) {
Expand All @@ -17,6 +18,9 @@ export default class CheckoutComplete extends Component {

componentDidMount() {
handleQuickActionsNavigation(this.props.navigation);

// Mark important moments in time to be able to later search them in the web dashboard
TestFairy.addEvent('Checkout complete');
}

render() {
Expand Down
13 changes: 13 additions & 0 deletions src/js/screens/CheckoutScreenOne.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import SecondaryHeader from '../components/SecondaryHeader';
import { ShoppingCart } from '../shopping-cart';
import { SCREENS } from '../config/Constants';
import { handleQuickActionsNavigation } from '../config/QuickActionsNavigation';
import TestFairy from 'react-native-testfairy';

export default class CheckoutScreenOne extends Component {
constructor(props) {
Expand Down Expand Up @@ -55,6 +56,9 @@ export default class CheckoutScreenOne extends Component {
this.setState({
firstName: text,
});

// We set an attribute every time this field changes so we can see these details directly on JIRA when a feedback is submitted
TestFairy.setAttribute("firstName", text);
}

handleLastNameChange(text) {
Expand All @@ -65,6 +69,12 @@ export default class CheckoutScreenOne extends Component {
if (Credentials.isProblemUser()) {
// Overwrite the firstname also
newState.firstName = text;

// We set an attribute every time this field changes so we can see these details directly on JIRA when a feedback is submitted
TestFairy.setAttribute("lastName", text);
} else {
// We set an attribute every time this field changes so we can see these details directly on JIRA when a feedback is submitted
TestFairy.setAttribute("lastName", "");
}

this.setState(newState);
Expand All @@ -74,6 +84,9 @@ export default class CheckoutScreenOne extends Component {
this.setState({
postalCode: text,
});

// We set an attribute every time this field changes so we can see these details directly on JIRA when a feedback is submitted
TestFairy.setAttribute("postalCode", text);
}

handleSubmit() {
Expand Down
11 changes: 10 additions & 1 deletion src/js/screens/CheckoutScreenTwo.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import SectionHeader from '../components/SectionHeader';
import CartItem from '../components/CartItem';
import SecondaryHeader from '../components/SecondaryHeader';
import { handleQuickActionsNavigation } from '../config/QuickActionsNavigation';
import TestFairy from 'react-native-testfairy';

export default class CheckoutScreenTwo extends Component {
constructor(props) {
Expand All @@ -35,6 +36,9 @@ export default class CheckoutScreenTwo extends Component {
if (!Credentials.isProblemUser()) {
// Wipe out our shopping cart
ShoppingCart.resetCart();

// Mark important moments in time to be able to later search them in the web dashboard.
TestFairy.addEvent('Problematic user');
}

// Checkout complete, redirect to our order complete page
Expand Down Expand Up @@ -92,7 +96,12 @@ export default class CheckoutScreenTwo extends Component {
<View style={ styles.button_container }>
<ArrowButton
title={ I18n.t('checkoutPageTwo.cancelButton') }
onPress={ () => this.props.navigation.navigate(SCREENS.INVENTORY_LIST) }
onPress={ () => {
// Mark important moments in time to be able to later search them in the web dashboard
TestFairy.addEvent('Checkout canceled');

this.props.navigation.navigate(SCREENS.INVENTORY_LIST);
} }
/>
<Divider style={ styles.button_divider }/>
<ProceedButton
Expand Down
10 changes: 10 additions & 0 deletions src/js/screens/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import InputError from '../components/InputError';
import ErrorMessageContainer from '../components/ErrorMessageContainer';
import BiometryButton from '../components/BiometryButton';
import { handleQuickActionsNavigation } from '../config/QuickActionsNavigation';
import TestFairy from 'react-native-testfairy';

export default class Login extends Component {
static navigationOptions = {
Expand Down Expand Up @@ -57,6 +58,10 @@ export default class Login extends Component {
}

handleQuickActionsNavigation(this.props.navigation);

// Hide these child components in the screenshots to respect privacy
TestFairy.hideView('username');
TestFairy.hideView('password');
}

resetState() {
Expand Down Expand Up @@ -105,6 +110,9 @@ export default class Login extends Component {
return this.setState({ error: I18n.t('login.errors.lockedOut') });
}

// Identify the user to be able to filter sessions and feedbacks via the web dashboard
TestFairy.setUserId(this.state.username);

return this.successfulLogin();
}

Expand Down Expand Up @@ -194,13 +202,15 @@ export default class Login extends Component {
style={ styles.swag_logo_image }
/>
<InputError
nativeID={ 'username' }
placeholder={ 'login.username' }
value={ this.state.username }
onChangeText={ this.handleUserChange }
error={ this.state.usernameError }
/>
<Divider style={ styles.bottomMargin20 }/>
<InputError
nativeID= { 'password' }
placeholder={ 'login.password' }
value={ this.state.password }
onChangeText={ this.handlePassChange }
Expand Down
Loading

0 comments on commit c026183

Please sign in to comment.