Code Monkey home page Code Monkey logo

testing's Introduction


NGXS Testing

Build Status NPM

$ npm install @ngxs-labs/testing --save-dev

Introduction

@ngxs-labs/testing is package for configures and initializes environment for ngxs unit testing and provides methods for creating states in unit tests.

Simple example

Unit testing is easy with NGXS.

import { NgxsTestBed } from '@ngxs-labs/testing';

describe('Zoo', () => {

  it('it toggles feed', async(() => {
    const { selectSnapshot, dispatch } = NgxsTestBed.configureTestingStates({ states: [ ZooState ] });
  
    dispatch(new FeedAnimals());
    const feed = selectSnapshot(state => state.zoo.feed);
    
    expect(feed).toBe(true);
  }));
  
});

Unit testing actions

Use getStateContextMocks to mock and spy on the first argument of @Actions functions: the StateContext.

With this state:

@State({ name: ZOO_STATE_NAME, defaults: { animals: 1, visitors: 10 } })
class ZooState {
    @Action(ResetAnimalAction)
    public reset(ctx: StateContext<any>) {
        ctx.setState({ animals: 1, visitors: 10 });
        ctx.dispatch(new AddAnimalAction());
    }

    @Action(AddAnimalAction)
    public add(ctx: StateContext<any>, { animalAmount }: AddAnimalAction) {
        const state = ctx.getState();
        ctx.patchState({ animals: state.animals + 1 });
    }
}

getStateContextMocks allows the following tests:

it('should set state and dispatch new action', () => {
    const { dispatch, getStateContextMocks } = NgxsTestBed.configureTestingStates({
        states: [ZooState]
    });
    dispatch(new ResetAnimalAction());

    expect(getStateContextMocks[ZOO_STATE_NAME].setState).toHaveBeenCalledWith({ animals: 1, visitors: 10 });

    expect(getStateContextMocks[ZOO_STATE_NAME].dispatch).toHaveBeenCalledWith(new AddAnimalAction());
    expect(getStateContextMocks[ZOO_STATE_NAME].dispatch).toHaveBeenCalledTimes(1);
});

it('should get state and patch to new value', () => {
    const { dispatch, getStateContextMocks } = NgxsTestBed.configureTestingStates({
        states: [ZooState]
    });
    dispatch(new AddAnimalAction());

    expect(getStateContextMocks[ZOO_STATE_NAME].getState).toHaveBeenCalled();
    expect(getStateContextMocks[ZOO_STATE_NAME].patchState).toHaveBeenCalledWith({ animals: 2 });
});

Mock Select

Use mockSelect to quickly mock selector in component. mockSelect provides a Subject allowing to trigger the mocked selector on demand and with any value.

import { mockSelect } from '@ngxs-labs/testing/jest';

describe('Select tests', () => {
    let foodSelectorSubject: Subject<number>;
  
    beforeEach(() => {
        TestBed.configureTestingModule({
            ...
            imports: [
                ...
                NgxsModule.forRoot([ZooState])
            ]
        }).compileComponents();
    
        foodSelectorSubject = mockSelect(ZooState.feed);

        ...
    });
    
    it('should display mocked value', () => {

        foodSelectorSubject.next(10);
        fixture.detectChanges();
        ...
        expect(food).toEqual(10)
    });
});

testing's People

Contributors

2kable avatar aymeric-duchein avatar renovate-bot avatar splincode avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

testing's Issues

Mock dispatch

Hi, I'm creating unit tests and have a problem when testing actions. I would like to mock dispatch function in a way it really dispatches only a tested action and any additional dispatch call are only spied.

Something like this:

    it('should login with valid credentials', async (done) => {
        const action = new Login(validCredentials)

        const dispatchSpy = spyOn(store, 'dispatch').withArgs(action).and.callThrough()

        store.dispatch(action)

        await expect(store.selectSnapshot(AuthState.getError)).toBeFalsy()
        await expect(store.selectSnapshot(AuthState.getPending)).toBeTruthy()

        authTrigger.next()

        const dispatchedLoginSuccessAction = [].concat(...dispatchSpy.calls.allArgs()).find(a => a instanceof LoginSuccess)

        await expect(dispatchedLoginSuccessAction).toBeTruthy()
        await expect(dispatchedLoginSuccessAction.payload).toEqual(token)
    })

BUT! This doesn't work, because as I investigate, the store.dispatch is different from the dispatch function in the action context. I know I can use the construction like this without mocking (and it works):

        actions$.pipe(ofActionDispatched(LoginSuccess)).subscribe(async (action) => {
            await expect(action).toBeTruthy()
            done()
        })

