1

Background

I have two Case need to test

  • should form valid when going to next page

    1. set form valid is true
    2. call goToNextPage()
    3. expect result is truthy
  • should form valid when filling out option info then going to next page

    1. set form valid is true
    2. open option info block
    3. ensure the form is valid
    4. call goToNextPage()
    5. expect result is truthy

Question

In step 3 of the second test, It will throw an Error When I spy a property by spyOnProperty more than two times

spyOnProperty(myObject, 'myPropertyName').and.returnValue(...);

Error: 'myPropertyName' has already been spied upon

I refer to the solutions of the past few years and write a temporary solution below. Are there any easier ways to solve this now?


My Temp Solution

  • set jasmine.getEnv().allowRespy(true);
  • cache the first spy and use it later

class SamplePageHelper {

  private respyHelper = new JasmineRespyHelper();

  constructor(
    public samplePage: SamplePage
  ) {

  }

  fakeValid() {
    // spyOnProperty(this.samplePage, 'isValid').and.returnValue(true);
    this.respyHelper.spyOnProperty(this.samplePage, 'isValid').and.returnValue(true);
  }



}
// helper
class JasmineRespyHelper {

  private cacheList = new Map();

  constructor() {
    jasmine.getEnv().allowRespy(true);
  }

  spyOnProperty < T > (object: T, property: keyof T, accessType ? : 'get' | 'set'): jasmine.Spy {
    const objectKey = object.constructor.toString().substring(0, 15);
    const cacheKey = `${objectKey}_${property}_${accessType || ''}`;
    //
    let spy = this.cacheList.get(cacheKey);
    const isNoCached = !spy;
    if (isNoCached) {
      spy = spyOnProperty(object, property, accessType);
      this.cacheList.set(cacheKey, spy);
    }
    //
    return spy;
  }
}

Online Sample

https://stackblitz.com/edit/jsamine-respy?file=src/test/sample.spec.ts

describe('demo (no TestBed):', () => {

  let samplePage;
  let samplePageHelper;
  
  beforeEach(() => {
    samplePage = new SamplePage();
    samplePageHelper = new SamplePageHelper(samplePage);
  })

  it('shoud valid when write option fields then go to next page', () => {
    samplePageHelper.fakeValid();
     //
    samplePage.openOptionFieldBlock();
    //  new option field value will trigger form validator

    // ensure `goToNextPage()` can be executed needs to specify isValid to true again
    // Error: isValid has already been spied upon
    samplePageHelper.fakeValid();


    const isSuccess = samplePage.goToNextPage();

    expect(isSuccess).toBeTruthy();
  })

  it('shout valid when go to next page', () => {
    samplePageHelper.fakeValid();

    const isSuccess = samplePage.goToNextPage();

    expect(isSuccess).toBeTruthy();
  })
});


class SamplePage {

  private formService = new FormServiceStub();

  get isValid() {
    // trigger form field's validator
    // real code like this : formService.validationAll(); 
    return this.formService.valiationAll();
  }

  constructor() {
  }

  openOptionFieldBlock() {
    if (this.isValid) {
      // do someting 
    }
  }

  goToNextPage() {
    if (this.isValid) {
      // do someting

      const isSuccess = true;
      return isSuccess;
    }

    return false;
  }

  showOptionFields() {
    return true;
  }


}


// stub
class FormServiceStub {
  valiationAll() {
    // it's have more codition in real code , return true for the demo
    return true;
  }
}

class SamplePageHelper {

  constructor(
    public samplePage: SamplePage
  ) {

  }

  fakeValid() {
    spyOnProperty(this.samplePage, 'isValid').and.returnValue(true);
  }



}
Chunbin Li
  • 2,196
  • 1
  • 17
  • 31

0 Answers0