单元测试--(四)周边生态库介绍

270 阅读1分钟

前言

  • cheerio介绍
  • jsdom介绍
  • nock介绍
  • puppeteer 介绍

一. cheerio介绍

Cheerio地址 Cheerio 是一个在 Node.js 中解析 HTML 和 XML 的工具

它快速、灵活且易于使用。由于它实现了 JQuery 的一个子集,如果你已经熟悉 JQuery,那么很容易开始使用 Cheerio

Cheerio 和 Web 浏览器之间的主要区别在于,cheerio 不生成视觉渲染、加载 CSS、加载外部资源或执行 JavaScript。 它只是解析标记并提供用于操作生成的数据结构的 API。这就解释了为什么它也非常快

1.1 简单使用

var cheerio = require('cheerio');
 
$ = cheerio.load("<h2 class='title'>Hello word</h2>");
$('.title').html("james.yang");
$('.title').addClass("myTitle");
 

// <html><head></head><body><h2 class="title myTitle">james.yang</h2></body></html>
console.log($.html());

1.2 作为爬虫

const axios = require("axios");
const cheerio = require("cheerio");
const fs = require("fs");
const getSiteData = async (url) => {
    const { data } = await axios.get(url);
    const ret = cheerio.load(data);
    return ret;
};
async function grabClassifysData(){
    const url = `https://juejin.cn/`;
    const $ = await getSiteData(url);

    const listItems = $(".view-nav .nav-item");
    
    
    const classifys = [];
    listItems.each((idx, el) => {
      let content = $(el).find(".category-popover-box").text();

      content = content.replace(/\s+/g,'');
      classifys.push(content);
    });

    console.log(classifys);

    fs.writeFileSync("classifys.json", JSON.stringify(classifys, null, 2));
};
grabClassifysData()


async function grabContentData(){
    const url = `https://juejin.cn/`;
    const $ = await getSiteData(url);

    const listItems = $(".entry-list-wrap");
    console.log(listItems.html());
};

grabContentData();

注意: 作为爬虫使用的时候只能抓取静态页面的数据,对于spa应用的内容没法抓取,但是可以通过puppeteer很好的解决网站动态数据的问题

二. jsdom介绍

jsdom地址 JSDOM 是一个基于 JavaScript 的无头浏览器,可用于创建真实的测试环境

const jsdom = require("jsdom");
const { JSDOM } = jsdom;
 
const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);
// console.log(dom.window)

// node环境下不能直接通过document来获取DOM节点
console.log(dom.window.document.querySelector("p").textContent); // "Hello world"
 
const $ = require('jquery')(dom.window);
 
console.log($('p').text());// "Hello world"

三. nock介绍

Nock地址 Nock 是一个 HTTP 模拟和预期测试库,用于 Node.js 平台。用来测试 HTTP 请求

const nock = require('nock')
const axios = require('axios');

nock('http://localhost:3000')
            .get('/user?name=james')
            .reply(200, {
                "name": "james2",
                "age": 30,
            });

let url = `http://localhost:3000/user?name=james`;
axios.get(url).then(res => {
    console.log('==res===', res.data);
    return res.data;
}).catch(err => {
    console.error(err);
});

四. puppeteer介绍

puppeteer地址

Puppeteer 是一个 Chrome官方出品的 headless Chrome node 库(当然你也可以配置成有UI的,默认是没有的)。
Puppeteer 是一个node库,他提供了一组用来操纵ChromeAPI。
既然是浏览器,那么我们手工可以在浏览器上做的事情 Puppeteer 都能胜任, 
另外,Puppeteer 翻译成中文是”木偶”意思,所以听名字就知道,操纵起来很方便,你可以很方便的操纵她去实现:

    1. 生成网页截图 或者 PDF

    2. 作为爬虫来爬取大量异步渲染网页的内容
        抓取 SPA(单页应用)并生成预渲染内容

    3. 模拟键盘输入、表单自动提交、登录网页等,实现 UI 自动化测试
        创建一个实时更新的自动化测试环境。 使用最新的 JavaScript 和浏览器功能直接在最新版本的Chrome中执行测试
    
    4. 捕获网站的时间线(timeline trace),以便追踪你的网站,帮助分析网站性能问题
    
    5. 测试浏览器扩展

抓取掘金网站首页最新10条数据

const path = require('path');
const puppeteer = require('puppeteer');
const fs = require('fs');
const start = async () => {
	const browser = await puppeteer.launch({
		// 是否以”无头”的模式运行 chrome, 也就是不显示 UI, 默认为 true
		headless: false,
		// 使 Puppeteer 操作减速,单位是毫秒。如果你想看看 Puppeteer 的整个工作过程,这个参数将非常有用。
		slowMo: 250, 
		// 等待 Chrome 实例启动的最长时间。默认为30000(30秒)。如果传入 0 的话则不限制时间
		timeout: 0
	});


	//  创建新标签页并打开
	let page = await browser.newPage();

	// Whether or not to enable JavaScript on the page
	await page.setJavaScriptEnabled(true);

	// 打开新页面
	await page.goto("https://juejin.cn/");


	// Page.$(selector) 获取单个元素,底层是调用的是 document.querySelector() 
	// page.waitForSelector(selector[, options]) 等待某个选择器的元素加载之后,这个元素可以是异步加载的
	// 等待元素加载之后,否则获取不到异步加载的元素
	await page.waitForSelector('.entry-list-wrap .item'); 

	// Page.$$(selector) 获取一组元素,底层调用的是 document.querySelectorAll().
	// Page.$$eval(selector, Function[, …args]), 获取单个元素的属性,这里的选择器 selector 跟上面 Page.$(selector) 是一样的
	const links = await page.$$eval('.entry-list-wrap .item .title', links => {
		return links.slice(0, 10).map(a => {
			return {
				href: a.href.trim(),
				title: a.title
			}
		});
	});
	// 浏览器关闭
	await page.close();
	await browser.close();

	console.log("===links===", links);
	
	write(links);
};


// 写入文件
const write = (links) => {
	let filename = path.resolve(__dirname, `./out/contents.txt`);
	fs.writeFileSync(filename, JSON.stringify(links, null, 2), 'utf-8');
};


start();

系列文章

单元测试--(一)前端测试的简单介绍

单元测试--(二)Jest测试工具介绍

单元测试--(三)React + Enzyme

单元测试--(四)周边生态库介绍