Angular报错:Cannot read properties of undefined (reading 'vote')排查求助
Let's tackle this error you're hitting when testing your DisplayComponent's output logic. First, let's recap the issue you shared:
You're seeing this error:
TypeError: Cannot read properties of undefined (reading 'vote')Here's your test code:
it('should handle outputs', () => { component.voterTestComponent.vote(true); fixture.detectChanges(); expect(getElementById("#lastVote").textContent).toEqual("Yes"); });
And the context screenshot:
You mentioned renaming the method didn't help—makes sense, since the error isn't about the method existing, it's about not being able to reach the component instance at all. Let's break down why this is happening and fix it.
Why This Error Happens
The message is clear: component.voterTestComponent is undefined when you try to call vote(true) on it. This almost always boils down to one of these four issues:
- The child component isn't properly referenced in your
DisplayComponenttemplate. - You're trying to access the child before Angular has finished initializing it.
- The template reference variable name doesn't match what you're using in the test.
- The child component isn't set up correctly in your test module.
Step-by-Step Fixes
1. Double-Check the Template Reference Variable
First, pop open your DisplayComponent template. You need to have a template reference variable assigned to the child VoterTestComponent that exactly matches voterTestComponent—the name you're using in the test.
It should look like this:
<app-voter-test #voterTestComponent></app-voter-test>
The #voterTestComponent part is critical here. If you used a different name (like #voter or #testComponent), that's why component.voterTestComponent is undefined.
2. Trigger Initial Change Detection
Angular doesn't initialize child components until the first change detection cycle runs. If you're trying to access voterTestComponent before that, it'll be undefined. Fix this by calling fixture.detectChanges() before you try to call the vote method:
it('should handle outputs', () => { // Run initial change detection to set up child components fixture.detectChanges(); component.voterTestComponent.vote(true); fixture.detectChanges(); // Run again to update the view after the vote // Also, note: getElementById doesn't take a selector with #—use the plain ID expect(document.getElementById("lastVote").textContent).toEqual("Yes"); });
3. Query for the Child Component Directly (Alternative Approach)
If you don't want to rely on template references in your tests, you can use Angular's test utilities to find the child component directly. This is often more robust:
import { By } from '@angular/platform-browser'; it('should handle outputs', () => { fixture.detectChanges(); // Find the child component using its directive class const voterComponent = fixture.debugElement .query(By.directive(VoterTestComponent)) .componentInstance; voterComponent.vote(true); fixture.detectChanges(); expect(document.getElementById("lastVote").textContent).toEqual("Yes"); });
4. Verify the Test Module Setup
Make sure your test module (in the .spec.ts file) includes the VoterTestComponent—either by declaring it or importing the module that contains it. Here's what that should look like:
beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ DisplayComponent, VoterTestComponent ], // Add VoterTestComponent here // Or if it's in a shared module, import that module instead: // imports: [ VoterModule ] }).compileComponents(); });
If the child component isn't in the test module, Angular won't render it, so component.voterTestComponent will never exist.
Wrap-Up
Start with checking the template reference variable and adding that initial fixture.detectChanges()—those are the two most common fixes for this exact error. If those don't work, move on to verifying the test module setup or using the direct query approach.
内容的提问来源于stack exchange,提问作者DELIZ

