Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular + (Jasmine/Karma) - Error: Illegal state: Could not load the summary for directive

I'm really trying to solve this error and nothing on the internet helps me for the moment...

lr-categories.component.spec.ts:

export function main() {
  describe('LrCategoriesComponent', () => {
    let fixture: ComponentFixture<LrCategoriesComponent>;
    let component: LrCategoriesComponent;
    let de: DebugElement;
    let glService: GeneralLedgeService;
    let lrService: LrService;
    let spy: jasmine.Spy;

    beforeEach(async(() => {
      TestBed.configureTestingModule({
        declarations: [
          LrComponent,
          LrMappingsComponent,
          LrCategoriesComponent,
        ],
        imports: [
          CommonModule,
          SharedModule,
          LrRoutingModule,
          AgGridModule.withComponents(
            [
              ButtonComponent,
              ColumnHeaderComponent,
              TypeaheadEditorComponent,
              ButtonGroupComponent
            ]
          )
        ],
        providers: [
          LrService,
          { provide: GeneralLedgeService, useClass: MockGeneralLedgeService },
          CompleterService,
        ]
      }).compileComponents().then(() => {
        // initialization
        fixture = TestBed.createComponent(LrCategoriesComponent);
        component = fixture.componentInstance;
        de = fixture.debugElement;

        // Service getters
        glService = de.injector.get(GeneralLedgeService);
        lrService = de.injector.get(LrService);
      });
    }));

    // beforeEach(() => {
    //   // initialization
    //   fixture = TestBed.createComponent(LrCategoriesComponent);
    //   component = fixture.componentInstance;
    //   de = fixture.debugElement;
    //
    //   // Service getters
    //   glService = de.injector.get(GeneralLedgeService);
    //   lrService = de.injector.get(LrService);
    // });

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

ERROR: enter image description here

ERROR: 'Unhandled Promise rejection:', 'Illegal state: Could not load the summary for directive LrCategoriesComponent.'

Any suggestions are accepted! I'm desperate at this point!

like image 995
SrAxi Avatar asked Jan 08 '18 13:01

SrAxi


2 Answers

I found a solution, I'll walk you through it (SOLUTION is point 3):

1. I moved the initialization stuff from .compileComponents().then(() => {...}); to beforeEach(() => {...});. (You can see it was commented)

export function main() {
  describe('LrCategoriesComponent', () => {
    let fixture: ComponentFixture<LrCategoriesComponent>;
    let component: LrCategoriesComponent;
    let de: DebugElement;
    let glService: GeneralLedgeService;
    let lrService: LrService;
    let spy: jasmine.Spy;

    beforeEach(async(() => {
      TestBed.configureTestingModule({
        // Module's stuff here
      }).compileComponents();
    }));

    beforeEach(() => {
      // initialization
      fixture = TestBed.createComponent(LrCategoriesComponent);
      component = fixture.componentInstance;
      de = fixture.debugElement;

      // Service getters
      glService = de.injector.get(GeneralLedgeService);
      lrService = de.injector.get(LrService);
    });

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

This gave me the following error:

Error: This test module uses the component ToolBarComponent which is using a "templateUrl" or "styleUrls", but they were never compiled.

This error is because one of the Components declared in SharedModule had issues while compiling (actually, this happened with any component in the declarations[] of SharedModule).

So, I started looking for ways to solve the setup of a spec file when importing SharedModule (or other heavy modules).

2. I found a new approach here:

const oldResetTestingModule = TestBed.resetTestingModule;
    beforeAll(done => (async () => {
      TestBed.resetTestingModule();
      TestBed.configureTestingModule({
       // Module's stuff here
      });
      await TestBed.compileComponents();

      // prevent Angular from resetting testing module
      TestBed.resetTestingModule = () => TestBed;
    })().then(done).catch(done.fail));

    afterAll(() => {
      // reinstate resetTestingModule method
      TestBed.resetTestingModule = oldResetTestingModule;
      TestBed.resetTestingModule();
    });

Even though it finally worked everything and at an amazing speed (5 seconds vs 20 seconds before), this approach has a main downside: Dependencies are created once per describe(), not per test. Meaning that you inherit the state from the previous test case. We don't want that!

3. I went back to square one, tried to understand and apply a smarter async logic...:

- SOLUTION -

beforeEach(done => (async () => {
      TestBed.configureTestingModule({
        // Module's stuff here, including SharedModule
      });
      await TestBed.compileComponents();
    })().then(done).catch(done.fail));

    beforeEach(() => {
      // initialization
      fixture = TestBed.createComponent(LrCategoriesComponent);
      component = fixture.componentInstance;
      de = fixture.debugElement;

      // Service getters
      glService = de.injector.get(GeneralLedgeService);
      lrService = de.injector.get(LrService);
    });

by playing with async / await I make sure that the Module is correctly configured before attempting to compile the Component.

With this, I manage to compile the component and have a clean and fresh instance to test on for each test case scenario!

like image 138
SrAxi Avatar answered Nov 15 '22 05:11

SrAxi


Had the same issue and all I had to do was to return the promise from beforeEach as below

beforeEach(() => {  

  return TestBed.configureTestingModule({
        .... setup code
     }).compileComponents().then(() => {
        ...initialization....
    });
  });

});
like image 36
crs Avatar answered Nov 15 '22 04:11

crs