Skip to content

Commit

Permalink
Merge branch '2.x' of https://github.com/open-amdocs/webrix into 2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
Yair Even Or authored and Yair Even Or committed Jan 29, 2023
2 parents 7131f27 + 7fc049e commit e189aee
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 44 deletions.
14 changes: 12 additions & 2 deletions src/components/Movable/Movable.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {NAMESPACE} from './Movable';
import Movable from './';

describe('<Movable/>', () => {
const _addEventListener = document.addEventListener;

describe('HTML structure', () => {
it('should render a Movable', () => {
Expand All @@ -23,16 +24,19 @@ describe('<Movable/>', () => {
const preventDefault = sinon.spy();
const wrapper = mount(<Movable onBeginMove={handleOnBeginMove}/>);

document.addEventListener = sinon.spy();
const addEventListenerSpy = sinon.spy(document, 'addEventListener');

wrapper.simulate('mousedown', {stopPropagation, preventDefault});
expect(handleOnBeginMove.calledOnce).toEqual(true);
expect(document.addEventListener.callCount).toEqual(2);
expect(addEventListenerSpy.callCount).toEqual(2);

const event = handleOnBeginMove.args[0][0];
event.stopPropagation();
event.preventDefault();
expect(stopPropagation.calledOnce).toEqual(true);
expect(preventDefault.calledOnce).toEqual(true);

addEventListenerSpy.restore();
});

it('onMove()', () => {
Expand All @@ -41,7 +45,9 @@ describe('<Movable/>', () => {
const handlers = {};
let event;

const _addEventListener = document.addEventListener;
document.addEventListener = (type, handler) => {handlers[type] = handler};

wrapper.simulate('mousedown', {clientX: 10, clientY: 10});
wrapper.simulate('touchstart', {changedTouches: [{clientX: 10, clientY: 10}]});

Expand Down Expand Up @@ -80,6 +86,8 @@ describe('<Movable/>', () => {
expect(event.cy).toEqual(-30);
expect(event.dx).toEqual(-10);
expect(event.dy).toEqual(-10);

document.addEventListener = _addEventListener;
});

it('onEndMove()', () => {
Expand All @@ -102,6 +110,8 @@ describe('<Movable/>', () => {
expect(event.cy).toEqual(10);
expect(event.dx).toEqual(10);
expect(event.dy).toEqual(10);

document.addEventListener = _addEventListener;
});
});

Expand Down
37 changes: 35 additions & 2 deletions src/components/Poppable/Poppable.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React from 'react';
import sinon from 'sinon';
import {mount} from 'enzyme';
import Poppable, {NAMESPACE} from './Poppable';
import PoppableStateful from './Poppable.stateful';
import defaultStrategy, {reposition, hide, trap} from './strategies';
import {sortPlacements, filterPlacements} from './strategies/reposition';
import {usePosition} from './Poppable.hooks';
import {getBoundingRects} from './Poppable.utils';
import {vbefore, vcenter, vafter, hbefore, hcenter, hafter} from './Poppable.placements';
import {HIDDEN_PLACEMENT} from './Poppable.constants';
Expand All @@ -19,9 +22,39 @@ describe('<Poppable/>', () => {
});
});

describe('Stateful', () => {
it('should render a stateful Poppable', () => {
const wrapper = mount(<PoppableStateful/>);
expect(wrapper.find('.' + NAMESPACE).hostNodes()).toHaveLength(1);
});
});

describe('Hooks', () => {
it.todo('updatePosition()');
it.todo('usePositioning()');
global.window.requestAnimationFrame.resetHistory();

const Elem = (props) => {
usePosition(props);
return null;
};

describe('usePosition', () => {
const props = {
target: new DOMRect(10, 10),
container: new DOMRect(),
reference: new DOMRect(30, 30),
placements: () => [{top: 0, left: 0}],
default: 0,
onPlacement: sinon.spy(),
strategy: defaultStrategy,
};

mount(<Elem {...props}/>);

const lastCall = global.window.requestAnimationFrame.lastCall;
lastCall.args[0]();

expect(props.onPlacement.calledWith({top: 0, left: 0, name: 'hidden'})).toEqual(true);
});
});

describe('Utils', () => {
Expand Down
5 changes: 2 additions & 3 deletions src/components/Resizable/Resizable.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@ describe('<Resizable>', () => {
});
});
describe('Methods', () => {
let addEventListener;
const _addEventListener = document.addEventListener;
const events = {};

beforeAll(() => {
addEventListener = document.addEventListener;
document.addEventListener = (type, callback) => events[type] = callback;
});

afterAll(() => {
document.addEventListener = addEventListener;
document.addEventListener = _addEventListener;
});

it('onBeginResize onResize onEndResize', () => {
Expand Down
71 changes: 61 additions & 10 deletions src/hooks/useClickOutside/useClickOutside.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,82 @@ import sinon from 'sinon';
import {mount} from 'enzyme';
import {useClickOutside} from './useClickOutside';

const Elem = callback => {
useClickOutside(callback);
let clickInsideHandler;
const Elem = ({callback}) => {
clickInsideHandler = useClickOutside(callback);
return <div/>;
};

describe('useClickOutside()', () => {
it('Should add an event listener to the document', () => {
document.addEventListener = sinon.spy();
document.removeEventListener = sinon.spy();
const addEventListenerSpy = sinon.spy(document, 'addEventListener');
const removeEventListenerSpy = sinon.spy(document, 'removeEventListener');

let elem;
act(() => {elem = mount(<Elem/>)});
expect(document.addEventListener.callCount).toEqual(4); // 2 calls are done regardless, not sure why, but it only happens during testing
expect(document.addEventListener.calledWith('mousedown')).toEqual(true);
expect(document.addEventListener.calledWith('mouseup')).toEqual(true);

expect(addEventListenerSpy.callCount).toEqual(4); // 2 calls are done regardless, not sure why, but it only happens during testing
expect(addEventListenerSpy.calledWith('mousedown')).toEqual(true);
expect(addEventListenerSpy.calledWith('mouseup')).toEqual(true);

act(() => {elem.unmount()});
expect(document.removeEventListener.calledTwice).toEqual(true);
expect(document.removeEventListener.calledWith('mousedown')).toEqual(true);
expect(document.removeEventListener.calledWith('mouseup')).toEqual(true);
expect(removeEventListenerSpy.calledTwice).toEqual(true);
expect(removeEventListenerSpy.calledWith('mousedown')).toEqual(true);
expect(removeEventListenerSpy.calledWith('mouseup')).toEqual(true);

addEventListenerSpy.restore();
removeEventListenerSpy.restore();
});

it('Should not trigger the callback on click inside', () => {
const callback = sinon.spy();
const elem = mount(<Elem callback={callback}/>);

expect(elem.find('div'));
elem.simulate('click');
expect(callback.callCount).toEqual(0);
});

it('Should trigger the "click outside" callback', () => {
const callback = sinon.spy();
const addEventListenerSpy = sinon.spy(document, 'addEventListener');
const removeEventListenerSpy = sinon.spy(document, 'removeEventListener');

mount(<Elem callback={callback}/>);

const mousedownCall = document.addEventListener.getCall(-2);
const mouseupCall = document.addEventListener.getCall(-1);

// manually trigger the mousedown event callback with a fake event
mousedownCall.args[1]({isMouseDown: true});
mouseupCall.args[1]({isMouseUp: true});
expect(callback.callCount).toEqual(1);
expect(callback.calledWith({isMouseUp: true})).toEqual(true);

addEventListenerSpy.restore();
removeEventListenerSpy.restore();
});

it('Should not trigger the "click outside" callback when clicked inside', () => {
const callback = sinon.spy();
const addEventListenerSpy = sinon.spy(document, 'addEventListener');
const removeEventListenerSpy = sinon.spy(document, 'removeEventListener');

mount(<Elem callback={callback}/>);

const mousedownCall = document.addEventListener.getCall(-2);
const mouseupCall = document.addEventListener.getCall(-1);

// 1 - simulate a mousedown event on the "outside"
clickInsideHandler();
// 2 - simulate the internal, global, "mousedown" event
mousedownCall.args[1]({isMouseDown: true});
// 3 - simulate the internal, global, "mouseup" event
mouseupCall.args[1]({isMouseUp: true});

expect(callback.callCount).toEqual(0);

addEventListenerSpy.restore();
removeEventListenerSpy.restore();
});
});
21 changes: 10 additions & 11 deletions src/hooks/useMounted/useMounted.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ import {mount} from 'enzyme';
import {useMounted} from './useMounted';

describe('useMounted()', () => {
it('Should return the previous value', () => {
const Elem = () => {
const mounted = useMounted();
return (
<div className={`${mounted ? '' : 'un'}mounted`}/>
);
};
let mounted;

const Elem = () => {
mounted = useMounted();
return null;
};

it('Should be false on first render cycle and true afterwards', () => {
let wrapper = null;
act(() => {wrapper = mount(<Elem/>)});
expect(wrapper.find('.unmounted').length).toEqual(1);
expect(wrapper.find('.mounted').length).toEqual(0);
expect(mounted).toBeFalsy();
wrapper.setProps({foo: 'bar'}); // Force an update...
expect(wrapper.find('.mounted').length).toEqual(1);
expect(wrapper.find('.unmounted').length).toEqual(0);
expect(mounted).toBeTruthy();
});
});
88 changes: 72 additions & 16 deletions src/hooks/useTimeout/useTimeout.test.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,87 @@
import React, {useState} from 'react';
import React from 'react';
import {act} from 'react-dom/test-utils';
import {mount} from 'enzyme';
import useTimeout from './useTimeout';

const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay));
let spy = 1, stopSpy;

const Elem = () => {
const [classname, setClassname] = useState('first');
const {start} = useTimeout(() => {
setClassname('second');
}, 0);
return (
<div className={classname} onClick={start}/>
);
const Timeout = ({delay, recurring}) => {
const {start, stop} = useTimeout(() => { spy += 1 }, delay, recurring);
start();
stopSpy = stop;
return null;
};

describe('useTimeout()', () => {
it('Should return the previous value', async () => {
beforeEach(() => {
spy = 1;
});

it('Should execute the timeout callback once, when no other prameters specified', async () => {
await act(async () => {
const wrapper = mount(<Timeout />);

expect(spy).toEqual(1);

await waitFor(0); // make sure the timeout has had enough time to fire
wrapper.update();
expect(spy).toEqual(2);
});
});

it('Should execute the timeout callback once', async () => {
await act(async () => {
const DELAY = 100;
const wrapper = mount(<Timeout delay={DELAY}/>);

expect(spy).toEqual(1);

await waitFor(DELAY/2);

// should remain "1" as the timeout has yet to be executed
expect(spy).toEqual(1);

await waitFor(DELAY/2);

wrapper.update();
expect(spy).toEqual(2);
});
});

it('Should not be recurring by default (called only once)', async () => {
await act(async () => {
const wrapper = mount(<Elem/>);
expect(wrapper.find('.first').length).toEqual(1);
expect(wrapper.find('.second').length).toEqual(0);
wrapper.find('.first').simulate('click');
const wrapper = await mount(<Timeout/>);

expect(spy).toEqual(1);

await waitFor(0);
wrapper.update();
expect(wrapper.find('.first').length).toEqual(0);
expect(wrapper.find('.second').length).toEqual(1);
expect(spy).toEqual(2);

// wait some more time to make sure the timeout is not recurring
await waitFor(50);
wrapper.update();
expect(spy).toEqual(2);
});
});

it('Should stop recurring', async () => {
await act(async () => {
const DELAY = 50;
const wrapper = await mount(<Timeout delay={DELAY} recurring={true}/>);

expect(spy).toEqual(1);

await waitFor(DELAY * 3);
wrapper.update();
expect(spy).toEqual(3);

stopSpy();
await waitFor(DELAY * 2);
wrapper.update();
// should remain unchanged since last time
expect(spy).toEqual(3);
});
});
});
Loading

0 comments on commit e189aee

Please sign in to comment.