深入理解Browser、Context、Page,可以让我们轻松掌握Playwright的工作原理,并从容应对问题如:如何处理对话框?如何复用登录身份信息?录制调整视频大小或者存储目录?

1. 概念

    在Playwright中,Browser, Context, 和 Page 是核心概念,它们共同定义了自动化测试的结构。

    测试会在浏览器(Browser)的上下文(BrowserContext)中执行,每个上下文包含多个页面(Page)。每个页面都代表了一个打开的浏览器标签页。这种层级结构允许你在同一个浏览器实例中同时执行多个测试用例,以提高效率。

Browser

  • • Browser 对应于一个完整的浏览器实例,比如 Chrome、Firefox 或 WebKit。

  • • Playwright 脚本通常从启动一个 Browser 实例开始,并在测试结束时关闭它。

  • • Browser 可以在无头(headless)或有头(headful)模式下启动。

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

// 无头模式启动浏览器
async function launchInHeadlessMode() {
  const browser = await chromium.launch({ headless: true });
  console.log('浏览器已在无头模式下启动');
  // 执行其他操作...
  await browser.close();
}

// 有头模式启动浏览器
async function launchInHeadfulMode() {
  const browser = await chromium.launch({ headless: false });
  console.log('浏览器已在有头模式下启动');
  // 执行其他操作...
  await browser.close();
}

// 分别调用无头模式和有头模式启动浏览器的函数
launchInHeadlessMode();
launchInHeadfulMode();
  • • 一个 Browser 实例可以包含多个BrowserContext。 BrowserContext 代表了浏览器的一个隔离环境,其中包含了一组浏览器窗口(Page)、cookies、缓存、本地存储等。使用多个 BrowserContext 可以帮助模拟不同用户的会话,或者隔离测试环境以避免相互干扰。

BrowserContext

  • • BrowserContext 代表了一个浏览器的会话,它类似于一个全新的浏览器配置文件。

  • • Playwright 为每个测试用例创建一个 BrowserContext,以确保测试之间的隔离。

  • • 每个 BrowserContext 拥有自己的 Cookie、浏览器存储和浏览历史记录。

  • • 可以在同一个 Browser 实例中创建多个 BrowserContext 来模拟多用户会话。

示例代码:

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

async function main() {
  // 启动一个浏览器实例
  const browser = await chromium.launch();

  // 创建第一个 BrowserContext
  let context1 = await browser.newContext();
  let page1 = await context1.newPage();
  await page1.goto('https://example.com');
  console.log('在第一个上下文中打开网页');

  // 创建第二个 BrowserContext
  let context2 = await browser.newContext();
  let page2 = await context2.newPage();
  await page2.goto('https://example.com');
  console.log('在第二个上下文中打开网页');

  // ... 在这里可以继续创建更多的 BrowserContext 和 Page,并进行相应的操作

  // 关闭所有打开的 BrowserContext
  await context1.close();
  await context2.close();

  // 关闭浏览器实例
  await browser.close();
}

说明如下:

  • • 启动了一个 Browser 实例,然后创建了两个 BrowserContext 实例。

  • • 每个 BrowserContext 实例都打开了相同的网页,但由于它们是隔离的,因此它们各自的状态(例如 cookies、localStorage)不会相互影响。

  • • 关闭了这两个 BrowserContext 以及最初的 Browser 实例

Page

  • • Page 是在 BrowserContext 中打开的单个网页。

  • • 每个 Page 代表了用户与浏览器交互时看到的视图。

  • • Page 提供了丰富的 API 用于导航、操作元素、处理表单、弹出窗口等。

  • • 在同一个 BrowserContext 中可以打开多个 Page 实例。

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

(async () => {
  const browser = await chromium.launch();
  const context = await browser.newContext();

  // 打开第一个页面
  const page1 = await context.newPage();
  await page1.goto('https://example.com');
  console.log(await page1.title());

  // 打开第二个页面
  const page2 = await context.newPage();
  await page2.goto('https://example.org');
  console.log(await page2.title());

  // 关闭浏览器
  await browser.close();
})();

说明如下:

  • • 使用browser.newContext() 创建了一个新的浏览器上下文。

  • • 通过 context.newPage() 分别创建了两个新的页面实例,即 page1 和 page2,每个页面可以独立进行导航和操作

三者关系图

Browser
  |--- BrowserContext
        |--- Page
        |--- Page
        |--- ...

2.典型场景

复用登录身份信息

  • • 使用同一 BrowserContext 打开多个 Page 可以共享相同的 Cookie,从而复用登录状态。

  • • 使用 context 的 storageState 方法来实现

  • • 保存当前上下文的状态,包括登录信息,并在创建新页面时进行恢复

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

(async () => {
  const browser = await chromium.launch();
  const context = await browser.newContext();

  // 在第一个页面登录
  const page1 = await context.newPage();
  await page1.goto('https://example.com/login');
  await page1.fill('input[name=username]', 'your_username');
  await page1.fill('input[name=password]', 'your_password');
  await page1.click('button[type=submit]');

  // 保存上下文状态
  const storageState = await context.storageState();

  // 在新页面中恢复登录状态
  const page2 = await context.newPage();
  await page2.goto('https://example.com/dashboard', { waitUntil: 'domcontentloaded' });

  // 具体的测试逻辑

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

操作对话框

当 Page 触发弹出对话框时,可以使用 Page 的相关 API 来定位和操作对话框元素。

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

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

  // 监听 'dialog' 事件
  page.on('dialog', async (dialog) => {
    console.log('Dialog message:', dialog.message());

    // 模拟输入值并点击确定按钮
    await dialog.type('Your input');
    await dialog.accept();
  });

  // 触发一个包含 Prompt 对话框的操作,例如点击一个按钮
  await page.goto('https://example.com');
  await page.click('button');

  // 关闭浏览器
  await browser.close();
})();

说明如下:

  • • 使用page.on()监听对话框事件

  • • 通过 dialog.type('Your input') 模拟输入文本,并使用 dialog.accept() 确认对话框

视频录制

通过 Browser 的 browserContext.newPage() 打开 Page 后,可以使用 Browser 的录制功能来保存整个浏览器会话的视频。

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

(async () => {
  const browser = await chromium.launch();
  const context = await browser.newContext({
    viewport: { width: 1920, height: 1080 }, // 设置视口大小为 1920x1080
    recordVideo: { dir: './videos/' } // 设置视频存储路径为当前目录下的 videos 文件夹
  });
  const page = await context.newPage();

  // 打开页面并进行一些操作
  await page.goto('https://example.com');
  // 进行其他操作...

  // 关闭浏览器
  await browser.close();
})();

说明如下:

  • • chromium.launch() 启动了 Chromium 浏览器实例

  • • 使用 browser.newContext() 创建了一个新的浏览器上下文,并设置了视口大小为 1920x1080,同时开启了视频录制并设置了存储路径为当前目录下的 videos 文件夹。

  • • 使用 context.newPage() 创建了一个新的页面。

  • • 可以在页面上执行各种操作,最后关闭了浏览器。

小结

    深入理解这些概念和它们的关系是理解和有效使用 Playwright 进行自动化测试的基础。通过合理地管理 Browser,Context,和 Page,可以编写出高效、可维护且稳定的自动化测试脚本。

深入比较:Playwright、Cypress、Selenium三款自动化测试框架

自动化测试是软件开发过程中至关重要的一环,而选择适当的测试框架是成功实施自动化测试的关键。本文深入对比3个流行的自动化测试框架:Playwright、Cypress 和 Selenium,从多个维度进行对比并给出评分,以帮助开发者更好地选择适合其项目需求的工具。

1. 市场趋势

    选取了npm下载次数和github上star数字对比三款工具表现: npm downloads和github stats说明:

  • • cypress和playwright分别占据12名位置,在3月初每周下载量分别有550w+和450w+下载次数

  • • playwright作为第2名在过去增长很快,尤其在过去1年

  • • github stars看,playwright排在第一超过6w+,而cypress排在第2有4.5w+

2. 技术架构

Playwright

  • • 基于Websocket通讯,建立与服务器连接,所有命令基于该连接

Cypress

  • • 基于浏览器内 ,命令无需网络传输

Selenium

  • • 基于http requests,在Selenium WebDriver 和 web browsers之间通讯

  • • Selenium实际上包含一组工具,基于录制回放的Selenium IDE、支持并行执行的Selenium Grid,还有核心的Selenium WebDriver,以及由此演化而来的Selenium2、Selenium3、Selenium4是下面重点要比较的内容

3. 兼容性

Playwright: 9/10

  • • 支持多种浏览器,包括 Chromium、Firefox 和 WebKit。

  • • 提供对不同浏览器的无缝支持,可在同一测试用例中执行多个浏览器的测试。

Cypress: 7/10

  • • 主要支持 Chromium和Electron,对于其他浏览器的支持较少。

  • • 在 Firefox 和 Microsoft Edge 上的支持相对较新。

Selenium: 8/10

  • • 多浏览器支持,但有时需要特定的驱动程序。

  • • 一些浏览器可能不支持所有功能。

4. 执行速度

Playwright: 9/10

  • • 采用先进的技术,如无头模式和并发执行,并行执行多个浏览器实例,加速测试过程。

Cypress: 8/10

  • • 专注于单页面应用 (SPA),因此在执行速度上相对较快。

  • • 但在大型应用或多页面测试中,性能可能有所下降。

Selenium: 7/10

  • • Selenium Grid 可以实现并发执行。

  • • 慢于 Playwright,尤其是在远程操作执行时。

5. 易用性

Playwright: 8/10

  • • 提供丰富的 API 和文档,学习曲线相对较低,尤其是有经验的开发者。

  • • 相对于 Selenium,更容易设置和运行。

  • • Playwright提供了强大而灵活的元素定位和断言机制,支持多种策略,包括文本、属性和角色。

  • • Playwright提供了强大的调试工具,可以直接在浏览器中调试测试用例。

Cypress: 9/10

  • • 专注于简化测试流程,易于上手。

  • • 提供直观的命令式 API。

  • • Cypress的元素定位和断言相对简单,通过类名和属性等辅助定位.

  • • Cypress的调试工具非常直观,可以在测试运行过程中实时查看。

Selenium: 7/10

  • • 学习曲线较陡峭,特别是对于初学者。

  • • 多语言支持,但某些语言的库可能不如其他语言成熟。

  • • Selenium的元素定位相对传统,通过XPath和CSS选择器等方式,断言也是基于页面元素状态。

  • • Selenium调试通常需要借助浏览器的开发者工具,相对较为独立。

6. 维护性

Playwright: 8/10

  • • 拥有稳定的 API,高度模块化,易于维护

  • • 相对较新,社区不如 Selenium 庞大

Cypress: 8/10

  • • 大型项目中,由于缺乏一些 Selenium 的通用性,可能需要更多的工作

Selenium: 7/10

  • • 成熟且稳定,但可能需要更多的配置。

  • • 随着时间的推移,可能需要不断更新测试脚本。

7. 社区支持

Playwright: 8/10

  • • 社区相对较新,但在不断增长

  • • 微软等大公司支持,但相比 Selenium 的社区规模还是较小

Cypress: 8/10

  • • 虽然不如 Selenium 那么大,但在社区中也有相当的支持。

  • • 活跃的维护者和贡献者。

Selenium: 9/10

  • • 问题通常能够得到迅速解决。

  • • 大量的文档和教程可用。

8. 结论

    根据以上对比和评分,开发者在选择适合自己项目需求的测试框架时,往往会考虑多种因素:

  • • Playwright 适合高性能大型的项目,在跨浏览器支持、执行速度和灵活性上,可能是一个很好的选择。

  • • Cypress 专注于简单易用,适用于单页面应用的测试。

  • • Selenium 在社区支持和成熟性上胜过其他两者,适合那些需要广泛支持的项目。

    以上工具我在过去项目中都有使用,Cypress在3-4年前使用,最近转到了Playwright,考虑的主要因素还是项目特点+团队情况:比如语言熟悉程度、自动化学习兴趣,独立解决问题能力等等。

    总之,自动化框架最终的选择Playwright、Cypress、Selenium根据项目的具体需求和团队的技术偏好来进行权衡。如果没有特别的想法,那么选择最新的Playwright大概率是不错的方案。

更多推荐