Skip to content

Add custom_wdio_E2E tests for Android and iOS using WebdriverIO + Appium #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
allure-results
node_modules
node_modules
custom_wdio_E2E/ios/logs
custom_wdio_E2E/ios/local.log
custom_wdio_E2E/ios/node_modules
custom_wdio_E2E/android/logs
custom_wdio_E2E/android/local.log
custom_wdio_E2E/android/node_modules
custom_wdio_E2E/android/node_modules
custom_wdio_E2E/ios/node_modules
.gitignore
local.log
Binary file added custom_wdio_E2E/android/app/WikipediaSample.apk
Binary file not shown.
19 changes: 19 additions & 0 deletions custom_wdio_E2E/android/configs/wdio.base.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const path = require('path');

exports.config = {
user: process.env.BROWSERSTACK_USERNAME || 'YOUR_USERNAME',
key: process.env.BROWSERSTACK_ACCESS_KEY || 'YOUR_ACCESS_KEY',

specs: [
'../features/**/*.feature' // Adjust this to the correct feature file location
],

logLevel: 'info',
framework: 'cucumber',

cucumberOpts: {
require: [path.resolve(__dirname, '../step-definitions/**/*.js')],
timeout: 60000
}
};

52 changes: 52 additions & 0 deletions custom_wdio_E2E/android/configs/wdio.browserstack.local.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const baseConfig = require('./wdio.base.conf');

exports.config = {
...baseConfig.config,
services: [
['browserstack',
{
browserstackLocal: true,
buildIdentifier: '#${BUILD_NUMBER}',
opts: {
forcelocal: true,
localIdentifier: 'webdriverio-browserstack-repo4'
}
}
],
],


commonCapabilities: {
platformName: 'android',
'appium:automationName': 'UiAutomator2',
'appium:app': 'bs://<app_id>',
'appium:autoGrantPermissions': true,
'bstack:options': {
realMobile: true,
interactiveDebugging: true,
projectName: 'WDIO App Automation Project',
buildName: 'Android Local Build',
sessionName: 'Search Wikipedia - Local Test Android'
}
},

capabilities: [
{
'bstack:options': {
deviceName: 'Google Pixel 6',
osVersion: '12'
}
}
]
};

// Apply common caps
exports.config.capabilities.forEach(cap => {
for (const key in exports.config.commonCapabilities) {
if (typeof cap[key] === 'object') {
cap[key] = { ...exports.config.commonCapabilities[key], ...cap[key] };
} else {
cap[key] = exports.config.commonCapabilities[key];
}
}
});
67 changes: 67 additions & 0 deletions custom_wdio_E2E/android/configs/wdio.browserstack.parallel.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const baseConfig = require('./wdio.base.conf');

exports.config = {
...baseConfig.config,

services: [
[
'browserstack',
{ buildIdentifier: '#${BUILD_NUMBER}' },
],
],

maxInstances: 3,

commonCapabilities: {
platformName: 'android',
'appium:automationName': 'UiAutomator2',
'appium:app': 'bs://<app_id>',
'appium:autoGrantPermissions': true,
'bstack:options': {
projectName: 'WDIO App Automation Project',
sessionName: 'Sample App - Public Test',
buildName: 'Android Parallel Build',
realMobile: true,
debug: true,
interactiveDebugging: true,
local: false
}
},

capabilities: [
{
'bstack:options': {
deviceName: 'Samsung Galaxy S22',
osVersion: '12.0',
sessionName: 'Parallel - S22'
}
},
{
'bstack:options': {
deviceName: 'Google Pixel 6',
osVersion: '12.0',
sessionName: 'Parallel - Pixel 6'
}
},
{
'bstack:options': {
deviceName: 'OnePlus 9',
osVersion: '11.0',
sessionName: 'Parallel - OnePlus 9'
}
}
],


};

// Merge commonCapabilities into each capability
exports.config.capabilities.forEach(cap => {
for (const key in exports.config.commonCapabilities) {
if (typeof cap[key] === 'object') {
cap[key] = { ...exports.config.commonCapabilities[key], ...cap[key] };
} else {
cap[key] = exports.config.commonCapabilities[key];
}
}
});
48 changes: 48 additions & 0 deletions custom_wdio_E2E/android/configs/wdio.browserstack.public.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const baseConfig = require('./wdio.base.conf');

exports.config = {
...baseConfig.config,

services: [
[
'browserstack',
{ buildIdentifier: '#${BUILD_NUMBER}' },
],
],

commonCapabilities: {
platformName: 'android',
'appium:automationName': 'UiAutomator2',
'appium:app': 'bs://<app_id>',
'appium:autoGrantPermissions': true,
'bstack:options': {
realMobile: true,
projectName: 'WDIO App Automation Project',
buildName: 'Android Build - Public App Test',
sessionName: 'Search Wikipedia - Public Test Android',
debug: true,
interactiveDebugging: true,
local: false
}
},

capabilities: [
{
'bstack:options': {
deviceName: 'Samsung Galaxy S22',
osVersion: '12'
}
}
]
};

