如何使用Puppeteer和Jest在Node.js中编写端到端测试

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Free and Open Source Fund 来接受捐赠。

介绍

端到端测试(简称e2e)是在类生产场景中从用户的角度对应用程序的整个生命周期进行测试的过程。 此过程通常涉及部署脚本以像普通用户一样自动浏览应用程序的界面,并在此过程中测试特定功能和行为。 在 Node.js 开发中,您可以结合使用 Chrome API Puppeteer 和 JavaScript 测试框架 Jest 来自动化 e2e 测试,允许您确保应用程序的用户界面 (UI) 在您修复错误和添加新功能时仍然正常工作。

在本教程中,您将编写一个 e2e 测试,以验证示例网页的帐户创建和登录功能是否按预期工作。 首先,您将编写一个基本的 Puppeteer 脚本来打开浏览器并导航到测试网页,然后您将配置使浏览器和页面实例全局可用的预设。 接下来,您将从 GitHub 上的 DigitalOcean 社区存储库中克隆 mock-auth 示例应用程序 并在本地提供应用程序。 这个示例应用程序将为用户提供一个界面来创建一个帐户并登录到该帐户。 最后,您将调整您的 Puppeteer 脚本以填写帐户创建和登录表单并单击提交按钮,然后您将在 Jest 中编写单元测试以验证脚本是否按预期工作。

警告: 网络抓取的道德和合法性是复杂的,并且在不断发展。 它们还会根据您的位置、数据的位置和相关网站而有所不同。 本教程抓取了一个本地服务的示例应用程序,该示例应用程序专门用于测试抓取应用程序。 抓取任何其他域超出了本教程的范围。


先决条件

在开始本指南之前,您需要以下内容:

  • Node.js 版本 14.16.0 或更高版本安装在您的计算机上。 要在 macOS 或 Ubuntu 20.04 上安装它,请按照 如何在 macOS 上安装 Node.js 和创建本地开发环境中的步骤或 选项 2 — 使用 NodeSource 使用 Apt 安装 Node.js 如何在 Ubuntu 20.04 上安装 Node.js 的 PPA 部分。
  • 安装了 Chrome 网络浏览器 的本地桌面环境。 由于本教程中使用的 Puppeteer 脚本不是在无头模式下运行的,因此需要桌面环境来运行测试。
  • 熟悉 Puppeteer 及其提供的 API。 您可以关注我们的 如何使用 Node.js 和 Puppeteer 来抓取网站以了解如何使用 Puppeteer。
  • 一些在 Jest 中编写单元测试的经验。 查看 Jest 的官方文档 以了解有关此主题的更多信息。

第 1 步 — 启动您的测试程序

在此步骤中,您将为 Node.js 测试程序创建一个目录并安装所需的依赖项。 本教程使用三个依赖项,您将使用 Node.js 的默认包管理器 npm 安装它们。 这些依赖项将使您能够一起使用 Jest 和 Puppeteer。

首先,为此项目创建一个文件夹并导航到该文件夹。 本教程将使用 end-to-end-test-tutorial 作为项目名称:

mkdir end-to-end-test-tutorial
cd end-to-end-test-tutorial

您将在此目录中运行所有后续命令。

您现在可以在您的目录中初始化 npm,以便它可以跟踪您的依赖项。 使用以下命令为您的项目初始化 npm:

npm init

此命令将显示一系列提示。 每次提示都可以按ENTER,也可以添加个性化描述。 确保按 ENTER 并在提示输入 entry point:test command: 时保留默认值。 或者,您可以将 -y 标志传递给 npm,它将为您提交所有默认值。

填写这些提示将为您创建一个 package.json 文件,该文件将管理您的项目的依赖项和一些额外的元数据。

然后将提示您保存文件。 键入 yes 并按 ENTER。 npm 会将此输出保存为您的 package.json 文件。

现在你可以安装你的依赖了。 本教程所需的三个依赖项是:

  • jest:单元测试库。
  • puppeteer:基于 Chrome Devtools 协议的高级抽象 API。
  • jest-puppeteer:帮助您正确设置 Jest 与 Puppeteer 的软件包。

