-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Tests]: System time tampering effects on _.throttle
and _.debounce
methods
#2913
[Tests]: System time tampering effects on _.throttle
and _.debounce
methods
#2913
Conversation
Monkey patch `Date.prototype` getTime and valueOf methods and `Date.now` method in _.debounce and _.throttle test cases. Provide additional test case asserting the outputs before and after monkey patching. Remove the reference to _.now method in test cases as the underlying implementation of library methods don't reference the methods from the `_` object but rather call dependent methods directly. ✅ Closes: jashkenas#2883
_.throttle
and _.debounce
methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great patch! Not only did you update those time-tampering tests to make them meaningful again, you also added new tests proving that _.throttle
and _.debounce
provide a stronger guarantee, i.e., they even continue working in the face of... let's call it "time vandalism". And you were very thorough in the PR description, I like that. Thank you so much, @ognjenjevremovic!
I have a few very minor change requests about the assertion comments, otherwise everything looks excellent.
Out of curiosity: why is there a ring emoji in the commit title? Is it some kind of cultural reference?
To answer your notes:
The underlying changes could've been done (...) in
before
(orbeforeEach
) andafter
(orafterEach
) hooks in the Functions QUnit module. However, that would require a minor changes in two other test cases from the same module (...).I can provide the change if necessary using
before
andafter
hooks instead.
I'm fine with the current solution, but if you want to refactor things a little bit, I'm fine with that, too. You can nest QUnit modules so that the hooks only affect the tests that should be affected, see docs here: https://api.qunitjs.com/QUnit/module/.
I just wanted to assure that the implementation of
_.throttle
and_.debounce
methods will not break, if the system time would be tempered (monkey patched).
I guess the test cases can be safely omitted as they're redundant @jgonggrijp?
If so, I can provide another commit to the same PR removing the obsolete test cases.
Which test cases are obsolete?
test/functions.js
Outdated
_.now = function() { | ||
return new Date(2013, 0, 1, 1, 1, 1); | ||
}; | ||
assert.strictEqual(counter, 1, '_.throttle: incr was called immediately'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good to add a comment to the assertion. Much clearer if it fails. 👍
}, 200); | ||
}); | ||
|
||
QUnit.test('throttle continues to function after system time is not accessible (or in invalid format)', function(assert) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow!
test/functions.js
Outdated
|
||
_.delay(function() { | ||
throttledIncr(); | ||
assert.strictEqual(counter, 2, '_.throttle: incr was debounced successfully, with tampered system time'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throttling and debouncing are subtly different things, so to prevent confusion, I'd rather avoid the word "debounce" here. There is no convention to prefix all assertion comments with a qualified function name (at least not as far as I'm aware) and I don't think such a convention is necessary, either, so I suggest just changing it to this:
assert.strictEqual(counter, 2, '_.throttle: incr was debounced successfully, with tampered system time'); | |
assert.strictEqual(counter, 2, 'incr was throttled successfully, with tampered system time'); |
test/functions.js
Outdated
|
||
_.delay(function() { | ||
throttledIncr(); | ||
assert.strictEqual(counter, 3, '_.throttle: incr was debounced successfully, after system time method restoration'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
likewise
assert.strictEqual(counter, 3, '_.throttle: incr was debounced successfully, after system time method restoration'); | |
assert.strictEqual(counter, 3, 'incr was throttled successfully, after system time method restoration'); |
test/functions.js
Outdated
|
||
_.delay(function() { | ||
debouncedIncr(); | ||
assert.strictEqual(counter, 2, 'incr was debounced successfully'); | ||
assert.strictEqual(counter, 2, '_.debounce: incr was debounced successfully, with tampered system time'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for brevity
assert.strictEqual(counter, 2, '_.debounce: incr was debounced successfully, with tampered system time'); | |
assert.strictEqual(counter, 2, 'incr was debounced successfully, with tampered system time'); |
test/functions.js
Outdated
|
||
_.delay(function() { | ||
debouncedIncr(); | ||
assert.strictEqual(counter, 2, '_.debounce: incr was debounced successfully, with tampered system time'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again for brevity
assert.strictEqual(counter, 2, '_.debounce: incr was debounced successfully, with tampered system time'); | |
assert.strictEqual(counter, 2, 'incr was debounced successfully, with tampered system time'); |
test/functions.js
Outdated
|
||
_.delay(function() { | ||
debouncedIncr(); | ||
assert.strictEqual(counter, 3, '_.debounce: incr was debounced successfully, after system time method restoration'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and one last time.
assert.strictEqual(counter, 3, '_.debounce: incr was debounced successfully, after system time method restoration'); | |
assert.strictEqual(counter, 3, 'incr was debounced successfully, after system time method restoration'); |
Hey @jgonggrijp, thank you so much for such an in depth review.
You're right; the messages should definitely be more concise.
I apologize for this 😄 . Thank you for noticing such a detail 🙂 .
Just wanted to check if adding these 2 new test cases provided value to the overall tests and didn't include redundancy.
If code duplication in tests is not too big of a trouble and doesn't introduce the confusion in the test cases by any means, I'm fine with the current implementation as well. |
Update the assertion comments in `_.throttle` and `_.debounce` unit tests, in order to prevent confusion and add more brevity to the test case messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, I wasn't sure how to structure the assertion comments. I wanted to somehow diversify the messages between
_.debounce
and_.throttle
but I'm not that good with the wording; I thought prefixing the assertion comments with the method name could help.
I'll be sure to address these with the suggested changes.
For clarity, I'm not entirely opposed to doing this. I just suggested removing the prefix in a few places because it was redundant in those particular cases.
I usually like to structure the commit messages in a descriptive manner, using the format: intention: + summary of the change (as a commit message head) followed by a long description. I use
git-cz
to make such formated commit messages.
I think the latestmajor
version of the tool included the emojis and automatically prepends them to every commit message (made using the tool).
I can change the commit message and remove the emoji if you'd like?
Ah, that explains! I think I have seen similar commit messages elsewhere, now I understand where they're coming from. No need to apologize and you can leave the emoji in there. I think it's amusing.
If code duplication in tests is not too big of a trouble and doesn't introduce the confusion in the test cases by any means, I'm fine with the current implementation as well.
UsingbeforeEach
andbeforeAll
would require certain changes and might be different from all other scenarios in the tests.
Yeah, if going that route, it's probably more consistent to restructure the tests a bit in general. That would more likely belong in a new issue or PR.
Congratulations with your first contribution! Please feel welcome to make more contributions. (A suggestion, if you feel up to it: I have a big PR waiting (#2908) which requires multiple reviews by different people. If you could take a look at the diff and leave some comments, or if you know other, seasoned Underscore users who might be willing to do a code review (or contribute a real-world benchmark), that would be great.) |
✅ Closes: #2883
Changes
Tests only:
Date.prototype.getTime
andDate.prototype.valueOf
methods andDate.now
method in_.debounce
and_.throttle
test cases,_.now
method in test cases as the underlying implementation of library methods don't reference the methods from the_
object but rather call dependent methods directly.Checklist
After the changes I ensured that:
npm run lint
,npm run test
,npm run bundle
.Done
Additional notes
The underlying changes could've been done by monkey patching the native
Date
andDate.prototype
methods inbefore
(orbeforeEach
) andafter
(orafterEach
) hooks in the Functions QUnit module. However, that would require a minor changes in two other test cases from the same module (as thevalueOf
method of theDate.prototype
would be changed for all test cases and always return the same value which would cause certain test cases to hang to the operationsnew Date - date < amount
as that will always result in thefalse
value in thewhile
loop).I can provide the change if necessary using
before
andafter
hooks instead.I just wanted to assure that the implementation of
_.throttle
and_.debounce
methods will not break, if the system time would be tempered (monkey patched).I guess the test cases can be safely omitted as they're redundant @jgonggrijp?
If so, I can provide another commit to the same PR removing the obsolete test cases.