what is the purpose of toBeFalsy()?

10,304

The test works because it relies on falsy values.

Try using this :

expect(comp.cardInput.nativeElement.valid).toEqual(false);    
expect(comp.cardInput.nativeElement.invalid).toEqual(true);    
expect(comp.cardInput.nativeElement.invalid).toBeTruthy();

None of them will work.

Why is that ?

comp.cardInput.nativeElement represents an HTMLElement. It contains properties such as className, onclick, querySelector and so on.

valid, on the other side, isn't part of the HTML standard : it's an Angular concept.

This means that when you write

expect(comp.cardInput.nativeElement.valid).toBeFalsy()

It outputs to

expect(undefined).toBeFalsy()

Which is true, because undefined is falsy.

The correct way to test this would be to test if the element contains a special Angular class, ng-invalid (or test that it doesn't contain ng-valid).

Before giving the code, I would suggest you to switch to reactive forms, they're way more powerful and easy to test.

But anyways, here is how you can do it.

it('should be invalid given a value of over 20 chars', () => {
  // NEVER use the nativeElement to set values. It's bad practice. 
  component.paciente.tarjetaSanitaria = 'dddddddddddddddddddddddddd';
  // Detect changes, it's not automatic
  fixture.detectChanges();
  // Test (bad practice)
  expect(component.cardInput.nativeElement.className.includes('ng-invalid').toEqual(true);
  // Test (good practice)
  expect(fixture.nativeElement.querySelector('input[name="tarjetaSanitaria"]').className.includes('ng-invalid')).toEqual(true);
});
Share:
10,304

Related videos on Youtube

Tester
Author by

Tester

Updated on June 04, 2022

Comments

  • Tester
    Tester almost 2 years

    I have an input in angular inside a template driven form.

    <form  name="editForm" role="form" novalidate (ngSubmit)="save()" #editForm="ngForm">
    
    <input #cardInput type="text" class="form-control" name="tarjetaSanitaria" id="field_tarjetaSanitaria"
                        [(ngModel)]="paciente.tarjetaSanitaria" maxlength="20"/>
                   <small class="form-text text-danger"
                       [hidden]="!editForm.controls.tarjetaSanitaria?.errors?.maxlength" jhiTranslate="entity.validation.maxlength" translateValues="{ max: 20 }">
                       This field cannot be longer than 20 characters.
                    </small>
    

    How can I unit test that it can only input texts that have a maxlength of 20.

    I have this in my component:

    export class PacienteDialogComponent implements OnInit {
      paciente: Paciente;
          constructor( //other things not paciente
          ){
        }
    .....
    

    And this is my paciente.model.ts that has the property of the input tarjetaSanitaria I wanna test:

    import { BaseEntity } from './../../shared';
    
    export class Paciente implements BaseEntity {
        constructor( public tarjetaSanitaria?: string)
        
        {
        }
    }
    

    And here is my testing class:

      import { Paciente } from...
    import { PacienteDialogComponent } from '..
     describe(....){
    
     let comp: PacienteDialogComponent;
            let fixture: ComponentFixture<PacienteDialogComponent>;....
    
      beforeEach(() => {
                fixture = TestBed.createComponent(PacienteDialogComponent);
                comp = fixture.componentInstance;...
    
          it ('Input validation', async(() => {
                       
                         comp.cardInput.nativeElement.value = 'dddddddddddddddddddddddddddddddddddddddddddddddddddddd' ; // a text longer than 20 characters
                        expect(comp.cardInput.nativeElement.valid).toBeFalsy();
                      }));
    

    The test passes, but anyway is this the right way to test the validation of an input? What happens after toBeFalsy()? How can the user know that this is false? Can I output a message in this case if it is false,?

    Is therea nother way to test the form inputs validation?

  • Tester
    Tester almost 6 years
    I gotta undo the acceptance of the answer until I verify that it works
  • Admin
    Admin almost 6 years
    I've never told you to accept my answer, I was just there to help. So sure, go ahead.
  • Tester
    Tester almost 6 years
    A closing brace is missing before toEqual. EDIT PLEASE
  • Tester
    Tester almost 6 years
    After filling the data in the app the className only prints form-control insead of form-control ng-valid, form-control ng-pristine , etc like in the tutorial of angular. What should I do?
  • Admin
    Admin almost 6 years
    I'm not your on-demand code monkey. Make new questions when you have new issues.
  • Tester
    Tester almost 6 years
    I guess this issue is still not closed, and I wanna give a solution on this before I create new questions.This answer is based on angular tutorial and appears to be correct in theory but doesnt work on practice.
  • Admin
    Admin almost 6 years
    That's because you didn't implement it correctly. And this issue is resolved, it's not closed because you decided so as the OP.
  • Tester
    Tester almost 6 years
    Ok, now I implemented it correctly (if you mean by this trying on the application) and if I print teh class name it doesnt prints the validators. So this means teh test wont work! Any way I see Im on teh right path, cause it prints teh validators on html {{input.className}} correctly
  • Tester
    Tester almost 6 years
    Thanks! When I find what wasnt working I will comment here and accept teh answer.
  • Admin
    Admin almost 6 years
    No I didn't mean that. We had an extended discussion about how you didn't implement a Validator, and how you needed it to make your test work. So yes, the test doesn't work, because you didn't make the proper code to make it work. Your original question was about toBeFalsy, your new question is about ng-valid. The case is closed here, I don't really care about you marking my answer, I'm just telling you to make another question about your new problem : 1 issue, 1 topic.
  • Tester
    Tester almost 6 years
    PEOPLE THIS ANSWER IS BASED ON ANGUAR TUTORIAL, IT GIVES A RESPNSE TO WHY FALSY DOESNT WORK, STILL THE TEST DOESNT PASS THIS WAY.
  • Admin
    Admin almost 6 years
    BECAUSE THE OP DIDN'T IMPLEMENT A VALIDATOR, THAT IS REQUIRED TO MAKE THE TEST PASS AND DISPLAY THE CORRECT CLASSES. Now stop your sassy tantrum, that's neither useful nor advised.
  • Tester
    Tester almost 6 years
    Do yu mean this by implementing validators? <div *ngIf="editForm.controls.tarjetaSanitaria?.errors?.maxlength‌​"> Name must have max 20 characters. </div>
  • Admin
    Admin almost 6 years
    See ? You don't even know what a validator is, and you say that the documentation is false. Educate yourself before throwing tantrums.
  • Admin
    Admin almost 6 years
    maxlength as an HTML attribute is an user convenience. FormControl.prototype.setValidators([Validators.maxLength(20‌​)]) is a validator. I don't see it anywhere in your code.
  • Tester
    Tester almost 6 years
    Oh, I see what you mean. Isn´t this for model-driven forms only?
  • Admin
    Admin almost 6 years
    That's called template-driven, and that's what you're using. This is available for template-driven forms as well as reactive forms.
  • Tester
    Tester almost 6 years
    Maybe i am putting the validator wrong. I moved in anothe issue since this is closed. Thanks
  • Tester
    Tester almost 6 years
    The link to the continution of this issue: stackoverflow.com/questions/50603966/…
  • Tester
    Tester almost 6 years
    @trichetriche Please could you have a look at this question stackoverflow.com/questions/51080100/…
  • Tester
    Tester almost 6 years
    If hidden is an html attribute w3schools.com/tags/att_hidden.asp and attributes do not change value according angular.io/guide/template-syntax#html-attribute-vs-dom-prope‌​rty how come that element.hasAttribute('hidden') in the tests work and outputs true or false according to its value????