使用 npm 安装这些依赖项:

npm install --save jest puppeteer jest-puppeteer

当您运行此命令时,它将安装 Jest、Puppeteer、Chromium 浏览器的兼容版本和 jest-puppeteer 库。

注意: 在 Linux 机器上,Puppeteer 可能需要一些额外的依赖项。 如果您使用的是 Ubuntu 20.04,请检查 Puppeteer 的故障排除文档 的 Chrome headless does not launch on UNIX 部分中的 Debian Dependencies 下拉菜单。 您还可以使用以下命令来帮助查找任何缺少的依赖项:

ldd ~/end-to-end-test-tutorial/node_modules/puppeteer/.local-chromium/linux-970485/chrome-linux/chrome | grep not

在此命令中,您在项目的 Chrome 安装中使用 ldd 来查找程序的依赖项,然后将结果传送到 grep 以查找包含单词 not 的所有依赖项. 这将向您显示未安装的依赖项。 请注意,您到 chrome 模块的个人路径可能会有所不同。


安装所需的依赖项后,您的 package.json 文件会将它们作为其 dependencies 的一部分包含在内。 您可以通过在首选文本编辑器中打开它来验证这一点:

nano package.json

这将向您显示类似于以下内容的文件:

端到端测试教程/package.json

{
  "name": "end-to-end-test-tutorial",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jest": "^27.5.1",
    "jest-puppeteer": "^6.1.0",
    "puppeteer": "^13.5.0"
  }
}

这确认已安装依赖项。

启动测试程序并设置依赖项后,接下来将对其进行配置并添加初始 Puppeteer 脚本,以确保一切都已正确设置。

第 2 步 — 配置您的测试程序

测试网站的手动方法是使用浏览器浏览网页、单击按钮、滚动页面,并确认每次交互都呈现正确的页面和文本。 这些是编写自动化端到端测试所涉及的相同过程:浏览器将以编程方式打开网页并导航界面,测试库将断言浏览器从网页获得了预期的行为或输出。 在这一步中,您将配置 Jest 和 Puppeteer 以在您的 Node.js 应用程序中执行这些过程,然后使用访问 www.google.com 的 Puppeteer 脚本测试配置。

首先,创建几个文件夹来为您的测试应用程序提供结构:

mkdir actions
mkdir logs
mkdir specs
mkdir utils

actions 文件夹将保存 Puppeteer 脚本,这些脚本将抓取您的本地网页,specs 将保存测试本身,而 utils 将保存帮助文件,如模拟凭证生成。 尽管本教程中没有使用,但最好的做法是创建一个 logs 文件夹来保存测试结果。

创建这些目录后,在首选编辑器中创建并打开一个 jest.config.js 文件:

nano jest.config.js

将这些配置添加到文件中:

端到端测试教程/jest.config.js

module.exports = {
  preset: 'jest-puppeteer',
  roots: [ 'specs' ],
};

这是一个 Jest 配置文件,设置为告诉 Jest 使用您安装的 jest-puppeteer 库的 preset 配置。 它还将 specs 文件夹指定为您将在本教程后面编写的测试脚本的位置。

保存并退出文件。 接下来,从根目录创建并打开 jest-puppeteer.config.js 文件:

nano jest-puppeteer.config.js

将这些配置添加到文件中:

端到端测试教程/jest-puppeteer.config.js

module.exports = {
  launch: {
    headless: false,
      args: [ "--window-size=1366,768" ],
  },
  browser: 'chromium',
}

这些配置定义了浏览器将如何打开以测试网页。 headless 判断浏览器是否运行有界面或无界面; 在这种情况下,您将 Puppeteer 配置为在桌面环境中打开窗口。 args 用于将相关的 Puppeteer 参数传递给浏览器实例。 在这种情况下,您使用它来指定打开的浏览器的窗口大小。 最后,browser 指定要使用的浏览器。 对于本教程,这是 Chromium,但如果您安装了 puppeteer-firefox,它可能是 Firefox

保存并退出文件。

specs 文件夹设置为保存所有测试的文件夹后,您现在将在该文件夹中创建一个基本测试文件。

