-
Notifications
You must be signed in to change notification settings - Fork 408
fakeAsync tests not working with lodash debounce #1050
Comments
thanks , I will implement the feature here. |
Why it's closed? The problem still exists. |
/** THE COMPONENT **/
@Component({
template: `
<button (click)="debounced()">Change</button>
<p>{{name}}</p>
`
})
export class ClickComponent implements OnInit {
name = 'init';
debounced = debounce(this.onClick.bind(this), 300);
onClick() {
this.name = 'changed';
}
}
/** THE TEST **/
it('should changed on click', fakeAsync(() => {
const button = fixture.nativeElement.querySelector('button');
button.click();
tick(310);
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('p').textContent).toEqual('changed');
}));
/** THE REAL LODASH IMPLEMENTATION **/
function debounce(func, wait, options: any = false) {
let lastArgs,
lastThis,
maxWait,
result,
timerId,
lastCallTime
let lastInvokeTime = 0
let leading = false
let maxing = false
let trailing = true
// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
const useRAF = (!wait && wait !== 0 && typeof requestAnimationFrame === 'function')
if (typeof func != 'function') {
throw new TypeError('Expected a function')
}
wait = +wait || 0
if (options) {
leading = !!options.leading
maxing = 'maxWait' in options
maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait
trailing = 'trailing' in options ? !!options.trailing : trailing
}
function invokeFunc(time) {
const args = lastArgs
const thisArg = lastThis
lastArgs = lastThis = undefined
lastInvokeTime = time
result = func.apply(thisArg, args)
return result
}
function startTimer(pendingFunc, wait) {
if (useRAF) {
return requestAnimationFrame(pendingFunc)
}
return setTimeout(pendingFunc, wait)
}
function cancelTimer(id) {
if (useRAF) {
return cancelAnimationFrame(id)
}
clearTimeout(id)
}
function leadingEdge(time) {
// Reset any `maxWait` timer.
lastInvokeTime = time
// Start the timer for the trailing edge.
timerId = startTimer(timerExpired, wait)
// Invoke the leading edge.
return leading ? invokeFunc(time) : result
}
function remainingWait(time) {
const timeSinceLastCall = time - lastCallTime
const timeSinceLastInvoke = time - lastInvokeTime
const timeWaiting = wait - timeSinceLastCall
return maxing
? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
: timeWaiting
}
function shouldInvoke(time) {
const timeSinceLastCall = time - lastCallTime
const timeSinceLastInvoke = time - lastInvokeTime
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait))
}
function timerExpired() {
const time = Date.now()
if (shouldInvoke(time)) {
return trailingEdge(time)
}
// Restart the timer.
timerId = startTimer(timerExpired, remainingWait(time))
}
function trailingEdge(time) {
timerId = undefined
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs) {
return invokeFunc(time)
}
lastArgs = lastThis = undefined
return result
}
function cancel() {
if (timerId !== undefined) {
cancelTimer(timerId)
}
lastInvokeTime = 0
lastArgs = lastCallTime = lastThis = timerId = undefined
}
function flush() {
return timerId === undefined ? result : trailingEdge(Date.now())
}
function pending() {
return timerId !== undefined
}
function debounced(...args) {
const time = Date.now()
const isInvoking = shouldInvoke(time)
lastArgs = args
lastThis = this
lastCallTime = time
if (isInvoking) {
if (timerId === undefined) {
return leadingEdge(lastCallTime)
}
if (maxing) {
// Handle invocations in a tight loop.
timerId = startTimer(timerExpired, wait)
return invokeFunc(lastCallTime)
}
}
if (timerId === undefined) {
timerId = startTimer(timerExpired, wait)
}
return result
}
debounced.cancel = cancel
debounced.flush = flush
debounced.pending = pending
return debounced
} |
@ArielGueta, you need to import this file.
I have tested with your test code, it passed. |
Thanks for your response. I added this to the test.ts file (angular-cli):
And it's still not working. (zone.js version 0.8.26) |
@ArielGueta , I see, the you can use the following code for now. Please see the
|
Yes, it's working, Thanks! Can we reopen it until it will be available in Angular? |
@ArielGueta , it has been merged in |
We are on version 5. I think it should also be merged to version 5. Most of us are still in 5. |
@ArielGueta , I see, you can file an issue in |
I will. Thanks! |
@mhevery , do you think we should also merge angular/angular#23108 and angular/angular#23227 into
Please review, thank you. |
I had originally posted this issue to Angular angular/angular#22826
@JiaLiPassion requested me to re-submit the issue here.
I'm submitting a...
Current behavior
Using fakeAsync() and tick() to test functions that are debounced with lodash.debounce() do not work as expected.
Expected behavior
fakeAsync() and tick() should be able to be used to synchronously test debounced functions.
Minimal reproduction of the problem with instructions
I have a repository with a minimal reproduction: https://github.com/johnmcase/angular-test-debounce
Just clone, install, ng test
What is the motivation / use case for changing the behavior?
Environment
The text was updated successfully, but these errors were encountered: