Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to mock an Attribute Directive in Angular?

Tags:

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.

Plunkr

like image 987
jenson-button-event Avatar asked Jun 12 '17 08:06

jenson-button-event


People also ask

How do you mock an Angular component?

A mock component in Angular tests can be created by MockComponent function. The mock component respects the interface of its original component, but all its methods are dummies. To create a mock component, simply pass its class into MockComponent function.

How do you test a jasmine directive?

We should Unit Test directives by mocking all dependencies with jasmine mocks and spies. We should also Shallow / Deep Test directives using concrete Components (Compiled DOM). A reasonable approach is to create TestComponent or pick up any component which uses the directive we want to test.

Can a directive have a template in Angular?

Components are directives with templates. The only difference between Components and the other two types of directives is the Template. Attribute and Structural Directives don't have Templates. So, we can say that the Component is a cleaner version of the Directive with a template, which is easier to use.

What is attribute directive in Angular?

Angular attribute directives are a number of built-in directives that we can add to our HTML elements that give them a dynamic behavior. In summary, an attribute directive changes the appearance or behavior of a DOM element.


2 Answers

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
  ]
})
like image 111
jenson-button-event Avatar answered Oct 25 '22 20:10

jenson-button-event


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
      })
  ]
})
like image 42
maia Avatar answered Oct 25 '22 20:10

maia