I'm having a hard time trying to test an angular component with Jest.
I have this component:
media-image.component.ts
import { Component, Input } from '@angular/core'
import { SanityService } from '@services/sanity/sanity.service'
import Waypoint from '@interfaces/waypoint'
@Component({
selector: 'app-media-image',
templateUrl: './media-image.component.html',
styleUrls: ['./media-image.component.scss']
})
export class MediaImageComponent {
@Input() mediaData: Waypoint = null
constructor(private _sanity: SanityService) {}
imageUrl(source: any) {
return this._sanity.urlFor(source)
}
}
imageUrl is called in the template
This component needs the SanityService
sanity.service.ts
import { Injectable } from '@angular/core'
import { environment } from '@environments/environment'
import imageUrlBuilder from '@sanity/image-url'
import sanityClient from '@sanity/client'
@Injectable({
providedIn: 'root'
})
export class SanityService {
sanityClientCredentials = {
option: sanityClient({
projectId: environment.sanity.projectId,
dataset: environment.sanity.dataset,
apiVersion: environment.sanity.apiVersion
})
}
urlFor(source: any) {
return imageUrlBuilder(this.sanityClientCredentials.option).image(source).url()
}
}
I would like to mock the urlFor
function of the service, just to check if it is called with the correct argument.
Here are my attempts:
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'
import { IonicModule } from '@ionic/angular'
import { MediaImageComponent } from './media-image.component'
import { SanityService } from '../../../services/sanity/sanity.service'
import { waypointImage } from '../../../mocks/waypoint.mocks'
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [MediaImageComponent],
providers: [{ provide: SanityService }],
imports: [IonicModule.forRoot()]
}).compileComponents()
fixture = TestBed.createComponent(MediaImageComponent)
component = fixture.componentInstance
component.mediaData = waypointImage
fixture.detectChanges()
})
)
it('should create', () => {
// First
jest.mock('../../../services/sanity/sanity.service', () => {
return {
urlFor: jest.fn()
}
})
// Second
const mockSanityService = SanityService as jest.Mock<SanityService> // to avoid typescript alerts
const mockService = jest
.spyOn(mockSanityService.prototype, 'urlFor')
.mockImplementation((source) => {return 'test'})
})
expect(mockService).toHaveBeenCalled()
expect(component.imageUrl).toHaveBeenCalled()
expect(component).toBeTruthy()
})
})
It' seems my mock is ignored. I always get an error from the @sanity/image-url
package which waits for specific data.
What I am doing wrong? What I am not understanding?
Thank you for your help!
CodePudding user response:
I'm not sure it will help, but what I do in my Jest tests when I need to mock a service is the following:
jest.mock('...../myService');
describe('...', () => {
let myServiceMock: MyService;
...
beforeEach(() => {
myServiceMock = TestBed.inject(myServiceMock);
...
jest.spyOn(myServiceMock, 'someServiceMethod').mock...
});
});
CodePudding user response:
Finally find a way to achieve that, thanks to this post : Testing Angular Component using JEST
Here is my test:
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { IonicModule } from '@ionic/angular'
import { MediaImageComponent } from './media-image.component'
import { SanityService } from '../../../services/sanity/sanity.service'
import { waypointImage } from '../../../mocks/waypoint.mocks'
const mockSanityService = {
urlFor: jest.fn()
}
describe('MediaImageComponent', () => {
let component: MediaImageComponent
let fixture: ComponentFixture<MediaImageComponent>
let spy
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [MediaImageComponent],
providers: [{ provide: SanityService, useValue: mockSanityService }],
imports: [IonicModule.forRoot()]
}).compileComponents()
fixture = TestBed.createComponent(MediaImageComponent)
component = fixture.componentInstance
component.mediaData = waypointImage
spy = jest.spyOn(component, 'imageUrl')
fixture.detectChanges()
})
)
afterEach(() => {
if (fixture) {
fixture.destroy()
}
mockSanityService.urlFor.mockReset()
spy.mockClear()
})
it('should create', () => {
mockSanityService.urlFor.mockImplementationOnce(() => 'plop')
expect(mockSanityService.urlFor).toHaveBeenCalled()
expect(spy).toHaveBeenCalled()
expect(component).toBeTruthy()
})
})
I hope it will be useful for someone else :)