Search code examples
angularstorybookangular-redux

Testing Angular with @angular-redux/store in Storybook


I wrote this up on @angular-redux/store and was wondering if a solution already existed.

https://github.com/angular-redux/store/issues/551

Here's a recap to save you from reading the link:

Using Angular and Storybook has worked out well so far. However, I have cases where my component is dependent upon @select(). How can I tell the component in my story to use a mocked observable or data point?

Here's my sample code:

import { storiesOf, moduleMetadata } from '@storybook/angular';

import { CommonModule } from '@angular/common';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

// Modules
... custom modules ...


// Components
...myAppComponents...
import { MyParticularComponent as component } from './my-particular.component';


// Mock Data
... mock json data...

const props = { ...mockData... };

storiesOf('This Particular Component', module)
  .addDecorator(
    moduleMetadata({
      declarations: [component, ...other components...],
      imports: [
        CommonModule,
        BrowserAnimationsModule,
        ...custom modules...
      ],
      schemas: [],
      providers: []
    })
  )
  .add('Some View of the Component', () => ({
    component,
    props
  }));

And my component has:

@Input()
someInput: string;

@select()
stateValue$: Observable<SomeData>;

propOne;
propTwo;

ngOnInit() {
    this.stateValue$.subscribe(data => {
      const { propOne, propTwo } = data;
      this.propOne = propOne;
      this.propTwo = propTwo;
    });
  }

Solution

  • First, I create props for my component. If anything has an @select decorator, then it needs to belong in an '@angular-redux::substore::instance::selections' property. Here we go:

    const createProps = {
    
       const stateValue: DataStruct = {...};
    
       // Create the Observable.  Need .next and .complete for subscribe.
       const stateValue$: Subject<DataStruct> = MockNgRedux.getSelectorStub('stateValue');
       stateValue$.next(stateValue);
       stateValue$.complete();
    
       return {
          someInput: 'Hello World!',
          '@angular-redux::substore::instance::selections': {
               stateValue$
           }
       }
    }
    
    
    ...
    .add('Some View of the Component', () => ({
        component,
        props: createProps()
    }));