-
Notifications
You must be signed in to change notification settings - Fork 91
Prefer declared component instead of same component on imported module #288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I'm not familiar with ng-mocks, what's the behavior when you do this with a "normal" test that's using the Angular TestBed? |
Hi, @timdeschryver. Below you'll find standalone tests both using Testing Library and TestBed. import { render, screen } from '@testing-library/angular';
import { Component, NgModule } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
@Component({
selector: 'app-parent-component',
template: '<app-child-component></app-child-component>',
})
class RealParentComponent {}
@Component({
selector: 'app-child-component',
template: '<p>Real child component</p>',
})
class RealChildComponent {}
@Component({
selector: 'app-child-component',
template: '<p>Mocked child component</p>',
})
class MockedChildComponent {}
@NgModule({
declarations: [RealParentComponent, RealChildComponent],
})
export class RealModule {}
fdescribe('RealParentComponent', () => {
it('Tests using Angular testing library', async () => {
await render(RealParentComponent, {
imports: [RealModule],
declarations: [MockedChildComponent],
excludeComponentDeclaration: true,
});
expect(screen.queryByText('Real child component')).toBeFalsy(); // Error: Expected <p>...</p> to be falsy
expect(screen.queryByText('Mocked child component')).toBeTruthy(); // Error: Expected null to be truthy
});
it("Tests using Angular's TestBed", async () => {
TestBed.configureTestingModule({
imports: [RealModule],
declarations: [MockedChildComponent],
});
const fixture: ComponentFixture<RealParentComponent> = TestBed.createComponent(RealParentComponent);
expect(fixture.nativeElement.querySelector('p').textContent).not.toEqual('Real child component'); // Error: Expected 'Real child component' not to equal 'Real child component'.
expect(fixture.nativeElement.querySelector('p').textContent).toEqual('Mocked child component'); // Expected 'Real child component' to equal 'Mocked child component'.
});
}); The TestBed test fails to find @NgModule({
declarations: [RealParentComponent /*, RealChildComponent */],
})
export class RealModule {}
The TestBed test succeeds if both components are declared directly on it (instead of on the module): TestBed.configureTestingModule({
declarations: [RealParentComponent, MockedChildComponent],
}); Conclusion: |
@marcioggs correct, that was my understanding as well the last time that I checked this but I wanted to be sure about it. |
Maybe it's still possible to dynamically create a module that overrides the components in the |
Hi again, @timdeschryver . Through this issue, I discovered that we can use TestBed#overrideComponent to achieve this. Would Testing Library need to be changed to use this TestBed's method? If it needs change and it makes sense to proceed with it, here's an interface spec alternative: render(ComponentName, {
imports: [...],
providers: [...],
overrideComponents: [ // {component: Type<any>, replacement: MetadataOverride<Component>}[]
{
component: ActivatedRoute,
replacement: {
set: { selector: 'app-child-component', template: '<p>Mocked child component</p>' },
},
},
// Other replacements here
],
}) There are also other override methods on TestBed that could make sense doing the same ( |
Hi @marcioggs, in theory "exclude" option of const dependencies = ngMocks.guts(null, ModuleContainingServiceAbc, ComponentToTest);
await render(ComponentToTest, dependencies); There is an article about |
Thanks for the tip @satanTime . |
Hi. Sorry for the delay. import { Component, NgModule } from '@angular/core';
import { render, screen } from '@testing-library/angular';
import { ngMocks } from 'ng-mocks';
@Component({
selector: 'app-parent-component',
template: '<app-child-component></app-child-component>',
})
class RealParentComponent {}
@Component({
selector: 'app-child-component',
template: '<p>Real child component</p>',
})
class RealChildComponent {}
@NgModule({
declarations: [RealParentComponent, RealChildComponent],
})
export class RealModule {}
fdescribe('RealParentComponent', () => {
it('Tests using Angular testing library', async () => {
const dependencies = ngMocks.guts(null, RealModule, RealParentComponent);
await render(RealParentComponent, dependencies);
expect(screen.queryByText('Real child component')).toBeNull();
});
}); @timdeschryver |
I'm currently on my phone, feel free to add this example in the docs, or as an example in this repo. If you want to do this you can reopen this issue so we don't forget about it. |
Hi!
First of all, thanks for your hard work simplificating my tests and I hope this becomes the de-facto library for Angular tests (as its name almost suggests it)✌
When we provide a service that's already contained in one of the imorted modules, Angular Testing Library gives preference to the one on the
providers
array. 👍I expected the same to happen on the
declarations
array, but this is not happening.Is this the implemented behavior? I'm not sure if I may be doing something wrong.
On my specific case,
ComponentAbc
is not directly declared and exported byModuleContainingComponentAbc
, but by another module that's imported byModuleContainingComponentAbc
.If you need details on how ng-mocks creates the mocks:
https://ng-mocks.sudo.eu/api/MockProvider
https://ng-mocks.sudo.eu/api/MockComponent
The text was updated successfully, but these errors were encountered: