Stack Exchange
Undefined dependency using Jasmine
I would like to test this code :
   constructor(drawingService: DrawingService) {
       super(drawingService);
       //...
    }

   private writeOnCanvas(): void {
      this.drawingService.clearCanvas(this.drawingService.previewCtx);

      this.drawingService.baseCtx.fillStyle = 'red';
      this.drawingService.baseCtx.font = 'arial 20px';
      this.drawingService.baseCtx.textAlign = 'center';

      this.drawingService.baseCtx.fillText("hello",0, 0);
}

This is DrawingService :
export class DrawingService {
   baseCtx: CanvasRenderingContext2D;
   previewCtx: CanvasRenderingContext2D;
   cursorCtx: CanvasRenderingContext2D;
   canvas: HTMLCanvasElement;
   previewCanvas: HTMLCanvasElement;

   clearCanvas(context: CanvasRenderingContext2D): void {
       //do something
   }

This is my .spec file :
fdescribe('TextService', () => {
  let service: TextService;
  let drawingServiceSpy: jasmine.SpyObj<DrawingService>;
  // const drawingServiceMock = {
  //   clearCanvas: jasmine.createSpy('clearCanvas'),
  //   baseCtx : CanvasRenderingContext2D,

beforeEach(() => {
  TestBed.configureTestingModule({
    providers: [ 
       { provide: DrawingService, useValue: drawingServiceSpy },
    ]
  });
  drawingServiceSpy = jasmine.createSpyObj('DrawingService',['clearCanvas']);
  service = TestBed.inject(TextService);
});


it('shoud write on baseCtx', () => {
  const ctx = CanvasType.baseCtx;
  service['drawingService'].baseCtx.fillStyle = 'red';
  service['drawingService'].baseCtx.font = 'Bold 10px Arial';
  service['drawingService'].baseCtx.textAlign = 'center' as CanvasTextAlign;

  service['writeOnCanvas'](ctx);

  expect(drawingServiceSpy.clearCanvas).toHaveBeenCalled();
  expect(drawingServiceSpy.baseCtx.fillText).toHaveBeenCalled();
});

I get the
Cannot set property 'fillStyle' of undefined' error.

I think the problem comes from
{
  provide: DrawingService,
  useValue: drawingServiceSpy
}

I tried to use a mockClass but i got errors ...

Your order seems to be off.
Try this:
beforeEach(() => {
  // put this line first so then it can be provided in the useValue properly
  drawingServiceSpy = jasmine.createSpyObj('DrawingService',['clearCanvas']);
  TestBed.configureTestingModule({
    providers: [ 
       { provide: DrawingService, useValue: drawingServiceSpy },
    ]
  });
  service = TestBed.inject(TextService);
});


Then for the test, first set baseCtx to an empty object before proceeding.
it('shoud write on baseCtx', () => {
  // first set baseCtx to an empty object before setting properties in it
  service['drawingService'].baseCtx = {};
  service['drawingService'].baseCtx.fillStyle = 'red';
  service['drawingService'].baseCtx.font = 'Bold 10px Arial';
  service['drawingService'].baseCtx.textAlign = 'center' as CanvasTextAlign;

  service['writeOnCanvas'](ctx);

  expect(drawingServiceSpy.clearCanvas).toHaveBeenCalled();
  expect(drawingServiceSpy.baseCtx.fillText).toHaveBeenCalled();
});

