jpereira
jpereira

Reputation: 251

Angular 4 ngModel not updated after input change in tests

I have a simple application that have 1 input:

@Component({   selector: 'mycomponent',   styles: [

  ],   template: `
    <div class="new-stuff">
      <div>
        <div>
        Name: <input type="text" class="new-stuff-name" [(ngModel)]="stuff.name"/>
        </div>
        <div class="new-stuff-name-error" *ngIf="nameError != null">
          {{nameError}}
        </div>
      </div>

      <button class="new-stuff-save" (click)="checkStuff()">Add idea</button>
    </div>  `, }) 
export class StuffComponent implements OnInit {
   public stuff = {name: ''};
   public allStuff = [];
   public checkStuff() {
    if (this.stuff.name.length === 0) {
      this.nameError = 'The name field cannot be empty';
    }

    if (this.stuff.name.length > 0) {
      this.allStuff.push(this.stuff);
      this.stuff= { name: ''};
    }
  }
 }

When I run the application I see the values changing and everything looks tied together, but when I try to test that when I change a value in the input box and click the button an error message is not displayed the error message is still displayed because the input value do not change.

Here is my Jasmine test:

describe(`stuff`, () => {
  let comp: StuffComponent ;
  let fixture: ComponentFixture<StuffComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [StuffComponent ],
      schemas: [NO_ERRORS_SCHEMA],
      imports: [FormsModule],
    }).compileComponents();
    fixture = TestBed.createComponent(StuffComponent );
    comp = fixture.componentInstance;
  }));

  describe('adding a new stuff', () => {
    let stuffNameInput;
    let saveButton;
    beforeEach(() => {
      stuffNameInput = fixture.nativeElement
        .querySelectorAll('.new-stuff-name')[0];
      saveButton = fixture.debugElement.nativeElement.querySelector(
        '.new-stuff-save');
    });

    describe('when is successfull', () => {
      beforeEach(async(() => {
        stuffNameInput.value = 'New Stuff';
        stuffNameInput.dispatchEvent(new Event('input'));
        saveButton.click();
        fixture.detectChanges();
      }));
      it('should display an error', () => {
        let errorDiv = fixture.nativeElement
          .querySelectorAll('.new-stuff-desc-error');
        expect(errorDiv.length)
          .toBe(0, 'Error message displayed');
      });
    });
  });
});

I tried multiple things, replace async with fakeAsync, call tick function, move the click inside a fixture.whenStable().then block, move the check for the div to the fixture.whenStable().then block. nothing worked so far.

I am using version 4.1.3 of angular

Upvotes: 3

Views: 2198

Answers (2)

jpereira
jpereira

Reputation: 251

Answering my own question to record the problem.

Using stuff.name as a ngModel doesn't work very well.

I changed the stuff.name to name and it started working

Upvotes: 1

BeaverusIV
BeaverusIV

Reputation: 1008

I found mousedown works better than click() for my tests:

    const e: Event = document.createEvent('HTMLEvents');
    e.initEvent('mousedown', false, true);
    itemElements[1].nativeElement.dispatchEvent(e);

Upvotes: 0

Related Questions