断言在自动化测试中扮演着至关重要的角色。它们帮助我们验证应用程序的行为是否符合预期,并在发现问题时提供详细的错误信息。本文将深入探讨断言的各个层面,从基础到高级,带您逐步了解如何利用Playwright进行高效的断言。

基础篇:断言

1. 为什么需要断言

    在自动化测试中,我们需要一种机制来验证应用程序的行为是否正确。断言是一种用于验证测试结果的机制,它们帮助我们确认测试是否按预期执行,并且在测试失败时提供有用的信息。

2. 断言生成器

 

 

Playwright提供了断言生成器,帮助验证元素是否存在、元素内容、元素属性等:

  • • expect(element).toBeVisible(): 验证元素是否可见,参见上图“小眼睛”图标

  • • expect(element).toHaveText(text): 验证元素的文本内容是否包含指定的文本,,参见上图“ab符号”图标

  • • expect(element).toHaveAttribute(name, value?): 验证元素是否具有指定的属性,以及属性值是否符合预期,参见上图“文本”图标

3. 断言api

    此外,Playwright还提供了丰富的断言api供调用,大致可以分为 基本断言、定位器断言、页面断言、接口类断言 等

基本断言

  • • 相等

expect(value).toBe(expected) //值比较
expect(value).toEqual(expected) //深度比较
  • • 不相等

expect(value).not.toBe(expected)
  • • 包含

expect(value).toContain(expected)
  • • 模式匹配

expect(value).any()
expect(value).anything()
expect(value).arrayContaining()
expect(value).closeTo()
expect(value).objectContaining()
expect(value).stringContaining()
expect(value).stringMatching()
expect(value).toMatch()
expect(value).toMatchObject()

例如

expect({
  list: [1, 2, 3],
  obj: { prop: 'Hello world!', another: 'some other value' },
  extra: 'extra',
}).toEqual(expect.objectContaining({
  list: expect.arrayContaining([2, 3]),
  obj: expect.objectContaining({ prop: expect.stringContaining('Hello') }),
}));

定位器断言

  • • 可见性

expect(element).toBeVisible(); //可见
expect(element).toBeHidden(); //隐藏
expect(element).toBeInViewport(); //视图中
  • • 状态变化

expect(element).toBeChecked(); //选中
const locator = page.getByRole('textbox');
await expect(locator).toBeFocused(); //聚焦
const locator = page.locator('div.warning');
await expect(locator).toBeEmpty(); //空
const locator = page.locator('button');
await expect(locator).toBeEnabled(); //可点
  • • 元素内容

const locator = page.locator('.title');
await expect(locator).toContainText(/\d messages/); //包含
await expect(locator).toHaveText(/Welcome/);
await expect(locator).toHaveValue(/[0-9]/);
const locator = page.getByRole('textbox');
await expect(locator).toHaveId('lastname');
const locator = page.locator('#component');
await expect(locator).toHaveClass(/selected/);

页面断言

  • • URL

await expect(page).toHaveURL(/.*checkout/);
  • • title

await expect(page).toHaveTitle(/.*checkout/);
  • • screenshot

await expect(page).toHaveScreenshot('image.png');

接口断言

  • • toBeOK

await expect(response).toBeOK();
  • • not

await expect(response).not.toBeOK();

进阶篇:软断言

1. 断言的问题

测试断言失败,后续用例都无法执行?这也是自动化测试中经常遇到的问题。 Playwright 提供了软断言Soft Assertions的支持,允许测试在遇到断言失败时继续执行,并在最后统一标记测试为失败,提升测试的灵活性。

2. 什么是软断言

软断言是一种特殊的断言方式,与传统的断言不同,软断言在遇到失败时不会立即中止测试执行,而是将测试标记为失败。这使得在测试中可以执行多个断言,即使其中一部分失败,测试仍能继续执行,方便查看所有断言的结果。

3. 在 Playwright 中使用软断言

在 Playwright 中,可以通过 expect.soft() 方法来执行软断言。

示例如下:

import { test, expect } from '@playwright/test';

test('软断言示范', async ({ page }) => {
  // 在页面上执行软断言
  await expect.soft(page).toHaveTitle('标题');

  // 其他测试步骤
  await page.goto('https://example.com');
  await expect(page).toHaveTitle('Example');
});

test.afterEach(async ({ testInfo }) => {
  // 在测试结束后检查是否有软断言失败
  if (testInfo.errors.length > 0) {
    console.error('软断言失败信息:');
    for (const error of testInfo.errors) {
      console.error(error.message);
      console.error(error.stack);
    }
  }
});

4. 软断言小结

  • • 软断言适用场合,检查多个元素状态但不希望因为一个失败而中断整个测试

  • • expect.soft()实现软断言,testInfo.errors查看是否存在软断言失败

  • • 灵活使用软断言可以提高自动化测试的鲁棒性

