Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
466 changes: 259 additions & 207 deletions package-lock.json

Large diffs are not rendered by default.

169 changes: 86 additions & 83 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,99 +16,102 @@
"prebuild:clean": "expo prebuild --clean",
"test:e2e": "export ANDROID_HOME=$HOME/Library/Android/sdk && export PATH=$PATH:$ANDROID_HOME/platform-tools && wdio run test/wdio.conf.ts",
"test:e2e:ios": "export ANDROID_HOME=$HOME/Library/Android/sdk && export PATH=$PATH:$ANDROID_HOME/platform-tools && wdio run test/wdio.ios.conf.ts",
"test:e2e:android": "export ANDROID_HOME=$HOME/Library/Android/sdk && export PATH=$PATH:$ANDROID_HOME/platform-tools && wdio run test/wdio.conf.ts",
"test:e2e:android": "export ANDROID_HOME=$HOME/Library/Android/sdk && export PATH=$PATH:$ANDROID_HOME/platform-tools && wdio run test/wdio.android.conf.ts",
"build:e2e:android": "export JAVA_HOME=$(/usr/libexec/java_home -v 21) && export PATH=$JAVA_HOME/bin:$PATH && npx expo export --platform android --output-dir ./dist && npx expo prebuild --platform android --clean && echo \"sdk.dir=$HOME/Library/Android/sdk\" > android/local.properties && cd android && ./gradlew assembleRelease && cp app/build/outputs/apk/release/app-release.apk ../test/apps/app-release.apk",
"build:e2e:ios": "export NVM_DIR=\"$HOME/.nvm\" && [ -s \"$NVM_DIR/nvm.sh\" ] && \\. \"$NVM_DIR/nvm.sh\" && npx expo export --platform ios --output-dir ./dist && cp -r dist/_expo ios/ 2>/dev/null || true && RELEASE_APP=$(find ~/Library/Developer/Xcode/DerivedData -name 'wdkstarterreactnative.app' -path '*/Release-iphonesimulator/*' -type d | head -1) && if [ -n \"$RELEASE_APP\" ]; then rm -rf test/apps/wdkstarterreactnative.app && cp -r \"$RELEASE_APP\" test/apps/wdkstarterreactnative.app && echo 'Copied existing Release build'; else echo 'No existing Release build found. Please run: npx expo run:ios --configuration Release first'; exit 1; fi"
},
"dependencies": {
"@craftzdog/react-native-buffer": "^6.1.0",
"@expo/vector-icons": "^15.0.2",
"@gorhom/bottom-sheet": "^5.2.6",
"@react-native-async-storage/async-storage": "^2.2.0",
"@react-navigation/bottom-tabs": "^7.4.0",
"@react-navigation/elements": "^2.6.3",
"@react-navigation/native": "^7.1.8",
"@reduxjs/toolkit": "^2.9.0",
"@tetherto/pear-wrk-wdk": "^1.0.0-beta.4",
"@tetherto/wdk-pricing-bitfinex-http": "^1.0.0-beta.1",
"@tetherto/wdk-pricing-provider": "^1.0.0-beta.1",
"@tetherto/wdk-react-native-provider": "^1.0.0-beta.3",
"@tetherto/wdk-uikit-react-native": "^1.0.0-beta.2",
"b4a": "^1.7.2",
"bip39": "^3.1.0",
"browserify-zlib": "^0.2.0",
"decimal.js": "^10.6.0",
"events": "^3.3.0",
"expo": "~54.0.8",
"expo-build-properties": "~1.0.9",
"expo-camera": "~17.0.8",
"expo-clipboard": "~8.0.7",
"expo-constants": "~18.0.9",
"expo-crypto": "^15.0.7",
"expo-dev-client": "^6.0.12",
"expo-font": "~14.0.8",
"expo-haptics": "~15.0.7",
"expo-image": "~3.0.8",
"expo-linking": "~8.0.8",
"expo-router": "~6.0.6",
"expo-splash-screen": "~31.0.10",
"expo-status-bar": "~3.0.8",
"expo-symbols": "~1.0.7",
"expo-system-ui": "~6.0.7",
"expo-web-browser": "~15.0.7",
"http2-wrapper": "^2.2.1",
"https-browserify": "^1.0.0",
"lucide-react-native": "^0.544.0",
"nice-grpc-web": "^3.3.8",
"path-browserify": "^1.0.1",
"process": "^0.11.10",
"querystring-es3": "^0.2.1",
"@craftzdog/react-native-buffer": "6.1.1",
Comment thread
tobi-legan marked this conversation as resolved.
"@expo/vector-icons": "15.0.2",
"@gorhom/bottom-sheet": "5.2.6",
"@react-native-async-storage/async-storage": "2.2.0",
"@react-navigation/bottom-tabs": "7.4.9",
"@react-navigation/elements": "2.6.5",
"@react-navigation/native": "7.1.18",
"@reduxjs/toolkit": "2.9.0",
"@tetherto/pear-wrk-wdk": "1.0.0-beta.4",
"@tetherto/wdk-pricing-bitfinex-http": "1.0.0-beta.1",
"@tetherto/wdk-pricing-provider": "1.0.0-beta.1",
"@tetherto/wdk-react-native-provider": "1.0.0-beta.3",
"@tetherto/wdk-uikit-react-native": "1.0.0-beta.2",
"b4a": "1.7.3",
"bip39": "3.1.0",
"browserify-zlib": "0.2.0",
"decimal.js": "10.6.0",
"events": "3.3.0",
"expo": "54.0.13",
"expo-build-properties": "1.0.9",
"expo-camera": "17.0.8",
"expo-clipboard": "8.0.7",
"expo-constants": "18.0.9",
"expo-crypto": "15.0.7",
"expo-dev-client": "6.0.15",
"expo-font": "14.0.9",
"expo-haptics": "15.0.7",
"expo-image": "3.0.9",
"expo-linking": "8.0.8",
"expo-router": "6.0.12",
"expo-splash-screen": "31.0.10",
"expo-status-bar": "3.0.8",
"expo-symbols": "1.0.7",
"expo-system-ui": "6.0.7",
"expo-web-browser": "15.0.8",
"http2-wrapper": "2.2.1",
"https-browserify": "1.0.0",
"lucide-react-native": "0.544.0",
"nice-grpc-web": "3.3.8",
"path-browserify": "1.0.1",
"process": "0.11.10",
"querystring-es3": "0.2.1",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-native": "0.81.4",
"react-native-bare-kit": "^0.10.2",
"react-native-chart-kit": "^6.12.0",
"react-native-crypto": "^2.2.1",
"react-native-device-info": "^14.1.1",
"react-native-fast-pbkdf2": "^0.3.1",
"react-native-gesture-handler": "~2.28.0",
"react-native-get-random-values": "^1.11.0",
"react-native-keychain": "^10.0.0",
"react-native-qr-svg": "^1.5.0",
"react-native-randombytes": "^3.6.2",
"react-native-reanimated": "~4.1.0",
"react-native-safe-area-context": "~5.6.0",
"react-native-screens": "~4.16.0",
"react-native-svg": "^15.13.0",
"react-native-tcp-socket": "^6.3.0",
"react-native-url-polyfill": "^2.0.0",
"react-native-web": "~0.21.0",
"react-native-bare-kit": "0.10.2",
"react-native-chart-kit": "6.12.0",
"react-native-crypto": "2.2.1",
"react-native-device-info": "14.1.1",
"react-native-fast-pbkdf2": "0.3.1",
"react-native-gesture-handler": "2.28.0",
"react-native-get-random-values": "1.11.0",
"react-native-keychain": "10.0.0",
"react-native-qr-svg": "1.5.0",
"react-native-randombytes": "3.6.2",
"react-native-reanimated": "4.1.3",
"react-native-safe-area-context": "5.6.1",
"react-native-screens": "4.16.0",
"react-native-svg": "15.14.0",
"react-native-tcp-socket": "6.3.0",
"react-native-url-polyfill": "2.0.0",
"react-native-web": "0.21.1",
"react-native-worklets": "0.5.1",
"react-redux": "^9.2.0",
"sodium-javascript": "^0.8.0",
"sonner-native": "^0.21.1",
"stream-browserify": "^3.0.0",
"stream-http": "^3.2.0"
"react-redux": "9.2.0",
"sodium-javascript": "0.8.0",
"sonner-native": "0.21.1",
"stream-browserify": "3.0.0",
"stream-http": "3.2.0"
},
"devDependencies": {
"@types/b4a": "^1.6.5",
"@types/mocha": "^10.0.10",
"@types/node": "^20.0.0",
"@types/react": "~19.1.0",
"@wdio/appium-service": "^9.13.0",
"@wdio/cli": "^9.13.0",
"@wdio/globals": "^9.13.0",
"@wdio/local-runner": "^9.13.0",
"@wdio/mocha-framework": "^9.13.0",
"@wdio/spec-reporter": "^9.13.0",
"eslint": "^9.25.0",
"eslint-config-expo": "~10.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"prettier": "^3.6.2",
"react-native-svg-transformer": "^1.5.1",
"sharp-cli": "^5.2.0",
"typescript": "~5.9.2"
"@types/b4a": "1.6.5",
"@types/mocha": "10.0.10",
"@types/node": "20.19.25",
"@types/react": "19.1.17",
"@wdio/appium-service": "9.21.0",
"@wdio/cli": "9.21.1",
"@wdio/globals": "9.17.0",
"@wdio/local-runner": "9.21.0",
"@wdio/mocha-framework": "9.21.0",
"@wdio/spec-reporter": "9.20.0",
"dotenv": "17.2.3",
"eslint": "9.37.0",
"qase-api-client": "1.1.1",
"strip-ansi": "6.0.1",
"eslint-config-expo": "10.0.0",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-prettier": "5.5.4",
"prettier": "3.6.2",
"react-native-svg-transformer": "1.5.1",
"sharp-cli": "5.2.0",
"typescript": "5.9.3"
},
"peerDependencies": {
"react": "19.1.0",
Expand Down
34 changes: 23 additions & 11 deletions test/e2e/pageObjects/home-onboarding-screen.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import { $ } from '@wdio/globals';
import { $, driver } from '@wdio/globals';

export class HomeOnboardingScreen {
/**
* Gets the title and subtitle welcome message elements
* Uses text selector since these are TextView elements without content-desc
* Cross-platform: Uses class chain for iOS and Android UiSelector for Android
*/
async getTitleAndSubtitleWelcomeMessage() {
// Use text selector for TextView elements
const titleElement = $('android=new UiSelector().text("Welcome!")');
const subtitleElement = $('android=new UiSelector().text("Set up your wallet and start exploring the crypto world.")');
// Cross-platform text selector
// For iOS: Use class chain or accessibility ID
// For Android: UiSelector works
const caps = driver.capabilities as WebdriverIO.Capabilities;
const isIOS = (caps.platformName || caps['appium:platformName']) === 'iOS';

const titleElement = isIOS
? $('-ios class chain:**/XCUIElementTypeStaticText[`name == "Welcome!" OR label == "Welcome!"`]')
: $('android=new UiSelector().text("Welcome!")');

const subtitleElement = isIOS
? $('-ios class chain:**/XCUIElementTypeStaticText[`name CONTAINS "Set up your wallet" OR label CONTAINS "Set up your wallet"`]')
: $('android=new UiSelector().text("Set up your wallet and start exploring the crypto world.")');

// Wait for elements to be displayed
await titleElement.waitForDisplayed({ timeout: 5000 });
await subtitleElement.waitForDisplayed({ timeout: 5000 });
await titleElement.waitForDisplayed({ timeout: 15000 });
await subtitleElement.waitForDisplayed({ timeout: 15000 });

// Get text from elements
const titleText = await titleElement.getText();
Expand All @@ -22,20 +32,22 @@ export class HomeOnboardingScreen {
}

/**
* Gets the Create Wallet button element using content-desc selector
* Gets the Create Wallet button element using accessibility ID
* Cross-platform: ~ prefix works for both iOS and Android
* @returns Chainable WebdriverIO element
*/
getCreateWalletButton() {
// Use accessibility ID selector (content-desc) - ~ prefix means content-desc
// Use accessibility ID selector - ~ prefix works for both iOS and Android
return $('~Create Wallet');
}

/**
* Gets the Import Wallet button element using content-desc selector
* Gets the Import Wallet button element using accessibility ID
* Cross-platform: ~ prefix works for both iOS and Android
* @returns Chainable WebdriverIO element
*/
getImportWalletButton() {
// Use accessibility ID selector (content-desc) - ~ prefix means content-desc
// Use accessibility ID selector - ~ prefix works for both iOS and Android
return $('~Import Wallet');
}
}
25 changes: 17 additions & 8 deletions test/e2e/specs/onboarding.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { driver, expect } from '@wdio/globals';
import { HomeOnboardingScreen } from '../pageObjects/home-onboarding-screen';
import { qase } from '../utils/qase-wrapper';

const homeOnboardingScreen = new HomeOnboardingScreen();

describe('Wallet App E2E Tests', () => {
it('should launch the standalone app and verify the create wallet button', async () => {
describe('Onboarding Screen', () => {
it('TW-1: First launch', qase('TW-1', async () => {
// Wait for app to load by waiting for the welcome message to appear
const { titleText, subtitleText } = await homeOnboardingScreen.getTitleAndSubtitleWelcomeMessage();
expect(titleText).toContain('Welcome!');
Expand All @@ -18,10 +19,18 @@ describe('Wallet App E2E Tests', () => {
await createWalletButton.waitForDisplayed({ timeout: 10000 });
await importWalletButton.waitForDisplayed({ timeout: 10000 });

// Verify buttons have correct content-desc (accessibility label)
const contentDesc = await createWalletButton.getAttribute('content-desc');
const importContentDesc = await importWalletButton.getAttribute('content-desc');
expect(contentDesc).toContain('Create Wallet');
expect(importContentDesc).toContain('Import Wallet');
});
// Verify buttons have correct accessibility label
// iOS uses 'name' or 'label', Android uses 'content-desc'
const caps = driver.capabilities as WebdriverIO.Capabilities;
const isIOS = (caps.platformName || caps['appium:platformName']) === 'iOS';
const createButtonLabel = isIOS
? (await createWalletButton.getAttribute('name')) || (await createWalletButton.getAttribute('label'))
: await createWalletButton.getAttribute('content-desc');
const importButtonLabel = isIOS
? (await importWalletButton.getAttribute('name')) || (await importWalletButton.getAttribute('label'))
: await importWalletButton.getAttribute('content-desc');

expect(createButtonLabel).toContain('Create Wallet');
expect(importButtonLabel).toContain('Import Wallet');
}));
});
Loading