简体   繁体   中英

How do i fetch my NGRX store state in Cypress test

I am trying to fetch my store state in my Cypress test. As advised here: Cypress - programmatically manipulating Angular/NGRX app I am exposing my store in my angular component this way:

  constructor(private store: Store<MigrationsState>) {
    if (window.Cypress) {
      window.store = this.store;
    }
  }

And I can get the store this way:

cy.window().its('store')

but when doing:

cy.window().its('store').invoke('getState')

as explained in the cypress docs (it is indeed aiming for Redux stores) - https://www.cypress.io/blog/2018/11/14/testing-redux-store/ , I am failing to get the state:

Timed out retrying after 20000ms: cy.invoke() errored because the property: getState does not exist on your subject. cy.invoke() waited for the specified property getState to exist, but it never did. If you do not expect the property getState to exist, then add an assertion such as: cy.wrap({ foo: 'bar' }).its('quux').should('not.exist')

Any idea what should I do differently here?

There's a difference between ngrx and redux api, see here NgRx API - unfortunately there's no .getState() method in ngrx.

NgRx have deliberately removed the ability to synchronously access the state values (which is what Redux .getState() does).

You can try using the function shown here How to get current value of State object with @ngrx/store . Since it uses RxJs operators, you would have to add the function to your store in the Angular app.

This version is the latest:

function getState(store: Store<State>): State {
  let state: State;
  store.pipe(take(1)).subscribe(s => state = s);
  return state;
}

Timing

There's some debate in the comments about this code running synchronously, but it looks like it can give you a "snapshot" at the time you make the call (from inside the test).

The problem will be timing the test assertions with the state updates in the app. Cypress has should() command to retry the DOM changes, but it won't retry RxJs queries.

You will probably need a recursive function on the test side to "poll" the state.

Roughly,

function assertStateValue(key, value, attempts = 0) {

  if (attempts > 10) {

    // with 100ms poll interval, this waits 1 second for RxJs to complete
    // adjust if you need more time

    throw new Error('Too many attempts, failing assertion')
  }

  const state = cy.state('window').store.getState() // only works after adding getState() in the app
  if (state[key] === value) { 
    return true
  } else {
    cy.wait(100)    // allow small time for RxJs to process in the app
    return assertStateValue(key, value, ++attempts)
  }
}

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