角張ったテストを簡素化するための強力なツール
観客は、すべてのボイラープレートのうなり声を取り除くのに役立ち、読みやすく、洗練された合理化されたユニットテストを残します。
and角度コンポーネント、ディレクティブ、およびサービスのテストのサポート
✅簡単なDOMクエリ
cleanキーボード/マウス/タッチイベントをトリガーするためのクリーンAPI
ng-contentテスト
customカスタムジャスミン/jestマッチャー(tohaveclass、tobedisabled ..)
Routingテストサポート
✅HTTPテストサポート
eventエントリコンポーネントの組み込みサポート
componentコンポーネントプロバイダーの組み込みサポート
✅自動モッキングプロバイダー
olling強く入力されました
jest Jestサポート
スポンサーシップは、NGNEATライブラリの継続的な開発とメンテナンスに役立ちます。 NGNEATをビジネスとアプリケーション開発の中心としてスポンサーするように会社に依頼することを検討してください。
ゴールドスポンサーになることでサポートを高め、トップ5のリポジトリのReadMeでロゴを際立たせてください。
ゴールドスポンサーになってバッキングを後押しし、READMEのトップ3リポジトリにロゴが際立って紹介されてスポットライトを楽しんでください。

ブロンズスポンサーになり、GitHubのReadMeにロゴを入手してください。
特徴
目次
インストール
npm
糸
コンポーネントのテスト
ネストされた延期可能なビュー
文字列セレクター
タイプセレクター
DOMセレクター
選択した要素をテストします
モッキングコンポーネント
単一コンポーネント/ディレクティブ角度モジュールのテスト
カスタムイベント
イベントクリエイター
イベントAPI
キーボードヘルパー
マウスヘルパー
クエリ
延期可能なビュー
ホストでのテスト
カスタムホストコンポーネント
ルーティングによるテスト
ナビゲーションのトリガー
RouterTestingModuleを使用した統合テスト
ルーティングオプション
テスト指示
テストサービス
追加のオプション
パイプのテスト
カスタムホストコンポーネントを使用します
モッキングプロバイダー
依存関係をモッキングします
モッキングコンストラクターの依存関係
冗談のサポート
httpでのテスト
グローバルな注入
コンポーネントプロバイダー
カスタムマッチャー
回路図
デフォルトの回路図コレクション
ワーキングスペクテーターとJESTサンプルリポジトリとカルマの比較
コアチーム
貢献者
npm install @ngneat/spectator --save-dev
yarn add @ngneat/spectator --dev
createComponentFactory()関数を使用してコンポーネントファクトリを作成し、テストするコンポーネントクラスを渡します。 createComponentFactory()それぞれのitブロックに新しいコンポーネントを作成する関数を返します。
'@ngneat/spectator'; import {buttonComponent}から './button.component';describe('buttonComponent'、()=> {from '@ngneat/spectator'; import {buttonComponent}からImport {Spectator、CreateComponentFactory}
観客としましょう:観客<buttonComponent>;
const createComponent = createComponentFactory(buttonComponent);
beforeeach(()=> spectator = createcomponent());
it( 'デフォルトで成功クラスを持つ必要があります'、()=> {expect(spectator.query( 'button'))。tohaveclass( 'success');
});
it( '[className] input'、()=> {spectator.setInput( 'className'、 'danger'); equid(spectator.query( 'button'))。tohaveclass( '危険 '); expect(spectator.query(' button '))。
});}); createComponentFactory関数は、オプションで、基本的な角度テストモジュールオプションを拡張する次のオプションを取得できます。
const createComponent = createComponentFactory({
コンポーネント:ButtonComponent、
輸入:[]、
プロバイダー:[]、
宣言:[]、
EntryComponents:[]、
ComponentProviders:[]、//コンポーネントのプロバイダーをオーバーライドします
ComponentViewProviders:[]、//コンポーネントのビュープロバイダーをオーバーライドします
Overridemodules:[]、//モジュールオーバーライド
OverrideComponents:[]、//スタンドアロンコンポーネントをテストした場合のコンポーネントオーバーライドコンポーネント
OverrideDirectives:[]、// Standaloneディレクティブをテストした場合のオーバーライド指令
OverridePipes:[]、//スタンドアロンパイプのテストの場合のパイプオーバーライドパイプ
模擬:[]、//自動的にモックされるプロバイダー
ComponentMocks:[]、//自動的にモックされるコンポーネントプロバイダー
componentViewProviderSmocks:[]、//コンポーネントビュープロバイダーは自動的にモックされるプロバイダーを表示
検出チェンジ:false、//デフォルトはtrueになります
sulrecomponent:false、//デフォルトはtrueになります
障害者:false、//デフォルトはtrueになります
浅い:true、//デフォルトはfalseになります
deferblockbehavior:deferblockbehavior //デフォルトはdeferblockbehavior.playthrough}); createComponent()関数は、オプションで次のオプションを取得します。
it( 'sele ...'、()=> {
Spectator = createComponent({//コンポーネントinputsprops:{title: 'click'}、//コンポーネントのプロバイダーをオーバーライド//「CreateComponentFactory`Providers:[]、//変更を実行するかどうかを1回宣言する必要があることに注意してください(デフォルトはtrue)検出チェンジ:false
});
想像(Spectator.Query( 'button'))。tohavetext( 'click');}); createComponent()関数の範囲でoverrideComponentsオプションを提供することにより、スタンドアロンコンポーネントをオーバーライドする方法を定義できます。
@成分({
セレクター: `app-standalone with-import`、
テンプレート: `<div id =" standalone ">インポートを含むスタンドアロンコンポーネント!
輸入:[StandAloneComponentWithDependency]、
スタンドアロン:true、})class class standalonewithimportscomponentをエクスポート{} @component({{
セレクター: `app-standalone-with依存性`、
テンプレート: `<div id =" standalonewithdependency ">依存関係のスタンドアロンコンポーネント!</div>`、
スタンドアロン:true、})class standalonecomponentswithdependencyをエクスポート{
Constructor(public query:queryservice){}}@component({{
セレクター: `app-standalone-with依存性`、
テンプレート: `<div id =" standalonewithdependency ">オーバーライド依存性を備えたスタンドアロンコンポーネント!</div>`、
スタンドアロン:true、})export class mockstandalonecomponentwithdependency {
constructor(){}} it( 'sext ...'、()=> {
const Spectator = createhostfactory({component:standalonewithimportscomponent、テンプレート: `<div> <app-standalone-with-import> </app-standalone with-import> </div>`、OverrideComponents:[[StandaloneWithimports、 {imports:[standalonecomponentwithdependency]}、add:{imports:[mockstandalonecomponentwithdependency]}、}、]、]、
});
expect(host.query( '#standalone'))
expect(host.query( '#standalonewithdependency')) createComponent()メソッドは、次のAPIを公開するSpectatorのインスタンスを返します。
fixture - テストされたコンポーネントのフィクスチャ
component - テストされたコンポーネントのインスタンス
element - テストされたコンポーネントのネイティブ要素
debugElementテスト済みのフィクスチャーのデバッグ要素
flushEffects() - TestBed.flushEffects()にラッパーを提供します
inject() - TestBed.inject()のラッパーを提供します。
const service = spectator.inject(queryservice); const fromComponentInjector = true; const service = spectator.inject(queryService、fromComponentInjector);
detectChanges() - テストされた要素/ホストでDetectChangesを実行します。
Spectator.DetectChanges();
detectComponentChanges() -テストされたコンポーネントでdetectChangesを実行します( hostではありません)。 host使用してテストされたコンポーネントがonPushある場合は、まれにこの方法が必要であり、変更検出サイクルの実行を強制する必要があります。
Spectator.DetectComponentChanges();
setInput() - テストされたコンポーネントの@input()の値を変更します。メソッドは、存在する場合に手動でSimpleChangesでngOnChanges実行します。
it( 'sele ...'、()=> {
Spectator.setInput( 'className'、 'Danger');
Spectator.setInput({className: 'Danger'
});}); output - テストされたコンポーネントのObutervable @Output()を返します。
それ( 'clickで$イベントを発する必要があります'、()=> {
出力とします。
spectator.output( 'click')。subscribe(result =>(output = result));
Spectator.component.onclick({type: 'click'});
expect(output).toequal({type: 'click'});}); tick(millis?: number) - fakeasync tick()関数を実行し、Call detectChanges()実行します。
それ( 'ティックで動作するはずです'、fakeasync(()=> {
Spectator = CreateComponent(ZippyComponent);
Spectator.component.update();
expect(Spectator.comPonent.UpdatedAsync).TobeFalsy();
Spectator.Tick(6000);
想像(Spectator.component.updatedAsync).not.tobefalsy();}))イベントのそれぞれは、次のいずれかの1つになる可能性のあるSpectatorElementを受け入れることができます。
TYPE SPECTATREREMENT = STRING |要素| debugelement | ElementRef |ウィンドウ|ドキュメント| domselector;
提供されていない場合、デフォルトの要素は、テスト中のコンポーネントのホスト要素になります。
click() - クリックイベントをトリガーします:
Spectator.Click(SpectatorElement); Spectator.Click(bytext( 'element'));
blur() - ぼかしイベントをトリガーします:
Spectator.blur(SpectatorElement); Spectator.blur(bytext( 'element'));
Jestフレームワークを使用する場合、Blur()は、要素が焦点を合わせている場合にのみ機能することに注意してください。詳細。
focus() - フォーカスイベントをトリガーします:
Spectator.Focus(SpectatorElement); Spectator.Focus(bytext( 'element'));
typeInElement() - ユーザーのタイピングのシミュレーション:
Spectator.TypeinElement(Value、SpectatorElement); Spectator.TypeinElement(Value、ByText( '要素'));
dispatchMouseEvent() - マウスイベントをトリガーします:
Spectator.DispatchMouseEvent(SpectatorElement、 'Mouseout'); Spectator.DispatchMouseEvent(SpectatorElement、 'Mouseout')、x、y、event); spectator.dispatchmousevent(bytext( 'element')、 'mouseout'); spectator.dispatchmousevent(bytext ( 'element')、 'mouseout'、x、y、event);
dispatchKeyboardEvent() - キーボードイベントをトリガーします。
Spectator.dispatcheyboardevent(spectatorelement、 'keyup'、 'escase'); spectator.dispatchkeyboardevent(key: 'escape'、keycode:27})spectator.dispatcheyboardevent(bytext( 'element')、 'keyupupator.dispatcheyboardevent.dispatchkeyboardevent '、' Escape '); Spectator.dispatcheyboardevent(bytext(' element ')、' keyup '、{key:' escase '、keycode:27}) dispatchTouchEvent() - タッチイベントをトリガーします:
Spectator.DispatchTouchEvent(SpectatorElement、Type、X、Y); Spectator.DispatchTouchEvent(bytext( 'element')、type、x、y);
次の方法を使用して、カスタムイベント(子コンポーネントの@output())をトリガーできます。
Spectator.triggereventhandler(myChildComponent、 'myCustomevent'、 'eventValue'); Spectator.triggeventhandler(myChildComponent、 'myCustomevent'、 'eventValue'、{root:true}); spectator.triggeerventler( 'child-component'、mycustomevent '、' eventValue '); Spectator.triggereventhandler(' app-child-component '、' mycustomevent '、' eventValue '、{root:true});テンプレート(プレゼンターサービスなど)とは独立してイベントをテストする場合は、基礎となるイベントクリエイターにフォールバックできます。彼らは基本的に、前の要素なしで同じ署名を提供しています。
const keyboardevent = createkeyboardevent( 'keyup'、 'arrowdown'/ *、targetelement */); const mouseemousevent( 'mouseout'); const touchevent = createTouchevent( 'touchmove'); const fakeEvent = createfakevent( 'input');
Spectator.keyboard.pressenter(); spectator.keyboard.pressescape(); spectator.keyboard.presstab(); spectator.keyboard.pressbackspace(); spectator.keyboard.presskey( 'a'); spectator.keyboard.presskey( ' ctrl.a '); spectator.keyboard.presskey(' ctrl.shift.a ');
Spectator.Mouse.ContextMenu( '。Selector'); Spectator.Mouse.dblclick( '。Selector');
上記のメソッドのそれぞれがdetectChanges()も実行されることに注意してください。
観客APIには、テストの一部としてDOMをクエリするための便利な方法: query 、 queryAll 、 queryLast 、 queryHost 、 queryHostAllが含まれています。すべてのクエリメソッドは多型であり、次の手法のいずれかを使用してクエリすることができます。
文字列セレクター(jQueryまたはdocument.queryselectorを使用する場合と同じスタイル)を渡します。クエリのためのこの方法は、Angular's by.css述語と同等です。ネイティブHTML要素が返されることに注意してください。例えば:
//単一のhtmlelementspectator.query( 'div> ul.nav li:first-child'); //すべての一致するhtmlementsspectator.queryall( 'div> ul.nav li'); Document ContextSpectator.Query( 'div'、{root:true}); spectator.query( 'app-child'、{read:childserviceservice});タイプ(コンポーネント、ディレクティブ、プロバイダークラスなど)を渡して、DOMのそのタイプのインスタンスをクエリします。これは、Angular's By.directive Presticateに相当します。オプションで2番目のパラメーターを渡して、一致する要素のインジェクターから特定のインジェクショントークンを読み取ることができます。例えば:
// myComponent(存在する場合)の単一のインスタンスを返しますspectator.query(mycomponent); // dom(存在する場合)に存在する「mycomponent」のインスタンスで見つかった「someservice」のインスタンスを返します。 、{read:someservice}); spectator.query(mycomponent、{read:elementref}); host.querylast(childcomponent); host.queryall(childcomponent);観客を使用すると、ドムテストライブラリに触発されたセレクターを使用して要素をクエリすることができます。利用可能なセレクターは次のとおりです。
Spectator.Query(by placeholder( 'メールアドレスを入力してください')); spectator.query(byvalue( 'by value')); spectator.query(bytitle( 'by title')); spectator.query(byalttext( 'by alt text ')); Spectator.Query(bylabel(' by label ')); spectator.query(bytext(' by text ')); spectator.query(bytext(' by text '、{selector:'#some。 selector '}) byTextとbyTextContentの違いは、前者がネストされた要素内のテキストと一致しないことです。
たとえば、次のHTML byText('foobar', {selector: 'div'})は次のdivと一致しませんが、 byTextContent次のとおりです。
<div> <span> foo </span> <span> bar </span> </div>
観客を使用すると、親要素内のネストされた要素をクエリすることができます。これは、ページ上に同じコンポーネントの複数のインスタンスがあり、特定のコンポーネント内の子供をクエリする場合に役立ちます。親セレクターは、親要素を見つけるために使用される文字列セレクターです。親セレクターは、クエリメソッドの2番目のパラメーターとして渡されます。例えば:
spectator.query(uldComponent、{parentselector: '#parent-component-1'}); spectator.queryall(childComponent、{parentselector: '#parent-component-1'});観客を使用すると、 <select></select>要素を簡単にテストし、マルチセレクトをサポートできます。
例:
It( 'Multi Selectに正しいオプションを設定する必要があります'、()=> {
const select = Spectator.Query( '#test-multi-select')as htmlselectelement;
Spectator.Selectoption(select、['1'、 '2']);
expect(select).tohaveselectedoptions(['1'、 '2']);}); it( '標準selectで正しいオプションを設定する必要があります'、()=> {
const select = Spectator.Query( '#test-single-select')as htmlselectelement;
Spectator.Selectoption(Select、 '1');
heques(select).tohaveselectedoptions( '1');});また、選択したアイテムごとにchangeイベントハンドラーが正しく動作しているかどうかを確認することもできます。変更イベントを発送せずに選択を事前に設定する必要がある場合は、これを無効にできます。
API:
Spectator.Selectoption(SelectElement:HtmlSelectElement、Options:String | String [] | HtmloptionElement | HtmloptionElement []、config:{emitevents:boolean} = {emitevents:true});例:
それは( '正しい数の変更イベントを派遣する必要があります'、()=> {
const onchangespy = spyon(spectator.component、 'handlechange');
const select = Spectator.Query( '#test-onChange-Select')as htmlselectelement;
Spectator.Selectoption(select、['1'、 '2']、{emitevents:true});
expect(select).tohaveselectedoptions(['1'、 '2']);
expect(onchangespy).tohavebeencalledtimes(2);}); it( '正しい数の変更イベントを派遣しないでください'、()=> {
const onchangespy = spyon(spectator.component、 'handlechange');
const select = Spectator.Query( '#test-onChange-Select')as htmlselectelement;
Spectator.Selectoption(select、['1'、 '2']、{emitevents:false});
expect(select).tohaveselectedoptions(['1'、 '2']);
(onchangespy).not.tohavebeencalledtimes(2);}); HTMLOptionElement selectOptionおよびtoHaveSelectedOptionsマッチャーの引数として渡すこともできます。これは、 [ngValue]バインディングを<option>を使用している場合に特に便利です。
それ( '要素を渡すときにシングル選択に正しいオプションを設定する必要があります'、()=> {
const select = Spectator.Query( '#test-single-select-element')as htmlselectelement;
Spectator.Selectoption(Select、Spectator.Query(bytext( 'two'))as htmloptionelement);
expect(select).tohaveselectedoptions(spectator.query(bytext( 'two'))としてhtmloptionelement);});コンポーネントをモックする必要がある場合は、NG-Mocksライブラリを使用できます。いくつかの問題を非表示にする可能性があり、入力、出力などを設定するのに役立ちないCUSTOM_ELEMENTS_SCHEMA使用する代わりに、 ng-mocksあなたのために入力、出力などを自動モックします。
例:
'@ng-mocks'; import {foocomponent} from './path/to/foo.component'h createhost = createhostfactory({{foocomponent}から'@ngneat/spectator '; import {mockcomponent}からのimport {createhostfactory}
コンポーネント:YourComponentTotEST、
宣言:[mockcomponent(foocomponent)
]});独自のモジュールで宣言されているコンポーネント(またはディレクティブ)は、コンポーネント工場のインポートリストにコンポーネントモジュールをコンポーネントとともに定義することでテストできます。例えば:
const createComponent = createComponentFactory({
コンポーネント:ButtonComponent、
インポート:[buttonComponentModule]、});ただし、このように使用すると、観客は内部的にコンポーネントButtonComponent内部で作成した新しいモジュールの宣言に追加します。したがって、次のエラーが表示されます。
Type ButtonComponent is part of the declarations of 2 modules [...]
コンポーネントを内部モジュールの宣言に追加しないように観客に指示し、代わりに明示的に定義されたモジュールをそのまま使用することができます。工場オプションのdeclareComponentプロパティをfalseに設定するだけです。
const createComponent = createComponentFactory({
コンポーネント:ButtonComponent、
インポート:[ButtonComponentModule]、
宣言コンポーネント:false、}); createdirectiveFactoryを使用する場合、工場オプションのdeclareDirectiveプロパティをfalseに設定します。
const recutedirective = createdirectiveFactory({
コンポーネント:ハイライトコンポーネント、
インポート:[HighlightComponentModule]、
宣言表現:false、});観客は、延期可能なビュー( @defer {} )にアクセスするための便利なAPIを提供します。
spectator.deferBlock(optionalIndex)メソッドを使用して、目的の延期ブロックにアクセスします。 optionalIndexパラメーターはオプションであり、アクセスする延期ブロックのインデックスを指定できます。
最初の延期ブロックへのアクセス: spectator.deferBlock()に電話するだけです。
後続の延期ブロックへのアクセス:対応するインデックスを引数として使用します。たとえば、 spectator.deferBlock(1) 2番目のブロック(ゼロベースのインデックス作成)にアクセスします。
spectator.deferBlock(optionalIndex)指定された延期ブロックの異なる状態をレンダリングするための4つの方法を返します。
renderComplete() - 延期ブロックの完全な状態をレンダリングします。
renderPlaceholder() - 延期ブロックのプレースホルダー状態をレンダリングします。
renderLoading() - 延期ブロックの負荷状態をレンダリングします。
renderError() - 延期ブロックのエラー状態をレンダリングします。
例:
@component({selector: 'app-cmp'、テンプレート: `@defer(biewport){<div>最初の延期ブロックの完全状態</div> <! - 親完全状態 - >} @placeholder { <div> placeholder </div>} `、})class dummycomponent {} const createcomponent = createcomponentfactory({component:dummycomponent、deferblockbehavior:deferblockbehavior.manual、}); > {// const spectator = createcomponent();ネストされた延期ブロック内の状態にアクセスするには、返されたブロック状態メソッドからチェーンをチェーンするdeferBlockメソッドを呼び出します。
例:ネストされた完全な状態へのアクセス:
// `Spectator.deferblock(0).RenderComplete()`を想定しています。 = await deferblock();
完全な例:
@component({selector: 'app-cmp'、テンプレート: `@defer(biewport){<div>最初の延期ブロックの完全状態</div> <! - 親完全状態 - > @defer {< div>ネストされた延期ブロックの完全状態</div> <! - ネストされた完全状態 - >}} @placeHolder {placeholder </div>} `、})クラスdummycomponent {} constecomponent = createComponentFactory( {component:dummycomponent、deferblockbehavior:deferblockbehavior.manual、}); it( '最初のネストされた完全状態をレンダリングする必要があります'、async()=> {// const spectator = createcomponent(); // act //親をレンダリングします完全な状態const parentcompletestate.deferblock()。rendercomplete(); defer block ');});ホストコンポーネントを使用してコンポーネントをテストすることは、コンポーネントをテストするためのよりエレガントで強力な手法です。基本的に、コードを書くのと同じ方法でテストを書き込むことができます。動作しているのを見てみましょう:
Import {createHostFactory、SpectatorHost} from '@ngneat/spectator';
観客としましょう:SpectatorHost <Zippycomponent>;
const createhost = createhostfactory(zippycomponent);
It( 'ホストプロパティからタイトルを表示する必要があります'、()=> {Spectator = createHost( `<zippy [title] =" title "> </zippy>`、{hostprops:{ittitle: 'spectator is awesome'}} }); equict(Spectator.Query('。Zippy__Title '))
});
It( '開いている場合は「閉じる」単語を表示する必要があります'、()=> {Spectator = createHost( `<zippy title =" zippy title "> zippy content </zippy>`); spectator.click( '。zippy__title' ' ); expect(Spectator.Query('。Arrow '))
});});ホストメソッドは、次の追加のAPIでSpectator拡張するSpectatorHostのインスタンスを返します。
hostFixtureホストのフィクスチャ
hostComponent - ホストのコンポーネントインスタンス
hostElement - ホストのネイティブ要素
hostDebugElementホストのフィクスチャーデバッグ要素
setHostInputホストコンポーネントの@Input()の値を変更する
queryHost観客のクエリの詳細を読んでください
queryHostAll観客のクエリの詳細を読んでください
ホストコンポーネントでテストする場合、 setInputまたはprops使用してコンポーネントに入力を直接設定することは不可能です。入力は、代わりにhostPropsまたはsetHostInput介して設定し、テンプレート内のコンポーネントに渡す必要があります。
自分のホストの実装に合格すると役立つ場合があります。カスタムホストコンポーネントをcreateHostFactory()に渡すことができます。これにより、デフォルトのコンポーネントが置き換えられます。
@component({selector: 'custom-host'、template: ''})class customhostcomponent {
title = 'Custom HostComponent';} describt( 'with custom host component'、function(){{
レッチャートレーター:SpectatorHost <Zippycomponent、customhostComponent>;
const createhost = createhostfactory({component:zippycomponent、host:customhostComponent
});
it( 'ホストコンポーネントタイトルを表示する必要があります'、()=> {Spectator = createHost( `<zippy [title] =" title "> </zippy>`); .tohaveText( 'Custom HostComponent');
});});ルーティングを使用するコンポーネントの場合、デフォルトの工場を使用できる特別な工場があり、追加のルーティングオプションを構成できるように、スタブActivatedRoute提供します。
説明( 'ProductDetailsComponent'、()=> {
観客としましょう:SpectAtrouting <ProductDetailsComponent>;
const createComponent = createroutingFactory({component:productdetailsComponent、params:{productId: '3'}、data:{title: 'some title'}}
});
beforeeach(()=> spectator = createcomponent());
it( 'ルートデータタイトルを表示する必要があります'、()=> {equing(spectator.query( '。title'))。tohaveText( 'some title');
});
it( 'ルートの変更に反応する必要があります'、()=> {spectator.setRouteparam( 'productid'、 '5'); //ここでのテスト...
});});SpectatorRouting APIには、現在のルートを更新するための便利な方法が含まれています。
インターフェイスSpectAtrouting <c>拡張<c> {
/*** PARAM、QueryParams、およびデータ観察可能なストリームを更新することにより、ルートナビゲーションをシミュレートします。 */
triggernavigation(options?:routeoptions):void;
/***ルートパラメーションを更新し、ルートナビゲーションをトリガーします。 */
setrouteparam(name:string、value:string):void;
/***ルートクエリパラメーションを更新し、ルートナビゲーションをトリガーします。 */
Setroutequeryparam(name:string、value:string):void;
/***ルートデータを更新し、ルートナビゲーションをトリガーします。 */
setroutedata(name:string、value:any):void;
/***ルートフラグメントを更新し、ルートナビゲーションをトリガーします。 */
setroutefragment(fragment:string | null):void;
/***ルートURLを更新し、ルートナビゲーションをトリガーします。 */
setrouteurl(url:urlsegment []):void;}RouterTestingModuleを使用した統合テストstubsEnabledオプションをfalseに設定すると、実際のルーティング構成に合格し、AngularのRouterTestingModuleを使用して統合テストをセットアップできます。
これには解決することが約束が必要であることに注意してください。これに対処する1つの方法は、テストを非同期にすることです。
説明( 'ルーティング統合テスト'、()=> {
const createComponent = createroutingFactory({component:mycomponent、宣言:[othercomponent]、stubsenabled:false、routes:[{path: ''、component:mycomponent}、{path: 'foo'、component:othercomponent}]]
});
it( 'ルーターリンクを使用してナビゲートする必要があります'、async()=> {const spectator = createcomponent(); // soltise ... wait spectator.fixture.whenstable(); //現在のルートをテストするのを待ちます。 locationexpect(spectator.inject(location).path())。tobe( '/'); // router linkspectator.click( '。link-1'); //待機することを忘れないでください解決することを約束します... spectator.fixture.whenStable()
});});createRoutesFactory関数は、デフォルトの観客オプションに加えて、次のオプションを取得できます。
params : ActivatedRouteスタブで使用する初期パラメージ
queryParams : ActivatedRouteスタブで使用する初期クエリパラマ
data : ActivatedRouteスタブで使用する初期データ
fragment : ActivatedRouteスタブで使用する初期フラグメント
url : ActivatedRouteスタブで使用する初期URLセグメント
root : ActivatedRouteスタブのrootの値
parent : ActivatedRouteスタブのparentの価値
children : ActivatedRouteスタブのchildrenの価値
firstChild : ActivatedRouteスタブのfirstChildの価値
stubsEnabled (デフォルト: true ): ActivatedRouteスタブを有効にしますfalseに設定すると、代わりにRouterTestingModule使用します
routes : stubsEnabledがfalseに設定されている場合、 RouterTestingModuleのRoutes構成を渡すことができます
テスト指令のための特別なテスト工場があります。次の指令があるとしましょう。
@directive({selector: '[highlight]'})エクスポートクラスHighlightDirective {
@hostbinding( 'style.background-color')backgroundcolor:string;
@hostlistener( 'mouseover')
onhover(){this.backgroundcolor = '#000000';
}
@hostlistener( 'mouseout')
onleave(){this.backgroundcolor = '#ffffff';
}}観客との指示を簡単にテストできる方法を見てみましょう。
説明( 'highlightdirective'、()=> {
観客としましょう:SpectOditivective <HighlightDirective>;
const recutedirective = createdirectiveFactory(highlightdirective);
beforeeach(()=> {Spectator = createdirective( `<div highlight>テストハイライトディレクティブ</div>`);
});
it( '背景色を変更する必要があります'、()=> {Spectator.dispatchMouseEvent(Spectator.element、 'MouseOver'); equied(spectator.element).tohavestyle({backgroundcolor: 'rgba(0,0,0、0.1 ) '}); spectator.dispatchmouseEvent(spectator.element、' mouseout '); expect(spectator.element).tohavestyle({backgroundcolor:' #fff '});
});
it( 'instance'を取得する必要があります '、()=> {const instance = spectator.directive; equict(instance).tobedefined();
});}); setInputまたはprops使用してディレクティブに入力を直接設定することは不可能です。入力は、代わりにhostPropsまたはsetHostInput介して設定し、テンプレートのディレクティブに渡す必要があります。
次の例は、観客とサービスをテストする方法を示しています。
'@ngneat/spectator'; import {authservice} from 'auth.service.ts'; descrid( 'authservice'、()=> {
let spectator:spectatorservice <authservice>;
const createService = createServiceFactory(authservice);
beforeeach(()=> spectator = createService());
it( 'はログインしてはいけません'、()=> {expect(spectator.service.isloggedin())。tobefalsy();
});}); createService()関数は、次のプロパティでSpectatorServiceを返します。
service - サービスのインスタンスを取得します
inject() - Angular TestBed.inject()のプロキシ
オプションをオプションで渡すこともできます。たとえば、テストされているサービスに焦点を当てているため、サービスをテストするときは、その依存関係を模倣したいことがよくあります。
例えば:
@Injectable()Export Class AuthService {
Constructor(PrivateDateservice:dateservice){}
iSloggedin(){if(this.dateservice.isexpired( 'Timestamp')){return false;} return true;
}}この場合、 DateService依存関係を模倣できます。
'@ngneat/spectator'; import {authservice} from 'auth.service.ts'; descrid( 'authservice'、()=> {
let spectator:spectatorservice <authservice>;
const createService = createServiceFactory({service:authservice、providers:[]、entrycomponents:[]、mocks:[dateservice]
});
beforeeach(()=> spectator = createService());
それ( 'ログインする必要があります'、()=> {const dateservice = spectator.inject(dateservice); dateservice.isexpired.and.ReturnValue(false); expect(spectator.service.isloggedin()。tobetruthy();
});});次の例は、観客とパイプをテストする方法を示しています。
'@ngneat/spectator'; import {statsservice} from './stats.service';import {sumpipe} from' ./sum.pipe';describe('sumpipe '、()= => {
レッチスペクテーター:SpectatorPipe <Sumpipe>;
const createpipe = createpipefactory(sumpipe);
It( '指定された数字のリスト(テンプレート)を合計する必要があります'、()=> {Spectator = createpipe( `{{[1、2、3] | sum}}`); expect(spectator.element).tohavetext ( '6');
});
それは( '指定された数字のリスト(prop)'、()=> {spectator = createpipe( `{prop | sum}}`、{hostprops:{prop:[1、2、3]}}}}を要約する必要があります。 )。
});
それは( '合計をサービスに委任する必要があります'、()=> {const sum =()=> 42; const provider = {statsservice、usevalue:{sum}}; spectator = createpipe( `{{prop | sum}} `、{hostprops:{prop:[2、40]}、providers:[provider]}); expect(spectator.element).tohaveText('42 ');
});}); createPipe()関数は、次のプロパティでSpectatorPipeを返します。
hostComponent - ホストコンポーネントのインスタンス
debugElementホストコンポーネントの周りのフィクスチャのデバッグ要素
element - ホストコンポーネントのネイティブ要素
detectChanges() - Angular TestBed.fixture.detectChanges()
inject() - Angular TestBed.inject()のプロキシ
setInputまたはprops使用してパイプに入力を直接設定することは不可能です。代わりに入力をhostPropsまたはsetHostInput介して設定し、テンプレート内のパイプに渡す必要があります。
次の例は、カスタムホストコンポーネントを使用してパイプをテストする方法を示しています。
「@angular/core '; import {spectatorpipe、createpipefactory}から'@ngneat/spectator '; import {veragePipe} from' ./average.pipe';import {statsservice}から './statsから'@angular/core 'から{component、input}からintember .service ';@component({
テンプレート: `<div> {{prop | avg}} </div> `})class CustomHostComponent {
@input()public prop:number [] = [1、2、3];} describt( 'veragePipe'、()=> {
レッチャーティーター:SpectatorPipe <EveragePipe>;
const createpipe = createpipefactory({pipe:veragepipe、host:customhostComponent
});
it( '数字の特定のリストの平均を計算する必要があります'、()=> {Spectator = createpipe(); expect(spectator.element).tohaveText( '2');
});
それ( '数字のリストが空である場合、'は0になります '、()=> {spectator = createpipe({hostprops:{prop:[]}}); equing(spectator.element).tohaveText(' 0 ');
});
それ( '計算をサービスに委任する必要があります'、()=> {const avg =()=> 42; const provider = {statsservice、usevalue:{avg}}; spectator = createpipe({providers:[provider ]}); expect(spectator.element).tohaveText('42 ');
});});すべての観客工場について、プロバイダーを簡単にモックできます。
mocksプロパティに渡すすべてのサービスは、 mockProvider()関数を使用してmockedされます。 mockProvider()関数は、各メソッドをジャスミンスパイに変換します。 (すなわちjasmine.createSpy() )。
ここにそれが公開する方法のいくつかは次のとおりです。
dateservice.isexpired.and.callthrough(); dateservice.isexpired.and.callfake(()=> fake); dateservice.isexpired.and.throwerror( 'error'); dateservice.isexpired.andcallfake(()=>> fake); ;
ただし、JESTをテストフレームワークとして使用し、代わりにそのモッキングメカニズムを使用する場合は、 @ngneat/spectator/jestからmockProvider()インポートします。これにより、 jest.fn()関数が自動的に使用され、代わりにJest互換のモックが作成されます。
mockProvider()プロパティが含まれません。モックにプロパティが必要な場合は、2番目の引数を使用できます。
const createService = createServiceFactory({
サービス:AuthService、
プロバイダー:[mockprovider(otherservice、{name: 'martin'、emitter:new subject()、mockedmethod:()=> 'mocked'})
]、});コンポーネントがOnInitライフサイクル法でock笑されているサービスに依存している場合、サービスが注入されるまで変更検出を無効にする必要があります。
これを構成するには、 createComponentメソッドを変更して、 detectChangesオプションをfalseに設定し、注入されたサービスをセットアップした後に観客のdetectChangesを手動で呼び出します。
const createComponent = createComponentFactory({
コンポーネント:WeatherDashBoardComponent}); it( 'initの天気APIを呼び出す必要があります'、()=> {
const Spectator = createComponent({DetectChanges:false
});
const weatherservice = spectator.inject(weatherdataapi);
weatherservice.getweatherdata.andReturn(of(mockweatherdata));
Spectator.DetectChanges();
expect(weatherservice.getweatherdata).tohavebeencalled();});コンポーネントがコンストラクターにock笑されているサービスに依存している場合、モックを作成および構成し、コンポーネントを作成するときにモックを提供する必要があります。
const createComponent = createComponentFactory({
コンポーネント:WeatherDashBoardComponent}); it( 'コンストラクターの天気APIを呼び出す必要があります'、()=> {
const weatherservice = createSpyObject(waterdataapi);
weatherservice.getweatherdata.andReturn(of(mockweatherdata));
Spectator = CreateComponent({Providers:[{sultion:weatherdataapi、usevalue:weatherservice}]
});
expect(weatherservice.getweatherdata).tohavebeencalled();});デフォルトでは、観客はジャスミンを使用してスパイを作成します。代わりにJestをテストフレームワークとして使用している場合は、観客にJest互換のスパイを作成させることができます。
@ngneat/spectator/jest ( @ngneat/spectatorの代わりに)から次の機能のいずれかをインポートするだけで、ジャスミンの代わりにjestを使用します。 createComponentFactory() 、 createHostFactory() 、 createServiceFactory() 、 createHttpFactory() 、 mockProvider() 。
'@ngneat/spectator/jest'; import {authservice} from './auth.service';import {dateservice} from' ./date.service';describe('authservice 'から'@ngneat/spectator/jest} from '@ngneat/spectator/jest}からのimport {createServiceFactory} => {
let spectator:spectatorservice <authservice>;
const createService = createServiceFactory({service:authservice、mocks:[dateservice]
});
beforeeach(()=> spectator = createService());
it( 'はログインしないでください'、()=> {const dateservice = spectator.inject <dateservice>(dateservice>(dateservice); dateservice.isexpired.mockreturnvalue(true); equid(spectator.service.isloggedin())。 );
});
it( 'はログインする必要があります'、()=> {const dateservice = spectator.inject <dateservice>(dateservice>(dateservice); dateservice.isexpired.mockreturnValue(false); expect(spectator.service.isloggedin()。tobetruthy() ;
});});コンポーネントの概略図を使用する場合、Jestインポートを使用するように--jestフラグを指定できます。 デフォルトをインポートするために、 angular.json更新します:
「schematics」:{"@ngneat/spectator:spectator-component":{"jest":true
}
}観客は、Angular HTTPモジュールを使用するテストデータサービスをはるかに簡単にします。たとえば、3つの方法でサービスがあり、1つはGet、1つは投稿を実行し、1つは同時リクエストを実行します。
export class todosdataservice {
コンストラクター(private httpclient:httpclient){}
gettodos(){this.httpclient.get( 'api/todos');
}
posttodo(id:number){return this.httpclient.post( 'api/todos'、{id});
}
collecttodos(){return merge(this.httpclient.get( '/api1/todos')、this.httpclient.get( '/api2/todos'));
}}上記のサービスのテストは次のようになります。
Import {createhttpfactory、httpmethod} from '@ngneat/spectator'; import {todosdataservice} from './todos-data.service';describe('httpclient Testing'、()=> {
let spectator:spectatorhttp <todosdataservice>;
const createhttp = createhttpfactory(todosdataservice);
beforeeach(()=> spectator = createhttp());
it( 'test httpclient.get'、()=> {spectator.service.getDos()。subscribe(); spectator.expectone( 'api/todos'、httpmethod.get);
});
it( 'httpclient.post'、()=> {spectator.service.posttodo(1).subscribe(); const req = spectator.expectone( 'api/todos'、httpmethod.post); expect(req。 request.body ['id'])。toequal(1);
});
it( '現在のhttp要求をテストできます'、()=> {spectator.service.getTodos()。subscribe(); const reqs = spectator.expectconcurrent([{url: '/api1/todos'、方法:httpmethod.get }、{url: '/api2/todos'、method:httpmethod.get}]); spectator.flushall(reqs、[{}、{}、{}]);
});}); createHttpFactory()関数を使用して、テストするサービスを渡すことにより、HTTPファクトリを作成する必要があります。 createHttpFactory()次のプロパティでspectatorhttpのインスタンスを取得するために呼び出される関数を返します。
controller - Angular HttpTestingControllerのプロキシ
httpClient角度HttpClientのプロキシ
service - サービスインスタンス
inject() - Angular TestBed.inject()のプロキシ
expectOne() - 指定されたURLとその方法に一致する単一のリクエストが作成され、そのモックリクエストを返すことを期待してください
各テストでそれらを再作成する必要なく、各テストで利用可能なインジェクションを定義することができます。
// test.tsimport {@ngneat/spectator '; import {tlansocomodule} from'@ngneat/tlansoco '; defineglobalsinjections({
輸入:[トランスコモジュール]、});モジュールがロードされる前に、 defineGlobalsInjections()する必要があることに注意してください。デフォルトのAngular test.tsでは、これはこの行の前に意味があります。
context.keys()。map(context);
デフォルトでは、元のコンポーネントプロバイダー( @Componentのprovidersなど)に触れられません。
ただし、ほとんどの場合、テストでコンポーネントのプロバイダーにアクセスするか、模擬に置き換えます。
例えば:
@成分({
テンプレート: '...'、
プロバイダー:[fooservice]})class foocomponent {
Constructor(PrivateFooservice:fooservice} {}
// ...} componentProvidersを使用して、 FooServiceプロバイダーを置き換えます。
const createComponent = createComponentFactory({
コンポーネント:foocomponent、
componentProviders:[{rodic:fooservice、usevalue:wonyelse}
]})または、 componentMocks使用してサービスをmockします。
const createComponent = createComponentFactory({
コンポーネント:foocomponent、
ComponentMocks:[fooservice]});プロバイダーにアクセスするには、 fromComponentInjectorパラメーターを使用してコンポーネントインジェクターから取得します。
Spectator.Inject(fooservice、true)
同様に、 componentViewProvidersとcomponentViewProvidersMocksを使用して、コンポーネントビュープロバイダーをオーバーライドすることもできます。
同じルールは、 directiveProvidersおよびdirectiveMocksパラメーターを使用した指令にも適用されます。
expect('。Zippy__Content ') zippy ')) ) )順序が無関係である場合、厳密なモードを手動で無効にします。Expect('。Zippy__Content ')。TohaveClass(' class '); equiend('。zippy__content ')。tohaveclass(' class-a、class-b '); expect('。 zippy__content ')。 ).not.tohaveclass(['class-b'、 'class-a']); expect( '。zippy__content')。tohaveclass( 'class'、{strict:false}); tohaveclass( 'class-a、class-b'、{strict:false}); expect( '。zippy__content')。tohaveclass( 'class-b、class-a'、{strict:false}); expect( '。 zippy__content ')。tohaveclass([' class-b '、' class-a ']、{strict:false}); expect('。zippy__content ')。 、{strict:false}); // tohaveTextは文字列の存在のみを探していることに注意してください。文字列がまったく同じ場合ではありません。文字列が完全に同じであることを確認する場合は、tohaveexacttext.//を使用して、文字列が完全に同じであるが最初にトリミングされていることを確認する場合は、tohaveexacttrimmedtext.//複数の値を渡すと、複数の値を渡すと、観客は、発見された要素のインデックスに対して各配列要素のテキストをチェックします。 ']); expect('。zippy__content ')。tohaveText((text)=> text.includes(' .. ')); equict('。zippy__content ')。tocontaintext(' content '); ').tocontaintext([' content a '、' content b ']); quict('。zippy__content ')コンテンツb ']); expect('。zippy__content ') ).tohavevalue( 'value'); expect( '。zippy__content') ( '.zippy__content')。tohavevalue(['value a'、 'value b']); expect( '。zippy__content') ).tohavestyle({backgroundcolor: 'rgba(0、0、0、0.1)'}); expect( '。zippy__content')。tohavedata({data: 'role'、val: 'admin'}); expect( '' '' .checkbox ')。tobechecked(); expect('。チェックボックス ') .tobehidden(); expect( 'element')。tobeselected(); // jest内の制限があるため(仮想domに実際のレイアウトロジックを適用しない)、特定のマッチャーが誤検知をもたらす可能性があることに注意してください。たとえば、幅と高さは0expect( 'element')。tobevisible(); expect( 'input')。tobefocused(); expect( 'div')。tobematchedby( '。Js-something'); expect(spectator。 component.object).tobepartial({aproperty: 'avalue'}); expect( 'div')。tohavedescendant( '。child'); expect( 'div')。 '文章'});Angular CLIを使用して、スペクテータースペックテンプレートを使用してコンポーネント、サービス、およびディレクティブを生成します:(デフォルトとして使用する場合)
成分
デフォルト仕様: ng g cs dashrized-name
ホスト付きスペック: ng g cs dashrized-name --withHost=true
カスタムホスト付き仕様: ng g cs dashrized-name --withCustomHost=true
サービス:
デフォルト仕様: ng g ss dashrized-name
テストのための仕様HTTPデータサービス: ng g ss dashrized-name --isDataService=true
指令:
ng g ds dashrized-name
Angular CLIプロジェクトのデフォルトコレクションとしてspectatorを使用するには、 angular.jsonに追加します。
ng configcli.defaultCollection @ngneat/spectator
spectator回路図は、デフォルトの@schematics/angular Collectionを拡張します。 SCSSファイルを使用してコンポーネントを生成するなどの回路図のデフォルトを設定する場合は、schematicsパッケージ名を@schematics/angularから@ngneat/spectator in angular.jsonに変更する必要があります。
「schematics」:{"@ngneat/spectator:spectator-component":{"style": "scss"
}
}Angular Docs Testing Developer GuideのKarmaの例は、観客とJestで再現されています。 (便利なため、これはカルマの例のローカルバージョンです。)
Septator&Jestバージョンにはこちらからアクセスできます。
Netanel Basal | Dirk Luijk | ベン・エリオット |
これらの素晴らしい人々(絵文字キー)に感謝します:~~~~
I.シナイ ? ? | バレンティン・ブリヤコフ ? | ベン・グリンハウス ? | マーティンnuc | Lars Gyrup Brink Nielsen ? | アンドリュー・グレコフ ? | Jeroen Zwartepoorte |
オリバー・シュレーゲル | レックスイェ ? | tchmura | Yoeri nijs | アンダーススカルビー | Gregor Woiwode | アレクサンダー・シェレメテフ ? |
マイク | メフメット・エリム | ブレット・エッカート | Ismail faizi | マキシム | ジョナサン・ボネフォイ | コラムフェリー |
クリスクーパー | マーク・シェイブ | dgsmith2 | DedwardStech ? | Tamasfoldi ? | パオロカレフィ | トニ・ヴィレナ |
itay oded | Guillaume de Jabrun | アナンド・ティワリー | エールズ・ドガノック | ゾルタン | vitalii baziuk | clementlemarc-certua |
Yuriy Grunin | アンドレイ・チャルキン | スティーブン・ハリス | リチャード・サハラコルピ | ドミニク・クレマー | Mehmet Ozan Turhan | Vlad Lashko |
William Tjondrosuharto | チャズ・ガティアン | Pavel Korobov | エンノ・ローマン | Pawel Boguslawski | トビアスウィットワー | マテオティバキラ |
このプロジェクトは、全委員会の仕様に従います。あらゆる種類の貢献を歓迎します!