正在加载

编写合成测试

Elastic Stack Serverless

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

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

提示

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

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

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

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

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

journey 函数接受两个参数:一个 name 和一个 callbackname 帮助您识别单个 journey。 callback 参数是一个封装 journey 所执行的操作的函数。 该 callback 提供对新的 Playwright pageparamsbrowsercontext 实例的访问。

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

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

实例:

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

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

一个基本的两步 journey 看起来像这样

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 参考
name字符串 用于描述 journey 的用户定义的字符串。
callback函数 您可以使用 Synthetics 和 Playwright 语法模拟用户工作流的函数。
注意

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

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

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

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

有关信息,请访问 Playwright 文档

注意

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

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

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

Elastic Synthetics 也不支持某些 Playwright 功能,包括

注意

通过 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?'
  );
});
  1. 找到类为 new-todoinput 元素。
  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 参数与 Playwright 公开的其他 request 对象类似,但有一些关键差异。

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

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

注意

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

如果在旅程之前或之后应该执行任何操作,您可以使用 beforebeforeAllafterafterAll

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

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

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

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

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。
  • 由于平台不一致,原生节点模块将无法按预期工作。

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

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://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)
© . All rights reserved.