编写合成测试
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
和一个 callback
。 name
帮助您识别单个 journey。 callback
参数是一个封装 journey 所执行的操作的函数。 该 callback 提供对新的 Playwright page
、params
、browser
和 context
实例的访问。
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
使用不同的主页(dev
为localhost
,prod
为 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/');
});
- 有关更多信息,请转到
page.goto
参考。
name (字符串) |
用于描述 journey 的用户定义的字符串。 |
callback (函数) |
您可以使用 Synthetics 和 Playwright 语法模拟用户工作流的函数。 |
如果您想通过直接与网页交互来生成代码,您可以使用Synthetics 录制器。
录制器会启动一个 Chromium 浏览器,该浏览器将侦听您与网页的每次交互,并使用 Playwright 在内部记录它们。 完成与浏览器的交互后,录制器会将记录的操作转换为 JavaScript 代码,您可以使用该代码进行 Elastic Synthetics 或 Heartbeat。
有关开始使用 Synthetics 录制器的更多详细信息,请参阅使用 Synthetics 录制器。
在每个步骤的回调中,您可能会使用大量的 Playwright 语法。 使用 Playwright 来模拟和验证用户工作流程,包括
- 与 浏览器或当前 页面交互(如上面的示例中所示)。
- 使用 定位器在网页上查找元素。
- 模拟 鼠标、触摸或 键盘事件。
- 使用
@playwright/test
的expect
函数进行断言。 在进行断言中阅读更多信息。
有关信息,请访问 Playwright 文档。
通过 Elastic 的全球托管测试基础设施或私有位置运行时,请勿尝试以 headful 模式运行(使用 headless:false
),因为不支持此模式。
但是,并非所有 Playwright 功能都应与 Elastic Synthetics 一起使用。 在某些情况下,Elastic Synthetics 库中内置了 Playwright 功能的替代方案。 这些替代方案旨在更好地用于合成监视。 *请勿*使用 Playwright 语法来
- 发出 API 请求。请改用 Elastic Synthetic 的
request
参数。 在发出 API 请求中阅读更多信息。
Elastic Synthetics 也不支持某些 Playwright 功能,包括
通过 screenshot
或 video
以编程方式完成的捕获不会被存储,也不会显示在 Synthetics 应用程序中。 提供 path
可能会由于缺少写入本地文件的权限而导致监视器失败。
更复杂的 step
可能会等待页面元素被选中,然后确保它与预期值匹配。
Elastic Synthetics 使用 @playwright/test
的 expect
函数进行断言,并支持大多数 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-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?'
);
});
- 找到类为
new-todo
的input
元素。 - 使用 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.request
和page.request
不同,后者与相应的BrowserContext
共享 cookie 存储。 - 如果您想控制
request
对象的创建,可以通过--playwright-options
或synthetics.config.ts
文件传递选项来实现。
有关显示如何使用 request
对象的完整示例,请参阅 Elastic Synthetics 演示存储库。
request
参数不适合用于编写纯 API 测试。相反,它是一种支持在基于浏览器的测试中编写纯 HTTP 请求的方法。
如果在旅程之前或之后应该执行任何操作,您可以使用 before
、beforeAll
、after
或 afterAll
。
要设置将用于**单个** 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)