Puppeteer——自动化脚本设计
我被分配了一个繁琐的任务,就是要给100个相同的站点做同样的配置。曾经就有做过相同的事,那时还不会写脚本,全靠手动配置。机械的配置了两天的时间,身体感觉被掏空。所以这次我决定还是写一个脚本自动的进行配置。
一、了解Puppeteer
中文版资料:https://juejin.im/entry/59ad6c4f5188250f4850dccc
官方文档(英文):https://github.com/GoogleChrome/puppeteer
Puppeteer的API(英文):https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#
二、环境
只安装了node环境
三、开发阶段
3.1 初始化项目
引用了https://juejin.im/entry/59ad6c4f5188250f4850dccc
项目都是以创建文件夹开始。
$ mkdir thal
$ cd thal
初始化 NPM,填入一些必要的信息。
$ npm init
安装 Puppeteer。由于 Puppeteer 并不是稳定的版本而且每天都在更新,所以如果你想要最新的功能可以直接通过 GitHub 的仓库安装。
$ npm i --save puppeteer
Puppeteer 包含了自己的 chrome / chromium 用以确保可以无界面地工作。因此每当你安装/更新 puppeteer 的时候,他都会下载指定的 chrome 版本。
3.2 编码
3.2.1 工程的目录结构
node_modeles中的内容是从git上拉下来的,src文件夹写得是我自己的代码,我执行的是addConfig里面的文件,common中是一些基础性配置,contentHub配置内容较多,所以我另建了一个contentHub文件夹。

3.2.2 common.js文件写的是常用的功能函数,这个是可以通用的。之前我不是说实现不了全选的功能吗,其实可以调用common中的setOption函数实现全选的功能
const config = require('./config');
//根据选择器sel选择id为val的子项
async function setOption(page, sel, val) {
await page.evaluate((sel, val) => {
document.querySelector(`${sel} > option[value="${val}"]`).selected = true;
element = document.querySelector(sel);
var event = new Event('change', { bubbles: true });
event.simulated = true;
element.dispatchEvent(event);
}, sel, val);
}
//在id为sel的输入框中输入val
async function setTextVal(page, sel, val) {
await page.evaluate((sel, val) => {
document.querySelector(sel).value = val;
element = document.querySelector(sel);
var event = new Event('change', { bubbles: true });
event.simulated = true;
element.dispatchEvent(event);
}, sel, val);
}
//判断选择器是否存在
async function isExist(page, selector) {
var is = await page.evaluate((sel) => {
const element = document.querySelector(sel);
if (!element) {
return false;
} else {
return true;
}
}, selector);
return is;
}
//导入单个配置
async function importSingleConfiguration(page, configType, configContent) {
const confirmBtn = 'input[value="Confirm"]';
const configTypeSel = '#edit-config-type';
await setOption(page, configTypeSel, configType);
await page.click('#edit-import');
await setTextVal(page, '#edit-import', configContent);
await page.click('#edit-submit');
await page.waitForNavigation();
const is = await isExist(page, confirmBtn);
if (is) {
await page.click(confirmBtn);
await page.waitForNavigation();
await page.waitFor(3 * config.stepWait);
}
}
//设置checkbox中子项的值
async function setCheckBoxVal(page, sel, val) {
await page.evaluate((sel, val) => {
document.querySelector(sel).checked = val;
element = document.querySelector(sel);
var event = new Event('change', { bubbles: true });
event.simulated = true;
element.dispatchEvent(event);
}, sel, val);
}
module.exports = {
setOption: setOption,
setTextVal: setTextVal,
importSingleConfiguration: importSingleConfiguration,
isExist: isExist,
selectAll: selectAll,
setCheckBoxVal: setCheckBoxVal,
}
3.2.3 config.js文件中申明了许多基础性配置
我要跳转的网站url,登录的用户名和密码,站内页面跳转的路径等信息都配置在这个文件里面
const baseUrlArray = [
{
url: '',
langcode: '',
},
];
const baseUrl = baseUrlArray[0].url; const getUrl = (index) => {
const baseUrl = baseUrlArray[index].url;
return {
hubConnection: `${baseUrl}/example`,
};
} const getLangCode = (index) => {
return baseUrlArray[index].langcode;
} module.exports = {
secondWait: 1000,
stepWait: 5000,
username: '',
password: '',
credentials: {
username: '',
password: '',
},
baseUrl: baseUrl,
baseUrlArray: baseUrlArray,
urls: getUrl(0),
getUrl: getUrl,
getLangCode: getLangCode,
}
3.2.4 login.js
const config = require('./config');
async function login(page, url = null) {
//fill authenticate user name and password
await page.authenticate(config.credentials);
// goto login page
await page.goto(url ? url : config.urls.login);
const agreeButton = await page.$('#block-popup .btn');
await agreeButton.click();
//fill admin user name and password
await page.focus('#edit-name');
await page.keyboard.type(config.username);
await page.focus('#edit-pass');
await page.keyboard.type(config.password);
const inputElement = await page.$('#edit-submit');
await inputElement.click();
await page.waitForNavigation();
}
module.exports = login;
3.2.5 好了,登录成功了
四、收获
1.需要被其它页面引用的函数,常量必须要在module.exports={}中申明
2.headles: false是设置自动化操作是可视化的
3.在输入框中输入值并覆盖原有的值:

4.调用其他页面函数的声明:const common = require('./common');
五、疑惑
1.关于全选的功能,puppeteer并不支持全选,虽然官方文档上面说了linux和windows支持全选,但是我的linux系统没有任何反应,估计并不支持。补充一下,我这里说的是实现不了ctrl+A的全选功能。
Puppeteer——自动化脚本设计的更多相关文章
- Robot Framework测试框架用例脚本设计方法
Robot Framework介绍 Robot Framework是一个通用的关键字驱动自动化测试框架.测试用例以HTML,纯文本或TSV(制表符分隔的一系列值)文件存储.通过测试库中实现的关键字驱动 ...
- 《手把手教你》系列基础篇(五)-java+ selenium自动化测试- 创建首个自动化脚本(详细教程)
1.简介 前面几篇宏哥介绍了两种(java和maven)环境搭建和三大浏览器的启动方法,这篇文章宏哥将要介绍第一个自动化测试脚本.前边环境都搭建成功了,浏览器也驱动成功了,那么我们不着急学习其他内容, ...
- Automation Framework Design 自动化框架设计思想
从2007年到2017年,十年内自动化测试工具层出不穷,各种工具在运用一段时间之后,各个公司都会有测试架构师对于目前的自动化测试工具进行框架定制设计. 从惠普2007年GDCC推出的的WebDrivi ...
- LoadRunner脚本设计、场景设计和结果分析
本次笔记主要记录LoadRunner脚本设计.场景设计和结果分析 1. 脚本设计 录制模式 手工模式:插入步骤.手动编写 1.1 脚本增强: ...
- Eclipse+Selenium自动化测试脚本设计V1.0
Eclipse+Selenium自动化测试脚本设计V1.0 http://www.docin.com/p-803032251.html
- VS2010+Selenium测试脚本设计
VS2010+Selenium测试脚本设计 http://www.docin.com/p-755903506.html
- CYQ.Data V5 分布式自动化缓存设计介绍(二)
前言: 最近一段时间,开始了<IT连>创业,所以精力和写的文章多数是在分享创业的过程. 而关于本人三大框架CYQ.Data.Aries.Taurus.MVC的相关文章,基本都很少写了. 但 ...
- 自动化脚本中click()或sendKeys()没有反应
前提: 排除xpath引用错误或元素的xpath每次都不同的情形. 问题描述 自动化脚本中click()方法和sendKeys()方法报错, 返回异常InvocationTargetException ...
- appium-desktop录制脚本二次开发,生成我司自动化脚本
目的 通过对appium-desktop脚本录制功能进行二次开发,使录制的java脚本符合我司自动化框架要求. 实现步骤 1.增加元素名称的输入框 由于ATK(我司自动化测试框架)脚本中元素是以“ap ...
随机推荐
- [luoguP2434] [SDOI2005]区间(贪心)
传送门 简单贪心 ——代码 #include <cstdio> #include <iostream> #include <algorithm> int n, l, ...
- 史上超全面的Neo4j使用指南
Create by yster@foxmail.com 2018-7-10 我的博客:https://blog.csdn.net/yueshutong123 W3Cschool文档:https://w ...
- java 远程调用
1.webservice (soap+http) -aixs -axis2 -xfire—>cxf 2.webservice问题 -基于xml,xml效率,(数据传输效率,xml序列化效率) - ...
- Linux下使用tcpdump进行抓包(转)
技巧: 1.可以通过tcpdump抓取某个网卡的包,然后输出日志文件,通过Wireshark进行分析. 2.可以设置Wifi热点,然后通过手机连接这个热点,然后进行tcpdump的分析.而且在Ubun ...
- SiteMesh2-sitemesh.xml的ConfigDecoratorMapper映射器的用法
继上一次的示例工程http://www.cnblogs.com/EasonJim/p/7083165.html,使用的就是ConfigDecoratorMapper映射器,通过指定目录下的页面,都同一 ...
- Python学习十四:filter()
Python 中内置了filter()函数用于过滤序列. 使用方法: filter()接收一个函数和一个序列. filter()把传入的函数依次作用于每一个元素,然后依据返回值是True还是False ...
- word设置
word文档编号
- 从2月14号開始,上传AppStore会碰到:Failed to locate or generate matching signing assets
从2月14号開始,上传AppStore时可能会碰到这个问题: Failed to locate or generate matching signing assets Xcode attempted ...
- TextWatcher基本用法
editText.addTextChangedListener(new TextWatcher() { /** * 内容改变前调用 * 原有的文本s中,从start开始的count个字符将会被一个新的 ...
- ALSA声卡驱动中的DAPM详解之五:建立widget之间的连接关系
前面我们主要着重于codec.platform.machine驱动程序中如何使用和建立dapm所需要的widget,route,这些是音频驱动开发人员必须要了解的内容,经过前几章的介绍,我们应该知道如 ...