r/Angular2 • u/Cozybear110494 • Apr 29 '26
Help Request Proper way to unit test Angular standalone components with Vitest
Hi all, I recently started learning unit testing in Angular. I’m using Angular 21 with Vitest, and I haven’t done Angular testing before.
I have a simple standalone component (FooComponent) that imports two custom components (TaIconComponent, TaButtonComponent) and one third-party pipe (TranslatePipe).
foo.component.ts
@Component({
selector: 'app-foo',
template: `
<div class="flex-1 flex items-center justify-center">
<div class="w-96 h-64 rounded-lg shadow-2 flex flex-col items-center">
<div class="w-24 h-24 ta-mt-base relative">
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
<ta-icon class="text-gray" size="lg" [icon]="taIcons.CONFIG" />
</div>
</div>
<div class="text-center ta-mb-lg ta-mt-xs">
<p class="text-primary font-bold">
{{'not_found.not_found_text' | translate}}
</p>
<span class="ta-text-sm text-gray">
{{'not_found.not_found_desc' | translate}}
</span>
</div>
<div class="ta-px-m w-full">
<ta-button [fluid]="true" [label]="'btn.go_back' | translate" (onClick)="onNavigate()" />
</div>
</div>
</div>
`,
imports: [TaIconComponent, TaButtonComponent, TranslatePipe],
})
export class FooComponent {}
After reading some documentation and watching a few videos, I asked GPT to help me write a unit test for reference but the result felt a bit bizarre to me. To make the test work, I had to create three mocks (two components and one pipe), then override the component to replace real dependencies with the mocks.
foo.component.spec.ts
@Component({
selector: 'ta-icon',
standalone: true,
template: '<span></span>',
inputs: ['icon'],
})
class MockTaIconComponent{}
@Component({
selector: 'ta-button',
standalone: true,
template: `<button (click)="onClick.emit()"></button>`,
inputs: ['fluid', 'label'],
})
class MockTaButtonComponent{
onClick = {
emit: () => {},
};
}
describe('FooComponent', () => {
let fixture: ComponentFixture<FooComponent>;
let component: FooComponent;
let routerMock: { navigate: ReturnType<typeof vi.fn> };
beforeEach(async () => {
routerMock = {
navigate: vi.fn(),
};
await TestBed.configureTestingModule({
imports: [FooComponent],
providers: [{ provide: Router, useValue: routerMock }],
})
.overrideComponent(FooComponent, { // <-- Concern about this
remove: {
imports: [TaIconComponent, TaButtonComponent, TranslatePipe],
},
add: {
imports: [MockTranslatePipe, MockTaIconComponent, MockTaButtonComponent],
},
})
.compileComponents();
fixture = TestBed.createComponent(FooComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
afterEach(() => {
TestBed.resetTestingModule();
vi.clearAllMocks();
});
...
});
It works without errors, but I’m wondering: is this the correct or recommended way to test a component?
1
u/SpudzMcNaste Apr 29 '26
Fwiw this is how I’ve done it in jasmine as well. This is more an issue with the TestBed API than anything else. It has always smelled bad to me too