2016-03-21 15 views
5

Tôi đang cố thử nghiệm một thành phần có chứa phần tử nhập văn bản. Tôi muốn xác minh rằng trạng thái của thành phần thay đổi như mong đợi khi giá trị của đầu vào văn bản thay đổi. Tất nhiên, đầu vào văn bản sử dụng chỉ thị ngModel (liên kết hai chiều).Làm cách nào để kích hoạt cập nhật mô hình ngModel trong thử nghiệm đơn vị Angular 2?

Mặc dù thành phần hoạt động tốt khi chạy, tôi gặp sự cố khi tạo thử nghiệm hợp lệ, vượt qua. Tôi đã đăng những gì tôi nghĩ rằng nên làm việc dưới đây, và kết quả kiểm tra sau đó.

Tôi đang làm gì sai?

TEST:

import {Component} from 'angular2/core'; 
import {describe, it, injectAsync, TestComponentBuilder} from 'angular2/testing'; 
import {FORM_DIRECTIVES} from 'angular2/common'; 
import {By} from 'angular2/platform/common_dom'; 

class TestComponent { 
    static get annotations() { 
     return [ 
      new Component({ 
       template: '<input type="text" [(ngModel)]="name" /><p>Hello {{name}}</p>', 
       directives: [FORM_DIRECTIVES] 
      }) 
     ] 
    } 
} 

describe('NgModel',() => { 
    it('should update the model', injectAsync([TestComponentBuilder], tcb => { 
     return tcb 
      .createAsync(TestComponent) 
      .then(fixture => { 
       fixture.nativeElement.querySelector('input').value = 'John'; 
       const inputElement = fixture.debugElement.query(By.css('input')); 
       inputElement.triggerEventHandler('input', { target: inputElement.nativeElement }); 
       fixture.detectChanges(); 
       expect(fixture.componentInstance.name).toEqual('John'); 
      }); 
    })); 
}); 

OUTPUT:

Chrome 45.0.2454 (Mac OS X 10.10.5) NgModel should update the model FAILED 
    Expected undefined to equal 'John'. 
     at /Users/nsaunders/Projects/ng2-esnext-seed/src/test/ngmodel.spec.js!transpiled:41:52 
     at ZoneDelegate.invoke (/Users/nsaunders/Projects/ng2-esnext-seed/node_modules/angular2/bundles/angular2-polyfills.js:322:29) 
     at Zone.run (/Users/nsaunders/Projects/ng2-esnext-seed/node_modules/angular2/bundles/angular2-polyfills.js:218:44) 
     at /Users/nsaunders/Projects/ng2-esnext-seed/node_modules/angular2/bundles/angular2-polyfills.js:567:58 
     at ZoneDelegate.invokeTask (/Users/nsaunders/Projects/ng2-esnext-seed/node_modules/angular2/bundles/angular2-polyfills.js:355:38) 
     at Zone.runTask (/Users/nsaunders/Projects/ng2-esnext-seed/node_modules/angular2/bundles/angular2-polyfills.js:254:48) 
     at drainMicroTaskQueue (/Users/nsaunders/Projects/ng2-esnext-seed/node_modules/angular2/bundles/angular2-polyfills.js:473:36) 
     at XMLHttpRequest.ZoneTask.invoke (/Users/nsaunders/Projects/ng2-esnext-seed/node_modules/angular2/bundles/angular2-polyfills.js:425:22) 
+0

Điều gì về việc đọc [mã nguồn] (https://github.com/angular/angular/blob/f9fb72fb0e9bcbda7aeebbf8321ce5d70d78ecee/modules/angular2/test/common/forms/integration_spec.ts#L824)? –

+1

Cảm ơn, tôi dường như đã bỏ qua điều này trong khi cọ rửa nguồn cho một ví dụ có liên quan. Thật không may là ví dụ này sử dụng những gì dường như là một API riêng (dispatchEvent từ angular2/testing_internal), nhưng nó đã cho tôi ý tưởng để thử fakeAsync ít nhất. –

Trả lời

2

NgModel lắng nghe sự kiện input để nhận được thông báo về những thay đổi:

dispatchEvent(inputElement, "input"); 
tick(); 

Đối với các yếu tố đầu vào khác các sự kiện khác có thể được sử dụng (hộp kiểm, radio, tùy chọn, ...).

+0

Tôi gặp phải lỗi ở đây: UNSPECIFIED_EVENT_TYPE_ERR: UNSPECIFIED_EVENT_TYPE_ERR: DOM Sự kiện Ngoại lệ 0 trong config/spec-bundle.js (dòng 49252) dispatchEvent @ [native code] –

+0

Khó nói mà không thấy mã của bạn trông như thế nào. –

+0

Nick Saunders trả lời ở trên có vẻ chính xác hơn –

9

Đây là một cách để làm điều đó:

import {Component} from 'angular2/core'; 
import {describe, it, inject, fakeAsync, tick, TestComponentBuilder} from 'angular2/testing'; 
import {FORM_DIRECTIVES} from 'angular2/common'; 

class TestComponent { 
    static get annotations() { 
     return [ 
      new Component({ 
       template: '<input type="text" [(ngModel)]="name" /><p>Hello {{name}}</p>', 
       directives: [FORM_DIRECTIVES] 
      }) 
     ] 
    } 
} 

describe('NgModel',() => { 
    it('should update the model', inject([TestComponentBuilder], fakeAsync(tcb => { 
     let fixture = null; 
     tcb.createAsync(TestComponent).then(f => fixture = f); 
     tick(); 

     fixture.detectChanges(); 
     let input = fixture.nativeElement.querySelector('input'); 
     input.value = 'John'; 
     let evt = document.createEvent('Event'); 
     evt.initEvent('input', true, false); 
     input.dispatchEvent(evt); 
     tick(50); 

     expect(fixture.componentInstance.name).toEqual('John'); 
    }))); 
}); 
+1

Lưu ý: Event.initEvent không được chấp nhận; bạn có thể muốn sử dụng hàm tạo sự kiện thay thế. Tôi đã phải sử dụng API không dùng nữa vì PhantomJS. Xem https://developer.mozilla.org/en-US/docs/Web/API/Event/initEvent và https://developer.mozilla.org/en-US/docs/Web/API/Event/Event để biết thêm thông tin. –

1

tôi xử lý nó theo cách này:

import {TestBed, ComponentFixture, async} from "@angular/core/testing"; 
import {dispatchEvent} from "@angular/platform-browser/testing/browser_util"; 
import {FormsModule} from "@angular/forms"; 
import {By} from "@angular/platform-browser"; 
import {DebugElement} from "@angular/core"; 

describe('my.component',() => { 

    let comp: MyComp, 
     fixture: ComponentFixture<MyComp>; 

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

    it('should handle inputs',() => { 
     const sendInputs = (inputs: Array<DebugElement>) => { 
      inputs.forEach(input => { 
       dispatchEvent(input.nativeElement, 'input'); 
      }); 
      fixture.detectChanges(); 
      return fixture.whenStable(); 
     }; 

     let inputs: Array<DebugElement> = fixture.debugElement.queryAll(By.css('input')); 

     // set username input value 
     inputs[0].nativeElement.value = "Username"; 

     // set email input value 
     inputs[1].nativeElement.value = "Email"; 

     sendInputs(inputs).then(() => { 
      // emit click event to submit form 
      fixture.nativeElement.querySelectorAll('button')[0].click(); 

      expect(comp.username).toBe("Username"); 
      expect(comp.email).toBe("Email"); 
     }); 
    }); 
}); 

Và html của tôi kinda tìm kiếm như thế này:

<form (ngSubmit)="submit()"> 
    <input type="text" name="username" class="form-control" placeholder="username" required [(ngModel)]="username"> 
    <input type="email" name="email" class="form-control" placeholder="email" required [(ngModel)]="email"> 
    <button type="submit" class="btn btn-primary block full-width m-b">Submit</button> 
</form> 

Tôi cũng đề nghị kiểm tra thử nghiệm mã nguồn của angulars đã giúp tôi rất nhiều: Forms tests

+0

Bạn có chức năng tùy chỉnh có tên dispatchEvent không được hiển thị không? Bởi vì tôi nghĩ dispatchEvent được cho là được gọi trên đối tượng đích. –

Các vấn đề liên quan