拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Angular CDK Selenium WebDriver 测试环境完全指南:@angular/cdk/testing/selenium-webdriver 公共 API 深度解析

Angular CDK Selenium WebDriver 测试环境完全指南angular/cdk/testing/selenium-webdriver 公共 API 深度解析【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/componentsangular/cdk/testing/selenium-webdriver是 Angular CDK 组件测试 Harness 体系在 Selenium WebDriver 端到端E2E测试场景下的官方绑定包。本指南以仓库中由 API Extractor 生成的 API 报告goldens/cdk/testing/selenium-webdriver/index.api.md为主线骨架结合该包源码实现与配套 E2E 测试完整解析SeleniumWebDriverElement、SeleniumWebDriverHarnessEnvironment、waitForAngularReady与WebDriverHarnessEnvironmentOptions四个公共 API 的含义、用法与底层原理帮助读者掌握同一套组件 Harness 在 Karma 单元测试与 Selenium E2E 测试中复用的完整方案。一、包定位Harness 环境抽象中的 WebDriver 实现在 Angular CDK 的组件测试体系中angular/cdk/testing定义了环境无关的核心抽象——TestElement接口、HarnessEnvironment抽象类、ComponentHarness基类与HarnessLoader其设计目标在 src/cdk/testing/test-harnesses.md 中阐述得很清楚让同一份 Harness 实现既可用于单元测试也可用于端到端测试用户只需学习一套 API。具体到测试环境CDK 提供了三套官方绑定环境包适用场景核心类angular/cdk/testing/testbedKarma 单元测试基于 TestBed / ComponentFixtureTestbedHarnessEnvironmentangular/cdk/testing/protractor基于 Protractor 的 E2E 测试ProtractorHarnessEnvironmentangular/cdk/testing/selenium-webdriver基于原生 Selenium WebDriver 的 E2E 测试SeleniumWebDriverHarnessEnvironment本文讨论的selenium-webdriver包即第三类。它的公共导出面很小且高度聚焦全部内容在 public-api.ts 中仅两条export *分别指向selenium-web-driver-element与selenium-web-driver-harness-environment最终对外暴露 4 个公共符号正是 API 报告列出的全部内容。从包结构BUILD.bazel可以看出这是一个独立的、仅依赖selenium-webdriver与核心angular/cdk/testing的轻量入口点。二、SeleniumWebDriverElementTestElement 的 WebDriver 实现TestElement接口定义于 src/cdk/testing/test-element.ts是 Harness 与真实 DOM 交互的统一抽象其所有方法均为异步并返回Promise。SeleniumWebDriverElement是它在 Selenium WebDriver 场景下的具体实现构造签名如下constructor(element: () webdriver.WebElement, _stabilize: () Promisevoid)两个参数值得注意element: () webdriver.WebElement一个惰性元素工厂而非元素本身。每次调用都重新获取 WebElement规避了 Selenium 常见的 Stale Element Reference元素引用失效问题——当ngIf等指令销毁并重建 DOM 节点后旧引用会失效而惰性获取保证操作总是命中当前 DOM 状态。_stabilize: () Promisevoid稳定化回调。源码selenium-web-driver-element.ts中几乎所有交互方法click、sendKeys、focus、hover等在执行完动作后都会调用它由SeleniumWebDriverHarnessEnvironment注入forceStabilize确保 Angular 应用完成变更检测与异步任务后再返回。2.1 交互类方法click的三种重载API 报告原文列出click(modifiers?: ModifierKeys): Promisevoid; click(location: center, modifiers?: ModifierKeys): Promisevoid; click(relativeX: number, relativeY: number, modifiers?: ModifierKeys): Promisevoid;无参数点击环境默认位置如需保证点击在特定位置应使用center或坐标形式center点击元素正中心(relativeX, relativeY)点击相对于元素左上角的坐标。从源码_dispatchClickEventSequenceselenium-web-driver-element.ts可以看到底层实现通过 WebDriver 的 Action 序列完成先mouseMove到目标位置省略 offset 参数即默认点击中心再对每个修饰键执行keyDown然后click(button)最后keyUp释放修饰键。rightClick与click共用同一套事件序列逻辑仅按钮不同webdriver.Button.LEFTvswebdriver.Button.RIGHT。sendKeys的两个重载sendKeys(...keys: (string | TestKey)[]): Promisevoid; sendKeys(modifiers: ModifierKeys, ...keys: (string | TestKey)[]): Promisevoid;实现要点selenium-web-driver-element.ts字符串参数会被拆成单字符逐一发送TestKey枚举值经seleniumWebDriverKeyMap映射为webdriver.Key常量详见下文 2.3 节若指定了修饰键则用webdriver.Key.chord(...)组合修饰键与按键——源码注释特别说明这是为了规避 geckodriver 下chord的兼容问题mozilla/geckodriver#1502因此无修饰键时不使用chord未指定任何键会抛出getNoKeysSpecifiedError来自 src/cdk/testing/test-element-errors.ts避免无意义的焦点事件被意外触发。配套测试cross-environment-tests.ts验证了sendKeys()、sendKeys()、sendKeys(, )三种情况均会抛错。其他交互方法方法行为底层实现源码依据focus()/blur()聚焦 / 失焦通过executeScript在浏览器内调用HTMLElement.focus()/blur()见 selenium-web-driver-element.tsclear()清空input/textarea文本直接调用WebElement.clear()hover()/mouseAway()悬停 / 移开鼠标actions().mouseMove(...)mouseAway移动到元素左上角偏移(-1, -1)处同文件selectOptions(...optionIndexes)按索引选择原生select的选项先setInputValue()重置状态再对目标选项按住 CONTROL 键点击以支持多选同文件dispatchEvent(name, data?)派发自定义事件注入浏览器执行一个纯函数被 WebDriver 字符串化后执行document.createEvent(Event)Object.assign(event, data)dispatchEvent同文件setInputValue(value)直接设置 input 的 value 属性通过executeScript在浏览器内赋值element.value valuesetContenteditableValue(value)设置contenteditable元素内容先校验contenteditable属性/true/plaintext-only不满足则抛错随后注入脚本改写textContent同文件2.2 查询类方法方法说明与实现细节text(options?: TextOptions)读取文本。默认不用 WebDriver 的getText而是注入脚本取(element.textContent || ).trim()——源码注释说明原因getText会排除隐藏元素的文本传入exclude选项时可基于_getTextWithExcludedElementssrc/cdk/testing/text-filtering.ts排除指定选择器的内容getAttribute(name)读取属性返回Promisestring \| null经注入脚本调用element.getAttributehasClass(name)读取class属性后按空白符拆分用Set判断是否包含指定类getCssValue(property)计算后的 CSS 属性值直接委托WebElement.getCssValuegetDimensions()尺寸与位置getSize()得width/heightgetLocation()得left/top返回ElementDimensionsgetPropertyT any(name)JS 属性值如 input 的value经注入脚本读取matchesSelector(selector)注入脚本调用Element.prototype.matches兼容msMatchesSelectorisFocused()通过webdriver.WebElement.equals(element, switchTo().activeElement())判断当前焦点元素是否为该元素同文件E2E 测试中一个典型的排除选择器用法来自 webdriver.e2e.spec.tsexpect(await subHarnessHost.text({exclude: h2})).toBe(ProtractorTestBedOther); expect(await subHarnessHost.text({exclude: li})).toBe(List of test tools);2.3 TestKey 到 WebDriver Key 的映射TestElement体系刻意不依赖任何具体测试框架的按键表示而是自定义TestKey枚举见 test-element.ts由各环境的实现类自行映射。SeleniumWebDriverElement的映射表seleniumWebDriverKeyMap完整覆盖了TestKey的 30 个值selenium-webdriver-keys.ts例如TestKey.ENTER → webdriver.Key.ENTER、TestKey.LEFT_ARROW → webdriver.Key.ARROW_LEFT、TestKey.F1~F12 → webdriver.Key.F1~F12、TestKey.COMMA → ,。修饰键则通过getSeleniumWebDriverModifierKeys(modifiers: ModifierKeys)同文件转换ModifierKeys接口的四个布尔字段control/alt/shift/meta各对应一个webdriver.Key常量。API 报告中的sendKeys(modifiers: ModifierKeys, ...)重载正是依赖这一映射。三、SeleniumWebDriverHarnessEnvironment环境入口SeleniumWebDriverHarnessEnvironment extends HarnessEnvironment() webdriver.WebElement实现于 selenium-web-driver-harness-environment.ts其泛型参数E () webdriver.WebElement表示原始元素类型——再次印证了惰性元素工厂的设计环境层传递的永远是能拿到当前 WebElement 的函数。3.1 两个核心静态方法static loader(driver: webdriver.WebDriver, options?: WebDriverHarnessEnvironmentOptions): HarnessLoader static getNativeElement(el: TestElement): webdriver.WebElementloader(driver, options?)创建以**文档根document.body**为根的HarnessLoader。源码实现是new SeleniumWebDriverHarnessEnvironment(() driver.findElement(webdriver.By.css(body)), options)。由于 Selenium 没有 TestBed 那样的 fixture 概念test-harnesses.md明确指出这个 loader 足以加载页面上的所有 Harness无需像TestbedHarnessEnvironment那样区分documentRootLoader与harnessForFixture。getNativeElement(el)把TestElement还原为原生webdriver.WebElement。若传入的TestElement并非本环境创建不是SeleniumWebDriverElement实例会抛出This TestElement was not created by the WebDriverHarnessEnvironment。E2E 测试演示了它的用途webdriver.e2e.spec.tsconst element SeleniumWebDriverHarnessEnvironment.getNativeElement(await harness.host()); expect(await element.getTagName()).toBe(test-main);3.2 WebDriverHarnessEnvironmentOptions 与 queryFnexport interface WebDriverHarnessEnvironmentOptions { queryFn: (selector: string, root: () webdriver.WebElement) Promisewebdriver.WebElement[]; }queryFn是元素查询函数给定 CSS 选择器与根元素返回匹配的 WebElement 数组。默认实现selenium-web-driver-harness-environment.ts为async (selector, root) root().findElements(webdriver.By.css(selector))由于默认的 CSS 查询无法穿透 Shadow DOM环境提供了注入自定义queryFn的能力。仓库的 E2E 测试正是利用这一点实现 Shadow DOM 穿透——借助浏览器内全局可用的kagekiri库通过webdriver.By.js注入脚本执行kagekiri.querySelectorAll(s, r)webdriver.e2e.spec.tsasync function piercingQueryFn(selector: string, root: () webdriver.WebElement) { return wd.findElements( webdriver.By.js((s: string, r: Element) kagekiri.querySelectorAll(s, r), selector, root()), ); }配套测试webdriver.e2e.spec.ts验证了三种行为默认不穿透shadows()为空数组使用piercingQueryFn后可查得 Shadow 内容[Shadow 1, Shadow 2]并可跨 Shadow 边界做深层查询。3.3 稳定化与异步任务处理forceStabilize()在浏览器内执行whenStable异步脚本selenium-web-driver-harness-environment.ts。该脚本读取 Angular 暴露在window.frameworkStabilizers上的钩子数组通过Promise.all等待所有稳定化器就绪每个稳定化器在 Angular 无待处理任务时回调。注释说明大多数情况下无需手动调用但某些动画场景需要第二轮的稳定化才能彻底 flush 动画事件。waitForTasksOutsideAngular()API 报告将其列为公共方法但源码实现目前是空操作并带有 TODO 注释指向已知问题angular/components#17412。在 WebDriver 环境下如何等待NgZone外的任务仍是待解决事项——这是文档与源码确认的当前限制读者应避免依赖该方法的行为。3.4 waitForAngularReady页面加载后的启动等待export async function waitForAngularReady(wd: webdriver.WebDriver): Promisevoid实现selenium-web-driver-harness-environment.ts分两步wd.wait(() wd.executeScript(isBootstrapped))——轮询等待 Angular 完成引导window.frameworkStabilizers已存在wd.executeAsyncScript(whenStable)——等待应用进入稳定态。E2E 测试在beforeAll中wd.get(url)之后立即调用它确保 Angular 就绪后再创建 Harnesswebdriver.e2e.spec.ts。四、实战在 Selenium E2E 测试中使用这套 API综合 webdriver.e2e.spec.ts 与 cross-environment-tests.ts一个完整的 E2E 测试骨架如下import {HarnessLoader, parallel} from angular/cdk/testing; import { SeleniumWebDriverHarnessEnvironment, waitForAngularReady, } from angular/cdk/testing/selenium-webdriver; import * as webdriver from selenium-webdriver; import {MainComponentHarness} from ./harnesses/main-component-harness; const wd: webdriver.WebDriver /* 创建 WebDriver 实例 */; beforeAll(async () { await wd.get(http://localhost:${port}/component-harness); await waitForAngularReady(wd); // 等待 Angular 引导并稳定 }); beforeEach(() { loader SeleniumWebDriverHarnessEnvironment.loader(wd); // 创建文档根 HarnessLoader }); it(creates loader and loads harnesses, async () { const harness await SeleniumWebDriverHarnessEnvironment.loader(wd).getHarness(MainComponentHarness); // 与单元测试完全相同的 Harness API const title await harness.title(); expect(await title.text()).toBe(Main Component); });几个关键实践结论测试代码只 import 一个环境类。test-harnesses.md明确要求Karma 单元测试用TestbedHarnessEnvironmentSelenium E2E 用SeleniumWebDriverHarnessEnvironment二者不可混用。Harness 用法跨环境一致。仓库通过crossEnvironmentSpecs(...)cross-environment-tests.ts把同一套测试用例同时跑在 TestBed 与 WebDriver 环境上覆盖了HarnessLoader的getChildLoader/getAllHarnesses/hasHarness、ComponentHarness的定位器、HarnessPredicate过滤、TestElement的全部交互/查询方法以及parallel()并行读取。这正是一套 Harness两种环境设计目标的实证。需要细粒度变更检测控制时可用manualChangeDetection包裹代码块src/cdk/testing/change-detection.ts在异步操作进行中手动触发fixture.detectChanges()并断言中间态。如需穿透 Shadow DOM向loader传入自定义queryFn选项见 3.2 节这同时展示了WebDriverHarnessEnvironmentOptions的唯一配置入口的实际用途。五、与 Protractor / Testbed 实现的对比要点API 报告虽然只聚焦 Selenium WebDriver 包但结合 src/cdk/testing 下的三套实现可以看清设计取舍Testbed 环境原始元素类型是 DOM 的Element依赖 Zone.js 与ComponentFixture通过manualChangeDetection/parallel等 API 优化变更检测次数Protractor 环境src/cdk/testing/protractor原始元素类型是ElementFinder定位依赖 Protractor 的element(by.css(...))Selenium WebDriver 环境原始元素类型是返回 WebElement 的函数用惰性引用规避 stale element 问题稳定性由注入浏览器的frameworkStabilizers机制保证。三者共享同一个TestElement接口与HarnessEnvironment抽象因此组件库作者只需编写一次 Harness即可同时服务单元测试与 E2E 测试——这正是angular/cdk/testing系列包的核心价值所在。六、使用边界与已知限制基于源码的事实根据源码注释与测试配置以下限制是文档/代码明确确认的使用时应留意waitForTasksOutsideAngular()目前是空实现selenium-web-driver-harness-environment.ts等待 NgZone 外任务在 WebDriver 环境下尚无内置方案sendKeys无法在部分环境复现浏览器原生键盘快捷键行为如Tab、CtrlA这是TestElement接口注释明确声明的边界默认queryFn不穿透 Shadow DOM需要穿透时必须自定义queryFn各环境的交互事件序列不可能与真实用户 100% 一致test-harnesses.md对此有专门说明CDK 的做法是尽力归一化并模拟最关键的事件序列无修饰键时sendKeys刻意避开webdriver.Key.chord以兼容 geckodriver若需组合键应显式传入ModifierKeys。综上angular/cdk/testing/selenium-webdriver以极小的公共 API 面4 个符号提供了完整的 Selenium E2E 环境支持。本文所涉及的 API 签名、实现细节与测试用例均可在仓库对应路径goldens/cdk/testing/selenium-webdriver/index.api.md、selenium-web-driver-element.ts、selenium-web-driver-harness-environment.ts、webdriver.e2e.spec.ts中逐一核对可作为编写基于 Selenium WebDriver 的 Angular 组件 E2E 测试的权威参考。【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门