高级篇:可视化回归

1. 什么是可视化回归

可视化回归测试,即Visual Regression Testing是一种自动化测试方法,用于检测页面布局和外观的变化。它通过比较页面的屏幕截图,来检测是否存在意外的视觉变化。

2. 利用snapshotAssert

Playwright提供了toMatchSnapshot()方法,用于捕获页面的屏幕截图,并将其与预期的参考截图进行比较。这种方式可以很容易地发现页面布局或样式的变化,从而确保应用程序的外观和用户体验始终如一。

3. 示例

test('可视化回归测试', async ({ page }) => {
    await page.goto('https://alipan.com');
    const screenshot = await page.screenshot();
    expect(screenshot).toMatchSnapshot('alipan.png');
});

说明如下:

  1. 首次运行,生成截面截图alipan.png

  2. 迭代上线后,再次运行,会截图并比对,Playwright检测视觉变化有差异,断言会失败并显示差异的详细信息,包括截图比较结果和差异的位置

结论

  • • 断言在自动化测试中扮演着至关重要的角色,它们帮助我们验证应用程序的行为是否符合预期,并在发现问题时提供详细的错误信息。通过 expect() 开启断言,结合代码生成工具可以快速生成各种断言方法,如 .toBeVisible().toContain().toHaveValue() 等,从而有效地验证页面元素的可见性、内容、属性等。

  • • 软断言 soft() 是一种特殊的断言方式,它允许测试在遇到断言失败时继续执行,并在最后统一标记测试为失败,提升了测试的灵活性。对于需要验证多个条件的测试场景,软断言能够帮助我们更好地捕获失败信息,而不至于中断整个测试流程。

  • • 利用 Playwright 的 toMatchSnapshot() 方法可以实现可视化回归测试,自动检测页面是否发生明显的 UI 变化。通过对比页面截图,我们可以快速发现页面布局或样式的变化,确保应用程序的外观和用户体验始终如一。

    综上所述,断言在自动化测试中是不可或缺的工具,我们可以根据项目需求灵活选用不同类型的断言,并结合软断言和可视化回归测试,提高测试的质量和效率,确保应用程序的稳定性和可靠性。

实现文件自动化下载

 

利用Playwright实现自动化下载文件,演示了自动化下载阿里云盘的基本步骤。详细介绍了Playwright中下载相关属性和方法,以及Promise.all()实现多文件下载。

Playwright实战自动化下载

以自动化下载阿里云盘为例:

 

操作步骤

  • • 首先打开页面alipan.cn

  • • 其次定位到下载桌面端按钮,该页面有2处,任意一处都是可以的,挑选左下角那个,把鼠标移动过去,会出现版本选择,这里我们选择Windows,点击

  • • 等待文件下载完成,并断言检查

用例录制

可以用录制的方法生成测试用例:

npx playwright codegen https://alipan.cn

具体操作可以看前面的介绍文章

【playwright -  CSDN App】https://blog.csdn.net/weixin_46281518/article/details/145601119?sharetype=blogdetail&shareId=145601119&sharerefer=APP&sharesource=weixin_46281518&sharefrom=link

第一篇 

实现代码

import { test, expect, browser } from '@playwright/test';

const playwright = require('playwright');

test('alipan', async ({ page }) => {
    await page.goto('https://www.alipan.com/');
    await expect(page
        .getByText('下载桌面端')
        .nth(1))
        .toBeVisible();
    const downloadPromise = page
        .waitForEvent('download');
    await page
        .getByText('下载桌面端')
        .nth(1)
        .hover();
    await page
        .getByRole('link', { name:'Windows' })
        .nth(1)
        .click();
    const download = await downloadPromise;
    await download
        .saveAs(download.suggestedFilename());
  });

几点说明

  1. 元素定位,采用getByText('下载桌面端'),会命中2条数据,这里用.nth(1)选择第2条结果;

  2. 文件下载,选择Windows链接后,触发下载事件,需要等待文件下载完成后才能进行后续操作,.waitForEvent('download'),并保存为download

  3. download提供了suggestedFilename()方法获取文件名,调用saveAs()方法保存文件

Playwright中下载相关内容

download方法

Playwright中download对象提供了以下方法:

  • • download.path():获取下载文件的路径。

  • • download.saveAs(path):将下载的文件保存到指定路径。

  • • download.failure():返回一个Promise,用于检查下载是否失败。

  • • download.delete():删除下载的文件。

download属性

Playwright中download对象提供了以下属性:

  • • download.url():返回下载文件的URL

  • • download.suggestedFilename():返回下载文件的建议文件名。

  • • download.headers():返回下载文件的响应头信息。

  • • download.finished():返回一个Promise,用于检查下载是否完成。

  • • download.failure():返回一个Promise,用于检查下载是否失败。

  • • download.createTime():返回下载任务创建的时间戳。

  • • download.endTime():返回下载任务结束的时间戳。

