Skip to content

Commit

Permalink
feat: 🎸 Add triggerEventHandler method (ngneat#249)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wykks committed Jan 6, 2020
1 parent b3a9643 commit 80a7436
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 4 deletions.
26 changes: 24 additions & 2 deletions projects/spectator/src/lib/base/dom-spectator.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ChangeDetectorRef, DebugElement, ElementRef, Type } from '@angular/core';
import { ChangeDetectorRef, DebugElement, ElementRef, Type, EventEmitter } from '@angular/core';
import { Observable } from 'rxjs';
import { ComponentFixture, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { Token } from '../token';
import { DOMSelector } from '../dom-selectors';
import { isString, QueryOptions, QueryType, SpectatorElement } from '../types';
import { isString, QueryOptions, QueryType, SpectatorElement, EventEmitterType, KeysMatching } from '../types';
import { SpyObject } from '../mock';
import { getChildren, setProps } from '../internals/query';
import { patchElementFocus } from '../internals/element-focus';
Expand Down Expand Up @@ -175,6 +175,28 @@ export abstract class DomSpectator<I> extends BaseSpectator {
return event;
}

public triggerEventHandler<C = any, K extends KeysMatching<C, EventEmitter<any>> = any>(
directiveOrSelector: Type<C> | string | DebugElement,
eventName: K,
eventObj: EventEmitterType<C[K]>
) {
let debugElement: DebugElement;
if (isString(directiveOrSelector)) {
debugElement = this.debugElement.query(By.css(directiveOrSelector));
} else if (directiveOrSelector instanceof DebugElement) {
debugElement = directiveOrSelector;
} else {
debugElement = this.debugElement.query(By.directive(directiveOrSelector));
}
if (!debugElement) {
// tslint:disable:no-console
console.error(`${directiveOrSelector} does not exists`);
return;
}
debugElement.triggerEventHandler(eventName as string, eventObj);
this.detectChanges();
}

public get keyboard() {
return {
pressKey: (key: string, selector: SpectatorElement = this.element, event = KEY_UP) => {
Expand Down
6 changes: 5 additions & 1 deletion projects/spectator/src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DebugElement, ElementRef, Type } from '@angular/core';
import { DebugElement, ElementRef, Type, EventEmitter } from '@angular/core';

import { DOMSelector } from './dom-selectors';
import { Token } from './token';
Expand All @@ -18,6 +18,10 @@ export interface QueryOptions<R> {
root?: boolean;
}

export type EventEmitterType<P> = P extends EventEmitter<infer T> ? T : never;

export type KeysMatching<T, V> = { [K in keyof T]: T[K] extends V ? K : never }[keyof T];

export type SelectOptions = string | string[] | HTMLOptionElement | HTMLOptionElement[];

export function isString(value: any): value is string {
Expand Down
3 changes: 2 additions & 1 deletion projects/spectator/test/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { FormInputComponent } from './form-input/form-input.component';
import { IntegrationModule } from './integration/integration.module';
import { TranslatePipe } from './translate.pipe';
import { EventsComponent } from './events/events.component';
import { ChildCustomEventModule } from './child-custom-event/child-custom-event.module';

@NgModule({
declarations: [
Expand Down Expand Up @@ -59,7 +60,7 @@ import { EventsComponent } from './events/events.component';
EventsComponent
],
entryComponents: [DynamicComponent],
imports: [BrowserModule, HttpClientModule, ReactiveFormsModule, IntegrationModule],
imports: [BrowserModule, HttpClientModule, ReactiveFormsModule, IntegrationModule, ChildCustomEventModule],
providers: [ChildServiceService, WidgetService, WidgetDataService],
bootstrap: [AppComponent]
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Spectator, createComponentFactory } from '@ngneat/spectator';

import { ChildCustomEventParentComponent } from './child-custom-event-parent.component';
import { ChildCustomEventModule } from './child-custom-event.module';
import { ChildCustomEventComponent } from './child-custom-event.component';
import { byText } from '@ngneat/spectator';

describe('ChildCustomEventParentComponent', () => {
let spectator: Spectator<ChildCustomEventParentComponent>;
const createComponent = createComponentFactory({
component: ChildCustomEventParentComponent,
imports: [ChildCustomEventModule],
declareComponent: false
});

it('should trigger custom event with directive selector', () => {
spectator = createComponent();
spectator.triggerEventHandler(ChildCustomEventComponent, 'customEvent', 'hello');
expect(spectator.query(byText('hello'))).toExist();
});

it('should trigger custom event with string selector', () => {
spectator = createComponent();
spectator.triggerEventHandler('app-child-custom-event', 'customEvent', 'hello');
expect(spectator.query(byText('hello'))).toExist();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Component } from '@angular/core';

@Component({
selector: 'app-child-custom-event-parent',
template: `
<app-child-custom-event (customEvent)="onCustomEvent($event)"></app-child-custom-event>
<p>{{ eventValue }}</p>
`
})
export class ChildCustomEventParentComponent {
public eventValue = '';

public onCustomEvent(eventValue: string): void {
this.eventValue = eventValue;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Component, Output, EventEmitter } from '@angular/core';

@Component({
selector: 'app-child-custom-event',
template: `
<p>Custom child</p>
`
})
export class ChildCustomEventComponent {
@Output() customEvent = new EventEmitter<string>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { ChildCustomEventParentComponent } from './child-custom-event-parent.component';
import { ChildCustomEventComponent } from './child-custom-event.component';

@NgModule({
imports: [CommonModule],
declarations: [ChildCustomEventParentComponent, ChildCustomEventComponent],
exports: [ChildCustomEventParentComponent]
})
export class ChildCustomEventModule {}

0 comments on commit 80a7436

Please sign in to comment.