使用NodeJS+Appium搭建Android自动化测试框架

2024-02-06  本文已影响0人  FredricZhu

本例是参考Youtube NodeJS Appium教程自己写的框架,没有直接用作者给的框架,但是Android测试的方方面面都已经支持,而且简单好用。
Android的环境搭建方面,可以参考如下视频,只需要管SDK就可以, AndroidStudio部分处理完之后可以删掉。另外需要注意的一个点是uiautomatorviewer这个组件已经过期,不可用了。不用刻意去找tools目录了。直接用appium_inspector去inspect元素即可
https://www.acfun.cn/v/ac43667234

工程的整体代码在如下repo,
https://gitlab.com/zhuge20100104/cpp_practice/-/tree/master/automation/appiums/6_page_objects?ref_type=heads

包括并发执行,截图等等。
测试框架基于Mocha Test FrameWork + Appium + WebDriverIO。

相关组件版本

nodejs: v18.19.0
appium server: 1.22.3
appium_inspector:  在这里下载Latest Release就可以了

各种包,

"dependencies": {
    "mochawesome": "^7.1.3",
    "webdriverio": "^6.4.6",
    "chai": "^4.4.1"
  },
  "devDependencies": {
    "@babel/cli": "^7.11.6",
    "@babel/core": "^7.11.6",
    "@babel/preset-env": "^7.11.5",
    "@babel/register": "^7.11.5"
  }

程序代码如下,
package.json

{
  "name": "6_page_objects",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "extension": "js",
  "scripts": {
    "test": "mocha --file ./src/test_scripts/account/TC_001_Login.js --no-timeouts --reporter mochawesome && cp -rf ./screenshot ./mochawesome-report"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "mochawesome": "^7.1.3",
    "webdriverio": "^6.4.6",
    "chai": "^4.4.1"
  },
  "devDependencies": {
    "@babel/cli": "^7.11.6",
    "@babel/core": "^7.11.6",
    "@babel/preset-env": "^7.11.5",
    "@babel/register": "^7.11.5"
  }
}

utils/Consts.js

const capabilities = {
    "platformName": "Android",
    "appium:automationName": "UiAutomator2",
    "appium:udid": "R28M32MWVBH",
    "appium:appPackage": "com.wdiodemoapp",
    "appium:appActivity": ".MainActivity",
    "appium:noReset": true
}


const wdOpts = {
    hostname: process.env.APPIUM_HOST || 'localhost',
    path: "/wd/hub",
    port: parseInt(process.env.APPIUM_PORT, 10) || 4723,
    logLevel: 'info',
    capabilities,
    waitforTimeout: 6000
};

export {capabilities, wdOpts}

utils/Funcs.js

import { wdOpts } from './Consts.js';
import {remote} from 'webdriverio';
import pkg from 'mochawesome/addContext.js'
const addContext = pkg;


let getDriver = async (wd_opts) => {
    return await remote(wd_opts)
}

global.driver = await getDriver(wdOpts)
global.$ = (selector) => driver.$(selector)
global.$$ = (selector) => driver.$$(selector)

let releaseResource = async (driver_) => {
    console.log("releaseResource")
    await driver_.pause(1000)
    await driver_.deleteSession()
}

let screenShot = async function(ctx, driver_, path_) {
    addContext(ctx, path_)
    await driver_.saveScreenshot(path_)
}

let releaseEach = async function(ctx, driver_, path_) {
    if(ctx.currentTest.state !== 'passed') {
        screenShot(ctx, driver_, path_)
    } 
}

export {releaseResource, addContext, screenShot, releaseEach }

page_objects/account/Login.js

import { expect } from "chai";

const LOGIN_ICON_HOME_SCREEN = '~Login'
const EMAIL_TEXT_FIELD = '~input-email'
const PASSWORD_TEXT_FIELD = '~input-password'
const LOGIN_BTN = '~button-LOGIN'
const SUCCESS_MSG = '//android.widget.TextView[@resource-id="android:id/message"]'

class Login {
    async is_on_home_page() {
        await $(LOGIN_ICON_HOME_SCREEN).then(async ele => await ele.waitForDisplayed())
        return await $(LOGIN_ICON_HOME_SCREEN).then(async ele => await ele.isDisplayed())
    }

    async go_to_login_page() {
        await $(LOGIN_ICON_HOME_SCREEN).then(async ele => await ele.click())
        await $(LOGIN_BTN).then(async ele => await ele.waitForDisplayed())
        return await $(LOGIN_BTN).then(async ele => await ele.isDisplayed())
    }
    

    async login() {
        await $(EMAIL_TEXT_FIELD).then(async ele => await ele.setValue('a@a.com'))
        await $(PASSWORD_TEXT_FIELD).then(async ele => await ele.setValue('12345678'))
        await $(LOGIN_BTN).then(async ele => await ele.click())
    }

    async is_login_successful() {
        await $(SUCCESS_MSG).then(async ele => await ele.waitForDisplayed())
        let text = await $(SUCCESS_MSG).then(async ele => await ele.getText())
        console.log("Text is: " + text)
        expect(text).to.equal("You are logged in!!")
        return true
    }
}

export {Login}

test_scripts/account/TC_001_Login.js

import { releaseResource, addContext, releaseEach } from '../../utils/Func.js';
import { Login } from '../../page_objects/account/Login.js';

describe('Learning WebdriverIO API', () => {
    after(async function() {
      releaseResource(driver)
    })

    afterEach(async function() {
      releaseEach(this, driver, './screenshot/login.png')
    })

    it('should click on Login Icon successfully', async function () {
      let login = new Login()
      await login.is_on_home_page()
      addContext(this, 'Go to home page successfully')
      await login.go_to_login_page()
      addContext(this, 'Go to login page successfully')
      await login.login()
      addContext(this, 'Login')
      await login.is_login_successful()
      addContext(this, 'Login successfully')
    });
});

本例故意用了一个错误的chai assert,好让大家看一下错误以后截图的效果
Report


image.png image.png image.png
上一篇 下一篇

猜你喜欢

热点阅读