# Selenium Skill

> 生成生产级 Selenium WebDriver 自动化脚本和测试，支持 Java、Python、JavaScript、C#、Ruby 或 PHP。支持本地执行和 TestMu AI 云端（3000+ 浏览器/操作系统组合）。当用户要求编写 Selenium 测试、使用 WebDriver 自动化、运行...

- Skill: `kscz0000/selenium-skill` (Agent Skill)
- Install (CLI): `npx skillmds@latest add kscz0000/selenium-skill`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kscz0000/selenium-skill/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: kscz0000 (https://skillmd.com/u/kscz0000)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/kscz0000/selenium-skill

---


# Selenium Automation Skill
## 何时使用

当需要生成生产级 Selenium WebDriver 自动化脚本和测试时使用此技能，支持 Java、Python、JavaScript、C#、Ruby 或 PHP。支持本地执行和 TestMu AI 云端（3000+ 浏览器/操作系统组合）。当用户要求编写 Selenium 测试、使用 WebDriver 自动化、运行...


你是一名资深 QA 自动化架构师。你编写可在本地或 TestMu AI 云端运行的生产级 Selenium WebDriver 脚本和测试。

## 步骤 1 — 执行目标

```
User says "automate" / "test my site"
│
├─ Mentions "cloud", "TestMu", "LambdaTest", "Grid", "cross-browser", "real device"?
│  └─ TestMu AI cloud (RemoteWebDriver)
│
├─ Mentions specific combos (Safari on Windows, old browsers)?
│  └─ Suggest TestMu AI cloud
│
├─ Mentions "locally", "my machine", "ChromeDriver"?
│  └─ Local execution
│
└─ Ambiguous? → Default local, mention cloud for broader coverage
```

## 步骤 2 — 语言检测

| 信号 | 语言 | 配置 |
|--------|----------|--------|
| 默认 / 无信号 | Java | Maven + JUnit 5 |
| "Python"、"pytest"、".py" | Python | pip + pytest |
| "JavaScript"、"Node"、".js" | JavaScript | npm + Mocha/Jest |
| "C#"、".NET"、"NUnit" | C# | NuGet + NUnit |
| "Ruby"、".rb"、"RSpec" | Ruby | gem + RSpec |
| "PHP"、"Codeception" | PHP | Composer + PHPUnit |

对于非 Java 语言 → 读取 `reference/<language>-patterns.md`

## 步骤 3 — 范围

| 请求类型 | 操作 |
|-------------|--------|
| "为 X 编写测试" | 单个测试文件，内联设置 |
| "搭建 Selenium 项目" | 包含 POM、配置、基类的完整项目 |
| "修复/调试测试" | 读取 `reference/debugging-common-issues.md` |
| "在云端运行" | 读取 `reference/cloud-integration.md` |

## 核心模式 — Java（默认）

### 定位器优先级

```
1. By.id("element-id")           ← 最稳定
2. By.name("field-name")         ← 表单元素
3. By.cssSelector(".class")      ← 快速、可读
4. By.xpath("//div[@data-testid]") ← 最后手段
```

**绝不使用：** 脆弱的 XPath，如 `//div[3]/span[2]/a`、绝对路径。

### 等待策略 — 关键

```java
// ✅ ALWAYS use explicit waits
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("submit")));

// ❌ NEVER use Thread.sleep() or implicit waits mixed with explicit
Thread.sleep(3000); // FORBIDDEN
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); // Don't mix
```

### 反模式

| 错误做法 | 正确做法 | 原因 |
|-----|------|-----|
| `Thread.sleep(5000)` | 显式 `WebDriverWait` | 不稳定、缓慢 |
| 隐式 + 显式等待混用 | 仅使用显式等待 | 超时不可预测 |
| 不加等待直接 `driver.findElement()` | 先等待再查找 | NoSuchElementException |
| 绝对 XPath | 相对 CSS/ID | DOM 变更即失效 |
| 没有 `driver.quit()` | 始终在 finally/teardown 中 `quit()` | 浏览器泄漏 |

### 基本测试结构

```java
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.junit.jupiter.api.*;
import java.time.Duration;

public class LoginTest {
    private WebDriver driver;
    private WebDriverWait wait;

    @BeforeEach
    void setUp() {
        driver = new ChromeDriver();
        wait = new WebDriverWait(driver, Duration.ofSeconds(10));
        driver.manage().window().maximize();
    }

    @Test
    void testLogin() {
        driver.get("https://example.com/login");
        wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("username")))
            .sendKeys("user@test.com");
        driver.findElement(By.id("password")).sendKeys("password123");
        driver.findElement(By.cssSelector("button[type='submit']")).click();
        wait.until(ExpectedConditions.urlContains("/dashboard"));
        Assertions.assertTrue(driver.getTitle().contains("Dashboard"));
    }

    @AfterEach
    void tearDown() {
        if (driver != null) driver.quit();
    }
}
```

### Page Object Model — 快速示例

```java
// pages/LoginPage.java
public class LoginPage {
    private WebDriver driver;
    private WebDriverWait wait;

    private By usernameField = By.id("username");
    private By passwordField = By.id("password");
    private By submitButton  = By.cssSelector("button[type='submit']");

    public LoginPage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    public void login(String username, String password) {
        wait.until(ExpectedConditions.visibilityOfElementLocated(usernameField))
            .sendKeys(username);
        driver.findElement(passwordField).sendKeys(password);
        driver.findElement(submitButton).click();
    }
}
```

### TestMu AI 云端 — 快速配置

```java
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.net.URL;
import java.util.HashMap;

String username = System.getenv("LT_USERNAME");
String accessKey = System.getenv("LT_ACCESS_KEY");
String hub = "https://" + username + ":" + accessKey + "@hub.lambdatest.com/wd/hub";

DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("browserName", "Chrome");
caps.setCapability("browserVersion", "latest");
HashMap<String, Object> ltOptions = new HashMap<>();
ltOptions.put("platform", "Windows 11");
ltOptions.put("build", "Selenium Build");
ltOptions.put("name", "My Test");
ltOptions.put("video", true);
ltOptions.put("network", true);
caps.setCapability("LT:Options", ltOptions);

WebDriver driver = new RemoteWebDriver(new URL(hub), caps);
```

### 测试状态上报

```java
// After test — report to TestMu AI dashboard
((JavascriptExecutor) driver).executeScript(
    "lambda-status=" + (testPassed ? "passed" : "failed")
);
```

## 验证工作流

1. **定位器**：无绝对 XPath，优先使用 ID/CSS
2. **等待**：仅使用显式 WebDriverWait，零 Thread.sleep()
3. **清理**：在 @AfterEach/teardown 中调用 driver.quit()
4. **云端**：LT_USERNAME + LT_ACCESS_KEY 从环境变量获取
5. **POM**：定位器放在页面对象类中，断言放在测试类中

## 快速参考

| 任务 | 命令/代码 |
|------|-------------|
| Maven 运行 | `mvn test` |
| 运行单个测试 | `mvn test -Dtest=LoginTest` |
| Gradle 运行 | `./gradlew test` |
| 并行（TestNG） | `<suite parallel="tests" thread-count="5">` |
| 截图 | `((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE)` |
| Actions API | `new Actions(driver).moveToElement(el).click().perform()` |
| 下拉选择 | `new Select(driver.findElement(By.id("dropdown"))).selectByValue("1")` |
| 处理弹窗 | `driver.switchTo().alert().accept()` |
| 切换 iframe | `driver.switchTo().frame("frameName")` |
| 新标签页/窗口 | `driver.switchTo().newWindow(WindowType.TAB)` |

## 参考文件

| 文件 | 何时读取 |
|------|-------------|
| `reference/cloud-integration.md` | 云端/Grid 配置、并行、capabilities |
| `reference/page-object-model.md` | 完整 POM 及基类、工厂 |
| `reference/python-patterns.md` | Python + pytest-selenium |
| `reference/javascript-patterns.md` | Node.js + Mocha/Jest |
| `reference/csharp-patterns.md` | C# + NUnit/xUnit |
| `reference/ruby-patterns.md` | Ruby + RSpec/Capybara |
| `reference/php-patterns.md` | PHP + Composer + PHPUnit |
| `reference/debugging-common-issues.md` | 旧元素、超时、不稳定测试 |

## 高级手册

生产级模式请参见 `reference/playbook.md`：

| 章节 | 内容 |
|---------|--------------|
| §1 DriverFactory | 线程安全、多浏览器、本地 + 远程、无头 CI |
| §2 配置管理 | 属性文件、环境变量覆盖、多环境支持 |
| §3 生产级 BasePage | 20+ 辅助方法、Shadow DOM、iframe、弹窗、Angular/jQuery 等待 |
| §4 页面对象示例 | 完整 LoginPage 继承 BasePage，流畅 API |
| §5 智能等待 | FluentWait、旧元素重试、稳定列表等待、自定义条件 |
| §6 数据驱动 | CSV、MethodSource、Excel DataProvider（Apache POI） |
| §7 截图 | JUnit 5 Extension + TestNG Listener 及 Allure 附件 |
| §8 Allure 报告 | Epic/Feature/Story 注解、步骤化报告 |
| §9 CI/CD | GitHub Actions 矩阵 + GitLab CI 及 Selenium 服务 |
| §10 并行 | TestNG XML + JUnit 5 并行属性 |
| §11 高级交互 | 文件下载、多窗口、网络日志 |
| §12 重试机制 | TestNG IRetryAnalyzer 处理不稳定测试 |
| §13 调试表 | 11 个常见异常的原因与修复 |
| §14 最佳实践 | 17 项生产级检查清单 |

## 限制

- 仅当任务明确匹配其上游来源和本地项目上下文时使用此技能。
- 在应用更改前，请验证命令、生成的代码、依赖项、凭证和外部服务行为。
- 不要将示例替代环境特定的测试、安全审查，或用户对破坏性/高成本操作的审批。

