Socket
Socket
Sign inDemoInstall

rel-events

Package Overview
Dependencies
Maintainers
1
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.1.4 to 0.2.0

__tests__/helpers.test.js

114

__tests__/events.test.js

@@ -1,5 +0,4 @@

import * as redux from 'react-redux';
// eslint-disable-next-line import/named
import { Event, HTTPEvent, __RewireAPI__ } from '../lib/events';
import { Event, HTTPEvent, dispatchEvent, getCurrentStateFromEvent } from '../lib/events';
describe('Event', () => {

@@ -31,2 +30,6 @@ it('should initialize correctly', async () => {

it('should throw an error when initializing with Empty', async () => {
expect(() => new Event()).toThrow('An Event should not be initialized without parameters.');
});
it('should throw error when initializing without name', async () => {

@@ -158,2 +161,31 @@ expect(() => new Event({})).toThrow('An Event should be initialized with an event name.');

it('createReducers should return object containing reducers from other event for event with useDataFrom', async () => {
const EventManager = {
onDispatch: jest.fn(() => ({ test: 'it works!' })),
initialState: { initial: 'state' },
};
const TestEvent = new Event({
name: 'testEvent',
useDataFrom: 'otherEvent',
manager: EventManager,
});
TestEvent._chainEvents = jest.fn();
const reducers = TestEvent.createReducers();
expect(reducers).toHaveProperty('otherEvent');
expect(reducers.testEvent).toBeUndefined();
expect(typeof reducers.otherEvent).toBe('function');
expect(reducers.otherEvent(undefined, { type: 'notThisOne' })).toEqual(
EventManager.initialState,
);
expect(EventManager.onDispatch).not.toBeCalled();
expect(TestEvent._chainEvents).not.toBeCalled();
expect(reducers.otherEvent({}, { type: 'TEST_EVENT' })).toEqual({ test: 'it works!' });
expect(EventManager.onDispatch).toBeCalled();
expect(TestEvent._chainEvents).toBeCalledWith({ type: 'TEST_EVENT' });
expect(TestEvent.__UNSAFE_state).toEqual({ test: 'it works!' });
});
it('createReducers should return object containing reducers with after dispatch', async () => {

@@ -195,3 +227,4 @@ jest.useFakeTimers();

const returnedConnect = jest.fn(() => 'final return');
redux.connect = jest.fn(() => returnedConnect);
const mockedReduxConnect = jest.fn(() => returnedConnect);
__RewireAPI__.__Rewire__('connect', mockedReduxConnect);
TestEvent._bindDataToProps = jest.fn(() => 'bound data');

@@ -202,3 +235,3 @@

expect(redux.connect).toHaveBeenCalledWith('bound data', TestEvent._bindDispatchToProps);
expect(mockedReduxConnect).toHaveBeenCalledWith('bound data', TestEvent._bindDispatchToProps);
expect(TestEvent._bindDataToProps).toHaveBeenCalledWith(['test']);

@@ -210,3 +243,3 @@ expect(returnedConnect).toHaveBeenCalledWith(Component);

expect(redux.connect).toHaveBeenCalledWith('bound data', TestEvent._bindDispatchToProps);
expect(mockedReduxConnect).toHaveBeenCalledWith('bound data', TestEvent._bindDispatchToProps);
expect(TestEvent._bindDataToProps).toHaveBeenCalledWith([]);

@@ -216,2 +249,11 @@ expect(returnedConnect).toHaveBeenCalledWith(Component);

it('register should raise error when props key is passed to event with useDataFrom', async () => {
const TestEvent = new Event({ name: 'testEvent', useDataFrom: 'otherEvent', manager: {} });
const Component = {};
expect(() => TestEvent.register({ Component, props: ['test'] })).toThrow(
`When configuring 'useDataFrom', you will end up with an empty state. Listen to the event with the name described in the 'useDataFrom' key instead.`,
);
});
it('_chainEvents iterates listenTo array and calls correct functions for normal events', async () => {

@@ -271,2 +313,6 @@ jest.useFakeTimers();

it('should throw an error when initializing with Empty', async () => {
expect(() => new HTTPEvent()).toThrow('An Event should be initialized with an event name.');
});
it('toRedux should return correct data', async () => {

@@ -452,57 +498,1 @@ let EventManager = {

});
describe('getCurrentStateFromEvent', () => {
it('should throw if we do not pass an event', async () => {
expect(() => getCurrentStateFromEvent({})).toThrow('You need to pass an event.');
});
it('should throw if we do not pass the appState', async () => {
expect(() => getCurrentStateFromEvent({ event: {} })).toThrow(
'You need to pass your app state. This is only available inside `shouldDispatch` methods or imported manually (not recommended).',
);
});
it('should return correct data', async () => {
expect(
getCurrentStateFromEvent({ event: { name: 'testEvent' }, appState: { testEvent: 'data' } }),
).toEqual('data');
});
});
describe('dispatchEvent', () => {
it('should throw if we do not pass an event', async () => {
expect(() => dispatchEvent({})).toThrow('You need to pass an event.');
});
it('should throw if we do not pass an event with a toRedux method', async () => {
expect(() => dispatchEvent({ event: {} })).toThrow(
'The event you passed needs to have a `toRedux` method. Are you sure you instantiated and passed the correct event?',
);
});
it('should throw if we do not pass a store', async () => {
expect(() => dispatchEvent({ event: { toRedux: () => {} } })).toThrow(
'You need to pass your redux store.',
);
});
it('should throw if we do not pass a store with a dispatch method', async () => {
expect(() => dispatchEvent({ event: { toRedux: () => {} }, store: {} })).toThrow(
'The store you passed does not have a `dispatch` method. Are you sure you passed the correct variable as the store?',
);
});
it('should call store.dispatch passing event.redux with data', async () => {
const event = {
toRedux: jest.fn(),
};
const store = {
dispatch: jest.fn(),
};
dispatchEvent({ event, store, data: { test: 'data' } });
expect(event.toRedux).toHaveBeenCalledWith({ test: 'data' });
expect(store.dispatch).toHaveBeenCalledWith(event.toRedux({ test: 'data' }));
});
});

@@ -8,2 +8,3 @@ module.exports = {

'arrow-body-style': ['error', 'as-needed'],
'no-plusplus': 'off',
'no-param-reassign': 'off',

@@ -10,0 +11,0 @@ 'no-underscore-dangle': 'off',

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

});
exports.dispatchEvent = dispatchEvent;
exports.getCurrentStateFromEvent = getCurrentStateFromEvent;
exports.HTTPEvent = exports.Event = void 0;

@@ -17,2 +15,3 @@

manager,
useDataFrom,
listenTo: _listenTo = []

@@ -29,20 +28,8 @@ } = {}) {

reducers[this.name] = (state = this.manager.initialState, action) => {
if (action.type === this.reducerName) {
const newState = this.manager.onDispatch(state, action);
if (this.useDataFrom) {
reducers[this.useDataFrom] = this._createReducersTo();
} else {
reducers[this.name] = this._createReducersTo();
}
if (this.manager.afterDispatch) {
setTimeout(() => this.manager.afterDispatch(state, newState), 0);
}
this.__UNSAFE_state = newState;
this._chainEvents(action);
return newState;
}
return state;
};
return reducers;

@@ -62,2 +49,20 @@ };

this._createReducersTo = () => (state = this.manager.initialState, action) => {
if (action.type === this.reducerName) {
const newState = this.manager.onDispatch(state, action);
if (this.manager.afterDispatch) {
setTimeout(() => this.manager.afterDispatch(state, newState), 0);
}
this.__UNSAFE_state = newState;
this._chainEvents(action);
return newState;
}
return state;
};
this._chainEvents = action => {

@@ -87,2 +92,6 @@ const {

this._bindDataToProps = props => {
if (this.useDataFrom) {
throw new Error(`When configuring 'useDataFrom', you will end up with an empty state. Listen to the event with the name described in the 'useDataFrom' key instead.`);
}
const {

@@ -110,12 +119,16 @@ name

if (!_name) {
throw new Error('An Event should be initialized with an event name.');
}
if (arguments.length === 0) {
throw new Error('An Event should not be initialized without parameters.');
} else {
if (!_name) {
throw new Error('An Event should be initialized with an event name.');
}
if (!manager) {
throw new Error('An Event should be initialized with an EventManager.');
}
if (!manager) {
throw new Error('An Event should be initialized with an EventManager.');
}
if (!Array.isArray(_listenTo) || !_listenTo.every(obj => obj.hasOwnProperty('event') && obj.hasOwnProperty('triggerOn') && typeof obj.event === 'function')) {
throw new Error('ListenTo must be an array of { event, triggerOn } objects, and the event key should be a function that returns an Event or HTTPEvent.');
if (!Array.isArray(_listenTo) || !_listenTo.every(obj => obj.hasOwnProperty('event') && obj.hasOwnProperty('triggerOn') && typeof obj.event === 'function')) {
throw new Error('ListenTo must be an array of { event, triggerOn } objects, and the event key should be a function that returns an Event or HTTPEvent.');
}
}

@@ -126,2 +139,3 @@

this.listenTo = _listenTo;
this.useDataFrom = useDataFrom;
this.__UNSAFE_state = manager.initialState;

@@ -139,2 +153,3 @@ this.reducerName = this._formatReducerName(this.name);

manager,
useDataFrom,
listenTo = []

@@ -145,2 +160,3 @@ } = {}) {

manager,
useDataFrom,
listenTo

@@ -161,36 +177,30 @@ });

this.createReducers = () => {
const reducers = {};
this._createReducersTo = () => (state = this.manager.initialState, action) => {
let newState = state;
reducers[this.name] = (state = this.manager.initialState, action) => {
let newState = state;
if (action.type === this.reducers.request) {
newState = this.manager.onDispatch(state, action);
}
if (action.type === this.reducers.request) {
newState = this.manager.onDispatch(state, action);
}
if (action.type === this.reducers.success) {
newState = this.manager.onSuccess(state, action);
if (action.type === this.reducers.success) {
newState = this.manager.onSuccess(state, action);
if (this.manager.afterSuccess) {
setTimeout(() => this.manager.afterSuccess(state, newState), 0);
}
if (this.manager.afterSuccess) {
setTimeout(() => this.manager.afterSuccess(state, newState), 0);
}
}
if (action.type === this.reducers.failure) {
newState = this.manager.onFailure(state, action);
if (action.type === this.reducers.failure) {
newState = this.manager.onFailure(state, action);
if (this.manager.afterFailure) {
setTimeout(() => this.manager.afterFailure(state, newState), 0);
}
if (this.manager.afterFailure) {
setTimeout(() => this.manager.afterFailure(state, newState), 0);
}
}
this.__UNSAFE_state = newState;
this.__UNSAFE_state = newState;
this._chainEvents(action);
this._chainEvents(action);
return newState;
};
return reducers;
return newState;
};

@@ -208,37 +218,2 @@

exports.HTTPEvent = HTTPEvent;
function dispatchEvent({
event,
store,
data
}) {
if (!event) {
throw new Error('You need to pass an event.');
} else if (typeof event.toRedux !== 'function') {
throw new Error('The event you passed needs to have a `toRedux` method. Are you sure you instantiated and passed the correct event?');
}
if (!store) {
throw new Error('You need to pass your redux store.');
} else if (typeof store.dispatch !== 'function') {
throw new Error('The store you passed does not have a `dispatch` method. Are you sure you passed the correct variable as the store?');
}
return store.dispatch(event.toRedux(data));
}
function getCurrentStateFromEvent({
appState,
event
}) {
if (!event) {
throw new Error('You need to pass an event.');
}
if (!appState) {
throw new Error('You need to pass your app state. This is only available inside `shouldDispatch` methods or imported manually (not recommended).');
}
return appState[event.name];
}
exports.HTTPEvent = HTTPEvent;

@@ -81,2 +81,3 @@

import { combineReducers } from 'redux';
import { combineEventReducers } from 'rel-events';
import { ChooseDateRangeEvent } from './events.js';

@@ -86,3 +87,3 @@

export default combineReducers({
...ChooseDateRangeEvent.createReducers(),
...combineEventReducers([ ChooseDateRangeEvent ]),
});

@@ -89,0 +90,0 @@ ```

@@ -78,7 +78,7 @@ ## Creating a HTTPEvent

import { combineReducers } from 'redux';
import { combineEventReducers } from 'rel-events';
import { ChooseDateRangeEvent, LoginHTTPEvent } from './events.js';
export default combineReducers({
...ChooseDateRangeEvent.createReducers(),
...LoginHTTPEvent.createReducers(), // <<< new line here
...combineEventReducers([ ChooseDateRangeEvent, LoginHTTPEvent ]),
});

@@ -85,0 +85,0 @@

@@ -37,2 +37,30 @@

### `useDataFrom` optional Event parameter
If you want, for example, to clear data from an Event, you'll notice there isn't a way inside the same Event to do so. Instead, you must create a new Event that writes data to the first Event's state.
```js
// on events.js
import { Event, HTTPEvent } from 'rel-events';
import { LoginHTTPEventManager, FetchUserDataHTTPEventManager } from './eventManagers.js';
export const LoginHTTPEvent = new HTTPEvent({
name: 'login',
manager: new LoginHTTPEventManager(),
});
export const ClearLoginDataEvent = new Event({
name: 'clearLoginData',
useDataFrom: 'login', // <-- we use the LoginHTTPEvent's name to link it's data to this new Event
manager: {
initialState: { isAuthenticated: false },
onDispatch: () => initialState,
}
});
```
You may use this optional param with HTTPEvents as well.
One thing to keep in mind: since this second Event uses the data from another, it can't be registered to a component passing a `props` key, since it doesn't have data of it's own. Don't worry, we'll warn if you if that happens. :)
### `shouldDispatch` optional method - helped by the `getCurrentStateFromEvent` helper

@@ -39,0 +67,0 @@

@@ -21,3 +21,8 @@

```js
new Event({ name: String, manager: Object, listenTo: Array.of(Object) });
new Event({
name: String.isRequired,
manager: Object.isRequired,
useDataFrom: String,
listenTo: Array.of(Object),
});

@@ -27,2 +32,3 @@ // example:

name: 'chooseDateRange',
useDataFrom: 'otherEvent',
manager: {

@@ -29,0 +35,0 @@ // refer to EventManager API docs

# rel-events docs
This folder contains all the docs on the current API and how to use the `rel-events` library.
This folder contains all the docs on the current API and how to use the `rel-events` library :D

@@ -10,1 +10,2 @@ - [1: Basic Usage](https://github.com/labcodes/rel-events/tree/master/docs/1-Basic-Usage.md)

- [5: How it works](https://github.com/labcodes/rel-events/tree/master/docs/5-How-it-works.md)
- [6: Contributing](https://github.com/labcodes/rel-events/tree/master/docs/6-Contributing.md)
import eventsMiddleware from 'react-redux-api-tools/lib/middleware';
import fetchFromApi from 'react-redux-api-tools/lib/api';
import { Event, HTTPEvent, getCurrentStateFromEvent, dispatchEvent } from './dist/events';
import { Event, HTTPEvent } from './dist/events';
import { getCurrentStateFromEvent, dispatchEvent, combineEventReducers } from './dist/helpers';
export {
eventsMiddleware,
fetchFromApi,
Event,
HTTPEvent,
combineEventReducers,
dispatchEvent,
getCurrentStateFromEvent,
dispatchEvent,
fetchFromApi,
};
import { connect } from 'react-redux';
export class Event {
constructor({ name, manager, listenTo = [] } = {}) {
if (!name) {
throw new Error('An Event should be initialized with an event name.');
}
constructor({ name, manager, useDataFrom, listenTo = [] } = {}) {
if (arguments.length === 0) {
throw new Error('An Event should not be initialized without parameters.');
} else {
if (!name) {
throw new Error('An Event should be initialized with an event name.');
}
if (!manager) {
throw new Error('An Event should be initialized with an EventManager.');
}
if (!manager) {
throw new Error('An Event should be initialized with an EventManager.');
}
if (
!Array.isArray(listenTo) ||
!listenTo.every(
obj =>
obj.hasOwnProperty('event') &&
obj.hasOwnProperty('triggerOn') &&
typeof obj.event === 'function',
)
) {
throw new Error(
'ListenTo must be an array of { event, triggerOn } objects, and the event key should be a function that returns an Event or HTTPEvent.',
);
if (
!Array.isArray(listenTo) ||
!listenTo.every(
obj =>
obj.hasOwnProperty('event') &&
obj.hasOwnProperty('triggerOn') &&
typeof obj.event === 'function',
)
) {
throw new Error(
'ListenTo must be an array of { event, triggerOn } objects, and the event key should be a function that returns an Event or HTTPEvent.',
);
}
}
this.name = name;
this.manager = manager;
this.listenTo = listenTo;
this.useDataFrom = useDataFrom;
this.__UNSAFE_state = manager.initialState;

@@ -43,18 +47,8 @@ this.reducerName = this._formatReducerName(this.name);

reducers[this.name] = (state = this.manager.initialState, action) => {
if (action.type === this.reducerName) {
const newState = this.manager.onDispatch(state, action);
if (this.useDataFrom) {
reducers[this.useDataFrom] = this._createReducersTo();
} else {
reducers[this.name] = this._createReducersTo();
}
if (this.manager.afterDispatch) {
setTimeout(() => this.manager.afterDispatch(state, newState), 0);
}
this.__UNSAFE_state = newState;
this._chainEvents(action);
return newState;
}
return state;
};
return reducers;

@@ -76,2 +70,18 @@ };

_createReducersTo = () => (state = this.manager.initialState, action) => {
if (action.type === this.reducerName) {
const newState = this.manager.onDispatch(state, action);
if (this.manager.afterDispatch) {
setTimeout(() => this.manager.afterDispatch(state, newState), 0);
}
this.__UNSAFE_state = newState;
this._chainEvents(action);
return newState;
}
return state;
};
_chainEvents = action => {

@@ -95,2 +105,7 @@ const { listenTo, toRedux } = this;

_bindDataToProps = props => {
if (this.useDataFrom) {
throw new Error(
`When configuring 'useDataFrom', you will end up with an empty state. Listen to the event with the name described in the 'useDataFrom' key instead.`,
);
}
const { name } = this;

@@ -125,4 +140,4 @@

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

@@ -148,68 +163,28 @@ delete this.reducerName;

createReducers = () => {
const reducers = {};
_createReducersTo = () => (state = this.manager.initialState, action) => {
let newState = state;
reducers[this.name] = (state = this.manager.initialState, action) => {
let newState = state;
if (action.type === this.reducers.request) {
newState = this.manager.onDispatch(state, action);
}
if (action.type === this.reducers.request) {
newState = this.manager.onDispatch(state, action);
if (action.type === this.reducers.success) {
newState = this.manager.onSuccess(state, action);
if (this.manager.afterSuccess) {
setTimeout(() => this.manager.afterSuccess(state, newState), 0);
}
}
if (action.type === this.reducers.success) {
newState = this.manager.onSuccess(state, action);
if (this.manager.afterSuccess) {
setTimeout(() => this.manager.afterSuccess(state, newState), 0);
}
if (action.type === this.reducers.failure) {
newState = this.manager.onFailure(state, action);
if (this.manager.afterFailure) {
setTimeout(() => this.manager.afterFailure(state, newState), 0);
}
}
if (action.type === this.reducers.failure) {
newState = this.manager.onFailure(state, action);
if (this.manager.afterFailure) {
setTimeout(() => this.manager.afterFailure(state, newState), 0);
}
}
this.__UNSAFE_state = newState;
this._chainEvents(action);
this.__UNSAFE_state = newState;
this._chainEvents(action);
return newState;
};
return reducers;
return newState;
};
}
export function dispatchEvent({ event, store, data }) {
if (!event) {
throw new Error('You need to pass an event.');
} else if (typeof event.toRedux !== 'function') {
throw new Error(
'The event you passed needs to have a `toRedux` method. Are you sure you instantiated and passed the correct event?',
);
}
if (!store) {
throw new Error('You need to pass your redux store.');
} else if (typeof store.dispatch !== 'function') {
throw new Error(
'The store you passed does not have a `dispatch` method. Are you sure you passed the correct variable as the store?',
);
}
return store.dispatch(event.toRedux(data));
}
export function getCurrentStateFromEvent({ appState, event }) {
if (!event) {
throw new Error('You need to pass an event.');
}
if (!appState) {
throw new Error(
'You need to pass your app state. This is only available inside `shouldDispatch` methods or imported manually (not recommended).',
);
}
return appState[event.name];
}
{
"name": "rel-events",
"version": "0.1.4",
"version": "0.2.0",
"description": "The relevant React Events Library. Events framework based on redux to decouple our from business logic and make state management easy.",

@@ -8,7 +8,7 @@ "main": "index.js",

"coveralls": "npm run test && cat ./coverage/lcov.info | coveralls",
"lint": "eslint lib/** __tests__/**",
"test": "npm run dist && jest --coverage",
"jest": "npm run dist && jest",
"dist": "./node_modules/.bin/babel lib -d dist",
"test_debug": "node --inspect node_modules/.bin/jest"
"lint": "NODE_ENV=production eslint lib/** __tests__/**",
"test": "NODE_ENV=test npm run dist && jest --coverage",
"jest": "NODE_ENV=test npm run dist && jest",
"dist": "NODE_ENV=production ./node_modules/.bin/babel lib -d dist",
"test_debug": "NODE_ENV=test node --inspect node_modules/.bin/jest"
},

@@ -40,2 +40,3 @@ "repository": {

"babel-eslint": "^10.0.2",
"babel-plugin-rewire": "^1.2.0",
"coveralls": "^3.0.5",

@@ -62,3 +63,3 @@ "eslint": "^6.0.1",

"global": {
"branches": 95,
"branches": 100,
"functions": 100,

@@ -65,0 +66,0 @@ "lines": 100,

@@ -6,2 +6,3 @@ # rel-events

*To read the docs, [go to our docs folder](https://github.com/labcodes/rel-events/tree/master/docs). :)*
*To see the app demo, [go to out codesandbox page](https://codesandbox.io/s/rel-events-example-w6yji?fontsize=12)!*

@@ -172,8 +173,6 @@ Welcome to the `rel-events` github repo!

Don't hesitate to open an issue for bugs!
Thanks for wanting to contribute! Please, read our [Contributing guide](https://github.com/labcodes/rel-events/tree/master/docs/6-Contributing.md) carefully before opening PRs, though. We do enjoy PRs, but any PRs that don't follow our contributing guidelines will probably be rejected :/
But if you would like a new feature, it would be nice to discuss it before accepting PRs. We reserve ourselves the right to reject a feature that was not discussed or that will impact the code or API in a meaningful way. In that case, open an issue so we can discuss it thoroughly. Thanks. <3
### Thanks
Thanks for everyone at Labcodes for giving me the structure and time for me to work on this pet project of mine and giving me lots of awesome feedback! Bernardo Fontes, Luan Fonseca, Thulio Philipe, Mariana Bedran, Breno Chamie and Renato Oliveira, I'm really, really grateful for your input! <3

Sorry, the diff of this file is not supported yet

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