เครื่องมือที่ทรงพลังในการทดสอบเชิงมุมของคุณทำให้ง่ายขึ้น
ผู้ชมช่วยให้คุณกำจัดงานทำเสียงฮึดฮัดของหม้อไอน้ำทั้งหมดทำให้คุณได้รับการทดสอบหน่วยที่อ่านง่ายและเพรียวบาง
✅สนับสนุนการทดสอบส่วนประกอบเชิงมุมคำสั่งและบริการ
✅การสืบค้น DOM ง่าย ๆ
✅ทำความสะอาด API สำหรับการเรียกใช้คีย์บอร์ด/เมาส์/สัมผัสเหตุการณ์
✅การทดสอบ ng-content
✅จัสมินที่กำหนดเอง/jest matchers (tohaveclass, tobedisabled .. )
✅การสนับสนุนการทดสอบการกำหนดเส้นทาง
✅การสนับสนุนการทดสอบ http
✅การสนับสนุนในตัวสำหรับส่วนประกอบรายการ
✅การสนับสนุนในตัวสำหรับผู้ให้บริการส่วนประกอบ
✅ผู้ให้บริการม็อกซ์อัตโนมัติ
✅พิมพ์อย่างมาก
✅การสนับสนุนที่ตลก
ผู้สนับสนุนช่วยในการพัฒนาและบำรุงรักษาห้องสมุด NGNEAT อย่างต่อเนื่อง พิจารณาขอให้ บริษัท ของคุณสนับสนุน Ngneat เป็นหลักในการพัฒนาธุรกิจและการพัฒนาแอปพลิเคชัน
ยกระดับการสนับสนุนของคุณด้วยการเป็นผู้สนับสนุนทองคำและให้โลโก้ของคุณโดดเด่นใน readme ของเราในที่เก็บ 5 อันดับแรก
เพิ่มการสนับสนุนของคุณด้วยการเป็นสปอนเซอร์ทองคำและเพลิดเพลินไปกับสปอตไลท์ด้วยโลโก้ของคุณที่จัดแสดงอย่างเด่นชัดในที่เก็บ 3 อันดับแรกใน ReadMe ของเรา

