【问题标题】:Unit test when a button is enabled using Karma in Angular2使用 Angular2 中的 Karma 启用按钮时的单元测试
【发布时间】:2017-05-23 11:54:15
【问题描述】:

我有一个使用 Angular CLI 的 Angular2 项目设置。我正在尝试测试表单组件。它有两个字段:电子邮件和密码。两者都是required。有一个submit 类型的登录按钮。只有在用户在两个字段中都提供了有效输入后才会启用它。

<form (ngSubmit)="login()" #loginForm="ngForm">

        <md-input-container class="md-block">
            <input md-input [(ngModel)]="user.email" class="userEmail"
                name="userEmail" type="email" placeholder="Email" 
                ngControl="userEmail" 
            required>
        </md-input-container>
        <br>

        <md-input-container class="md-block">
            <input md-input [(ngModel)]="user.password" class="userPassword"
                name="userPassword" type="password" placeholder="Password" 
                ngControl="userPassword" 
            required>
        </md-input-container>
        <br>



        <!--the button is enabled only after all form fields are valid-->
        <button  color="primary" md-button 
            type="submit" class='loginButton'
        [disabled]="!loginForm.form.valid">
            Login
         </button>

现在,我想使用 karma 测试按钮。我浏览了文档并能够通过在测试期间提供随机输入并对其进行验证来测试输入:

//imports...

describe('LoginComponent (inline template)', () => {
  let comp:    LoginComponent;
  let fixture: ComponentFixture<TmLoginComponent>;
  let userEmail: HTMLInputElement;
  let userPassword: HTMLInputElement;
  let loginBtn: HTMLElement;
  let title: HTMLElement;



  beforeEach(() => {

    TestBed.configureTestingModule({
      declarations: [ LoginComponent ], // declare the test component
      imports: [ MaterialModule.forRoot(), FormsModule, 
                  RouterTestingModule.withRoutes(
                  [{path: 'login', component: LoginComponent}, ])
                ],
      providers: [{provide: UserAuthenticationService, useValue: uaServiceStub }, CookieService],

    });

    fixture = TestBed.createComponent(LoginComponent);

    comp = fixture.componentInstance; //LoginComponent test instance

    // query by CSS element selector
    userEmail = fixture.debugElement.query(By.css('.userEmail')).nativeElement;
    userPassword = fixture.debugElement.query(By.css('.userPassword')).nativeElement;
    loginBtn = fixture.debugElement.query(By.css('.loginButton')).nativeElement;


//tests

//this test is successful
  it('should check initial input', () => {
    fixture.detectChanges();
    expect(userEmail.value).toBe('')
  });

//this test is successful
  it('should check later input', async(() => {    
    fixture.detectChanges();
    fixture.whenStable().then(() => {
      userEmail.value = 'someValue';
      userEmail.dispatchEvent(new Event('change'));

      expect(userEmail.value).toBe('someValue');
    });

  }));

//EDITED: NEW TEST
it('should check loginBtn is disabled initially', () => {
  fixture.detectChanges();
  loginBtn =   fixture.debugElement.query(By.css('.loginButton')).nativeElement;
  fixture.whenStable().then(() => {
    expect(loginBtn.disabled).toBe(true)
   })
 });


//this test fails. "Expected true to be false"
  it('should check loginBtn is enabled after inputs check out', async(() => {
   fixture.detectChanges();
   fixture.whenStable().then(() => {
   userEmail.value = 'raj@gmail.com';//valid
   userEmail.dispatchEvent(new Event('change'));

   userPassword.value = 'asdf';//vaild
   userPassword.dispatchEvent(new Event('change'));
   fixture.detectChanges();
   expect(loginBtn.disabled).toBe(false)
  })
 }));

});

我不明白为什么测试会失败。有人可以帮忙吗?

【问题讨论】:

    标签: unit-testing angular karma-jasmine angular-cli


    【解决方案1】:

    如果你看一下DefaultValueAccessor源代码:

    host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
    

    https://github.com/angular/angular/blob/2.4.2/modules/%40angular/forms/src/directives/default_value_accessor.ts#L36

    你可以注意到你的错误主要是错误的事件名称。

    您必须使用input 事件而不是change

    it('should check loginBtn is enabled after inputs check out', async(() => {
      fixture.detectChanges();
      fixture.whenStable().then(() => {
        userEmail.value = 'raj@gmail.com';
        userEmail.dispatchEvent(new Event('input'));
    
        userPassword.value = 'asdf';
        userPassword.dispatchEvent(new Event('input'));
        fixture.detectChanges();
        expect(loginBtn.disabled).toBe(false)
      });
    }));
    

    Plunker Example

    【讨论】:

    • 谢谢,朋友。有效。现在,当我将电子邮件简单地输入为 raj 时,它也返回 true,而只有在 @ 字符后跟至少一个其他字符(默认条件)时它才应该有效。我能做些什么来实现这一目标?
    • 谢谢。所以这是一个错误。无论如何,非常感谢您的帮助,以及您在设置 plunker 时付出的额外努力。真诚的感谢。
    • 很抱歉再次打扰您。看,我的登录按钮最初被禁用(在 plunker 中看不到)。我有另一个单元测试:'应该检查 loginBtn 最初是否被禁用',我已经编辑了要包含的问题。现在,此测试自行通过,“输入后检查”测试自行通过。但是当我同时测试它们时,后者失败了。知道可能是什么原因吗?
    • whenStableplnkr.co/edit/vwyoQFBXWqYOid9eJCa9?p=preview之后需要再次调用detectChanges
    • 第一个detectChanges 用于设置控件,然后我们应该等到NgForm 中的异步操作被执行(take.ms/TmB7N)但是我们的模板在这些操作之后还没有更新所以我们有触发 detectChanges 以正确状态更新我们的视图
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-21
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 2018-01-24
    相关资源
    最近更新 更多