Khetesh kumawat
Khetesh kumawat

Reputation: 711

How to override Provider in Angular 13 for angular testing Jasmine Karma?

So i've looked at many issues online related override Provider but not getting success. Showing in this code i have already working in angular version 7 this test case working fine.When i upgrade to angular version 13 than test cases are failing and getting errors like this. This error relate to overrideProviders when code comment in component than all test case success Otherwise failed. I have to created mock several times the same service with different mocks.

Error: Actions must be plain objects. Use custom middleware for async actions. enter image description here

Here Is package Json File screenshot enter image description here For example, something like this code component.ts file.

import { Component } from '@angular/core';
import { ReleaseAction } from 'src/app/actions/release.action';
import { RELEASE_INIT_STATE } from '../../../../utils/constants/release_setup.constant';
import { ReduxStore } from 'src/app/store/Redux.store';
import { Router } from '@angular/router';
import * as _ from 'lodash';

@Component({
  selector: 'add-release',
  templateUrl: './add-release.component.html',
  styleUrls: ['./add-release.component.scss'],
  viewProviders: [ReleaseAction],
})
export class AddReleaseComponent {
  ReduxStore;
  state;
  breadCrumbsList;
  release_setupDetailsLink = '/release_setup/details';
  releaseForm: any = RELEASE_INIT_STATE;
  constructor( private _releaseAction: ReleaseAction, public router: Router) {
      this.ReduxStore = ReduxStore.getReduxStore();
      this.breadCrumbsList = [{text: 'Release Setup' , id: this.release_setupDetailsLink}];
  }

  onReleaseFormSubmit(formValues) {

      this.ReduxStore.dispatch(this._releaseAction.addRelease(formValues));
  }

}

For example, something like this code spec file.

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
import { ReleaseAction } from 'src/app/actions/release.action';
import { Router } from '@angular/router';
import { RELEASE_INIT_STATE } from '../../../../utils/constants/release_setup.constant';
import { _ } from 'lodash';
import { AddReleaseComponent } from './add-release.component';
import { ReduxStore } from 'src/app/store/Redux.store';
import configureStore from 'redux-mock-store' //ES6 modules
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

const middlewares = []
const mockStore = configureStore(middlewares)

describe('AddReleaseComponent', () => {
  let component: AddReleaseComponent;
  let fixture: ComponentFixture<AddReleaseComponent>;
  const initialState = {};  
  let ReduxStore;
  beforeEach(() => {
    ReduxStore = mockStore(initialState);
    spyOn(ReduxStore, "getReduxStore").and.returnValue(ReduxStore);
    const releaseActionStub = { addRelease: formValues => ({type: "TRIGGER_LAST_RELEASE"}) };
    const routerStub = { navigateByUrl: release_setupDetailsLink => ({}) };
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule, ReactiveFormsModule, FormsModule],
      schemas: [NO_ERRORS_SCHEMA],
      declarations: [AddReleaseComponent]
      ,providers: [
        { provide: Router, useValue: routerStub }
      ]
    })

    TestBed.overrideProvider(ReleaseAction, { useValue: releaseActionStub });
    TestBed.overrideProvider(Router, { useValue: routerStub });
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(AddReleaseComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });
  it('can load instance', () => {
    console.log("add-release");
    expect(component).toBeTruthy();
  });

  describe('onReleaseFormSubmit', () =>{
    it('addRelease and url called properly', () => {
      let releaseForm = component.releaseForm;
      component.onReleaseFormSubmit(component.releaseForm);
      expect(component.ReduxStore.getActions()).toContain({type:"TRIGGER_LAST_RELEASE"})
      
    });
  });


});

All code same working fine in angular7 but not working in angular13. Could you explain me how to use it properly? Or have you an other method to do that?

It just doesn't feel right that I would have to do so when the only thing I need to change is the provider, i'm unsure what overrideProvider even does at this point! Any help would be greatly appreciated!

Upvotes: 1

Views: 4396

Answers (2)

GKA
GKA

Reputation: 1356

The config kind of does not make sense. Why have a providers section within the TestBed and then override providers separately below it?

TestBed.configureTestingModule({
  providers: [
    { provide: Router, useValue: routerStub },
    // this makes more sense for the scenario described above
    { ReleaseAction, useValue: releaseActionStub },
    { Router, useValue: routerStub },
  ]
})

// Why do this here separately?
// TestBed.overrideProvider(ReleaseAction, { useValue: releaseActionStub });
// TestBed.overrideProvider(Router, { useValue: routerStub });

But if for some reason you needed to override the provider for different tests/scenarios then you still have to define it in the main providers: [] and then override it

Kind of makes sense if you think about. First you specify the initial provider then you override it.

TestBed.configureTestingModule({
  providers: [
    { provide: Router, useValue: routerStub },
    // define the initial value
    { ReleaseAction, useValue: releaseActionStub },
    { Router, useValue: routerStub },
  ]
})

// in a beforeEach() or it()
// override the initial value
TestBed.overrideProvider(ReleaseAction, { useValue: releaseActionStubOverride });
TestBed.overrideProvider(Router, { useValue: routerStubOverride });

Note that you cannot override once the TestBed has been "compiled"

Upvotes: 0

satanTime
satanTime

Reputation: 13539

viewProviders is a tricky topic, especially to override and restore them.

you can use ng-mocks. It will take care how to mock it and how to restore it:

beforeEach(() => {
  return MockBuilder(
    [
      // things to test
      AddReleaseComponent,

      // additional imports
      HttpClientTestingModule,
      ReactiveFormsModule,
      FormsModule,
    ],

    // its module to mock dependencies
    AddReleaseModule,
  )

  // customizing the mock of the viewProvider dependency
  .mock(ReleaseAction, {
    addRelease: formValues => ({type: "TRIGGER_LAST_RELEASE"}),
  })

  // providing Router
  .provide(
    MockProvider(
      Router,
      {navigateByUrl: release_setupDetailsLink => ({})}
    ),
  );
});

it('test', () => {
  const fixture = TestBed.createComponent(AddReleaseComponent);
  // ReleaseAction is its mock.
});

You can do that with other providers too: root providers, module providers, etc.

Upvotes: 1

Related Questions