Socket
Socket
Sign inDemoInstall

rel-events

Package Overview
Dependencies
Maintainers
2
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rel-events - npm Package Compare versions

Comparing version 0.4.0 to 0.4.3

110

__tests__/events.test.js

@@ -15,2 +15,4 @@ // eslint-disable-next-line import/named

expect(TestEvent.listenTo).toEqual([]);
expect(TestEvent.debounce).toEqual(false);
expect(TestEvent.debounceDelay).toEqual(300);

@@ -23,2 +25,4 @@ const mockEvent = jest.fn(() => 'event');

listenTo,
debounce: true,
debounceDelay: 200,
});

@@ -30,2 +34,4 @@ expect(TestEvent.name).toEqual('testEvent');

expect(TestEvent.listenTo).toEqual(listenTo);
expect(TestEvent.debounce).toEqual(true);
expect(TestEvent.debounceDelay).toEqual(200);
});

@@ -47,2 +53,8 @@

it('should throw error when initializing with debounce true and non number duration', async () => {
expect(
() => new Event({ name: 'testEvent', manager: {}, debounce: true, debounceDelay: 'wrong' }),
).toThrow('When debounce is true, debounceDelay needs to be a Number.');
});
it('should throw error when initializing with invalid listenTo param', async () => {

@@ -78,14 +90,42 @@ expect(() => new Event({ name: 'testEvent', manager: {}, listenTo: {} })).toThrow(

it('_dispatch should call toRedux passing data using redux dispatch', async () => {
it('_callRedux should call _formatToRedux passing data using redux dispatch', async () => {
const TestEvent = new Event({ name: 'testEvent', manager: {} });
TestEvent.toRedux = jest.fn();
const data = { test: 'data' };
const reduxDispatch = jest.fn();
TestEvent._dispatch(reduxDispatch)(data);
TestEvent._formatToRedux = jest.fn();
TestEvent.__UNSAFE_reduxDispatch = reduxDispatch;
const data = { test: 'data' };
TestEvent._callRedux(data);
expect(reduxDispatch).toBeCalled();
expect(TestEvent.toRedux).toBeCalledWith({ ...data, shouldDispatch: expect.Function });
expect(TestEvent._formatToRedux).toBeCalledWith({ ...data, shouldDispatch: expect.Function });
});
it('_callRedux should be debounced if Event is initialized with debounce as true', async () => {
const mockedDebounce = jest.fn(() => data => data);
__RewireAPI__.__Rewire__('_debounce', mockedDebounce);
const TestEvent = new Event({ name: 'testEvent', manager: {}, debounce: true });
expect(TestEvent._callRedux('test')).toEqual('test');
expect(mockedDebounce).toHaveBeenCalledWith(expect.any(Function), TestEvent.debounceDelay);
});
it('debounced _callRedux should use passed debounceDelay if debouce is true', async () => {
const mockedDebounce = jest.fn(() => data => data);
__RewireAPI__.__Rewire__('_debounce', mockedDebounce);
const TestEvent = new Event({
name: 'testEvent',
manager: {},
debounce: true,
debounceDelay: 200,
});
expect(TestEvent._callRedux('test')).toEqual('test');
expect(mockedDebounce).toHaveBeenCalledWith(expect.any(Function), 200);
});
it('_bindDataToProps should map state and set event on it', async () => {

@@ -105,14 +145,16 @@ const TestEvent = new Event({ name: 'testEvent', manager: {} });

it('_bindDispatchToProps should map actions and pass redux dispatch', async () => {
it('_bindDispatchToProps should map actions and set __UNSAFE_reduxDispatch', async () => {
const reduxDispatch = jest.fn();
const TestEvent = new Event({ name: 'testEvent', manager: {} });
TestEvent._dispatch = jest.fn(() => 'dispatched');
TestEvent._callRedux = jest.fn(() => 'dispatched');
expect(TestEvent.__UNSAFE_reduxDispatch).toBeUndefined();
const _bindDispatchToProps = TestEvent._bindDispatchToProps(reduxDispatch);
expect(TestEvent._dispatch).toHaveBeenCalledWith(reduxDispatch);
expect(_bindDispatchToProps.testEvent).toEqual('dispatched');
expect(TestEvent.__UNSAFE_reduxDispatch).toEqual(reduxDispatch);
expect(_bindDispatchToProps.testEvent()).toEqual('dispatched');
});
it('toRedux should return correct data', async () => {
it('_formatToRedux should return correct data', async () => {
let TestEvent = new Event({ name: 'testEvent', manager: {} });

@@ -124,6 +166,7 @@ let expectedReturn = {

},
test: 'yes',
shouldDispatch: expect.any(Function),
};
let returnedValue = TestEvent.toRedux({ test: 'yes' });
let returnedValue = TestEvent._formatToRedux({ test: 'yes' });
expect(returnedValue).toEqual(expectedReturn);

@@ -139,6 +182,7 @@ expect(returnedValue.shouldDispatch()).toEqual(true);

},
test: 'yes',
shouldDispatch,
};
returnedValue = TestEvent.toRedux({ test: 'yes' });
returnedValue = TestEvent._formatToRedux({ test: 'yes' });
expect(returnedValue).toEqual(expectedReturn);

@@ -277,3 +321,3 @@ expect(returnedValue.shouldDispatch()).toEqual('lala');

const action = { type: 'LISTENED_EVENT', __UNSAFE_dispatch: jest.fn() };
TestEvent.toRedux = jest.fn(() => 'toReduxCalled');
TestEvent._formatToRedux = jest.fn(() => '_formatToReduxCalled');
expect(ListenedEventReturnFunction).not.toBeCalled();

@@ -284,8 +328,8 @@

expect(ListenedEventReturnFunction).toBeCalled();
expect(TestEvent._formatToRedux).not.toBeCalled();
expect(action.__UNSAFE_dispatch).not.toBeCalled();
expect(TestEvent.toRedux).not.toBeCalled();
jest.runAllTimers();
expect(action.__UNSAFE_dispatch).toBeCalledWith('toReduxCalled');
expect(TestEvent.toRedux).toBeCalledWith('__UNSAFE_state');
expect(action.__UNSAFE_dispatch).toBeCalledWith('_formatToReduxCalled');
expect(TestEvent._formatToRedux).toBeCalledWith('__UNSAFE_state');
});

@@ -325,3 +369,3 @@ });

it('toRedux should return correct data', async () => {
it('_formatToRedux should return correct data', async () => {
let EventManager = {

@@ -338,5 +382,5 @@ call: jest.fn(() => 'api called'),

let toReduxReturn = TestEvent.toRedux({ test: 'data' });
expect(toReduxReturn).toEqual(expectedReturn);
expect(toReduxReturn.shouldDispatch()).toBeTruthy();
let _formatToReduxReturn = TestEvent._formatToRedux({ test: 'data' });
expect(_formatToReduxReturn).toEqual(expectedReturn);
expect(_formatToReduxReturn.shouldDispatch()).toBeTruthy();

@@ -355,5 +399,5 @@ EventManager = {

toReduxReturn = TestEvent.toRedux({ test: 'data' });
expect(toReduxReturn).toEqual(expectedReturn);
expect(toReduxReturn.shouldDispatch()).toBeFalsy();
_formatToReduxReturn = TestEvent._formatToRedux({ test: 'data' });
expect(_formatToReduxReturn).toEqual(expectedReturn);
expect(_formatToReduxReturn.shouldDispatch()).toBeFalsy();
});

@@ -442,3 +486,3 @@

const action = { type: 'LISTENED_EVENT', __UNSAFE_dispatch: jest.fn() };
TestEvent.toRedux = jest.fn(() => 'toReduxCalled');
TestEvent._formatToRedux = jest.fn(() => '_formatToReduxCalled');
expect(ListenedEventReturnFunction).not.toBeCalled();

@@ -449,8 +493,8 @@

expect(ListenedEventReturnFunction).toBeCalled();
expect(TestEvent._formatToRedux).not.toBeCalled();
expect(action.__UNSAFE_dispatch).not.toBeCalled();
expect(TestEvent.toRedux).not.toBeCalled();
jest.runAllTimers();
expect(action.__UNSAFE_dispatch).toBeCalledWith('toReduxCalled');
expect(TestEvent.toRedux).toBeCalledWith('__UNSAFE_state');
expect(action.__UNSAFE_dispatch).toBeCalledWith('_formatToReduxCalled');
expect(TestEvent._formatToRedux).toBeCalledWith('__UNSAFE_state');
});

@@ -470,3 +514,3 @@

const action = { type: 'LISTENED_EVENT', __UNSAFE_dispatch: jest.fn() };
TestEvent.toRedux = jest.fn(() => 'toReduxCalled');
TestEvent._formatToRedux = jest.fn(() => '_formatToReduxCalled');
expect(ListenedEventReturnFunction).not.toBeCalled();

@@ -478,7 +522,7 @@

expect(action.__UNSAFE_dispatch).not.toBeCalled();
expect(TestEvent.toRedux).not.toBeCalled();
expect(TestEvent._formatToRedux).not.toBeCalled();
jest.runAllTimers();
expect(action.__UNSAFE_dispatch).not.toBeCalled();
expect(TestEvent.toRedux).not.toBeCalled();
expect(TestEvent._formatToRedux).not.toBeCalled();
});

@@ -498,3 +542,3 @@

const action = { type: 'NOT_LISTENED_EVENT', __UNSAFE_dispatch: jest.fn() };
TestEvent.toRedux = jest.fn(() => 'toReduxCalled');
TestEvent._formatToRedux = jest.fn(() => '_formatToReduxCalled');
expect(ListenedEventReturnFunction).not.toBeCalled();

@@ -506,8 +550,8 @@

expect(action.__UNSAFE_dispatch).not.toBeCalled();
expect(TestEvent.toRedux).not.toBeCalled();
expect(TestEvent._formatToRedux).not.toBeCalled();
jest.runAllTimers();
expect(action.__UNSAFE_dispatch).not.toBeCalled();
expect(TestEvent.toRedux).not.toBeCalled();
expect(TestEvent._formatToRedux).not.toBeCalled();
});
});

@@ -10,4 +10,5 @@ module.exports = {

'no-param-reassign': 'off',
'no-prototype-builtins': 'off',
'no-restricted-properties': 'off',
'no-underscore-dangle': 'off',
'no-prototype-builtins': 'off',
'array-callback-return': 'off',

@@ -14,0 +15,0 @@ 'no-console': ['error', { allow: ['error'] }],

@@ -10,2 +10,4 @@ "use strict";

var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));

@@ -17,2 +19,4 @@

var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

@@ -22,2 +26,12 @@

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var _debounce = require('lodash.debounce');
var isNumber = function isNumber(n) {
return !window.isNaN(parseFloat(n)) && !window.isNaN(n - 0);
};
var Event = function Event() {

@@ -30,2 +44,6 @@ var _this = this;

useDataFrom = _ref.useDataFrom,
_ref$debounce = _ref.debounce,
debounce = _ref$debounce === void 0 ? false : _ref$debounce,
_ref$debounceDelay = _ref.debounceDelay,
debounceDelay = _ref$debounceDelay === void 0 ? 300 : _ref$debounceDelay,
_ref$listenTo = _ref.listenTo,

@@ -36,12 +54,2 @@ _listenTo = _ref$listenTo === void 0 ? [] : _ref$listenTo;

this.toRedux = function (dispatchData) {
return {
type: _this.reducerName,
shouldDispatch: _this.manager.shouldDispatch || function () {
return true;
},
extraData: dispatchData
};
};
this.createReducers = function () {

@@ -97,4 +105,5 @@ var reducers = {};

this._chainEvents = function (action) {
// eslint-disable-next-line camelcase
var listenTo = _this.listenTo,
toRedux = _this.toRedux;
_formatToRedux = _this._formatToRedux;

@@ -110,3 +119,3 @@ if (listenTo.length) {

setTimeout(function () {
return action.__UNSAFE_dispatch(toRedux(event.__UNSAFE_state));
return action.__UNSAFE_dispatch(_formatToRedux(event.__UNSAFE_state));
});

@@ -118,8 +127,16 @@ }

this._dispatch = function (reduxDispatch) {
return function (dispatchData) {
return reduxDispatch(_this.toRedux(dispatchData));
};
this._callRedux = function (dispatchData) {
return _this.__UNSAFE_reduxDispatch(_this._formatToRedux(dispatchData));
};
this._formatToRedux = function (dispatchData) {
return _objectSpread({
type: _this.reducerName,
shouldDispatch: _this.manager.shouldDispatch || function () {
return true;
},
extraData: dispatchData
}, dispatchData);
};
this._bindDataToProps = function (props) {

@@ -143,4 +160,5 @@ if (_this.useDataFrom && props.length) {

this._bindDispatchToProps = function (reduxDispatch) {
_this.__UNSAFE_reduxDispatch = reduxDispatch;
var actions = {};
actions[_this.name] = _this._dispatch(reduxDispatch);
actions[_this.name] = _this._callRedux;
return actions;

@@ -173,4 +191,10 @@ };

if (debounce && !isNumber(debounceDelay)) {
throw new Error('When debounce is true, debounceDelay needs to be a Number.');
}
this.name = _name;
this.manager = manager;
this.debounce = debounce;
this.debounceDelay = debounceDelay;
this.listenTo = _listenTo;

@@ -180,2 +204,6 @@ this.useDataFrom = useDataFrom;

this.reducerName = this._formatReducerName(this.name);
if (this.debounce) {
this._callRedux = _debounce(this._callRedux, this.debounceDelay);
}
};

@@ -195,16 +223,10 @@

name = _ref4.name,
manager = _ref4.manager,
useDataFrom = _ref4.useDataFrom,
_ref4$listenTo = _ref4.listenTo,
listenTo = _ref4$listenTo === void 0 ? [] : _ref4$listenTo;
rest = (0, _objectWithoutProperties2.default)(_ref4, ["name"]);
(0, _classCallCheck2.default)(this, HTTPEvent);
_this2 = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(HTTPEvent).call(this, {
name: name,
manager: manager,
useDataFrom: useDataFrom,
listenTo: listenTo
}));
_this2 = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(HTTPEvent).call(this, _objectSpread({
name: name
}, rest)));
_this2.toRedux = function (dispatchData) {
_this2._formatToRedux = function (dispatchData) {
var shouldDispatch = _this2.manager.shouldDispatch;

@@ -211,0 +233,0 @@ return {

@@ -24,2 +24,48 @@

### Debouncing Events
It's not unusual to have a use case in which you don't really want to trigger the Event right away. When the user is typing some data into a text input, for example, we may want to wait for a certein amount of time so that the user has finished typing, and only then trigger the Event with the latest data.
Doing that inside a component may give you some undesirable effects. First of all the Component will need to implement the debouncing itself, and more code is more windows for errors. The redux flow will be oh so slightly off from the input change as well, which may lead to rendering issues when presenting the loading spinner, for example.
To deal with those cases, we provide an optional `debounce` and `debounceDelay` configurations. When instantiating the Event, you are able to do something like this:
```js
// on events.js
import { HTTPEvent } from 'rel-events';
import { SearchByUsernameHTTPEventManager } from './eventManagers.js';
export const SearchByUsernameHTTPEvent = new HTTPEvent({
name: 'searchByUsername',
manager: new SearchByUsernameHTTPEventManager(),
// we set debounce as true and optionally pass a custom delay in ms
debounce: true,
debounceDelay: 500, // defaults to 300
});
```
Then, just trigger the Event as you would before and the Event will wait for that amount of time before dispatching itself:
```js
// on SearchByUsernameComponent.js
import { SearchByUsernameHTTPEvent } from './events.js';
class SearchByUsernameComponent extends React.Component {
//...
// even though the Event will be triggered whenever something is typed,
// it will only be dispatched after the user stopped typing
// and 500ms has passed since the last edit
render() {
return <inpyt type="text" onChange={e => this.props.searchByUsername({ username: e.target.value })} />
};
// ...
}
export default LoginHTTPEvent.register({ Component: LoginComponent });
```
The debounce function is provided straight from [lodash](https://lodash.com/docs/4.17.15#debounce).
### Event Chaining - Making Events listen to Events

@@ -26,0 +72,0 @@

@@ -26,2 +26,4 @@

listenTo: Array.of(Object),
debounce: Boolean,
debounceDelay: Number,
});

@@ -41,3 +43,5 @@

}
]
],
debounce: true,
debounceDelay: 500,
});

@@ -110,15 +114,2 @@ ```

### Event.toRedux
"Serializes" data in a way that redux knows how to dispatch. Receives an object and returns an object. Mostly used internally. Unsafe.
```js
EventInstance.toRedux({ data });
// returns an object of { type: formatted event.name, shouldDispatch: Function -> Boolean, ...data }
// example:
ChooseDateRangeEvent.toRedux({ startDate: new Date, endDate: new Date });
// returns { type: 'CHOOSE_DATE_RANGE', shouldDispatch: () => true, startDate, endDate }
```
---------------------------------------

@@ -125,0 +116,0 @@

import { connect } from 'react-redux';
const _debounce = require('lodash.debounce');
const isNumber = n => !window.isNaN(parseFloat(n)) && !window.isNaN(n - 0);
export class Event {
constructor({ name, manager, useDataFrom, listenTo = [] } = {}) {
constructor({
name,
manager,
useDataFrom,
debounce = false,
debounceDelay = 300,
listenTo = [],
} = {}) {
if (arguments.length === 0) {

@@ -30,4 +41,11 @@ throw new Error('An Event should not be initialized without parameters.');

}
if (debounce && !isNumber(debounceDelay)) {
throw new Error('When debounce is true, debounceDelay needs to be a Number.');
}
this.name = name;
this.manager = manager;
this.debounce = debounce;
this.debounceDelay = debounceDelay;
this.listenTo = listenTo;

@@ -37,10 +55,8 @@ this.useDataFrom = useDataFrom;

this.reducerName = this._formatReducerName(this.name);
if (this.debounce) {
this._callRedux = _debounce(this._callRedux, this.debounceDelay);
}
}
toRedux = dispatchData => ({
type: this.reducerName,
shouldDispatch: this.manager.shouldDispatch || (() => true),
extraData: dispatchData,
});
createReducers = () => {

@@ -85,3 +101,4 @@ const reducers = {};

_chainEvents = action => {
const { listenTo, toRedux } = this;
// eslint-disable-next-line camelcase
const { listenTo, _formatToRedux } = this;

@@ -94,3 +111,3 @@ if (listenTo.length) {

if (action.type === reducer) {
setTimeout(() => action.__UNSAFE_dispatch(toRedux(event.__UNSAFE_state)));
setTimeout(() => action.__UNSAFE_dispatch(_formatToRedux(event.__UNSAFE_state)));
}

@@ -101,4 +118,11 @@ });

_dispatch = reduxDispatch => dispatchData => reduxDispatch(this.toRedux(dispatchData));
_callRedux = dispatchData => this.__UNSAFE_reduxDispatch(this._formatToRedux(dispatchData));
_formatToRedux = dispatchData => ({
type: this.reducerName,
shouldDispatch: this.manager.shouldDispatch || (() => true),
extraData: dispatchData,
...dispatchData,
});
_bindDataToProps = props => {

@@ -126,4 +150,5 @@ if (this.useDataFrom && props.length) {

_bindDispatchToProps = reduxDispatch => {
this.__UNSAFE_reduxDispatch = reduxDispatch;
const actions = {};
actions[this.name] = this._dispatch(reduxDispatch);
actions[this.name] = this._callRedux;
return actions;

@@ -140,4 +165,4 @@ };

export class HTTPEvent extends Event {
constructor({ name, manager, useDataFrom, listenTo = [] } = {}) {
super({ name, manager, useDataFrom, listenTo });
constructor({ name, ...rest } = {}) {
super({ name, ...rest });

@@ -153,3 +178,3 @@ delete this.reducerName;

toRedux = dispatchData => {
_formatToRedux = dispatchData => {
const { shouldDispatch } = this.manager;

@@ -156,0 +181,0 @@ return {

{
"name": "rel-events",
"version": "0.4.0",
"version": "0.4.3",
"description": "The relevant React Events Library. Events framework based on redux to decouple our from business logic and make state management easy.",

@@ -12,3 +12,3 @@ "main": "index.js",

"dist": "NODE_ENV=production ./node_modules/.bin/babel lib -d dist",
"test_debug": "NODE_ENV=test node --inspect node_modules/.bin/jest"
"test_debug": "NODE_ENV=test node --inspect node_modules/.bin/jest --watch"
},

@@ -79,4 +79,5 @@ "repository": {

"dependencies": {
"lodash.debounce": "^4.0.8",
"react-redux-api-tools": "^2.1.1"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc