Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 903
Sahil Agarwal Avatar asked Feb 22 '17 05:02

Sahil Agarwal


People also ask

How do you fix ng0100 expression has changed after it was checked?

Navigate up the call stack until you find a template expression where the value displayed in the error has changed. Ensure that there are no changes to the bindings in the template after change detection is run. This often means refactoring to use the correct component lifecycle hook for your use case.

Where should we call the detectChanges () method if we want to ensure that an initial data binding has occurred prior to a test being executed?

Your first call of detectChanges() is NgOninit , your second call of detectChanges() updates the view and initiates data binding . Your additional example illustrates this fact. The first call to detectChanges() which does call NgOnInit is in line 27 (first example) and line 37 (second example) in the beforeEach block.


1 Answers

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');
    });
});
like image 158
Aravind Avatar answered Sep 24 '22 20:09

Aravind