Dojo 如何測試 widget

測試

dojo/framework/src/testing/README.md

commit 84e254725f41d60f624ab5ad38fe82e15b6348a2

用于測試和斷言 Dojo 部件期望的虛擬 DOM 和行為的簡單 API。

  • 測試

    • Features
    • harness

      • API
      • Custom Comparators
    • selectors
    • harness.expect

      • harness.expectPartial

        • harness.trigger
        • harness.getRender
    • Assertion Templates

Features

  • 簡單、熟悉和少量的 API
  • 重點測試 Dojo 虛擬 DOM 結構
  • 默認不需要 DOM
  • 全面支持函數式編程和 tsx 聲明

harness

當使用 @dojo/framework/testing 時,harness 是最重要的 API,主要用于設置每一個測試并提供一個執行虛擬 DOM 斷言和交互的上下文。目的在于當更新 propertieschildren 和失效部件時,鏡像部件的核心行為,并且不需要任何特殊或自定義邏輯。

API

harness(renderFunction: () => WNode, customComparators?: CustomComparator[]): Harness;
  • renderFunction: 返回被測部件 WNode 的函數
  • customComparators: 一組自定義比較器的描述符。每個描述符提供一個比較器函數,用于比較通過 selectorproperty 定位的 properties

harness 函數返回的 Harness 對象提供了與被測部件交互的精簡 API:

Harness

  • expect: 對被測部件完整的渲染結果執行斷言
  • expectPartial: 對被測部件的一部分渲染結果執行斷言
  • trigger: 用于在被測部件的節點上觸發函數
  • getRender: 根據提供的索引返回對應的渲染器

使用 @dojo/framework/widget-core 中的 w() 函數設置一個待測試的部件簡單且眼熟:

class MyWidget extends WidgetBase<{ foo: string }> {protected render() {const { foo } = this.properties;return v('div', { foo }, this.children);}
}const h = harness(() => w(MyWidget, { foo: 'bar' }, ['child']));

如下所示,harness 函數也支持 tsx 語法。README 文檔中其余示例使用編程式的 w() API,在 unit tests 中可查看更多 tsx 示例。

const h = harness(() => <MyWidget foo="bar">child</MyWidget>);

renderFunction 是延遲執行的,所以可在斷言之間包含額外的邏輯來操作部件的 propertieschildren

let foo = 'bar';const h = harness(() => {return w(MyWidget, { foo }, [ 'child' ]));
};h.expect(/** assertion that includes bar **/);
// update the property that is passed to the widget
foo = 'foo';
h.expect(/** assertion that includes foo **/)

Custom Comparators

在某些情況下,我們在測試期間無法得知屬性的確切值,所以需要使用自定義比較描述符。

描述符中有一個定位要檢查的虛擬節點的 selector,一個應用自定義比較的屬性名和一個接收實際值并返回一個 boolean 類型斷言結果的比較器函數。

const compareId = {selector: '*', // all nodesproperty: 'id',comparator: (value: any) => typeof value === 'string' // checks the property value is a string
};const h = harness(() => w(MyWidget, {}), [compareId]);

對于所有的斷言,返回的 harness API 將只對 id 屬性使用 comparator 進行測試,而不是標準的相等測試。

selectors

harness API 支持 CSS style 選擇器概念,來定位要斷言和操作的虛擬 DOM 中的節點。查看 支持的選擇器的完整列表 以了解更多信息。

除了標準 API 之外還提供:

  • 支持將定位節點 key 屬性簡寫為 @ 符號
  • 當使用標準的 . 來定位樣式類時,使用 classes 屬性而不是 class 屬性

harness.expect

測試中最常見的需求是斷言部件的 render 函數的輸出結構。expect 接收一個返回被測部件期望的渲染結果的函數作為參數。

API

expect(expectedRenderFunction: () => DNode | DNode[], actualRenderFunction?: () => DNode | DNode[]);
  • expectedRenderFunction: 返回查詢節點期望的 DNode 結構的函數
  • actualRenderFunction: 一個可選函數,返回被斷言的實際 DNode 結構
h.expect(() =>v('div', { key: 'foo' }, [w(Widget, { key: 'child-widget' }), 'text node', v('span', { classes: ['class'] })])
);

expect 也可以接收第二個可選參數,返回要斷言的渲染結果的函數。

