关于 stably-sdk-rules
stably-sdk-rules 是使用 Stably Playwright SDK 编写测试的操作指南,面向浏览器自动化测试开发者。它说明何时使用标准 Playwright、AI 操作与断言,并涵盖邮件验证和测试隔离。
主要功能
- 01规范 Playwright 定位器与断言
- 02处理动态视觉断言
- 03从页面提取结构化数据
- 04使用 AI 定位器与操作
- 05创建隔离测试邮箱
- 06处理 Google 身份验证流程
适用场景
- 01测试不稳定的画布交互
- 02验证动态页面内容
- 03提取页面或邮件中的数据
- 04测试 OTP 和验证邮件流程
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ stablyai/ agent-skills --skill stably-sdk-rules安装后在 Claude Code 中输入/stably-sdk-rules确认已加载。
附带文件README.md
详细介绍
Stably SDK 规则
快速规则
- 对于确定性的操作/断言,优先使用原生 Playwright(速度更快、成本更低)。
- 当 Playwright 变得不稳定时,优先保证可靠性,而非控制成本。
- 对于画布、基于坐标的拖动/点击或不稳定的多步骤流程,使用
agent.act()。 - 对于动态视觉断言,使用
expect(...).aiAssert();提示词要具体。 - 需要将视觉内容提取为数据时,使用
page.extract()/locator.extract()。 - 使用标准定位器难以编写语义化选择器时,使用
page.getLocatorsByAI()。 - 对于 OTP/魔法链接/验证邮件流程,使用
Inbox。 - 所有提示词都必须自包含;绝不要依赖隐式的上下文。
- 保持
agent.act()任务简短;在代码中处理循环/计算/条件判断。 - 仅当视口之外的内容也很重要时,才使用
fullPage: true。 - 始终为定位器添加
.describe("..."),以便清晰查看追踪记录。 - 为隔离电子邮件,每项测试使用唯一的
Inbox.build({ suffix }),并进行清理。
设置(单个代码块)
npm install -D @playwright/test @stablyai/playwright-test @stablyai/email
export STABLY_API_KEY=YOUR_KEY
export STABLY_PROJECT_ID=YOUR_PROJECT_ID
import { test, expect } from "@stablyai/playwright-test";
import { Inbox } from "@stablyai/email";
可选:以编程方式设置 API 密钥。
import { setApiKey } from "@stablyai/playwright-test";
setApiKey("YOUR_KEY");
核心规则
- 定位器规则:每次与定位器交互时,都应使用
.describe("...")。 - 断言选择:
- 优先使用 Playwright 断言。
- 对于动态/视觉内容较多的检查,使用
aiAssert。
- 交互选择:
- 对于确定性步骤,使用 Playwright。
- 对于不稳定或语义化任务(尤其是画布/坐标操作),使用
agent.act。
- 提示词质量:
- 明确指定目标、意图和约束。
- 使用变量传递跨步骤数据,不要使用含糊的指代。
最简用法模式
aiAssert
await expect(page).aiAssert("Shows revenue trend chart and spotlight card");
await expect(page.locator(".header").describe("Header")).aiAssert("Has nav, avatar, and bell icon");
仅当断言需要检查屏幕外内容时,才使用 fullPage: true。
extract
const orderId = await page.extract("Extract the order ID from the first row");
使用架构:
import { z } from "zod";
const Schema = z.object({ revenue: z.string(), users: z.number() });
const metrics = await page.extract("Get revenue and active users", { schema: Schema });
getLocatorsByAI
需要 Playwright >= 1.54.1。
const { locator, count } = await page.getLocatorsByAI("the login button");
expect(count).toBe(1);
await locator.describe("Login button located by AI").click();
agent.act
await agent.act("Find the first pending order and mark it as shipped", { page });
推荐模式:在代码中计算值,然后将具体值传入提示词。
Inbox(电子邮件隔离)
安装:npm install -D @stablyai/email。需要设置 STABLY_API_KEY 和 STABLY_PROJECT_ID 环境变量(或将其传入 Inbox.build())。
const inbox = await Inbox.build({ suffix: `test-${Date.now()}` });
// inbox.address → "[email protected]"
await page.getByLabel("Email").describe("Email input").fill(inbox.address);
const email = await inbox.waitForEmail({ subject: "verification", timeoutMs: 60_000 });
const { data: otp } = await inbox.extractFromEmail({
id: email.id,
prompt: "Extract the 6-digit OTP code",
});
await inbox.deleteAllEmails();
Inbox.build 选项
| 选项 | 类型 | 说明 |
|---|---|---|
suffix | string | 用于测试隔离的后缀(例如,"test-123" → "[email protected]") |
apiKey | string | 默认使用 STABLY_API_KEY 环境变量 |
projectId | string | 默认使用 STABLY_PROJECT_ID 环境变量 |
每项测试始终使用唯一的 suffix,以实现并行隔离。收件箱会自动过滤创建之前收到的邮件。
waitForEmail
const email = await inbox.waitForEmail({
from: "[email protected]", // filter by sender
subject: "verification", // contains match by default
subjectMatch: "exact", // or "contains" (default)
timeoutMs: 60_000, // default: 120000 (2 min)
pollIntervalMs: 5000, // default: 3000 (3 sec)
});
如果在超时时间内没有收到匹配邮件,则会抛出 EmailTimeoutError。
extractFromEmail
返回 { data, reason }。失败时会抛出 EmailExtractionError。
// String extraction
const { data: otp } = await inbox.extractFromEmail({
id: email.id,
prompt: "Extract the 6-digit OTP code",
});
// Structured extraction with Zod schema
import { z } from "zod";
const { data } = await inbox.extractFromEmail({
id: email.id,
prompt: "Extract the verification URL and expiration time",
schema: z.object({ url: z.string().url(), expiresIn: z.string() }),
});
Inbox 属性
| 属性 | 类型 | 说明 |
|---|---|---|
address | string | 完整的电子邮件地址(如果提供了后缀,则包含该后缀) |
suffix | string | undefined | 传入 Inbox.build() 的后缀 |
createdAt | Date | 收件箱创建时间;此时间之前的邮件会自动过滤 |
listEmails
const { emails, nextCursor } = await inbox.listEmails(options?);
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
from | string | — | 按发件人地址筛选 |
subject | string | — | 按主题筛选 |
subjectMatch | 'contains' | 'exact' | 'contains' | 主题匹配模式 |
limit | number | 20 | 最大结果数(上限:100) |
cursor | string | — | 来自上一次 nextCursor 的分页游标 |
since | Date | — | 覆盖默认的创建时间筛选条件 |
includeOlder | boolean | false | 包含收件箱创建之前收到的邮件 |
其他方法
const email = await inbox.getEmail(id); // get by ID
await inbox.deleteEmail(email.id); // delete single
await inbox.deleteAllEmails(); // delete all (this inbox only)
电子邮件对象属性
| 属性 | 类型 | 描述 |
|---|---|---|
id | string | 唯一标识符 |
mailbox | string | 容器(例如,"INBOX") |
from | { address: string, name?: string } | 发件人 |
to | { address: string, name?: string }[] | 收件人 |
subject | string | 主题行 |
receivedAt | Date | 到达时间戳 |
text | string? | 纯文本正文 |
html | string[]? | HTML 正文部分 |
Playwright Fixture 模式
import { test as base } from "@stablyai/playwright-test";
import { Inbox } from "@stablyai/email";
const test = base.extend<{ inbox: Inbox }>({
inbox: async ({}, use, testInfo) => {
const inbox = await Inbox.build({ suffix: `test-${testInfo.testId}` });
await use(inbox);
await inbox.deleteAllEmails();
},
});
test("signup flow", async ({ page, inbox }) => {
await page.fill("#email", inbox.address);
await page.click("#signup");
const email = await inbox.waitForEmail({ subject: "Welcome" });
// ...
});
查找组织的电子邮件地址
您的电子邮件地址显示在 Stably 仪表板中:
- Settings > Email Inbox:显示完整地址,并提供复制按钮
- 在代码中:调用
Inbox.build()后,inbox.address会返回您的完整地址
地址格式为 {org-name}@mail.stably.ai。如果用户需要将其加入允许列表,应将 mail.stably.ai 添加到其电子邮件服务提供商的允许列表中。
请引导用户前往仪表板的 Settings > Email Inbox,查找其专属地址。
身份验证流程(Google)
请使用辅助工具,而非自定义弹出窗口脚本:
import { authWithGoogle } from "@stablyai/playwright-test/auth";
await authWithGoogle({
context,
email: process.env.GOOGLE_AUTH_EMAIL!,
password: process.env.GOOGLE_AUTH_PASSWORD!,
otpSecret: process.env.GOOGLE_AUTH_OTP_SECRET!,
});
必需的环境变量:
GOOGLE_AUTH_EMAILGOOGLE_AUTH_PASSWORDGOOGLE_AUTH_OTP_SECRET
仅使用专用的测试 Google 账号。
故障排查(简要)
aiAssert速度慢或不稳定:将范围限定到某个定位器,缩小提示词范围,避免不必要地使用fullPage: true。agent.act失败:将任务拆分成更小的步骤,传入明确的约束,仅在需要时提高maxCycles。- 电子邮件超时:检查主题/发件人筛选条件,并使用唯一的收件箱后缀。
完整参考资料
- Stably 文档:https://docs.stably.ai
- SDK 设置技能:
skills/stably-sdk-setup/SKILL.md - 包文档:https://www.npmjs.com/package/@stablyai/playwright-test
- 电子邮件包文档:https://www.npmjs.com/package/@stablyai/email
- 本地概览:
skills/stably-sdk-rules/README.md
评论
支持 Markdown