Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

栏目: Node.js · 发布时间: 5年前

内容简介:在上一期内容中,我们介绍了Node.js 结合 Cucumber开发多端的自动化,并发布了演示视频:这一期我们就主要介绍一下开发的详细步骤。通过本例学习,可以掌握如何同时测试Windows,Mobile,Web应用。
Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

在上一期内容中,我们介绍了Node.js 结合 Cucumber开发多端的自动化,并发布了演示视频: 如何做跨平台业务流程自动化(Windows,Moible,Web)

这一期我们就主要介绍一下开发的详细步骤。

主要目标

通过本例学习,可以掌握如何同时测试Windows,Mobile,Web应用。

环境配置

  • 操作系统:Windows 10
  • 开发语言:node.js
  • 编辑工具:CukeTest
  • 被测应用:Windows Outlook邮件
  • 桌面端:Windows 10 Mail

Mobile端:安卓应用商店搜索"Outlook" Web端: outlook.live.com/mail/

其它必要库

自动化Mobile端使用到Appium,请在本机安装好Appium 以及Android相关配置环境(具体请在网上查找相关资料)

自动化Web端需要使用到selenium-server,以及浏览器驱动,可以在npm.taobao.org/ 下载。

操作步骤

1. 创建项目

打开CukeTest,新建项目,【项目模板】选择 "Basic",【项目名】输入"OutlookTesting",【项目路径】输入自己的本地目录。点击【创建】

Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

2. 安装项目依赖库

CukeTest本身自带的有操作Windows库的控件,所以我们只需要引用即可。针对Web端和Mobile端,我们使用开源的webdriver.io库作为实现库。具体api可以参考官方文档 webdriver.io/guide.html

【项目名】右键--【在命令行窗口打开】

Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

在打开的命令行窗口输入

npm install webdriverio @types/webdriverio --save
复制代码

安装成功之后会有如下提示

npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN outlooktesting@1.0.0 No repository field.

+ @types/webdriverio@4.13.0
+ webdriverio@4.14.0
added 155 packages from 192 contributors and audited 345 packages in 50.09s
found 0 vulnerabilities
复制代码

3. 创建驱动

分别为Windows,Mobile,Web 创建不同驱动。

features/support/web_driver.js

var webdriverio = require('webdriverio');// 设置浏览器信息
var options = {
    desiredCapabilities: {
        browserName: 'chrome'
    }};

//创建driver

function createDriver(){
    return webdriverio.remote(options)
}
exports.driver = createDriver();
复制代码

features/support/mobile_driver.js

const webdriverio = require('webdriverio');

//设置被测应用参数

let options = {
    desiredCapabilities: {
        platformName: "Android",
        deviceName: "9c83590", //设备序列串号 
        // platformVersion: "5.1", //系统平台版本
        appPackage: "com.microsoft.office.outlook", //package 名字
        appActivity: ".MainActivity", //启动activity 名字
        resetKeyboard: true,
        noReset: true,
        unicodeKeyboard: true
    },
    host: "127.0.0.1",
    port: 4723
}

//根据参数配置创建WebDriverIO实例;

function createDriver() {
    const client = webdriverio.remote(options);
    return client;
}

exports.app_driver = createDriver();
复制代码

创建Windows桌面应用模型文件features\support\Mail.tmodel

Windows驱动文件 features\support\win_driver.js

const { TestModel, Auto } = require("leanpro.win");

let path = require('path')

let tmodelfile = path.join(__dirname,'Mail.tmodel')

var model = TestModel.loadModel(tmodelfile);

exports.model = model;
复制代码

此时的目录结构为

│  package-lock.json
│  package.json
│
└─features
    │  feature1.feature
    │
    ├─step_definitions
    │      definitions1.js
    │
    └─support
            Mail.tmodel
            mobile_driver.js
            web_driver.js
            win_driver.js
复制代码

4. 编写测试场景

为了让我们的测试更有趣,这里虚拟了一个这样的剧本:

Jason作为公司的老板,开会需要用到一些培训文档,Carol作为公司职员,已经将培训文档做好并存储在公司电脑上。 Jason使用Windows桌面端 Mail向Carol发送邮件索要文档。 Carol在公司外边使用mobile收到邮件后利用mobile端回复Jason稍后会回到公司发送。 Carol回到公司后使用web端将文档作为附件发送给Jason。

利用这样的用户场景:可以将Windows,Mobile,Web 这三端的自动化连接起来。于是我们在feature文件中可以如下编辑:

features/feature1.feature