เป็นสปอนเซอร์บรอนซ์และรับโลโก้ของคุณบน readme ของเราใน GitHub
คุณสมบัติ
สารบัญ
การติดตั้ง
NPM
เส้นด้าย
ส่วนประกอบการทดสอบ
มุมมองที่เลื่อนออกไป
ตัวเลือกสตริง
ประเภทตัวเลือก
ตัวเลือก DOM
การทดสอบองค์ประกอบเลือก
ส่วนประกอบที่เยาะเย้ย
การทดสอบโมดูลเชิงมุมส่วนประกอบ/คำสั่งเดียว
กิจกรรมที่กำหนดเอง
ผู้สร้างงาน
กิจกรรม API
ผู้ช่วยคีย์บอร์ด
ผู้ช่วยเมาส์
การสอบถาม
มุมมองที่เลื่อนออกไปได้
การทดสอบกับโฮสต์
ส่วนประกอบโฮสต์ที่กำหนดเอง
การทดสอบด้วยการกำหนดเส้นทาง
ทริกเกอร์การนำทาง
การทดสอบการรวมเข้ากับ RouterTestingModule
ตัวเลือกการกำหนดเส้นทาง
คำสั่งทดสอบ
บริการทดสอบ
ตัวเลือกเพิ่มเติม
การทดสอบท่อ
การใช้ส่วนประกอบโฮสต์ที่กำหนดเอง
ผู้ให้บริการที่เยาะเย้ย
เยาะเย้ยการพึ่งพา
เยาะเย้ยการพึ่งพาตัวสร้าง
การสนับสนุนตลก
การทดสอบด้วย http
การฉีดยาทั่วโลก
ผู้ให้บริการส่วนประกอบ
คู่จับคู่ที่กำหนดเอง
แผนผัง
คอลเลกชันแผนผังเริ่มต้น
ผู้ชมที่ใช้งานได้และการเปรียบเทียบตัวอย่าง repo และ Karma
ทีมหลัก
ผู้มีส่วนร่วม
npm install @ngneat/spectator --save-dev
yarn add @ngneat/spectator --dev
สร้างส่วนประกอบโรงงานโดยใช้ฟังก์ชัน createComponentFactory() ผ่านคลาสส่วนประกอบที่คุณต้องการทดสอบ createComponentFactory() ส่งคืนฟังก์ชั่นที่จะสร้างองค์ประกอบใหม่ในแต่ละบล็อก it :
นำเข้า {spectator, createComponentFactory} จาก '@ngneat/spectator'; นำเข้า {buttoncomponent} จาก './button.Component';describe('ButtonComponent', () => {
ให้ผู้ชม: ผู้ชม <putbonce Component>;
const createComponent = createComponentFactory (button -Component);
ก่อนหน้า (() => ผู้ชม = createComponent ());
มัน ('ควรมีคลาสความสำเร็จตามค่าเริ่มต้น', () => {คาดหวัง (spectator.query ('ปุ่ม')). tohaveclass ('ความสำเร็จ');
-
มัน ('ควรตั้งค่าชื่อคลาสตาม [className] อินพุต', () => {spectator.setInput ('className', 'Danger'); คาดหวัง (spectator.Query ('ปุ่ม')). Danger '); คาดหวัง (spectator.query (' ปุ่ม ')). not.toHaveClass (' ความสำเร็จ ');
- ฟังก์ชั่น createComponentFactory สามารถเลือกตัวเลือกต่อไปนี้ซึ่งขยายตัวเลือกโมดูลการทดสอบเชิงมุมพื้นฐาน:
const createComponent = createComponentFactory ({
ส่วนประกอบ: ButtonComponent,
นำเข้า: [],
ผู้ให้บริการ: [],
การประกาศ: [],
ส่วนประกอบ: [],
ComponentProviders: [], // แทนที่ผู้ให้บริการของส่วนประกอบ
ComponentViewProviders: [], // แทนที่ผู้ให้บริการมุมมองของส่วนประกอบ
overridemodules: [], // แทนที่โมดูล
overridecomponents: [], // ส่วนประกอบแทนที่ในกรณีของการทดสอบองค์ประกอบแบบสแตนด์อโลน
overriedirectives: [], // แทนที่คำสั่งในกรณีของการทดสอบคำสั่งแบบสแตนด์อโลน
overridepipes: [], // การแทนที่ท่อในกรณีของการทดสอบท่อแบบสแตนด์อโลน
Mocks: [], // ผู้ให้บริการที่จะถูกล้อเลียนโดยอัตโนมัติ
ComponentMocks: [], // ผู้ให้บริการส่วนประกอบที่จะถูกล้อเลียนโดยอัตโนมัติ
ComponentViewProvidersMocks: [], // ผู้ให้บริการมุมมองส่วนประกอบที่จะเยาะเย้ยโดยอัตโนมัติ
DetectChanges: FALSE, // ค่าเริ่มต้นเป็นจริง
ประกาศ: false, // ค่าเริ่มต้นเป็นจริง
disableanimations: false, // ค่าเริ่มต้นเป็นจริง
ตื้น: จริง // ค่าเริ่มต้นเป็นเท็จ
deferblockbehavior: deferblockbehavior // ค่าเริ่มต้นเป็น deferblockbehavior.playthrough}); ฟังก์ชั่น createComponent() เลือกใช้ตัวเลือกต่อไปนี้:
มัน ('ควร ... ', () => {
spectator = createComponent ({// ส่วนประกอบ inputsprops: {title: 'คลิก'}, // แทนที่ผู้ให้บริการของส่วนประกอบ // โปรดทราบว่าคุณต้องประกาศครั้งเดียวใน `createComponentFactory`providers: [] // ว่าจะเรียกใช้การตรวจจับการเปลี่ยนแปลงการเปลี่ยนแปลง (ค่าเริ่มต้นเป็นจริง) DetectChanges: FALSE
-
คาดหวัง (spectator.query ('ปุ่ม')). tohavetext ('คลิก');}); ด้วยการจัดหาตัวเลือก overrideComponents ในขอบเขตของฟังก์ชั่น createComponent() ของเราเราสามารถกำหนดวิธีการเอาชนะส่วนประกอบแบบสแตนด์อโลนและการพึ่งพา
@ส่วนประกอบ({
ตัวเลือก: `แอพ-มาตรฐาน-กับอิมพอร์ต '
เทมเพลต: `<div id =" สแตนด์อโลน "> ส่วนประกอบแบบสแตนด์อโลนพร้อมการนำเข้า! </div> <แอพ-สแตนด์อโลน-พึ่งพาอาศัยกัน> </แอพ-มาตรฐาน-พึ่งพาอาศัยกัน>`,,,,,
นำเข้า: [standalonecomponentwithDependency],
แบบสแตนด์อโลน: จริง,}) การส่งออกคลาสสแตนด์อโลนวิทเทมพอร์ตสโตร์ {} @component ({
ตัวเลือก: `แอพ-มาตรฐาน-พึ่งพาอาศัยกัน '
เทมเพลต: `<div id =" standalonewithDependency "> องค์ประกอบสแตนด์อโลนที่มีการพึ่งพา! </div>`,,,
แบบสแตนด์อโลน: จริง,}) การส่งออกคลาสสแตนด์อโลนคอมโพเนทการพึ่งพาอาศัยกัน {
Constructor (Query Public: QueryService) {}}@Component ({
ตัวเลือก: `แอพ-มาตรฐาน-พึ่งพาอาศัยกัน '
เทมเพลต: `<div id =" standalonewithDependency "> องค์ประกอบสแตนด์อโลนที่มีการพึ่งพาแทนที่! </div>`,,,,,
แบบสแตนด์อโลน: จริง,}) การส่งออกคลาส mockstandalonecomponentwithDependency {
constructor () {}} มัน ('ควร ... ', () => {
const spectator = createHostFactory ({ส่วนประกอบ: standalOnewithImportScomponent, เทมเพลต: `<div> <แอพ-สแตนด์อโลน-with-import> </แอพ-สแตนดาร์ {นำเข้า: [standalonecomponentWithDependency]}, เพิ่ม: {imports: [mockstandalonecomponentwithDependency]},},],],],],],],],],],],],],]
-
คาดหวัง (host.query ('#standalone')). tocontaintext ('องค์ประกอบสแตนด์อโลนที่มีการนำเข้า!');
คาดหวัง (host.Query ('#standalonewithDependency')). tocontaintext ('องค์ประกอบสแตนด์อโลนที่มีการพึ่งพาแทนที่!');}); เมธอด createComponent() ส่งคืนอินสแตนซ์ของ Spectator ซึ่งเปิดเผย API ต่อไปนี้:
fixture - การติดตั้งของส่วนประกอบที่ทดสอบ
component - อินสแตนซ์ของส่วนประกอบที่ทดสอบ
element - องค์ประกอบดั้งเดิมขององค์ประกอบที่ทดสอบ
debugElement - องค์ประกอบการดีบักของการแข่งขันที่ทดสอบแล้ว
flushEffects() - จัดให้มี wrapper สำหรับ TestBed.flushEffects()
inject() - จัดเตรียม wrapper สำหรับ TestBed.inject() :
const service = spectator.Inject (QueryService); const from -ComponentInjector = true; const service = spectator.inject (QueryService, FromComponentInjector);
detectChanges() - รัน DetectChanges บนองค์ประกอบที่ทดสอบ/โฮสต์:
ผู้ชม. detectchanges ();
detectComponentChanges() - เรียกใช้ detectChanges บนส่วนประกอบ ที่ทดสอบ (ไม่ได้อยู่ใน host ) คุณจะต้องใช้วิธีนี้ในบางกรณี ที่หายาก เมื่อใช้ host และส่วนประกอบที่ทดสอบคือ onPush และคุณต้องการบังคับให้ใช้งานรอบการตรวจจับการเปลี่ยนแปลง
Spectator.DetectComponentChanges ();
setInput() - เปลี่ยนค่าของ @Input () ของส่วนประกอบที่ทดสอบ วิธีการทำงาน ngOnChanges ด้วย SimpleChanges ด้วยตนเองหากมีอยู่
มัน ('ควร ... ', () => {
Spectator.setInput ('classname', 'Danger');
spectator.setInput ({classname: 'Danger'
- output - ส่งคืน @Output () ที่สังเกตได้ของส่วนประกอบที่ทดสอบ:
มัน ('ควรปล่อย Event on on Click', () => {
ปล่อยให้เอาต์พุต;
Spectator.Output ('คลิก') สมัครสมาชิก (result => (output = ผลลัพธ์));
spectator.component.onclick ({type: 'คลิก'});
คาดหวัง (เอาท์พุท) .toequal ({ประเภท: 'คลิก'});}); tick(millis?: number) - เรียกใช้ฟังก์ชั่น fakeasync tick() และโทร detectChanges() ::
มัน ('ควรทำงานกับ tick', fakeasync (() => {
ผู้ชม = createComponent (zippycomponent);
ผู้ชม. component.update ();
คาดหวัง (spectator.component.updatedasync) .tobefalsy ();
ผู้ชมทิก (6000);
คาดหวัง (spectator.component.updatedasync) .not.tobefalsy ();})) แต่ละเหตุการณ์สามารถยอมรับ SpectatorElement ซึ่งสามารถเป็นหนึ่งในสิ่งต่อไปนี้:
พิมพ์ SpectatorElement = String | องค์ประกอบ | debugelement | Elementref | หน้าต่าง | เอกสาร | domselector;
หากไม่ได้ให้องค์ประกอบเริ่มต้นจะเป็นองค์ประกอบโฮสต์ของส่วนประกอบภายใต้การทดสอบ
click() - ทริกเกอร์เหตุการณ์คลิก:
spectator.lick (spectatorelement); spectator.lick (bytext ('องค์ประกอบ')); blur() - ทริกเกอร์เหตุการณ์เบลอ:
spectator.blur (spectatorelement); spectator.blur (bytext ('องค์ประกอบ'));โปรดทราบว่าหากการใช้กรอบการใช้งาน JEST เบลอ () จะทำงานได้ก็ต่อเมื่อองค์ประกอบนั้นมุ่งเน้น รายละเอียด.
focus() - ทริกเกอร์เหตุการณ์โฟกัส:
spectator.focus (spectatorelement); spectator.focus (bytext ('องค์ประกอบ')); typeInElement() - การจำลองการพิมพ์ของผู้ใช้:
Spectator.TypeinElement (ค่า, ผู้ชม); ผู้ชม. TYPEinElement (ค่า, bytext ('องค์ประกอบ')); dispatchMouseEvent() - ทริกเกอร์เหตุการณ์เมาส์:
spectator.dispatchmousevent (spectatorelement, 'mouseout'); spectator.dispatchmousevent (spectatorelement, 'mouseout'), x, y, event); spectator.dispatchmousevent (bytext ('องค์ประกอบ'), 'mouseout'); ('องค์ประกอบ'), 'mouseout', x, y, เหตุการณ์); dispatchKeyboardEvent() - ทริกเกอร์เหตุการณ์แป้นพิมพ์:
spectator.dispatchkeyboardEvent (spectatorelement, 'keyup', 'Escape'); spectator.dispatchkeyboardEvent (spectatorelement, 'Keyup', {key: 'Escape', Keycode: 27}) ผู้ชม ',' Escape '); spectator.dispatchKeyBoardEvent (bytext (' องค์ประกอบ '),' keyup ', {key:' Escape ', Keycode: 27}) dispatchTouchEvent() - ทริกเกอร์เหตุการณ์สัมผัส:
spectator.dispatchTouchEvent (spectatorElement, ประเภท, x, y); spectator.dispatchTouchEvent (bytext ('องค์ประกอบ'), ประเภท, x, y);คุณสามารถทริกเกอร์เหตุการณ์ที่กำหนดเอง (@Output () ของส่วนประกอบเด็ก) โดยใช้วิธีการต่อไปนี้:
Spectator.TriggerEventHandler (MyChildComponent, 'Mycustomevent', 'EventValue'); ผู้ชม TriggerEventHandler (MyChildComponent, 'Mycustomevent', 'EventValue', {root: true}); ',' EventValue '); Spectator.TriggerEventHandler (' App-Child-Component ',' Mycustomevent ',' EventValue ', {root: true});ในกรณีที่คุณต้องการทดสอบเหตุการณ์ที่เป็นอิสระจากเทมเพลตใด ๆ (เช่นในบริการผู้นำเสนอ) คุณสามารถย้อนกลับไปที่ผู้สร้างเหตุการณ์พื้นฐาน โดยทั่วไปแล้วจะให้ลายเซ็นเดียวกันโดยไม่มีองค์ประกอบก่อนหน้า
const keyboardEvent = createKeyBoardEvent ('keyup', 'Arrowdown'/ *, targetElement */); const MouseEvent = createMouseVent ('MouseOut'); const touchEvent = createToUTUCHEVENT ('TouchMove'); 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 วิธีการสืบค้นทั้งหมดเป็น polymorphic และอนุญาตให้คุณสืบค้นโดยใช้เทคนิคใด ๆ ต่อไปนี้
ผ่านตัวเลือกสตริง (ในสไตล์เดียวกับที่คุณใช้เมื่อใช้ jQuery หรือ document.querySelector) เพื่อสอบถามองค์ประกอบที่ตรงกับเส้นทางนั้นใน DOM วิธีการสอบถามนี้เทียบเท่ากับ Angular BY.CSS Predicate โปรดทราบว่าองค์ประกอบ HTML ดั้งเดิมจะถูกส่งคืน ตัวอย่างเช่น:
// ส่งคืน htmlelementspectator.query เดียว ('div> ul.nav li: first-cild'); // ส่งคืนอาร์เรย์ของ htmlelementsspectator.queryall ('div> ul.nav li'); Document ContextSator.Query ('div', {root: true}); spectator.query ('App-Child', {อ่าน: ChildServiceservice}); ผ่านประเภท (เช่นคลาสส่วนประกอบคำสั่งหรือผู้ให้บริการ) เพื่อสอบถามสำหรับอินสแตนซ์ของประเภทนั้นใน DOM สิ่งนี้เทียบเท่ากับ Angular By.directive Predicate คุณสามารถเลือกผ่านพารามิเตอร์ที่สองเพื่ออ่านโทเค็นการฉีดเฉพาะจากหัวฉีดองค์ประกอบที่ตรงกัน ตัวอย่างเช่น:
// ส่งคืนอินสแตนซ์เดียวของ myComponent (ถ้ามี) spectator.query (myComponent); // ส่งคืนอินสแตนซ์ของ `someservice` พบในอินสแตนซ์ของ` myComponent` ที่มีอยู่ในผู้ชม DOM (ถ้าปัจจุบัน) , {อ่าน: someservice}); spectator.Query (myComponent, {อ่าน: ElementRef}); host.QueryLast (childComponent); host.queryall (childcomponent);ผู้ชมช่วยให้คุณสามารถสืบค้นองค์ประกอบโดยใช้ตัวเลือกที่ได้รับแรงบันดาลใจจากการทดสอบ DOM-Testing-Library ตัวเลือกที่มีอยู่คือ:
Spectator.Query (Byplaceholder ('โปรดป้อนที่อยู่อีเมลของคุณ')); spectator.query (Byvalue ('by value')); spectator.query (bytitle ('โดยชื่อ')); spectator.query (byaltText (' text alt ')); spectator.Query (bylabel (' โดย label ')); spectator.Query (bytext (' by text ')); spectator.Query (bytext (' โดยข้อความ ', {ตัวเลือก:' #Some ตัวเลือก '})); spectator.Query (bytextContent (' โดยเนื้อหาข้อความ ', {ตัวเลือก:' #SOME .Selector '}))); spectator.Query (byrole (' ช่องทำเครื่องหมาย ', {ตรวจสอบ: จริง})); ความแตกต่างระหว่าง byText และ byTextContent คืออดีตไม่ตรงกับข้อความภายในองค์ประกอบที่ซ้อนกัน
ตัวอย่างเช่นใน html byText('foobar', {selector: 'div'}) จะไม่ตรงกับ div ต่อไปนี้ แต่ byTextContent จะ:
<div> <span> foo </span> <span> bar </span> </div>
ผู้ชมช่วยให้คุณสามารถสอบถามองค์ประกอบที่ซ้อนกันภายในองค์ประกอบหลัก สิ่งนี้มีประโยชน์เมื่อคุณมีหลายอินสแตนซ์ของส่วนประกอบเดียวกันในหน้าและคุณต้องการสอบถามสำหรับเด็กภายในหนึ่ง ตัวเลือกหลักคือตัวเลือกสตริงที่ใช้ในการค้นหาองค์ประกอบหลัก ตัวเลือกหลักจะถูกส่งผ่านเป็นพารามิเตอร์ที่สองไปยังวิธีการสืบค้น ตัวอย่างเช่น:
spectator.Query (ChildComponent, {ผู้ปกครอง: '#parent-component-1'}); spectator.Queryall (childComponent, {ParenterfElector: '#parent-component-1'}); ผู้ชมอนุญาตให้คุณทดสอบ <select></select> องค์ประกอบได้อย่างง่ายดายและรองรับ Multi Select
ตัวอย่าง:
มัน ('ควรตั้งค่าตัวเลือกที่ถูกต้องใน Multi Select', () => {
const select = spectator.query ('#test-multi-select') เป็น htmlselectelement;
Spectator.SelectOption (เลือก, ['1', '2']);
คาดหวัง (เลือก) .toHaveselectedOptions (['1', '2']);}); มัน ('ควรตั้งค่าตัวเลือกที่ถูกต้องในการเลือกมาตรฐาน', () => {
const select = spectator.query ('#test-single-select') เป็น htmlselectelement;
Spectator.SelectOption (เลือก, '1');
คาดหวัง (เลือก) .toHaveselectedOptions ('1');}); นอกจากนี้ยังช่วยให้คุณตรวจสอบว่าตัวจัดการเหตุการณ์ change ของคุณทำงานอย่างถูกต้องสำหรับแต่ละรายการที่เลือกหรือไม่ คุณสามารถปิดการใช้งานสิ่งนี้ได้หากคุณต้องการตั้งค่าตัวเลือกล่วงหน้าโดยไม่ต้องส่งเหตุการณ์การเปลี่ยนแปลง
API:
spectator.selectOption (SelectElement: HTMLSeleCtElement, ตัวเลือก: String | String [] | HTMLOPTIONELEMENT | HTMLOPTIONELEMENT [], config: {emitevents: บูลีน} = {emitevents: true});ตัวอย่าง:
มัน ('ควรจัดส่งจำนวนเหตุการณ์การเปลี่ยนแปลงที่ถูกต้อง', () => {
const onChangespy = Spyon (ผู้ชม. Component, 'handlechange');
const select = spectator.Query ('#ทดสอบ-แยก-เลือก') เป็น htmlselectelement;
spectator.selectoption (เลือก, ['1', '2'], {emitevents: true});
คาดหวัง (เลือก) .toHaveselectedOptions (['1', '2']);
คาดหวัง (onchangespy) .tohavebeencalledTimes (2);}); ('ไม่ควรส่งจำนวนเหตุการณ์การเปลี่ยนแปลงที่ถูกต้อง' () () => {
const onChangespy = Spyon (ผู้ชม. Component, 'handlechange');
const select = spectator.Query ('#ทดสอบ-แยก-เลือก') เป็น htmlselectelement;
spectator.selectoption (เลือก, ['1', '2'], {emitevents: false});
คาดหวัง (เลือก) .toHaveselectedOptions (['1', '2']);
คาดหวัง (onchangespy) .not.toHaveBeencalledTimes (2);}); นอกจากนี้คุณยังสามารถส่ง HTMLOptionElement (S) เป็นอาร์กิวเมนต์ในการ selectOption และตัวจับคู่ toHaveSelectedOptions สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อคุณใช้ [ngValue] ผูกพันกับ <option> ::
มัน ('ควรตั้งค่าตัวเลือกที่ถูกต้องในการเลือกเดียวเมื่อผ่านองค์ประกอบ', () => {
const select = spectator.query ('#test-single-select-element') เป็น htmlselectelement;
spectator.selectOption (เลือก, ผู้ชม. QUARY (BYTEXT ('สอง')) เป็น HTMLOPTIONELEMENT);
คาดหวัง (เลือก) .toHaveselectedOptions (spectator.query (bytext ('สอง')) เป็น htmloptionelement);}); หากคุณต้องการเยาะเย้ยส่วนประกอบคุณสามารถใช้ไลบรารี NG-mocks แทนที่จะใช้ CUSTOM_ELEMENTS_SCHEMA ซึ่งอาจซ่อนปัญหาบางอย่างและจะไม่ช่วยให้คุณตั้งค่าอินพุตเอาต์พุต ฯลฯ ng-mocks จะทำการเยาะเย้ยอินพุตเอาต์พุต ฯลฯ สำหรับคุณ
ตัวอย่าง:
นำเข้า {createHostFactory} จาก '@ngneat/spectator'; นำเข้า {mockComponent} จาก 'ng-mocks'; นำเข้า {foocomponent} จาก './path/to/foo.Component';
ส่วนประกอบ: คุณคอมโพเนนต์
การประกาศ: [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],
Declarecomponent: false,}); เมื่อใช้ createDirectivefactory ตั้งค่าคุณสมบัติ declareDirective ของตัวเลือกโรงงานเป็น false :
const createDirective = createDirectiveFactory ({
ส่วนประกอบ: ไฮไลต์คอมโพเนนต์
นำเข้า: [ไฮไลต์คอมโพเนนต์โมดูล]
ประกาศ: เท็จ,}); ผู้ชมมี API ที่สะดวกในการเข้าถึงมุมมองที่เลื่อนเวลา ( @defer {} )
เข้าถึงบล็อก Delfer ที่ต้องการโดยใช้วิธี spectator.deferBlock(optionalIndex) พารามิเตอร์ optionalIndex เป็นตัวเลือกและอนุญาตให้คุณระบุดัชนีของบล็อกเลื่อนที่คุณต้องการเข้าถึง
การเข้าถึงบล็อกการเลื่อนเวลาแรก : เพียงแค่เรียก spectator.deferBlock()
การเข้าถึงบล็อกเลื่อนเวลาที่ตามมา : ใช้ดัชนีที่เกี่ยวข้องเป็นอาร์กิวเมนต์ ตัวอย่างเช่น spectator.deferBlock(1) เข้าถึงบล็อกที่สอง (การจัดทำดัชนีที่อิงกับศูนย์)
spectator.deferBlock(optionalIndex) ส่งคืนสี่วิธีสำหรับการแสดงสถานะที่แตกต่างกันของบล็อกการเลื่อนเวลาที่ระบุ:
renderComplete() - แสดงสถานะ ที่สมบูรณ์ ของบล็อกการเลื่อนเวลา
renderPlaceholder() - แสดงสถานะ ตัวยึดตำแหน่ง ของบล็อกเลื่อน
renderLoading() - แสดงสถานะ การโหลด ของบล็อกเลื่อนออก
renderError() - แสดงสถานะ ข้อผิดพลาด ของบล็อกเลื่อนออก
ตัวอย่าง:
@Component ({selector: 'app-cmp', เทมเพลต: `@defer (บน viewport) {<div> สถานะที่สมบูรณ์ของบล็อกเลื่อนครั้งแรก </div> <! <div> placeholder </div>} `,}) คลาส dummycomponent {} const createComponent = createComponentFactory ({องค์ประกอบ: dummycomponent, deferblockbehavior: deferblockbehavior.anual,}); > {// จัดเรียงผู้ชม const = createComponent (); ในการเข้าถึงสถานะภายในบล็อกเลื่อนเวลาที่ซ้อนกันให้เรียกใช้วิธีการ เลื่อนลอย deferBlock จากวิธีการบล็อกที่ส่งคืน
ตัวอย่าง: การเข้าถึงรัฐที่สมบูรณ์แบบ:
// สมมติว่า `spectator.deferblock (0) .RenderComplete ()` แสดงสถานะที่สมบูรณ์ของการเลื่อนบล็อก ParentConstATESTATE = รอผู้ชม. deferBlock () RenderComplete (); // เข้าถึงสถานะที่สมบูรณ์ = รอ ParentcompleTestate.rendercomplete (). deferblock ();
ตัวอย่างที่สมบูรณ์ :
@Component ({selector: 'app-cmp', เทมเพลต: `@defer (บน viewport) {<div> สถานะที่สมบูรณ์ของบล็อกเลื่อนครั้งแรก </div> <!-สถานะที่สมบูรณ์ของพาเรนต์-> @defer {< div> สถานะที่สมบูรณ์ของบล็อกเลื่อนที่ซ้อนกัน </div> <!-สถานะที่สมบูรณ์แบบซ้อนกัน->}} @plockholder {<div> สถานที่ </div>} `,}) คลาส dummycomponent {} const createComponent = createComponentFactory ( {ส่วนประกอบ: dummycomponent, deferblockbehavior: deferblockbehavior.anual,}); มัน ('ควรแสดงสถานะที่สมบูรณ์แบบแรกที่สมบูรณ์', async () => {// จัดเรียง const ผู้ชม = createComponent (); // พระราชบัญญัติ // Const Const ParentcompleTestate = Await ผู้ชม. deferblock (). rendercomplete (); เลื่อนบล็อก ');});การทดสอบส่วนประกอบด้วยส่วนประกอบโฮสต์เป็นเทคนิคที่สง่างามและทรงพลังกว่าในการทดสอบส่วนประกอบของคุณ โดยทั่วไปจะช่วยให้คุณสามารถเขียนการทดสอบของคุณในลักษณะเดียวกับที่คุณเขียนรหัสของคุณ มาดูกันว่าในการดำเนินการ:
นำเข้า {createHostFactory, spectatorhost} จาก '@ngneat/spectator'; อธิบาย ('zippycomponent', () => {
ให้ผู้ชม: Spectatorhost <ZippyComponent>;
const createHost = createHostFactory (zippycomponent);
มัน ('ควรแสดงชื่อจากคุณสมบัติโฮสต์', () => {spectator = createHost (`<zippy [title] =" title "> </zippy>`, {hostprops: {title: 'ผู้ชมยอดเยี่ยม'}} }); คาดหวัง (spectator.query ('. zippy__title')). tohavetext ('ผู้ชมยอดเยี่ยม');
-
มัน ('ควรแสดง "ปิด" คำว่าเปิด', () => {spectator = createHost (`<zippy title =" zippy title "> เนื้อหา zippy </zippy>`); spectator.lick ('. zippy__title' ); คาดหวัง (spectator.query ('. Arrow')). tohavetext ('close'); คาดหวัง (spectator.query ('. Arrow')). not.toHavetext ('เปิด');
- วิธีการโฮสต์ส่งคืนอินสแตนซ์ของ SpectatorHost ซึ่งขยาย Spectator ด้วย API เพิ่มเติมต่อไปนี้:
hostFixture - การแข่งขันของโฮสต์
hostComponent - อินสแตนซ์ส่วนประกอบของโฮสต์
hostElement - องค์ประกอบดั้งเดิมของโฮสต์
hostDebugElement - องค์ประกอบการดีบักของโฮสต์
setHostInput - เปลี่ยนค่าของ @Input() ของส่วนประกอบโฮสต์
queryHost - อ่านเพิ่มเติมเกี่ยวกับการสืบค้นในผู้ชม
queryHostAll - อ่านเพิ่มเติมเกี่ยวกับการสืบค้นในผู้ชม
การตั้งค่าอินพุตโดยตรงบนส่วนประกอบโดยใช้ setInput หรือ props เป็นไปไม่ได้เมื่อทดสอบกับส่วนประกอบโฮสต์ ควรตั้งค่าอินพุตผ่าน hostProps หรือ setHostInput แทนและส่งผ่านไปยังส่วนประกอบของคุณในเทมเพลต
บางครั้งการผ่านการใช้โฮสต์ของคุณเองก็มีประโยชน์ เราสามารถผ่านส่วนประกอบโฮสต์ที่กำหนดเองไปยัง createHostFactory() ที่จะแทนที่ค่าเริ่มต้น:
@Component ({selector: 'custom-host', เทมเพลต: ''}) คลาส CustomhostComponent {
title = 'Custom HostComponent';} อธิบาย ('ด้วยองค์ประกอบโฮสต์ที่กำหนดเอง', function () {
ให้ผู้ชม: Spectatorhost <zippycomponent, contherhostComponent>;
const createHost = createHostFactory ({Component: zippycomponent, host: contherhostComponent
-
มัน ('ควรแสดงชื่อส่วนประกอบโฮสต์', () => {spectator = createHost (`<zippy [title] =" title "> </zippy>`); คาดหวัง .toHavetext ('โฮสต์โฮสต์ที่กำหนดเอง');
- สำหรับส่วนประกอบที่ใช้การกำหนดเส้นทางมีโรงงานพิเศษที่ขยายค่าเริ่มต้นและให้ ActivatedRoute stubbed เพื่อให้คุณสามารถกำหนดค่าตัวเลือกการกำหนดเส้นทางเพิ่มเติม
อธิบาย ('ProductDetailScomponent', () => {
ให้ผู้ชม: spectatorrouting <productDetailScomponent>;
const createComponent = createroutingFactory ({Component: ProductDetailScomponent, params: {productId: '3'}, ข้อมูล: {title: 'ชื่อบางชื่อ'}
-
ก่อนหน้า (() => ผู้ชม = createComponent ());
มัน ('ควรแสดงชื่อข้อมูลเส้นทาง', () => {คาดหวัง (spectator.query ('. title')). tohavetext ('บางชื่อ');
-
มัน ('ควรตอบสนองต่อการเปลี่ยนแปลงเส้นทาง', () => {spectator.setRouteParam ('productId', '5'); // การทดสอบของคุณที่นี่ ...
- API SpectatorRouting รวมถึงวิธีการที่สะดวกสำหรับการอัปเดตเส้นทางปัจจุบัน:
อินเตอร์เฟส spectatorrouting <c> ขยายผู้ชม <c> {
/*** จำลองการนำทางเส้นทางโดยการอัปเดตพารามิเตอร์ queryParams และสตรีมที่สังเกตได้ -
TriggerNavigation (ตัวเลือก?: RouteOptions): เป็นโมฆะ;
/*** อัปเดตพารามิเตอร์เส้นทางและทริกเกอร์การนำทางเส้นทาง -
setRouteParam (ชื่อ: สตริง, ค่า: สตริง): โมฆะ;
/*** อัปเดตพารามิเตอร์การสืบค้นเส้นทางและทริกเกอร์การนำทางเส้นทาง -
SetRouteQueryParam (ชื่อ: สตริง, ค่า: สตริง): โมฆะ;
/*** อัปเดตข้อมูลเส้นทางและทริกเกอร์การนำทางเส้นทาง -
setRoutedata (ชื่อ: สตริง, ค่า: ใด ๆ ): โมฆะ;
/*** อัปเดตชิ้นส่วนเส้นทางและทริกเกอร์การนำทางเส้นทาง -
SetRouteFragment (แฟรกเมนต์: สตริง | null): โมฆะ;
/*** อัปเดต URL เส้นทางและทริกเกอร์การนำทางเส้นทาง -
SetRouteurl (URL: urlsegment []): void;}RouterTestingModule หากคุณตั้งค่าตัวเลือก stubsEnabled เป็น false คุณสามารถผ่านการกำหนดค่าการกำหนดเส้นทางจริงและตั้งค่าการทดสอบการรวมโดยใช้ RouterTestingModule จาก Angular
โปรดทราบว่าสิ่งนี้ต้องการสัญญาที่จะแก้ไข วิธีหนึ่งในการจัดการกับสิ่งนี้คือการทำแบบทดสอบของคุณ Async:
อธิบาย ('การทดสอบการรวมเส้นทาง', () => {
const createComponent = createroutingFactory ({ส่วนประกอบ: myComponent, การประกาศ: [อื่น ๆ คอมโพเนนต์], stubsenabled: เท็จ, เส้นทาง: [{path: '', ส่วนประกอบ: myComponent}, {path: 'foo', ส่วนประกอบ: องค์ประกอบอื่น ๆ }]]
-
มัน ('ควรนำทางไปโดยใช้ลิงก์เราเตอร์', async () => {const ผู้ชม = createComponent (); // รอสัญญาที่จะแก้ไข ... รอผู้ชม. fixture.wenstable (); // ทดสอบเส้นทางปัจจุบันโดย ยืนยันตำแหน่งที่ตั้งไว้ (spectator.Inject (ตำแหน่ง) .Path ()). tobe ('/'); // คลิกที่ลิงก์เราเตอร์ linkspectator.lick ('. link-1'); // อย่าลืมรอ สัญญาที่จะแก้ไข ... รอผู้ชม. fixture.whenstable (); // ทดสอบเส้นทางใหม่โดยการอ้างถึงตำแหน่ง (spectator.inject (ตำแหน่ง) .path ()). tobe ('/foo');
- ฟังก์ชั่น createRoutesFactory สามารถใช้ตัวเลือกต่อไปนี้ได้ที่ด้านบนของตัวเลือกผู้ชมเริ่มต้น:
params : พารามิเตอร์เริ่มต้นที่จะใช้ใน ActivatedRoute Stub
queryParams : พารามิเตอร์การสืบค้นเริ่มต้นที่จะใช้ใน ActivatedRoute Stub
data : ข้อมูลเริ่มต้นที่จะใช้ใน ActivatedRoute Stub
fragment : ชิ้นส่วนเริ่มต้นที่จะใช้ใน ActivatedRoute stub
url : ส่วน URL เริ่มต้นที่จะใช้ใน ActivatedRoute Stub
root : ค่าสำหรับ root สำหรับต้นขั้ว ActivatedRoute
parent : ค่าสำหรับ parent สำหรับ ActivatedRoute stub
children : ค่าสำหรับ children สำหรับ stub ActivatedRoute
firstChild : ค่าสำหรับ firstChild สำหรับ ActivatedRoute Stub
stubsEnabled (ค่าเริ่มต้น: true ): เปิดใช้ ActivatedRoute stub หากตั้งค่าเป็น false จะใช้ RouterTestingModule แทน
routes : หาก stubsEnabled ถูกตั้งค่าเป็น FALSE คุณสามารถผ่านการกำหนด Routes สำหรับ RouterTestingModule
มีโรงงานทดสอบพิเศษสำหรับการทดสอบคำสั่ง สมมติว่าเรามีคำสั่งดังต่อไปนี้:
@Directive ({ตัวเลือก: '[ไฮไลต์]'}) การส่งออกคลาสไฮไลต์ไดเร็กต์ {
@hostbinding ('style.background-color') backgroundColor: String;
@HostListener ('MouseOver')
onHover () {this.backgroundColor = '#000000';
-
@HostListener ('Mouseout')
onleave () {this.backgroundColor = '#ffffff';
-มาดูกันว่าเราสามารถทดสอบคำสั่งได้อย่างง่ายดายกับผู้ชม:
อธิบาย ('ไฮไลต์ไดเร็กต์', () => {
ให้ผู้ชม: spectatordirective <highlightDirective>;
const createDirective = createDirectiveFactory (ไฮไลต์ไดเรกทอรี);
ก่อนหน้า (() => {spectator = createDirective (`<dhighlight> การทดสอบไฮไลต์คำสั่ง </div>`);
-
มัน ('ควรเปลี่ยนสีพื้นหลัง', () => {spectator.dispatchmousevent (ผู้ชม., 'mouseover'); คาดหวัง (ผู้ชม. Element) .ToHaVestyle ({พื้นหลัง: 'RGBA (0,0,0, 0.1, 0.1, 0.1, 0.1 ) '}); spectator.dispatchMouseVent (ผู้ชม. element,' mouseout '); คาดหวัง (spectator.element) .toHaVestyle ({backgroundColor:' #FFF '});
-
มัน ('ควรได้รับอินสแตนซ์', () => {const instance = spectator.directive; คาดหวัง (อินสแตนซ์) .tobedefined ();
- การตั้งค่าอินพุตโดยตรงบนคำสั่งโดยใช้ setInput หรือ props เป็นไปไม่ได้ ควรตั้งค่าอินพุตผ่าน hostProps หรือ setHostInput แทนและส่งผ่านไปยังคำสั่งของคุณในเทมเพลต
ตัวอย่างต่อไปนี้แสดงวิธีทดสอบบริการกับผู้ชม:
นำเข้า {createserviceFactory, spectatorservice} จาก '@ngneat/spectator'; นำเข้า {AuthService} จาก 'auth.service.ts'; อธิบาย ('AuthService', () => {
ให้ผู้ชม: ผู้ชม <AuthService>;
const createService = createServiceFactory (AuthService);
ก่อนหน้า (() => ผู้ชม = createService ());
มัน ('ไม่ควรลงชื่อเข้าใช้', () => {คาดหวัง (spectator.service.isloggedIn ()). tobefalsy ()
- ฟังก์ชั่น createService() ส่งคืน SpectatorService ด้วยคุณสมบัติต่อไปนี้:
service - รับอินสแตนซ์ของบริการ
inject() - พร็อกซีสำหรับ TestBed.inject()
นอกจากนี้ยังเป็นไปได้ที่จะผ่านวัตถุที่มีตัวเลือก ตัวอย่างเช่นเมื่อทำการทดสอบบริการคุณมักจะต้องการเยาะเย้ยการพึ่งพาของมันในขณะที่เรามุ่งเน้นไปที่การทดสอบบริการ
ตัวอย่างเช่น:
@injectable () Export Class AuthService {
Constructor (Dateservice ส่วนตัว: Dateservice) {}
isloggedIn () {ถ้า (this.dateservice.isexpired ('timestamp')) {return false;} return true;
- ในกรณีนี้เราสามารถเยาะเย้ยการพึ่งพา DateService
นำเข้า {createserviceFactory, spectatorservice} จาก '@ngneat/spectator'; นำเข้า {AuthService} จาก 'auth.service.ts'; อธิบาย ('AuthService', () => {
ให้ผู้ชม: ผู้ชม <AuthService>;
const createService = createServiceFactory ({Service: AuthService, ผู้ให้บริการ: [], entrycomponents: [], mocks: [dateservice]
-
ก่อนหน้า (() => ผู้ชม = createService ());
มัน ('ควรลงชื่อเข้าใช้ใน', () => {const dateservice = spectator.inject (dateservice); dateservice.isexpired.and.returnvalue (เท็จ); คาดหวัง (spectator.service.isloggedin ())
-ตัวอย่างต่อไปนี้แสดงวิธีทดสอบท่อกับผู้ชม:
นำเข้า {spectatorpipe, createpipefactory} จาก '@ngneat/spectator'; นำเข้า {statsservice} จาก './stats.service'; {sumpipe} จาก' ./sum.pipe'; {
ให้ผู้ชม: SpectatorPipe <Sumpipe>;
const createPipe = createPipeFactory (sumpipe);
มัน ('ควรสรุปรายการตัวเลข (เทมเพลต)', () => {spectator = createPipe (`{{[1, 2, 3] | sum}}`); ('6');
-
มัน ('ควรสรุปรายการตัวเลข (prop)', () => {spectator = createPipe (`{{prop | sum}}`, {hostprops: {prop: [1, 2, 3]}}}} ); คาดหวัง (ผู้ชม. element) .toHavetext ('6');
-
มัน ('ควรมอบหมายผลรวมให้กับบริการ', () => {const sum = () => 42; const ผู้ให้บริการ = {ให้: statsService, useValue: {sum}}; spectator = createpipe (`` {{prop | sum}} `, {hostprops: {prop: [2, 40]}, ผู้ให้บริการ: [ผู้ให้บริการ]}); คาดหวัง (spectator.element) .toHavetext ('42 ');
- ฟังก์ชั่น createPipe() ส่งคืน SpectatorPipe ด้วยคุณสมบัติต่อไปนี้:
hostComponent - อินสแตนซ์ของส่วนประกอบโฮสต์
debugElement - องค์ประกอบการดีบักของการติดตั้งรอบ ๆ องค์ประกอบโฮสต์
element - องค์ประกอบดั้งเดิมขององค์ประกอบโฮสต์
detectChanges() - พร็อกซีสำหรับการทดสอบเชิงมุม. TestBed.fixture.detectChanges()
inject() - พร็อกซีสำหรับ TestBed.inject()
การตั้งค่าอินพุตโดยตรงบนท่อโดยใช้ setInput หรือ props เป็นไปไม่ได้ ควรตั้งค่าอินพุตผ่าน hostProps หรือ setHostInput แทนและส่งผ่านไปยังท่อของคุณในเทมเพลต
ตัวอย่างต่อไปนี้แสดงวิธีทดสอบท่อโดยใช้ส่วนประกอบโฮสต์ที่กำหนดเอง:
นำเข้า {ส่วนประกอบ, อินพุต} จาก '@angular/core'; นำเข้า {spectatorpipe, createpipefactory} จาก '@ngneat/spectator'; นำเข้า {averagepipe} จาก './Average.pipe'; .Service ';@Component ({
เทมเพลต: `<div> {{prop | Avg}} </div> `}) คลาส CustomhostComponent {
@Input () Publ Prop: Number [] = [1, 2, 3];} อธิบาย ('AveragePipe', () => {
ให้ผู้ชม: SpectatorPipe <AveragePipe>;
const createPipe = createPipeFactory ({pipe: averagepipe, โฮสต์: contherhostComponent
-
มัน ('ควรคำนวณค่าเฉลี่ยของรายการตัวเลขที่กำหนด', () => {spectator = createPipe (); คาดหวัง (spectator.element) .toHavetext ('2');
-
มัน ('ควรส่งผลให้ 0 เมื่อรายการตัวเลขว่างเปล่า', () => {spectator = createPipe ({hostprops: {prop: []}}); คาดหวัง
-
มัน ('ควรมอบหมายการคำนวณไปยังบริการ', () => {const avg = () => 42; const ผู้ให้บริการ = {ให้: statsService, useValue: {avg}}; spectator = createPipe ({ผู้ให้บริการ: [ผู้ให้บริการ ]}); คาดหวัง (ผู้ชม. element) .toHavetext ('42 ');
-สำหรับโรงงานผู้ชมทุกคนเราสามารถเยาะเย้ยผู้ให้บริการใด ๆ ได้อย่างง่ายดาย
บริการทุกอย่างที่เราส่งผ่านไปยังคุณสมบัติ mocks จะถูกล้อเลียนโดยใช้ฟังก์ชัน mockProvider() ฟังก์ชั่น mockProvider() แปลงแต่ละวิธีเป็นสายลับจัสมิน (เช่น jasmine.createSpy() )
นี่คือวิธีการบางส่วนที่เปิดเผย:
dateservice.isexpired.and.callthrough (); dateservice.isexpired.and.callfake (() => ปลอม); dateservice.isexpired.and.throwerror ('ข้อผิดพลาด'); dateservice.isexpired.andcallfake (() => ปลอม) ; อย่างไรก็ตามหากคุณใช้ Jest เป็นกรอบทดสอบและคุณต้องการใช้กลไกการเยาะเย้ยแทนนำเข้า mockProvider() จาก @ngneat/spectator/jest สิ่งนี้จะใช้ฟังก์ชั่น jest.fn() โดยอัตโนมัติเพื่อสร้างการจำลองที่เข้ากันได้กับ jest แทน
mockProvider() ไม่รวมคุณสมบัติ ในกรณีที่คุณต้องมีคุณสมบัติในการเยาะเย้ยคุณสามารถใช้อาร์กิวเมนต์ที่ 2:
const createService = createServiceFactory ({
บริการ: Authservice,
ผู้ให้บริการ: [MockProvider (อื่น ๆ บริการ, {ชื่อ: 'Martin', emitter: New Subject (), MockedMethod: () => 'Mocked'})
-หากส่วนประกอบขึ้นอยู่กับบริการที่ถูกเยาะเย้ยในวิธีวงจรชีวิต ONINIT จำเป็นต้องปิดการตรวจจับการเปลี่ยนแปลงจนกว่าจะได้รับบริการแล้ว
ในการกำหนดค่าสิ่งนี้ให้เปลี่ยนเมธอด createComponent เพื่อให้ตัวเลือก detectChanges ตั้งค่าเป็นเท็จจากนั้นเรียกใช้ detectChanges ด้วยตนเองบนผู้ชมหลังจากตั้งค่าบริการที่ฉีด
const createComponent = createComponentFactory ({
ส่วนประกอบ: WeatherDashboardComponent}); ('ควรเรียก Weather API บน init', () => {
const spectator = createComponent ({detectChanges: false
-
const weatherservice = spectator.inject (WeatherDataapi);
Weatherservice.getWeatherData.andreturn (จาก (Mockweatherdata));
ผู้ชม. detectchanges ();
คาดหวัง (Weatherservice.getWeatherData) .toHaveBeencalled ();});หากส่วนประกอบขึ้นอยู่กับบริการที่ถูกเยาะเย้ยในตัวสร้างคุณจะต้องสร้างและกำหนดค่าการเยาะเย้ยและให้การเยาะเย้ยเมื่อสร้างส่วนประกอบ
const createComponent = createComponentFactory ({
ส่วนประกอบ: WeatherDashboardComponent}); ('ควรเรียก API สภาพอากาศในตัวสร้าง', () => {
const weatherservice = createSpyObject (WeatherDataapi);
Weatherservice.getWeatherData.andreturn (จาก (Mockweatherdata));
spectator = createComponent ({ผู้ให้บริการ: [{ให้: weatherdataapi, usevalue: weatherservice}]
-
คาดหวัง (Weatherservice.getWeatherData) .toHaveBeencalled ();});โดยค่าเริ่มต้นผู้ชมใช้จัสมินในการสร้างสายลับ หากคุณใช้ JEST เป็นกรอบทดสอบแทนคุณสามารถให้ผู้ชมสร้างสายลับที่เข้ากันได้กับ JEST
เพียงนำเข้าหนึ่งในฟังก์ชั่นต่อไปนี้จาก @ngneat/spectator/jest (แทนที่จะเป็น @ngneat/spectator) และจะใช้ jest แทน jasmine createComponentFactory() , createHostFactory() , createServiceFactory() , createHttpFactory() , mockProvider()
นำเข้า {createserviceFactory, spectatorservice} จาก '@ngneat/spectator/jest'; นำเข้า {AuthService} จาก './auth.service'; {dateservice} จาก' ./date.service'; => {
ให้ผู้ชม: ผู้ชม <AuthService>;
const createService = createServiceFactory ({Service: AuthService, Mocks: [Dateservice]
-
ก่อนหน้า (() => ผู้ชม = createService ());
มัน ('ไม่ควรลงชื่อเข้าใช้ใน', () => {const Dateservice = spectator.Inject <Tateservice> (dateservice); dateservice.isexpired.mockreturnvalue (จริง); คาดหวัง );
-
มัน ('ควรลงชื่อเข้าใช้ใน', () => {const dateservice = spectator.inject <Tateservice> (dateservice); dateservice.isexpired.mockreturnvalue (เท็จ); คาดหวัง ;
- เมื่อใช้แผนผังส่วนประกอบคุณสามารถระบุ --jest Flag เพื่อใช้การนำเข้าแบบ jest ในการตลกนำเข้าค่าเริ่มต้นอัปเดต angular.json :
"Schematics": {"@ngneat/ผู้ชม: ผู้ชม-องค์ประกอบ": {"jest": จริง
-
-ผู้ชมทำการทดสอบบริการข้อมูลซึ่งใช้โมดูล HTTP เชิงมุมง่ายขึ้นมาก ตัวอย่างเช่นสมมติว่าคุณมีบริการด้วยสามวิธีหนึ่งดำเนินการหนึ่งโพสต์และหนึ่งดำเนินการตามคำขอพร้อมกัน:
TODOSDATASERVICE คลาสส่งออก {
ตัวสร้าง (ส่วนตัว httpClient: httpClient) {}
getTodos () {return this.httpClient.get ('api/todos');
-
posttodo (id: number) {return this.httpClient.post ('api/todos', {id});
-
collecttodos () {return merge (this.httpClient.get ('/api1/todos'), thit.httpClient.get ('/api2/todos'));
-การทดสอบสำหรับบริการข้างต้นควรมีลักษณะ:
นำเข้า {createhttpfactory, httpmethod} จาก '@ngneat/spectator'; นำเข้า {todosdataservice} จาก './todos-data.service';describe('httpClient', () => {
ให้ผู้ชม: Spectatorhttp <ToDosdataservice>;
const createhttp = createhttpfactory (toDosdataservice);
ก่อนหน้า (() => ผู้ชม = createhttp ());
มัน ('สามารถทดสอบ httpclient.get', () => {spectator.service.getTodos (). สมัครสมาชิก (); spectator.expectone ('api/todos', httpmethod.get);
-
มัน ('สามารถทดสอบ httpclient.post', () => {spectator.service.posttodo (1) .subscribe (); const req = spectator.expectone ('api/todos', httpmethod.post); คาดหวัง (req request.body ['id']). toequal (1);
-
มัน ('สามารถทดสอบคำขอ http ปัจจุบัน', () => {spectator.service.getTodos (). สมัครสมาชิก (); const reqs = spectator.expectConcurrent ([{url: '/api1/todos', วิธี: httpmethod.get }, {url: '/api2/todos', วิธี: httpmethod.get}]); spectator.flushall (reqs, [{}, {}, {}]);
- เราจำเป็นต้องสร้างโรงงาน HTTP โดยใช้ฟังก์ชั่น createHttpFactory() ผ่านบริการที่คุณต้องการทดสอบ createHttpFactory() ส่งคืนฟังก์ชันที่สามารถเรียกได้เพื่อรับอินสแตนซ์ของ spectatorhttp ด้วยคุณสมบัติต่อไปนี้:
controller - พร็อกซีสำหรับ HttpTestingController เชิงมุม
httpClient - พร็อกซีสำหรับ HttpClient เชิงมุม
service - อินสแตนซ์บริการ
inject() - พร็อกซีสำหรับ TestBed.inject()
expectOne() - คาดว่าจะมีการร้องขอครั้งเดียวซึ่งตรงกับ URL ที่กำหนดและวิธีการและส่งคืนคำขอจำลอง
เป็นไปได้ที่จะกำหนดการฉีดซึ่งจะมีให้สำหรับการทดสอบแต่ละครั้งโดยไม่จำเป็นต้องประกาศอีกครั้งในการทดสอบแต่ละครั้ง:
// test.tsimport {defineGlobalsInjections} จาก '@ngneat/spectator'; นำเข้า {translocomodule} จาก '@ngneat/transloco'; defineGlobalsInjections ({{
นำเข้า: [translocomodule],}); โปรดทราบว่าจะต้องมีการเรียกว่า defineGlobalsInjections() ก่อนที่โมดูลจะถูกโหลด ใน test.ts เชิงมุมเริ่มต้นนี้หมายถึงก่อนบรรทัดนี้:
context.keys (). แผนที่ (บริบท);
โดยค่าเริ่มต้นผู้ให้บริการส่วนประกอบดั้งเดิม (เช่น providers บน @Component ) จะไม่ถูกสัมผัส
อย่างไรก็ตามในกรณีส่วนใหญ่คุณต้องการเข้าถึงผู้ให้บริการของส่วนประกอบในการทดสอบของคุณหรือแทนที่ด้วยการเยาะเย้ย
ตัวอย่างเช่น:
@ส่วนประกอบ({
เทมเพลต: '... ',
ผู้ให้บริการ: [fooservice]}) คลาส foocomponent {
Constructor (Private Fooservice: fooservice} {}
- ใช้ componentProviders เพื่อแทนที่ผู้ให้ FooService :
const createComponent = createComponentFactory ({
ส่วนประกอบ: foocomponent,
ComponentProviders: [{prost: fooservice, usevalue: somethingelse}
- หรือเยาะเย้ยบริการโดยใช้ componentMocks :
const createComponent = createComponentFactory ({
ส่วนประกอบ: foocomponent,
ComponentMocks: [fooservice]}); ในการเข้าถึงผู้ให้บริการให้รับจากหัวฉีดส่วนประกอบโดยใช้พารามิเตอร์ fromComponentInjector :
Spectator.inject (Fooservice, True)
ในทำนองเดียวกันคุณยังสามารถแทนที่ผู้ให้บริการมุมมองส่วนประกอบโดยใช้ componentViewProviders และ componentViewProvidersMocks
กฎเดียวกันนี้ยังใช้กับคำสั่งโดยใช้พารามิเตอร์ directiveProviders และ directiveMocks
คาดหวัง ('zippy__content'). not.toexist (); คาดหวัง ('. zippy__content'). tohavelength (3); คาดหวัง ('zippy__content') tohaveid ('id'); คาดหวัง zippy ')). tohaveattribute (' id ',' zippy '); คาดหวัง (spectator.query ('. zippy ')). tohaveattribute ({id:' zippy '}); ). ToHaveProperty ('ตรวจสอบ', จริง); คาดหวัง (spectator.query ('. img')). tohaveproperty ({src: 'สินทรัพย์/myimg.jpg'}); คาดหวัง ). tocontainproperty ({src: 'myimg.jpg'}); // โปรดทราบว่า tohaveclass ยอมรับคลาสเฉพาะในลำดับที่เข้มงวด หากคำสั่งซื้อไม่เกี่ยวข้องให้ปิดการใช้งานโหมดที่เข้มงวดด้วยตนเอง Expect ('zippy__Content'). tohaveclass ('คลาส'); คาดหวัง ('zippy__content') tohaveclass ('class-a, class-b'); zippy__content '). not.tohaveclass (' class-b, class-a '); คาดหวัง (' zippy__content ') tohaveclass ([' class-a ',' class-b ']; ) .not.toHaveClass (['class-b', 'class-a']); คาดหวัง ('. zippy__content'). tohaveclass ('class', {เข้มงวด: เท็จ}); คาดหวัง ('zippy__Content') tohaveclass ('class-a, class-b', {เข้มงวด: false}); คาดหวัง ('. zippy__content'). tohaveclass ('class-b, class-a', {เข้มงวด: เท็จ}); คาดหวัง (' zippy__content '). tohaveclass ([' class-b ',' class-a '], {เข้มงวด: เท็จ}); คาดหวัง (' zippy__content ') tohaveclass ([' class-b ',' class-a '] , {เข้มงวด: false}); // โปรดทราบว่า tohavetext จะมองหาการมีอยู่ของสตริงเท่านั้นไม่ใช่ถ้าสตริงเหมือนกันทุกประการ หากคุณต้องการตรวจสอบว่าสตริงนั้นเหมือนกันอย่างสมบูรณ์ให้ใช้ tohaveExactText.// โปรดทราบว่าหากคุณต้องการตรวจสอบว่าสตริงนั้นเหมือนกันอย่างสมบูรณ์ ผู้ชมตรวจสอบข้อความของแต่ละองค์ประกอบอาร์เรย์กับดัชนีขององค์ประกอบ found.expect ('zippy__content'). tohavetext ('เนื้อหา'); คาดหวัง ('zippy__content'). ']); คาดหวัง ('. zippy__content '). tohavetext ((ข้อความ) => text.includes (' .. ')); ') .tocontaintext ([' เนื้อหา A ',' เนื้อหา B ']); คาดหวัง ('. zippy__Content '). toHaveExactText (' เนื้อหา '); คาดหวัง (' zippy__Content '). toHaveExactText ([เนื้อหา A', ',' เนื้อหา b ']); คาดหวัง (' zippy__content '). tohaveexactTrimmedtext (' เนื้อหา '); คาดหวัง (' zippy__content '). tohaveexacttrimmedtext ([' เนื้อหา ',' เนื้อหา b ']); ) .toHaveValue ('ค่า'); คาดหวัง ('. zippy__Content'). tocontainValue ('ค่า'); // หมายเหตุสิ่งนี้มองหาหลายองค์ประกอบด้วยคลาสและตรวจสอบค่าของแต่ละองค์ประกอบอาร์เรย์กับดัชนี ('.zippy__Content'). tohavevalue (['value a', 'value b']); คาดหวัง ('. zippy__content'). tocontainvalue (['ค่า A', 'value B']); ) .toHaVestyle ({backgroundColor: 'rgba (0, 0, 0, 0.1)'}); คาดหวัง ('zippy__Content'). tohavedata ({data: 'บทบาท', val: 'admin'}); .CheckBox '). tobechecked (); คาดหวัง ('. ช่องทำเครื่องหมาย '). tobeIndeterminate (); คาดหวัง (' ปุ่ม '). toBedisabled (); คาดหวัง (' div ') .tobehidden (); คาดหวัง ('องค์ประกอบ'). tobeselected (); // สังเกตว่าเนื่องจากข้อ จำกัด ภายใน JEST (ไม่ใช้ตรรกะเลย์เอาต์จริงใน DOM เสมือนจริง) ผู้จับคู่บางคนอาจส่งผลให้เกิดผลบวกปลอม ตัวอย่างเช่นความกว้างและความสูงตั้งค่าเป็น 0EptEcpect ('Element'). tobevisible (); คาดหวัง ('อินพุต'). tobefocused (); คาดหวัง ('div') tobematchedby ('. js-something'); คาดหวัง (ผู้ชม Component.Object) .tobepartial ({aproperty: 'Avalue'}); คาดหวัง ('div'). tohavedescendant ('. เด็ก'); คาดหวัง ('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
หากต้องการใช้ spectator เป็นคอลเลกชันเริ่มต้นในโครงการ CLI เชิงมุมของคุณเพิ่มลงใน angular.json ของคุณ:
ng config cli.defaultcollection @ngneat/spectator
แผนผัง spectator ขยายค่าเริ่มต้น @schematics/angular Collection หากคุณต้องการตั้งค่าเริ่มต้นสำหรับแผนผังเช่นการสร้างส่วนประกอบด้วยไฟล์ SCSS คุณต้องเปลี่ยนชื่อแพคเกจแผนผังจาก @schematics/angular เป็น @ngneat/spectator ใน angular.json :
"Schematics": {"@ngneat/ผู้ชม: ผู้ชม-องค์ประกอบ": {"style": "scss"
-
-ตัวอย่างใน Karma จากคู่มือนักพัฒนา Docs Angular ได้รับการทำซ้ำในผู้ชมและความตลกขบขัน (เพื่อความสะดวกนี่คือตัวอย่าง Karma รุ่นท้องถิ่น)
สามารถเข้าถึงเวอร์ชันผู้ชมและ jest ได้ที่นี่
Netanel Basal | Dirk Luijk | เบ็นเอลเลียต |
ขอบคุณไปที่คนที่ยอดเยี่ยมเหล่านี้ (คีย์อีโมจิ): ~~~~
I. ซีนาย - - | Valentin Buryakov - | Ben Grynhaus - | มาร์ตินนิว | Lars Gyrup Brink Nielsen - | Andrew Grekov - | Jeroen Zwartepoorte |
Oliver Schlegel | Rex Ye - | tchmura | yoeri nijs | Anders Skarby | Gregor Woiwode | Alexander Sheremetev - |
ไมค์ | Mehmet Erim | Brett Eckert | Ismail Faizi | สูงสุด | Jonathan Bonnefoy | เรือข้ามฟาก Colum |
คริสคูเปอร์ | Marc Scheib | DGSMITH2 | dedwardstech - | Tamasfoldi - | Paolo Caleffi | Toni Villena |
itay oded | Guillaume de Jabrun | อานันท์ Tiwary | Ales Doganoc | zoltan | Vitalii Baziuk | Clementlemarc-Certua |
Yuriy Grunin | Andrey Chalkin | สตีเวนแฮร์ริส | Richard Sahrakorpi | Dominik Kremer | Mehmet Ozan Turhan | วลาด Lashko |
William Tjondrosuharto | Chaz Gatian | Pavel Korobov | Enno Lohmann | Pawel Boguslawski | Tobias Wittwer | Mateo Tibaquirá |
โครงการนี้เป็นไปตามข้อกำหนดทั้งหมดของผู้เข้าร่วม การมีส่วนร่วมทุกชนิดยินดีต้อนรับ!