编写合成测试编辑

设置项目后,您可以开始编写合成测试,以检查最终用户可能在您的站点上执行的关键操作和请求。

语法概述编辑

要为您的应用程序编写合成测试,您需要了解基本的 JavaScript 和 Playwright 语法。

Playwright 是由 Microsoft 开发的浏览器测试库。它速度快、可靠性高,并具有现代 API,可以自动等待页面元素准备就绪。

合成代理公开了一个用于创建和运行测试的 API,包括

journey

测试一个离散的功能单元。采用两个参数:name(字符串)和 callback(函数)。在创建旅程中了解更多信息。

step

旅程中应按特定顺序完成的操作。采用两个参数:name(字符串)和 callback(函数)。在添加步骤中了解更多信息。

expect

检查值是否满足特定条件。支持多种检查。在进行断言中了解更多信息。

beforeAll

在任何 journey 运行之前运行一次提供的函数。如果提供的函数是一个 promise,则运行程序将在调用 journey 之前等待 promise 解析。采用一个参数:callback(函数)。在设置和删除全局状态中了解更多信息。

before

在单个 journey 运行之前运行提供的函数。采用一个参数:callback(函数)。在设置和删除全局状态中了解更多信息。

afterAll

在所有 journey 运行完成后运行一次提供的函数。采用一个参数:callback(函数)。在设置和删除全局状态中了解更多信息。

after

在单个 journey 完成后运行提供的函数。采用一个参数:callback(函数)。在设置和删除全局状态中了解更多信息。

monitor

monitor.use 方法允许您逐个旅程地确定监视器的配置。例如,如果您希望两个旅程创建具有不同间隔的监视器,则应在每个旅程中调用 monitor.use,并在每个旅程中将 schedule 属性设置为不同的值。请注意,这仅在使用 push 命令在 Kibana 中创建监视器时才相关。在配置单个监视器中了解更多信息。

创建旅程编辑

使用 .journey.ts.journey.js 文件扩展名创建一个新文件,或编辑其中一个示例旅程文件。

旅程测试一个离散的功能单元。例如,登录网站、将商品添加到购物车或加入邮件列表。

journey 函数采用两个参数:namecallbackname 帮助您识别单个旅程。callback 参数是一个函数,它封装了旅程的功能。回调函数提供对新的 Playwright pageparamsbrowsercontext 实例的访问。

journey('Journey name', ({ page, browser, context, params, request }) => {
  // Add steps here
});
参数编辑

name (string)

用户定义的字符串,用于描述旅程。

callback (function)

您将在其中添加步骤的函数。

实例:

page
Playwright 中的 page 对象,允许您控制浏览器的当前页面。
browser
由 Playwright 创建的 browser 对象。
context
一个 浏览器上下文,它不与其他浏览器上下文共享 cookie 或缓存。
params
用户定义的变量,允许您使用自定义参数调用 Synthetics 套件。例如,如果您想根据 env 使用不同的主页(dev 使用 localhostprod 使用 URL)。有关更多信息,请参阅使用参数和密钥
request
一个请求对象,可用于独立于浏览器交互发出 API 请求。例如,获取身份验证凭据或令牌以服务于基于浏览器的测试。有关更多信息,请参阅发出 API 请求

添加步骤编辑

旅程由一个或多个步骤组成。步骤是应按特定顺序完成的操作。步骤在 Synthetics 应用程序中单独显示,并附带屏幕截图,以便于调试和错误跟踪。

一个基本的包含两个步骤的旅程如下所示

journey('Journey name', ({ page, browser, client, params, request }) => {
    step('Step 1 name', () => {
      // Do something here
    });
    step('Step 2 name', () => {
      // Do something else here
    });
});

步骤可以根据您的需要简单或复杂。例如,一个基本的第一步可能是加载网页

step('Load the demo page', () => {
  await page.goto('https://elastic.github.io/synthetics-demo/'); 
});

有关更多信息,请转到 page.goto 参考

参数编辑

name (string)

用户定义的字符串,用于描述旅程。

callback (function)

一个函数,您可以在其中使用 Synthetics 和 Playwright 语法模拟用户工作流程。

如果您想通过直接与网页交互来生成代码,可以使用Synthetics 记录器

记录器会启动一个 Chromium 浏览器,该浏览器会监听您与网页的每次交互,并使用 Playwright 在内部记录它们。当您完成与浏览器的交互后,记录器会将记录的操作转换为 JavaScript 代码,您可以将该代码与 Elastic Synthetics 或 Heartbeat 一起使用。

有关 Synthetics 记录器入门的更多详细信息,请参阅使用 Synthetics 记录器

Playwright 语法编辑

在每个步骤的回调函数中,您可能会使用很多 Playwright 语法。使用 Playwright 模拟和验证用户工作流程,包括

有关信息,请访问 Playwright 文档

在通过 Elastic 的全球托管测试基础设施或私有位置运行时,请勿尝试在有头模式下运行(使用 headless:false),因为不支持此功能。

但是,并非所有 Playwright 功能都应与 Elastic Synthetics 一起使用。在某些情况下,Elastic Synthetics 库中内置了 Playwright 功能的替代方案。这些替代方案旨在更好地用于合成监控。请使用 Playwright 语法来

  • 发出 API 请求。 请改用 Elastic Synthetic 的 request 参数。在发出 API 请求中了解更多信息。

还有一些 Playwright 功能在 Elastic Synthetics 中默认不受支持,包括

通过 screenshotvideo 以编程方式完成的捕获不会被存储,也不会显示在 Synthetics 应用程序中。提供 path 可能会导致监视器因缺少写入本地文件的权限而失败。

进行断言编辑

更复杂的 step 可能会等待页面元素被选中,然后确保它与预期值匹配。

Elastic Synthetics 使用 @playwright/testexpect 函数进行断言,并支持大多数 Playwright 断言。Elastic Synthetics 支持 toHaveScreenshot 或任何 快照断言

例如,在使用以下 HTML 的页面上

<header class="header">
  <h1>todos</h1>
  <input class="new-todo"
    autofocus autocomplete="off"
    placeholder="What needs to be done?">
</header>

您可以使用以下测试来验证类为 new-todoinput 元素是否具有预期的 placeholder 值(input 元素的提示文本)

step('Assert placeholder text', async () => {
  const input = await page.locator('input.new-todo'); 
  expect(await input.getAttribute('placeholder')).toBe(
    'What needs to be done?'
  ); 
});

找到类为 new-todoinput 元素。

使用 Synthetics 代理提供的断言库来检查 placeholder 属性的值是否与特定字符串匹配。

发出 API 请求编辑

您可以使用 request 参数独立于浏览器交互发出 API 请求。例如,您可以从 HTTP 端点检索令牌,并在后续网页请求中使用它。

step('make an API request', async () => {
  const response = await request.get(params.url);
  // Do something with the response
})

Elastic Synthetics request 参数类似于Playwright 公开的其他请求对象,但有一些关键区别

  • Elastic Synthetics request 参数内置于库中,因此无需单独导入,这减少了所需的代码量,并允许您在内联旅程中发出 API 请求。
  • 与 Playwright 的 context.requestpage.request(与相应的BrowserContext共享 Cookie 存储)不同,Elastic Synthetics 公开的顶级 request 对象具有其自己的隔离 Cookie 存储。
  • 如果您想控制 request 对象的创建,可以通过--playwright-options或在synthetics.config.ts 文件中传递选项来实现。

有关显示如何使用 request 对象的完整示例,请参阅Elastic Synthetics 演示存储库

request 参数并非用于编写纯 API 测试。相反,它是一种支持在基于浏览器的测试中编写普通 HTTP 请求的方法。

设置和删除全局状态编辑

如果在旅程之前或之后有任何操作需要执行,可以使用 beforebeforeAllafterafterAll

例如,要设置将用于单个 journey 的全局状态或服务器,请使用 before 钩子。要在所有旅程之前执行一次此设置,请使用 beforeAll 钩子。

before(({ params }) => {
  // Actions to take
});

beforeAll(({ params }) => {
  // Actions to take
});

您可以使用 after 钩子清理用于单个 journey 的全局状态或关闭服务器。要在所有旅程之后执行一次此清理,请使用 afterAll 钩子。

after(({ params }) => {
  // Actions to take
});

afterAll(({ params }) => {
  // Actions to take
});

导入 NPM 包编辑

您可以在旅程代码中导入和使用其他 NPM 包。请参阅以下使用外部 NPM 包 is-positive 的示例

import { journey, step, monitor, expect } from '@elastic/synthetics';
import isPositive from 'is-positive';

journey('bundle test', ({ page, params }) => {
  step('check if positive', () => {
    expect(isPositive(4)).toBe(true);
  });
});

当您从使用外部 NPM 包的旅程创建监视器时,在调用 push 命令时,这些包将与旅程代码一起捆绑。

但是,使用外部包时存在一些限制

  • 压缩后的捆绑旅程不应超过 800 KB。
  • 由于平台不一致,原生节点模块将无法按预期工作。

示例合成测试编辑

一个完整的基本合成测试示例可能如下所示

import { journey, step, expect } from '@elastic/synthetics';

journey('Ensure placeholder is correct', ({ page }) => {
  step('Load the demo page', async () => {
    await page.goto('https://elastic.github.io/synthetics-demo/');
  });
  step('Assert placeholder text', async () => {
    const placeholderValue = await page.getAttribute(
      'input.new-todo',
      'placeholder'
    );
    expect(placeholderValue).toBe('What needs to be done?');
  });
});

您可以在Elastic Synthetics 演示存储库中找到更复杂的示例。

本地测试编辑

在编写旅程时,您可以在本地运行它们以验证它们是否按预期工作。然后,您可以创建监视器以定期运行您的旅程。

要测试项目中的所有旅程,请导航到包含 Synthetics 项目的目录并在其中运行旅程。默认情况下,@elastic/synthetics 运行器将仅运行与文件名 *.journey.(ts|js)* 匹配的文件。

# Run tests on the current directory. The dot `.` indicates
# that it should run all tests in the current directory.
npx @elastic/synthetics .
测试内联监视器编辑

要在本地测试内联监视器的旅程,请将内联旅程通过管道传递到 npx @elastic/synthetics 命令。

例如,假设您的内联监视器包含以下代码

step('load homepage', async () => {
    await page.goto('https://elastic.ac.cn');
});
step('hover over products menu', async () => {
    await page.hover('css=[data-nav-item=products]');
});

要在本地运行该旅程,您可以将该代码保存到文件中,并将文件的内容通过管道传递到 @elastic-synthetics

cat path/to/sample.js | npx @elastic/synthetics --inline

您将收到如下响应

Journey: inline
   ✓  Step: 'load homepage' succeeded (1831 ms)
   ✓  Step: 'hover over products menu' succeeded (97 ms)

 2 passed (2511 ms)