Expression has changed after it was checked, getting error in testing an angular 2 component with jasmine

11,937

Solution 1

The changes should be detected every time the value is changed and your before Each will be executed before the value is assigned so hi will get the error have the

fixture.detectChanges(); 

Inside your it statements and call for every change in value.

Update 1:

import { ManualProcessService } from '../../services/manual-process.service';
import { ManualProcessComponent } from './manual-process.component';
import { MANUALPROCESSMOCKDATA } from '../../shared/mocks/mock-manualprocessdata';
import { IManualProcessData } from '../../models/manual-process.model';
import {
    async,
    TestBed,
    fakeAsync,
    tick,
} from '@angular/core/testing';
// used to interact with the HTML elements 
import { By } from '@angular/platform-browser';

describe('Testing Manual Process Component', () => {

    let fixture,
        event = {
            first: 0,
            rows: 10
        },
        manualProcessService;
    let hardCodedData = {
        ...
    };
    beforeEach(async () => {
        TestBed.configureTestingModule({
            imports: [],
            declarations: [ManualProcessComponent],
            providers: [
                { provide: ManualProcessService, useValue: mockManualProcessService }
            ]
        }).compileComponents();
    });

    beforeEach(() => {
        fixture = TestBed.createComponent(ManualProcessComponent);
        component = fixture.componentInstance;
        debugElement = fixture.debugElement;
        element = fixture.nativeElement;
        // analyse your component and the variables used in it and make hard values of them
        let variables;
        // Note: Never call detectChanges() inside a beforeEach
    })

    it('Filters should be reset', (done) => {
        fixture.componentInstance.clearFilters();
        fixture.detectChanges();
        expect(fixture.componentInstance.filterBy.length).toBe(0);
        done();
    })

    it('Should load list of manual process files', fakeAsync(() => {
        fixture.componentInstance.loadData(event);
        tick();
        fixture.detectChanges();
        expect(fixture.componentInstance.filterBy.length).toBe(10);
    }));

    it('a sample case to check if the text box contains expected value aor not',()=>{
        expect(debugElement.query(By.css('.className')).nativeElement.textContent).toBe('somename');
    });
});

Solution 2

I was having this problem too, and changed my test to target the component's ngOnInit() method directly. So, instead of

fixture.detectChanges();

in your tests, you could try

fixture.componentInstance.ngOnInit();

(or whatever lifecycle hook is the entry point for your component). That worked for me. It unblocked me from tests that were falling over even though the component itself ran fine.

Share:
11,937
Sahil Agarwal
Author by

Sahil Agarwal

Updated on June 15, 2022

Comments

  • Sahil Agarwal
    Sahil Agarwal almost 2 years

    I am getting an error while testing a component that is receiving an observable from the service, I have tried to mock that behaviour in the spec but I am getting the following error: Expression has changed after it was checked, previous vale '', current value: [object Object]. Could you please help me with this. My spec file is as follows:

    import { ManualProcessService } from '../../services/manual-process.service';
    import { ManualProcessComponent } from './manual-process.component';
    import { MANUALPROCESSMOCKDATA } from '../../shared/mocks/mock-manualprocessdata';
    import {DataTableModule, SharedModule, DropdownModule as PrimeNgDropDownModule, CheckboxModule, InputTextModule} from 'primeng/primeng';
    import {MenuModule} from 'primeng/components/menu/menu';
    import {DropdownModule} from 'ng2-bootstrap';
    import { PopoverModule } from 'ng2-popover';
    import {Observable} from 'rxjs/Observable';
    import { IManualProcessData} from '../../models/manual-process.model';
    import {FormsModule, ReactiveFormsModule} from '@angular/forms';
    import {
      async,
      TestBed,
      fakeAsync,
      tick,
    } from '@angular/core/testing';
    
    class MockManualProcessService {
    
      getManualProcessData(): Observable<IManualProcessData> {
          return Observable.of(MANUALPROCESSMOCKDATA);
      }
    }
    
    describe('Testing Manual Process Component', () => {
    
      let fixture,
      event = {
        first: 0,
        rows: 10
      }, 
      manualProcessService;
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          declarations: [
            ManualProcessComponent
          ],
          providers: [
            { provide: ManualProcessService, useClass: MockManualProcessService }
          ],
          imports: [
            FormsModule, 
            ReactiveFormsModule,
            DataTableModule,
            SharedModule,
            PopoverModule,
            PrimeNgDropDownModule,
            DropdownModule.forRoot(),
            CheckboxModule,
            InputTextModule,
            MenuModule
        ],
        });
        fixture = TestBed.createComponent(ManualProcessComponent);
        manualProcessService = TestBed.get(ManualProcessService);
        spyOn(manualProcessService, 'getManualProcessData').and.returnValue(Observable.of(MANUALPROCESSMOCKDATA));
        fixture.detectChanges();
      });
    
      it('Filters should be reset', (done) => {
        fixture.componentInstance.clearFilters()
        fixture.detectChanges();
        expect(fixture.componentInstance.filterBy.length).toBe(0);
        done();
      })
    
    
      it('Should load list of manual process files', fakeAsync(() => {
        fixture.componentInstance.loadData(event);
        tick();
        fixture.detectChanges();
        expect(fixture.componentInstance.filterBy.length).toBe(10);
      }));
    });
    

    I am new to angular 2 and unit testing. Can someone guide, what am I doing wrong.