<<<<<<< HEAD
(This project was executed with apk, app, ipa generated from) Repository (link)
Mobile, Web and API automation framework based on Cucumber - WebdriverIO - NodeJS - TypeScript - Axios - Allure Reports. With support to execute test on BrowserStack cloud service.
- Install a Git Client and clone Automation project.
- Install latest version of Node.js from the official website or using nvm (nvm approach is preferred).
- If you install Node.js from the official website, you must check the 'Tools for Native Modules' checkbox during the installation (it is not checked by default).
- Go to official website JDK 1.8 , go to Java SE Development Kit download and install the last version.
- Install Android Studio from the official website.
- Lastest Appium Server version from the official website.
- Right click the Computer icon.
- Choose Properties from the context menu.
- Click the Advanced system settings link.
- Click Environment Variables.
- In the section System Variables, create or edit "ANDROID_HOME" variable and set path of Android sdk. For example
Name : ANDROID_HOME
Value : C:\Users\USERID\AppData\Local\Android\Sdk
- In the section System Variables, create or edit "JAVA_HOME" variable and set path of Android sdk. For example
Name : JAVA_HOME
Value : C:\Program Files\Java\jdk1.8.0_241
- In the section System Variables, create or edit "path" variable and set path of Android sdk platform-tools. For example
Name : path
Value : C:\Users\USERID\AppData\Local\Android\Sdk\platform-tools
- In the section System Variables, create or edit "path" variable and set path of Android emulator. For example
Name : path
Value : C:\Users\USERID\AppData\Local\Android\Sdk\emulator
- Open **Android Studio** and go to: **Tools** -> **AVD Manager** -> **Create Virtual Device...**
- Select **Nexus 6** - > **Next** -> **API Level 10** -> **Next** -> Then rename device as Nexus 6 -> **Finish**.
**List of devices connected**
With this command we can see a list of emualtors available on our local machine.
```
$ emulator -list-avds
```
**Open an emulator**
We can open an emulator with the command **emulator** *@device_name* from the list of devices availables on local machine.
For example:
```
$ emulator @Nexus_6
```
As root or admin.
To install dependencies:
$ npm installTo execute web testing in Chrome
$ npm run start-webWith an emulator open to execute mobile testing on local machine.
$ npm run start-mobileExclusive BrowserStack: With user and key of an account and to execute mobile testing. Account's data must be in config file: config\wdio.mobile.bs.conf.ts.
$ npm run start-mobile-bs$ npm run clean-reportTo Open an Allure Report
$ npm run open-reportIn this folder we need to have the apk artifact.
We have this files:
- wdio.chrome.conf.ts: with configurations to run tests on Chrome.
- wdio.mobile.conf.ts: with configurations to run tests on a local mobile Android Device.
- wdio.mobile.bs.conf.ts: with configurations to run mobile tests on a BrowserStack mobile Android Device.
Configuration and parameters:
-
specs: List of cucumber features to execute.
-
reporters/reporter options: Specifies the reporter to use, we use Allure Report.
-
host/port/path: Configuration of Appium server.
-
maxInstances: Maximus instances per execution, by default we must execute with 1 for mobile.
-
waitforTimeout/connectionRetryTimeout: Parameters to set maximus time out.
-
capabilities: set of options related to device, platform, device name.
- browserName: 'chrome' for web, empty for mobile.
- maxInstances: To define the maximum amount to run parallel tests.
- platformName: Android/iOS.
- app: './app/Android-NativeDemoApp-0.4.0.apk'*.
- appPackage:: Package name of the app.
- Field: manifest.package of AndroidManifest.xml file of apk.
- appActivity:: Name of the first view or activity that open when we open our app.
- Field: manifest.activity (android:name) of AndroidManifest.xml file of apk.
- platformVersion: Associated to API version, Android version. For example: 10.
- deviceName: Identifier of the device. For example: Nexus 6 of default value: emulator-5554.
- automationName: We always use: UiAutomator2 for Android.
-
capabilities: (BrowserStack) set of options related to device, platform, device name.
- appium:app: app_url value that we get after uploading an app to BrowserStack, For example: 'bs://dbf4840f740e91f9d2e546479afd820ebc5a6e56'.
- appium:deviceName: Identifier of the device. For example: Google Pixel 3.
- appium:platformVersion: Associated to API version, Android version. For example: 10.
- appium:automationName: We always use: UiAutomator2 for Android.
-
services:
- For web we use chromedriver.
- For mobile we use appium service.
- To use BrowserStack service we use: browserstack and browserstackLocal property in true.
-
logLevel: We can use debug to log all the actions on appium or silent mode only to log final results.
-
framework/cucumberOpts: We use Cucumber framework to execute.
- On cucumberOpts.require we specify the steps of .ts files to exectute of the folder stepDefinitions.
List of hooks of Cucumber we use:
IMPORTANT: All hooks must be implemented using async/await.
Examples:
/**
* Runs after a Cucumber step
*/
afterStep: async function () {
await browser.takeScreenshot();
}, /**
* Runs after a Cucumber scenario
*/
afterScenario: async function () {
await browser.closeApp();
await browser.reset();
},- onPrepare: Actions to to before de begin of the excecution.
- afterCommand: Actions to do after a command is executed, for example after a click we want to take a screenshot.
- onComplete: Actions to do after all test had been executed.
- beforeScenario: Actions to do before a scenario is executed. For example: we use browser.reset(); to prepeare the initial conditions.
- afterScenario: Actions to do after a scenario was executed. For example: browser.closeApp(); to close a mobile app. browser.reloadSession(); to reload a web browser.
We can use differents hooks, please visit WebDriver IO Hooks for more details.
On this folder we have the list of cucumber .feature files group by functionalities.
On this folder we have the definitions of each view of our application using Page Object Model pattern to define using Typescript.
The basic structure of each POM must have: Filename: viewToModelPO.ts
import Page from './page';
/**
* sub page containing specific selectors and methods for a specific page
*/
class LoginPage extends Page {
/**
* define selectors using getter methods
*/
get inputUsername() { return $('#username') }
get inputPassword() { return $('#password') }
get btnSubmit() { return $('button[type="submit"]') }
/**
* a method to encapsule automation code to interact with the page
* e.g. to login using username and password
*/
async login(username: string, password: string) {
await (await this.inputUsername).setValue(username);
await (await this.inputPassword).setValue(password);
await (await this.btnSubmit).click();
}
/**
* overwrite specifc options to adapt it to page object
*/
open() {
return super.open('login');
}
}
export default new LoginPage();On this folder we have to create the steps per functionality out set of scenarios defined on our .feature files.
For example: We have an login.feature file with this definition to execute with a set of 2 groups of data:
@run @web
Feature: The Internet Guinea Pig Website
@login_web
Scenario Outline: As a user <username>, I can log into the secure area
Given I am on the login page
When I login with <username> and <password>
Then I should see a flash message saying <message>
Examples:
| username | password | message |
| tomsmith | SuperSecretPassword! | You logged into a secure area! |
| foobar | barfoo | Your username is invalid! |For each Given, When, Then step we have to create a step to do the behavior that happen on the application.
For example: On our loginSteps.ts file, we will import our pages defined to create a test.
import { Given, Then, When } from '@cucumber/cucumber';
import LoginPage from '../../pages/web/login.page';
import Page from '../../pages/web/page';
import SecurePage from '../../pages/web/secure.page';
const pages: { [key: string]: Page } = { ["login"]: LoginPage };
Given(/^I am on the (\w+) page$/, async (page: string) => {
await pages[page].open();
});
When(/^I login with (\w+) and (.+)$/, async (username: string, password: string) => {
await LoginPage.login(username, password);
});
Then(/^I should see a flash message saying (.*)$/, async (message: string) => {
await expect(SecurePage.flashAlert).toBeExisting();
await expect(SecurePage.flashAlert).toHaveTextContaining(message);
});On this folder we have a few utility classes for example: constants.ts, utils.ts.
Scripts desctiptions:
clean: Delete all files generated on each execution like reports.start-mobile: with this script we only run the scenarios or features with @run tag. on every .feature file that we have on our wdio ./config/wdio.mobile.config.ts on field specs and have to be releated to the stepDefinition files on cucumberOpts.require from the same config file.start-mobile-bs: exclusive to use BrowserStack service. With this script we only run the scenarios or features with @run tag. on every .feature file that we have on our wdio ./config/wdio.mobile.bs.config.ts on field specs and have to be releated to the stepDefinition files on cucumberOpts.require from the same config file.start-web: with this script we only run the scenarios or features with @run tag. on every .feature file that we have on our wdio ./config/wdio.chrome.config.ts on field specs and have to be releated to the stepDefinition files on cucumberOpts.require from the same config file.clean-report: We generate the allure reports after an excecution.open-report: We can open de allure reports.version: We can auto-generate release note of our changes.
Generate *PO.ts files to have our Page Object Model class
Open utils/generator/generator.ts file and set the list the elements that will be nessesary for our scripts.
For example: Header Page
import { Util } from './util';
/**
* on fieldList we define the names of our UI Elements that we will model in our POM classes
*/
const fieldList: string[] = [
'menu_side',
'title_header',
'logout_btn',
];
const util: Util = new Util();
util.generatePageObjectFile(fieldList);Run generator
npm run generate-po
It will generate viewPO.ts file for page layer. We only need to change class name and fill the path to locale the elements.
For example:
--------------------------------------------
poGenerated/viewPO.ts
--------------------------------------------
export class ViewPO {
private menu_side: string;
private title_header: string;
private logout_btn: string;
constructor() {
this.menu_side = '#menu_side';
this.title_header = '#title_header';
this.logout_btn = '#logout_btn';
}
public validatePage(): void {
browser.$(this.menu_side).waitForExist();
browser.$(this.title_header).waitForExist();
browser.$(this.logout_btn).waitForExist();
}
public menuSide(): WebdriverIO.Element {
browser.$(this.menu_side).waitForExist();
return browser.$(this.menu_side);
}
public titleHeader(): WebdriverIO.Element {
browser.$(this.title_header).waitForExist();
return browser.$(this.title_header);
}
public logoutBtn(): WebdriverIO.Element {
browser.$(this.logout_btn).waitForExist();
return browser.$(this.logout_btn);
}
}If you don't have an account but you want to try this service, firstly you need to create an ACCESS_KEY, that is BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY.
To create an account please go to the official website to sign up.
When you are logged in, go to profile and click on "Go to Dashboard" to get username and access key.
This credentials have to be in config file, for example in: config\wdio.mobile.bs.conf.ts y fields: user and key entry respectively.
Upload App
An API to upload the App you want to test on the BrowserStack servers for interactive app testing. Use it to upload via CLI or automation scripts.
curl -u "BROWSERSTACK_USERNAME:BROWSERSTACK_ACCESS_KEY" -X POST "https://api-cloud.browserstack.com/app-automate/upload" -F "file=@/path/to/app/file/Application-debug.apk"Example:
BROWSERSTACK_USERNAME=sdetbaufest_zJFoTm BROWSERSTACK_ACCESS_KEY=yMT1Mg8rXX3MnH1bvqFC
curl -u "sdetbaufest_zJFoTm:yMT1Mg8rXX3MnH1bvqFC" -X POST "https://api-cloud.browserstack.com/app-automate/upload" -F "file=@C:/baf/app/Android-NativeDemoApp-0.4.0.apk"Note:
1. Supported file formats are .apk and .aab for Android apps and .ipa for iOS apps.
2. App upload will take few seconds to about a minute depending on the size of your app. Do not interrupt the curl command until you get the response back.
3. If you upload an iOS app, we will resign the app with our own provisioning profile to be able to install your app on our devices during test execution.
4. We will delete the uploaded app after 30 days from the date of upload.
5. Max file size supported is 1 GB.After executing this command you will get the app_url value:
{"app_url":"bs://f21b5b310fc6684c6f9dbd24d2549c7a586cde85"}That app_url value is needed to add to capabilities in the config file to have a reference of our app to be automated.
capabilities: [{
"appium:app": 'bs://f21b5b310fc6684c6f9dbd24d2549c7a586cde85',
"appium:deviceName": 'Google Pixel 3',
"appium:platformVersion": '10.0',
"appium:automationName": 'UiAutomator2',
"platformName": "Android",
}],Run "version" command to create the change log with details of changes that we made on each sprint.
npm run versionThis will create a HISTORY.md file.
For our commits message we use Conventional Commits specification which provides an easy set of rules for creating an explicit commit history adding readable meaning to commit messages.
-
Fork from
masterbranch. -
Create your branch with the reference of the associated ticket id of your project management tool like Jira, Azure DevOps (
git checkout -b type/####-Description) -
Commit your changes (
git commit -am 'feat(feature):') -
Push to the branch (
git push origin type/####-description) -
Create new Pull Request =======
2489a255b86212df622d6ddbd7525a6dd528bb4b