Skip to content

Commit

Permalink
feat: support structural directives
Browse files Browse the repository at this point in the history
  • Loading branch information
ike18t committed Jun 4, 2018
1 parent 68ffe41 commit 050e70c
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 11 deletions.
22 changes: 20 additions & 2 deletions lib/mock-directive/mock-directive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FormControl, FormControlDirective } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { MockDirective } from './mock-directive';

// tslint:disable:max-classes-per-file
@Directive({
exportAs: 'foo',
selector: '[exampleDirective]'
Expand All @@ -14,18 +15,29 @@ export class ExampleDirective {
@Input('bah') something: string;
}

@Directive({
selector: '[exampleStructuralDirective]'
})
export class ExampleStructuralDirective {
@Input() exampleStructuralDirective = true;
}

@Component({
selector: 'example-component-container',
template: `
<div [exampleDirective]="'bye'" [bah]="'hi'" #f="foo" (someOutput)="emitted = $event"></div>
<div exampleDirective></div>
<div id="example-structural-directive" *exampleStructuralDirective="true">
hi
</div>
<input [formControl]="fooControl"/>
`
})
export class ExampleComponentContainer {
emitted = false;
foo = new FormControl('');
} // tslint:disable-line:max-classes-per-file
}
// tslint:enable:max-classes-per-file

describe('MockDirective', () => {
let fixture: ComponentFixture<ExampleComponentContainer>;
Expand All @@ -35,7 +47,8 @@ describe('MockDirective', () => {
declarations: [
ExampleComponentContainer,
MockDirective(FormControlDirective),
MockDirective(ExampleDirective)
MockDirective(ExampleDirective),
MockDirective(ExampleStructuralDirective)
]
})
.compileComponents();
Expand Down Expand Up @@ -79,4 +92,9 @@ describe('MockDirective', () => {
const debugElement = fixture.debugElement.query(By.directive(MockDirective(ExampleDirective)));
expect(debugElement).not.toBeNull();
});

it('should display structural directive content', () => {
const debugElement = fixture.debugElement.query(By.css('#example-structural-directive'));
expect(debugElement.nativeElement.innerHTML).toContain('hi');
});
});
22 changes: 13 additions & 9 deletions lib/mock-directive/mock-directive.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Directive, EventEmitter, Type } from '@angular/core';
import { Directive, EventEmitter, Inject, Optional, TemplateRef, Type, ViewContainerRef } from '@angular/core';
import { MockOf } from '../common';
import { directiveResolver } from '../common/reflect';

Expand All @@ -15,20 +15,24 @@ export function MockDirective<TDirective>(directive: Type<TDirective>): Type<TDi
}

const { selector, exportAs, inputs, outputs } = directiveResolver.resolve(directive);
const options: Directive = { exportAs, inputs, outputs, selector };

// tslint:disable:no-unnecessary-class
@MockOf(directive)
// tslint:disable-next-line:no-unnecessary-class
@Directive({ exportAs, inputs, outputs, selector })
class DirectiveMock {
constructor() {
(options.outputs || []).forEach((output) => {
constructor(@Optional() @Inject(TemplateRef) templateRef?: TemplateRef<any>,
@Optional() @Inject(ViewContainerRef) viewContainer?: ViewContainerRef) {
(outputs || []).forEach((output) => {
(this as any)[output.split(':')[0]] = new EventEmitter<any>();
});

if (templateRef && viewContainer) {
viewContainer.createEmbeddedView(templateRef);
}
}
}
// tslint:enable:no-unnecessary-class

const mockedDirective = Directive(options)(DirectiveMock as Type<TDirective>);
cache.set(directive, mockedDirective);
cache.set(directive, DirectiveMock);

return mockedDirective;
return DirectiveMock as Type<TDirective>;
}

0 comments on commit 050e70c

Please sign in to comment.