// Apply common caps
exports.config.capabilities.forEach(cap => {
for (const key in exports.config.commonCapabilities) {
if (typeof cap[key] === 'object') {
cap[key] = { ...exports.config.commonCapabilities[key], ...cap[key] };
} else {
cap[key] = exports.config.commonCapabilities[key];
}
}
});
15 changes: 15 additions & 0 deletions custom_wdio_E2E/android/features/search.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Feature: Wikipedia Search Testing

Scenario: Search for BrowserStack
Given I launch the search screen
When I search with keyword "BrowserStack"
Then The search results should be listed
Then I clear the search field to prevent interaction with it
Then I click on the ImageButton after every search

Scenario: Search for WebdriverIO
Given I launch the search screen
When I search with keyword "WebdriverIO"
Then The search results should be listed
Then I clear the search field to prevent interaction with it
Then I click on the ImageButton after every search
15 changes: 15 additions & 0 deletions custom_wdio_E2E/android/features/searchWeb.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Feature: Wikipedia Search Testing - Web Testing Tools

Scenario: Search for Playwright
Given I launch the search screen
When I search with keyword "Playwright"
Then The search results should be listed
Then I clear the search field to prevent interaction with it
Then I click on the ImageButton after every search

Scenario: Search for Cypress
Given I launch the search screen
When I search with keyword "Cypress"
Then The search results should be listed
Then I clear the search field to prevent interaction with it
Then I click on the ImageButton after every search
31 changes: 31 additions & 0 deletions custom_wdio_E2E/android/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "wdio_appaut_cucumber",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "npx wdio run wdio.conf.js",
"test:local": "npx wdio run ./configs/wdio.browserstack.local.conf.js",
"test:public": "npx wdio run ./configs/wdio.browserstack.public.conf.js",
"test:parallel": "npx wdio run ./configs/wdio.browserstack.parallel.conf.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@babel/register": "^7.25.9",
"@wdio/browserstack-service": "^9.12.5",
"@wdio/cli": "^9.12.5",
"@wdio/cucumber-framework": "^9.12.5",
"@wdio/local-runner": "^9.12.5",
"@wdio/selenium-standalone-service": "^8.14.0",
"@wdio/spec-reporter": "^9.12.3",
"appium-xcuitest-driver": "^9.2.0",
"chai": "^5.2.0",
"cucumber": "^6.0.7",
"wdio-chromedriver-service": "^8.1.1"
},
"dependencies": {
"appium": "^2.18.0"
}
}
59 changes: 59 additions & 0 deletions custom_wdio_E2E/android/step-definitions/searchSteps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// import { Given, When, Then } from '@wdio/cucumber-framework';

// Given('I try to search using Wikipedia App', async () => {
// const searchInit = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_container")');
// await searchInit.click();
// });

// When('I search with keyword BrowserStack', async () => {
// const searchInput = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")');
// await searchInput.setValue('BrowserStack');
// });

// Then('The search results should be listed', async () => {
// const results = await $$('android=new UiSelector().resourceId("org.wikipedia.alpha:id/page_list_item_title")');
// await expect(results.length).toBeGreaterThan(0);
// });

import { Given, When, Then } from '@wdio/cucumber-framework';


Given('I launch the search screen', async () => {
const searchContainer = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_container")');

// If search container is not visible, navigate back twice
let retries = 0;
while (!(await searchContainer.isDisplayed()) && retries < 2) {
await driver.back();
retries++;
}

// Ensure the search container is displayed
await searchContainer.waitForDisplayed({ timeout: 5000 });
await searchContainer.click();

const searchInput = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")');
await searchInput.waitForDisplayed({ timeout: 15000 });
await searchInput.clearValue(); // Clear input field in case it's pre-filled
});

When(/^I search with keyword "(.*)"$/, async (searchTerm) => {
const searchInput = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")');
await searchInput.setValue(searchTerm);
});

Then('The search results should be listed', async () => {
const results = await $$('android=new UiSelector().resourceId("org.wikipedia.alpha:id/page_list_item_title")');
await expect(results.length).toBeGreaterThan(0);
});

Then('I clear the search field to prevent interaction with it', async () => {
const searchInput = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")');
await searchInput.clearValue(); // Clear the search field to prevent further interaction
});

Then('I click on the ImageButton after every search', async () => {
// Find the ImageButton by its class name and click it after each search
const el4 = await $('android.widget.ImageButton'); // CLASS_NAME
await el4.click();
});
Binary file added custom_wdio_E2E/ios/app/BStackSampleApp.ipa
Binary file not shown.
19 changes: 19 additions & 0 deletions custom_wdio_E2E/ios/configs/wdio.base.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const path = require('path');

exports.config = {
user: process.env.BROWSERSTACK_USERNAME || 'YOUR_USERNAME',
key: process.env.BROWSERSTACK_ACCESS_KEY || 'YOUR_ACCESS_KEY',

specs: [
'../features/**/*.feature' // Adjust this to the correct feature file location
],

logLevel: 'info',
framework: 'cucumber',

cucumberOpts: {
require: [path.resolve(__dirname, '../step-definitions/**/*.js')],
timeout: 60000
}
};

Loading