Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: Provide usage examples of MockStore#overrideSelectors in component tests #1778

Closed
damienwebdev opened this issue Apr 20, 2019 · 3 comments

Comments

@damienwebdev
Copy link

damienwebdev commented Apr 20, 2019

Other information:

@brandonroberts new MockStore.overrideSelectors API needs further documentation, as using it is a bit of a pain at the moment.

#915 #1504 #1688 #1761

Goal

As a developer, I would like to write an integration test that asserts that I've properly passed my State data down into a subcomponent. Specifically, I would optionally like to be able to test additional cases surrounding what happens if I want to try different types of data configurations passed into a subcomponents input or an *ngIf on a component in a container template.

Use case

As a trivial example, assume the following component setup and template:

Template

<my-form [errors]="errors$ | async"></my-form>

Component Definition(Container)

import { Component, OnInit } from '@angular/core';
import { Store, select } from '@ngrx/store';

import { Observable } from 'rxjs';
import { selectFormErrorsState } from './selectors';

@Component({
  selector: 'my-form-container',
  templateUrl: './my-form-container.component.html'
})
export class MyFormContainer implements OnInit {

  errors$: Observable<string[]>;

  constructor(private store: Store<State>) { }

  ngOnInit() {
    this.errors$ = this.store.pipe(select(selectFormErrorsState));
  }
}

Container Spec

describe('MyFormContainer', () => {
  let component: MyFormContainer;
  let fixture: ComponentFixture<MyFormContainer>;
  let mockStore: MockStore<State>;
  let form: MyFormComponent;
  let formDe: DebugElement;
  let formErrors: MemoizedSelector<object, string[]>;


  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [MyFormComponentModule],
      declarations: [
        MyFormContainer
      ],
      providers: [provideMockStore()],
      schemas: []
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MyFormContainer);
    component = fixture.componentInstance;

    mockStore = TestBed.get(Store);
    spyOn(mockStore, 'dispatch');
    
    formErrors = mockStore.overrideSelector(selectFormErrorsState, []);

    fixture.detectChanges();

    formDe = fixture.debugElement.query(By.css('my-form'));
    form = formDe.componentInstance;
  });

  it('should compile', () => {
    expect(form).toBeTruthy();
  });

  it('should set the `errors` input on `my-form`', () => {
    mockStore.resetSelectors();
    formErrors.release();
    
    formErrors = mockStore.overrideSelector(selectFormErrorsState, ['an error']);
    formErrors.setResult(['an error'])

    fixture.detectChanges();
    
    expect(form.errors).toEqual(['an error']);
  });
});

Specifically, look at the above test. Ideally, I'd like to assert that if the state of the selectFormErrorsState selector changes, then so does the property errors on the my-form component.

Currently, the output is:

Expected $.length = 0 to equal 1.
Expected $[0] = undefined to equal 'an error'.

I think the issue at hand is that the Store observable isn't updating a new state, but I even tried to forcibly do that via MockStore#setState but to no avail;

Notes

While this is a trivialized use-case, I plan on using this in various situations, and currently, doing so is pretty frustrating even in the above case.

I would be willing to submit a PR for the docs ❤️

[x] Yes (Assistance is provided if you need help submitting a pull request)
[ ] No

@damienwebdev
Copy link
Author

I'm closing this as a duplicate of #1761, but this should be covered as a case in both tests & documentation there.

@timdeschryver
Copy link
Member

form.errors is an Observable, you should use toBeObservable to assert the expected output.

expect(form.errors).toBeObservable(cold('(a|)', {a: ['an error']}))

@damienwebdev
Copy link
Author

@timdeschryver form.errors is off the dumb component, and is not an observable, it is a string array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants