Gregory Mazur
Gregory Mazur

Reputation: 2468

Angular how not to import all the dependencies in component unit tests each time

I have a working app(when run ng serve all works fine) however, when I run ng test compiler complains about not recognizing directives/properties such as Can't bind to 'formControl' since it isn't a known property of 'input'. When I add

TestBed.configureTestingModule({
      declarations: [
        AppComponent,
        SomeComponent
      ],
      imports: [
        BrowserModule,
        AppRoutingModule,
        HttpClientModule,
        .. other dependencies
    ]

what is the smart way not to add all the imports that I have already added in the app.module ?

UPDATE: I am talking about unit testing a component.

Upvotes: 3

Views: 2892

Answers (4)

Roope Lehtonen
Roope Lehtonen

Reputation: 31

I solved this error by importing the module, where the tested component is declared in. This allows the test file to have access to the dependencies provided by the module.

I still need to separately import testing modules, for example HttpClientTestingModule and RouterTestingModule, in addition to the component's module, since the module doesn't use these. But this still reduces the amount of copy-paste needed and seems like a good approach to import only the needed modules instead of declaring everything in a shared module.

My module:

@NgModule({
    declarations: [
        TestedComponent,
    ],
    imports: [
        CommonModule,
        DirectivesModule,
        FormsModule,
        PipesModule,
    ],
})
export class TestedComponentModule { }

My test file:

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

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            declarations: [
                TestedComponent,
            ],
            imports: [
                HttpClientTestingModule,
                RouterTestingModule,
                TestedComponentModule,
            ],
        }).compileComponents();

        fixture = TestBed.createComponent(TestedComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

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

Upvotes: 0

Chandana
Chandana

Reputation: 122

Since the error is Can't bind to 'formControl' since it isn't a known property of 'input', you will have to import following module/s under TestBed configuration. FormsModule, ReactiveFormsModule, MatInputModule, MatFormFieldModule

Ex: I have additional modules imported in my case and below is the sample code.

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [SomeComponent],
      imports: [HttpClientModule, RouterTestingModule, MatCardModule, MatIconModule, FormsModule, ReactiveFormsModule,
        MatInputModule, MatProgressSpinnerModule, MatButtonModule, MatFormFieldModule,
        BrowserAnimationsModule],
      providers: [SomeService]
    })
      .compileComponents();
  }));

  function setup() {
    const fixture = TestBed.createComponent(SomeComponent);
    const component = fixture.componentInstance;
    const someService = fixture.debugElement.injector.get(SomeService);

    return { fixture, component, someService };
    return { fixture, component };
  }

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


});

Upvotes: 0

Wandrille
Wandrille

Reputation: 6821

Your tests are Independent from your app.module. So you need to import all needed modules.

If you want, you can do a shared.module.ts where you have all the modules for test:

const MODULE_DEPENDENCIES = [
  TranslateModule,
  HttpClientModule,
  ReactiveFormsModule,
  ScrollingModule,
  MatFormFieldModule,
  MatInputModule,
];

@NgModule({
  imports: MODULE_DEPENDENCIES,
  exports: [
    ...MODULE_DEPENDENCIES
  ],
})

export class SharedModule {
  constructor() { }

  }
}

Upvotes: 4

Arikael
Arikael

Reputation: 2085

you can create a SharedModule which holds all your directives etc

or just reuse the array of modules

basically

export const modules: any[] = [
  BrowserModule, ReactiveFormsModule
];

@NgModule({
  imports:      modules,
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

and in your test

TestBed.configureTestingModule({
      declarations: [
        AppComponent,
        SomeComponent
      ],
      imports: modules

I don't know of another way.

But you can do the same with declarations and providersa and save some typing with that

Upvotes: 1

Related Questions