从零开始的Puppeteer(四)

834 阅读4分钟

通过前三章学习,这一章来和大家一起实现一个自动化测试的小例子

思路是想通过网页端,点击一个按钮来实现自动化测试,希望能有每一步测试的进度和状态如图所示:

image.png 大概思路就是这样,下面开始实现这个例子。

前期准备

  • 需要上一章这一章中我们一起搭建的express服务,在其基础上进行扩展。
  • 需要上一章这一章中搭建的ui界面,在其基础上进行扩展。

后端接口

在上一章中已经实现了一个 /pins 接口这里我们想要点击按钮进行测试,需要实现两个两个接口,一个 /home 接口,用来登录判断首页状态, 一个 /checklist 接口用来判断沸点的发布状态。 生成 home.js ,checklist.js 放到 puppeteer目录下

const express = require('express')
const start = require('./puppeteer/pins')
const checklist = require('./puppeteer/checklist')
const home = require('./puppeteer/home')
const app = express()
app.get('/home', async function (req, res) {
  const homeStatus = await home().catch(err => {
    res.send(err)
  })
  res.send(homeStatus)
})
app.get('/pins', async function (req, res) {
  const pins = await start()
  res.send(pins)
})
app.get('/checklist', async function (req, res) {
  const checklistStatus = await checklist().catch(err => {
    res.send(err)
  })
  res.send(checklistStatus)
})
app.listen(3000)

这样两个接口就准备好了

puppeteer脚本实现

home

首先实现home脚本,笔记简单做一个登录即可

const puppeteer = require("puppeteer");
const cookieObjects = require('./cookie');
async function home() {
  const browser = await puppeteer.launch({
    headless: false 
  });
  const page = await browser.newPage();
  await page.setViewport({
    width: 1280,
    height: 800
  }); // 设置浏览器视窗大小
  cookieObjects.forEach((cookie) => {
    page.setCookie(cookie);
  });
  await page.goto("https://juejin.cn", {
    waitUntil: 'networkidle0' 
  });
  return true
}

module.exports = home
  • cookie是上一章中和大家一起导出的cookie.js
  • headless: false可以不加,现在打开是为了好看而已
  • waitUntil: 'networkidle0' 等待接口都加载完 这样页面数据就ok了

这里简单的返回了一个true用来做状态

checkList

checkList我们也让他返回一个true来做成功状态判断,checkList除了登录之外还有其他操作:

  1. 等待页面跳转完成
  2. 等待某个元素出现
  3. 输入沸点内容
  4. 点击按钮进行提交
  5. 监听接口,根据返回值来判断状态
const puppeteer = require("puppeteer");
const cookieObjects = require('./cookie');
async function checkList() {
  const browser = await puppeteer.launch({
    headless: false
  });
  const page = await browser.newPage();
  await page.setViewport({
    width: 1280,
    height: 800
  }); // 设置浏览器视窗大小
  cookieObjects.forEach((cookie) => {
    page.setCookie(cookie);
  });
  
  // 5. 监听接口,根据返回值来判断状态
  function getResponseBody(resolve, reject){
    page.on('response',async (response) => {
      if (['xhr', 'fetch'].includes(response.request().resourceType())) {
        if (response.url().indexOf('/short_msg/publish') >= 0) {
          if (response.ok()) {
            let body = await response.json()
            console.log(body)
            if (body.err_msg !== 'success') {
              reject(body)
            } else {
              resolve(true)
            }
          }
          reject(false)
        }
      }
    })
  }
  // 5. 监听接口,根据返回值来判断状态
  waitForResponse = new Promise(getResponseBody)
  // 1. 等待页面跳转完成
  await page.goto("https://juejin.cn/pins", {
    waitUntil: 'networkidle0' // 接口都加载完 这样页面数据就ok了
});
  // await page.content()
  // 进入新鲜事
  const newBtn = '#juejin > div.view-container.pin_container > main > main > div.dock.shadow > nav > div:nth-child(4) > div > a:nth-child(1)'
  // 2. 等待某个元素出现
  await page.waitForSelector(newBtn)
  
  
  const [response] = await Promise.all([
    page.waitForNavigation(),
    page.click(newBtn),
  ]);
  const inputSel = '.auth-card > div'
  // 3. 输入沸点内容
  await page.type(inputSel, 'hi')

  const submitBtn = '.submit > button'
  // 4. 点击按钮进行提交
  await page.click(submitBtn)
  // 5. 监听接口,根据返回值来判断状态
  return waitForResponse
}

module.exports = checkList
  1. 注意第五步,分为了三步来做的,首先用page.on('response', fn)进行请求的监听,然后把他包装成一个Promise, 最后将他返回给接口。
  2. 使用await Promise.all([ page.waitForNavigation(), page.click(newBtn), ]);来实现等待点击a标签的跳转
  3. 这里还是将true作为返回值唯一正确判断,小伙伴们可以自己修改返回值,或者将返回值原样返回用来展示信息。

ui界面实现

上一章已经实现了一个沸点的展示,在此基础上我们增加一些代码:

<div class="pins-steps">
      <a-button type="primary" @click="clickCheckListHandle">开始测试</a-button>
      <div class="step-list-box">
        <a-steps :current="currentStep" size="small" :status="stepsStatus">
          <a-step title="开始"></a-step>
          <a-step title="首页测试">
            <template #icon v-if="currentStep === 1 && stepsStatus !== 'error'">
              <loading-outlined />
            </template>
          </a-step>
          <a-step title="发布沸点测试" >
            <template #icon v-if="currentStep === 2 && stepsStatus !== 'error'">
              <loading-outlined />
            </template>
          </a-step>
        </a-steps>
      </div>
    </div>
    ...
    // 主要代码
    async getHomeStatus() {
        const homeStatus = await axios.get('/api/home')
        return homeStatus.data === true
      },
      async getPinsStatus() {
        const pinsStatus = await axios.get('/api/checklist')
        return pinsStatus.data === true
      },
      async clickCheckListHandle() {
        if (stepsStatus.value === 'error') return
        currentStep.value = currentStep.value + 1
        const homeStatus = await this.getHomeStatus()
        if(homeStatus) {
          currentStep.value = currentStep.value + 1
          const pinsStatus = await this.getPinsStatus()
          if (pinsStatus) {
            currentStep.value = currentStep.value + 1
            currentStep.value = currentStep.value + 1
          } else {
            stepsStatus.value = 'error'
          }
        } else {
          stepsStatus.value = 'error'
        }
      },
    
  • 引入ant的步骤条,测试状态中使用loading状态,成功使用对号失败红色提示;
  • 点击按钮开始测试进行接口调用,并根据返回值来改变步骤条的状态

成果展示

测试不通过展示:

image.png

测试通过展示:

image.png

这样我们就实现了通过web端点击按钮的自动化测试小例子。