Is it possible to mock the attribute directive in Angular?
I have the following directive that applies to input tags. When running the jasmine spec on a host component, I want it to ignore (mock) this directive as it has a jquery dependency which I am not interested in testing.
I tried to create a class MockDirective
but was not successful. Does anyone know how to achieve this?
@Directive({
selector: '[skinColorPicker]'
})
export class ColorPickerDirective implements OnInit {
@Input('skinColorPicker') initialColor;
@Output() colorSelected: EventEmitter<string> = new EventEmitter<string>();
constructor(private el: ElementRef) {}
ngOnInit() {
// legacy jQuery blah blah
}
}
inside the host:
<input skinColorPicker="'#555'" (colorSelected)="onPageBackgroundColorSelected($event)"
/>
specification:
describe('PrintSidebarComponent', () => {
let component: PrintSidebarComponent;
let fixture: ComponentFixture<PrintSidebarComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
PrintSidebarComponent,
MockDirective({ selector: '[skinColorPicker]' }) // does not work
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PrintSidebarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
export function MockDirective(options: Component): Component {
let metadata: Directive = {
selector: options.selector,
inputs: options.inputs,
outputs: options.outputs
};
return Directive(metadata)(class _ { });
}
Cannot bind to 'skinColorPicker' as it is not a known Input property.
I've seen this overrideDirective method but couldn't find a decent example.
One solution
Turned out to be the missing declaration for the property @Input('skinColorPicker')
:
MockDirective({selector: '[skinColorPicker]', inputs: ['skinColorPicker']})
I still think it's better to see an example with an inline function Testbed.overrideDirective
.
source to share
MockDirective
works, but it has been misconfigured.
export function MockDirective(options: Component): Directive {
const metadata: Directive = {
selector: options.selector,
inputs: options.inputs,
outputs: options.outputs
};
return Directive(metadata)(class _ { });
}
Thrown out by a missing mock declaration for a property @Input('skinColorPicker')
:
TestBed.configureTestingModule({
declarations: [
PrintSidebarComponent,
MockDirective({
selector: '[skinColorPicker]',
inputs: ['skinColorPicker'] }) // does work
]
})
source to share
Since the component is a directive without a template, we can use the MockComponent directly . I think MockDirective is also inspired by this.
The way to use MockComponent to forge a directive is as follows:
MockComponent({
selector: '[skinColorPicker]',
inputs: ['skinColorPicker']
}),
source to share
My solution is identical to @ jenson-button-event's solution with some minor changes, so it compiles to TypeScript.
export function MockDirective(options: Component): Directive {
const metadata: Directive = {
selector: options.selector,
inputs: options.inputs,
outputs: options.outputs
};
return <any>Directive(metadata)(class _ {}); // <----- add <any>
}
TestBed.configureTestingModule({
declarations: [
PrintSidebarComponent,
MockDirective({
selector: '[skinColorPicker]',
inputs: [] // <--- empty, unless the directive has inputs
})
]
})
source to share