# language: zh-CN

功能: 同时自动化desktop,mobile,web
Outlook 应用分为移动端,Windows端和Web端。
Jason在Windows端给Carol发送邮件,Carol手机端收到邮件后回复Jason。
之后Carol在Web端给Jason发送一封带有附件的邮件。

  @desktop
  场景: Jason使用PC端Mail给Carol发送邮件索要文档
    假如打开Outlook桌面客户端
    当点击新建邮件
    并且在收件人,主题,收件内容中输入对应的信息
    同时点击发送邮件

  @mobile
  场景: Carol手机端回复Jason稍后发送
    假如打开手机端Outlook
    当打开收件箱窗口
    同时打开未读邮件
    同时答复框内回复对应内容并发送

  @web
  场景: Carol使用web端回复Jason
    假如用户Carol登录Outlook web页面
    当打开收件箱并打开最新一次的邮件
    那么回复Jason邮件并上传相关文档
复制代码

对应的可视化界面

Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

5. 完善自动化脚本

在features/step_definitons 目录里分别创建mobileAction.js, webAction.js, windowsAction.js 分别存储3端的自动化脚本。

场景1中,实现对Windows桌面应用的自动化。

  1. 打开windowsAction.js, 点击场景1中每个操作步骤后的灰色按钮,在windwosAction.js中生成Windows应用操作的自动化代码样例。
var { Given, When, Then } = require('cucumber')

Given(/^打开Outlook桌面客户端$/, async function () {
    return 'pending';
});

When(/^点击新建邮件$/, async function () {
    return 'pending';
});

When(/^在收件人,主题,收件内容中输入对应的信息$/, async function () {
    return 'pending';
});

When(/^点击发送邮件$/, async function () {
    return 'pending';
});

复制代码
  1. 打开tmodel文件,利用CukeTest自带的模型管理器选取Windows操作控件,具体选取方式可以参考视频教程 ke.qq.com/course/3473…
Node.js开发多端自动化步骤详解(Windows,Mobile,Web)
  1. Windows对象选取完成后实现windowsAction.js中定义的操作步骤。

引入Windows对象模型

const { model } = require('../support/win_driver');

const { Util } = require('leanpro.common');
复制代码
  1. 模型管理器中根据选取的对象控件复制对应的实现代码。最终代码 features/step_definitons/windowsAction.js
const { Given, When, Then } = require('cucumber');

const { model } = require('../support/win_driver');

const { Util } = require('leanpro.common');

Given(/^打开Outlook桌面客户端$/, async function () {
    await model.getButton("开始").click(0, 0, 1);
    await Util.delay(2000);
    await model.getListItem("Mail").click(0, 0, 1);

});

When(/^点击新建邮件$/, async function () {
    await Util.delay(2000)
    await model.getButton("New mail").click(0, 0, 1);

})

;When(/^在收件人,主题,收件内容中输入对应的信息$/, async function () {
    await model.getEdit("To:").clearAll();
    await model.getEdit("To:").set("carolseaver1@outlook.com");

    await model.getEdit("Subject").clearAll();
    await model.getEdit("Subject").set("培训大纲");

    let content = "hi,Carol:{ENTER}请把本次培训内容发送给我好吗?{ENTER}Jason Seaver"    
    
    await model.getDocument("消息").clearAll();
    await model.getDocument("消息").set(content);});

When(/^点击发送邮件$/, async function () {
    await model.getButton("Send").click(0, 0, 1);
    await Util.delay(1000)

});
复制代码

场景2中,实现对Mobile应用的自动化。

  1. 打开features/step_definitions/moblieAction.js, 点击feature的可视化界面中场景2中每个步骤后的灰色按钮,在mobileAction.js中生成手机端操作代码样例。
var { Given, When, Then } = require('cucumber')

Given(/^打开手机端Outlook$/, async function () {
    return 'pending';
});

When(/^打开收件箱窗口$/, async function () {
    return 'pending';
})

;When(/^打开未读邮件$/, async function () {
    return 'pending';
});

When(/^答复框内回复对应内容并发送$/, async function () {
    return 'pending';
});

复制代码
  1. 引入手机端驱动
const { Util} = require('leanpro.common')

const { app_driver } = require('../support/mobile_driver')
复制代码

使用webdriver.io 相关api 实现自动化操作代码。最终代码 features/step_defintions/mobileAction.js

const { Given, When, Then } = require('cucumber')
const { Util} = require('leanpro.common')
const { app_driver } = require('../support/mobile_driver')

