1

In an angular application, I use some tools library and some of my code that have:

  1. Async declaration
  2. Use a setInterval inside that I don't want to wait.

I've found this article that shows how to use fakeAsync, flushMicrotask and tick, that seem to do the job, but it doesn't seems to work.

Currently I've this:

  it('should refresh the token in time', fakeAsync(() => {
    //Arrange
    let token = null;
    generateToken().then(result => {
      token = result;
      console.log('Generated token: ' + token); //properly displayed
    });
    flushMicrotasks();
    expect(token).not.toBeNull(); //crashes
    //Rest of the test


  }));
});

but it seems the expect is executed before the generateToken method.

(generateToken returns a Promise and basically generate a test token with jose library)

I could use the async declaration in the "it" method, but my understanding is that won't solve my real issue, to accelerate a setInterval

Has the recommended way of testing async code changed? Or what am I missing?

J4N
  • 19,480
  • 39
  • 187
  • 340
  • I'm resonably sure fakeAsync will accept an `async () => `. Then you just await it as normal. The other option is to use the complete callback of your `it` – Liam Apr 12 '22 at 12:51
  • Does this answer your question? [Angular testing: using fakeAsync with async/await](https://stackoverflow.com/questions/61739584/angular-testing-using-fakeasync-with-async-await) – Liam Apr 12 '22 at 12:52

2 Answers2

0

Have you tried tick and flush?

    let token = null;
    generateToken().then(result => {
      token = result;
      console.log('Generated token: ' + token); //properly displayed
    });
    tick(2 * 60 * 1000); // move time 2 minutes in a fake way
   
    flush();
    // can also use discardPeriodicTasks(); instead of flush
    expect(token).not.toBeNull();

The tick should move the time 2 minutes in a fake way and the flush should get rid of the setInterval. You can't use flushMicroTrasks() because that will flush microtasks (promises) and not Web APIs like setInterval or setTimeout. Web APIs are macrotasks.

AliF50
  • 16,947
  • 1
  • 21
  • 37
-1

Just await for the result

it('should refresh the token in time', async () =>{
   const token = await generateToken();
   expect(token).not.toBeNull();
});

this way you can serialize code execution.

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • As I say in the question, this works, but won't allow me to accelerate the time to not wait 2 minutes in my test due to a `setInterval ` – J4N Apr 12 '22 at 10:53
  • Well you didnt include relevant code, so how should I know? Use fakeAsync + tick(). If it does not work for you, then its because you are doing it wrong as tick() is the way to go here. Again, cannot tell as I see no relevant code (no test subject)( – Antoniossss Apr 12 '22 at 10:54
  • How should you know? Because there is not only code in the question :/. This code is in a service which is called in another service, which is called by this test, it would just pollute the question – J4N Apr 12 '22 at 11:59
  • How should I know that you need to wait X time and not only single tick? I rarely read all OP statements (and rather never trust them anyway) as those are full of assumptions, statements that this works (no proof) but that does not work(no proof) just like in your case. Showing the actual code including that troublesome interval would be not polluting but clearifying. But hey, since you know better, why is it not working for you yet? – Antoniossss Apr 12 '22 at 12:12
  • I would gladly reproduce your case to solve it, but how can I do it if the test subject which has to be obviosuly tested in some particular way, is just blackboxed. You are not even showing the context that you have used `setTimeout` somewhere. Your example is incomplete, but yet you think I should be able to "figure it out" from the description. – Antoniossss Apr 12 '22 at 12:17