在进行如下的阅读之前,我假设你已经阅读了如下的文章:
-
Observability:Synthetic monitoring - 合成监测入门(一)
-
Observability:Synthetic monitoring - 合成监测入门(二)
你已经知道如何部署 Elastic Stack,并安装 Fleet server 及 Elastic Agent 来进行监控。
创建浏览器监测器
浏览器监测器是一种综合监测器。 合成监测扩展了传统的端到端测试技术,因为它允许你的测试在云上持续运行。 通过合成监测,你可以通过重复使用用于在计算机上验证软件的相同旅程来断言你的应用程序在部署后继续工作。
你可以使用合成监视器来检测由你无法预测且未编写测试的无效状态引起的错误。 合成监测器还可以让你定期模拟用户的操作,从而帮助你捕获流量不大的功能中的错误。
首先学习综合监测的基础知识,包括如何:
- 编写合成测试
- 本地测试
- 配置单独的监视器
- 使用参数和 secrets
- 使用合成记录器
编写合成测试
设置项目后,你可以开始编写综合测试来检查最终用户可能在你的站点上发出的关键操作和请求。如果你还不知道如何创建一个项目,请仔细阅读我之前的文章 “Observability:Synthetic monitoring - 合成监测入门(一)”
语法概述
要为你的应用程序编写合成测试,你需要了解基本的 JavaScript 和 Playwright 语法。
提示:Playwright 是微软开发的浏览器测试库。 它快速、可靠,并具有现代 API,可自动等待页面元素准备就绪。
合成代理公开用于创建和运行测试的 API,包括:
名称 | 描述 |
---|---|
journey | 测试一个离散的功能单元。 接受两个参数:name(字符串)和 callback(函数)。 在 Create a journey 中了解更多信息。 |
step | 旅程中应按特定顺序完成的操作。 接受两个参数:name(字符串)和 callback(函数)。 在 Add steps 中了解更多信息。 |
expect | 检查值是否满足特定条件。 有几种受支持的检查。 在 Make assertions 中了解更多信息。 |
beforeAll | 在任何 journey 运行之前运行一次提供的函数。 如果提供的函数是一个 promise,则运行程序将在调用 journery 之前等待 promise 解决。 采用一个参数:callback(函数)。 了解有关设置和删除全局状态的更多信息。 |
before | 在单个 journey 运行之前运行提供的函数。 采用一个参数:callback(函数)。 了解有关设置和删除全局状态的更多信息。 |
afterAll | 在所有 journey 运行完成后,运行提供的函数一次。 采用一个参数:callback(函数)。 了解有关设置和删除全局状态的更多信息。 |
after | 在单次 journey 完成后运行提供的函数。 采用一个参数:callback(函数)。 了解有关设置和删除全局状态的更多信息。 |
monitor | Monitor.use 方法允许你在每个 journey 的基础上确定监测器的配置。 例如,如果你希望两个 journey 以不同的间隔创建监测器,则应该在每个旅程中调用 monitor.use,并将每个旅程的 schedule 属性设置为不同的值。 请注意,这仅在使用 Push 命令在 Kibana 中创建监测器时才相关。 在配置单个监测器中了解更多信息。 |
Create a journey - 创建旅程
使用 .journey.ts 或 .journey.js 文件扩展名创建新文件,或编辑示例 journey 文件之一。
旅程测试一个独立的功能单元。 例如,登录网站、将商品添加到购物车或加入邮件列表。
旅程函数有两个参数:name 和 callback。 该名称可帮助你识别单个旅程。 callback 回调参数是一个封装旅程功能的函数。 该回调提供对新的 Playwright page、params、browser 和 context 实例的访问。
1. journey('Journey name', ({ page, browser, context, params, request }) => {
2. // Add steps here
3. });
参数 | 描述 |
---|---|
name (string) | 用于描述旅程的用户定义的字符串。 |
callback (function) |
你将在其中添加步骤的函数。 参数: page:来自 Playwright 的 page 对象,可让你控制浏览器的当前页面。 browser:由 Playwright 创建的 browser 对象。 context:不与其他浏览器上下文共享 cookie 或缓存的浏 browser contexts。 params:用户定义的变量允许你使用自定义参数调用 Synthetics 套件。 例如,如果你想根据 env 使用不同的主页(dev 为 localhost,prod 为 URL)。 有关更多信息,请参阅使用参数和 secrets。 request:一个请求对象,可用于独立于浏览器交互发出 API 请求。 例如,获取用于基于浏览器的测试的身份验证凭据或令牌。 有关详细信息,请参阅下面的发出 API 请求。 |
Add steps - 添加步骤
旅程由一个或多个步骤组成。 步骤是应按特定顺序完成的操作。 步骤在 Synthetics 应用程序中单独显示,并附有屏幕截图,以便于调试和错误跟踪。
基本的两步旅程如下所示:
1. journey('Journey name', ({ page, browser, client, params, request }) => {
2. step('Step 1 name', () => {
3. // Do something here
4. });
5. step('Step 2 name', () => {
6. // Do something else here
7. });
8. });
步骤可以简单也可以复杂,具体取决于你的需要。 例如,基本的第一步可能会加载网页:
1. step('Load the demo page', () => {
2. await page.goto('https://elastic.github.io/synthetics-demo/');
3. });
访问 page.goto 参考以获取更多信息。
参数 | 描述 |
---|---|
name (string) | 用于描述旅程的用户定义的字符串。 |
callback(function) | 你可以使用 Synthetics 和 Playwright 语法模拟用户工作流程的函数。 |
注意:如果你想通过直接与网页交互来生成代码,你可以使用 Synthetics Recorder。
记录器启动 Chromium 浏览器,该浏览器将监听你与网页的每次交互,并使用 Playwright 在内部记录它们。 当你完成与浏览器的交互后,记录器会将记录的操作转换为可与 Elastic Synthetics 或 Heartbeat 一起使用的 JavaScript 代码。
有关开始使用 Synthetics Recorder 的更多详细信息,请参阅使用 Synthetics Recorder。
Playwright 语法
在每个步骤的回调中,你可能会使用大量 Playwright 语法。 Elastic Synthetics 库支持许多 Playwright 类来模拟用户工作流程,包括以下任务:
- 与 browser 或当前 page 交互(如上例所示)。
- 使用 locators 查找网页上的元素。
- 模拟鼠标、触摸或键盘事件。
请访问 Playwright 文档以获取信息。
但是,并非所有 Playwright 功能都应与 Elastic Synthetics 一起使用。
在某些情况下,Elastic Synthetics 库中内置了 Playwright 功能的替代方案。 这些替代方案旨在更好地进行合成监测。 请勿使用 Playwright 语法来:
- Make assertions。 请改用 Elastic Synthetics 的 Expect 方法。
- Make API requests。 请改用 Elastic Synthetic 的请求参数。
Elastic Synthetics 中还存在一些不支持开箱即用的 Playwright 功能,包括:
- Videos
Make assertions
检查值是否满足特定条件。 更复杂的步骤可能会等待选择页面元素,然后确保它与预期值匹配。
例如,在使用以下 HTML 的页面上:
1.
2. todos
3.
6.
你可以通过以下测试来验证类 new-todo 的输入元素是否具有预期的占位符(placeholder)值(输入元素的提示文本):
1. step('Assert placeholder text', async () => {
2. const input = await page.locator('input.new-todo');
3. expect(await input.getAttribute('placeholder')).toBe(
4. 'What needs to be done?'
5. );
6. });
在上面,我们首先通过 locator 来找到名叫 new-todo 的 input 元素,然后使用 Synthetics 代理提供的 assertion 库来检查占位符属性的值是否与特定字符串匹配。
Supported expect
methods
- not ()
- resolves ()
- rejects ()
- toBe (expected)
- toBeCloseTo (expected, numDigits?)
- toBeDefined ()
- toBeFalsy ()
- toBeGreaterThan (expected)
- toBeGreaterThanOrEqual (expected)
- toBeInstanceOf (expected)
- toBeLessThan (expected)
- toBeLessThanOrEqual (expected)
- toBeNull ()
- toBeTruthy ()
- toBeUndefined ()
- toBeNaN ()
- toContain (expected)
- toContainEqual (expected)
- toEqual (expected)
- toHaveLength (expected)
- toHaveProperty (keyPath, value?)
- toMatch (expected)
- toMatchObject (expected)
- toStrictEqual (expected)
发出 API 请求
你可以使用 request 参数来发出独立于浏览器交互的 API 请求。 例如,你可以从 HTTP 端点检索令牌并在后续网页请求中使用它。
1. step('make an API request', async () => {
2. const response = await request.get(params.url);
3. // Do something with the response
4. })
Elastic Synthetics 请求参数与Playwright 公开的其他请求对象类似,但有一些关键区别:
- Elastic Synthetics 请求参数内置于库中,因此无需单独导入,这减少了所需的代码量,并允许你在内联旅程中发出 API 请求。
- Elastic Synthetics 公开的顶级请求对象有自己独立的 cookie 存储,这与 Playwright 的 context.request 和 page.request 不同,它们与相应的 BrowserContext 共享 cookie 存储。
- 如果你想控制请求对象的创建,可以通过 --playwright-options 或在 Synthetics.config.ts 文件中传递选项来实现。
有关演示如何使用请求对象的完整示例,请参阅 Elastic Synthetics 演示存储库。
注意:request 参数不适合用于编写纯 API 测试。 相反,它是一种支持编写纯 HTTP 请求以服务于基于浏览器的测试的方法。
设置和删除全局状态
如果有任何操作需要在 journey 之前或之后完成,你可以使用 before、beforeAll、after 或 afterAll。
例如,要设置全局状态或将用于单个旅程的服务器,请使用 before 挂钩。 要在所有旅程之前执行一次此设置,请使用 beforeAll 挂钩。
1. before(({ params }) => {
2. // Actions to take
3. });
5. beforeAll(({ params }) => {
6. // Actions to take
7. });
你可以使用 after hook 清理全局状态或关闭用于单个旅程的服务器。 要在所有旅程之后执行一次此清理,请使用 afterAll 挂钩。
1. after(({ params }) => {
2. // Actions to take
3. });
5. afterAll(({ params }) => {
6. // Actions to take
7. });
导入NPM包
你可以在旅程代码中导入和使用其他 NPM 包。 参考下面使用外部 NPM 包 is_positive 的例子:
1. import { journey, step, monitor, expect } from '@elastic/synthetics';
2. import isPositive from 'is-positive';
4. journey('bundle test', ({ page, params }) => {
5. step('check if positive', () => {
6. expect(isPositive(4)).toBe(true);
7. });
8. });
当你从使用外部 NPM 包的旅程创建监测器时,在调用推送命令时,这些包将与旅程代码一起捆绑。
然而,使用外部包时有一些限制:
- 压缩后的捆绑旅程不应超过 800 KB。
- 由于平台不一致,Native 节点模块将无法按预期工作。
合成测试示例
基本综合测试的完整示例可能如下所示:
1. import { journey, step, expect } from '@elastic/synthetics';
3. journey('Ensure placeholder is correct', ({ page }) => {
4. step('Load the demo page', async () => {
5. await page.goto('https://elastic.github.io/synthetics-demo/');
6. });
7. step('Assert placeholder text', async () => {
8. const placeholderValue = await page.getAttribute(
9. 'input.new-todo',
10. 'placeholder'
11. );
12. expect(placeholderValue).toBe('What needs to be done?');
13. });
14. });
你可以在 Elastic Synthetics 演示存储库中找到更复杂的示例。
本地测试
当你编写旅程时,你可以在本地运行它们以验证它们是否按预期工作。 然后,你可以创建监测器来定期运行你的旅程。
要测试项目中的所有旅程,请导航到包含合成项目的目录并在其中运行旅程。 默认情况下,@elastic/synthetics 运行程序将仅运行与文件名 .journey.(ts|js) 匹配的文件。
1. # Run tests on the current directory. The dot `.` indicates
2. # that it should run all tests in the current directory.
3. npx @elastic/synthetics .
测试内联监视器
要在本地测试内联监测器(inline monitor)的旅程,请将内联旅程通过管道传输到 npx @elastic/synthetics 命令。
例如,假设你的内联监测器包含以下代码:
1. step('load homepage', async () => {
2. await page.goto('https://www.elastic.co');
3. });
4. step('hover over products menu', async () => {
5. await page.hover('css=[data-nav-item=products]');
6. });
要在本地运行该旅程,你可以将该代码保存到文件中,并将文件的内容通过管道传输到 @elastic-synthetics:
cat path/to/sample.js | npx @elastic/synthetics --inline
你将收到如下响应:
1. Journey: inline
2. ✓ Step: 'load homepage' succeeded (1831 ms)
3. ✓ Step: 'hover over products menu' succeeded (97 ms)
5. 2 passed (2511 ms)
配置单独的浏览器监视器
注意:这仅与项目监视器相关。 有关配置 Synthetics 应用程序中添加的浏览器监视器的更多信息,请参阅使用 Synthetics 应用程序。
在上面,我们已经了解如何创建合成旅程了。在创建旅程之后,你可以使用 Monitor.use 配置将运行测试的浏览器监测器。
你需要设置一些配置选项:
- 为你的监测器命名。 为监测器提供人类可读的名称和唯一 ID。 这将出现在 Kibana 中,你可以在创建监测器后在其中查看和管理监视器。
- 设定时间表。 指定测试运行的时间间隔。
- 指定监测器应运行的位置。 你可以在 Elastic 的全球托管测试基础设施上运行监视器,也可以创建一个私有位置来从你自己的场所运行监测器。
- 根据需要设置其他选项。 你还可以设置其他几个选项来自定义你的实现,包括参数、标签、屏幕截图选项、限制选项等。
使用 Monitor.use 直接在旅程代码中配置每个监视器。 监视器 API 允许你直接通过代码为每个旅程的监视器设置独特的选项。 例如:
1. import { journey, step, monitor, expect } from '@elastic/synthetics';
3. journey('Ensure placeholder is correct', ({ page, params }) => {
4. monitor.use({
5. id: 'example-monitor',
6. schedule: 10,
7. throttling: {
8. download: 10,
9. upload: 5,
10. latency: 100,
11. },
12. });
13. step('Load the demo page', async () => {
14. await page.goto('https://elastic.github.io/synthetics-demo/');
15. });
16. step('Assert placeholder text', async () => {
17. const placeholderValue = await page.getAttribute(
18. 'input.new-todo',
19. 'placeholder'
20. );
21. expect(placeholderValue).toBe('What needs to be done?');
22. });
23. });
对于每个旅程,你可以指定其时间表和运行地点。 当这些选项没有设置时,Synthetics 将使用全局配置文件中的默认值。
配置合成项目
合成测试支持可在项目中使用的动态参数的配置。 此外,构建在 Playwright 之上的 Synthetics 代理支持配置 Playwright 特定方法中可用的浏览器和上下文选项,例如,ignoreHTTPSErrors、extraHTTPHeaders 和 viewport。
在 Synthesis 项目的根目录中创建 synthetics.config.js 或 synthetics.config.ts 文件并指定选项:
1. import { SyntheticsConfig } from '@elastic/synthetics'
3. const config: SyntheticsConfig = {
4. params: {
5. url: 'https://www.elastic.co'
6. },
7. playwrightOptions: {
8. ignoreHTTPSErrors: true, // ignores all HTTPS errors during navigation
9. extraHTTPHeaders: {
10. 'foo': 'bar' // additional HTTP headers to be sent with every request
11. }
12. },
13. monitor: {
14. schedule: 10,
15. locations: [ 'us-east4-a' ],
16. }
17. }
19. export default config;
配置文件可以导出一个对象,也可以导出一个函数,调用该函数时应返回生成的配置。 要了解有关根据环境配置测试的更多信息,请查看动态配置文档。
**params:**定义测试所需的任何变量的对象。
**playwsrightOption:**有关可用选项,请参阅 Playwright 文档。
注意: Playwright 在 Elastic Synthetics 中使用两种类型的超时:action 超时和 navigation 超时。
Elastic Synthetics 使用 50 秒的默认操作和导航超时。 你可以使用 playwrightOptions 中的 actionTimeout 和 navigationTimeout 覆盖此默认值。
Device emulation
用户可以使用配置文件模拟移动设备。 下面的示例配置在 Pixel 5 模拟模式下运行测试。
1. import { SyntheticsConfig } from "@elastic/synthetics"
2. import { devices } from "playwright-chromium"
4. const config: SyntheticsConfig = {
5. playwrightOptions: {
6. ...
7. devices['Pixel 5']
8. }
9. }
11. export default config;
monitor
使用 @elastic/synthetics Push 命令时应用于所有监测器的默认值。
名称 | 描述 |
---|---|
id (string) | 该监测器的唯一标识符。 |
name (string) | 监测器的人类可读名称。 |
tags (Array ) |
将与监测器事件一起发送的标签列表。 标签显示在 Synthetics 应用程序中,允许你按标签搜索监测器。 |
schedule (number ) |
监测器应运行的时间间隔(以分钟为单位)。 |
enabled (boolean ) |
启用或禁用监测器运行,而无需删除并重新创建它。 |
locations (Array) |
在哪里部署监测器。 监测器可以部署在多个位置,以便你可以检测这些位置之间可用性和响应时间的差异。要列出可用位置,你可以:
|
privateLocations (Array ) |
将部署监测器的私人位置。 这些私有位置是指由你托管和管理的位置,而位置由 Elastic 托管。 你可以使用位置名称指定私有位置。要列出可用的私有位置,你可以:
|
throttling (boolean | ThrottlingOptions) |
控制显示器的下载速度、上传速度和延迟,以模拟应用程序在较慢或较慢的网络上的行为。 设置为 false 以完全禁用限制。 |
screenshot (ScreenshotOptions) |
控制是否捕获屏幕截图。 选项包括 “on”、“off” 或 “only-on-failure”。 |