ts-bus
Version:
<p align="center"> <img src="logo.png" width="100" height="100"/> </p>
292 lines • 12.7 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_hooks_1 = require("@testing-library/react-hooks");
var eventemitter2_1 = require("eventemitter2");
var react_1 = __importDefault(require("react"));
var react_test_renderer_1 = require("react-test-renderer");
var EventBus_1 = require("./EventBus");
var react_2 = require("./react");
var useBusReducer_1 = require("./useBusReducer");
var bus = new EventBus_1.EventBus();
function mockEventBus() {
var _unsubscribe = jest.fn();
var subscribe = jest.fn(function () { return _unsubscribe; });
var publish = jest.fn();
var emitter = new eventemitter2_1.EventEmitter2();
return { subscribe: subscribe, emitter: emitter, publish: publish, _unsubscribe: _unsubscribe };
}
var wrapper = function (_a) {
var children = _a.children;
return (react_1.default.createElement(react_2.BusProvider, { value: bus }, children));
};
it("should provide a bus", function () {
var result = react_hooks_1.renderHook(function () { return react_2.useBus(); }, { wrapper: wrapper }).result;
expect(result.current).toBe(bus);
});
it("should not subscribe without unsubscribing (useBusReducer)", function () {
var mockBus = mockEventBus();
// run once to subscribe to bus
// type SubscribeFn = (d: any, b: any) => void;
var hook = react_hooks_1.renderHook(function (subscriberFn) {
var useReducer = react_2.useBusReducer.configure({ subscriber: subscriberFn });
return useReducer(function (state) { return state; }, {}, function (a) { return a; });
}, {
wrapper: function (_a) {
var children = _a.children;
return (react_1.default.createElement(react_2.BusProvider, { value: mockBus }, children));
},
initialProps: useBusReducer_1._defaultSubscriber
});
// change subscriber to different reference to invalidate useEffect
hook.rerender(function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return useBusReducer_1._defaultSubscriber.apply(void 0, args);
});
hook.unmount();
expect(mockBus.subscribe.mock.calls.length).toBe(2);
expect(mockBus._unsubscribe.mock.calls.length).toBe(2);
});
it("should not subscribe without unsubscribing (useBusState)", function () {
var mockBus = mockEventBus();
var incrementEvent = EventBus_1.createEventDefinition()("increment");
// run once to subscribe to bus
var hook = react_hooks_1.renderHook(function () { return react_2.useBusState(0, incrementEvent); }, {
wrapper: function (_a) {
var children = _a.children;
return (react_1.default.createElement(react_2.BusProvider, { value: mockBus }, children));
}
});
hook.unmount();
expect(mockBus.subscribe.mock.calls.length).toBe(1);
expect(mockBus._unsubscribe.mock.calls.length).toBe(1);
});
it("should update state (options configuration)", function () {
var incrementEvent = EventBus_1.createEventDefinition()("counter.increment");
var result = react_hooks_1.renderHook(function () {
return react_2.useBusState.configure({
subscriber: function (dispatch, bus) {
return bus.subscribe("counter.**", function (v) { return dispatch(v.payload); });
}
})(0);
}, {
wrapper: wrapper
}).result;
expect(result.current).toBe(0);
react_hooks_1.act(function () {
bus.publish(incrementEvent(1));
});
expect(result.current).toBe(1);
});
it("should update state by subscribing to multiple events", function () {
var positiveNumberEvent = EventBus_1.createEventDefinition()("positive");
var negativeNumberEvent = EventBus_1.createEventDefinition()("negative");
var result = react_hooks_1.renderHook(function () {
return react_2.useBusState.configure({
subscriber: react_2.stateSubscriber("positive", "negative")
})(0);
}, {
wrapper: wrapper
}).result;
expect(result.current).toBe(0);
react_hooks_1.act(function () { return bus.publish(positiveNumberEvent(15)); });
expect(result.current).toBe(15);
react_hooks_1.act(function () { return bus.publish(negativeNumberEvent(-5)); });
expect(result.current).toBe(-5);
});
it("should update state", function () {
var incrementEvent = EventBus_1.createEventDefinition()("increment");
var result = react_hooks_1.renderHook(function () { return react_2.useBusState(0, incrementEvent); }, {
wrapper: wrapper
}).result;
expect(result.current).toBe(0);
react_hooks_1.act(function () {
bus.publish(incrementEvent(1));
});
expect(result.current).toBe(1);
});
it("should not reduce for not subscribed event", function () {
var result = react_hooks_1.renderHook(function () {
var reducer = react_2.useBusReducer.configure({
subscriber: react_2.reducerSubscriber("increment", "decrement")
});
return reducer(function (state, event) {
switch (event.type) {
case "increment":
return __assign({}, state, { counter: state.counter + 1 });
case "decrement":
return __assign({}, state, { counter: state.counter - 1 });
case "multiply": // Must never be called
return __assign({}, state, { counter: state.counter * 100 });
}
return state;
}, { counter: 0 }, function (a) { return a; });
}, { wrapper: wrapper }).result;
expect(result.current.counter).toBe(0);
react_hooks_1.act(function () {
bus.publish({ type: "increment", payload: null });
bus.publish({ type: "multiply", payload: null });
bus.publish({ type: "increment", payload: null });
bus.publish({ type: "decrement", payload: null });
});
expect(result.current.counter).toBe(1);
});
it("should reduce using multiple event subscription types", function () {
var minusFour = EventBus_1.createEventDefinition()("minusFour");
var result = react_hooks_1.renderHook(function () {
var reducer = react_2.useBusReducer.configure({
subscriber: react_2.reducerSubscriber("increment", "decrement", minusFour, function (x) { return x.payload !== null && x.payload >= 3; })
});
return reducer(function (state, event) {
switch (event.type) {
case "increment":
return __assign({}, state, { counter: state.counter + 1 });
case "decrement":
return __assign({}, state, { counter: state.counter - 1 });
case "minusFour":
return __assign({}, state, { counter: state.counter - 4 });
case "multiply":
return __assign({}, state, { counter: state.counter * event.payload });
}
return state;
}, { counter: 0 }, function (a) { return a; });
}, { wrapper: wrapper }).result;
expect(result.current.counter).toBe(0);
react_hooks_1.act(function () {
bus.publish({ type: "increment", payload: null }); // Reaches reducer
bus.publish({ type: "increment", payload: null }); // Reaches reducer
bus.publish({ type: "decrement", payload: null }); // Reaches reducer
bus.publish({ type: "increment", payload: null }); // Reaches reducer
bus.publish({ type: "multiply", payload: 2 }); // Does not reach reducer
bus.publish({ type: "multiply", payload: 3 }); // Reaches reducer
bus.publish({ type: "multiply", payload: 4 }); // Reaches reducer
bus.publish({ type: "multiply", payload: 2 }); // Reaches reducer
bus.publish(minusFour()); // Reaches reducer
});
expect(result.current.counter).toBe(20);
});
it("should reduce state", function () {
var result = react_hooks_1.renderHook(function () {
return react_2.useBusReducer(function (state, event) {
switch (event.type) {
case "increment": {
return __assign({}, state, { counter: state.counter + 1 });
}
case "decrement": {
return __assign({}, state, { counter: state.counter - 1 });
}
}
return state;
}, { counter: 0 }, function (a) { return a; });
}, { wrapper: wrapper }).result;
expect(result.current.counter).toBe(0);
react_hooks_1.act(function () {
bus.publish({ type: "increment", payload: null });
bus.publish({ type: "increment", payload: null });
bus.publish({ type: "increment", payload: null });
});
expect(result.current.counter).toBe(3);
});
it("should subscribe state", function () {
var result = react_hooks_1.renderHook(function () {
var useReducer = react_2.useBusReducer.configure({
subscriber: function (dispatch, bus) {
return bus.subscribe("count.**", dispatch);
}
});
return useReducer(function (state, event) {
switch (event.type) {
case "count.increment": {
return __assign({}, state, { counter: state.counter + 1 });
}
case "count.decrement": {
return __assign({}, state, { counter: state.counter - 1 });
}
case "reset": {
return __assign({}, state, { counter: 0 });
}
}
return state;
}, { counter: 0 });
}, { wrapper: wrapper }).result;
expect(result.current.counter).toBe(0);
react_hooks_1.act(function () {
bus.publish({ type: "count.increment", payload: null });
bus.publish({ type: "reset", payload: null });
});
// Reset should have no effect because of subscriber
expect(result.current.counter).toBe(1);
});
it("should use an alternate useReducer", function () {
var mockUseReducer = jest.fn(function (reducer, initialState, initializer) {
return react_1.default.useReducer(reducer, initialState, initializer);
});
var reducer = function (state) {
return state;
};
var init = { counter: 0 };
var ident = function (a) { return a; };
react_hooks_1.renderHook(function () {
var useReducer = react_2.useBusReducer.configure({
useReducer: mockUseReducer
});
return useReducer(reducer, init, ident);
}, { wrapper: wrapper });
expect(mockUseReducer).toBeCalledWith(reducer, init, ident);
});
it("should not loose events during the render cycle when mounted.", function (done) {
var myBus = new EventBus_1.EventBus();
var reducer = jest.fn(function (s) { return s; });
var EVENT_DELAY = { type: "myevent", payload: "DELAY" };
var EVENT_URGENT = { type: "myevent", payload: "URGENT" };
function MyContextProvider(props) {
react_2.useBusReducer(reducer, {});
return props.children;
}
function EventPublisher() {
var b = react_2.useBus();
react_1.default.useEffect(function () {
setTimeout(function () {
b.publish(EVENT_DELAY);
}, 0);
}, [b]);
react_1.default.useEffect(function () {
b.publish(EVENT_URGENT);
}, [b]);
return react_1.default.createElement("div", null);
}
function App() {
return (react_1.default.createElement(react_2.BusProvider, { value: myBus },
react_1.default.createElement(MyContextProvider, null,
react_1.default.createElement(EventPublisher, null))));
}
// render the component
react_hooks_1.act(function () {
react_test_renderer_1.create(react_1.default.createElement(App, null));
});
setTimeout(function () {
var eventList = reducer.mock.calls.map(function (_a) {
var ev = _a[1];
return ev;
});
expect(eventList).toEqual([EVENT_URGENT, EVENT_DELAY]);
done();
}, 0);
});
//# sourceMappingURL=react.test.js.map