sinonjs - 将时钟提前到 59 分钟并实际等待 1 分钟
sinonjs - advance clock to 59 minutes and wait for 1 minute actually
我有一个用于自动注销功能的网络组件,它在第 59 分钟显示模态 window 和一条消息,如果没有 activity,则再停留一分钟。如果用户没有点击 window 上的任何地方,则注销用户。因此,一个小时内没有 activity 将自动注销用户。这很好用。
现在,为了测试此功能,我尝试使用 sinonjs
。我使用 FakeTimers
但无法达到结果。我正在尝试测试显示消息的模态 window。
代码如下:
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
如何使用sinonjs
FakeTimer将时间提前到n分钟然后实际等待n分钟?
Sinon 的假计时器非常易于使用,是我最喜欢的 sinon 功能。
用法是这样的
在你的代码中
// in your code
eatCake() {
setTimeout(function() {
// eat cake after 10s
}, 10000); // 10000 === 10s
}
在你的测试中
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
所以 sinon 基本上(以编程方式)快进计时器,这样我们的测试就可以检查所需的结果而无需实际等待时间,因为所有测试框架通常都有 2 秒的等待超时,超过 2 秒测试用例就会失败。
在你的情况下,要等待 59 分钟,你可以这样写
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
并且不要忘记像您已经完成的那样在最后恢复时钟。
clock.restore();
您的一般问题可能在您的函数 (browser.execute
) 之前的 await
:
- 在before await 之前推进时钟是没有意义的(关于内部的 setTimeOut 之类的东西)...因为任何这些内部计时功能都尚未设置。
- 在
await <function>
之后推进时钟 是没有意义的,因为 await
确实会等待...
解决方案是不要将 await 与您的(异步)函数一起使用,但要像对待任何其他返回承诺的函数(实际上是任何异步函数)一样对待它。
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)
})
我有一个用于自动注销功能的网络组件,它在第 59 分钟显示模态 window 和一条消息,如果没有 activity,则再停留一分钟。如果用户没有点击 window 上的任何地方,则注销用户。因此,一个小时内没有 activity 将自动注销用户。这很好用。
现在,为了测试此功能,我尝试使用 sinonjs
。我使用 FakeTimers
但无法达到结果。我正在尝试测试显示消息的模态 window。
代码如下:
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
如何使用sinonjs
FakeTimer将时间提前到n分钟然后实际等待n分钟?
Sinon 的假计时器非常易于使用,是我最喜欢的 sinon 功能。
用法是这样的
在你的代码中
// in your code
eatCake() {
setTimeout(function() {
// eat cake after 10s
}, 10000); // 10000 === 10s
}
在你的测试中
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
所以 sinon 基本上(以编程方式)快进计时器,这样我们的测试就可以检查所需的结果而无需实际等待时间,因为所有测试框架通常都有 2 秒的等待超时,超过 2 秒测试用例就会失败。
在你的情况下,要等待 59 分钟,你可以这样写
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
并且不要忘记像您已经完成的那样在最后恢复时钟。
clock.restore();
您的一般问题可能在您的函数 (browser.execute
) 之前的 await
:
- 在before await 之前推进时钟是没有意义的(关于内部的 setTimeOut 之类的东西)...因为任何这些内部计时功能都尚未设置。
- 在
await <function>
之后推进时钟 是没有意义的,因为await
确实会等待...
解决方案是不要将 await 与您的(异步)函数一起使用,但要像对待任何其他返回承诺的函数(实际上是任何异步函数)一样对待它。
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)
})