Skip to content

Commit 64d1c9c

Browse files
committed
feat: add testing utilities for components
* Moves existing testing helpers to a testing folder in the core package. * The testing utilities currently consist of functions to create dom events and shorthands to dispatch them. * Also fixes that **releases** include components `spec.d.ts` files. The `core/testing` utilities are not includes in releases for now. It could be possible to expose them as part of the Component Toolkit. Closes #2902
1 parent e3b2486 commit 64d1c9c

File tree

14 files changed

+193
-231
lines changed

14 files changed

+193
-231
lines changed

src/lib/autocomplete/autocomplete.spec.ts

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
1313
import {FakeViewportRuler} from '../core/overlay/position/fake-viewport-ruler';
1414
import {MdAutocomplete} from './autocomplete';
1515
import {MdInputContainer} from '../input/input-container';
16+
import {dispatchFakeEvent} from '../core/testing/dispatch-events';
1617

1718
describe('MdAutocomplete', () => {
1819
let overlayContainerElement: HTMLElement;
@@ -61,7 +62,7 @@ describe('MdAutocomplete', () => {
6162
expect(fixture.componentInstance.trigger.panelOpen)
6263
.toBe(false, `Expected panel state to start out closed.`);
6364

64-
dispatchEvent('focus', input);
65+
dispatchFakeEvent(input, 'focus');
6566
fixture.detectChanges();
6667

6768
expect(fixture.componentInstance.trigger.panelOpen)
@@ -88,11 +89,11 @@ describe('MdAutocomplete', () => {
8889
});
8990

9091
it('should close the panel when blurred', async(() => {
91-
dispatchEvent('focus', input);
92+
dispatchFakeEvent(input, 'focus');
9293
fixture.detectChanges();
9394

9495
fixture.whenStable().then(() => {
95-
dispatchEvent('blur', input);
96+
dispatchFakeEvent(input, 'blur');
9697
fixture.detectChanges();
9798

9899
expect(fixture.componentInstance.trigger.panelOpen)
@@ -103,7 +104,7 @@ describe('MdAutocomplete', () => {
103104
}));
104105

105106
it('should close the panel when an option is clicked', async(() => {
106-
dispatchEvent('focus', input);
107+
dispatchFakeEvent(input, 'focus');
107108
fixture.detectChanges();
108109

109110
fixture.whenStable().then(() => {
@@ -119,13 +120,13 @@ describe('MdAutocomplete', () => {
119120
}));
120121

121122
it('should close the panel when a newly created option is clicked', async(() => {
122-
dispatchEvent('focus', input);
123+
dispatchFakeEvent(input, 'focus');
123124
fixture.detectChanges();
124125

125126
fixture.whenStable().then(() => {
126127
// Filter down the option list to a subset of original options ('Alabama', 'California')
127128
input.value = 'al';
128-
dispatchEvent('input', input);
129+
dispatchFakeEvent(input, 'input');
129130
fixture.detectChanges();
130131

131132
let options =
@@ -135,7 +136,7 @@ describe('MdAutocomplete', () => {
135136
// Changing value from 'Alabama' to 'al' to re-populate the option list,
136137
// ensuring that 'California' is created new.
137138
input.value = 'al';
138-
dispatchEvent('input', input);
139+
dispatchFakeEvent(input, 'input');
139140
fixture.detectChanges();
140141

141142
fixture.whenStable().then(() => {
@@ -166,7 +167,7 @@ describe('MdAutocomplete', () => {
166167
});
167168

168169
it('should hide the panel when the options list is empty', async(() => {
169-
dispatchEvent('focus', input);
170+
dispatchFakeEvent(input, 'focus');
170171

171172
fixture.whenStable().then(() => {
172173
fixture.detectChanges();
@@ -178,7 +179,7 @@ describe('MdAutocomplete', () => {
178179

179180
// Filter down the option list such that no options match the value
180181
input.value = 'af';
181-
dispatchEvent('input', input);
182+
dispatchFakeEvent(input, 'input');
182183
fixture.detectChanges();
183184

184185
fixture.whenStable().then(() => {
@@ -242,14 +243,14 @@ describe('MdAutocomplete', () => {
242243
fixture.detectChanges();
243244

244245
input.value = 'a';
245-
dispatchEvent('input', input);
246+
dispatchFakeEvent(input, 'input');
246247
fixture.detectChanges();
247248

248249
expect(fixture.componentInstance.stateCtrl.value)
249250
.toEqual('a', 'Expected control value to be updated as user types.');
250251

251252
input.value = 'al';
252-
dispatchEvent('input', input);
253+
dispatchFakeEvent(input, 'input');
253254
fixture.detectChanges();
254255

255256
expect(fixture.componentInstance.stateCtrl.value)
@@ -283,7 +284,7 @@ describe('MdAutocomplete', () => {
283284
fixture.detectChanges();
284285

285286
input.value = 'Californi';
286-
dispatchEvent('input', input);
287+
dispatchFakeEvent(input, 'input');
287288
fixture.detectChanges();
288289

289290
expect(fixture.componentInstance.stateCtrl.value)
@@ -340,7 +341,7 @@ describe('MdAutocomplete', () => {
340341

341342
it('should clear the text field if value is reset programmatically', async(() => {
342343
input.value = 'Alabama';
343-
dispatchEvent('input', input);
344+
dispatchFakeEvent(input, 'input');
344345
fixture.detectChanges();
345346

346347
fixture.whenStable().then(() => {
@@ -377,7 +378,7 @@ describe('MdAutocomplete', () => {
377378
.toBe(false, `Expected control to start out pristine.`);
378379

379380
input.value = 'a';
380-
dispatchEvent('input', input);
381+
dispatchFakeEvent(input, 'input');
381382
fixture.detectChanges();
382383

383384
expect(fixture.componentInstance.stateCtrl.dirty)
@@ -419,7 +420,7 @@ describe('MdAutocomplete', () => {
419420
expect(fixture.componentInstance.stateCtrl.touched)
420421
.toBe(false, `Expected control to start out untouched.`);
421422

422-
dispatchEvent('blur', input);
423+
dispatchFakeEvent(input, 'blur');
423424
fixture.detectChanges();
424425

425426
expect(fixture.componentInstance.stateCtrl.touched)
@@ -439,8 +440,8 @@ describe('MdAutocomplete', () => {
439440
fixture.detectChanges();
440441

441442
input = fixture.debugElement.query(By.css('input')).nativeElement;
442-
DOWN_ARROW_EVENT = new FakeKeyboardEvent(DOWN_ARROW) as KeyboardEvent;
443-
ENTER_EVENT = new FakeKeyboardEvent(ENTER) as KeyboardEvent;
443+
DOWN_ARROW_EVENT = new MockKeyboardEvent(DOWN_ARROW) as KeyboardEvent;
444+
ENTER_EVENT = new MockKeyboardEvent(ENTER) as KeyboardEvent;
444445

445446
fixture.componentInstance.trigger.openPanel();
446447
fixture.detectChanges();
@@ -501,7 +502,7 @@ describe('MdAutocomplete', () => {
501502
const optionEls =
502503
overlayContainerElement.querySelectorAll('md-option') as NodeListOf<HTMLElement>;
503504

504-
const UP_ARROW_EVENT = new FakeKeyboardEvent(UP_ARROW) as KeyboardEvent;
505+
const UP_ARROW_EVENT = new MockKeyboardEvent(UP_ARROW) as KeyboardEvent;
505506
fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
506507

507508
fixture.whenStable().then(() => {
@@ -532,7 +533,7 @@ describe('MdAutocomplete', () => {
532533

533534
fixture.whenStable().then(() => {
534535
input.value = 'o';
535-
dispatchEvent('input', input);
536+
dispatchFakeEvent(input, 'input');
536537
fixture.detectChanges();
537538

538539
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
@@ -566,10 +567,10 @@ describe('MdAutocomplete', () => {
566567
it('should fill the text field, not select an option, when SPACE is entered', async(() => {
567568
fixture.whenStable().then(() => {
568569
input.value = 'New';
569-
dispatchEvent('input', input);
570+
dispatchFakeEvent(input, 'input');
570571
fixture.detectChanges();
571572

572-
const SPACE_EVENT = new FakeKeyboardEvent(SPACE) as KeyboardEvent;
573+
const SPACE_EVENT = new MockKeyboardEvent(SPACE) as KeyboardEvent;
573574
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
574575
fixture.componentInstance.trigger._handleKeydown(SPACE_EVENT);
575576
fixture.detectChanges();
@@ -605,7 +606,7 @@ describe('MdAutocomplete', () => {
605606
.toEqual('', `Expected panel to close after ENTER key.`);
606607

607608
input.value = 'Alabam';
608-
dispatchEvent('input', input);
609+
dispatchFakeEvent(input, 'input');
609610
fixture.detectChanges();
610611

611612
expect(fixture.componentInstance.trigger.panelOpen)
@@ -679,7 +680,7 @@ describe('MdAutocomplete', () => {
679680
expect(input.hasAttribute('aria-activedescendant'))
680681
.toBe(false, 'Expected aria-activedescendant to be absent if no active item.');
681682

682-
const DOWN_ARROW_EVENT = new FakeKeyboardEvent(DOWN_ARROW) as KeyboardEvent;
683+
const DOWN_ARROW_EVENT = new MockKeyboardEvent(DOWN_ARROW) as KeyboardEvent;
683684
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
684685
fixture.detectChanges();
685686

@@ -783,7 +784,7 @@ describe('MdAutocomplete', () => {
783784

784785
fixture.whenStable().then(() => {
785786
input.value = 'f';
786-
dispatchEvent('input', input);
787+
dispatchFakeEvent(input, 'input');
787788
fixture.detectChanges();
788789

789790
const inputTop = input.getBoundingClientRect().top;
@@ -809,7 +810,7 @@ describe('MdAutocomplete', () => {
809810

810811
const input = fixture.debugElement.query(By.css('input')).nativeElement;
811812
input.value = 'd';
812-
dispatchEvent('input', input);
813+
dispatchFakeEvent(input, 'input');
813814
fixture.detectChanges();
814815

815816
const options =
@@ -906,22 +907,8 @@ class AutocompleteWithoutForms {
906907

907908
}
908909

909-
/**
910-
* TODO: Move this to core testing utility until Angular has event faking
911-
* support.
912-
*
913-
* Dispatches an event from an element.
914-
* @param eventName Name of the event
915-
* @param element The element from which the event will be dispatched.
916-
*/
917-
function dispatchEvent(eventName: string, element: HTMLElement): void {
918-
let event = document.createEvent('Event');
919-
event.initEvent(eventName, true, true);
920-
element.dispatchEvent(event);
921-
}
922-
923910
/** This is a mock keyboard event to test keyboard events in the autocomplete. */
924-
class FakeKeyboardEvent {
911+
class MockKeyboardEvent {
925912
constructor(public keyCode: number) {}
926913
preventDefault() {}
927914
}

src/lib/core/overlay/scroll/scroll-dispatcher.spec.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {NgModule, Component, ViewChild, ElementRef} from '@angular/core';
33
import {ScrollDispatcher} from './scroll-dispatcher';
44
import {OverlayModule} from '../overlay-directives';
55
import {Scrollable} from './scrollable';
6+
import {dispatchFakeEvent} from '../../testing/dispatch-events';
67

78
describe('Scroll Dispatcher', () => {
89

@@ -53,9 +54,7 @@ describe('Scroll Dispatcher', () => {
5354
// Emit a scroll event from the scrolling element in our component.
5455
// This event should be picked up by the scrollable directive and notify.
5556
// The notification should be picked up by the service.
56-
const scrollEvent = document.createEvent('UIEvents');
57-
scrollEvent.initUIEvent('scroll', true, true, window, 0);
58-
fixture.componentInstance.scrollingElement.nativeElement.dispatchEvent(scrollEvent);
57+
dispatchFakeEvent(fixture.componentInstance.scrollingElement.nativeElement, 'scroll');
5958

6059
// The scrollable directive should have notified the service immediately.
6160
expect(hasDirectiveScrollNotified).toBe(true);

0 commit comments

Comments
 (0)