导航到 specs 文件夹并创建一个 users.test.js 文件。 打开 users.test.js 文件并添加以下代码来测试您的应用程序的功能:

端到端测试教程/spec/users.test.js

jest.setTimeout(60000)

describe('Basic authentication e2e tests', () => {
  beforeAll( async () => {
  // Set a definite size for the page viewport so view is consistent across browsers
    await page.setViewport( {
      width: 1366,
      height: 768,
      deviceScaleFactor: 1
    } );   

    await page.goto('https://www.google.com');

    await page.waitFor(5000);
    } );

  it( 'Should be truthy', async () => {
    expect( true ).toBeTruthy();
  })  
});

在此代码中,您首先使用 setTimeout() 方法将 Jest 的默认超时设置为 60 秒。 Jest 有五秒的默认超时时间,测试必须通过或失败,否则测试将返回错误。 由于浏览器交互的运行时间通常超过 5 秒,因此您将其设置为 60 秒以适应时间流逝。

接下来,describe 块使用 describe 关键字将相关测试相互分组。 其中,beforeAll 脚本允许您在此块中的每个测试之前运行特定代码。 这包含类似变量的代码,这些变量对于这个测试块是本地的,但对于它包含的所有测试都是全局的。 在这里,您使用它将在浏览器中打开的页面的视口设置为 jest-puppeteer.config.js 中指定的浏览器大小。 然后使用 page 对象导航到 www.google.com 并等待五秒钟,以便在页面加载后和浏览器关闭之前看到页面。 page 对象在所有测试套件中全局可用。

接下来,您创建了一个模拟测试来验证您编写的脚本是否有效。 它检查布尔值 true 是否为真值,如果一切正常,情况总是如此。

保存并退出文件。

现在,您需要一种方法来运行测试以查看它是否按预期工作。 打开您的 package.json 文件并修改 scripts 部分,如以下代码块所示:

端到端测试教程/package.json

{
  "name": "Doe's-e2e-test",
  "version": "1.0.0",
  "description": "An end to end test",
  "main": "index.js",
  "scripts": {
    "e2e": "jest"
  },
  "keywords": [],
  "author": "John Doe",
  "license": "MIT"
}

这将使关键字 e2e 调用 jest 命令来运行测试。 保存文件后,使用以下命令在终端中运行 e2e 测试:

npm run e2e

运行此命令后,将打开一个新的浏览器窗口,导航到 Google,然后在控制台上打印以下输出:

Output
> jest

 PASS  specs/users.test.js (13.772s)
  Basic authentication e2e tests
    √ Should be truthy (3ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        14.221s, estimated 16s
Ran all test suites.

这表明 Puppeteer 和 Jest 都正常工作。 您现在已准备好开始为网页编写测试。 但首先,您将设置示例网页,以便您有一个界面进行测试。

第 3 步 — 运行示例 Web 界面

在此步骤中,您将从 DigitalOcean 社区 GitHub 存储库 克隆一个示例应用程序,然后使用 Live Server 开发服务器 在本地运行它。 这将为您提供一个用户界面来测试您的 Node.js 应用程序。

注意: 本教程将仅从用户的角度检查此示例 UI; 构建用户界面所需的开发超出了本教程的范围。 如果您对开发 UI 登录验证页面感兴趣,请查看我们的 如何将登录验证添加到 React 应用程序 教程。


首先,打开一个新终端并在测试应用程序之外运行以下 git 命令:

git clone https://github.com/do-community/mock-auth.git

这将从 DigitalOcean 存储库中克隆用户界面。 此代码包含创建模拟身份验证接口的 HTMLCSSJavaScript

接下来,使用以下命令全局安装 Live Server:

npm install -g live-server

注意: 在某些系统上,例如Ubuntu 20.04,全局安装npm包会导致权限错误,从而中断安装。 由于避免将 sudonpm install 一起使用是一种安全最佳实践,因此您可以通过更改 npm 的默认目录来解决此问题。 如果遇到 EACCES 错误,请按照 npm 官方文档 中的 说明进行操作。


Live Server 是具有实时重新加载功能的轻型开发服务器。 它将获取您的静态 HTML 页面并使它们在 localhost 上可用。

接下来,导航到 mock-auth 示例界面:

cd mock-auth

然后使用以下命令在本地开发服务器上启动应用程序:

live-server

一个网页将在您的默认浏览器中打开 http://127.0.0.1:8080,呈现如下图像:

这是您的测试程序将与之交互的 UI。 如果单击 Login 按钮,浏览器将加载登录表单,其中包含 用户名密码 字段。 选择 Create Account 按钮将引导您进入 Create Account 表单,其中包含 FullnameUsernamePassword 字段。 在接下来的步骤中,您将编写测试以浏览每个界面,确保帐户创建和登录按预期工作。

第 4 步 - 测试帐户创建

当您在网站上创建帐户时,最常见的行为是网站将您导航到一个欢迎页面,该页面包含您的姓名和有关您新创建的帐户的一些相关信息。 在此步骤中,您将验证示例 Web 应用程序上的帐户创建页面是否以这种方式工作。 为此,您将在 actions 文件夹中编写一个脚本来导航界面,然后编写一个使用该操作来验证功能的测试。

首先,返回包含您的测试程序的终端,并创建一个脚本来爬取示例 Web 应用程序的 Create Account 页面。 本教程将把这个文件命名为 createAccount.js

nano actions/createAccount.js

打开此文件后,添加以下代码:

端到端测试教程/actions/createAccount.js

const chalk = require( 'chalk' );

class createAccount {
  constructor( page ) {
    this.url = "http://127.0.0.1:8080/"
    this.page = page;
    this.signupBtn = '#signup';
    this.signupBody = '#signupBody';
    this.fullnameField = '#fullname';
    this.usernameField = '#username';
    this.passwordField = '#password';
    this.loginPageBtn = '#loginBtn';
    this.signupPageBtn = '#signupBtn';
  }
}

module.exports = ( page ) => new createAccount( page );

此代码段首先导入 chalk 模块,稍后将使用该模块在终端中格式化错误消息。 这不是必需的,但会使您的错误报告更清晰。 接下来,创建一个名为 createAccount。 构造函数采用 page 参数,然后设置示例 Web 应用程序的主页 URL,并将对象的属性设置为 ID 引用您的程序将在 DOM[X229X 上与之交互的 HTML 元素]。 最后,您的代码导出了一个 函数,它创建了一个 createAccount 类的新实例。

接下来,您将向 createAccount 类添加一个 signup 方法,该方法将帮助您在页面上执行各种操作。 将以下突出显示的代码添加到您的文件中:

端到端测试教程/actions/createAccount.js

...
    this.signupPageBtn = '#signupBtn';
  }

  async signup( fullname, username, password ) {
    try {
      await this.page.goto( this.url );
      await this.page.waitFor( this.signupBtn );
      await this.page.click( this.signupBtn );
      // Wait for the signupBody on the signup page to load
      await this.page.waitFor( this.signupBody );

      // Type the login credentials into the input fields
      await this.page.type( this.fullnameField, fullname );
      await this.page.waitFor( 1000 );
      await this.page.type( this.usernameField, username );
      await this.page.waitFor( 1000 );
      await this.page.type( this.passwordField, password );
      await this.page.waitFor( 1000 );
            
      // Click then create account button
      await this.page.click( this.signupPageBtn );

      // Wait for homepage to load
      await this.page.waitFor( '#firstname' );
      await this.page.waitFor( 2000 );

      const firstname = await this.page.$eval( '#homeBody #firstname', el =>  el.textContent );
            
      return firstname;
    } catch ( err ) {
      console.log( chalk.red( 'ERROR => ', err ) );
    }
  }
}

module.exports = ( page ) => new createAccount( page );

在这里,您使用 async 关键字 signup 方法声明为 异步。 此函数使用 try...catch 块转到 Web 应用程序的 URL 并在界面中导航。 page 对象上使用的一些方法是:

  • page.goto(url):将浏览器导航到指定的 URL。
  • page.waitFor(milliseconds or element):将页面上的其他操作延迟指定的毫秒数,或者直到元素加载完毕。
  • page.click(selector):点击页面上的一个元素。
  • page.type(selector, text):在指定的输入字段中键入文本。
  • page.$eval(selector, callback(element)):选择一个元素并在其上运行回调函数。

