加载中

编写合成测试

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

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

提示

Playwright 是由微软开发的一个浏览器测试库。它速度快、可靠,并具有现代化的 API,可自动等待页面元素就绪。

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

journey
测试一个独立的功能单元。接受两个参数:一个 name(字符串)和一个 callback(函数)。在创建旅程中了解更多信息。
step
旅程中应按特定顺序完成的操作。接受两个参数:一个 name(字符串)和一个 callback(函数)。在添加步骤中了解更多信息。
expect
检查某个值是否满足特定条件。支持多种检查。在进行断言中了解更多信息。
beforeAll
在任何 journey 运行之前,运行一次提供的函数。如果提供的函数是一个 promise,运行器将等待 promise 解析后再调用 journey。接受一个参数:一个 callback(函数)。在设置和移除全局状态中了解更多信息。
之前
在单个 journey 运行之前运行提供的函数。接受一个参数:一个 callback(函数)。在设置和移除全局状态中了解更多信息。
afterAll
在所有 journey 运行完成后,运行一次提供的函数。接受一个参数:一个 callback(函数)。在设置和移除全局状态中了解更多信息。
之后
在单个 journey 完成后运行提供的函数。接受一个参数:一个 callback(函数)。在设置和移除全局状态中了解更多信息。
监控
monitor.use 方法允许您按旅程逐个确定监视器的配置。例如,如果您希望两个旅程创建具有不同间隔的监视器,则应在每个旅程中调用 monitor.use 并将 schedule 属性设置为不同的值。请注意,这仅在使用 push 命令在 Kibana 或 Observability Serverless 项目中创建监视器时相关。在配置单个监视器中了解更多信息。

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

一个 journey(旅程)测试一个独立的功能单元。例如,登录网站、向购物车添加商品或加入邮件列表。

journey 函数接受两个参数:一个 name 和一个 callbackname 帮助您识别单个旅程。callback 参数是一个封装了旅程操作的函数。该回调提供了对全新 Playwright pageparamsbrowsercontext 实例的访问权限。

journey('Journey name', ({ page, browser, context, params, request }) => {
  // Add steps here
});
		
namestring
用于描述旅程的用户定义字符串。
callbackfunction

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

实例:

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

一个旅程由一个或多个 steps(步骤)组成。步骤是应按特定顺序完成的操作。步骤会连同屏幕截图一起在 Synthetics UI 中单独显示,以便于调试和错误跟踪。

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

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

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

step('Load the demo page', async () => {
  await page.goto('https://elastic.github.io/synthetics-demo/');
});
		
  1. 转到 page.goto 参考文档了解更多信息。
namestring 用于描述旅程的用户定义字符串。
callbackfunction 使用 Synthetics 和 Playwright 语法模拟用户工作流的函数。
注意

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

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

有关开始使用 Synthetics 录制器的更多详细信息,请参阅使用 Synthetics 录制器

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

访问 Playwright 文档获取相关信息。

注意

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

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

  • 发起 API 请求。请改用 Elastic Synthetics 的 request 参数。在发起 API 请求中阅读更多信息。

此外,Elastic Synthetics 中开箱即不支持某些 Playwright 功能,包括

注意

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

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

Elastic Synthetics 使用 @playwright/testexpect 函数来执行断言,并支持大多数 Playwright 断言。Elastic Synthetics 不支持 toHaveScreenshot 或任何快照断言 (Snapshot Assertions)

例如,在包含以下 HTML 的页面上

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

您可以使用以下测试来验证带有 new-todo 类的 input 元素是否具有预期的 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?'
  );
});
		
  1. 查找带有 new-todo 类的 input 元素。
  2. 使用 Synthetics 代理提供的断言库来检查 placeholder 属性的值是否与特定字符串匹配。

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

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

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

  • Elastic Synthetics 的 request 参数内置于库中,因此无需单独导入,这减少了所需的代码量,并允许您在内联旅程 (inline journeys) 中发起 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 包 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。
  • 由于平台不一致,原生 Node 模块将无法按预期工作。

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

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 项目中的所有旅程,请导航到包含 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://esdocs.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)
		
© . This website operates independently and is not affiliated with or endorsed by Elasticsearch B.V. All brand names, logos, and trademarks are the property of their respective owners.