3
votes

Test de l'effet NGRX avec retard

Je souhaite tester un effet qui fonctionne comme suit:

  1. L'effet démarre si l'action LoadEntriesSucces a été distribuée
  2. Il attend 5 secondes
  3. Au bout de 5 secondes, la requête http est envoyée
  4. Lorsque la réponse arrive, une nouvelle action est envoyée (selon que la réponse a été un succès ou une erreur).

Le code de l'effet ressemble à ceci:

Expected $.length = 0 to equal 3.
Expected $[0] = undefined to equal Object({ frame: 20, notification: Notification({ kind: 'N', value: undefined, error: undefined, hasValue: true }) }).
Expected $[1] = undefined to equal Object({ frame: 30, notification: Notification({ kind: 'N', value: undefined, error: undefined, hasValue: true }) }).
Expected $[2] = undefined to equal Object({ frame: 50, notification: Notification({ kind: 'N', value: LoadEntriesSucces({ payload: Object({ entries: [ Object({ type: 'type', userText: 'userText', ipAddress: '0.0.0.0' }) ] }), type: '[Subnet Browser API] Load Entries Succes' }), error: undefined, hasValue: true }) }).

Ce que je veux tester, c'est si un effet est distribué après 5 secondes:

it('should dispatch action after 5 seconds', () => {
  const entries: SubnetEntry[] = [{
    type: 'type',
    userText: 'userText',
    ipAddress: '0.0.0.0'
  }];

  const action = new SubnetBrowserApiActions.LoadEntriesSucces({entries});
  const completion = new SubnetBrowserApiActions.LoadEntriesSucces({entries});

  actions$ = hot('-a', { a: action });
  const response = cold('-a', {a: entries});
  const expected = cold('- 5s b ', { b: completion });

  subnetBrowserService.getSubnetEntries = () => (response);

  expect(effects.continuePollingEntries$).toBeObservable(expected);
});

Cependant, ce test ne fonctionne pas pour moi. Le résultat du test ressemble à ceci:

  @Effect()
  continuePollingEntries$ = this.actions$.pipe(
    ofType(SubnetBrowserApiActions.SubnetBrowserApiActionTypes.LoadEntriesSucces),
    delay(5000),
    switchMap(() => {
      return this.subnetBrowserService.getSubnetEntries().pipe(
        map((entries) => {
          return new SubnetBrowserApiActions.LoadEntriesSucces({ entries });
        }),
        catchError((error) => {
          return of(new SubnetBrowserApiActions.LoadEntriesFailure({ error }));
        }),
      );
    }),
  );

Que dois-je faire pour que ce test fonctionne?


3 commentaires

Avez-vous déjà trouvé une solution? Je suis prêt à utiliser TestScheduler, mais je ne l'ai jamais fait fonctionner. dev.to/mokkapps/ …


Non, j'ai fini par ne pas le tester du tout:


Voir ma réponse ci-dessous. Cela a fonctionné pour moi. Vous pouvez également ajouter un paramètre à votre effet pour désactiver la minuterie, de sorte que vous n'ayez pas à vous soucier de passer le délai des secondes. Dis-moi si tu as besoin d'aide.


3 Réponses :


1
votes

vous pouvez utiliser le rappel done de jasmine

it('should dispatch action after 5 seconds', (done) => {
  const resMock = 'resMock';
  const entries: SubnetEntry[] = [{
    type: 'type',
    userText: 'userText',
    ipAddress: '0.0.0.0'
  }];

  const action = new SubnetBrowserApiActions.LoadEntriesSucces({entries});
  const completion = new SubnetBrowserApiActions.LoadEntriesSucces({entries});

  actions$ = hot('-a', { a: action });
  const response = cold('-a', {a: entries});
  const expected = cold('- 5s b ', { b: completion });

  subnetBrowserService.getSubnetEntries = () => (response);
  effects.continuePollingEntries$.subscribe((res)=>{
    expect(res).toEqual(resMock);
    done()
  })
});


4 commentaires

Il ne teste pas du tout si la réponse est arrivée après 5 secondes :(


vous voulez tester pour tester votre temps de retard d'effet?


Eh bien, je suppose que je veux tester si tout le flux observable est le même que je m'attends à ce qu'il soit. Dans votre exemple, il n'est jamais testé si ce flux ressemble à ce que j'attends (voir variable `` attendu '')


bien sûr, ce que je voulais dire dans cet exemple, c'est que vous allez fournir un objet simulé avec votre réponse :)



1
votes

La deuxième notation ne fonctionne pas avec jasmine-marbles , utilisez des tirets à la place:

 const expected = cold('------b ', { b: completion });


1 commentaires

le problème avec les marbeaux tel quel est que le résultat sera vide car l'effet est retardé par l'opérateur de retard. Vous devrez changer le planificateur et basculer sur delayWhen. Pour moi, cela ressemble au retard même si son retard (0), il tique toujours et cela fait un retard et une désynchronisation entre votre résultat attendu du test unitaire et votre effet, mais avec du retard Quand, cela ne se produit pas.



1
votes

Vous devrez faire 3 choses

1- Dans votre beforeEach , vous devez remplacer le planificateur interne de RxJs comme suit:

const expected = cold('------b ', { b: outcome });

2- Remplacez delay, par delay Quand comme suit: delayWhen (_x => (true? interval (50): of (undefined)))

3- Utiliser des frames, je ne sais pas vraiment comment utiliser les secondes pour cela, j'ai donc utilisé des cadres. Chaque image dure 10 ms. Donc, par exemple, mon retard ci-dessus est de 50 ms et ma trame est -b, donc c'est les 10 ms attendus + il me fallait encore 50 ms donc cela équivaut à 5 images supplémentaires qui étaient ------ b comme suit:

    import { async } from 'rxjs/internal/scheduler/async';
    import { cold, hot, getTestScheduler } from 'jasmine-marbles';
    beforeEach(() => {.....
        const testScheduler = getTestScheduler();
        async.schedule = (work, delay, state) => testScheduler.schedule(work, delay, state);
})


0 commentaires