简体   繁体   中英

property is not declared configurable (Error: <spyOnProperty>)

Given a MenuComponent

@Component({
  selector: 'cg-menu',
  templateUrl: './menu.component.html',
  styleUrls: [ './menu.component.scss' ]
})
export class MenuComponent implements OnInit {
  menu: MenuItem[];

  isLoggedIn$ = this.authStateService.isLoggedIn.pipe(untilDestroyed(this));

  constructor(private readonly authStateService: AuthStateService,
              private readonly router: Router) {
  }

  ngOnInit() {
    this.authStateService
      .state
      .pipe(
        untilDestroyed(this),
        ...some logic...
      .subscribe();
  }

  ...some logic...
}

and a AuthStateService

@Injectable({ providedIn: 'root' })
export class AuthStateService {
  private readonly state$: Observable<AuthState | null>;
  private readonly isLoggedIn$: Observable<boolean | null>;

  constructor(private readonly sessionManager: SessionManagerService) {

    this.state$ = this.stateTrigger$
      .pipe(
        ...some logic...
        shareReplay(1));

    this.isLoggedIn$ = this.stateTrigger$
      .pipe(
        map(state => state !== null),
        shareReplay(1));
  }

  get state(): Observable<AuthState> {
    return this.state$;
  }

  get isLoggedIn(): Observable<boolean> {
    return this.isLoggedIn$;
  }

  ...some logic...
}

When I'm trying to run this code, Karma is triggering an error.

describe('MenuComponent', () => {
  let component: MenuComponent;
  let fixture: ComponentFixture<MenuComponent>;

  let authStateServiceSpy;

  beforeEach(async(() => {
    authStateServiceSpy = jasmine.createSpyObj(
      'AuthStateService',
      {},
      {
        state: of(null),
        isLoggedIn: of(false)
      });

    TestBed.configureTestingModule({
      declarations: [ MenuComponent ],
      imports: [ RouterTestingModule ],
      providers: [
        { provide: AuthStateService, useValue: authStateServiceSpy }
      ],
      schemas: [ NO_ERRORS_SCHEMA ]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MenuComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should generate correct menu (expert)', () => {
    // The problem is here
    spyOnProperty(authStateServiceSpy, 'state', 'get').and.callFake(() => of(stateMock));

    expect(component.menu).toEqual([
      ...something...
    ]);
  });
});

The error is this.

Error: <spyOnProperty> : state is not declared configurable
    Usage: spyOnProperty(<object>, <propName>, [accessType])
    Error: <spyOnProperty> : state is not declared configurable
    Usage: spyOnProperty(<object>, <propName>, [accessType])
        at <Jasmine>
        at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/src/app/modules/structure/components/menu/menu.component.spec.ts:55:5)
        at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:364:1)
        at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:292:1)
        at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:363:1)
        at Zone.run (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:123:1)
        at runInTestZone (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:545:1)
        at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:560:1)

Any idea what I'm doing wrong? Thanks for help.

I guess it's because AuthStateService 's state is a getter in the class, but your mock declares it as regular property. You should declare it as getter as well.

The issue seems related to using createSpyObj in conjunction with spyOnProperty , since it's not a real getter you're trying to spy on.

Looking at your code, there seems to be no reason to use createSpyObj though, so this might do the trick:

    // ... 

    authStateServiceMock = {
        get state() { return of(null) },
        get isLoggedIn() { return of(false) },
    };

    // ...

    spyOnProperty(authStateServiceMock, 'state', 'get').and.callFake(() => of(stateMock));
    
    expect(component.menu).toEqual([
        ...something...
    ]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM