sinonjs - advance clock to 59 minutes and wait for 1 minute actually

跟風遠走 提交于 2019-12-11 08:41:26

问题


I've a web component for auto-logout functionality which shows modal window with a message on 59th minute and stay for another minute in case of no activity. And logs out the user if user doesn't click anywhere on the window. So, no activity for an hour will logout the user automatically. This works fine.

Now, to test this functionality, I tried to use sinonjs. I used FakeTimers but couldn't able to achieve the result. I am trying to test that modal window with message shows up.

Here's the code:

const { When } = require('cucumber'); // eslint-disable-line import/no-extraneous-dependencies
const fs = require('fs');
const path = require('path');

let clock;    

async function setupSinon() {
  const sinonPath = require.resolve('sinon');

  const content = await new Promise((resolve, reject) => {
    fs.readFile(
      path.join(sinonPath, '../../pkg/sinon.js'),
      'utf-8',
      async (error, cont) => {
        if (error) return reject(error);
        resolve(cont);
      },
    );
  });
  // creating <script> element for sinonjs to execute on the page
  await browser.execute((content) => {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.text = content;
    document.head.appendChild(script);
  }, content);
}

async function iWaitForNMinutes() {
  await setupSinon();
  await browser.execute(() => {
    before(() => {
      clock = sinon.useFakeTimers();
    });
    clock = sinon.useFakeTimers({
      now: Date.now(),
      shouldAdvanceTime: true,
      toFake: ['setTimeout'],
    });

    clock.tick('59:00'); // advancing the clock to 59 minutes so that auto-logout modal window popup, but this doesn't work

    after(() => {
      clock.restore();
    });

    setTimeout(() => {}, 60000);

  });
} 

When(/^I wait for minutes$/, iWaitForNMinutes);

module.exports = {      
  iWaitForNMinutes,
};

sinon 5.0.10

How to user sinonjs FakeTimer to advance the time to n minutes and then wait actually for n minutes ?


回答1:


Sinon's fake timers are pretty easy to work with and are my favourite feature of sinon.

The usage goes like this

In your code

// in your code
eatCake() {
  setTimeout(function() {
    // eat cake after 10s
  }, 10000); // 10000 === 10s
}

In your test

clock = sinon.useFakeTimers();
clock.tick(9000);
// check if cake is eaten - answer will be false
clock.tick(1000); // 9000 + 1000 === 10s
// check if cake is eaten - answer will be true

So sinon basically fast forwards (programatically) the timer so our test can check for the desired result without actually waiting the time because all test frameworks usually have a wait timeout of 2s after which a test case will fail.

In your case, to wait for 59 minutes, you could write

clock.tick(1000 * 60 * 59); // 59 minutes

// check if the modal has opened up

clock.tick(1000 * 60 * 1); // 1 minute

// check if the user is logged out

And don't forget to restore the clock at the end as you've already done.

clock.restore();



回答2:


Your general problem is probably in the await before your function (browser.execute):

  • advancing the clock before await is pointless (regarding anything like setTimeOut inside)... since any of those inner timing functions is not yet set up.
  • advancing the clock after the await <function> is pointless because indeed, the await will wait...

The solution is to not use await with your (async) function but treat it like any other promise-returning function (which any async function actually is).

it('some test', async () => {

    await new Promise((resolve, reject) => {

        // normally used with await
        functionToBeTested(...some params).then(
            (value) => {
                log('now it happend')
                resolve()
            },
            (reason) => {
                reject(reason)
            }
        )

        // by not using await (despite deleteAction being an sync function)
        // but rather just chaining a then, this clock.tick gets run while
        // deleteAction is "running" resp. waiting for some timeout:
        clock.tick(1000)
    })

    ... some more asserts on the result...
    (we can be rest-assured the command under test is completed here)
})


来源:https://stackoverflow.com/questions/50646921/sinonjs-advance-clock-to-59-minutes-and-wait-for-1-minute-actually

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!