組件測試指南:MatIconHarness 與 MatIconTestingModule 深度解析)
Angular Material 圖標(biāo)組件測試指南MatIconHarness 與 MatIconTestingModule 深度解析【免費(fèi)下載鏈接】componentsComponent infrastructure and Material Design components for Angular項目地址: https://gitcode.com/GitHub_Trending/co/componentsangular/material/icon的測試基礎(chǔ)設(shè)施位于 goldens/material/icon/testing/index.api.md 與 src/material/icon/testing為開發(fā)者在單元測試中驗(yàn)證圖標(biāo)渲染提供了兩條核心路徑通過MatIconHarness以類型安全的方式查詢、過濾并讀取mat-icon實(shí)例的狀態(tài)以及通過FakeMatIconRegistry/MatIconTestingModule在測試環(huán)境中以空實(shí)現(xiàn)替換真實(shí)的MatIconRegistry從而消除網(wǎng)絡(luò)請求與 XSS 清洗依賴。讀完本文你將掌握如何在組件測試中穩(wěn)定地加載圖標(biāo)、按類型/名稱/命名空間篩選圖標(biāo)、斷言圖標(biāo)是否為 inline以及如何用假注冊表為測試套件搭建隔離的圖標(biāo)環(huán)境。一、API 報告文檔說明這份文檔是什么goldens/material/icon/testing/index.api.md是一份由 API Extractor二者共同構(gòu)成了 icon 模塊 API 的黃金基線。從報告可以看出angular/material/icon/testing對外僅暴露 5 個符號職責(zé)高度聚焦符號種類職責(zé)MatIconTestingModuleNgModule測試模塊提供假注冊表FakeMatIconRegistryInjectable 類空實(shí)現(xiàn)的圖標(biāo)注冊表MatIconHarnessComponentHarness 子類測試中操作/查詢mat-iconIconHarnessFiltersinterfaceHarness 查詢過濾器IconTypeenum圖標(biāo)類型枚舉SVG / FONT這 5 個符號對應(yīng)到源碼中的三個文件icon-harness.ts、icon-harness-filters.ts、fake-icon-registry.ts并由 public-api.ts 統(tǒng)一導(dǎo)出。二、MatIconHarness類型安全的圖標(biāo)查詢與斷言MatIconHarness繼承自 CDK 的ComponentHarness是所有圖標(biāo)測試交互的入口。2.1 宿主選擇器與查找方式static hostSelector .mat-icon;Harness 通過 CSS 類選擇器.mat-icon定位宿主元素。要創(chuàng)建 Harness需要搭配 CDK 測試環(huán)境如TestbedHarnessEnvironmentimport {TestbedHarnessEnvironment} from angular/cdk/testing/testbed; import {MatIconHarness} from angular/material/icon/testing; const loader TestbedHarnessEnvironment.loader(fixture); const icons await loader.getAllHarnesses(MatIconHarness); // 查找全部圖標(biāo)2.2 實(shí)例方法讀取圖標(biāo)狀態(tài)根據(jù) API 報告MatIconHarness提供 5 個實(shí)例方法全部返回PromisegetType(): PromiseIconType— 返回IconType.SVG或IconType.FONT。其實(shí)現(xiàn)讀取宿主元素上的data-mat-icon-type屬性type svg ? IconType.SVG : IconType.FONT見 icon-harness.ts。getName(): Promisestring | null— 優(yōu)先讀取data-mat-icon-name屬性對于字體圖標(biāo)ligature回退到從 DOM 文本中提取名稱。這里有一個值得注意的細(xì)節(jié)實(shí)現(xiàn)會用host.text({exclude: *})只取直接文本節(jié)點(diǎn)排除子元素文本避免其他指令如MatBadge注入的內(nèi)容污染圖標(biāo)名若排除后為空再回退到完整文本見 icon-harness.ts。getNamespace(): Promisestring | null— 讀取data-mat-icon-namespace屬性。isInline(): Promiseboolean— 判斷宿主元素是否帶有mat-icon-inline類。static with(options?: IconHarnessFilters): HarnessPredicateMatIconHarness— 構(gòu)建帶過濾條件的查詢謂詞。2.3 過濾條件IconHarnessFiltersIconHarnessFilters繼承 CDK 的BaseHarnessFilters額外支持三個字段見 icon-harness-filters.tsexport interface IconHarnessFilters extends BaseHarnessFilters { type?: IconType; // 按圖標(biāo)類型過濾 name?: string | RegExp; // 按名稱過濾支持正則 namespace?: string | null | RegExp; // 按命名空間過濾null 表示默認(rèn)命名空間 }namespace之所以允許null是因?yàn)槟J(rèn)命名空間的圖標(biāo)在 DOM 上不設(shè)置 namespace 屬性傳null即可精確匹配無命名空間的圖標(biāo)。2.4 IconType 枚舉export enum IconType { SVG, // 數(shù)值 0 FONT, // 數(shù)值 1 }API 報告顯示其成員順序?yàn)镕ONT 1, SVG 0與源碼中SVG, FONT的聲明一致第一個成員從 0 遞增。三、FakeMatIconRegistry無網(wǎng)絡(luò)的假注冊表真實(shí)MatIconRegistry在測試中會帶來兩個問題一是通過HttpClient發(fā)起網(wǎng)絡(luò)請求受同源策略約束二是所有 SVG URL / HTML 字符串必須經(jīng)DomSanitizer標(biāo)記為可信。而FakeMatIconRegistry從根源上消除了這兩個依賴。3.1 空實(shí)現(xiàn)設(shè)計FakeMatIconRegistry實(shí)現(xiàn)了PublicApiMatIconRegistry并實(shí)現(xiàn)OnDestroy。PublicApiT是一個將返回this的方法遞歸映射為this的映射類型見 fake-icon-registry.ts因此所有注冊類方法addSvgIcon、addSvgIconInNamespace、addSvgIconLiteral、addSvgIconSet、addSvgIconResolver、registerFontClassAlias等共 10 個都直接返回this靜默丟棄所有注冊請求。有實(shí)際返回值的三個方法也做了最小實(shí)現(xiàn)classNameForFontAlias(alias)直接返回aliasgetDefaultFontSetClass()返回[material-icons]getSvgIconFromUrl()/getNamedSvgIcon()返回of(this._generateEmptySvg())即一個即時完成的 Observable發(fā)出一個空的 SVG 元素。3.2 空 SVG 的生成細(xì)節(jié)_generateEmptySvg()見 fake-icon-registry.ts通過document.createElementNS(http://www.w3.org/2000/svg, svg)創(chuàng)建 SVG并添加fake-testing-svg類以及fit、height100%、width100%、preserveAspectRatioxMidYMid meet、focusablefalse等屬性。源碼注釋點(diǎn)明了設(shè)計意圖Emulate real icon characteristics fromMatIconRegistryso size remains consistent in tests——即模擬真實(shí)圖標(biāo)的尺寸特征保證測試中的布局尺寸一致。3.3 MatIconTestingModule一行代碼安裝假注冊表NgModule({ providers: [{provide: MatIconRegistry, useClass: FakeMatIconRegistry}], }) export class MatIconTestingModule {}該模塊的唯一職責(zé)就是用FakeMatIconRegistry覆蓋MatIconRegistry的 provider。測試中只需在TestBed導(dǎo)入它TestBed.configureTestingModule({ imports: [MatIconTestingModule, ...], });此后組件內(nèi)所有MatIconRegistry的注入點(diǎn)都會拿到假實(shí)現(xiàn)即使模板中使用了未注冊的svgIcon也不會報錯或發(fā)起請求。四、實(shí)戰(zhàn)在組件測試中組合使用下面基于官方測試用例 icon-harness.spec.ts 還原完整用法。該 spec 注冊了一個命名空間圖標(biāo)并渲染 6 種形態(tài)的mat-iconregistry.addSvgIconLiteralInNamespace( svgIcons, svgIcon, sanitizer.bypassSecurityTrustHtml(svg/svg), );測試模板覆蓋了字體圖標(biāo)、SVG 圖標(biāo)、inline、ligature 文本、帶額外子元素與間接名稱等多種場景mat-icon fontSetfontIcons fontIconfontIcon/mat-icon mat-icon svgIconsvgIcons:svgIcon/mat-icon mat-icon inlineligature_icon/mat-icon mat-icon fontIconligature_icon_by_attribute/mat-icon mat-iconligature_icon_with_additional_content span classfake-badgeHello/span/mat-icon mat-iconspanligature_icon_with_indirect_name/span/mat-icon4.1 按類型過濾const [svgIcons, fontIcons] await parallel(() [ loader.getAllHarnesses(MatIconHarness.with({type: IconType.SVG})), loader.getAllHarnesses(MatIconHarness.with({type: IconType.FONT})), ]); // svgIcons.length 1fontIcons.length 54.2 按名稱過濾字符串與正則loader.getAllHarnesses(MatIconHarness.with({name: /^font/})); // 1 個 loader.getAllHarnesses(MatIconHarness.with({name: fontIcon})); // 1 個4.3 按命名空間過濾含 null 語義loader.getAllHarnesses(MatIconHarness.with({namespace: /^font/})); // 1 個 loader.getAllHarnesses(MatIconHarness.with({namespace: svgIcons})); // 1 個 loader.getAllHarnesses(MatIconHarness.with({namespace: null})); // 4 個匹配無命名空間圖標(biāo)4.4 狀態(tài)斷言const icons await loader.getAllHarnesses(MatIconHarness); const types await parallel(() icons.map(icon icon.getType())); // [FONT, SVG, FONT, FONT, FONT, FONT] const names await parallel(() icons.map(icon icon.getName())); // [fontIcon, svgIcon, ligature_icon, ligature_icon_by_attribute, // ligature_icon_with_additional_content, ligature_icon_with_indirect_name] const namespaces await parallel(() icons.map(icon icon.getNamespace())); // [fontIcons, svgIcons, null, null, null, null] const inlineStates await parallel(() icons.map(icon icon.isInline())); // [false, false, true, false, false, false]注意第 5 個圖標(biāo)盡管含有span classfake-badgeHello/span子元素getName()仍正確返回ligature_icon_with_additional_content——這正是 2.2 節(jié)所述排除子元素文本策略的驗(yàn)證。五、原理印證Harness 數(shù)據(jù)從何而來MatIconHarness讀取的data-mat-icon-*屬性并非測試專用而是MatIcon組件真實(shí)暴露的宿主綁定。在 icon.ts 中host: { role: img, class: mat-icon notranslate, [class]: color ? mat- color : , [attr.data-mat-icon-type]: _usingFontIcon() ? font : svg, [attr.data-mat-icon-name]: _svgName || fontIcon, [attr.data-mat-icon-namespace]: _svgNamespace || fontSet, [attr.fontIcon]: _usingFontIcon() ? fontIcon : null, [class.mat-icon-inline]: inline, ... }由此可清晰對應(yīng)data-mat-icon-type由_usingFontIcon()即!this.svgIcon決定data-mat-icon-name來自_svgName || fontIcon其中_svgName由svgIcon輸入經(jīng)過_splitIconName拆分支持[namespace]:[name]格式見 icon.ts得到data-mat-icon-namespace來自_svgNamespace || fontSetmat-icon-inline類由inline輸入驅(qū)動。因此 Harness 讀取的是組件渲染后的真實(shí) DOM 狀態(tài)測試斷言與生產(chǎn)行為完全一致。此外MatIcon構(gòu)造函數(shù)中默認(rèn)設(shè)置aria-hiddentrue除非用戶顯式指定這一點(diǎn)在編寫可訪問性相關(guān)測試時也應(yīng)納入考量詳見 icon.md 的 Accessibility 章節(jié)。六、使用建議與邊界何時用MatIconTestingModule當(dāng)被測組件依賴MatIconRegistry加載遠(yuǎn)程或內(nèi)聯(lián) SVG 圖標(biāo)而你不想在測試中引入HttpClient請求、跨域問題或真實(shí) SVG 解析時直接導(dǎo)入MatIconTestingModule即可。何時用MatIconHarness當(dāng)需要斷言圖標(biāo)的類型、名稱、命名空間、inline 狀態(tài)或按這些維度篩選特定圖標(biāo)時優(yōu)先使用 Harness 而非直接操作 DOM以獲得更強(qiáng)的健壯性與可讀性。注冊類方法的靜默語義FakeMatIconRegistry對addSvgIcon*等注冊調(diào)用一律忽略這意味著驗(yàn)證注冊是否成功不屬于假注冊表的能力范圍——它只保證圖標(biāo)渲染不報錯、尺寸一致。需注意的前提本指南基于當(dāng)前倉庫中angular/material/icon的源碼與 API 報告編寫。Harness 依賴 CDK 的ComponentHarness基礎(chǔ)設(shè)施angular/cdk/testing使用時需確保測試環(huán)境已配置TestbedHarnessEnvironment若使用其他測試運(yùn)行器需替換為對應(yīng)的 Harness 環(huán)境。延伸閱讀主包完整 API 見 goldens/material/icon/index.api.md圖標(biāo)功能完整文檔見 src/material/icon/icon.md測試用例見 src/material/icon/testing/icon-harness.spec.ts。【免費(fèi)下載鏈接】componentsComponent infrastructure and Material Design components for Angular項目地址: https://gitcode.com/GitHub_Trending/co/components創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考