3

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

jpereira
  • 251
  • 2
  • 11

2 Answers2

1

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

jpereira
  • 251
  • 2
  • 11
0

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);
BeaverusIV
  • 988
  • 1
  • 11
  • 26
  • I tried your solution but still have the same problem. My problem is that when I change the value of the input despite that I dispatch the event it is not triggering the change on ngModel – jpereira May 25 '17 at 22:36
  • Have you tried running an ngOnChanges() function to debug if you can see it triggering that way? Narrow down where it is breaking in the chain. – BeaverusIV May 25 '17 at 23:02
  • Good tip, I added the ngOnChanges function and no luck, so I tried the ngDoCheck and updating the variable by hand and it works. But to do that I had to add @ViewChild('inputId') to get the value from the input. Doesn't look like a clean solution – jpereira May 26 '17 at 12:44