Skip to content
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

Refactor SyntheticClipboardEvent tests to only use the public API #11365

Merged
139 changes: 114 additions & 25 deletions packages/react-dom/src/events/__tests__/SyntheticClipboardEvent-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,36 @@

'use strict';

var SyntheticClipboardEvent;
var React;
var ReactDOM;

describe('SyntheticClipboardEvent', () => {
var createEvent;
var simulateEvent;

beforeEach(() => {
// TODO: can we express this test with only public API?
SyntheticClipboardEvent = require('../SyntheticClipboardEvent').default;
createEvent = function(nativeEvent) {
var target = require('../getEventTarget').default(nativeEvent);
return SyntheticClipboardEvent.getPooled({}, '', nativeEvent, target);
React = require('react');
ReactDOM = require('react-dom');

document.body.innerHTML = '';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove container from body at the end of each test instead? Or, better, declare variable once, and remove/add it before and after each test.


simulateEvent = (element, type, data) => {
var event = document.createEvent('Event');
event.initEvent(type, true, true);

if (data) {
event.clipboardData = data;
}

element.dispatchEvent(event);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gaearon Does it make any huge difference on our tests using the Event constructor rather than the old-fashioned initEvent way when we want to create events?

Actually, how is Fiber dealing with these two approaches today?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if there's any difference. React just subscribes with addEventListener. If that works with both approaches in jsdom, let's use whichever is simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my first attempt, but I keep getting this error:
TypeError: Argument to dispatchEvent must be an Event

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SadPandaBear Not sure if it's possible to use the Event constructor in this case, since I have to mock the clipboardData. Any ideas?

Copy link
Contributor

@SadPandaBear SadPandaBear Nov 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking on doing something like:

var event = new ClipboardEvent(type, { bubbles: true });
if(data) event.clipboardData = data;
element.dispatchEvent(event);

But unfortunately ClipboardEvent is not supported. 😢

};
});

describe('ClipboardEvent interface', () => {
describe('clipboardData', () => {
describe('when event has clipboardData', () => {
it("returns event's clipboardData", () => {
var expectedCount = 3;

// Mock clipboardData since native implementation doesn't have a constructor
var clipboardData = {
dropEffect: null,
Expand All @@ -35,42 +47,119 @@ describe('SyntheticClipboardEvent', () => {
items: null,
types: null,
};
var clipboardEvent = createEvent({clipboardData: clipboardData});

expect(clipboardEvent.clipboardData).toBe(clipboardData);
var eventHandler = event => {
expect(event.clipboardData).toBe(clipboardData);
expectedCount -= 1;
};

var container = document.createElement('div');
var div = ReactDOM.render(
<div
onCopy={eventHandler}
onCut={eventHandler}
onPaste={eventHandler}
/>,
container,
);
document.body.appendChild(div);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we add the container to body instead? This detaches the div from the original container.


simulateEvent(div, 'copy', clipboardData);
simulateEvent(div, 'cut', clipboardData);
simulateEvent(div, 'paste', clipboardData);

expect(expectedCount).toBe(0);
});
});
});
});

describe('EventInterface', () => {
it('normalizes properties from the Event interface', () => {
var target = document.createElement('div');
var syntheticEvent = createEvent({srcElement: target});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this test specifically verifies that the synthetic event still determines the target even if only srcElement was set. Your test doesn't verify this.

var expectedCount = 3;
var div;

expect(syntheticEvent.target).toBe(target);
expect(syntheticEvent.type).toBe(undefined);
var eventHandler = type => event => {
expect(event.target).toBe(div);
expect(event.type).toBe(type);
expectedCount -= 1;
};

var container = document.createElement('div');
div = ReactDOM.render(
<div
onCopy={eventHandler('copy')}
onCut={eventHandler('cut')}
onPaste={eventHandler('paste')}
/>,
container,
);
document.body.appendChild(div);

simulateEvent(div, 'copy');
simulateEvent(div, 'cut');
simulateEvent(div, 'paste');

expect(expectedCount).toBe(0);
});

it('is able to `preventDefault` and `stopPropagation`', () => {
var nativeEvent = {};
var syntheticEvent = createEvent(nativeEvent);
var expectedCount = 3;

var eventHandler = event => {
expect(event.isDefaultPrevented()).toBe(false);
event.preventDefault();
expect(event.isDefaultPrevented()).toBe(true);
expect(event.isPropagationStopped()).toBe(false);
event.stopPropagation();
expect(event.isPropagationStopped()).toBe(true);
expectedCount -= 1;
};

expect(syntheticEvent.isDefaultPrevented()).toBe(false);
syntheticEvent.preventDefault();
expect(syntheticEvent.isDefaultPrevented()).toBe(true);
var container = document.createElement('div');
var div = ReactDOM.render(
<div
onCopy={eventHandler}
onCut={eventHandler}
onPaste={eventHandler}
/>,
container,
);
document.body.appendChild(div);

expect(syntheticEvent.isPropagationStopped()).toBe(false);
syntheticEvent.stopPropagation();
expect(syntheticEvent.isPropagationStopped()).toBe(true);
simulateEvent(div, 'copy');
simulateEvent(div, 'cut');
simulateEvent(div, 'paste');

expect(expectedCount).toBe(0);
});

it('is able to `persist`', () => {
var syntheticEvent = createEvent({});
var expectedCount = 3;

var eventHandler = event => {
expect(event.isPersistent()).toBe(false);
event.persist();
expect(event.isPersistent()).toBe(true);
expectedCount -= 1;
};

var container = document.createElement('div');
var div = ReactDOM.render(
<div
onCopy={eventHandler}
onCut={eventHandler}
onPaste={eventHandler}
/>,
container,
);
document.body.appendChild(div);

simulateEvent(div, 'copy');
simulateEvent(div, 'cut');
simulateEvent(div, 'paste');

expect(syntheticEvent.isPersistent()).toBe(false);
syntheticEvent.persist();
expect(syntheticEvent.isPersistent()).toBe(true);
expect(expectedCount).toBe(0);
});
});
});