Can not implement unit test on components with ionic 5/ angular 11 - javascript

I have created components and pages in my ionic 5 project.
The pages are working fine in unit tests.
But, the components are not being tested in the same way.
describe('component', () => {
let component: Component;
let fixture: ComponentFixture<Component>;
let modalSpy = jasmine.createSpyObj('Modal', ['present', 'onDidDismiss', 'catch', 'dismiss']);
modalSpy.onDidDismiss.and.returnValue(Promise.resolve(true));
let modalCtrlSpy = jasmine.createSpyObj('ModalController', ['create', 'dismiss']);
modalCtrlSpy.create.and.callFake(function () {
return modalSpy;
});
let popoverSpy = jasmine.createSpyObj('Popover', ['present', 'onDidDismiss', 'dismiss']);
popoverSpy.onDidDismiss.and.returnValue(Promise.resolve(true));
let popoverCtrlSpy = jasmine.createSpyObj('PopoverController', ['create', 'dismiss']);
popoverCtrlSpy.create.and.callFake(function () {
return popoverSpy;
});
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ Component ],
imports: [
IonicModule.forRoot(),
TranslateModule.forChild(),
ComponentsModule,
PipesModule,
TranslateModule.forRoot({
loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }
})
],
providers: [
{ provide: ModalController, useValue: modalCtrlSpy },
{ provide: PopoverController, useValue: popoverCtrlSpy },
AppGlobalState,
IonContent,
HttpClient,
HttpHandler,
Http,
HttpClientTestingModule,
Api,
ConnectionBackend,
SQLiteService,
SQLite,
InAppBrowser,
RequestOptions
]
}).compileComponents();
}));
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(Component);
component = fixture.componentInstance;
fixture.detectChanges();
component.loading=false;
component.ngOnInit();
fixture.detectChanges();
}))
afterEach(async () => {
component.ngOnDestroy();
})
This does not show the component being loaded.
<ion-card *ngIf='loading'>
</ion-card>
<ion-card *ngIf='!loading'>
</ion-card>
public loading: boolean = true
ngOnInit() {
subscriber.subscribe(() => {
this.loading = false
})
}
another issue in the same code is when I added renderer2. It gives error can not read property style of undefined. for the function setStyle being used in code.
any help is appreciated.

Related

Angular 9 FormModule Unit Testog

So I have an #Input form: FormGroup.
Unit Testing
describe('Component', () => {
let component: Component;
let fixture: ComponentFixture<Component>;
let apiService: ApiService;
let fb: FormBuilder = new FormBuilder();
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [Component, TranslatePipeMock],
imports: [ReactiveFormsModule, FormsModule],
providers: [
ChangeDetectorRef,
{ provide: FormBuilder, useValue: fb },
{
provide: ApiService,
useValue: apiServiceStub,
},
{
provide: TranslateService,
userValue: translateServiceStub,
},
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
apiLookupService = TestBed.inject(ApiLookupService);
fixture = TestBed.createComponent(InputWhtComponent);
fb = TestBed.inject(FormBuilder);
component = fixture.componentInstance;
const expectedForm = fb.group({
isWithholdingTaxEnabled: new FormControl(true),
});
component.form = expectedForm;
fixture.detectChanges();
});
But i am having this error right now,
No value accessor for form control with name: 'isWithholdingTaxEnabled'

Angular 9 testing component dependant on service with observable - Cannot read property 'subscribe' of undefined

I am deperately trying to test a component that is using a service. I use spy to mock it but every time I run tests it fails with exception:
Cannot read property 'subscribe' of undefined
My test looks like this:
describe('FilmOverviewComponent', () => {
let component: FilmOverviewComponent;
let fixture: ComponentFixture<FilmOverviewComponent>;
let filmsServiceSpy: jasmine.SpyObj<FilmsService>;
beforeEach(async(() => {
const spy = jasmine.createSpyObj('FilmsService',
['searchFilmByID']
);
TestBed.configureTestingModule({
declarations: [ FilmOverviewComponent ],
providers: [
{provide: AppTitleService, useValue: {getTitle: () => 'title'}},
{provide: ActivatedRoute, useValue: {params: of({id: 123})} },
{provide: FilmsService, useValue: spy}
]
})
.compileComponents();
filmsServiceSpy = TestBed.get(FilmsService);
}));
beforeEach(() => {
filmsServiceSpy.searchFilmByID.and.returnValue(Observable.create([{title: "", year: ""}]));
fixture = TestBed.createComponent(FilmOverviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Methods used in the service:
searchFilmByID(movieID: string): Observable<Film> {
return this.http.get<Film>(this.getUrlWithID(movieID));
}
private getUrlWithID(movieID: string) {
return 'api/externalfilms/film/' + movieID;
}
I have no idea how to tackle this. I suspect that it would be resolved with some kind of mocking of subscribe method but I completely failed at that.
Thank you for your help in advance!
The error is from this.http.get<Film>....
There are 2 ways to solve it.
First way - mock http client service and call fake
describe('FilmOverviewComponent', () => {
let component: FilmOverviewComponent;
let fixture: ComponentFixture<FilmOverviewComponent>;
let filmsService: FilmsService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FilmOverviewComponent ],
imports: [ HttpClientTestingModule ],
providers: [
{provide: AppTitleService, useValue: {getTitle: () => 'title'}},
{provide: ActivatedRoute, useValue: {params: of({id: 123})} },
FilmsService
]
})
.compileComponents();
}));
beforeEach(() => {
filmsService = TestBed.inject(FilmsService);
/* Mock response */
const httpClient: HttpClient = TestBed.inject(HttpClient);
spyOn(httpClient, 'get').and.callFake(() => of({title: "", year: ""}));
fixture = TestBed.createComponent(FilmOverviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Second way - call fake service method
const FilmsServiceStub = jasmine.createSpyObj('FilmsService', ['searchFilmByID']);
describe('FilmOverviewComponent', () => {
let component: FilmOverviewComponent;
let fixture: ComponentFixture<FilmOverviewComponent>;
let filmsService: FilmsService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FilmOverviewComponent ],
providers: [
{provide: AppTitleService, useValue: {getTitle: () => 'title'}},
{provide: ActivatedRoute, useValue: {params: of({id: 123})} },
{provide: FilmsService, useValue: FilmsServiceStub}
]
})
.compileComponents();
}));
beforeEach(() => {
filmsService = TestBed.inject(FilmsService);
/* Mock response */
spyOn(filmsService, 'searchFilmByID').and.callFake(() => of({title: "", year: ""}));
fixture = TestBed.createComponent(FilmOverviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

How to test subscribe function in angular onInit method?

I have the following component that I want to test:
component:
constructor(
private countrystore: Store<CountryAppState>,
private docstore: Store<DocumentAppState>,
private formBuilder: FormBuilder,
) {}
ngOnInit() {
this.getCountryState = this.countrystore.select('selecttimaticCountryState');
this.getCountryState.subscribe((state) => {
this.countries = state.response;
});
Spec file:
describe('TravellerInfoComponent', () => {
let component: TravellerInfoComponent;
let fixture: ComponentFixture<TravellerInfoComponent>;
Object.defineProperty(window, "matchMedia", {
value: jest.fn(() => { return { matches: true } })
});
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({}),
EffectsModule.forRoot([]),
BrowserAnimationsModule,
HttpClientModule
],
providers: [
FormsModule
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TravellerInfoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
Before I can even write a test I'm getting the following error:
I have looked at similar answers that suggest using the 'of' rxjs operator to simulate an observable, others suggest using a spyOn technique. But I don't quite understand where this should be inserted. Any help for a testing noob would be great.
const countrystore = TestBed.get(Store<CountryAppState>);
spyOn(countrystore, 'select').and.callFake(() => {
return of(someTestDataYouCreate);
});

How to provide injected values while unit testing a component in angular5+

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' }
]

Unit test queryParams subscription (Angular5)

i'm having problems testing the logic inside ActivatedRoute queryParams subscription.
constructor(private router: Router, private route: ActivatedRoute, private auth: AuthService) {}
ngOnInit(): void {
this.route.queryParams.subscribe((params:any) => {
if(params['data']) {
this.handle(params['data']);
} else {
if (this.auth.isAuthenticated()) {
this.router.navigate(['/home']);
}
}
});
}
I would like to test:
If this.handle() is triggered when mocked params['data'] is supplied
If there is no params and this.auth.isAuthenticated() returns true that this.router.navigate is called
I have tried multiple things and i'm running out of ideas.
My test file:
describe('TestComponent', () => {
let component: TestComponent;
let fixture: ComponentFixture<TestComponent>;
const mockService = {
navigate: jasmine.createSpy('navigate'),
isAuthenticated: jasmine.createSpy('isAuthenticated'),
queryParams: jasmine.createSpy('queryParams')
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
providers: [
{ provide: Router, useValue: mockService },
{ provide: ActivatedRoute, useValue: mockService },
{ provide: AuthService, useValue: mockService }
]
}).compileComponents();
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
mockService.navigate.calls.reset();
}));
it('should create the test component', () => {
expect(component).toBeTruthy();
});
it('should navigate away when authenticated', () => {
mockService.isAuthenticated.and.returnValue(true);
mockService.queryParams.and.callFake((data, params) => new Observable(o => o.next({ params: {} })));
component.ngOnInit();
expect(mockService.navigate).toHaveBeenCalledWith(['/home']);
});
});
But with that i get TypeError: this.route.queryParams.subscribe is not a function. I know that mockService.isAuthenticated.and.returnValue(true); is working correctly because before using subscription to params i had only this if statement inside ngOnInit().
I have tried to change the mockService to:
const mockService = {
navigate: jasmine.createSpy('navigate'),
isAuthenticated: jasmine.createSpy('isAuthenticated'),
queryParams: {
subscribe: jasmine.create('subscribe')
}
};
I also tried with:
const mockService = {
navigate: jasmine.createSpy('navigate'),
isAuthenticated: jasmine.createSpy('isAuthenticated'),
queryParams: {
subscribe: Observable.of({ params: {} })
}
};
But no success, for those last two i get Expected spy navigate to have been called with [ [ '/home' ] ] but it was never called.
So does someone know how to correctly test logic inside querParams subscription?
You can use rxjs observable in useValue to mock it.
const router = {
navigate: jasmine.createSpy('navigate')
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([]),
RouterTestingModule,
PlanPrimengModule
],
declarations: [YourComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
provideMockStore(),
{
provide: ActivatedRoute,
useValue: {
queryParams: of({
param1: "value1",
param1: "value2"
})
}
},
{ provide: Router, useValue: router }
]
}).compileComponents(); }));
I can't say if it is too late to answer this or not, but maybe it will help new googlers...
I manage to solve that this way:
class ActivatedRouteMock {
queryParams = new Observable(observer => {
const urlParams = {
param1: 'some',
param2: 'params'
}
observer.next(urlParams);
observer.complete();
});
}
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [
HttpClient,
HttpHandler,
ControlContainer,
{
provide: ActivatedRoute,
useClass: ActivatedRouteMock
}
]
}).compileComponents();
injector = getTestBed();
httpMock = injector.get(HttpTestingController);
}));
That allows you to assert the logic inside your .subscribe(() => {}) method..
Hope it hepls

Categories

Resources