项目
将单元测试框架mocha,断言chai和puppeteer结合起来做端到端测试:
- 将打开百度首页
- 搜索Puppeteer,确定有搜索内容
- 清空输入,返回百度首页
puppeteer实现自动化
-
安装puppeteer
npm install puppeteer@2.1.1
-
根据用户操作,找标签选择器
F12->点击箭头->更具页面找标签
-
找到标签后,先验证下,页面是否存在这个标签
document.querySelector()
document.querySelectorAll()
- 输入node 1.js 执行
设定了headless: true,所以不会打开浏览器,直接运行出结果
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: true,
devtools: false,
timeout: 20000,
});
const page = await browser.newPage();
await page.goto('http://www.baidu.com/');
const title = await page.title()
console.log(title);
await page.type('input[id="kw"]', 'puppeteer');
await page.click('input[id="su"]');
await page.waitFor(2000);
await page.waitForSelector('div[class="result c-container "]');
const links = await page.evaluate(() => {
return Array.from(document.querySelectorAll('div[class="result c-container "]'));
});
console.log(links.length);
await page.waitFor(2000);
await page.$eval('input[id="kw"]', input => input.value = '');
await page.click('input[id="su"]');
await page.waitFor(2000);
})();
知识点补充
-
等待某个 DOM 节点
在对页面进行操作前,必须等DOM 加载完成才能操作,比如,你要点击图片,但是图片没加载出来。下面这个是等待搜索结果节点节点出现:await page.waitForSelector('div[class="result c-container ');
-
如果加载时间不够,需要用时间间隔
await page.waitFor(500);
-
获取节点集合
下面是获取搜索结果列表,两种写法都可以const links = await page.evaluate(() => { return Array.from(document.querySelectorAll('div[class="result c-container "]')); });; const links = await page.$$eval('div[class="result c-container ', els => Array.from(els).map(el=> el));
-
使用了eval,清空input框
await page.$eval('input[id="kw"]', input => input.value = '');
Mocha+Chai实现测试
将上面的代码,加入 Mocha+Chai,进行测试
- 安装Mocha+Chai,看这
- 代码,注意运行的时候,使用的是mocha 2.js -t 30000
const puppeteer = require('puppeteer'); const { expect } = require('chai'); describe('Baidu search', () => { let browser; let page before(async () => { browser = await puppeteer.launch(); page = await browser.newPage(); await page.goto('http://www.baidu.com/'); }); after(async () => { await browser.close(); }); it('page title', async () => { expect(await page.title()).to.eql('百度一下,你就知道'); }); it('get the list number of results', async () => { await page.type('input[id="kw"]', 'puppeteer'); await page.click('input[id="su"]'); await page.waitFor(2000); await page.waitForSelector('div[class="result c-container "]'); const links = await page.evaluate(() => { return Array.from(document.querySelectorAll('div[class="result c-container "]')); }); expect(links.length).to.be.greaterThan(0); }); it('back to BaiDu page ', async () => { await page.waitFor(2000); await page.$eval('input[id="kw"]', input => input.value = ''); await page.click('input[id="su"]'); await page.waitFor(2000); expect(await page.title()).to.eql('百度一下,你就知道'); }); });
这份代码实现了,验证首页是否打开,搜索是否有信息,搜索清空后,点击提交,是否返回首页。
browser和page定义在外面,这样,其他函数可以使用到。
优化代码
为了增加代码的可维护性,可理解性。我们一些操作封装起来,使用的时候直接调用它。
执行的时候使用mocha 3.test.js -t 30000
-
3.js
这个里面写了获取标题,搜索,获取搜索条数,返回首页几个方法class BaiDu { constructor(page) { this.page = page; } async getTitle() { return this.page.title(); } async search(word) { await this.page.type('input[id="kw"]', word); await this.page.click('input[id="su"]'); } async getNumber(page) { await this.page.waitForSelector('div[class="result c-container "]'); const links = await this.page.evaluate(() => { return Array.from(document.querySelectorAll('div[class="result c-container "]')); }); return links.length; } async back() { await this.page.$eval('input[id="kw"]', input => input.value = ''); await this.page.click('input[id="su"]'); await this.page.waitFor(2000); } } module.exports = BaiDu;
-
3.test.js
引入BaiDu ,直接调用BaiDu的方法,获取结果,进行验证const puppeteer = require('puppeteer'); const { expect } = require('chai'); const BaiDu = require('./3.js'); describe('Baidu search', () => { let browser; let page; before(async () => { browser = await puppeteer.launch(); page = await browser.newPage(); await page.goto('http://www.baidu.com/'); }); after(async () => { await browser.close(); }); it('page title', async () => { const baiDu = new BaiDu(page); expect(await baiDu.getTitle()).to.eql('百度一下,你就知道'); }); it('get the list number of results', async () => { const baiDu = new BaiDu(page); await baiDu.search('puppeteer'); expect(await baiDu.getNumber()).to.be.greaterThan(0); }); it('back to BaiDu page', async () => { const baiDu = new BaiDu(page); await baiDu.back(); expect(await baiDu.getTitle()).to.eql('百度一下,你就知道'); }); });
-
结果