mcpField
S
stably-sdk-rules

stably-sdk-rules

github.com/stablyai测试与质量2465 次安装28 周前更新
代码仓库

关于 stably-sdk-rules

stably-sdk-rules 是使用 Stably Playwright SDK 编写测试的操作指南,面向浏览器自动化测试开发者。它说明何时使用标准 Playwright、AI 操作与断言,并涵盖邮件验证和测试隔离。

主要功能

  1. 01规范 Playwright 定位器与断言
  2. 02处理动态视觉断言
  3. 03从页面提取结构化数据
  4. 04使用 AI 定位器与操作
  5. 05创建隔离测试邮箱
  6. 06处理 Google 身份验证流程

适用场景

  1. 01测试不稳定的画布交互
  2. 02验证动态页面内容
  3. 03提取页面或邮件中的数据
  4. 04测试 OTP 和验证邮件流程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/stablyai/agent-skills --skill stably-sdk-rules

安装后在 Claude Code 中输入/stably-sdk-rules确认已加载。

附带文件README.md

详细介绍

Stably SDK 规则

快速规则

  1. 对于确定性的操作/断言,优先使用原生 Playwright(速度更快、成本更低)。
  2. 当 Playwright 变得不稳定时,优先保证可靠性,而非控制成本。
  3. 对于画布、基于坐标的拖动/点击或不稳定的多步骤流程,使用 agent.act()。
  4. 对于动态视觉断言,使用 expect(...).aiAssert();提示词要具体。
  5. 需要将视觉内容提取为数据时,使用 page.extract() / locator.extract()。
  6. 使用标准定位器难以编写语义化选择器时,使用 page.getLocatorsByAI()。
  7. 对于 OTP/魔法链接/验证邮件流程,使用 Inbox。
  8. 所有提示词都必须自包含;绝不要依赖隐式的上下文。
  9. 保持 agent.act() 任务简短;在代码中处理循环/计算/条件判断。
  10. 仅当视口之外的内容也很重要时,才使用 fullPage: true。
  11. 始终为定位器添加 .describe("..."),以便清晰查看追踪记录。
  12. 为隔离电子邮件,每项测试使用唯一的 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 选项
选项类型说明
suffixstring用于测试隔离的后缀(例如,"test-123" → "[email protected]")
apiKeystring默认使用 STABLY_API_KEY 环境变量
projectIdstring默认使用 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 属性
属性类型说明
addressstring完整的电子邮件地址(如果提供了后缀,则包含该后缀)
suffixstring | undefined传入 Inbox.build() 的后缀
createdAtDate收件箱创建时间;此时间之前的邮件会自动过滤
listEmails
const { emails, nextCursor } = await inbox.listEmails(options?);
选项类型默认值说明
fromstring—按发件人地址筛选
subjectstring—按主题筛选
subjectMatch'contains' | 'exact''contains'主题匹配模式
limitnumber20最大结果数(上限:100)
cursorstring—来自上一次 nextCursor 的分页游标
sinceDate—覆盖默认的创建时间筛选条件
includeOlderbooleanfalse包含收件箱创建之前收到的邮件
其他方法
const email = await inbox.getEmail(id);                          // get by ID
await inbox.deleteEmail(email.id);                               // delete single
await inbox.deleteAllEmails();                                   // delete all (this inbox only)
电子邮件对象属性
属性类型描述
idstring唯一标识符
mailboxstring容器(例如,"INBOX")
from{ address: string, name?: string }发件人
to{ address: string, name?: string }[]收件人
subjectstring主题行
receivedAtDate到达时间戳
textstring?纯文本正文
htmlstring[]?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_EMAIL
  • GOOGLE_AUTH_PASSWORD
  • GOOGLE_AUTH_OTP_SECRET

仅使用专用的测试 Google 账号。

故障排查(简要)

  • aiAssert 速度慢或不稳定:将范围限定到某个定位器,缩小提示词范围,避免不必要地使用 fullPage: true。
  • agent.act 失败:将任务拆分成更小的步骤,传入明确的约束,仅在需要时提高 maxCycles。
  • 电子邮件超时:检查主题/发件人筛选条件,并使用唯一的收件箱后缀。

完整参考资料

评论

支持 Markdown