angular-redux / store

Angular 2+ bindings for Redux
MIT License
1.34k stars 205 forks source link

Unit Tests: Question About Setting Up NgReduxTestingModule #545

Closed lcecil closed 5 years ago

lcecil commented 5 years ago

This is a...

What toolchain are you using for transpilation/bundling?

Environment

NodeJS Version: 8.11.2 Typescript Version: 2.7.2 Angular Version: 6.0.9 @angular-redux/store version: 9.0.0 @angular/cli version: (if applicable)

Description

I've read through the unit test examples, and believe that I have my set up correct. However, it seems like my mock instance is not being substituted for the real NgRedux that is injected.

Simplified Code

Component

  export class MyComponent implements OnInit {
    state: ApplicationState;
    constructor(private ngRedux: NgRedux<ApplicationState>) {}

    ngOnInit() {
       this.state = this.ngRedux.getState();
    }
  }

Unit Test

  // In the main describe...
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ NgReduxTestingModule ],
      declarations: [ MyComponent ],
      schemas: [ NO_ERRORS_SCHEMA ]
    })
    .compileComponents();
    MockNgRedux.reset();
   }));

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

  it('should set the initial state object', () => {
    const spy = spyOn(MockNgRedux.mockInstance, 'getState');
    expect(spy).toHaveBeenCalled();
  });

Error Message

When I run my tests with the code above, I get the message: Expected spy getState to have been called.

Am I missing something in my set up?

graemeNorman commented 5 years ago

Not sure if this would be help but I think mockInstance method has been deprecated and replace with getInstance - check in @angular-redux/store/testing/ng-redux.mock.ts

lcecil commented 5 years ago

@graemeNorman Hello. I was originally using getInstance() but didn't find any difference in the behavior, and my problem still exists. Good to know it's deprecated though - I'll go ahead and change to using that.

graemeNorman commented 5 years ago

@lcecil I haven't had much luck with getting that module to work either - haven't found the documentation very useful.

gregkopp commented 5 years ago

Since all of this is asynchronous, you should consider wrapping your test in fakeAsync:

  it('should set the initial state object', fakeAsync(() => {
    const spy = spyOn(MockNgRedux.mockInstance, 'getState');
   fixture.detectChanges();
    tick();
    expect(spy).toHaveBeenCalled();
  }));

Not sure if this helps or not. I've been using this mocking framework for a while. Took some effort to get it working. However, I have since abstracted Redux away from all of my components, so that I rarely, if ever, have to mock Redux.

lcecil commented 5 years ago

Hi @gregkopp ,

I ended up getting an answer in this thread: https://github.com/angular-redux/platform/issues/47#issuecomment-452481864

And you have the correct solution above - calling fixture.detectChanges() after spyOn(MockNgRedux.getInstance(), 'getState').

However, I'm not sure that wrapping it in a fakeAsync really matters. the ngOnit isn't asynchronous, is it? And i'm just checking to see whether the the method has been called, not check the value of the getState observable.