我被分配了一个繁琐的任务,就是要给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——自动化脚本设计的更多相关文章

  1. Robot Framework测试框架用例脚本设计方法

    Robot Framework介绍 Robot Framework是一个通用的关键字驱动自动化测试框架.测试用例以HTML,纯文本或TSV(制表符分隔的一系列值)文件存储.通过测试库中实现的关键字驱动 ...

  2. 《手把手教你》系列基础篇(五)-java+ selenium自动化测试- 创建首个自动化脚本(详细教程)

    1.简介 前面几篇宏哥介绍了两种(java和maven)环境搭建和三大浏览器的启动方法,这篇文章宏哥将要介绍第一个自动化测试脚本.前边环境都搭建成功了,浏览器也驱动成功了,那么我们不着急学习其他内容, ...

  3. Automation Framework Design 自动化框架设计思想

    从2007年到2017年,十年内自动化测试工具层出不穷,各种工具在运用一段时间之后,各个公司都会有测试架构师对于目前的自动化测试工具进行框架定制设计. 从惠普2007年GDCC推出的的WebDrivi ...

  4. LoadRunner脚本设计、场景设计和结果分析

    本次笔记主要记录LoadRunner脚本设计.场景设计和结果分析   1. 脚本设计       录制模式            手工模式:插入步骤.手动编写       1.1  脚本增强:     ...

  5. Eclipse+Selenium自动化测试脚本设计V1.0

    Eclipse+Selenium自动化测试脚本设计V1.0 http://www.docin.com/p-803032251.html

  6. VS2010+Selenium测试脚本设计

    VS2010+Selenium测试脚本设计 http://www.docin.com/p-755903506.html

  7. CYQ.Data V5 分布式自动化缓存设计介绍(二)

    前言: 最近一段时间,开始了<IT连>创业,所以精力和写的文章多数是在分享创业的过程. 而关于本人三大框架CYQ.Data.Aries.Taurus.MVC的相关文章,基本都很少写了. 但 ...

  8. 自动化脚本中click()或sendKeys()没有反应

    前提: 排除xpath引用错误或元素的xpath每次都不同的情形. 问题描述 自动化脚本中click()方法和sendKeys()方法报错, 返回异常InvocationTargetException ...

  9. appium-desktop录制脚本二次开发,生成我司自动化脚本

    目的 通过对appium-desktop脚本录制功能进行二次开发,使录制的java脚本符合我司自动化框架要求. 实现步骤 1.增加元素名称的输入框 由于ATK(我司自动化测试框架)脚本中元素是以“ap ...

随机推荐

  1. [USACO 4.2] 完美的牛栏

    ★★☆   输入文件:stall4.in   输出文件:stall4.out   简单对比 时间限制:1 s   内存限制:128 MB USACO/stall4(译by Felicia Crazy) ...

  2. java虚拟机(三)-- 虚拟机类加载机制

    1.类加载的时机:类从被加载到虚拟机内存中开始,到卸载出内存为止.包含以下几个阶段: 1.加载 2.验证 3.准备 4.解析 5.初始化 6.使用 7.卸载 2.类加载器的种类 1.启动类加载器:这个 ...

  3. ORACLE分区表删除分区数据

    --全删除 ALTER TABLE tableName DROP PARTITION partionName UPDATE GLOBAL INDEXES; --清数据 ALTER TABLE tabl ...

  4. Keywords Search AC自动机

    In the modern time, Search engine came into the life of everybody like Google, Baidu, etc. Wiskey al ...

  5. sqlacodegen

    这个工具可以把数据库的表转成sqlalchemy用的class. 但是 table必须要有主键.否则转化成的是Table类型而不是class root@rijx:/tmp# sqlacodegen - ...

  6. SQL Error (2013): Lost connection to MySQL server at 'waiting for initial communication packet', system error: 0 解决方案

    远程服务器的操作系统:Ubuntu 本地:navicat +win10 连接名:随意填写 主机名:localhost 端口:3306 用户名:连接电脑的数据库的用户名 密码:连接电脑的数据库的密码 主 ...

  7. 条款39: 避免 "向下转换" 继承层次

    基类指针不能调用派生类的独有的成员,即使基类指针指向派生类对象,因为编译器是根据指针的静态类型来确定调用对象在内存中占据的空间的.此时可以使用static_cast来转换,但不要这么做,因为向下转换难 ...

  8. 3.5 在批处理模式下使用mysql

    在前面的章节中,你交互式地使用mysql输入查询而且查看结果.你也能够以批模式执行mysql.为了做到这些.把你想要执行的命令放在一个文件里,然后告诉mysql从文件读取它的输入: shell> ...

  9. JavaWeb开发环境搭建

    Tomcat 的主要配置 Tomcat:tomcat是实现了一个JavaEE标准的最小的Webserver,是Apche组织开发的,免费的server,能够在网络中直接下载. 最新的版本号应该是8的版 ...

  10. phpstorm安装和调试

    首先: phpstorm是用JAVA开发的,所以在安装之前须要先安装jdk sudo apt-get install default-jdk 从官网上下载phpstorm 的linux版本号 http ...