I have Parent Component which has View child component associated with it. I'm trying to set up unit test for parent component but i'm not able to override the View Child component with mock class. I tried NO_ERRORS_SCHEMA, CUSTOM_SCHEMA in Schema provider and also used ng2-mock-component.
describe('Mobile Application Card:', () => {
let comp: MobileAppCardComponent;
let fixture: ComponentFixture<MobileAppCardComponent>;
beforeEach(() => {
const mock = MockComponent({ selector: 'bt-modal'}); // View Child Component.
TestBed.configureTestingModule({
declarations: [MobileAppCardComponent, mock],
providers: [{provide: MobileAppService, useValue: serviceStub},
{provide: ToastService, useValue: {}},
{provide: Router, userValue: null }
]
});
fixture = TestBed.createComponent(MobileAppCardComponent);
});
});
Related
I'm new to Angular, and I have a new team that told me to implement unit testing on an old project with Angular 8. So after investigating that, I decided to use Karma + Jasmine, and I created .spect.ts document like this:
describe("CashFlowSalariesComponent", () => {
let fixture: ComponentFixture < CashFlowSalariesComponent > ;
let instance;
let profile: ProfileModel;
beforeEach(async() => {
TestBed.configureTestingModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [
RouterTestingModule,
FormsModule,
ReactiveFormsModule,
BrowserModule,
HttpClientModule,
ToastrModule.forRoot({
positionClass: "toast-bottom-right",
}),
],
declarations: [CashFlowSalariesComponent],
providers: [
ApiService,
UserService,
ProfileService,
VettingStatusService,
SkillService,
ApplicationRoleService,
SeniorityLevelService,
PlacementStatusService,
EducationLevelService,
UtilsService,
ShirtSizeService,
GenderService,
TimeZoneService,
CountryService,
CityService,
PostalCodeService,
StateService,
ClientSectorService,
JobService,
ClientService,
PulsecheckQuestionService,
PulsecheckMasterService,
ExchangeRateService,
DepartmentService,
ExpenseService,
ProfileRoleService,
SkillCategoriesService,
ProfileActivityService,
ProfileSalaryActivityService,
TimeSheetService,
HolidayService,
RequestTimeOffService,
TimeOffTypeService,
InvoiceService,
PulsecheckDetailService,
],
}).compileComponents();
fixture = TestBed.createComponent(CashFlowSalariesComponent);
instance = fixture.componentInstance;
fixture.detectChanges();
profile = new ProfileModel();
(instance as any).exchangeRate = 18.92;
});
afterEach(() => {
fixture.destroy();
});
it("To test instance creation of component", () => {
expect(instance).toBeTruthy();
});
As you can see, I had to import many services from providers because my ApiService had injected them, so if I no add them, it returned an error like this:
NullInjectorError: No provider for {serviceName}!
So each time I call the ApiService on each component, developers should copy and paste from this component all the services. So my question is: is this a way to create a class or something to import all providers in once without copying and pasting code each time? How can I achieve this?
There are 2 things that could help you with your issue:
You can define your services as providedIn: 'root' in this case you don't need to provide them in any module or test. Angular would resolve them automatically.
example:
#Injectable({ providedIn: 'root' })
export class UserService {}
You could also define global providers in your test.ts file.
example:
#NgModule({
imports: [RouterTestingModule, HttpClientTestingModule],
providers: [...],
})
class GlobalTestingSetupModule {}
TestBed.initTestEnvironment([BrowserDynamicTestingModule, GlobalTestingSetupModule], platformBrowserDynamicTesting());
Also, instead of HttpClientModule it is preferable to use HttpClientTestingModule in unit tests.
I have an Angular project that whatever spec file I created to test any component is failing due Error: Illegal state: Could not load the summary for directive ...
For example, I created a component that contains some Material design tags, and belongs to a module called PagesModule, the component does not do anything:
pages.module.ts
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { SharedModule } from '../_shared/shared.module';
import { NotFoundComponent } from './error/not-found/not-found.component';
#NgModule({
declarations: [NotFoundComponent],
imports: [SharedModule, RouterModule],
exports: [],
providers: []
})
export class PagesModule {}
not-found.component.spec.ts
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { MatCardModule } from '#angular/material';
import { NotFoundComponent } from './not-found.component';
describe('NotFoundComponent', () => {
let component: NotFoundComponent;
let fixture: ComponentFixture<NotFoundComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [SharedModule],
declarations: [NotFoundComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(NotFoundComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeDefined();
});
});
Additional information:
My SharedModule is already exporting all necessary material modules.
Your NotFoundComponent may contain nested components or directives, whose templates may contain more components. There are basically two techniques to deal with this in your tests (see. Nested component tests).
create and declare stub versions of the components and directives
add NO_ERRORS_SCHEMA to the TestBed.schemas metadata.
When opting for the first solutions, your test could look something like this.
#Component({selector: 'app-nested', template: ''})
class NestedStubComponent {}
describe('NotFoundComponent', () => {
...
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [SharedModule],
declarations: [NotFoundComponent]
}).compileComponents();
}));
When opting for the second solution, TestBed.configureTestingModule would have to be changed as follows.
TestBed.configureTestingModule({
imports: [SharedModule],
declarations: [NotFoundComponent],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
I am writing tests for a component that is initialized dynamically as a modal (entryComponent). Inputs for this component are retrieved via injector.
I need a way to provide these inputs in my component creation step in beforeEach.
this.modalService.create({
component: sampleComponent, inputs: {
test: 'testMsg'
}
});
SampleComponent:
#Modal()
#Component({
selector: 'sample-component',
templateUrl: './sample.component.html',
styleUrls: ['./sample.component.scss']
})
export class SampleComponent implements OnInit {
test: string;
constructor(private injector: Injector) {
}
ngOnInit() {
this.test= this.injector.get('test');
}
}
Test for sampleComponent:
describe('sampleComponent', () => {
let component: SampleComponent;
let fixture: ComponentFixture<SampleComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [SampleComponent],
imports: [
ModalModule,
BrowserAnimationsModule,
],
providers: [
ModalService,
]
})
.compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(SampleComponent);
component = fixture.componentInstance;
fixture.detectChanges();
component.ngOnInit();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
test fails with:
Error: StaticInjectorError(DynamicTestModule)[test]:
StaticInjectorError(Platform: core)[test]:
NullInjectorError: No provider for test!
How do provide value for 'test' in this case?
In providers, provide values for the injected values that component is expecting:
providers: [
{ provide: 'test', useValue: 'valueOfTest' }
]
I am testing an app in angular and JHipster.
I try to test a label like this:
<label #hiddenLabel class="form-control-label" jhiTranslate="oncosupApp.paciente.nombre" for="field_nombre" >Nombre</label>
and it gives the error that the hidden is undefined, that means that it doesn't take the reference of the HTML element.
Then I try without jhiTranslate like this:
<label #hiddenLabel class="form-control-label" for="field_nombre" >Nombre</label>
and everything works perfectly.
The testBed code is here and I haven't included any translation functionality from jhi cause I am a newbie in JHI and don't know what to insert:
imports.....
describe('Component Tests', () => {
describe('Paciente Management Dialog Component', () => {
let comp: PacienteDialogComponent;
let fixture: ComponentFixture<PacienteDialogComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [OncosupTestModule,
OncosupSharedModule,
BrowserModule,
FormsModule,
],
declarations: [PacienteDialogComponent,
],
providers: [
JhiAlertService, ],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
//.overrideTemplate(PacienteDialogComponent, '')
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PacienteDialogComponent);
comp = fixture.componentInstance;
//service = fixture.debugElement.injector.get(PacienteService);
//mockEventManager = fixture.debugElement.injector.get(JhiEventManager);
//mockActiveModal = fixture.debugElement.injector.get(NgbActiveModal);
});
fit ('first test asdsadfdfd', async(() => {
expect(comp.hidden.nativeElement.innerHTML).toContain('Nombre');
}));
My component :
imports...
#Component({
selector: 'jhi-paciente-dialog',
template: require('./paciente-dialog.component.html'),
styleUrls: [
'paciente.css'
],
})
export class PacienteDialogComponent implements OnInit {
#ViewChild('hiddenLabel') hidden: ElementRef;
This means that jhiTranslate is not permitting me to take the reference of the HTML element. How can I fix this? I cannot remove jhiTranslate, cause the app is not mine. I just need to test it.
This is my test file and I am trying to identify the error preventing me from running a successful test:
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { Component, Directive, Input, OnInit } from '#angular/core';
import { TestComponent } from './test.component';
import { NgbDropdownModule, NgbCollapse } from '#ng-bootstrap/ng-bootstrap';
import { CommonModule } from '#angular/common';
import { Routes } from '#angular/router';
import { RouterTestingModule } from '#angular/router/testing';
import { NO_ERRORS_SCHEMA } from '#angular/core';
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '#angular/platform-browser-dynamic/testing';
let comp: TestComponent;
let fixture: ComponentFixture<MyComponent>;
describe('TestComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ TestComponent ],
providers: [
// DECLARE PROVIDERS HERE
{ provide: TestingCompilerFactory }
]
}).compileComponents()
.then(() => {
fixture = TestBed.createComponent(TestComponent);
comp = fixture.componentInstance;
});
}));
it('should be created', () => {
expect(TestComponent).toBeTruthy();
});
I am getting this error which I guess is because I am not wrapping it correctly.
error TS1005: ';' expected.
But I also get
No provider for TestingCompilerFactory
First fix your syntax error1,2
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
providers: [{ provide: TestingCompilerFactory }]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(TestComponent);
comp = fixture.componentInstance;
});
}); // excess `)` removed
Now, onto the noteworthy error
A provider takes can take two forms.
The first is a value that acts as both the value provided and the key under which it is registered. This commonly takes the form of a class as in the following example
const Dependency = class {};
#NgModule({
providers: [Dependency]
}) export default class {}
The second is an object with a provide property specifying the key under which the provider is registered and one or more additional properties specifying the value being provided. A simple example is
const dependencyKey = 'some key';
const Dependency = class {};
#NgModule({
providers: [
{
provide: dependencyKey,
useClass: Dependency
}
]
}) export default class {}
From the above it you can infer that you failed to specify the actual value provided under the key TestingCompilerFactory.
To resolve this write
TestBed.configureTestingModule({
declarations: [TestComponent],
providers: [
{
provide: TestingCompilerFactory,
useClass: TestingCompilerFactory
}
]
})
which is redundant and can be replaced with
TestBed.configureTestingModule({
declarations: [TestComponent],
providers: [TestingCompilerFactory]
})
as described above.
Notes
In the future do not post questions that include such an obvious error - fix it yourself instead.
Do not post two questions as one.