h.expect(() => v('div', { key: 'foo' }), () => v('div', { key: 'foo' }));

如果實際的渲染輸出和期望的渲染輸出不同,就會拋出一個異常,并使用結構化的可視方法,用 (A) (實際值)和 (E) (期望值)指出所有不同點。

斷言的錯誤輸出示例:

v("div", {"classes": ["root",
(A)     "other"
(E)     "another"],"onclick": "function"
}, [v("span", {"classes": "span","id": "random-id","key": "label","onclick": "function","style": "width: 100px"}, ["hello 0"])w(ChildWidget, {"id": "random-id","key": "widget"})w("registry-item", {"id": true,"key": "registry"})
])

harness.expectPartial

expectPartial 根據 selector 斷言部件的部分渲染輸出。

API

expectPartial(selector: string, expectedRenderFunction: () => DNode | DNode[]);
  • selector: 用于查找目標節點的選擇器
  • expectedRenderFunction: 返回查詢節點期望的 DNode 結構的函數
  • actualRenderFunction: 一個可選函數,返回被斷言的實際 DNode 結構

示例:

h.expectPartial('@child-widget', () => w(Widget, { key: 'child-widget' }));

harness.trigger

harness.trigger()selector 定位的節點上調用 name 指定的函數。

interface FunctionalSelector {(node: VNode | WNode): undefined | Function;
}trigger(selector: string, functionSelector: string | FunctionalSelector, ...args: any[]): any;
  • selector: 用于查找目標節點的選擇器
  • functionSelector: 要么是從節點的屬性中找到的被調用的函數名,或者是從節點的屬性中返回一個函數的函數選擇器
  • args: 為定位到的函數傳入的參數

如果有返回結果,則返回的是被觸發函數的結果。

用法示例:

// calls the `onclick` function on the first node with a key of `foo`
h.trigger('@foo', 'onclick');
// calls the `customFunction` function on the first node with a key of `bar` with an argument of `100`
// and receives the result of the triggered function
const result = h.trigger('@bar', 'customFunction', 100);

functionalSelector 返回部件屬性中的函數。函數也會被觸發,與使用普通字符串 functionSelector 的方式相同。

用法示例:

假定有如下 VDOM 樹結構,

v(Toolbar, {key: 'toolbar',buttons: [{icon: 'save',onClick: () => this._onSave()},{icon: 'cancel',onClick: () => this._onCancel()}]
});

并且你想觸發 save 按鈕的 onClick 函數。

h.trigger('@buttons', (renderResult: DNode<Toolbar>) => {return renderResult.properties.buttons[0].onClick;
});

harness.getRender

harness.getRender() 返回索引指定的渲染器,如果沒有提供索引則返回最后一個渲染器。

getRender(index?: number);
  • index: 要返回的渲染器的索引

用法示例:

// Returns the result of the last render
const render = h.getRender();
// Returns the result of the render for the index provided
h.getRender(1);

Assertion Templates

斷言模板(assertion template)允許你構建一個傳入 h.expect() 的期望渲染函數。斷言模板背后的思想來自經常要斷言整個渲染輸出,并需要修改斷言的某些部分。

要使用斷言模板,首先需要導入模塊:

import assertionTemplate from '@dojo/framework/testing/assertionTemplate';

然后,在你的測試中,你可以編寫一個基本斷言,它是部件的默認渲染狀態:

假定有以下部件:

class NumberWidget extends WidgetBase<{ num?: number }> {protected render() {const { num } = this.properties;const message = num === undefined ? 'no number passed' : `the number ${num}`;return v('div', [v('span', [message])]);}
}

基本斷言如下所示:

const baseAssertion = assertionTemplate(() => {return v('div', [v('span', { '~key': 'message' }, [ 'no number passed' ]);]);
});

在測試中這樣寫:

it('should render no number passed when no number is passed as a property', () => {const h = harness(() => w(NumberWidget, {}));h.expect(baseAssertion);
});

現在我們看看,為 NumberWidget 部件傳入 num 屬性后,如何測試數據結果:

it('should render the number when a number is passed as a property', () => {const numberAssertion = baseAssertion.setChildren('~message', ['the number 5']);const h = harness(() => w(NumberWidget, { num: 5 }));h.expect(numberAssertion);
});

