Closed jasonfma closed 7 years ago
Our workaround right now is to copy the source from the raf
npm module and add a reset
call that clears it's queue and resets the counter. Then we call it before every test.
/* eslint-disable */
// taken from https://github.com/chrisdickinson/raf version 3.3.2
var now = require('performance-now')
, root = typeof window === 'undefined' ? global : window
, vendors = ['moz', 'webkit']
, suffix = 'AnimationFrame'
, raf = root['request' + suffix]
, caf = root['cancel' + suffix] || root['cancelRequest' + suffix]
for(var i = 0; !raf && i < vendors.length; i++) {
raf = root[vendors[i] + 'Request' + suffix]
caf = root[vendors[i] + 'Cancel' + suffix]
|| root[vendors[i] + 'CancelRequest' + suffix]
}
// Some versions of FF have rAF but not cAF
if(!raf || !caf) {
var last = 0
, id = 0
, queue = []
, frameDuration = 1000 / 60
raf = function(callback) {
if(queue.length === 0) {
var _now = now()
, next = Math.max(0, frameDuration - (_now - last))
last = next + _now
setTimeout(function() {
var cp = queue.slice(0)
// Clear queue here to prevent
// callbacks from appending listeners
// to the current frame's queue
queue.length = 0
for(var i = 0; i < cp.length; i++) {
if(!cp[i].cancelled) {
try{
cp[i].callback(last)
} catch(e) {
setTimeout(function() { throw e }, 0)
}
}
}
}, Math.round(next))
}
queue.push({
handle: ++id,
callback: callback,
cancelled: false
})
return id;
}
caf = function(handle) {
for(var i = 0; i < queue.length; i++) {
if(queue[i].handle === handle) {
queue[i].cancelled = true
}
}
}
resetQueue = function() { <----------------------------- custom reset function
queue = [];
id = 0;
last = 0;
}
}
module.exports = function(fn) {
// Wrap in a new function to prevent
// `cancel` potentially being assigned
// to the native rAF function
return raf.call(root, fn)
}
module.exports.cancel = function() {
caf.apply(root, arguments)
}
module.exports.reset = function() {
resetQueue.apply(root, arguments)
}
module.exports.polyfill = function() {
root.requestAnimationFrame = raf
root.cancelAnimationFrame = caf
}
/* eslint-enable */
Inside our init.js
for mocha tests:
...
// this mock raf needs to happen before react-native-mock is required
const raf = require('./testHelpers/mockRaf');
mockery.enable({
warnOnUnregistered: false,
});
mockery.registerMock('raf', raf);
require('react-native-mock/mock');
...
beforeEach(() => {
raf.reset();
});
...
This is a strange and unfortunate issue, but i'm not sure of the correct solution, or if it's anything to do with react-native-mock
. This looks like a great patch, but it's probably better submitted to raf
as a hidden API.
We came across this issue doing snapshot testing with
Animated
components andenzyme-to-json
. There is a property that gets generated called_animationFrame
that keeps incrementing throughout the entire test run.This makes our snapshots fragile because if we add a test or change the order of the tests, the snapshots now have a different
_animationFrame
property.I dug into the code and it looks like
react-native-mock
is getting that value fromrequestAnimationFrame
which is from a library calledraf
. I'm not sure what the right solution here is but I will post our workaround below.example test breakage: