Search code examples
angularunit-testingjasmineangular-test

Angular 8 Unit Test, Cannot set property 'valueAccessor' of null


I'm trying to simply pass the test (should create - component=> toBeTruthy) for the custom component (angular component class) implemented with ControlValueAccessor. I've injected NgControl in constructor and pass the this keyword.

 constructor(@Optional() @Self() public controlDir?: NgControl) {
    this.controlDir.valueAccessor = this;
  } 

And then on ngOnInit()

ngOnInit() {
    const control = this.controlDir.control;
    const validators = control.validator ? [control.validator] : [];
    const asyncValidators = control.asyncValidator ? [control.asyncValidator] : [];

    control.setValidators(validators);
    control.setAsyncValidators(asyncValidators);
    control.updateValueAndValidity();
  }

In the test file

describe('TextInputComponent', () => {
  let component: TextInputComponent;
  let fixture: ComponentFixture<TextInputComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [TextInputComponent],
      imports: [ReactiveFormsModule]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(TextInputComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

});

And the errors

TypeError: Cannot set property 'valueAccessor' of null

I'd be appreciated if anyone shares your ideas to solve this issue?

Thank you. Rabin


Solution

  • I got solved this issue by creating the new mock class component with calling the <app-text-input formControlName="test"></app-text-input> template including form.

    Here is a code details:

    @Component({
      template: `
      <form [formGroup]="form">
       <app-text-input formControlName="input">
       </app-text-input>
      </form>`
    })
    class TestingInput {
      @ViewChild(TextInputComponent, { static: true })
      textInputComponent: TextInputComponent;
    
      form = new FormGroup({
        input: new FormControl('Test Value')
      });
    }
    
    describe('TextInputComponent', () => {
      let component: TextInputComponent;
      let fixture: ComponentFixture<TestingInput>;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [TextInputComponent, TestingInput],
          imports: [ReactiveFormsModule]
        })
          .compileComponents();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(TestingInput);
        component = fixture.componentInstance.textInputComponent;
      });
    
      it('should create', () => {
        expect(component).toBeTruthy();
      });
    });
    

    Thanks, Everyone for the answer and comments, all did not solve the exact issue though at least got the idea to figure out. Feel free to post the answer if you have any other better way to solve this issue. Much appreciated!