mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Fix captured/bubbled in ReactNativeTreeTraversal (#8019)
Follow-up to #7741. Added a test for RN event bubbling that fails before the fix.
(cherry picked from commit a8beab3341)
This commit is contained in:
committed by
Paul O’Shannessy
parent
ac0c3e60fb
commit
fbe19e90b9
@@ -82,10 +82,10 @@ function traverseTwoPhase(inst, fn, arg) {
|
||||
}
|
||||
var i;
|
||||
for (i = path.length; i-- > 0;) {
|
||||
fn(path[i], false, arg);
|
||||
fn(path[i], 'captured', arg);
|
||||
}
|
||||
for (i = 0; i < path.length; i++) {
|
||||
fn(path[i], true, arg);
|
||||
fn(path[i], 'bubbled', arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,52 @@ var RCTUIManager = {
|
||||
updateView: jest.fn(),
|
||||
removeSubviewsFromContainerWithID: jest.fn(),
|
||||
replaceExistingNonRootView: jest.fn(),
|
||||
customBubblingEventTypes: {
|
||||
topBlur: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onBlur',
|
||||
captured: 'onBlurCapture',
|
||||
},
|
||||
},
|
||||
topFocus: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onFocus',
|
||||
captured: 'onFocusCapture',
|
||||
},
|
||||
},
|
||||
topTouchCancel: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onTouchCancel',
|
||||
captured: 'onTouchCancelCapture',
|
||||
},
|
||||
},
|
||||
topTouchEnd: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onTouchEnd',
|
||||
captured: 'onTouchEndCapture',
|
||||
},
|
||||
},
|
||||
topTouchMove: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onTouchMove',
|
||||
captured: 'onTouchMoveCapture',
|
||||
},
|
||||
},
|
||||
topTouchStart: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onTouchStart',
|
||||
captured: 'onTouchStartCapture',
|
||||
},
|
||||
},
|
||||
},
|
||||
customDirectEventTypes: {
|
||||
topAccessibilityTap: {
|
||||
registrationName: 'onAccessibilityTap',
|
||||
},
|
||||
topTextLayout: {
|
||||
registrationName: 'onTextLayout',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = RCTUIManager;
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright 2013-2015, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var RCTEventEmitter;
|
||||
var React;
|
||||
var ReactErrorUtils;
|
||||
var ReactNative;
|
||||
var UIManager;
|
||||
var createReactNativeComponentClass;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModuleRegistry();
|
||||
|
||||
RCTEventEmitter = require('RCTEventEmitter');
|
||||
React = require('React');
|
||||
ReactErrorUtils = require('ReactErrorUtils');
|
||||
ReactNative = require('ReactNative');
|
||||
UIManager = require('UIManager');
|
||||
createReactNativeComponentClass = require('createReactNativeComponentClass');
|
||||
|
||||
// Ensure errors from event callbacks are properly surfaced (otherwise,
|
||||
// jest/jsdom swallows them when we do the .dispatchEvent call)
|
||||
ReactErrorUtils.invokeGuardedCallback =
|
||||
ReactErrorUtils.invokeGuardedCallbackWithCatch;
|
||||
});
|
||||
|
||||
it('handles events', () => {
|
||||
expect(RCTEventEmitter.register.mock.calls.length).toBe(1);
|
||||
var EventEmitter = RCTEventEmitter.register.mock.calls[0][0];
|
||||
var View = createReactNativeComponentClass({
|
||||
validAttributes: { foo: true },
|
||||
uiViewClassName: 'View',
|
||||
});
|
||||
|
||||
|
||||
var log = [];
|
||||
ReactNative.render(
|
||||
<View
|
||||
foo="outer"
|
||||
onTouchEnd={() => log.push('outer touchend')}
|
||||
onTouchEndCapture={() => log.push('outer touchend capture')}
|
||||
onTouchStart={() => log.push('outer touchstart')}
|
||||
onTouchStartCapture={() => log.push('outer touchstart capture')}>
|
||||
<View
|
||||
foo="inner"
|
||||
onTouchEndCapture={() => log.push('inner touchend capture')}
|
||||
onTouchEnd={() => log.push('inner touchend')}
|
||||
onTouchStartCapture={() => log.push('inner touchstart capture')}
|
||||
onTouchStart={() => log.push('inner touchstart')}
|
||||
/>
|
||||
</View>,
|
||||
1
|
||||
);
|
||||
|
||||
expect(UIManager.createView.mock.calls.length).toBe(2);
|
||||
var innerTag = UIManager.createView.mock.calls[1][0];
|
||||
|
||||
EventEmitter.receiveTouches(
|
||||
'topTouchStart',
|
||||
[{target: innerTag, identifier: 17}],
|
||||
[0]
|
||||
);
|
||||
EventEmitter.receiveTouches(
|
||||
'topTouchEnd',
|
||||
[{target: innerTag, identifier: 17}],
|
||||
[0]
|
||||
);
|
||||
|
||||
expect(log).toEqual([
|
||||
'outer touchstart capture',
|
||||
'inner touchstart capture',
|
||||
'inner touchstart',
|
||||
'outer touchstart',
|
||||
'outer touchend capture',
|
||||
'inner touchend capture',
|
||||
'inner touchend',
|
||||
'outer touchend',
|
||||
]);
|
||||
});
|
||||
Reference in New Issue
Block a user