使用这些方法,signup 函数首先将页面导航到基本 URL,然后等待加载注册按钮。 然后它单击此按钮并等待注册表单的正文加载。 它每隔一秒在各自的字段中输入全名、用户名和密码。 然后,它单击注册按钮并等待欢迎页面加载。 page.$eval() 方法用于获取该方法返回的欢迎页面上显示的名称。

保存并退出文件。

现在,您将编写测试来验证帐户创建是否按预期工作。 但在继续之前,您必须决定使用哪些凭据创建新帐户。 为此,您将创建一个新模块。

utils 文件夹中创建一个 credentials.js 文件:

nano utils/credentials.js

将以下代码添加到文件中:

端到端测试教程/utils/credentials.js

module.exports = ( user ) => {
  let username = `${user}-${Math.random()}`
  let password = `${Math.random()}`;
  // Make sure both usernames and passwords are strings
  username = String( username );
  password = String( password );
  const fullname = "John Doe"
  let credential = { fullname, username, password };
  return credential;
}

此代码生成随机用户名、密码和硬编码全名,然后将生成的凭据作为 JSON 对象 返回。 您可以将硬编码名称更改为您选择的名称,但创建帐户时的唯一实体通常是用户名。

保存并退出credentials.js

接下来,导航到 specs 文件夹并在编辑器中打开 users.test.js 文件。 修改代码如下所示:

端到端测试教程/specs/users.test.js

let credentials = require( '../utils/credentials' );

jest.setTimeout(60000);

describe('Basic authentication e2e tests', () => {
  let credential;
  beforeAll( async () => {
  // Set a definite site for the page viewport so view is consistent across browsers
    await page.setViewport( {
      width: 1366,
      height: 768,
      deviceScaleFactor: 1
    } );
        
    credential = credentials( 'User' ); 
        
    await page.goto('https://www.google.com');
        
    await page.waitFor(5000);
  } );
    
  it( 'Should be truthy', async () => {
    expect( true ).toBeTruthy();
  })
} );

在这里,您导入了之前创建的 credentials 模块,然后创建了一个全局可用于该块中所有测试的 credential 变量,并使用 beforeAll 将生成的凭据分配给该变量块,它在此块中的每个测试之前运行。

现在,您可以通过修改代码来编写实际执行验证的测试,如下所示:

端到端测试教程/specs/users.test.js

let credentials = require( '../utils/credentials' );
let createAccount = require( '../actions/createAccount' );

jest.setTimeout(60000);

describe('Basic authentication e2e tests', () => {
  let credential;
  beforeAll( async () => {
  // Set a definite site for the page viewport so view is consistent across browsers
    await page.setViewport( {
      width: 1366,
      height: 768,
      deviceScaleFactor: 1
    } );

    credential = credentials( 'User' );
    createAccount = await createAccount( page );
  } );

  it( 'Should be able to create an account', async () => {
    const firstname = await createAccount.signup( credential.fullname, credential.username, credential.password );
    page.waitFor( 1000 );
    expect( credential.fullname ).toContain( firstname );
  })

} );

您现在已导入 createAccount 模块并调用 signup 方法,以便在程序导航界面后在欢迎页面上显示 fullname。 然后代码断言此 fullname 与调用测试方法之前生成的 fullname 相同。

保存脚本,然后使用命令 npm run e2e 运行它:

npm run e2e

Chrome 浏览器将打开并使用生成的凭据自动创建一个帐户。 测试完成后,以下输出将记录到您的控制台:

