I'm trying to write jest unit tests for a basic angular component. But I seem to have stumbled on a strange error. A minimal repro is hosted here.
When running the test using VS Code and the Jest Runner extension, I get the following error
TypeError: Cannot read properties of undefined (reading 'Symbol(SIGNAL)')
Here's my specfile
@Component({
selector: 'demo-checkbox-test',
template: `
<div bsCheckboxGroup>
<bs-checkbox>
This is a checkbox
</bs-checkbox>
</div>`
})
class BsCheckboxTestComponent { }
describe('BsCheckboxComponent', () => {
let component: BsCheckboxTestComponent;
let fixture: ComponentFixture<BsCheckboxTestComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
// Mock dependencies
],
declarations: [
// Unit to test
BsCheckboxComponent,
// Mock dependencies
MockDirective(BsCheckboxGroupDirective),
// Testbench
BsCheckboxTestComponent,
]
}).compileComponents();
fixture = TestBed.createComponent(BsCheckboxTestComponent);
await fixture.whenStable();
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
And here's my unit-to-test
@Component({
selector: 'bs-checkbox',
template: `
<label>
<input type="checkbox">
</label>`
})
export class BsCheckboxComponent {}
The testbed mocks the following directive:
@Directive({
selector: '[bsCheckboxGroup]',
})
export class BsCheckboxGroupDirective {
name = input.required<string>();
children = contentChildren(forwardRef(() => BsCheckboxComponent));
// @ContentChildren(forwardRef(() => BsCheckboxComponent)) children!: QueryList<BsCheckboxComponent>;
}
Remarkably when using the @ContentChildren(...)
decorator instead of the contentChildren(...)
function, the test runs perfectly fine.
What's causing this? How can I fix it?
EDIT: It seems there is an existing issue about this
Here's what you can do while we wait for the open PR to be merged.
Make sure the Component you are trying to test is standalone, in your example that'd be the BsCheckboxTestComponent
Split your TestBed setup in Configuration and Initialization:
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
// Mock dependencies
],
declarations: [
// Testbench
BsCheckboxTestComponent,
// Don't Mock your Directive here!
// MockDirective(BsCheckboxGroupDirective)
]
}).compileComponents();
});
// Do it here by replacing it from your Component's imports
beforeEach(() => {
TestBed.overrideComponent(BsCheckboxTestComponent, {
remove: { imports: [BsCheckboxGroupDirective] },
add: { imports: [BsCheckboxGroupMockDirective] }
});
});
// Now we can initialize it
beforeEach(async () => {
fixture = TestBed.createComponent(BsCheckboxTestComponent);
await fixture.whenStable();
component = fixture.componentInstance;
fixture.detectChanges();
});
The last piece is a manually created Mock of your BsCheckGroupDirective:
@Directive({
selector: '[bsCheckboxGroup]',
standalone: true
})
class BsCheckGroupMockDirective{
public name= input<string>();
}
Hope it helps!