Is it possible to mock an Attribute Directive in Angular?
Solution 1
The MockDirective
does work, but it was misconfigured.
export function MockDirective(options: Component): Directive {
const metadata: Directive = {
selector: options.selector,
inputs: options.inputs,
outputs: options.outputs
};
return Directive(metadata)(class _ { });
}
Turned out to be a missing mock declaration for the @Input('skinColorPicker')
property:
TestBed.configureTestingModule({
declarations: [
PrintSidebarComponent,
MockDirective({
selector: '[skinColorPicker]',
inputs: ['skinColorPicker'] }) // does work
]
})
Solution 2
My solution is identical to @jenson-button-event's solution, with some minor changes so it compiles in 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
})
]
})
Solution 3
Since Component is Directive without template, we could directly use MockComponent. I guess the 'MockDirective' is also inspired by it.
Way of using MockComponent to mock directive is as follows:
MockComponent({
selector: '[skinColorPicker]',
inputs: ['skinColorPicker']
}),
Solution 4
This solution is exactly the same as @jenson-button-event's and @maia's solution, except for improved Typescript correctness. Without the improvements it did not work for me.
export function MockDirective(options: Component): Type<Directive> {
const metadata: Directive = {
selector: options.selector,
inputs: options.inputs,
outputs: options.outputs,
};
return Directive(metadata)(class MockDirectiveClass {
});
}
TestBed.configureTestingModule({
declarations: [
PrintSidebarComponent,
MockDirective({
selector: '[skinColorPicker]',
inputs: [] // <--- empty, unless the directive has inputs
})
]
})
Related videos on Youtube
Comments
-
jenson-button-event about 2 years
I have the following directive that is applied to input tags. When running a jasmine spec on the host component I want it to ignore (mock) this directive since it has a dependency on jquery that I am not interested in testing.
I have tried to create a
MockDirective
class but have not been successful. Anyone know how 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)" />
the spec:
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 _ { }); }
Can't bind to 'skinColorPicker' since it isn't a known property of 'input'.
I saw this overrideDirective method but have not been able to find a decent example of it.
One Solution Turned out to be a missing mock declaration for the
@Input('skinColorPicker')
property:MockDirective({selector: '[skinColorPicker]', inputs: ['skinColorPicker']})
I still think seeing an example with the built in
Testbed.overrideDirective
function would be better.-
yurzui about 7 yearsWhy should you mock it? Is it not working without mocking? Angular will not complain on attribute directive if you don't declare it in
declarations
array. Anyway there isNO_ERROR_SCHEMA
for this purpose -
jenson-button-event about 7 years@yurzui i am mocking it mainly because it is not the system under test, but also because it has a legacy dependency on jQuery that i am not interested into bringing into my test suite.
-
jenson-button-event about 7 yearsthe error is still evident without the declaration,
schemas: [ NO_ERRORS_SCHEMA ]
is needed to prevent it, but that feels like sweeping it under the carpet (try ... catch.. continue.. crap) -
yurzui about 7 yearsCan you reproduce it here? plnkr.co/edit/sKRmPFAyVHoD3FAm5cgZ?p=preview
-
jenson-button-event about 7 yearsshort answer: no. but it helped me solve it. i had 2 pickers in the html one with a default value, so had to add the input to the mock:
MockDirective({selector: '[skinColorPicker]', inputs: ['skinColorPicker']})
. thank you. -
yurzui about 7 years
skinColorPicker="#555"
is key point in your question. In this case angular will complain if you don't declare @Input for your directive
-
-
Sebastian Patten about 6 yearsDon't think this compiles in modern TypeScript. Is there any less voodoo way of creating a mock directive?
-
maia about 6 years@SebastianPatten see my answer below
-
Aico Klein Ovink over 5 yearsI wonder, with this approach, is it possible to test the input values of the directive?