BUT! I don't want to actually dispatch additional actions because of side effects. Consider the tested action dispatches an action from another module, so I would have to mock all services which causes side effects in that module.

I've found out the actual dispatch to be mocked is the one in the InternalStateOperations object, but I don't know how to mock it.

QUESTION So what is the proper way to make tests like this?

is this ready?

Hi, thanks for this package. I am looking forward to use it but last time I checked ngxs website wasn't listed in there so I am not sure if it's ready to be used.

Also, it would be nice to know if I have other questions, where is the best way to ask them?

Documentation for unit testing Actions

I am having some issues with testing an Action which makes a API request and on success it dispatch an action which transform that response into a particular format .Is there any way to test API Action using Jest and check if the store is mutating based on API response.

Add test helper for @Select

Feature Request

When I am unit testing my components that use a store, I often just want to mock the store to check whether the right dispatch methods were called.

However when the component contains @select you'll get a errors like:

Error: SelectFactory not connected to store!

Now we can use ugly hacks like the following to get rid of the errors:

Object.defineProperty(component, 'active$', { writable: true });
component.active$ = of([]);

But it would be nicer if we have the ability to have some helpers to mock the selects, or let the SelectFactory be mockable somehow.

See also: #482

How to mock @Select in ngxs when using a mock store

I am using ngxs for state handling in angular, and I am trying to test our components as units, so preferably only with mock stores, states etc.

What we have in our component is something like:

export class SelectPlatformComponent {

  @Select(PlatformListState) platformList$: Observable<PlatformListStateModel>;

  constructor(private store: Store, private fb: FormBuilder) {
    this.createForm();
    this.selectPlatform();
  }

  createForm() {
    this.selectPlatformForm = this.fb.group({
      platform: null,
    });
  }

  selectPlatform() {
    const platformControl = this.selectPlatformForm.get('platform');
    platformControl.valueChanges.forEach(
      (value: Platform) => {
        console.log("select platform " + value);
        this.store.dispatch(new PlatformSelected(value));
      }
    );
  }

}

And our fixture setup looks like this, so we can check calls on the store:

describe('SelectPlatformComponent', () => {
  let component: SelectPlatformComponent;
  let fixture: ComponentFixture<SelectPlatformComponent>;
  let store: Store;

  beforeEach(async(() => {
    const storeSpy = jasmine.createSpyObj('Store', ['dispatch']);
    TestBed.configureTestingModule({
      imports: [ReactiveFormsModule],
      declarations: [SelectPlatformComponent],
      providers: [{provide: Store, useValue: storeSpy}]

    })
      .compileComponents();
    store = TestBed.get(Store);
  }));

But when we run this, we get the following error:

Error: SelectFactory not connected to store!
    at SelectPlatformComponent.createSelect (webpack:///./node_modules/@ngxs/store/fesm5/ngxs-store.js?:1123:23)
    at SelectPlatformComponent.get [as platformList$] (webpack:///./node_modules/@ngxs/store/fesm5/ngxs-store.js?:1150:89)
    at Object.eval [as updateDirectives] (ng:///DynamicTestModule/SelectPlatformComponent.ngfactory.js:78:87)
    at Object.debugUpdateDirectives [as updateDirectives] (webpack:///./node_modules/@angular/core/fesm5/core.js?:11028:21)
    at checkAndUpdateView (webpack:///./node_modules/@angular/core/fesm5/core.js?:10425:14)
    at callViewAction (webpack:///./node_modules/@angular/core/fesm5/core.js?:10666:21)
    at execComponentViewsAction (webpack:///./node_modules/@angular/core/fesm5/core.js?:10608:13)
    at checkAndUpdateView (webpack:///./node_modules/@angular/core/fesm5/core.js?:10431:5)
    at callWithDebugContext (webpack:///./node_modules/@angular/core/fesm5/core.js?:11318:25)
    at Object.debugCheckAndUpdateView [as checkAndUpdateView] (webpack:///./node_modules/@angular/core/fesm5/core.js?:10996:12)

I could enable the entire ngxs module for this, but then I would need to create services mocks to inject into state objects, which I do not like because I am then not testing the component in isolation anymore. I tried to create a mock SelectFactory, but it seems it is not exported from the module.

Is there a way to mock the SelectFactory, or inject some mocks into the platformList$ directly? Other suggestions?

PS: I also asked this on stackoverflow, but no real answer was given: https://stackoverflow.com/questions/51082002/how-to-mock-select-in-ngxs-when-using-a-mock-store

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.