Output> jest

 PASS  specs/users.test.js (28.881s)
  Basic authentication e2e tests
    √ Should be able to create an account (26273ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        29.087s
Ran all test suites.

此脚本现在已经验证了帐户创建过程。

在此步骤中,您编写了一个脚本来爬取示例 Web 应用程序并自动创建一个帐户。 然后,您通过为爬虫脚本编写单元测试来断言该过程按预期工作。 在下一步中,您将对登录功能执行相同的操作。

第 5 步 — 测试登录过程

在此步骤中,您将断言登录功能可以正常工作。 此步骤类似于创建帐户步骤,您将首先创建一个网络爬虫脚本来导航登录页面,然后编写一个单元测试以确认该功能按预期工作。

首先,在您喜欢的编辑器中创建并打开一个 loginAccount.js 文件:

nano actions/loginAccount.js

然后添加如下代码遍历登录页面:

端到端测试教程/actions/loginAccount.js

const chalk = require( 'chalk' );

class LoginAccount {
  constructor( page ) {
    this.url = "http://127.0.0.1:8080/"
    this.page = page;
    this.loginBtn = '#login';
    this.loginBody = '#loginBody';
    this.usernameField = '#username';
    this.passwordField = '#password';
    this.loginPageBtn = '#loginBtn';
  }

  async login( username, password ) {
    try {
      await this.page.goto( this.url );
      await this.page.waitFor( this.loginBtn );
      await this.page.click( this.loginBtn );
      // Wait for the loginBody on the login page to load
      await this.page.waitFor( this.loginBody );

      // Type the login credentials into the input fields
      await this.page.type( this.usernameField, username );
      await this.page.waitFor( 1000 );
            
      await this.page.type( this.passwordField, password );
      await this.page.waitFor( 1000 );

      await this.page.click( this.loginPageBtn );

      // Wait for homepage to load 
      await this.page.waitFor( '#firstname' );
      await this.page.waitFor( 2000 );
 
      const firstname = await this.page.$eval( '#homeBody #firstname', el =>  el.textContent );

      return firstname;
    } catch ( err ) {
      console.log( chalk.red( 'ERROR => ', err ) );
    }
  }
}

module.exports = ( page ) => new LoginAccount( page );

此代码类似于 createAccount.js 文件。 首先,您创建了一个 LoginAccount 类并导出了一个以 page 对象作为参数的函数。 构造函数包含对要在 DOM 上交互的几个 HTML 元素的 ID 引用。

LoginAccount 类有一个异步的 login 方法,它以 usernamepassword 作为参数,帮助您在页面上执行各种操作。 代码首先导航到示例 Web 应用程序的 URL,然后单击加载登录页面的按钮。 登录页面加载完成后,它会使用 login 方法中传入的用户名和密码填写表单,然后单击 Login 按钮提交。 如果登录成功,它会加载欢迎页面并返回名字,您将把它传递给您的单元测试。

保存并退出文件。

接下来,再次打开您的 users.test.js 文件并修改如下:

端到端测试教程/specs/users.test.js

let credentials = require( '../utils/credentials' );
let createAccount = require( '../actions/createAccount' );
let loginAccount = require( '../actions/loginAccount' );


jest.setTimeout(60000);

describe('Basic authentication e2e tests', () => {
  let credential;
  beforeAll( async () => {
  // Set a definite site for the page viewport so view is consistent across browsers
    await page.setViewport( {
      width: 1366,
      height: 768,
      deviceScaleFactor: 1
    } );
        
    credential = credentials( 'User' );
    createAccount = await createAccount( page );
    loginAccount = await loginAccount( page );
  } );
    
  it( 'Should be able to create an account', async () => {
    const firstname = await createAccount.signup( credential.fullname, 
    credential.username, credential.password );
    page.waitFor( 1000 );
    expect( credential.fullname ).toContain( firstname );
  })

  it( 'Should be able to log in after a successful account creation', async () => {
    const firstname = await loginAccount.login( credential.username, credential.password );
    page.waitFor( 1000 );
    expect( credential.fullname ).toContain( firstname );
  } );

} );

在这段代码中,您导入了 loginAccount 模块,在 page 上调用了网络爬虫函数,然后创建了一个新的测试断言,如果 Login 页面上的名称则通过包含在生成的凭据中。

保存文件,然后从终端运行 npm run e2e

npm run e2e

网络爬虫将打开一个浏览器,导航到 Login 页面,然后输入凭据,然后运行测试脚本来确定网络爬虫是否进入了欢迎页面。

以下将记录到终端:

Output> jest

 PASS  specs/users.test.js (48.96s)
  Basic authentication e2e tests
    √ Should be able to create an account (21534ms)
    √ Should be able to log in after a successful account creation (12899ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        52.426s
Ran all test suites.

这表明成功登录的测试按预期通过。 但是,测试尚未完成; 该程序仍然需要能够处理不成功的登录尝试。

如果提供了错误的用户名和密码组合,则会弹出警告提示消息输入的用户名或密码无效。 要测试警告框消息,您可以在 page 对象上侦听 dialog event。 警告框的存在表明刚刚进行了不成功的登录尝试。

要实现这一点,请修改 users.test.js 脚本,如下所示:

端到端测试教程/specs/users.test.js

let credentials = require( '../utils/credentials' );
let createAccount = require( '../actions/createAccount' );
let loginAccount = require( '../actions/loginAccount' );


jest.setTimeout(60000);

describe('Basic authentication e2e tests', () => {
  let credential;
  beforeAll( async () => {
  // Set a definite site for the page viewport so view is consistent across browsers
    await page.setViewport( {
      width: 1366,
      height: 768,
      deviceScaleFactor: 1
    } );
        
    credential = credentials( 'User' );
    createAccount = await createAccount( page );
    loginAccount = await loginAccount( page );
  } );
    
  it( 'Should be able to create an account', async () => {
    const firstname = await createAccount.signup( credential.fullname, credential.username, credential.password );
    page.waitFor( 1000 );
    expect( credential.fullname ).toContain( firstname );
  })

  it( 'Should be able to log in after a successful account creation', async () => {
    const firstname = await loginAccount.login( credential.username, 
    credential.password );
    page.waitFor( 1000 );
    expect( credential.fullname ).toContain( firstname );
  } );

  it( 'Should not login on wrong credentials', async () => {
    try {
      page.on( 'dialog', dialog => {
        expect( dialog.message() ).toBe( 'Invalid username or password inputted' );
        dialog.accept();
      });

      await page.goto( 'http://127.0.0.1:8080/login.html' );
      await page.type( '#username', 'username' );
      await page.type( '#password', 'password' );
      await page.click( '#loginBtn' );
      await page.waitFor(5000) //Wait for the dialog to accept the prompt before proceeding

    } catch(err){
      console.log("An error occured while trying to login => ", err)
    }
  })

} );

在此代码中,您添加了一个新断言,该断言首先为 dialog 事件设置事件侦听器,然后再执行任何页面交互。 如果网络爬虫在侦听 dialog 事件之前单击按钮,则 dialog 会在事件冒泡之前弹出。

接下来,代码导航到 login.html 页面并输入 usernamepassword 作为凭据。 由于这些凭据与您创建帐户时输入的凭据不匹配,这将导致错误,这将触发您的断言正在等待的对话框。 最后,请注意您在最后添加了 5 秒延迟。 这是为了确保 dialog 事件在 jest-puppeteer 关闭页面之前接受对话框。 一旦不再有可运行的测试,该页面就会关闭。

保存 users.test.js 文件并运行测试:

npm run e2e

接下来,观察所有测试是否通过:

Output PASS  specs/users.test.js (25.736 s)
  Basic authentication e2e tests
    ✓ Should be able to create an account (11987 ms)
    ✓ Should be able to log in after a successful account creation (8196 ms)
    ✓ Should not login on wrong credentials (5168 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        25.826 s, estimated 27 s
Ran all test suites.

这表明示例 Web 应用程序正在按预期工作。

结论

在本教程中,您使用 Puppeteer 和 Jest 为具有帐户创建和登录功能的示例 Web 应用程序编写自动化测试。 您将 Puppeteer 和 Jest 配置为一起工作,然后编写脚本来导航 Web 应用程序 UI 并返回它遇到的 HTML 元素的值。 最后,您测试了这些值是否与您正在测试的操作的预期值相匹配。

端到端测试不仅是测试 UI 的有用方法; 您还可以使用它来确定 Web 应用程序中的其他关键功能是否按预期工作。 例如,您可以使用 设备仿真 和网络节流在多个设备上运行性能测试。 有关端到端测试的更多信息,请查看 PuppeteerJest 的官方文档。