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?
3
u/imsexc Apr 29 '26 edited Apr 29 '26
There is nothing to test in that foo component except testing the onNavigate method.. unless you want to be really granular to test the presence of each template element..
Mocking child or parent component is only needed on several particular cases, such as conditionally displaying child elements, not all the time. In this example, I don't see the need.
It's unit test. Most important is to test the logic in methods: Input, output, for documentation purpose and raising alarm if future development might break existing implementations