Skip to content

Commit 343b09d

Browse files
author
Kasey Powers
committed
feat(message-core): subscriber functionality
1 parent 5d68c0c commit 343b09d

File tree

3 files changed

+83
-37
lines changed

3 files changed

+83
-37
lines changed

packages/message-core/README.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,16 @@
33
A package wrapping the postMessage function with helper functions and security checks.
44

55
## Install
6-
`npm install @availity/message-core`
76

8-
## Configure
7+
`npm install @availity/message-core`
98

10-
`AvMessage` requires an `onMessage` function to be defined. It is called with an event and data parameters.
9+
## Methods
1110

12-
```javascript
13-
import AvMessage from '@availity/message-core';
11+
### subscribe
1412

15-
AvMessage.onMessage = (event, data) => {
16-
// handle postMessage event
17-
}
18-
```
13+
`const unsubscribe = avMessage.subscribe(event, fn)` when a message event is received and verified, fn will be called with the event data.
1914

20-
## Methods
15+
it returns a function that can be used to unsubscribe from that event
2116

2217
### enabled
2318

@@ -31,12 +26,15 @@ returns a string of the windows current domain.
3126

3227
## send
3328

34-
`AvMessage.send(payload, target)` will send the payload to the target if AvMessage is enabled.
29+
`avMessage.send(payload, target)` will send the payload to the target if AvMessage is enabled.
3530
target defaults to the parent window. payload will be stringified if not a string.
3631

3732
## Authors
33+
3834
**Kasey Powers**
39-
* [kaseyepowers@gmail.com](kaseyepowers@gmail.com)
35+
36+
- [kaseyepowers@gmail.com](kaseyepowers@gmail.com)
4037

4138
## License
39+
4240
[MIT](../../LICENSE)

packages/message-core/src/index.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
class AvMessage {
2+
subscribers = {};
3+
24
constructor() {
35
this.isEnabled = true;
46
this.DEFAULT_EVENT = 'avMessage';
@@ -15,9 +17,7 @@ class AvMessage {
1517

1618
getEventData(event) {
1719
if (
18-
!this.isEnabled ||
19-
!this.onMessage ||
20-
typeof this.onMessage !== 'function' || // do nothing if not enabled or no onMessage function given
20+
!this.isEnabled || // do nothing if not enabled
2121
!event ||
2222
!event.data ||
2323
!event.origin ||
@@ -49,6 +49,26 @@ class AvMessage {
4949
this.onMessage(event, data);
5050
}
5151

52+
subscribe(event, fn) {
53+
if (!this.subscribers[event]) {
54+
this.subscribers[event] = [];
55+
}
56+
this.subscribers[event].push(fn);
57+
return () => {
58+
this.subscribers[event] = this.subscribers[event].filter(
59+
val => val !== fn
60+
);
61+
};
62+
}
63+
64+
onMessage(event, data) {
65+
if (this.subscribers[event]) {
66+
this.subscribers[event].forEach(fn => {
67+
fn(data);
68+
});
69+
}
70+
}
71+
5272
// if current domain doesn't match regex DOMAIN, return true.
5373
isDomain(url) {
5474
return !this.DOMAIN.test(this.domain()) || this.DOMAIN.test(url);

packages/message-core/src/tests/message.test.js

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,56 @@ describe('AvMessage', () => {
2121
expect(avMessage.enabled('hello')).toBe(true);
2222
});
2323

24+
describe('subscribers', () => {
25+
test('onMessage should call all subscribers for event', () => {
26+
const testEvent = 'testEvent';
27+
const fns = [jest.fn(), jest.fn()];
28+
avMessage.subscribers = {
29+
[testEvent]: fns,
30+
};
31+
avMessage.onMessage(`${testEvent}Other`);
32+
fns.forEach(fn => expect(fn).not.toHaveBeenCalled());
33+
34+
const data = { testData: 'hello world' };
35+
avMessage.onMessage(testEvent, data);
36+
fns.forEach(fn => expect(fn).toHaveBeenCalledWith(data));
37+
});
38+
39+
test('subscribe should add function to subscribers', () => {
40+
avMessage.subscribers = {};
41+
const testEvent = 'testEvent';
42+
const fn = 'totally a function';
43+
avMessage.subscribe(testEvent, fn);
44+
expect(avMessage.subscribers).toEqual({
45+
[testEvent]: [fn],
46+
});
47+
48+
const fn2 = 'totally another function';
49+
avMessage.subscribe(testEvent, fn2);
50+
expect(avMessage.subscribers).toEqual({
51+
[testEvent]: [fn, fn2],
52+
});
53+
});
54+
55+
test('subscribe should return function to remove subscribers', () => {
56+
avMessage.subscribers = {};
57+
const testEvent = 'testEvent';
58+
const fn = 'totally a function';
59+
const unsubscribe = avMessage.subscribe(testEvent, fn);
60+
61+
const fn2 = 'totally another function';
62+
avMessage.subscribe(testEvent, fn2);
63+
expect(avMessage.subscribers).toEqual({
64+
[testEvent]: [fn, fn2],
65+
});
66+
67+
unsubscribe();
68+
expect(avMessage.subscribers).toEqual({
69+
[testEvent]: [fn2],
70+
});
71+
});
72+
});
73+
2474
describe('getEventData()', () => {
2575
let spyParse;
2676
const mockEvent = {
@@ -49,20 +99,6 @@ describe('AvMessage', () => {
4999
expect(avMessage.onMessage).not.toHaveBeenCalled();
50100
});
51101

52-
test('should return early when AvMessages.onMessage not defined', () => {
53-
delete avMessage.onMessage;
54-
avMessage.getEventData(mockEvent);
55-
expect(avMessage.isDomain).not.toHaveBeenCalled();
56-
expect(spyParse).not.toHaveBeenCalled();
57-
});
58-
59-
test('should return early when AvMessages.onMessage not function', () => {
60-
avMessage.onMessage = 'onMessage';
61-
avMessage.getEventData(mockEvent);
62-
expect(avMessage.isDomain).not.toHaveBeenCalled();
63-
expect(spyParse).not.toHaveBeenCalled();
64-
});
65-
66102
test('should return early when event does not have all fields', () => {
67103
const mockEvent1 = Object.assign({}, mockEvent, { data: false });
68104
const mockEvent2 = Object.assign({}, mockEvent, { origin: false });
@@ -153,14 +189,6 @@ describe('AvMessage', () => {
153189
test('should return location.origin if exists', () => {
154190
expect(avMessage.domain()).toBe(URL);
155191
});
156-
157-
// test('if no location.origin, should return domain generated with hostname', () => {
158-
// expect(avMessage.domain()).toBe(URL);
159-
// });
160-
161-
// test("if no location origin or hostname, should return '*'", () => {
162-
// expect(avMessage.domain()).toBe(URL);
163-
// });
164192
});
165193

166194
test("isDomain should return true if domain() doesn't match regex", () => {

0 commit comments

Comments
 (0)