Skip to content

Commit

Permalink
Map lowercase native events to React camelcase
Browse files Browse the repository at this point in the history
React camelcases a bunch of events that JS has in all lower case. This
PR adds a map of them so people can call `simulate` with either the
React version or the native event version.

Fixes #29.
  • Loading branch information
jackfranklin committed Jan 14, 2016
1 parent 0910d00 commit 2f303b2
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 2 deletions.
4 changes: 3 additions & 1 deletion src/ReactWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
Simulate,
findDOMNode,
} from './react-compat';
import { mapNativeEventNames } from './Utils';

/**
* Finds all nodes in the current wrapper nodes' render trees that match the provided predicate
Expand Down Expand Up @@ -306,7 +307,8 @@ export default class ReactWrapper {
*/
simulate(event, ...args) {
this.single(n => {
const eventFn = Simulate[event];
const mappedEvent = mapNativeEventNames(event);
const eventFn = Simulate[mappedEvent];
if (!eventFn) {
throw new TypeError(`ReactWrapper::simulate() event '${event}' does not exist`);
}
Expand Down
51 changes: 50 additions & 1 deletion src/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import {
isDOMComponent,
findDOMNode,
} from './react-compat';
import { REACT013 } from './version';
import {
REACT013,
REACT014,
} from './version';

export function propsOfNode(node) {
if (REACT013) {
Expand Down Expand Up @@ -168,3 +171,49 @@ export function coercePropValue(propValue) {
// coerce to boolean
return propValue === 'true' ? true : false;
}

export function mapNativeEventNames(event) {
const nativeToReactEventMap = {
compositionend: 'compositionEnd',
compositionstart: 'compositionStart',
compositionupdate: 'compositionUpdate',
keydown: 'keyDown',
keyup: 'keyUp',
keypress: 'keyPress',
contextmenu: 'contextMenu',
doubleclick: 'doubleClick',
dragend: 'dragEnd',
dragenter: 'dragEnter',
dragexist: 'dragExit',
dragleave: 'dragLeave',
dragover: 'dragOver',
dragstart: 'dragStart',
mousedown: 'mouseDown',
mousemove: 'mouseMove',
mouseout: 'mouseOut',
mouseover: 'mouseOver',
mouseup: 'mouseUp',
touchcancel: 'touchCancel',
touchend: 'touchEnd',
touchmove: 'touchMove',
touchstart: 'touchStart',
canplay: 'canPlay',
canplaythrough: 'canPlayThrough',
durationchange: 'durationChange',
loadeddata: 'loadedData',
loadedmetadata: 'loadedMetadata',
loadstart: 'loadStart',
ratechange: 'rateChange',
timeupdate: 'timeUpdate',
volumechange: 'volumeChange',
};

if (REACT014) {
// these could not be simulated in React 0.13:
// https://github.com/facebook/react/issues/1297
nativeToReactEventMap.mouseenter = 'mouseEnter';
nativeToReactEventMap.mouseleave = 'mouseLeave';
}

return nativeToReactEventMap[event] || event;
}
36 changes: 36 additions & 0 deletions src/__tests__/ReactWrapper-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,42 @@ describeWithDOM('mount', () => {
expect(wrapper.simulate.bind(wrapper, 'invalidEvent'))
.to.throw(TypeError, "ReactWrapper::simulate() event 'invalidEvent' does not exist");
});

describe('Normalizing JS event names', () => {
it('should convert lowercase events to React camelcase', () => {
const spy = sinon.spy();
class Foo extends React.Component {
render() {
return (
<a onDoubleClick={spy}>foo</a>
);
}
}

const wrapper = mount(<Foo />);

wrapper.simulate('doubleclick');
expect(spy.calledOnce).to.equal(true);
});

describeIf(!REACT013, 'normalizing mouseenter', () => {
it('should convert lowercase events to React camelcase', () => {
const spy = sinon.spy();
class Foo extends React.Component {
render() {
return (
<a onMouseEnter={spy}>foo</a>
);
}
}

const wrapper = mount(<Foo />);

wrapper.simulate('mouseenter');
expect(spy.calledOnce).to.equal(true);
});
});
});
});

describe('.setState(newState)', () => {
Expand Down
24 changes: 24 additions & 0 deletions src/__tests__/Utils-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
propFromEvent,
SELECTOR,
selectorType,
mapNativeEventNames,
} from '../Utils';
import {
describeWithDOM,
Expand Down Expand Up @@ -240,7 +241,30 @@ describe('Utils', () => {
expect(coercePropValue('true')).to.equal(true);
expect(coercePropValue('false')).to.equal(false);
});
});

describe('mapNativeEventNames', () => {
describe('given an event that isn\'t a mapped', () => {
it('returns the original event', () => {
const result = mapNativeEventNames('click');
expect(result).to.equal('click');
});

});

describe('given a React capitalised mouse event', () => {
it('returns the original event', () => {
const result = mapNativeEventNames('mouseEnter');
expect(result).to.equal('mouseEnter');
});
});

describe('given a native lowercase event', () => {
it('transforms it into the React capitalised event', () => {
const result = mapNativeEventNames('dragenter');
expect(result).to.equal('dragEnter');
});
});
});

});

0 comments on commit 2f303b2

Please sign in to comment.