Given(/^打开手机端Outlook$/, async function () {
    // 手机客户端接收邮件需要5-10秒的延迟
    await Util.delay(5000)
    return true
});

When(/^打开收件箱窗口$/, async function () {
    await app_driver.click('~打开导航抽屉');
    await app_driver.click('android=new UiSelector().resourceId("com.microsoft.office.outlook:id/drawer_item_title").index(1).text("收件箱")')});

Then(/^打开未读邮件$/, async function () {

    await app_driver.waitForExist('android=new UiSelector().resourceId("com.microsoft.office.outlook:id/message_snippet_frontview").index(0).className("android.widget.LinearLayout")',20*1000);
    await app_driver.click('android=new UiSelector().resourceId("com.microsoft.office.outlook:id/message_snippet_frontview").index(0).className("android.widget.LinearLayout")')});Then(/^答复框内回复对应内容并发送$/, async function () {
    let loctor = 'new UiSelector().text("答复").index(1)'
    await app_driver.click('android='+loctor)
    await app_driver.clearElement('~邮件正文。')
    let content = `
    Hi,Jason:
        培训内容文档在我公司PC上保存,现在我在外边,稍后我到公司回复您。
    
    Carol Seaver
    `
    await app_driver.setValue('~邮件正文。',content);
    await app_driver.click('~发送');

});
复制代码

场景3中,实现对web应用的自动化。

  1. 打开features/step_definitions/webAction.js, 点击feature的可视化界面中场景3中每个步骤后的灰色按钮,在mobileAction.js中生成web端操作代码样例。
var { Given, When, Then } = require('cucumber')

Given(/^用户Carol登录Outlook web页面$/, async function () {
    return 'pending';
});

When(/^打开收件箱并打开最新一次的邮件$/, async function () {
    return 'pending';
});

Then(/^回复Jason邮件并上传相关文档$/, async function () {
    return 'pending';
});
复制代码
  1. 添加对web_driver 的引用:
const { driver } = require('../support/web_driver');
复制代码
  1. 根据webdriverio相关api 完成对应的操作。最终代码 features/step_definitions/webAction.js
var { Given, When, Then } = require('cucumber')
const { Auto } = require('leanpro.win')
const { Util } = require('leanpro.common')

const path = require('path')

const assert = require('assert');

const { driver } = require('../support/web_driver');

Given(/^用户Carol登录Outlook web页面$/, async function () {
    await driver.url("https://outlook.live.com/mail/inbox#");
    await driver.click('div.headerHero>a:last-child');
    await driver.setValue('#i0116','carolseaver1@outlook.com');
    await driver.click('#idSIButton9');
    await driver.setValue('#i0118','密码');
    await driver.waitForEnabled('#idSIButton9',20*1000)
    await driver.click('#idSIButton9');

});

When(/^打开收件箱并打开最新一次的邮件$/, async function () {
    await driver.waitForEnabled('div > div[role="option"] > div[draggable="true"] > div[tabindex="-1"]',15*1000);

    await driver.click('div > div[role="option"] > div[draggable="true"] > div[tabindex="-1"]' );

});

Then(/^回复Jason邮件并上传相关文档$/,{timeout:180*1000}, async function () {
    // await Util.delay(1000);

    let content = `
    hi,Jason:
        附件为本次培训内容大纲。请查收,谢谢。

    Carol Seaver
    `
    let bool = await driver.waitForEnabled('div[tabindex="-1"] > div > button[type="button"]> div >span',45*1000)
    
    console.log("ele",bool);
    if(bool==true){  
        console.log("get Text ===")
        let text = await driver.getText('div[tabindex="-1"] > div > button[type="button"]> div >span')

        console.log("text == ",text)
        if(text.includes('加载')){
            console.log('click loading')
            await driver.click('div[tabindex="-1"] > div > button[type="button"]> div >span');
            await Util.delay(1000)
            await driver.click('div[tabindex="-1"] > div > button[type="button"]> div >span')
        }else{
            await driver.click('div[tabindex="-1"] > div > button[type="button"]> div >span')
        }
    }
    // await driver.keys()
    // let input_area = await driver.element('div[dir="ltr"]');
    await driver.waitForExist('div[dir="ltr"]',20*1000);
    await driver.click('div[dir="ltr"]')
    // await driver.clearElement('div[dir="ltr"]')
    await driver.setValue('div[dir="ltr"]',content);

    await driver.waitForEnabled('button[name="附加"]',20*1000);
    await driver.click('button[name="附加"]');
    await Util.delay(500)
    await driver.waitForVisible('button[name="浏览此计算机"]',20*1000);
    await driver.click('button[name="浏览此计算机"]');

    await Util.delay(1500);
    let uplaodFilePane =await Auto.getPane({
        "className": "Chrome_WidgetWin_1",
        "name": "邮件 - Carol Seaver - Outlook - Google Chrome"
    }).getWindow({
        "className": "#32770",
        "title": "打开"
    }).getComboBox({
        "automationId": "1148",
        "name": "文件名(N):"
    }).getEdit({
        "automationId": "1148",
        "name": "文件名(N):"
    })

    let filepath = path.join(__dirname, '..', '..', 'files','培训大纲.md')
    await uplaodFilePane.clearAll();
    await uplaodFilePane.set(filepath);
    await Auto.getPane({
        "className": "Chrome_WidgetWin_1",
        "name": "邮件 - Carol Seaver - Outlook - Google Chrome"
    }).getWindow({
        "className": "#32770",
        "title": "打开"
    }).getButton({
        "automationId": "1",
        "name": "打开(O)"
    }).click(0, 0, 1);

    await driver.waitForEnabled('div.ms-Button-flexContainer> i[data-icon-name="Send"]',20*1000);
    await driver.click('div.ms-Button-flexContainer> i[data-icon-name="Send"]')
    await Util.delay(500);

});
复制代码

设置hooks

  1. 打开features/support/hooks.js 文件,设置运行时:
const { BeforeAll, After, Before, AfterAll, setDefaultTimeout } = require('cucumber');

const cuketest = require('cuketest');

const { Util } = require('leanpro.win');

const { app_driver } = require('./mobile_driver');

const { model } = require('./win_driver');

const { driver } = require('./web_driver');

//set default step timeout

setDefaultTimeout(120 * 1000);

BeforeAll(async function () {
    await cuketest.minimize();
    await driver.init();
    await driver.windowHandleMaximize();
    await driver.timeouts(30 * 1000);
    await app_driver.init();
    await app_driver.timeouts(10000);

})

After({ tags: "@desktop" }, async function () {

    let screenshot = await model.getWindow("Window").takeScreenshot();
    this.attach(screenshot, 'image/png');
    await cuketest.delay(1000);
    await model.getWindow("Window").close();

});

After({ tags: "@mobile" }, async function () {

    let screenshot = await app_driver.saveScreenshot();
    this.attach(screenshot, 'image/png');
    await app_driver.end();});

After({ tags: "@web" }, async function () {

    let screenshot = await driver.saveScreenshot();
    this.attach(screenshot, 'image/png');
    //clean up cookies
    await driver.deleteCookie();
    await driver.end();
});

AfterAll(async function () {
    await cuketest.restore();})
复制代码

运行

  1. 启动appium

命令行中输入 appium

$ appium
[Appium] Welcome to Appium v1.9.1
[Appium] Appium REST http interface listener started on 0.0.0.0:4723 
复制代码
  1. 启动selenium-server
$ java -jar -Dwebdriver.chrome.driver=./chromedriver.exe selenium-server-standalone-3.141.0.jar14:53:29.932 INFO [GridLauncherV3.parse] - Selenium server version: 3.141.0, revision: 2ecb7d9a14:53:30.135 INFO [GridLauncherV3.lambda$buildLaunchers$3] - Launching a standalone Selenium Server on port 44442018-11-08 14:53:30.260:INFO::main: Logging initialized @1318ms to org.seleniumhq.jetty9.util.log.StdErrLog14:53:30.728 INFO [WebDriverServlet.<init>] - Initialising WebDriverServlet14:53:31.564 INFO [SeleniumServer.boot] - Selenium Server is up and running on port 4444
复制代码

点击feature文件上每个场景后的运行按钮可以运行单个场景,点击运行项目,可以运行整个项目。运行项目后会生成对应的图文报表。

Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

总结

依托强大的Node.js生态和大量的开源库。使用CukeTest配合开源的 工具 可以完成各类应用的自动化。既快速又免费,有兴趣的可以尝试一下噢。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

RESTful Web Services Cookbook

RESTful Web Services Cookbook

Subbu Allamaraju / Yahoo Press / 2010-3-11 / USD 39.99

While the REST design philosophy has captured the imagination of web and enterprise developers alike, using this approach to develop real web services is no picnic. This cookbook includes more than 10......一起来看看 《RESTful Web Services Cookbook》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具