這里,我們使用 baseAssertion 的 setChildren() api,然后我們使用特殊的 ~ 選擇器來定位 key 值為 ~message 的節點。~key 屬性(使用 tsx 的模板中是 assertion-key)是斷言模板的一個特殊屬性,在斷言時會被刪除,因此在匹配渲染結構時不會顯示出來。此功能允許你修飾斷言模板,以便能簡單的選擇節點,而不需要擴展實際的部件渲染函數。一旦我們獲取到 message 節點,我們就可以將其子節點設置為期望的 the number 5,然后在 h.expect 中使用生成的模板。需要注意的是,斷言模板在設置值時總是返回一個新的斷言模板,這可以確保你不會意外修改現有模板(可能導致其他測試失敗),并允許你基于新模板,增量逐層構建出新的模板。

斷言模板具有以下 API:

setChildren(selector: string, children: DNode[], type?: 'prepend' | 'replace' | 'append'): AssertionTemplateResult;
setProperty(selector: string, property: string, value: any): AssertionTemplateResult;
getChildren(selector: string): DNode[];
getProperty(selector: string, property: string): any;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252396.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252396.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252396.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python中將四元數轉換為旋轉矩陣

在制作bundlefusion時,想測試TUM數據集,并且將groundtruth寫入到數據集中,TUM中給定的groundtruth中的旋轉是使用四元數表示的,而bundlefusion中需要SE3的形式,所以我需要首先將四元數轉換為旋轉矩陣,然后再將其與平移向量合并在一起,因為我之前關于生成bundlefusion數據集寫了…

js -- 時間轉年月日

