Migrate conditional tests to gate pragma (#18585)
* Migrate conditional tests to gate pragma I searched through the codebase for this pattern: ```js describe('test suite', () => { if (!__EXPERIMENTAL__) { // or some other condition test("empty test so Jest doesn't complain", () => {}); return; } // Unless we're in experimental mode, none of the tests in this block // will run. }) ``` and converted them to the `@gate` pragma instead. The reason this pattern isn't preferred is because you end up disabling more tests than you need to. * Add flag for www release channels Using a heuristic where I check a flag that is known to only be enabled in www. I left a TODO to instead set the release channel explicitly in each test config.
This commit is contained in:
parent
6c43a62c0f
commit
bec7599067
|
@ -25,11 +25,7 @@ describe('ReactHooksInspection', () => {
|
|||
ReactDebugTools = require('react-debug-tools');
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('should inspect a simple useResponder hook', () => {
|
||||
const TestResponder = React.DEPRECATED_createResponder('TestResponder', {});
|
||||
|
||||
|
@ -51,6 +47,7 @@ describe('ReactHooksInspection', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should inspect a simple ReactDOM.useEvent hook', () => {
|
||||
let clickHandle;
|
||||
let ref;
|
||||
|
|
|
@ -27,6 +27,7 @@ describe('StoreStressConcurrent', () => {
|
|||
print = require('./storeSerializer').print;
|
||||
});
|
||||
|
||||
// TODO: Remove this in favor of @gate pragma
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
|
|
|
@ -87,11 +87,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
SuspenseList = React.SuspenseList;
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates a parent even if a child Suspense boundary is blocked', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -150,6 +146,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(ref.current).toBe(span);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('calls the hydration callbacks after hydration or deletion', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -240,6 +237,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(deleted.length).toBe(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('calls the onDeleted hydration callback if the parent gets deleted', async () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(() => {});
|
||||
|
@ -297,6 +295,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(deleted.length).toBe(1);
|
||||
});
|
||||
|
||||
// @gate experimental || www
|
||||
it('warns and replaces the boundary content in legacy mode', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -368,6 +367,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(container.textContent).toBe('Hello');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can insert siblings before the dehydrated boundary', () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(() => {});
|
||||
|
@ -426,6 +426,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(container.firstChild.firstChild.textContent).toBe('First');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can delete the dehydrated boundary before it is hydrated', () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(() => {});
|
||||
|
@ -482,6 +483,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(container.firstChild.children[1].textContent).toBe('After');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('blocks updates to hydrate the content first if props have changed', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -553,6 +555,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(span.className).toBe('hi');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('shows the fallback if props have changed before hydration completes and is still suspended', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -622,6 +625,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(container.textContent).toBe('Hi');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('shows the fallback of the outer if fallback is missing', async () => {
|
||||
// This is the same exact test as above but with a nested Suspense without a fallback.
|
||||
// This should be a noop.
|
||||
|
@ -695,6 +699,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(container.textContent).toBe('Hi');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('clears nested suspense boundaries if they did not hydrate yet', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -767,6 +772,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(container.textContent).toBe('Hi Hi');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates first if props changed but we are able to resolve within a timeout', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -847,6 +853,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(span.className).toBe('hi');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('blocks the update to hydrate first if context has changed', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -931,6 +938,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(span.className).toBe('hi');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('shows the fallback if context has changed before hydration completes and is still suspended', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -1014,6 +1022,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(container.textContent).toBe('Hi');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('replaces the fallback with client content if it is not rendered by the server', async () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(resolvePromise => {});
|
||||
|
@ -1062,6 +1071,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(ref.current).toBe(span);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('replaces the fallback within the suspended time if there is a nested suspense', async () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(resolvePromise => {});
|
||||
|
@ -1121,6 +1131,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(ref.current).toBe(span);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('replaces the fallback within the suspended time if there is a nested suspense in a nested suspense', async () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(resolvePromise => {});
|
||||
|
@ -1182,6 +1193,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(ref.current).toBe(span);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('waits for pending content to come in from the server and then hydrates it', async () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(resolvePromise => {});
|
||||
|
@ -1269,6 +1281,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(ref.current).toBe(span);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('handles an error on the client if the server ends up erroring', async () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(resolvePromise => {});
|
||||
|
@ -1363,6 +1376,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(ref.current).toBe(div);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('shows inserted items in a SuspenseList before content is hydrated', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -1448,6 +1462,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(ref.current).toBe(spanB);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('shows is able to hydrate boundaries even if others in a list are pending', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -1522,6 +1537,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(container.textContent).toBe('ALoading B');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('shows inserted items before pending in a SuspenseList as fallbacks', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -1613,6 +1629,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(container.textContent).toBe('ABC');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can client render nested boundaries', async () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(() => {});
|
||||
|
@ -1667,6 +1684,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(container.lastChild.data).toBe('unrelated comment');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can hydrate TWO suspense boundaries', async () => {
|
||||
const ref1 = React.createRef();
|
||||
const ref2 = React.createRef();
|
||||
|
@ -1706,6 +1724,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(ref2.current).toBe(span2);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('regenerates if it cannot hydrate before changes to props/context expire', async () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(resolvePromise => {});
|
||||
|
@ -1787,6 +1806,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
expect(newSpan.className).toBe('hi');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('does not invoke an event on a hydrated node until it commits', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -1868,6 +1888,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('does not invoke an event on a hydrated EventResponder until it commits', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -1949,6 +1970,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('invokes discrete events on nested suspense boundaries in a root (legacy system)', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -2028,6 +2050,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('invokes discrete events on nested suspense boundaries in a root (responder system)', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -2110,6 +2133,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('does not invoke the parent of dehydrated boundary event', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -2184,6 +2208,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('does not invoke an event on a parent tree when a subtree is dehydrated', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -2261,6 +2286,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
document.body.removeChild(parentContainer);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('blocks only on the last continuous event (legacy system)', async () => {
|
||||
let suspend1 = false;
|
||||
let resolve1;
|
||||
|
@ -2365,20 +2391,16 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
// @gate experimental
|
||||
it('blocks only on the last continuous event (Responder system)', async () => {
|
||||
useHover = require('react-interactions/events/hover').useHover;
|
||||
|
||||
let suspend1 = false;
|
||||
let resolve1;
|
||||
const promise1 = new Promise(
|
||||
resolvePromise => (resolve1 = resolvePromise),
|
||||
);
|
||||
const promise1 = new Promise(resolvePromise => (resolve1 = resolvePromise));
|
||||
let suspend2 = false;
|
||||
let resolve2;
|
||||
const promise2 = new Promise(
|
||||
resolvePromise => (resolve2 = resolvePromise),
|
||||
);
|
||||
const promise2 = new Promise(resolvePromise => (resolve2 = resolvePromise));
|
||||
|
||||
function First({text}) {
|
||||
if (suspend1) {
|
||||
|
@ -2486,8 +2508,8 @@ describe('ReactDOMServerPartialHydration', () => {
|
|||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('finishes normal pri work before continuing to hydrate a retry', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
|
|
@ -106,11 +106,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
Suspense = React.Suspense;
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates the target boundary synchronously during a click', async () => {
|
||||
function Child({text}) {
|
||||
Scheduler.unstable_yieldValue(text);
|
||||
|
@ -173,6 +169,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates at higher pri if sync did not work first time', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -257,6 +254,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates at higher pri for secondary discrete events', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -349,7 +347,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
// @gate experimental
|
||||
it('hydrates the target boundary synchronously during a click (flare)', async () => {
|
||||
const usePress = require('react-interactions/events/press').usePress;
|
||||
|
||||
|
@ -415,6 +413,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates at higher pri if sync did not work first time (flare)', async () => {
|
||||
const usePress = require('react-interactions/events/press').usePress;
|
||||
let suspend = false;
|
||||
|
@ -498,6 +497,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates at higher pri for secondary discrete events (flare)', async () => {
|
||||
const usePress = require('react-interactions/events/press').usePress;
|
||||
let suspend = false;
|
||||
|
@ -588,8 +588,8 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates the hovered targets as higher priority for continuous events', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -690,6 +690,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates the last target path first for continuous events', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -775,6 +776,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates the last explicitly hydrated target at higher priority', async () => {
|
||||
function Child({text}) {
|
||||
Scheduler.unstable_yieldValue(text);
|
||||
|
@ -823,6 +825,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
|
|||
expect(Scheduler).toFlushAndYield(['App', 'C', 'B', 'A']);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('hydrates before an update even if hydration moves away from it', async () => {
|
||||
function Child({text}) {
|
||||
Scheduler.unstable_yieldValue(text);
|
||||
|
|
|
@ -44,11 +44,6 @@ describe('ReactDOMServerSuspense', () => {
|
|||
resetModules();
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
function Text(props) {
|
||||
return <div>{props.text}</div>;
|
||||
}
|
||||
|
@ -57,6 +52,7 @@ describe('ReactDOMServerSuspense', () => {
|
|||
throw new Promise(() => {});
|
||||
}
|
||||
|
||||
// @gate experimental || www
|
||||
it('should render the children when no promise is thrown', async () => {
|
||||
const c = await serverRender(
|
||||
<div>
|
||||
|
@ -71,6 +67,7 @@ describe('ReactDOMServerSuspense', () => {
|
|||
expect(e.textContent).toBe('Children');
|
||||
});
|
||||
|
||||
// @gate experimental || www
|
||||
it('should render the fallback when a promise thrown', async () => {
|
||||
const c = await serverRender(
|
||||
<div>
|
||||
|
@ -85,6 +82,7 @@ describe('ReactDOMServerSuspense', () => {
|
|||
expect(e.textContent).toBe('Fallback');
|
||||
});
|
||||
|
||||
// @gate experimental || www
|
||||
it('should work with nested suspense components', async () => {
|
||||
const c = await serverRender(
|
||||
<div>
|
||||
|
@ -105,6 +103,7 @@ describe('ReactDOMServerSuspense', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('server renders a SuspenseList component and its children', async () => {
|
||||
const example = (
|
||||
<React.SuspenseList>
|
||||
|
@ -137,6 +136,8 @@ describe('ReactDOMServerSuspense', () => {
|
|||
expect(divB).toBe(divB2);
|
||||
});
|
||||
|
||||
// TODO: Remove this in favor of @gate pragma
|
||||
if (__EXPERIMENTAL__) {
|
||||
itThrowsWhenRendering(
|
||||
'a suspending component outside a Suspense node',
|
||||
async render => {
|
||||
|
@ -164,6 +165,7 @@ describe('ReactDOMServerSuspense', () => {
|
|||
},
|
||||
'Add a <Suspense fallback=...> component higher in the tree',
|
||||
);
|
||||
}
|
||||
|
||||
it('does not get confused by throwing null', () => {
|
||||
function Bad() {
|
||||
|
|
|
@ -18,14 +18,6 @@ const renderSubtreeIntoContainer = require('react-dom')
|
|||
|
||||
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
|
||||
// Once this flag is always true, we should delete this test file
|
||||
if (__EXPERIMENTAL__) {
|
||||
describe('renderSubtreeIntoContainer', () => {
|
||||
it('empty test', () => {
|
||||
// Empty test to prevent "Your test suite must contain at least one test." error.
|
||||
});
|
||||
});
|
||||
} else {
|
||||
describe('renderSubtreeIntoContainer', () => {
|
||||
it('should pass context when rendering subtree elsewhere', () => {
|
||||
const portal = document.createElement('div');
|
||||
|
@ -338,4 +330,3 @@ if (__EXPERIMENTAL__) {
|
|||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1097,11 +1097,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
ReactTestUtils = require('react-dom/test-utils');
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('should create the same event listener map', () => {
|
||||
const listenerMaps = [];
|
||||
|
||||
|
@ -1119,6 +1115,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(listenerMaps[0]).toEqual(listenerMaps[1]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can render correctly with the ReactDOMServer', () => {
|
||||
const clickEvent = jest.fn();
|
||||
|
||||
|
@ -1136,6 +1133,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(output).toBe(`<div data-reactroot="">Hello world</div>`);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can render correctly with the ReactDOMServer hydration', () => {
|
||||
const clickEvent = jest.fn();
|
||||
const spanRef = React.createRef();
|
||||
|
@ -1164,6 +1162,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(clickEvent).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly work for a basic "click" listener', () => {
|
||||
let log = [];
|
||||
const clickEvent = jest.fn(event => {
|
||||
|
@ -1272,6 +1271,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(clickEvent2).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly work for setting and clearing a basic "click" listener', () => {
|
||||
const clickEvent = jest.fn();
|
||||
const divRef = React.createRef();
|
||||
|
@ -1315,6 +1315,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(clickEvent).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should handle the target being a text node', () => {
|
||||
const clickEvent = jest.fn();
|
||||
const buttonRef = React.createRef();
|
||||
|
@ -1337,6 +1338,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(clickEvent).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('handle propagation of click events', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const divRef = React.createRef();
|
||||
|
@ -1390,6 +1392,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(log[3]).toEqual(['bubble', buttonElement]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('handle propagation of click events mixed with onClick events', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const divRef = React.createRef();
|
||||
|
@ -1442,6 +1445,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(log[5]).toEqual(['bubble', buttonElement]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly work for a basic "click" listener on the outer target', () => {
|
||||
const log = [];
|
||||
const clickEvent = jest.fn(event => {
|
||||
|
@ -1507,6 +1511,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(clickEvent).toBeCalledTimes(2);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly handle many nested target listeners', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const targetListener1 = jest.fn();
|
||||
|
@ -1572,6 +1577,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(targetListener4).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly handle stopPropagation corrrectly for target events', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const divRef = React.createRef();
|
||||
|
@ -1605,6 +1611,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(clickEvent).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly handle stopPropagation corrrectly for many target events', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const targetListerner1 = jest.fn(e => e.stopPropagation());
|
||||
|
@ -1639,6 +1646,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(targetListerner4).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly handle stopPropagation for mixed capture/bubbling target listeners', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const targetListerner1 = jest.fn(e => e.stopPropagation());
|
||||
|
@ -1725,6 +1733,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(log).toEqual([{counter: 1}]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly work for a basic "click" listener that upgrades', () => {
|
||||
const clickEvent = jest.fn();
|
||||
const buttonRef = React.createRef();
|
||||
|
@ -1776,6 +1785,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(clickEvent).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly work for a basic "click" listener that upgrades #2', () => {
|
||||
const clickEvent = jest.fn();
|
||||
const buttonRef = React.createRef();
|
||||
|
@ -1827,6 +1837,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(clickEvent).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly work for a basic "click" window listener', () => {
|
||||
const log = [];
|
||||
const clickEvent = jest.fn(event => {
|
||||
|
@ -1878,6 +1889,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(clickEvent).toBeCalledTimes(2);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('handle propagation of click events on the window', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const divRef = React.createRef();
|
||||
|
@ -1937,6 +1949,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(log[5]).toEqual(['bubble', window]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly handle stopPropagation for mixed listeners', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const rootListerner1 = jest.fn(e => e.stopPropagation());
|
||||
|
@ -1975,6 +1988,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(rootListerner2).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly handle stopPropagation for delegated listeners', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const rootListerner1 = jest.fn(e => e.stopPropagation());
|
||||
|
@ -2014,6 +2028,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(rootListerner4).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('handle propagation of click events on the window and document', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const divRef = React.createRef();
|
||||
|
@ -2079,6 +2094,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(log[7]).toEqual(['bubble', window]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('handles propagation of custom user events', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const divRef = React.createRef();
|
||||
|
@ -2153,6 +2169,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(log[5]).toEqual(['bubble', buttonElement]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('beforeblur and afterblur are called after a focused element is unmounted', () => {
|
||||
const log = [];
|
||||
// We have to persist here because we want to read relatedTarget later.
|
||||
|
@ -2202,6 +2219,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(log).toEqual(['beforeblur', 'afterblur']);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('beforeblur and afterblur are called after a nested focused element is unmounted', () => {
|
||||
const log = [];
|
||||
// We have to persist here because we want to read relatedTarget later.
|
||||
|
@ -2346,6 +2364,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
ReactDOMServer = require('react-dom/server');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('handle propagation of click events on a scope', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const log = [];
|
||||
|
@ -2390,6 +2409,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('handle mixed propagation of click events on a scope', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const divRef = React.createRef();
|
||||
|
@ -2464,6 +2484,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not handle the target being a dangling text node within a scope', () => {
|
||||
const clickEvent = jest.fn();
|
||||
const buttonRef = React.createRef();
|
||||
|
@ -2495,6 +2516,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(clickEvent).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('handle stopPropagation (inner) correctly between scopes', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const outerOnClick = jest.fn();
|
||||
|
@ -2531,6 +2553,7 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(outerOnClick).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('handle stopPropagation (outer) correctly between scopes', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const outerOnClick = jest.fn(e => e.stopPropagation());
|
||||
|
@ -2567,6 +2590,8 @@ describe('DOMModernPluginEventSystem', () => {
|
|||
expect(outerOnClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
|
||||
it('handle stopPropagation (inner and outer) correctly between scopes', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const onClick = jest.fn(e => e.stopPropagation());
|
||||
|
|
|
@ -66,11 +66,6 @@ function dispatchClickEvent(element) {
|
|||
describe('DOMEventResponderSystem', () => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
|
@ -89,6 +84,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
container = null;
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can mount and render correctly with the ReactTestRenderer', () => {
|
||||
jest.resetModules();
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
|
@ -106,6 +102,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(renderer).toMatchRenderedOutput(<div>Hello world</div>);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can render correctly with the ReactDOMServer', () => {
|
||||
const TestResponder = createEventResponder({});
|
||||
|
||||
|
@ -118,6 +115,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(output).toBe(`<div data-reactroot="">Hello world</div>`);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can render correctly with the ReactDOMServer hydration', () => {
|
||||
const onEvent = jest.fn();
|
||||
const TestResponder = createEventResponder({
|
||||
|
@ -147,6 +145,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(onEvent).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('the event responders should fire on click event', () => {
|
||||
let eventResponderFiredCount = 0;
|
||||
const eventLog = [];
|
||||
|
@ -202,6 +201,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(eventResponderFiredCount).toBe(2);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('the event responders should fire on click event (passive events forced)', () => {
|
||||
// JSDOM does not support passive events, so this manually overrides the value to be true
|
||||
const checkPassiveEvents = require('react-dom/src/events/checkPassiveEvents');
|
||||
|
@ -246,6 +246,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('nested event responders should not fire multiple times', () => {
|
||||
let eventResponderFiredCount = 0;
|
||||
let eventLog = [];
|
||||
|
@ -327,6 +328,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('nested event responders should fire in the correct order', () => {
|
||||
let eventLog = [];
|
||||
const buttonRef = React.createRef();
|
||||
|
@ -390,6 +392,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(eventLog).toEqual(['B [bubble]', 'A [bubble]']);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('nested event responders should fire in the correct order #2', () => {
|
||||
const eventLog = [];
|
||||
const buttonRef = React.createRef();
|
||||
|
@ -426,6 +429,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(eventLog).toEqual(['B [bubble]']);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('custom event dispatching for click -> magicClick works', () => {
|
||||
const eventLog = [];
|
||||
const buttonRef = React.createRef();
|
||||
|
@ -472,6 +476,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(eventLog).toEqual(['magic event fired', 'magicclick', 'bubble']);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('the event responder onMount() function should fire', () => {
|
||||
let onMountFired = 0;
|
||||
|
||||
|
@ -505,6 +510,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(onMountFired).toEqual(2);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('the event responder onUnmount() function should fire', () => {
|
||||
let onUnmountFired = 0;
|
||||
|
||||
|
@ -551,6 +557,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(onUnmountFired).toEqual(4);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('the event responder onUnmount() function should fire using scopes', () => {
|
||||
let onUnmountFired = 0;
|
||||
|
||||
|
@ -598,6 +605,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(onUnmountFired).toEqual(4);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('the event responder onUnmount() function should fire with state', () => {
|
||||
let counter = 0;
|
||||
|
||||
|
@ -621,6 +629,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(counter).toEqual(5);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('the event responder target listeners should correctly fire for only their events', () => {
|
||||
let clickEventComponent1Fired = 0;
|
||||
let clickEventComponent2Fired = 0;
|
||||
|
@ -682,6 +691,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('the event responder system should warn on accessing invalid properties', () => {
|
||||
const TestResponder = createEventResponder({
|
||||
targetEventTypes: ['click'],
|
||||
|
@ -747,6 +757,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(container.innerHTML).toBe('<button>Click me!</button>');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should work with event responder hooks', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const eventLogs = [];
|
||||
|
@ -839,6 +850,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(log).toEqual([{counter: 1}]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly pass through event properties', () => {
|
||||
const timeStamps = [];
|
||||
const ref = React.createRef();
|
||||
|
@ -903,6 +915,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not propagate target events through portals by default', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const onEvent = jest.fn();
|
||||
|
@ -926,6 +939,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(onEvent).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should propagate target events through portals when enabled', () => {
|
||||
const buttonRef = React.createRef();
|
||||
const onEvent = jest.fn();
|
||||
|
@ -950,6 +964,7 @@ describe('DOMEventResponderSystem', () => {
|
|||
expect(onEvent).toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('event upgrading should work correctly', () => {
|
||||
let eventResponderFiredCount = 0;
|
||||
const buttonRef = React.createRef();
|
||||
|
|
|
@ -28,9 +28,14 @@ function initializeModules(hasPointerEvents) {
|
|||
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
|
||||
// TODO: This import throws outside of experimental mode. Figure out better
|
||||
// strategy for gated imports.
|
||||
if (__EXPERIMENTAL__) {
|
||||
useContextMenu = require('react-interactions/events/context-menu')
|
||||
.useContextMenu;
|
||||
}
|
||||
}
|
||||
|
||||
const forcePointerEvents = true;
|
||||
const table = [[forcePointerEvents], [!forcePointerEvents]];
|
||||
|
@ -38,11 +43,6 @@ const table = [[forcePointerEvents], [!forcePointerEvents]];
|
|||
describe.each(table)('ContextMenu responder', hasPointerEvents => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
initializeModules(hasPointerEvents);
|
||||
container = document.createElement('div');
|
||||
|
@ -56,6 +56,7 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
describe('all platforms', () => {
|
||||
// @gate experimental
|
||||
it('mouse right-click', () => {
|
||||
const onContextMenu = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -79,6 +80,7 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('touch long-press', () => {
|
||||
const onContextMenu = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -102,6 +104,7 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('"disabled" is true', () => {
|
||||
const onContextMenu = jest.fn();
|
||||
const ref = React.createRef();
|
||||
|
@ -119,6 +122,7 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => {
|
|||
expect(onContextMenu).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('"preventDefault" is false', () => {
|
||||
const preventDefault = jest.fn();
|
||||
const onContextMenu = jest.fn();
|
||||
|
@ -149,6 +153,7 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => {
|
|||
platform.clear();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('mouse modified left-click', () => {
|
||||
const onContextMenu = jest.fn();
|
||||
const ref = React.createRef();
|
||||
|
@ -181,6 +186,7 @@ describe.each(table)('ContextMenu responder', hasPointerEvents => {
|
|||
platform.clear();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('mouse modified left-click', () => {
|
||||
const onContextMenu = jest.fn();
|
||||
const ref = React.createRef();
|
||||
|
|
|
@ -28,9 +28,14 @@ function initializeModules(hasPointerEvents) {
|
|||
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
|
||||
// TODO: This import throws outside of experimental mode. Figure out better
|
||||
// strategy for gated imports.
|
||||
if (__EXPERIMENTAL__) {
|
||||
FocusResponder = require('react-interactions/events/focus').FocusResponder;
|
||||
useFocus = require('react-interactions/events/focus').useFocus;
|
||||
}
|
||||
}
|
||||
|
||||
const forcePointerEvents = true;
|
||||
const table = [[forcePointerEvents], [!forcePointerEvents]];
|
||||
|
@ -38,11 +43,6 @@ const table = [[forcePointerEvents], [!forcePointerEvents]];
|
|||
describe.each(table)('Focus responder', hasPointerEvents => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
initializeModules(hasPointerEvents);
|
||||
container = document.createElement('div');
|
||||
|
@ -58,7 +58,7 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
describe('disabled', () => {
|
||||
let onBlur, onFocus, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onBlur = jest.fn();
|
||||
onFocus = jest.fn();
|
||||
ref = React.createRef();
|
||||
|
@ -71,9 +71,11 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('does not call callbacks', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.focus();
|
||||
target.blur();
|
||||
|
@ -85,7 +87,7 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
describe('onBlur', () => {
|
||||
let onBlur, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onBlur = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -95,9 +97,11 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "blur" event', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.focus();
|
||||
target.blur();
|
||||
|
@ -125,21 +129,25 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
ReactDOM.render(<Component />, container);
|
||||
};
|
||||
|
||||
beforeEach(componentInit);
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "focus" event', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.focus();
|
||||
expect(onFocus).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called if descendants of target receive focus', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(innerRef.current);
|
||||
target.focus();
|
||||
expect(onFocus).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called with the correct pointerType: mouse', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown();
|
||||
target.pointerup();
|
||||
|
@ -149,7 +157,9 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called with the correct pointerType: touch', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const pointerType = 'touch';
|
||||
target.pointerdown({pointerType});
|
||||
|
@ -161,7 +171,9 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
if (hasPointerEvents) {
|
||||
// @gate experimental
|
||||
it('is called with the correct pointerType: pen', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const pointerType = 'pen';
|
||||
target.pointerdown({pointerType});
|
||||
|
@ -173,7 +185,9 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
});
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('is called with the correct pointerType using a keyboard', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'LeftArrow'});
|
||||
target.focus();
|
||||
|
@ -183,6 +197,7 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called with the correct pointerType using Tab+altKey on Mac', () => {
|
||||
platform.set('mac');
|
||||
jest.resetModules();
|
||||
|
@ -207,7 +222,7 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
describe('onFocusChange', () => {
|
||||
let onFocusChange, ref, innerRef;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onFocusChange = jest.fn();
|
||||
ref = React.createRef();
|
||||
innerRef = React.createRef();
|
||||
|
@ -222,9 +237,11 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "blur" and "focus" events', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.focus();
|
||||
expect(onFocusChange).toHaveBeenCalledTimes(1);
|
||||
|
@ -234,7 +251,9 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
expect(onFocusChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after "blur" and "focus" events on descendants', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(innerRef.current);
|
||||
target.focus();
|
||||
expect(onFocusChange).toHaveBeenCalledTimes(0);
|
||||
|
@ -246,7 +265,7 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
describe('onFocusVisibleChange', () => {
|
||||
let onFocusVisibleChange, ref, innerRef;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onFocusVisibleChange = jest.fn();
|
||||
ref = React.createRef();
|
||||
innerRef = React.createRef();
|
||||
|
@ -261,9 +280,11 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "focus" and "blur" if keyboard navigation is active', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const containerTarget = createEventTarget(container);
|
||||
// use keyboard first
|
||||
|
@ -276,7 +297,9 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
expect(onFocusVisibleChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called if non-keyboard event is dispatched on target previously focused with keyboard', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const containerTarget = createEventTarget(container);
|
||||
// use keyboard first
|
||||
|
@ -293,7 +316,9 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
expect(onFocusVisibleChange).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after "focus" and "blur" events without keyboard', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const containerTarget = createEventTarget(container);
|
||||
target.pointerdown();
|
||||
|
@ -303,7 +328,9 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
expect(onFocusVisibleChange).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after "blur" and "focus" events on descendants', () => {
|
||||
componentInit();
|
||||
const innerTarget = createEventTarget(innerRef.current);
|
||||
const containerTarget = createEventTarget(container);
|
||||
containerTarget.keydown({key: 'Tab'});
|
||||
|
@ -315,6 +342,7 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
describe('nested Focus components', () => {
|
||||
// @gate experimental
|
||||
it('propagates events in the correct order', () => {
|
||||
const events = [];
|
||||
const innerRef = React.createRef();
|
||||
|
@ -367,6 +395,7 @@ describe.each(table)('Focus responder', hasPointerEvents => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('expect displayName to show up for event component', () => {
|
||||
expect(FocusResponder.displayName).toBe('Focus');
|
||||
});
|
||||
|
|
|
@ -25,10 +25,15 @@ const initializeModules = hasPointerEvents => {
|
|||
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
// TODO: This import throws outside of experimental mode. Figure out better
|
||||
// strategy for gated imports.
|
||||
if (__EXPERIMENTAL__) {
|
||||
FocusWithinResponder = require('react-interactions/events/focus')
|
||||
.FocusWithinResponder;
|
||||
useFocusWithin = require('react-interactions/events/focus').useFocusWithin;
|
||||
Scheduler = require('scheduler');
|
||||
}
|
||||
};
|
||||
|
||||
const forcePointerEvents = true;
|
||||
|
@ -37,11 +42,6 @@ const table = [[forcePointerEvents], [!forcePointerEvents]];
|
|||
describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
initializeModules();
|
||||
container = document.createElement('div');
|
||||
|
@ -57,7 +57,7 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
describe('disabled', () => {
|
||||
let onFocusWithinChange, onFocusWithinVisibleChange, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onFocusWithinChange = jest.fn();
|
||||
onFocusWithinVisibleChange = jest.fn();
|
||||
ref = React.createRef();
|
||||
|
@ -70,9 +70,11 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('prevents custom events being dispatched', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.focus();
|
||||
target.blur();
|
||||
|
@ -96,15 +98,17 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onFocusWithinChange = jest.fn();
|
||||
ref = React.createRef();
|
||||
innerRef = React.createRef();
|
||||
innerRef2 = React.createRef();
|
||||
ReactDOM.render(<Component show={true} />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "blur" and "focus" events on focus target', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.focus();
|
||||
expect(onFocusWithinChange).toHaveBeenCalledTimes(1);
|
||||
|
@ -114,7 +118,9 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
expect(onFocusWithinChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "blur" and "focus" events on descendants', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(innerRef.current);
|
||||
target.focus();
|
||||
expect(onFocusWithinChange).toHaveBeenCalledTimes(1);
|
||||
|
@ -124,7 +130,9 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
expect(onFocusWithinChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is only called once when focus moves within and outside the subtree', () => {
|
||||
componentInit();
|
||||
const node = ref.current;
|
||||
const innerNode1 = innerRef.current;
|
||||
const innerNode2 = innerRef.current;
|
||||
|
@ -165,15 +173,17 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onFocusWithinVisibleChange = jest.fn();
|
||||
ref = React.createRef();
|
||||
innerRef = React.createRef();
|
||||
innerRef2 = React.createRef();
|
||||
ReactDOM.render(<Component show={true} />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "focus" and "blur" on focus target if keyboard was used', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const containerTarget = createEventTarget(container);
|
||||
// use keyboard first
|
||||
|
@ -186,7 +196,9 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "focus" and "blur" on descendants if keyboard was used', () => {
|
||||
componentInit();
|
||||
const innerTarget = createEventTarget(innerRef.current);
|
||||
const containerTarget = createEventTarget(container);
|
||||
// use keyboard first
|
||||
|
@ -199,7 +211,9 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called if non-keyboard event is dispatched on target previously focused with keyboard', () => {
|
||||
componentInit();
|
||||
const node = ref.current;
|
||||
const innerNode1 = innerRef.current;
|
||||
const innerNode2 = innerRef2.current;
|
||||
|
@ -235,7 +249,9 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after "focus" and "blur" events without keyboard', () => {
|
||||
componentInit();
|
||||
const innerTarget = createEventTarget(innerRef.current);
|
||||
innerTarget.pointerdown();
|
||||
innerTarget.pointerup();
|
||||
|
@ -243,7 +259,9 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is only called once when focus moves within and outside the subtree', () => {
|
||||
componentInit();
|
||||
const node = ref.current;
|
||||
const innerNode1 = innerRef.current;
|
||||
const innerNode2 = innerRef2.current;
|
||||
|
@ -280,6 +298,7 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
innerRef2 = React.createRef();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after a focused element is unmounted', () => {
|
||||
const Component = ({show}) => {
|
||||
const listener = useFocusWithin({
|
||||
|
@ -310,6 +329,7 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after a nested focused element is unmounted', () => {
|
||||
const Component = ({show}) => {
|
||||
const listener = useFocusWithin({
|
||||
|
@ -405,6 +425,7 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('expect displayName to show up for event component', () => {
|
||||
expect(FocusWithinResponder.displayName).toBe('FocusWithin');
|
||||
});
|
||||
|
|
|
@ -24,9 +24,14 @@ function initializeModules(hasPointerEvents) {
|
|||
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
|
||||
// TODO: This import throws outside of experimental mode. Figure out better
|
||||
// strategy for gated imports.
|
||||
if (__EXPERIMENTAL__) {
|
||||
HoverResponder = require('react-interactions/events/hover').HoverResponder;
|
||||
useHover = require('react-interactions/events/hover').useHover;
|
||||
}
|
||||
}
|
||||
|
||||
const forcePointerEvents = true;
|
||||
const table = [[forcePointerEvents], [!forcePointerEvents]];
|
||||
|
@ -34,11 +39,6 @@ const table = [[forcePointerEvents], [!forcePointerEvents]];
|
|||
describe.each(table)('Hover responder', hasPointerEvents => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
initializeModules(hasPointerEvents);
|
||||
container = document.createElement('div');
|
||||
|
@ -54,7 +54,7 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
describe('disabled', () => {
|
||||
let onHoverChange, onHoverStart, onHoverMove, onHoverEnd, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onHoverChange = jest.fn();
|
||||
onHoverStart = jest.fn();
|
||||
onHoverMove = jest.fn();
|
||||
|
@ -71,9 +71,11 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('does not call callbacks', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerenter();
|
||||
target.pointerexit();
|
||||
|
@ -87,7 +89,7 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
describe('onHoverStart', () => {
|
||||
let onHoverStart, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onHoverStart = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -97,22 +99,28 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('is called for mouse pointers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerenter();
|
||||
expect(onHoverStart).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called for touch pointers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointerup({pointerType: 'touch'});
|
||||
expect(onHoverStart).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called if a mouse pointer is used after a touch pointer', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointerup({pointerType: 'touch'});
|
||||
|
@ -124,7 +132,7 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
describe('onHoverChange', () => {
|
||||
let onHoverChange, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onHoverChange = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -134,9 +142,11 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('is called for mouse pointers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerenter();
|
||||
expect(onHoverChange).toHaveBeenCalledTimes(1);
|
||||
|
@ -146,7 +156,9 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
expect(onHoverChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called for touch pointers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointerup({pointerType: 'touch'});
|
||||
|
@ -157,7 +169,7 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
describe('onHoverEnd', () => {
|
||||
let onHoverEnd, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onHoverEnd = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -167,9 +179,11 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('is called for mouse pointers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerenter();
|
||||
target.pointerexit();
|
||||
|
@ -177,7 +191,9 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
if (hasPointerEvents) {
|
||||
// @gate experimental
|
||||
it('is called once for cancelled mouse pointers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerenter();
|
||||
target.pointercancel();
|
||||
|
@ -192,14 +208,18 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
});
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('is not called for touch pointers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointerup({pointerType: 'touch'});
|
||||
expect(onHoverEnd).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly work with React Portals', () => {
|
||||
componentInit();
|
||||
const portalNode = document.createElement('div');
|
||||
const divRef = React.createRef();
|
||||
const spanRef = React.createRef();
|
||||
|
@ -227,6 +247,7 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
describe('onHoverMove', () => {
|
||||
// @gate experimental
|
||||
it('is called after the active pointer moves"', () => {
|
||||
const onHoverMove = jest.fn();
|
||||
const ref = React.createRef();
|
||||
|
@ -250,6 +271,7 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
describe('nested Hover components', () => {
|
||||
// @gate experimental
|
||||
it('not propagate by default', () => {
|
||||
const events = [];
|
||||
const innerRef = React.createRef();
|
||||
|
@ -310,10 +332,12 @@ describe.each(table)('Hover responder', hasPointerEvents => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('expect displayName to show up for event component', () => {
|
||||
expect(HoverResponder.displayName).toBe('Hover');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly pass through event properties', () => {
|
||||
const timeStamps = [];
|
||||
const ref = React.createRef();
|
||||
|
|
|
@ -38,18 +38,18 @@ const modulesInit = () => {
|
|||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
Scheduler = require('scheduler');
|
||||
|
||||
// TODO: This import throws outside of experimental mode. Figure out better
|
||||
// strategy for gated imports.
|
||||
if (__EXPERIMENTAL__) {
|
||||
InputResponder = require('react-interactions/events/input').InputResponder;
|
||||
useInput = require('react-interactions/events/input').useInput;
|
||||
}
|
||||
};
|
||||
|
||||
describe('Input event responder', () => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
modulesInit();
|
||||
|
@ -66,7 +66,7 @@ describe('Input event responder', () => {
|
|||
describe('disabled', () => {
|
||||
let onChange, onValueChange, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onChange = jest.fn();
|
||||
onValueChange = jest.fn();
|
||||
ref = React.createRef();
|
||||
|
@ -80,9 +80,11 @@ describe('Input event responder', () => {
|
|||
return <input ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
}
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('prevents custom events being dispatched', () => {
|
||||
componentInit();
|
||||
ref.current.dispatchEvent(
|
||||
new Event('change', {bubbles: true, cancelable: true}),
|
||||
);
|
||||
|
@ -104,6 +106,7 @@ describe('Input event responder', () => {
|
|||
// keep track of the "current" value and only fire events when it changes.
|
||||
// See https://github.com/facebook/react/pull/5746.
|
||||
|
||||
// @gate experimental
|
||||
it('should consider initial text value to be current', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -151,6 +154,7 @@ describe('Input event responder', () => {
|
|||
}
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should consider initial checkbox checked=true to be current', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -194,6 +198,7 @@ describe('Input event responder', () => {
|
|||
expect(onValueChangeCalled).toBe(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should consider initial checkbox checked=false to be current', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -236,6 +241,7 @@ describe('Input event responder', () => {
|
|||
expect(onValueChangeCalled).toBe(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should fire change for checkbox input', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -283,6 +289,7 @@ describe('Input event responder', () => {
|
|||
expect(onValueChangeCalled).toBe(2);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not fire change setting the value programmatically', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -345,6 +352,7 @@ describe('Input event responder', () => {
|
|||
expect(onValueChangeCalled).toBe(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not distinguish equal string and number values', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -390,6 +398,7 @@ describe('Input event responder', () => {
|
|||
});
|
||||
|
||||
// See a similar input test above for a detailed description of why.
|
||||
// @gate experimental
|
||||
it('should not fire change when setting checked programmatically', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -441,6 +450,7 @@ describe('Input event responder', () => {
|
|||
expect(onValueChangeCalled).toBe(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should only fire change for checked radio button once', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -477,6 +487,7 @@ describe('Input event responder', () => {
|
|||
expect(onValueChangeCalled).toBe(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should track radio button cousins in a group', () => {
|
||||
let onChangeCalled1 = 0;
|
||||
let onValueChangeCalled1 = 0;
|
||||
|
@ -566,6 +577,7 @@ describe('Input event responder', () => {
|
|||
expect(onValueChangeCalled2).toBe(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should deduplicate input value change events', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -672,6 +684,7 @@ describe('Input event responder', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should listen for both change and input events when supported', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -711,6 +724,7 @@ describe('Input event responder', () => {
|
|||
expect(onValueChangeCalled).toBe(2);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should only fire events when the value changes for range inputs', () => {
|
||||
let onChangeCalled = 0;
|
||||
let onValueChangeCalled = 0;
|
||||
|
@ -756,6 +770,7 @@ describe('Input event responder', () => {
|
|||
expect(onValueChangeCalled).toBe(2);
|
||||
});
|
||||
|
||||
// @gate experimental || build === "production"
|
||||
it('does not crash for nodes with custom value property', () => {
|
||||
let originalCreateElement;
|
||||
// https://github.com/facebook/react/issues/10196
|
||||
|
@ -793,6 +808,7 @@ describe('Input event responder', () => {
|
|||
});
|
||||
|
||||
describe('concurrent mode', () => {
|
||||
// @gate experimental
|
||||
// @gate experimental
|
||||
it('text input', () => {
|
||||
const root = ReactDOM.createRoot(container);
|
||||
|
@ -849,6 +865,7 @@ describe('Input event responder', () => {
|
|||
expect(input.value).toBe('changed [!]');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
// @gate experimental
|
||||
it('checkbox input', () => {
|
||||
const root = ReactDOM.createRoot(container);
|
||||
|
@ -918,6 +935,7 @@ describe('Input event responder', () => {
|
|||
expect(input.checked).toBe(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
// @gate experimental
|
||||
it('textarea', () => {
|
||||
const root = ReactDOM.createRoot(container);
|
||||
|
@ -976,6 +994,7 @@ describe('Input event responder', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('expect displayName to show up for event component', () => {
|
||||
expect(InputResponder.displayName).toBe('Input');
|
||||
});
|
||||
|
|
|
@ -22,17 +22,17 @@ function initializeModules(hasPointerEvents) {
|
|||
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
|
||||
// TODO: This import throws outside of experimental mode. Figure out better
|
||||
// strategy for gated imports.
|
||||
if (__EXPERIMENTAL__) {
|
||||
useKeyboard = require('react-interactions/events/keyboard').useKeyboard;
|
||||
}
|
||||
}
|
||||
|
||||
describe('Keyboard responder', () => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
initializeModules();
|
||||
container = document.createElement('div');
|
||||
|
@ -82,6 +82,7 @@ describe('Keyboard responder', () => {
|
|||
};
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
test('propagates key event when a continuePropagation() is used', () => {
|
||||
const {
|
||||
onClickInner,
|
||||
|
@ -104,6 +105,7 @@ describe('Keyboard responder', () => {
|
|||
expect(onClickOuter).toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('does not propagate key event by default', () => {
|
||||
const {
|
||||
onClickInner,
|
||||
|
@ -129,7 +131,7 @@ describe('Keyboard responder', () => {
|
|||
describe('disabled', () => {
|
||||
let onKeyDown, onKeyUp, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onKeyDown = jest.fn();
|
||||
onKeyUp = jest.fn();
|
||||
ref = React.createRef();
|
||||
|
@ -138,9 +140,11 @@ describe('Keyboard responder', () => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
test('does not call callbacks', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown();
|
||||
target.keyup();
|
||||
|
@ -152,7 +156,7 @@ describe('Keyboard responder', () => {
|
|||
describe('onClick', () => {
|
||||
let onClick, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onClick = jest.fn(e => {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
@ -162,10 +166,12 @@ describe('Keyboard responder', () => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// e.g, "Enter" on link
|
||||
// @gate experimental
|
||||
test('click is between key events', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keyup({key: 'Enter'});
|
||||
|
@ -187,7 +193,9 @@ describe('Keyboard responder', () => {
|
|||
});
|
||||
|
||||
// e.g., "Spacebar" on button
|
||||
// @gate experimental
|
||||
test('click is after key events', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keyup({key: 'Enter'});
|
||||
|
@ -209,7 +217,9 @@ describe('Keyboard responder', () => {
|
|||
});
|
||||
|
||||
// e.g, generated by a screen-reader
|
||||
// @gate experimental
|
||||
test('click is orphan', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.virtualclick();
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
|
@ -232,7 +242,7 @@ describe('Keyboard responder', () => {
|
|||
describe('onKeyDown', () => {
|
||||
let onKeyDown, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onKeyDown = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -240,9 +250,11 @@ describe('Keyboard responder', () => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
test('key down', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Q'});
|
||||
expect(onKeyDown).toHaveBeenCalledTimes(1);
|
||||
|
@ -263,7 +275,9 @@ describe('Keyboard responder', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('modified key down', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({
|
||||
key: 'Q',
|
||||
|
@ -293,7 +307,7 @@ describe('Keyboard responder', () => {
|
|||
describe('onKeyUp', () => {
|
||||
let onKeyUp, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onKeyUp = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -301,9 +315,11 @@ describe('Keyboard responder', () => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
test('key up', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Q'});
|
||||
target.keyup({key: 'Q'});
|
||||
|
@ -325,7 +341,9 @@ describe('Keyboard responder', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('modified key up', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Q'});
|
||||
target.keyup({
|
||||
|
@ -364,6 +382,7 @@ describe('Keyboard responder', () => {
|
|||
return ref;
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
test('does not prevent native click by default', () => {
|
||||
const onClick = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -381,6 +400,7 @@ describe('Keyboard responder', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('prevents native behaviour with preventDefault', () => {
|
||||
const onClick = jest.fn(e => e.preventDefault());
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -409,6 +429,7 @@ describe('Keyboard responder', () => {
|
|||
return ref;
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
test('key config matches', () => {
|
||||
const onKeyDown = jest.fn(e => {
|
||||
if (e.key === 'Tab') {
|
||||
|
@ -434,6 +455,7 @@ describe('Keyboard responder', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('key config matches (modifier keys)', () => {
|
||||
const onKeyDown = jest.fn(e => {
|
||||
if (e.key === 'Tab' && e.shiftKey) {
|
||||
|
@ -457,6 +479,7 @@ describe('Keyboard responder', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('key config does not match (modifier keys)', () => {
|
||||
const onKeyDown = jest.fn(e => {
|
||||
if (e.key === 'Tab' && e.shiftKey) {
|
||||
|
|
|
@ -19,11 +19,6 @@ let Scheduler;
|
|||
describe('mixing responders with the heritage event system', () => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
|
||||
|
@ -39,11 +34,7 @@ describe('mixing responders with the heritage event system', () => {
|
|||
container = null;
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('should properly only flush sync once when the event systems are mixed', () => {
|
||||
const useTap = require('react-interactions/events/tap').useTap;
|
||||
const ref = React.createRef();
|
||||
|
@ -113,6 +104,7 @@ describe('mixing responders with the heritage event system', () => {
|
|||
document.body.removeChild(newContainer);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should properly flush sync when the event systems are mixed with unstable_flushDiscreteUpdates', () => {
|
||||
const useTap = require('react-interactions/events/tap').useTap;
|
||||
const ref = React.createRef();
|
||||
|
@ -182,6 +174,7 @@ describe('mixing responders with the heritage event system', () => {
|
|||
document.body.removeChild(newContainer);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it(
|
||||
'should only flush before outermost discrete event handler when mixing ' +
|
||||
'event systems',
|
||||
|
@ -241,6 +234,7 @@ describe('mixing responders with the heritage event system', () => {
|
|||
);
|
||||
|
||||
describe('mixing the Input and Press repsonders', () => {
|
||||
// @gate experimental
|
||||
it('is async for non-input events', () => {
|
||||
const useTap = require('react-interactions/events/tap').useTap;
|
||||
const useInput = require('react-interactions/events/input').useInput;
|
||||
|
|
|
@ -30,19 +30,17 @@ function initializeModules(hasPointerEvents) {
|
|||
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
|
||||
// TODO: This import throws outside of experimental mode. Figure out better
|
||||
// strategy for gated imports.
|
||||
if (__EXPERIMENTAL__) {
|
||||
usePress = require('react-interactions/events/press').usePress;
|
||||
}
|
||||
|
||||
const pointerTypesTable = [['mouse'], ['touch']];
|
||||
}
|
||||
|
||||
describeWithPointerEvent('Press responder', hasPointerEvents => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
initializeModules(hasPointerEvents);
|
||||
container = document.createElement('div');
|
||||
|
@ -59,7 +57,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
describe('disabled', () => {
|
||||
let onPressStart, onPressChange, onPressMove, onPressEnd, onPress, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPressStart = jest.fn();
|
||||
onPressChange = jest.fn();
|
||||
onPressMove = jest.fn();
|
||||
|
@ -78,9 +76,11 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
test('does not call callbacks for pointers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown();
|
||||
target.pointerup();
|
||||
|
@ -91,7 +91,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
expect(onPress).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('does not call callbacks for keyboard', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keyup({key: 'Enter'});
|
||||
|
@ -106,7 +108,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
describe('onPressStart', () => {
|
||||
let onPressStart, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPressStart = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -117,21 +119,33 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
it.each(pointerTypesTable)(
|
||||
'is called after pointer down: %s',
|
||||
pointerType => {
|
||||
// @gate experimental
|
||||
it('is called after pointer down: mouse', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
expect(onPressStart).toHaveBeenCalledTimes(1);
|
||||
expect(onPressStart).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType, type: 'pressstart'}),
|
||||
);
|
||||
},
|
||||
expect.objectContaining({pointerType: 'mouse', type: 'pressstart'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after pointer down: mouse', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
expect(onPressStart).toHaveBeenCalledTimes(1);
|
||||
expect(onPressStart).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType: 'touch', type: 'pressstart'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after middle-button pointer down', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const pointerType = 'mouse';
|
||||
target.pointerdown({
|
||||
|
@ -150,7 +164,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after virtual middle-button pointer down', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const pointerType = 'mouse';
|
||||
target.pointerdown({
|
||||
|
@ -169,7 +185,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('ignores any events not caused by primary/middle-click or touch/pen contact', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({buttons: buttonsType.secondary});
|
||||
target.pointerup({buttons: buttonsType.secondary});
|
||||
|
@ -178,7 +196,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
expect(onPressStart).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called once after "keydown" events for Enter', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keydown({key: 'Enter'});
|
||||
|
@ -189,7 +209,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called once after "keydown" events for Spacebar', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const preventDefault = jest.fn();
|
||||
target.keydown({key: ' ', preventDefault});
|
||||
|
@ -204,7 +226,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after "keydown" for other keys', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'a'});
|
||||
expect(onPressStart).not.toBeCalled();
|
||||
|
@ -214,7 +238,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
describe('onPressEnd', () => {
|
||||
let onPressEnd, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPressEnd = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -225,22 +249,35 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
it.each(pointerTypesTable)(
|
||||
'is called after pointer up: %s',
|
||||
pointerType => {
|
||||
// @gate experimental
|
||||
it('is called after pointer up: mouse', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
target.pointerup({pointerType});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
target.pointerup({pointerType: 'mouse'});
|
||||
expect(onPressEnd).toHaveBeenCalledTimes(1);
|
||||
expect(onPressEnd).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType, type: 'pressend'}),
|
||||
);
|
||||
},
|
||||
expect.objectContaining({pointerType: 'mouse', type: 'pressend'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after pointer up: touch', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointerup({pointerType: 'touch'});
|
||||
expect(onPressEnd).toHaveBeenCalledTimes(1);
|
||||
expect(onPressEnd).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType: 'touch', type: 'pressend'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after middle-button pointer up', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({
|
||||
button: buttonType.auxiliary,
|
||||
|
@ -258,7 +295,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after virtual middle-button pointer up', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({
|
||||
button: buttonType.auxiliary,
|
||||
|
@ -276,7 +315,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "keyup" event for Enter', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
// click occurs before keyup
|
||||
|
@ -288,7 +329,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "keyup" event for Spacebar', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: ' '});
|
||||
target.keyup({key: ' '});
|
||||
|
@ -298,14 +341,18 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after "keyup" event for other keys', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keyup({key: 'a'});
|
||||
expect(onPressEnd).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called with keyboard modifiers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keyup({
|
||||
|
@ -331,7 +378,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
describe('onPressChange', () => {
|
||||
let onPressChange, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPressChange = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -342,22 +389,35 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
it.each(pointerTypesTable)(
|
||||
'is called after pointer down and up: %s',
|
||||
pointerType => {
|
||||
// @gate experimental
|
||||
it('is called after pointer down and up: %s', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
expect(onPressChange).toHaveBeenCalledTimes(1);
|
||||
expect(onPressChange).toHaveBeenCalledWith(true);
|
||||
target.pointerup({pointerType});
|
||||
target.pointerup({pointerType: 'mouse'});
|
||||
expect(onPressChange).toHaveBeenCalledTimes(2);
|
||||
expect(onPressChange).toHaveBeenCalledWith(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after pointer down and up: touch', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
expect(onPressChange).toHaveBeenCalledTimes(1);
|
||||
expect(onPressChange).toHaveBeenCalledWith(true);
|
||||
target.pointerup({pointerType: 'touch'});
|
||||
expect(onPressChange).toHaveBeenCalledTimes(2);
|
||||
expect(onPressChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after valid "keydown" and "keyup" events', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
expect(onPressChange).toHaveBeenCalledTimes(1);
|
||||
|
@ -371,7 +431,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
describe('onPress', () => {
|
||||
let onPress, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPress = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -388,22 +448,35 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
right: 100,
|
||||
});
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
it.each(pointerTypesTable)(
|
||||
'is called after pointer up: %s',
|
||||
pointerType => {
|
||||
// @gate experimental
|
||||
it('is called after pointer up: %s', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
target.pointerup({pointerType, x: 10, y: 10});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
target.pointerup({pointerType: 'mouse', x: 10, y: 10});
|
||||
expect(onPress).toHaveBeenCalledTimes(1);
|
||||
expect(onPress).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType, type: 'press'}),
|
||||
);
|
||||
},
|
||||
expect.objectContaining({pointerType: 'mouse', type: 'press'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after pointer up: %s', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointerup({pointerType: 'touch', x: 10, y: 10});
|
||||
expect(onPress).toHaveBeenCalledTimes(1);
|
||||
expect(onPress).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType: 'touch', type: 'press'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after middle-button press', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({
|
||||
button: buttonType.auxiliary,
|
||||
|
@ -414,7 +487,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
expect(onPress).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after virtual middle-button press', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({
|
||||
button: buttonType.auxiliary,
|
||||
|
@ -425,7 +500,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
expect(onPress).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after valid "keyup" event', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keyup({key: 'Enter'});
|
||||
|
@ -435,7 +512,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after invalid "keyup" event', () => {
|
||||
componentInit();
|
||||
const inputRef = React.createRef();
|
||||
const Component = () => {
|
||||
const listener = usePress({onPress});
|
||||
|
@ -450,7 +529,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
expect(onPress).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called with modifier keys', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({metaKey: true, pointerType: 'mouse'});
|
||||
target.pointerup({metaKey: true, pointerType: 'mouse'});
|
||||
|
@ -463,7 +544,9 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called once after virtual screen reader "click" event', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const preventDefault = jest.fn();
|
||||
target.virtualclick({preventDefault});
|
||||
|
@ -481,7 +564,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
describe('onPressMove', () => {
|
||||
let onPressMove, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPressMove = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -498,25 +581,41 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
right: 100,
|
||||
});
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
it.each(pointerTypesTable)(
|
||||
'is called after pointer move: %s',
|
||||
pointerType => {
|
||||
// @gate experimental
|
||||
it('is called after pointer move: mouse', () => {
|
||||
componentInit();
|
||||
const node = ref.current;
|
||||
const target = createEventTarget(node);
|
||||
target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
|
||||
target.pointerdown({pointerType});
|
||||
target.pointermove({pointerType, x: 10, y: 10});
|
||||
target.pointermove({pointerType, x: 20, y: 20});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
target.pointermove({pointerType: 'mouse', x: 10, y: 10});
|
||||
target.pointermove({pointerType: 'mouse', x: 20, y: 20});
|
||||
expect(onPressMove).toHaveBeenCalledTimes(2);
|
||||
expect(onPressMove).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType, type: 'pressmove'}),
|
||||
);
|
||||
},
|
||||
expect.objectContaining({pointerType: 'mouse', type: 'pressmove'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after pointer move: touch', () => {
|
||||
componentInit();
|
||||
const node = ref.current;
|
||||
const target = createEventTarget(node);
|
||||
target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointermove({pointerType: 'touch', x: 10, y: 10});
|
||||
target.pointermove({pointerType: 'touch', x: 20, y: 20});
|
||||
expect(onPressMove).toHaveBeenCalledTimes(2);
|
||||
expect(onPressMove).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType: 'touch', type: 'pressmove'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called if pointer move occurs during keyboard press', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
|
||||
target.keydown({key: 'Enter'});
|
||||
|
@ -531,6 +630,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
describe('link components', () => {
|
||||
// @gate experimental
|
||||
it('prevents native behavior by default', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -551,6 +651,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('prevents native behaviour for keyboard events by default', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefaultClick = jest.fn();
|
||||
|
@ -575,6 +676,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('deeply prevents native behaviour by default', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -596,6 +698,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
expect(preventDefault).toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('prevents native behaviour by default with nested elements', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -620,6 +723,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('uses native behaviour for interactions with modifier keys', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -642,6 +746,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('uses native behaviour for pointer events if preventDefault is false', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -662,6 +767,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('uses native behaviour for keyboard events if preventDefault is false', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -685,6 +791,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not trigger an invariant in addRootEventTypes()', () => {
|
||||
const ref = React.createRef();
|
||||
|
||||
|
@ -701,6 +808,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
|
|||
target.pointerdown();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('when blur occurs on a pressed target, we should disengage press', () => {
|
||||
const onPress = jest.fn();
|
||||
const onPressStart = jest.fn();
|
||||
|
|
|
@ -30,10 +30,15 @@ function initializeModules(hasPointerEvents) {
|
|||
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
|
||||
// TODO: This import throws outside of experimental mode. Figure out better
|
||||
// strategy for gated imports.
|
||||
if (__EXPERIMENTAL__) {
|
||||
PressResponder = require('react-interactions/events/press-legacy')
|
||||
.PressResponder;
|
||||
usePress = require('react-interactions/events/press-legacy').usePress;
|
||||
}
|
||||
}
|
||||
|
||||
function removePressMoveStrings(eventString) {
|
||||
if (eventString === 'onPressMove') {
|
||||
|
@ -50,11 +55,6 @@ const pointerTypesTable = [['mouse'], ['touch']];
|
|||
describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
initializeModules(hasPointerEvents);
|
||||
container = document.createElement('div');
|
||||
|
@ -71,7 +71,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
describe('disabled', () => {
|
||||
let onPressStart, onPress, onPressEnd, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPressStart = jest.fn();
|
||||
onPress = jest.fn();
|
||||
onPressEnd = jest.fn();
|
||||
|
@ -87,9 +87,11 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('does not call callbacks', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown();
|
||||
target.pointerup();
|
||||
|
@ -102,7 +104,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
describe('onPressStart', () => {
|
||||
let onPressStart, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPressStart = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -113,21 +115,33 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
it.each(pointerTypesTable)(
|
||||
'is called after pointer down: %s',
|
||||
pointerType => {
|
||||
// @gate experimental
|
||||
it('is called after pointer down: mouse', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
expect(onPressStart).toHaveBeenCalledTimes(1);
|
||||
expect(onPressStart).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType, type: 'pressstart'}),
|
||||
);
|
||||
},
|
||||
expect.objectContaining({pointerType: 'mouse', type: 'pressstart'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after pointer down: touch', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
expect(onPressStart).toHaveBeenCalledTimes(1);
|
||||
expect(onPressStart).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType: 'touch', type: 'pressstart'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after middle-button pointer down', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({
|
||||
button: buttonType.auxiliary,
|
||||
|
@ -144,7 +158,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after pointer move following middle-button press', () => {
|
||||
componentInit();
|
||||
const node = ref.current;
|
||||
const target = createEventTarget(node);
|
||||
target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
|
||||
|
@ -159,7 +175,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPressStart).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('ignores any events not caused by primary/middle-click or touch/pen contact', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({buttons: buttonsType.secondary});
|
||||
target.pointerup({buttons: buttonsType.secondary});
|
||||
|
@ -168,7 +186,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPressStart).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called once after "keydown" events for Enter', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keydown({key: 'Enter'});
|
||||
|
@ -179,7 +199,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called once after "keydown" events for Spacebar', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const preventDefault = jest.fn();
|
||||
target.keydown({key: ' ', preventDefault});
|
||||
|
@ -194,7 +216,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after "keydown" for other keys', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'a'});
|
||||
expect(onPressStart).not.toBeCalled();
|
||||
|
@ -204,7 +228,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
describe('onPressEnd', () => {
|
||||
let onPressEnd, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPressEnd = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -215,22 +239,35 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
it.each(pointerTypesTable)(
|
||||
'is called after pointer up: %s',
|
||||
pointerType => {
|
||||
// @gate experimental
|
||||
it('is called after pointer up: mouse', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
target.pointerup({pointerType});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
target.pointerup({pointerType: 'mouse'});
|
||||
expect(onPressEnd).toHaveBeenCalledTimes(1);
|
||||
expect(onPressEnd).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType, type: 'pressend'}),
|
||||
);
|
||||
},
|
||||
expect.objectContaining({pointerType: 'mouse', type: 'pressend'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after pointer up: touch', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointerup({pointerType: 'touch'});
|
||||
expect(onPressEnd).toHaveBeenCalledTimes(1);
|
||||
expect(onPressEnd).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType: 'touch', type: 'pressend'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after middle-button pointer up', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({
|
||||
buttons: buttonsType.auxiliary,
|
||||
|
@ -247,7 +284,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "keyup" event for Enter', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
// click occurs before keyup
|
||||
|
@ -259,7 +298,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after "keyup" event for Spacebar', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: ' '});
|
||||
target.keyup({key: ' '});
|
||||
|
@ -269,14 +310,18 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after "keyup" event for other keys', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keyup({key: 'a'});
|
||||
expect(onPressEnd).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called with keyboard modifiers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keyup({
|
||||
|
@ -302,7 +347,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
describe('onPressChange', () => {
|
||||
let onPressChange, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPressChange = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -313,22 +358,35 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
it.each(pointerTypesTable)(
|
||||
'is called after pointer down and up: %s',
|
||||
pointerType => {
|
||||
// @gate experimental
|
||||
it('is called after pointer down and up: mouse', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
expect(onPressChange).toHaveBeenCalledTimes(1);
|
||||
expect(onPressChange).toHaveBeenCalledWith(true);
|
||||
target.pointerup({pointerType});
|
||||
target.pointerup({pointerType: 'mouse'});
|
||||
expect(onPressChange).toHaveBeenCalledTimes(2);
|
||||
expect(onPressChange).toHaveBeenCalledWith(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after pointer down and up: touch', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
expect(onPressChange).toHaveBeenCalledTimes(1);
|
||||
expect(onPressChange).toHaveBeenCalledWith(true);
|
||||
target.pointerup({pointerType: 'touch'});
|
||||
expect(onPressChange).toHaveBeenCalledTimes(2);
|
||||
expect(onPressChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after valid "keydown" and "keyup" events', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
expect(onPressChange).toHaveBeenCalledTimes(1);
|
||||
|
@ -342,7 +400,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
describe('onPress', () => {
|
||||
let onPress, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPress = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -359,22 +417,35 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
right: 100,
|
||||
});
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
it.each(pointerTypesTable)(
|
||||
'is called after pointer up: %s',
|
||||
pointerType => {
|
||||
// @gate experimental
|
||||
it('is called after pointer up: mouse', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
target.pointerup({pointerType, x: 10, y: 10});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
target.pointerup({pointerType: 'mouse', x: 10, y: 10});
|
||||
expect(onPress).toHaveBeenCalledTimes(1);
|
||||
expect(onPress).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType, type: 'press'}),
|
||||
);
|
||||
},
|
||||
expect.objectContaining({pointerType: 'mouse', type: 'press'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after pointer up: touch', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointerup({pointerType: 'touch', x: 10, y: 10});
|
||||
expect(onPress).toHaveBeenCalledTimes(1);
|
||||
expect(onPress).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType: 'touch', type: 'press'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after middle-button press', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({
|
||||
buttons: buttonsType.auxiliary,
|
||||
|
@ -384,7 +455,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPress).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after virtual middle-button press', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({
|
||||
button: buttonType.auxiliary,
|
||||
|
@ -395,7 +468,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPress).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after valid "keyup" event', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.keydown({key: 'Enter'});
|
||||
target.keyup({key: 'Enter'});
|
||||
|
@ -405,7 +480,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called after invalid "keyup" event', () => {
|
||||
componentInit();
|
||||
const inputRef = React.createRef();
|
||||
const Component = () => {
|
||||
const listener = usePress({onPress});
|
||||
|
@ -420,7 +497,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPress).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called with modifier keys', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({metaKey: true, pointerType: 'mouse'});
|
||||
target.pointerup({metaKey: true, pointerType: 'mouse'});
|
||||
|
@ -433,7 +512,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called if target rect is not right but the target is (for mouse events)', () => {
|
||||
componentInit();
|
||||
const buttonRef = React.createRef();
|
||||
const divRef = React.createRef();
|
||||
|
||||
|
@ -455,7 +536,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPress).toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called once after virtual screen reader "click" event', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const preventDefault = jest.fn();
|
||||
target.virtualclick({preventDefault});
|
||||
|
@ -473,7 +556,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
describe('onPressMove', () => {
|
||||
let onPressMove, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onPressMove = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -490,25 +573,41 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
right: 100,
|
||||
});
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
it.each(pointerTypesTable)(
|
||||
'is called after pointer move: %s',
|
||||
pointerType => {
|
||||
// @gate experimental
|
||||
it('is called after pointer move: mouse', () => {
|
||||
componentInit();
|
||||
const node = ref.current;
|
||||
const target = createEventTarget(node);
|
||||
target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
|
||||
target.pointerdown({pointerType});
|
||||
target.pointermove({pointerType, x: 10, y: 10});
|
||||
target.pointermove({pointerType, x: 20, y: 20});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
target.pointermove({pointerType: 'mouse', x: 10, y: 10});
|
||||
target.pointermove({pointerType: 'mouse', x: 20, y: 20});
|
||||
expect(onPressMove).toHaveBeenCalledTimes(2);
|
||||
expect(onPressMove).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType, type: 'pressmove'}),
|
||||
);
|
||||
},
|
||||
expect.objectContaining({pointerType: 'mouse', type: 'pressmove'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is called after pointer move: touch', () => {
|
||||
componentInit();
|
||||
const node = ref.current;
|
||||
const target = createEventTarget(node);
|
||||
target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointermove({pointerType: 'touch', x: 10, y: 10});
|
||||
target.pointermove({pointerType: 'touch', x: 20, y: 20});
|
||||
expect(onPressMove).toHaveBeenCalledTimes(2);
|
||||
expect(onPressMove).toHaveBeenCalledWith(
|
||||
expect.objectContaining({pointerType: 'touch', type: 'pressmove'}),
|
||||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is not called if pointer move occurs during keyboard press', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
|
||||
target.keydown({key: 'Enter'});
|
||||
|
@ -525,7 +624,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
describe.each(pointerTypesTable)('press with movement: %s', pointerType => {
|
||||
let events, ref, outerRef;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
events = [];
|
||||
ref = React.createRef();
|
||||
outerRef = React.createRef();
|
||||
|
@ -548,7 +647,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
const rectMock = {width: 100, height: 100, x: 50, y: 50};
|
||||
const pressRectOffset = 20;
|
||||
|
@ -569,7 +668,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
* │ HitRect X │ <= Move to X and release
|
||||
* └──────────────────┘
|
||||
*/
|
||||
// @gate experimental
|
||||
it('"onPress*" events are called immediately', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.setBoundingClientRect(rectMock);
|
||||
target.pointerdown({pointerType});
|
||||
|
@ -585,7 +686,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('"onPress*" events are correctly called with target change', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const outerTarget = createEventTarget(outerRef.current);
|
||||
target.setBoundingClientRect(rectMock);
|
||||
|
@ -614,7 +717,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('press retention offset can be configured', () => {
|
||||
componentInit();
|
||||
const localEvents = [];
|
||||
const localRef = React.createRef();
|
||||
const createEventHandler = msg => () => {
|
||||
|
@ -654,7 +759,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('responder region accounts for decrease in element dimensions', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.setBoundingClientRect(rectMock);
|
||||
target.pointerdown({pointerType});
|
||||
|
@ -674,7 +781,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('responder region accounts for increase in element dimensions', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.setBoundingClientRect(rectMock);
|
||||
target.pointerdown({pointerType});
|
||||
|
@ -704,7 +813,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
* └──────────────────┘
|
||||
* X <= Move to X and release
|
||||
*/
|
||||
// @gate experimental
|
||||
it('"onPress" is not called on release', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const targetContainer = createEventTarget(container);
|
||||
target.setBoundingClientRect(rectMock);
|
||||
|
@ -727,7 +838,9 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('"onPress" is called on re-entry to hit rect', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const targetContainer = createEventTarget(container);
|
||||
target.setBoundingClientRect(rectMock);
|
||||
|
@ -759,6 +872,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
|
||||
describe('nested responders', () => {
|
||||
if (hasPointerEvents) {
|
||||
// @gate experimental
|
||||
it('dispatch events in the correct order', () => {
|
||||
const events = [];
|
||||
const ref = React.createRef();
|
||||
|
@ -819,6 +933,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
}
|
||||
|
||||
describe('correctly not propagate', () => {
|
||||
// @gate experimental
|
||||
it('for onPress', () => {
|
||||
const ref = React.createRef();
|
||||
const onPress = jest.fn();
|
||||
|
@ -845,6 +960,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPress).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('for onPressStart/onPressEnd', () => {
|
||||
const ref = React.createRef();
|
||||
const onPressStart = jest.fn();
|
||||
|
@ -874,6 +990,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPressEnd).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('for onPressChange', () => {
|
||||
const ref = React.createRef();
|
||||
const onPressChange = jest.fn();
|
||||
|
@ -903,6 +1020,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
describe('link components', () => {
|
||||
// @gate experimental
|
||||
it('prevents native behavior by default', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -923,6 +1041,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('prevents native behaviour for keyboard events by default', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -943,6 +1062,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('deeply prevents native behaviour by default', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -964,6 +1084,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(preventDefault).toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('prevents native behaviour by default with nested elements', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -988,6 +1109,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('uses native behaviour for interactions with modifier keys', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -1010,6 +1132,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('uses native behaviour for pointer events if preventDefault is false', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -1030,6 +1153,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('uses native behaviour for keyboard events if preventDefault is false', () => {
|
||||
const onPress = jest.fn();
|
||||
const preventDefault = jest.fn();
|
||||
|
@ -1053,7 +1177,8 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
describe('responder cancellation', () => {
|
||||
it.each(pointerTypesTable)('ends on pointer cancel', pointerType => {
|
||||
// @gate experimental
|
||||
it('ends on pointer cancel: mouse', () => {
|
||||
const onPressEnd = jest.fn();
|
||||
const ref = React.createRef();
|
||||
|
||||
|
@ -1064,12 +1189,30 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
ReactDOM.render(<Component />, container);
|
||||
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
target.pointercancel({pointerType});
|
||||
target.pointerdown({pointerType: 'mouse'});
|
||||
target.pointercancel({pointerType: 'mouse'});
|
||||
expect(onPressEnd).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('ends on pointer cancel: touch', () => {
|
||||
const onPressEnd = jest.fn();
|
||||
const ref = React.createRef();
|
||||
|
||||
const Component = () => {
|
||||
const listener = usePress({onPressEnd});
|
||||
return <a href="#" ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
target.pointercancel({pointerType: 'touch'});
|
||||
expect(onPressEnd).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('does end on "scroll" to document (not mouse)', () => {
|
||||
const onPressEnd = jest.fn();
|
||||
const ref = React.createRef();
|
||||
|
@ -1087,6 +1230,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPressEnd).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('does end on "scroll" to a parent container (not mouse)', () => {
|
||||
const onPressEnd = jest.fn();
|
||||
const ref = React.createRef();
|
||||
|
@ -1109,6 +1253,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPressEnd).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('does not end on "scroll" to an element outside', () => {
|
||||
const onPressEnd = jest.fn();
|
||||
const ref = React.createRef();
|
||||
|
@ -1132,10 +1277,12 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPressEnd).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('expect displayName to show up for event component', () => {
|
||||
expect(PressResponder.displayName).toBe('Press');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not trigger an invariant in addRootEventTypes()', () => {
|
||||
const ref = React.createRef();
|
||||
|
||||
|
@ -1152,6 +1299,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
target.pointerdown();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('event.preventDefault works as expected', () => {
|
||||
const onPress = jest.fn(e => e.preventDefault());
|
||||
const onPressStart = jest.fn(e => e.preventDefault());
|
||||
|
@ -1173,6 +1321,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
|
|||
expect(onPressEnd).toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('when blur occurs on a pressed target, we should disengage press', () => {
|
||||
const onPress = jest.fn();
|
||||
const onPressStart = jest.fn();
|
||||
|
|
|
@ -31,8 +31,13 @@ function initializeModules(hasPointerEvents) {
|
|||
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
|
||||
// TODO: This import throws outside of experimental mode. Figure out better
|
||||
// strategy for gated imports.
|
||||
if (__EXPERIMENTAL__) {
|
||||
useTap = require('react-interactions/events/tap').useTap;
|
||||
}
|
||||
}
|
||||
|
||||
const coordinatesInside = {x: 51, y: 51};
|
||||
const coordinatesOutside = {x: 49, y: 49};
|
||||
|
@ -73,11 +78,6 @@ function tapAndReleaseOutside({
|
|||
describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
||||
let container;
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
initializeModules(hasPointerEvents);
|
||||
container = document.createElement('div');
|
||||
|
@ -91,6 +91,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
resetActivePointers();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('supports repeated use', () => {
|
||||
const ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -114,7 +115,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
describe('disabled', () => {
|
||||
let onTapStart, onTapChange, onTapUpdate, onTapCancel, onTapEnd, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onTapStart = jest.fn();
|
||||
onTapChange = jest.fn();
|
||||
onTapUpdate = jest.fn();
|
||||
|
@ -133,9 +134,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
return <div ref={ref} DEPRECATED_flareListeners={listener} />;
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
test('does not call callbacks', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown();
|
||||
target.pointerup();
|
||||
|
@ -159,7 +162,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
document.elementFromPoint = () => ref.current;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onTapCancel = jest.fn();
|
||||
onTapUpdate = jest.fn();
|
||||
ref = React.createRef();
|
||||
|
@ -168,9 +171,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
onTapCancel,
|
||||
onTapUpdate,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
test('ignores values less than 10', () => {
|
||||
componentInit();
|
||||
render({
|
||||
maximumDistance: 5,
|
||||
onTapCancel,
|
||||
|
@ -184,7 +189,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
expect(onTapCancel).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
// TODO: Get rid of this condition somehow. Perhaps with a dynamic verion of
|
||||
// the @gate pragma.
|
||||
if (__EXPERIMENTAL__) {
|
||||
testWithPointerType('below threshold', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType, x: 0, y: 0});
|
||||
target.pointermove({pointerType, x: 10, y: 10});
|
||||
|
@ -193,18 +202,20 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
testWithPointerType('above threshold', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType, x: 0, y: 0});
|
||||
target.pointermove({pointerType, x: 15, y: 14});
|
||||
expect(onTapUpdate).toHaveBeenCalledTimes(0);
|
||||
expect(onTapCancel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('onAuxiliaryTap', () => {
|
||||
let onAuxiliaryTap, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onAuxiliaryTap = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -213,9 +224,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
test('auxiliary-button pointer up', () => {
|
||||
componentInit();
|
||||
const pointerType = 'mouse';
|
||||
const button = buttonType.auxiliary;
|
||||
const buttons = buttonsType.auxiliary;
|
||||
|
@ -225,7 +238,9 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
expect(onAuxiliaryTap).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('modifier-button pointer up', () => {
|
||||
componentInit();
|
||||
const pointerType = 'mouse';
|
||||
const button = buttonType.primary;
|
||||
const buttons = buttonsType.primary;
|
||||
|
@ -239,7 +254,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
describe('onTapStart', () => {
|
||||
let onTapStart, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onTapStart = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -248,9 +263,13 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: Get rid of this condition somehow. Perhaps with a dynamic verion of
|
||||
// the @gate pragma.
|
||||
if (__EXPERIMENTAL__) {
|
||||
testWithPointerType('pointer down', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const nativeEvent = {
|
||||
button: buttonType.primary,
|
||||
|
@ -294,8 +313,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
test('second pointer on target', () => {
|
||||
componentInit();
|
||||
const pointerType = 'touch';
|
||||
const target = createEventTarget(ref.current);
|
||||
const button = buttonType.primary;
|
||||
|
@ -306,7 +328,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
expect(onTapStart).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// TODO: Get rid of this condition somehow. Perhaps with a dynamic verion of
|
||||
// the @gate pragma.
|
||||
if (__EXPERIMENTAL__) {
|
||||
testWithPointerType('ignored buttons and modifiers', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
if (pointerType !== 'touch') {
|
||||
// right-click
|
||||
|
@ -373,12 +399,13 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
|
||||
expect(onTapStart).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('onTapEnd', () => {
|
||||
let onTapEnd, ref;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onTapEnd = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -387,9 +414,13 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: Get rid of this condition somehow. Perhaps with a dynamic verion of
|
||||
// the @gate pragma.
|
||||
if (__EXPERIMENTAL__) {
|
||||
testWithPointerType('pointer up', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const button = buttonType.primary;
|
||||
const buttons = buttonsType.primary;
|
||||
|
@ -432,6 +463,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
testWithPointerType('zero-dimension hit rect', pointerType => {
|
||||
componentInit();
|
||||
const targetRef = React.createRef();
|
||||
const innerRef = React.createRef();
|
||||
|
||||
|
@ -455,6 +487,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
testWithPointerType('pointer up outside target', pointerType => {
|
||||
componentInit();
|
||||
const downTarget = createEventTarget(ref.current);
|
||||
const upTarget = createEventTarget(container);
|
||||
tapAndReleaseOutside({
|
||||
|
@ -465,9 +498,12 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
expect(onTapEnd).not.toBeCalled();
|
||||
});
|
||||
}
|
||||
|
||||
if (hasPointerEvents) {
|
||||
// @gate experimental
|
||||
test('second pointer up off target', () => {
|
||||
componentInit();
|
||||
const pointerType = 'touch';
|
||||
const target = createEventTarget(ref.current);
|
||||
const offTarget = createEventTarget(container);
|
||||
|
@ -490,7 +526,9 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
test('ignored buttons and modifiers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
// right-click
|
||||
target.pointerdown({
|
||||
|
@ -553,7 +591,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
const rect = {x: 0, y: 0, width: 100, height: 100};
|
||||
const coordinates = {x: 10, y: 10};
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onTapUpdate = jest.fn();
|
||||
ref = React.createRef();
|
||||
const Component = () => {
|
||||
|
@ -562,9 +600,13 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: Get rid of this condition somehow. Perhaps with a dynamic verion of
|
||||
// the @gate pragma.
|
||||
if (__EXPERIMENTAL__) {
|
||||
testWithPointerType('requires activation', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.setBoundingClientRect(rect);
|
||||
if (pointerType !== 'touch') {
|
||||
|
@ -575,6 +617,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
testWithPointerType('pointer move', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.setBoundingClientRect(rect);
|
||||
target.pointerdown({pointerType});
|
||||
|
@ -615,6 +658,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
testWithPointerType('pointer moves outside target', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const containerTarget = createEventTarget(container);
|
||||
target.setBoundingClientRect(rect);
|
||||
|
@ -634,9 +678,12 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
// No extra 'onTapUpdate' calls when the pointer is outside the target
|
||||
expect(onTapUpdate).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
}
|
||||
|
||||
if (hasPointerEvents) {
|
||||
// @gate experimental
|
||||
test('second pointer off target', () => {
|
||||
componentInit();
|
||||
const pointerType = 'touch';
|
||||
const target = createEventTarget(ref.current);
|
||||
const offTarget = createEventTarget(container);
|
||||
|
@ -659,7 +706,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
eventsLog.push(msg);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
eventsLog = [];
|
||||
onTapChange = jest.fn();
|
||||
ref = React.createRef();
|
||||
|
@ -677,9 +724,13 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
document.elementFromPoint = () => ref.current;
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: Get rid of this condition somehow. Perhaps with a dynamic verion of
|
||||
// the @gate pragma.
|
||||
if (__EXPERIMENTAL__) {
|
||||
testWithPointerType('pointer down/up', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
expect(onTapChange).toHaveBeenCalledTimes(1);
|
||||
|
@ -691,6 +742,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
testWithPointerType('pointer cancel', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
expect(onTapChange).toHaveBeenCalledTimes(1);
|
||||
|
@ -702,6 +754,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
testWithPointerType('pointer move outside target', pointerType => {
|
||||
componentInit();
|
||||
const downTarget = createEventTarget(ref.current);
|
||||
const upTarget = createEventTarget(container);
|
||||
tapAndMoveOutside({
|
||||
|
@ -712,12 +765,13 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
expect(onTapChange).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('onTapCancel', () => {
|
||||
let onTapCancel, onTapUpdate, parentRef, ref, siblingRef;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
onTapCancel = jest.fn();
|
||||
onTapUpdate = jest.fn();
|
||||
parentRef = React.createRef();
|
||||
|
@ -733,9 +787,13 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
);
|
||||
};
|
||||
ReactDOM.render(<Component />, container);
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: Get rid of this condition somehow. Perhaps with a dynamic verion of
|
||||
// the @gate pragma.
|
||||
if (__EXPERIMENTAL__) {
|
||||
testWithPointerType('pointer cancel', pointerType => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown({pointerType});
|
||||
target.pointercancel({pointerType});
|
||||
|
@ -768,8 +826,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
target.pointermove({pointerType, x: 5, y: 5});
|
||||
expect(onTapUpdate).not.toBeCalled();
|
||||
});
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
test('second pointer on target', () => {
|
||||
componentInit();
|
||||
const pointerType = 'touch';
|
||||
const target = createEventTarget(ref.current);
|
||||
const button = buttonType.primary;
|
||||
|
@ -780,7 +841,9 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
if (hasPointerEvents) {
|
||||
// @gate experimental
|
||||
test('second pointer off target', () => {
|
||||
componentInit();
|
||||
const pointerType = 'touch';
|
||||
const target = createEventTarget(ref.current);
|
||||
const offTarget = createEventTarget(container);
|
||||
|
@ -792,7 +855,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
}
|
||||
|
||||
// TODO: Get rid of this condition somehow. Perhaps with a dynamic verion of
|
||||
// the @gate pragma.
|
||||
if (__EXPERIMENTAL__) {
|
||||
testWithPointerType('pointer move outside target', pointerType => {
|
||||
componentInit();
|
||||
const downTarget = createEventTarget(ref.current);
|
||||
const upTarget = createEventTarget(container);
|
||||
tapAndMoveOutside({
|
||||
|
@ -803,8 +870,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
expect(onTapCancel).toBeCalled();
|
||||
});
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
test('ignored modifiers', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const button = buttonType.primary;
|
||||
const buttons = buttonsType.primary;
|
||||
|
@ -824,13 +894,17 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
expect(onTapCancel).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('long press context menu', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.contextmenu({}, {pointerType: 'touch'});
|
||||
expect(onTapCancel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('parent scroll (non-mouse)', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const parentTarget = createEventTarget(parentRef.current);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
|
@ -838,7 +912,9 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
expect(onTapCancel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('sibling scroll', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const siblingTarget = createEventTarget(siblingRef.current);
|
||||
target.pointerdown();
|
||||
|
@ -846,7 +922,9 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
expect(onTapCancel).not.toBeCalled();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('document scroll (non-mouse)', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const documentTarget = createEventTarget(document);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
|
@ -855,7 +933,9 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
});
|
||||
|
||||
// Scroll on an element not managed by React
|
||||
// @gate experimental
|
||||
test('root container scroll (non-mouse)', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
const containerTarget = createEventTarget(container);
|
||||
target.pointerdown({pointerType: 'touch'});
|
||||
|
@ -867,7 +947,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
describe('preventDefault', () => {
|
||||
let onTapEnd, ref, innerRef, preventDefault, remount;
|
||||
|
||||
beforeEach(() => {
|
||||
const componentInit = () => {
|
||||
remount = function(shouldPreventDefault) {
|
||||
onTapEnd = jest.fn();
|
||||
preventDefault = jest.fn();
|
||||
|
@ -887,9 +967,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
ReactDOM.render(<Component />, container);
|
||||
};
|
||||
remount();
|
||||
});
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
test('prevents native behavior by default', () => {
|
||||
componentInit();
|
||||
const target = createEventTarget(ref.current);
|
||||
target.pointerdown();
|
||||
target.pointerup({preventDefault});
|
||||
|
@ -899,7 +981,9 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('prevents native behaviour by default (inner target)', () => {
|
||||
componentInit();
|
||||
const innerTarget = createEventTarget(innerRef.current);
|
||||
innerTarget.pointerdown();
|
||||
innerTarget.pointerup({preventDefault});
|
||||
|
@ -909,7 +993,9 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
test('allows native behaviour if false', () => {
|
||||
componentInit();
|
||||
remount(false);
|
||||
|
||||
const target = createEventTarget(ref.current);
|
||||
|
|
|
@ -24,6 +24,7 @@ export const {
|
|||
getOrCreateRootContainer,
|
||||
createRoot,
|
||||
createBlockingRoot,
|
||||
createLegacyRoot,
|
||||
getChildrenAsJSX,
|
||||
getPendingChildrenAsJSX,
|
||||
createPortal,
|
||||
|
|
|
@ -50,16 +50,12 @@ function initReactDOMServer() {
|
|||
}
|
||||
|
||||
describe('ReactFiberFundamental', () => {
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
describe('NoopRenderer', () => {
|
||||
beforeEach(() => {
|
||||
initNoopRenderer();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should render a simple fundamental component with a single child', () => {
|
||||
const FundamentalComponent = createReactFundamentalComponent({
|
||||
reconcileChildren: true,
|
||||
|
@ -94,6 +90,7 @@ describe('ReactFiberFundamental', () => {
|
|||
initTestRenderer();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should render a simple fundamental component with a single child', () => {
|
||||
const FundamentalComponent = createReactFundamentalComponent({
|
||||
reconcileChildren: true,
|
||||
|
@ -130,6 +127,7 @@ describe('ReactFiberFundamental', () => {
|
|||
initReactDOM();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should render a simple fundamental component with a single child', () => {
|
||||
const FundamentalComponent = createReactFundamentalComponent({
|
||||
reconcileChildren: true,
|
||||
|
@ -155,6 +153,7 @@ describe('ReactFiberFundamental', () => {
|
|||
expect(container.innerHTML).toBe('');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should render a simple fundamental component without reconcileChildren', () => {
|
||||
const FundamentalComponent = createReactFundamentalComponent({
|
||||
reconcileChildren: false,
|
||||
|
@ -186,6 +185,7 @@ describe('ReactFiberFundamental', () => {
|
|||
initReactDOMServer();
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should render a simple fundamental component with a single child', () => {
|
||||
const getInstance = jest.fn();
|
||||
const FundamentalComponent = createReactFundamentalComponent({
|
||||
|
@ -210,6 +210,7 @@ describe('ReactFiberFundamental', () => {
|
|||
expect(output).toBe('<div>Hello world again</div>');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should render a simple fundamental component without reconcileChildren', () => {
|
||||
const FundamentalComponent = createReactFundamentalComponent({
|
||||
reconcileChildren: false,
|
||||
|
|
|
@ -1121,12 +1121,7 @@ describe('ReactHooksWithNoopRenderer', () => {
|
|||
},
|
||||
);
|
||||
|
||||
if (
|
||||
require('shared/ReactFeatureFlags')
|
||||
.deferPassiveEffectCleanupDuringUnmount &&
|
||||
require('shared/ReactFeatureFlags')
|
||||
.runAllPassiveEffectDestroysBeforeCreates
|
||||
) {
|
||||
// @gate deferPassiveEffectCleanupDuringUnmount && runAllPassiveEffectDestroysBeforeCreates
|
||||
it('defers passive effect destroy functions during unmount', () => {
|
||||
function Child({bar, foo}) {
|
||||
React.useEffect(() => {
|
||||
|
@ -1211,6 +1206,7 @@ describe('ReactHooksWithNoopRenderer', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate deferPassiveEffectCleanupDuringUnmount && runAllPassiveEffectDestroysBeforeCreates
|
||||
it('does not warn about state updates for unmounted components with pending passive unmounts', () => {
|
||||
let completePendingRequest = null;
|
||||
function Component() {
|
||||
|
@ -1258,7 +1254,7 @@ describe('ReactHooksWithNoopRenderer', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('still warns about state updates for unmounted components with no pending passive unmounts', () => {
|
||||
it('warns about state updates for unmounted components with no pending passive unmounts', () => {
|
||||
let completePendingRequest = null;
|
||||
function Component() {
|
||||
Scheduler.unstable_yieldValue('Component');
|
||||
|
@ -1295,6 +1291,7 @@ describe('ReactHooksWithNoopRenderer', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate deferPassiveEffectCleanupDuringUnmount && runAllPassiveEffectDestroysBeforeCreates
|
||||
it('still warns if there are pending passive unmount effects but not for the current fiber', () => {
|
||||
let completePendingRequest = null;
|
||||
function ComponentWithXHR() {
|
||||
|
@ -1355,7 +1352,7 @@ describe('ReactHooksWithNoopRenderer', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('still warns if there are updates after pending passive unmount effects have been flushed', () => {
|
||||
it('warns if there are updates after pending passive unmount effects have been flushed', () => {
|
||||
let updaterFunction;
|
||||
|
||||
function Component() {
|
||||
|
@ -1498,7 +1495,6 @@ describe('ReactHooksWithNoopRenderer', () => {
|
|||
expect(Scheduler).toFlushAndYield(['Child passive destroy']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it('updates have async priority', () => {
|
||||
function Counter(props) {
|
||||
|
|
|
@ -26,11 +26,6 @@ describe('ReactScope', () => {
|
|||
Scheduler = require('scheduler');
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
describe('ReactDOM', () => {
|
||||
let ReactDOM;
|
||||
let container;
|
||||
|
@ -47,6 +42,7 @@ describe('ReactScope', () => {
|
|||
container = null;
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('DO_NOT_USE_queryAllNodes() works as intended', () => {
|
||||
const testScopeQuery = (type, props) => true;
|
||||
const TestScope = React.unstable_createScope();
|
||||
|
@ -81,6 +77,7 @@ describe('ReactScope', () => {
|
|||
expect(scopeRef.current).toBe(null);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('DO_NOT_USE_queryAllNodes() provides the correct host instance', () => {
|
||||
const testScopeQuery = (type, props) => type === 'div';
|
||||
const TestScope = React.unstable_createScope();
|
||||
|
@ -127,6 +124,7 @@ describe('ReactScope', () => {
|
|||
expect(scopeRef.current).toBe(null);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('DO_NOT_USE_queryFirstNode() works as intended', () => {
|
||||
const testScopeQuery = (type, props) => true;
|
||||
const TestScope = React.unstable_createScope();
|
||||
|
@ -161,6 +159,7 @@ describe('ReactScope', () => {
|
|||
expect(scopeRef.current).toBe(null);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('containsNode() works as intended', () => {
|
||||
const TestScope = React.unstable_createScope();
|
||||
const scopeRef = React.createRef();
|
||||
|
@ -210,6 +209,7 @@ describe('ReactScope', () => {
|
|||
expect(scopeRef.current.containsNode(emRef.current)).toBe(false);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('scopes support server-side rendering and hydration', () => {
|
||||
const TestScope = React.unstable_createScope();
|
||||
const scopeRef = React.createRef();
|
||||
|
@ -240,6 +240,7 @@ describe('ReactScope', () => {
|
|||
expect(nodes).toEqual([divRef.current, spanRef.current, aRef.current]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('event responders can be attached to scopes', () => {
|
||||
let onKeyDown = jest.fn();
|
||||
const TestScope = React.unstable_createScope();
|
||||
|
@ -282,6 +283,7 @@ describe('ReactScope', () => {
|
|||
expect(onKeyDown).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('getChildContextValues() works as intended', () => {
|
||||
const TestContext = React.createContext();
|
||||
const TestScope = React.unstable_createScope();
|
||||
|
@ -310,6 +312,7 @@ describe('ReactScope', () => {
|
|||
expect(scopeRef.current).toBe(null);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('correctly works with suspended boundaries that are hydrated', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
|
@ -384,6 +387,7 @@ describe('ReactScope', () => {
|
|||
ReactTestRenderer = require('react-test-renderer');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('DO_NOT_USE_queryAllNodes() works as intended', () => {
|
||||
const testScopeQuery = (type, props) => true;
|
||||
const TestScope = React.unstable_createScope();
|
||||
|
@ -420,6 +424,7 @@ describe('ReactScope', () => {
|
|||
expect(nodes).toEqual([aRef.current, divRef.current, spanRef.current]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('DO_NOT_USE_queryFirstNode() works as intended', () => {
|
||||
const testScopeQuery = (type, props) => true;
|
||||
const TestScope = React.unstable_createScope();
|
||||
|
@ -456,6 +461,7 @@ describe('ReactScope', () => {
|
|||
expect(node).toEqual(aRef.current);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('containsNode() works as intended', () => {
|
||||
const TestScope = React.unstable_createScope();
|
||||
const scopeRef = React.createRef();
|
||||
|
|
|
@ -6,11 +6,6 @@ let Suspense;
|
|||
let SuspenseList;
|
||||
|
||||
describe('ReactSuspenseList', () => {
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
|
@ -47,6 +42,7 @@ describe('ReactSuspenseList', () => {
|
|||
return Component;
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('warns if an unsupported revealOrder option is used', () => {
|
||||
function Foo() {
|
||||
return (
|
||||
|
@ -66,6 +62,7 @@ describe('ReactSuspenseList', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('warns if a upper case revealOrder option is used', () => {
|
||||
function Foo() {
|
||||
return (
|
||||
|
@ -85,6 +82,7 @@ describe('ReactSuspenseList', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('warns if a misspelled revealOrder option is used', () => {
|
||||
function Foo() {
|
||||
return (
|
||||
|
@ -105,6 +103,7 @@ describe('ReactSuspenseList', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('warns if a single element is passed to a "forwards" list', () => {
|
||||
function Foo({children}) {
|
||||
return <SuspenseList revealOrder="forwards">{children}</SuspenseList>;
|
||||
|
@ -137,6 +136,7 @@ describe('ReactSuspenseList', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('warns if a single fragment is passed to a "backwards" list', () => {
|
||||
function Foo() {
|
||||
return (
|
||||
|
@ -157,6 +157,7 @@ describe('ReactSuspenseList', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('warns if a nested array is passed to a "forwards" list', () => {
|
||||
function Foo({items}) {
|
||||
return (
|
||||
|
@ -184,6 +185,7 @@ describe('ReactSuspenseList', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('shows content independently by default', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -250,6 +252,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('shows content independently in legacy mode regardless of option', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -322,6 +325,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('displays all "together"', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -391,6 +395,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('displays all "together" even when nested as siblings', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -476,6 +481,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('displays all "together" in nested SuspenseLists', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -537,6 +543,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('displays all "together" in nested SuspenseLists where the inner is default', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -596,6 +603,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('displays all "together" during an update', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -680,6 +688,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('avoided boundaries can be coordinate with SuspenseList', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -778,6 +787,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('displays each items in "forwards" order', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -843,6 +853,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('displays each items in "backwards" order', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -908,6 +919,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('displays added row at the top "together" and the bottom in "forwards" order', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -1062,6 +1074,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('displays added row at the top "together" and the bottom in "backwards" order', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -1246,6 +1259,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('switches to rendering fallbacks if the tail takes long CPU time', async () => {
|
||||
function Foo() {
|
||||
return (
|
||||
|
@ -1308,6 +1322,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('only shows one loading state at a time for "collapsed" tail insertions', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -1377,6 +1392,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('warns if an unsupported tail option is used', () => {
|
||||
function Foo() {
|
||||
return (
|
||||
|
@ -1397,6 +1413,7 @@ describe('ReactSuspenseList', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('warns if a tail option is used with "together"', () => {
|
||||
function Foo() {
|
||||
return (
|
||||
|
@ -1417,6 +1434,7 @@ describe('ReactSuspenseList', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('renders one "collapsed" fallback even if CPU time elapsed', async () => {
|
||||
function Foo() {
|
||||
return (
|
||||
|
@ -1483,6 +1501,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('adding to the middle does not collapse insertions (forwards)', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -1625,6 +1644,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('adding to the middle does not collapse insertions (backwards)', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -1772,6 +1792,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('adding to the middle of committed tail does not collapse insertions', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -1929,6 +1950,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('only shows no initial loading state "hidden" tail insertions', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
@ -1992,6 +2014,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('eventually resolves a nested forwards suspense list', async () => {
|
||||
const B = createAsyncText('B');
|
||||
|
||||
|
@ -2054,6 +2077,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('eventually resolves a nested forwards suspense list with a hidden tail', async () => {
|
||||
const B = createAsyncText('B');
|
||||
|
||||
|
@ -2100,6 +2124,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('eventually resolves two nested forwards suspense lists with a hidden tail', async () => {
|
||||
const B = createAsyncText('B');
|
||||
|
||||
|
@ -2167,6 +2192,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can do unrelated adjacent updates', async () => {
|
||||
let updateAdjacent;
|
||||
function Adjacent() {
|
||||
|
@ -2213,6 +2239,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is able to re-suspend the last rows during an update with hidden', async () => {
|
||||
const AsyncB = createAsyncText('B');
|
||||
|
||||
|
@ -2301,6 +2328,7 @@ describe('ReactSuspenseList', () => {
|
|||
expect(previousInst).toBe(setAsyncB);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is able to re-suspend the last rows during an update with hidden', async () => {
|
||||
const AsyncB = createAsyncText('B');
|
||||
|
||||
|
@ -2389,6 +2417,7 @@ describe('ReactSuspenseList', () => {
|
|||
expect(previousInst).toBe(setAsyncB);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('is able to interrupt a partially rendered tree and continue later', async () => {
|
||||
const AsyncA = createAsyncText('A');
|
||||
|
||||
|
@ -2486,6 +2515,7 @@ describe('ReactSuspenseList', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('can resume class components when revealed together', async () => {
|
||||
const A = createAsyncText('A');
|
||||
const B = createAsyncText('B');
|
||||
|
|
|
@ -11,11 +11,6 @@ let resolveText;
|
|||
let rejectText;
|
||||
|
||||
describe('ReactSuspenseWithNoopRenderer', () => {
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
|
@ -922,6 +917,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
expect(ReactNoop.getChildren()).toEqual([span('Async')]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('starts working on an update even if its priority falls between two suspended levels', async () => {
|
||||
function App(props) {
|
||||
return (
|
||||
|
@ -2331,6 +2327,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
timeoutMs: 2000,
|
||||
};
|
||||
|
||||
// @gate experimental
|
||||
it('top level render', async () => {
|
||||
function App({page}) {
|
||||
return (
|
||||
|
@ -2385,6 +2382,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
expect(ReactNoop.getChildren()).toEqual([span('B')]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('hooks', async () => {
|
||||
let transitionToPage;
|
||||
function App() {
|
||||
|
@ -2452,6 +2450,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
expect(ReactNoop.getChildren()).toEqual([span('B')]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('classes', async () => {
|
||||
let transitionToPage;
|
||||
class App extends React.Component {
|
||||
|
@ -2523,6 +2522,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('disables suspense config when nothing is passed to withSuspenseConfig', async () => {
|
||||
function App({page}) {
|
||||
return (
|
||||
|
@ -2597,6 +2597,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('withSuspenseConfig timeout applies when we use an updated avoided boundary', async () => {
|
||||
function App({page}) {
|
||||
return (
|
||||
|
@ -2645,6 +2646,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('withSuspenseConfig timeout applies when we use a newly created avoided boundary', async () => {
|
||||
function App({page}) {
|
||||
return (
|
||||
|
@ -2692,6 +2694,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('supports delaying a busy spinner from disappearing', async () => {
|
||||
const SUSPENSE_CONFIG = {
|
||||
timeoutMs: 10000,
|
||||
|
@ -2854,6 +2857,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
expect(root).toMatchRenderedOutput(<span prop="Foo" />);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not render hidden content while suspended on higher pri', async () => {
|
||||
function Offscreen() {
|
||||
Scheduler.unstable_yieldValue('Offscreen');
|
||||
|
@ -2908,6 +2912,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should be able to unblock higher pri content before suspended hidden', async () => {
|
||||
function Offscreen() {
|
||||
Scheduler.unstable_yieldValue('Offscreen');
|
||||
|
@ -3624,6 +3629,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('regression: ping at high priority causes update to be dropped', async () => {
|
||||
const {useState, useTransition} = React;
|
||||
|
||||
|
|
|
@ -140,11 +140,9 @@ describe('useMutableSource', () => {
|
|||
return <div>{`${label}:${snapshot}`}</div>;
|
||||
}
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
} else {
|
||||
beforeEach(loadModules);
|
||||
|
||||
// @gate experimental
|
||||
it('should subscribe to a source and schedule updates when it changes', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -212,6 +210,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should restart work if a new source is mutated during render', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -246,6 +245,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should schedule an update if a new source is mutated between render and commit (subscription)', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -285,6 +285,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should unsubscribe and resubscribe if a new source is used', () => {
|
||||
const sourceA = createSource('a-one');
|
||||
const mutableSourceA = createMutableSource(sourceA);
|
||||
|
@ -335,6 +336,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should unsubscribe and resubscribe if a new subscribe function is provided', () => {
|
||||
const source = createSource('a-one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -399,6 +401,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should re-use previously read snapshot value when reading is unsafe', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -455,6 +458,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should read from source on newly mounted subtree if no pending updates are scheduled for source', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -494,6 +498,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should throw and restart render if source and snapshot are unavailable during an update', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -521,13 +526,10 @@ describe('useMutableSource', () => {
|
|||
|
||||
// Changing values should schedule an update with React.
|
||||
// Start working on this update but don't finish it.
|
||||
Scheduler.unstable_runWithPriority(
|
||||
Scheduler.unstable_LowPriority,
|
||||
() => {
|
||||
Scheduler.unstable_runWithPriority(Scheduler.unstable_LowPriority, () => {
|
||||
source.value = 'two';
|
||||
expect(Scheduler).toFlushAndYieldThrough(['a:two']);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
const newGetSnapshot = s => 'new:' + defaultGetSnapshot(s);
|
||||
|
||||
|
@ -563,6 +565,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should throw and restart render if source and snapshot are unavailable during a sync update', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -590,13 +593,10 @@ describe('useMutableSource', () => {
|
|||
|
||||
// Changing values should schedule an update with React.
|
||||
// Start working on this update but don't finish it.
|
||||
Scheduler.unstable_runWithPriority(
|
||||
Scheduler.unstable_LowPriority,
|
||||
() => {
|
||||
Scheduler.unstable_runWithPriority(Scheduler.unstable_LowPriority, () => {
|
||||
source.value = 'two';
|
||||
expect(Scheduler).toFlushAndYieldThrough(['a:two']);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
const newGetSnapshot = s => 'new:' + defaultGetSnapshot(s);
|
||||
|
||||
|
@ -629,6 +629,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should only update components whose subscriptions fire', () => {
|
||||
const source = createComplexSource('a:one', 'b:one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -657,11 +658,7 @@ describe('useMutableSource', () => {
|
|||
</>,
|
||||
() => Scheduler.unstable_yieldValue('Sync effect'),
|
||||
);
|
||||
expect(Scheduler).toFlushAndYield([
|
||||
'a:a:one',
|
||||
'b:b:one',
|
||||
'Sync effect',
|
||||
]);
|
||||
expect(Scheduler).toFlushAndYield(['a:a:one', 'b:b:one', 'Sync effect']);
|
||||
|
||||
// Changes to part of the store (e.g. A) should not render other parts.
|
||||
source.valueA = 'a:two';
|
||||
|
@ -671,6 +668,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should detect tearing in part of the store not yet subscribed to', () => {
|
||||
const source = createComplexSource('a:one', 'b:one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -735,6 +733,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('does not schedule an update for subscriptions that fire with an unchanged snapshot', () => {
|
||||
const MockComponent = jest.fn(Component);
|
||||
|
||||
|
@ -761,6 +760,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should throw and restart if getSnapshot changes between scheduled update and re-render', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -790,12 +790,9 @@ describe('useMutableSource', () => {
|
|||
ReactNoop.flushPassiveEffects();
|
||||
|
||||
// Change the source (and schedule an update).
|
||||
Scheduler.unstable_runWithPriority(
|
||||
Scheduler.unstable_LowPriority,
|
||||
() => {
|
||||
Scheduler.unstable_runWithPriority(Scheduler.unstable_LowPriority, () => {
|
||||
source.value = 'two';
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// Schedule a higher priority update that changes getSnapshot.
|
||||
Scheduler.unstable_runWithPriority(
|
||||
|
@ -809,6 +806,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should recover from a mutation during yield when other work is scheduled', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -842,6 +840,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not throw if the new getSnapshot returns the same snapshot value', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -896,6 +895,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not throw if getSnapshot changes but the source can be safely read from anyway', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -935,6 +935,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should still schedule an update if an eager selector throws after a mutation', () => {
|
||||
const source = createSource({
|
||||
friends: [
|
||||
|
@ -1001,6 +1002,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not warn about updates that fire between unmount and passive unsubcribe', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -1037,6 +1039,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should support inline selectors and updates that are processed after selector change', async () => {
|
||||
const source = createSource({
|
||||
a: 'initial',
|
||||
|
@ -1081,6 +1084,7 @@ describe('useMutableSource', () => {
|
|||
expect(root).toMatchRenderedOutput('Another update');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should clear the update queue when getSnapshot changes with pending lower priority updates', async () => {
|
||||
const source = createSource({
|
||||
a: 'initial',
|
||||
|
@ -1137,6 +1141,7 @@ describe('useMutableSource', () => {
|
|||
expect(root).toMatchRenderedOutput('B: Update');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should clear the update queue when source changes with pending lower priority updates', async () => {
|
||||
const sourceA = createSource('initial');
|
||||
const sourceB = createSource('initial');
|
||||
|
@ -1175,6 +1180,7 @@ describe('useMutableSource', () => {
|
|||
expect(root).toMatchRenderedOutput('B: Update');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should always treat reading as potentially unsafe when getSnapshot changes between renders', async () => {
|
||||
const source = createSource({
|
||||
a: 'foo',
|
||||
|
@ -1264,6 +1270,7 @@ describe('useMutableSource', () => {
|
|||
expect(Scheduler).toHaveYielded(['x: bar, y: bar']);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('getSnapshot changes and then source is mutated in between paint and passive effect phase', async () => {
|
||||
const source = createSource({
|
||||
a: 'foo',
|
||||
|
@ -1322,6 +1329,7 @@ describe('useMutableSource', () => {
|
|||
expect(root).toMatchRenderedOutput('baz');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('getSnapshot changes and then source is mutated in between paint and passive effect phase, case 2', async () => {
|
||||
const source = createSource({
|
||||
a: 'a0',
|
||||
|
@ -1391,6 +1399,7 @@ describe('useMutableSource', () => {
|
|||
expect(root.getChildrenAsJSX()).toEqual('first: a1, second: a1');
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('getSnapshot changes and then source is mutated during interleaved event', async () => {
|
||||
const {useEffect} = React;
|
||||
|
||||
|
@ -1456,11 +1465,7 @@ describe('useMutableSource', () => {
|
|||
await act(async () => {
|
||||
root.render(<App parentConfig={configA} childConfig={configB} />);
|
||||
});
|
||||
expect(Scheduler).toHaveYielded([
|
||||
'Parent: 1',
|
||||
'Child: 2',
|
||||
'Commit: 1, 2',
|
||||
]);
|
||||
expect(Scheduler).toHaveYielded(['Parent: 1', 'Child: 2', 'Commit: 1, 2']);
|
||||
|
||||
await act(async () => {
|
||||
// Switch the parent and the child to read using the same config
|
||||
|
@ -1494,6 +1499,7 @@ describe('useMutableSource', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should not tear with newly mounted component when updates were scheduled at a lower priority', async () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -1576,6 +1582,7 @@ describe('useMutableSource', () => {
|
|||
|
||||
if (__DEV__) {
|
||||
describe('dev warnings', () => {
|
||||
// @gate experimental
|
||||
it('should warn if the subscribe function does not return an unsubscribe function', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -1598,6 +1605,7 @@ describe('useMutableSource', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should error if multiple renderers of the same type use a mutable source at the same time', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -1654,6 +1662,7 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should error if multiple renderers of the same type use a mutable source at the same time with mutation between', () => {
|
||||
const source = createSource('one');
|
||||
const mutableSource = createMutableSource(source);
|
||||
|
@ -1714,5 +1723,4 @@ describe('useMutableSource', () => {
|
|||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -62,13 +62,9 @@ describe('ReactDOMTracing', () => {
|
|||
loadModules();
|
||||
});
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
describe('interaction tracing', () => {
|
||||
describe('hidden', () => {
|
||||
// @gate experimental
|
||||
it('traces interaction through hidden subtree', () => {
|
||||
const Child = () => {
|
||||
const [didMount, setDidMount] = React.useState(false);
|
||||
|
@ -145,6 +141,7 @@ describe('ReactDOMTracing', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('traces interaction through hidden subtree when there is other pending traced work', () => {
|
||||
const Child = () => {
|
||||
Scheduler.unstable_yieldValue('Child');
|
||||
|
@ -212,6 +209,7 @@ describe('ReactDOMTracing', () => {
|
|||
).toHaveBeenLastNotifiedOfInteraction(interaction);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('traces interaction through hidden subtree that schedules more idle/never work', () => {
|
||||
const Child = () => {
|
||||
const [didMount, setDidMount] = React.useState(false);
|
||||
|
@ -294,6 +292,7 @@ describe('ReactDOMTracing', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('does not continue interactions across pre-existing idle work', () => {
|
||||
const Child = () => {
|
||||
Scheduler.unstable_yieldValue('Child');
|
||||
|
@ -394,6 +393,7 @@ describe('ReactDOMTracing', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should properly trace interactions when there is work of interleaved priorities', () => {
|
||||
const Child = () => {
|
||||
Scheduler.unstable_yieldValue('Child');
|
||||
|
@ -515,6 +515,7 @@ describe('ReactDOMTracing', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// @gate experimental
|
||||
it('should properly trace interactions through a multi-pass SuspenseList render', () => {
|
||||
const SuspenseList = React.SuspenseList;
|
||||
const Suspense = React.Suspense;
|
||||
|
@ -599,7 +600,8 @@ describe('ReactDOMTracing', () => {
|
|||
});
|
||||
|
||||
describe('hydration', () => {
|
||||
it('traces interaction across hydration', async done => {
|
||||
// @gate experimental
|
||||
it('traces interaction across hydration', () => {
|
||||
const ref = React.createRef();
|
||||
|
||||
function Child() {
|
||||
|
@ -644,11 +646,10 @@ describe('ReactDOMTracing', () => {
|
|||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
).toHaveBeenLastNotifiedOfInteraction(interaction);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('traces interaction across suspended hydration', async done => {
|
||||
// @gate experimental
|
||||
it('traces interaction across suspended hydration', async () => {
|
||||
let suspend = false;
|
||||
let resolve;
|
||||
const promise = new Promise(
|
||||
|
@ -716,11 +717,10 @@ describe('ReactDOMTracing', () => {
|
|||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
).toHaveBeenLastNotifiedOfInteraction(interaction);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('traces interaction across client-rendered hydration', async done => {
|
||||
// @gate experimental
|
||||
it('traces interaction across client-rendered hydration', () => {
|
||||
let suspend = false;
|
||||
const promise = new Promise(() => {});
|
||||
const ref = React.createRef();
|
||||
|
@ -788,8 +788,6 @@ describe('ReactDOMTracing', () => {
|
|||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
).toHaveBeenLastNotifiedOfInteraction(interaction);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -53,11 +53,7 @@ describe('ProfilerDOM', () => {
|
|||
return props.text;
|
||||
}
|
||||
|
||||
if (!__EXPERIMENTAL__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
// @gate experimental
|
||||
it('should correctly trace interactions for async roots', async () => {
|
||||
let resolve;
|
||||
let thenable = {
|
||||
|
|
|
@ -36,9 +36,7 @@ describe('ReactError', () => {
|
|||
}
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
} else {
|
||||
// @gate build === "production"
|
||||
it('should error with minified error code', () => {
|
||||
expect(() => ReactDOM.render('Hi', null)).toThrowError(
|
||||
'Minified React error #200; visit ' +
|
||||
|
@ -47,6 +45,8 @@ describe('ReactError', () => {
|
|||
' for full errors and additional helpful warnings.',
|
||||
);
|
||||
});
|
||||
|
||||
// @gate build === "production"
|
||||
it('should serialize arguments', () => {
|
||||
function Oops() {
|
||||
return;
|
||||
|
@ -60,5 +60,4 @@ describe('ReactError', () => {
|
|||
' for full errors and additional helpful warnings.',
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
let React;
|
||||
let ReactDOM;
|
||||
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
|
||||
describe('Component stack trace displaying', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -19,11 +18,7 @@ describe('Component stack trace displaying', () => {
|
|||
ReactDOM = require('react-dom');
|
||||
});
|
||||
|
||||
if (ReactFeatureFlags.enableComponentStackLocations) {
|
||||
it("empty test so Jest doesn't complain", () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
// @gate !enableComponentStackLocations || !__DEV__
|
||||
it('should provide filenames in stack traces', () => {
|
||||
class Component extends React.Component {
|
||||
render() {
|
||||
|
|
|
@ -35,7 +35,11 @@
|
|||
const environmentFlags = {
|
||||
__DEV__,
|
||||
build: __DEV__ ? 'development' : 'production',
|
||||
|
||||
// TODO: Should "experimental" also imply "modern"? Maybe we should
|
||||
// always compare to the channel?
|
||||
experimental: __EXPERIMENTAL__,
|
||||
// Similarly, should stable imply "classic"?
|
||||
stable: !__EXPERIMENTAL__,
|
||||
};
|
||||
|
||||
|
@ -44,6 +48,18 @@ function getTestFlags() {
|
|||
// not to but there are exceptions.
|
||||
const featureFlags = require('shared/ReactFeatureFlags');
|
||||
|
||||
// TODO: This is a heuristic to detect the release channel by checking a flag
|
||||
// that is known to only be enabled in www. What we should do instead is set
|
||||
// the release channel explicitly in the each test config file.
|
||||
const www = featureFlags.enableSuspenseCallback === true;
|
||||
const releaseChannel = www
|
||||
? __EXPERIMENTAL__
|
||||
? 'modern'
|
||||
: 'classic'
|
||||
: __EXPERIMENTAL__
|
||||
? 'experimental'
|
||||
: 'stable';
|
||||
|
||||
// Return a proxy so we can throw if you attempt to access a flag that
|
||||
// doesn't exist.
|
||||
return new Proxy(
|
||||
|
@ -52,6 +68,11 @@ function getTestFlags() {
|
|||
old: featureFlags.enableNewReconciler === true,
|
||||
new: featureFlags.enableNewReconciler === true,
|
||||
|
||||
channel: releaseChannel,
|
||||
modern: releaseChannel === 'modern',
|
||||
classic: releaseChannel === 'classic',
|
||||
www,
|
||||
|
||||
...featureFlags,
|
||||
...environmentFlags,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue