How do I rerender an Angular attribute directive using testing-library

1.8k views Asked by At

Given this very trivial attribute directive where all it does is putting text from input into innerText

import { Directive, ElementRef, Input } from '@angular/core';
    
@Directive({
  selector: '[appTrivial]',
})
export class TrivialDirective {
  @Input() set text(value: any) {
    this.el.nativeElement.innerText = value.toString();
  }

  constructor(private el: ElementRef) { }
}

and I am trying to use rerender from @testing-library/angular to easily change the input:

import { render } from '@testing-library/angular';
import { TrivialDirective } from './trivial.directive';

describe('TrivialDirective', () => {
  it('should replace case insensitive', async () => {
    const template = `<div appTrivial text="qwe"></div>`;
    const { container, rerender, fixture } = await render(template, { declarations: [TrivialDirective] });

    expect(container.querySelector('div[appTrivial]').textContent).toEqual('qwe');

    rerender({ template: `<div appTrivial text="rty"></div>` });
    // fixture.detectChanges();
    expect(container.querySelector('div[appTrivial]').textContent).toEqual('rty');
  });
});

The second assertion doesn't work - with or without fixture.detectChanges().

Then, what is the proper way of testing such a directive? esp. when you have a couple of inputs and you want to change all their values at once during tests.

1

There are 1 answers

0
rfprod On

Something like this may work:

  1. create a testing component for the directive;
  2. bootstrap the testing component;
  3. modify the testing component input, and verify respective debug element native element changes;
import { Component, DebugElement } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

@Component({
    selector: 'testing-component',
    template: '<div appTrivial text="{{textInput}}"></div>',
})
export class TestingComponent {
    public textInput = ''
}

describe('TrivialDirective', () => {
    let component: TestingComponent;
    let fixture: ComponentFixture<TestingComponent>;
    let debugElement: DebugElement;
    let directive: TrivialDirective;

    beforeEach(
        waitForAsync(() => {
            void TestBed.configureTestingModule({
                declarations: [TestingComponent, TrivialDirective],
            })
                .compileComponents()
                .then(() => {
                    fixture = TestBed.createComponent(TestingComponent);
                    component = fixture.componentInstance;
                    debugElement = fixture.debugElement.query(By.directive(TrivialDirective));
                    directive = debugElement.injector.get(TrivialDirective);
                    fixture.detectChanges();
                });
        }),
    );

    it('testing component with the directive should compile successfully', () => {
        expect(component).toBeDefined();
        expect(directive).toBeDefined();
    });

    it('should set text', () => {
        const directiveElement = () => <HTMLElement>debugElement.nativeElement;
        expect(component.textInput).toEqual('');
        expect(directiveElement().innerText).toEqual('');
        const testInput = 'test input'; 
        component.textInput = testInput;
        fixture.detectChanges();
        expect(directiveElement().innerText).toEqual(testInput);
    });
});