/*** 時間轉年月日* param sdate 開始的時間* param edate 結束的時間* returns {*}*/function day2ymrStr2(sdate, edate) {var day2ymrStr "";var date1 new Date(edate);var date2 new Date(sdate);var y 0, m 0, d 0;var y1 date1.getFullYear();var m1 …

iOS sha1加密算法

最近在項目中使用到了網絡請求簽名認證的方法&#xff0c;于是在網上找關于OC sha1加密的方法&#xff0c;很快找到了一個大眾使用的封裝好的方法&#xff0c;以下代碼便是 首先需要添加頭文件 #import<CommonCrypto/CommonDigest.h> 然后直接使用下面的方法就可以了 //s…

Linux開發5款實用工具推薦

今天安利給大家5款實用的Linux開發工具&#xff0c;希望對大家工作效率的提升有所幫助。容器放眼于現實&#xff0c;現在已經是容器的時代了。容器既及其容易部署&#xff0c;又可以方便地構建開發環境。如果你針對的是特定的平臺的開發&#xff0c;將開發流程所需要的各種工具…

TUM數據集制作BundleFusion數據集

BundleFusion的數據集中,在生成.sens文件之前,包括彩色圖,深度圖和一個位姿文件,并且這個pose文件中的位姿態是有變化的,所以我懷疑,推測,在這個pose文件中可以寫入groundtruth的位姿,然后在重建的時候就按照傳入的位姿進行計算.為了測試一下效果,我從TUM數據集開始入手,這個數…

Linq查詢datatable的記錄集合

通過linq查詢datatable數據集合滿足條件的數據集 1.首先定義查詢字段的變量&#xff0c;比方深度 string strDepth查詢深度的值&#xff1b; var dataRows from datarow in dataTable(須要查詢的datatable數據集).AsEnumerable() where …

Java 概述和編程基礎

First of all&#xff0c;Java概述&#xff1a; 類是Java程序設計的基石和基本單元&#xff1b; main()方法是程序的入口&#xff0c;它是共有的、靜態的&#xff0c;參數String[] args表示一個字符串數組可以傳入該程序&#xff0c;用來傳遞外部數據以初始化程序。   計算機…

19、Fragment

一、Fragment 1.1、fragment介紹 fragment的出現是為了同時適應手機和平板&#xff0c;可以將其看做Activity的組成部分&#xff0c;甚至Activity界面完全由不同的Fragment組成&#xff0c;它擁有自己的生命 周期和接收、處理用戶的事件&#xff0c;更為重要的是&#xff0c;可…

喜好:

不喜歡吃&#xff1a;一瓣瓣的蘑菇、海帶、豆腐皮、 不喜歡喝&#xff1a;魚湯&#xff1b; 不喜歡吃&#xff1a;山楂片、法式小面包&#xff08;軟軟的&#xff09;、果凍、 不喜歡喝&#xff1a;對飲料無感、不喜歡脈動、可樂雪碧等少量還行、 喜歡&#xff1a;啃骨頭、排骨…

將TUM數據集制作成BundleFusion數據集

在上一篇文章中,我寫到了如何將TUM數據生成BundleFusion所需要的數據集,生成的數據集如下圖中所示.并且是將每一組數據的groundtruth.txt中的位姿數據寫如到這里的pose文件中,作為每一幀圖像的先驗位姿. 今天我便將生成的數據集轉換為了.sens格式,然后運行bundlefusion算法,第…

每一次突破都是一種進步

一直以來&#xff0c;我接觸一門新技術&#xff0c;都是先看開發文檔&#xff0c;了解了這個技術是做什么的&#xff0c;能做什么。但是不知道怎么起步&#xff0c;也不敢貿然動手。我的解決辦法是看視頻&#xff0c;看別人怎么使用&#xff0c;跟著別人做&#xff0c;然后聽別…

mysql盲注學習-1

mysql: 1.left() //left()函數 left(a,b)從左側截取a,的b位 2.mid() //mid()函數 參數 描述 column_name 必需。要提取字符的字段。 start 必需。規定開始位置&#xff08;起始值是 1&#xff09;。 length 可選。要返回的字符數。如果省略&#xff0c;則 MID() 函數…

二分學習筆記

寫在前面 二分是一種常用且非常精妙的算法&#xff0c;常常是我們解決問題的突破口。二分的基本用途是在單調序列或單調函數中做查找。因此當問題的答案具有單調性時&#xff0c;就可以通過二分把求解轉化為判定。進一步地&#xff0c;我們還可以通過三分法解決單調函數的極值以…

解析.sens數據集

python腳本在下面網址中https://github.com/ScanNet/ScanNet/tree/master/SensReader/python 一定要使用python2運行此腳本. 使用指令如下 python reader.py --filename /media/yunlei/YL/DATASETS/ICL_DATABASE/lr_kt1/living_room_traj1n_frei_png.sens --output_path /me…

ConcurrentHashMap 解讀

初始化&#xff1a; 問題&#xff1a;如何當且僅只有一個線程初始化table 1 private final Node<K,V>[] initTable() {2 Node<K,V>[] tab; int sc;3 while ((tab table) null || tab.length 0) {4 if ((sc sizeCtl) < 0)5 …

XML Schema 基本結構

<?xml version1.0?> <Schema name"cangchuSchema" metamodelVersion"4.0"><PhysicalSchema><Table name"highway_toll"><Key><Column name"uid"/></Key></Table><Table name&qu…

關于系統自帶 .NET Framework 版本的說明

系統自帶版本&#xff1a; Windows XP (SP3) .NET Framework 1.1Windows 7 (SP1) .NET Framework 3.5.1Windows 8.1 .NET Framework 4.5.1Windows 10 (1507) .NET Framework 4.6Windows 10 (1511) .NET Framework 4.6.1Windows 10 (1607) .NET Framework 4.6.2Windows 10 (1703…

BundleFusion那些事兒

背景&#xff1a;前面幾篇博客中寫了很多關于BundleFusion的東西&#xff0c;主要包括bundlefusion的論文閱讀筆記&#xff0c;.sens數據集的生成等&#xff0c;經過最近幾天的工作&#xff0c;我對bundlefusion又有了新的技術積累&#xff0c;在這里整理一下&#xff0c;也算是…

問題:圖片怎么保存到數據庫, 以及怎么把圖片從數據庫中取出來使用?(已解決)...

簡單&#xff0c;不保存圖片到數據庫&#xff0c;而是圖片的路徑。 也就是說&#xff0c;先把圖片下載到服務器的指定目錄下&#xff0c;然后&#xff0c;在把相對的路徑保存到數據庫中。 如果下次獲取圖片&#xff0c;就訪問數據庫&#xff0c;獲取圖片路徑&#xff0c;然后根…

Oracle Study之--Oracle 11gR2通過RMAN克隆數據庫

Oracle Study之--Oracle 11gR2通過RMAN克隆數據庫Purpose of Database Duplication A duplicate database is useful for a variety of purposes, most of which involve testing. You can perform the following tasks in a duplicate database: Test backup and recovery pro…