Updating input html field from within an Angular 2 test

前端 未结 3 445
独厮守ぢ
独厮守ぢ 2020-12-02 16:51

I would like to change the value of an input field from within an Angular 2 unit test.



        
相关标签:
3条回答
  • 2020-12-02 17:35

    I also had trouble getting jonrsharpe's answer to work with Angular 2.4. I found that the calls to fixture.detectChanges() and fixture.whenStable() caused the form component to reset. It seems that some initialization function is still pending when the test starts. I solved this by adding extra calls to these methods before each test. Here is a snippet of my code:

    beforeEach(() => {
        TestBed.configureTestingModule({
            // ...etc...
        });
        fixture = TestBed.createComponent(LoginComponent);
        comp = fixture.componentInstance;
        usernameBox = fixture.debugElement.query(By.css('input[name="username"]'));
        passwordBox = fixture.debugElement.query(By.css('input[type="password"]'));
        loginButton = fixture.debugElement.query(By.css('.btn-primary'));
        formElement = fixture.debugElement.query(By.css('form'));
    });
    
    beforeEach(async(() => {
        // The magic sauce!!
        // Because this is in an async wrapper it will automatically wait
        // for the call to whenStable() to complete
        fixture.detectChanges();
        fixture.whenStable();
    }));
    
    function sendInput(inputElement: any, text: string) {
        inputElement.value = text;
        inputElement.dispatchEvent(new Event('input'));
        fixture.detectChanges();
        return fixture.whenStable();
    }
    
    it('should log in correctly', async(() => {
    
        sendInput(usernameBox.nativeElement, 'User1')
        .then(() => {
            return sendInput(passwordBox.nativeElement, 'Password1')
        }).then(() => {
            formElement.triggerEventHandler('submit', null);
            fixture.detectChanges();
    
            let spinner = fixture.debugElement.query(By.css('img'));
            expect(Helper.isHidden(spinner)).toBeFalsy('Spinner should be visible');
    
            // ...etc...
        });
    }));
    
    0 讨论(0)
  • 2020-12-02 17:42

    The accepted solution didn't quite work for me in Angular 2.4. The value I had set was not appearing in the (test) UI, even after detectChanges() was called.

    The way I got it to work was to set up my test as follows:

    describe('TemplateComponent', function () {
      let comp: TemplateComponent;
      let fixture: ComponentFixture<TemplateComponent>;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          imports: [ FormsModule ],
          declarations: [ TemplateComponent ]
        })
        .compileComponents();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(TemplateComponent);
        comp = fixture.componentInstance;
      });
    
      it('should allow us to set a bound input field', fakeAsync(() => {
        setInputValue('#test2', 'Tommy');
    
        expect(comp.personName).toEqual('Tommy');
      }));
    
      // must be called from within fakeAsync due to use of tick()
      function setInputValue(selector: string, value: string) {
        fixture.detectChanges();
        tick();
    
        let input = fixture.debugElement.query(By.css(selector)).nativeElement;
        input.value = value;
        input.dispatchEvent(new Event('input'));
        tick();
      }
    });
    

    My TemplateComponent component has a property named personName in this example, which was the model property I am binding to in my template:

    <input id="test2" type="text" [(ngModel)]="personName" />

    0 讨论(0)
  • 2020-12-02 17:49

    You're right that you can't just set the input, you also need to dispatch the 'input' event. Here is a function I wrote earlier this evening to input text:

    function sendInput(text: string) {
      inputElement.value = text;
      inputElement.dispatchEvent(new Event('input'));
      fixture.detectChanges();
      return fixture.whenStable();
    }
    

    Here fixture is the ComponentFixture and inputElement is the relevant HTTPInputElement from the fixture's nativeElement. This returns a promise, so you'll probably have to resolve it sendInput('whatever').then(...).

    In context: https://github.com/textbook/known-for-web/blob/52c8aec4c2699c2f146a33c07786e1e32891c8b6/src/app/actor/actor.component.spec.ts#L134


    Update:

    We had some issues getting this to work in Angular 2.1, it didn't like creating a new Event(...), so instead we did:

    import { dispatchEvent } from '@angular/platform-browser/testing/browser-util';
    
    ...
    
    function sendInput(text: string) {
      inputElement.value = text;
      dispatchEvent(fixture.nativeElement, 'input');
      fixture.detectChanges();
      return fixture.whenStable();
    }
    
    0 讨论(0)
提交回复
热议问题