page.on('download')

page.on('download') 是 Playwright 中用于监听文件下载事件的方法。该方法用于注册一个监听器,当页面触发文件下载事件时,该监听器会被调用。

在监听器中,我们可以获取到下载的相关信息,例如下载的文件名、文件大小等,并且可以对下载的文件进行保存或其他处理。

参考示例

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();

  // 监听文件下载事件
  page.on('download', download => {
    console.log('Download started: ', download.suggestedFilename());
    // 保存下载的文件到指定路径
    download.saveAs('/path/to/save/' + download.suggestedFilename());
  });

  // 访问包含文件下载链接的页面
  await page.goto('https://example.com');

  // 点击页面上的文件下载链接
  await page.click('a[download]');

  // 等待一段时间,确保下载完成
  await page.waitForTimeout(5000);

  await browser.close();
})();

说明如下:

  • • page.on('download') 方法注册了一个监听器,用于捕获页面上的文件下载事件

  • • 当页面中的文件下载链接被点击时,下载事件被触发

  • • 在监听器中将文件保存到指定的路径中,完成日志打印

Playwright实战多文件下载

Promise.all()

Promise.all() 是 JavaScript 中的一个方法,用于将多个 Promise 对象组合成一个新的 Promise 对象:

  • • 它接收一个由 Promise 对象组成的可迭代对象,并返回一个新的 Promise 对象

  • • 新的 Promise 对象在所有输入 Promise 对象都成功完成时才会被解析,否则会被拒绝,返回拒绝原因中的第一个拒绝的 Promise 对象的结果。示例 假设我们有一个数组 urls 包含多个 URL 地址,我们想要同时发起多个网络请求,并在所有请求都完成时获取它们的响应数据

示例:

const urls = ['https://example.com/1', 'https://example.com/2', 'https://example.com/3'];

const promises = urls.map(url => fetch(url)); // 假设 fetch 是一个异步函数,返回一个 Promise

Promise.all(promises)
  .then(responses => Promise.all(responses.map(response => response.json())))
  .then(dataArray => {
    // 所有请求成功完成后的数据数组
    console.log(dataArray);
  })
  .catch(error => {
    // 处理任何一个请求失败的情况
    console.error('At least one request failed:', error);
  });

说明如下:

  • • Promise.all() 同时发起多个网络请求,并在所有请求完成后,再次使用 Promise.all() 将所有响应转换为 JSON 数据

  • • 通过 .then() 处理所有请求成功完成后的数据,以及通过 .catch() 处理任何一个请求失败的情况

总之,Promise.all() 是一个非常有用的工具,用于管理多个异步操作,使得它们能够并行执行,并且在所有操作完成后统一处理结果。

多文件下载

当需要下载多个文件时,可以利用 Promise.all() 来同时发起多个文件下载请求,并在所有下载完成后进行处理。

示例如下:

const playwright = require('playwright');
const fs = require('fs');

async function downloadFiles(urls) {
  const browser = await playwright.chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();

  const downloadPromises = urls.map(async (url, index) => {
    // 在新标签页中打开文件下载链接
    await page.goto(url);
    // 等待文件下载完成的事件
    const [download] = await Promise.all([
      page.waitForEvent('download'), // 等待文件下载完成
      page.click('a') // 触发文件下载链接点击事件
    ]);
    // 获取文件名
    const fileName = download.suggestedFilename();
    // 将文件保存到本地
    await download.saveAs(`file_${index + 1}_${fileName}`);
    console.log(`File ${fileName} downloaded successfully.`);
  });

  try {
    await Promise.all(downloadPromises);
    console.log('All files downloaded successfully.');
  } catch (error) {
    console.error('Failed to download one or more files:', error);
  }

  await browser.close();
}

// 示例:下载多个文件
const urls = [
  'https://example.com/file1.pdf',
  'https://example.com/file2.docx',
  'https://example.com/file3.xlsx'
];

downloadFiles(urls);

说明如下:

  1. 定义了一个名为 downloadFiles 的异步函数,该函数接收一个 URL 数组作为参数,然后使用 Promise.all() 方法来同时发起多个文件下载请求

  2. 每个 URL,在新的浏览器上下文中打开一个页面,并在页面中点击文件下载链接。

  3. 等待文件下载完成的事件,并使用 download.saveAs() 方法将下载的文件保存到本地。

  4. 通过 Promise.all() 来等待所有文件下载完成,或捕获其中任何一个下载失败的情况

小结

  1. Playwright中利用定位和点击等触发下载操作,可以利用codegen录制代码,再手动调整修改

  2. Playwright中下载触发download事件,.waitForEvent('download')

  3. download.saveAs()保存下载文件

  4. 多文件下载,用Promise.all()处理

 

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