Search code examples
htmlangularunit-testingjasmineangular-standalone-components

How can mock a component child to test the parent standalone component in Angular


I converted all of my Angular components to standalone components. However, I'm encountering issues with my unit tests. The tests that were previously working are now failing.

I try to pass a mock component to the parent, but parent always is rendering the original component, not the mock I want.

Example:

@Component({
  selector: 'app-root',
  template: '<h2>Hello{{title}}</h2><app-table></app-table>',
  styleUrls: ['./app.component.css'],
  standalone: true,
  imports: [CommonModule, TableComponent],
})
export class AppComponent {
  title = 'CodeSandbox';
}

table.component.ts

@Component({
  selector: 'app-table',
  template: '<h1>Original Table {{text}}</h1>',
  standalone: true,
})
export class TableComponent {
  text = 'CodeSandbox';
}

app.component.spec.ts

describe('AppComponent', () => {
  let component: LanesComponent;
  let fixture: ComponentFixture<LanesComponent>;
  let mockTableComponent: jasmine.SpyObj<TableComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [AppComponent, mockTableComponent],
    }).compileComponents();

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

  it('should render the mock table', () => {
    const tableComponent: MockTableComponent = fixture.debugElement.query(By.directive(MockTableComponent)).componentInstance;
  });
});

If I debug fixture.debugElement is rendering <h1>Original Table {{text}}</h1>, my mockTable only has a <h2>Hi</h2>. How can I force AppComponent to render the mock table component instead the original table component? Thanks a lot!


Solution

  • You need to remove the original import and then import the mock component, this might fix your problem.

    Reference: Testing standalone components

    CODE:

    describe('AppComponent', () => {
      let component: LanesComponent;
      let fixture: ComponentFixture<LanesComponent>;
      let mockTableComponent: jasmine.SpyObj<TableComponent>;
    
      beforeEach(async () => {
        await TestBed.configureTestingModule({
          imports: [AppComponent, mockTableComponent],
        })
        .overrideComponent(AppComponent, {
          remove: { imports: [ TableComponent] },
          add: { imports: [ mockTableComponent ] }
        }).compileComponents();
    
        fixture = TestBed.createComponent(AppComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
      });
    
      it('should render the mock table', () => {
        const tableComponent: MockTableComponent = fixture.debugElement.query(By.directive(MockTableComponent)).componentInstance;
      });
    });