@eleven-am/pondsocket 0.1.56 → 0.1.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/.eslintrc.json +387 -0
  2. package/dist/LICENSE +674 -0
  3. package/dist/README.md +139 -0
  4. package/dist/package.json +51 -0
  5. package/{types.d.ts → dist/types.d.ts} +0 -5
  6. package/jest.config.js +11 -0
  7. package/package.json +3 -3
  8. package/src/abstracts/abstractRequest.test.ts +49 -0
  9. package/src/abstracts/abstractRequest.ts +56 -0
  10. package/src/abstracts/abstractResponse.ts +26 -0
  11. package/src/abstracts/middleware.test.ts +75 -0
  12. package/src/abstracts/middleware.ts +50 -0
  13. package/src/channel/channel.test.ts +501 -0
  14. package/src/channel/channel.ts +305 -0
  15. package/src/channel/eventRequest.test.ts +37 -0
  16. package/src/channel/eventRequest.ts +27 -0
  17. package/src/channel/eventResponse.test.ts +249 -0
  18. package/src/channel/eventResponse.ts +172 -0
  19. package/src/client/channel.test.ts +799 -0
  20. package/src/client/channel.ts +342 -0
  21. package/src/client.ts +124 -0
  22. package/src/endpoint/endpoint.test.ts +825 -0
  23. package/src/endpoint/endpoint.ts +304 -0
  24. package/src/endpoint/response.ts +106 -0
  25. package/src/enums.ts +52 -0
  26. package/src/errors/pondError.ts +32 -0
  27. package/src/express.ts +58 -0
  28. package/src/index.ts +3 -0
  29. package/src/lobby/JoinRequest.test.ts +48 -0
  30. package/src/lobby/JoinResponse.test.ts +162 -0
  31. package/src/lobby/joinRequest.ts +32 -0
  32. package/src/lobby/joinResponse.ts +146 -0
  33. package/src/lobby/lobby.ts +182 -0
  34. package/src/matcher/matcher.test.ts +103 -0
  35. package/src/matcher/matcher.ts +105 -0
  36. package/src/node.ts +33 -0
  37. package/src/presence/presence.ts +127 -0
  38. package/src/presence/presenceEngine.test.ts +143 -0
  39. package/src/server/pondSocket.ts +153 -0
  40. package/src/subjects/subject.test.ts +163 -0
  41. package/src/subjects/subject.ts +137 -0
  42. package/src/typedefs.d.ts +451 -0
  43. package/src/types.d.ts +89 -0
  44. package/tsconfig.build.json +7 -0
  45. package/tsconfig.json +12 -0
  46. /package/{abstracts → dist/abstracts}/abstractRequest.js +0 -0
  47. /package/{abstracts → dist/abstracts}/abstractResponse.js +0 -0
  48. /package/{abstracts → dist/abstracts}/middleware.js +0 -0
  49. /package/{channel → dist/channel}/channel.js +0 -0
  50. /package/{channel → dist/channel}/eventRequest.js +0 -0
  51. /package/{channel → dist/channel}/eventResponse.js +0 -0
  52. /package/{client → dist/client}/channel.js +0 -0
  53. /package/{client.d.ts → dist/client.d.ts} +0 -0
  54. /package/{client.js → dist/client.js} +0 -0
  55. /package/{endpoint → dist/endpoint}/endpoint.js +0 -0
  56. /package/{endpoint → dist/endpoint}/response.js +0 -0
  57. /package/{enums.js → dist/enums.js} +0 -0
  58. /package/{errors → dist/errors}/pondError.js +0 -0
  59. /package/{express.d.ts → dist/express.d.ts} +0 -0
  60. /package/{express.js → dist/express.js} +0 -0
  61. /package/{index.d.ts → dist/index.d.ts} +0 -0
  62. /package/{index.js → dist/index.js} +0 -0
  63. /package/{lobby → dist/lobby}/joinRequest.js +0 -0
  64. /package/{lobby → dist/lobby}/joinResponse.js +0 -0
  65. /package/{lobby → dist/lobby}/lobby.js +0 -0
  66. /package/{matcher → dist/matcher}/matcher.js +0 -0
  67. /package/{node.d.ts → dist/node.d.ts} +0 -0
  68. /package/{node.js → dist/node.js} +0 -0
  69. /package/{presence → dist/presence}/presence.js +0 -0
  70. /package/{server → dist/server}/pondSocket.js +0 -0
  71. /package/{subjects → dist/subjects}/subject.js +0 -0
@@ -0,0 +1,162 @@
1
+ import { JoinResponse } from './joinResponse';
2
+ import { createChannelEngine } from '../channel/eventResponse.test';
3
+ import { RequestCache } from '../endpoint/endpoint';
4
+ import { ErrorTypes, ServerActions, ChannelReceiver } from '../enums';
5
+
6
+ const createPondResponse = () => {
7
+ const channelEngine = createChannelEngine();
8
+
9
+ const socket: RequestCache = {
10
+ clientId: 'sender',
11
+ assigns: { assign: 'assign' },
12
+ channelName: 'channel',
13
+ socket: {
14
+ send: jest.fn(),
15
+ } as any,
16
+ };
17
+
18
+ const response = new JoinResponse(socket, channelEngine);
19
+
20
+ return {
21
+ channelEngine,
22
+ socket,
23
+ response,
24
+ };
25
+ };
26
+
27
+
28
+ describe('JoinResponse', () => {
29
+ it('should create a new PondChannelResponse', () => {
30
+ const { response } = createPondResponse();
31
+
32
+ expect(response).toBeDefined();
33
+ });
34
+
35
+ it('should accept the request', () => {
36
+ const { response, channelEngine, socket } = createPondResponse();
37
+ // spy on the channelEngine to see if the user was added
38
+
39
+ jest.spyOn(channelEngine, 'addUser');
40
+ response.accept();
41
+
42
+ // check if the response was sent
43
+ expect(channelEngine.addUser).toHaveBeenCalledWith(socket.clientId, socket.assigns, expect.any(Function));
44
+ expect(channelEngine.getUserData(socket.clientId)).not.toBeNull();
45
+ });
46
+
47
+ it('should reject the request', () => {
48
+ const { response, channelEngine, socket } = createPondResponse();
49
+ // spy on the channelEngine to see if the user was added
50
+
51
+ jest.spyOn(channelEngine, 'addUser');
52
+ response.reject();
53
+
54
+ // check if the response was sent
55
+ expect(channelEngine.addUser).not.toHaveBeenCalled();
56
+ expect(channelEngine.getUserData(socket.clientId)).toBeUndefined();
57
+
58
+ // also check if the socket was sent a message
59
+ expect(socket.socket.send).toHaveBeenCalledWith(JSON.stringify({
60
+ event: ErrorTypes.UNAUTHORIZED_JOIN_REQUEST,
61
+ payload: {
62
+ message: 'Request to join channel test rejected: Unauthorized request',
63
+ code: 403,
64
+ },
65
+ channelName: 'test',
66
+ action: ServerActions.ERROR,
67
+ }));
68
+ });
69
+
70
+ it('should send a direct message', () => {
71
+ const { response, channelEngine, socket } = createPondResponse();
72
+ // spy on the channelEngine to see if the user was added
73
+
74
+ jest.spyOn(channelEngine, 'addUser');
75
+ response.send('POND_MESSAGE', { message: 'message' });
76
+
77
+ // check if the response was sent
78
+ expect(channelEngine.addUser).toHaveBeenCalled();
79
+ expect(channelEngine.getUserData(socket.clientId)).toStrictEqual({
80
+ assigns: {
81
+ assign: 'assign',
82
+ },
83
+ id: 'sender',
84
+ presence: {},
85
+ });
86
+
87
+ // also check if the socket was sent a message
88
+ expect(socket.socket.send).toHaveBeenCalledWith(JSON.stringify({
89
+ channelName: 'test',
90
+ action: ServerActions.SYSTEM,
91
+ payload: {
92
+ message: 'message',
93
+ },
94
+ event: 'POND_MESSAGE',
95
+ }));
96
+ });
97
+
98
+ // auxiliary functions
99
+ it('should send messages to different users', () => {
100
+ const { response, channelEngine } = createPondResponse();
101
+ // spy on the channelEngine to see if any messages were published
102
+ const broadcast = jest.spyOn(channelEngine, 'sendMessage');
103
+
104
+ // add a second user to the channel
105
+ channelEngine.addUser('user2', { assign: 'assign' }, () => {});
106
+
107
+ // send a message to a single user
108
+ // this is because the sender does not exist in the channel yet
109
+ expect(() => response.sendToUsers('hello_everyone', { message: 'hello' }, ['user2'])).toThrow();
110
+
111
+ // clear the spy
112
+ broadcast.mockClear();
113
+
114
+ // add the sender to the channel by using the response.accept() method
115
+ response.accept().sendToUsers('hello_everyone', { message: 'hello' }, ['user2']);
116
+
117
+ // check if the message was sent
118
+ expect(broadcast).toHaveBeenCalledWith('sender', ['user2'], ServerActions.BROADCAST, 'hello_everyone', { message: 'hello' });
119
+
120
+ // clear the spy
121
+ broadcast.mockClear();
122
+
123
+ // send a message to all users
124
+ response.broadcast('hello_everyone', { message: 'hello' });
125
+ expect(broadcast).toHaveBeenCalledWith('sender', ChannelReceiver.ALL_USERS, ServerActions.BROADCAST, 'hello_everyone', { message: 'hello' });
126
+
127
+ // clear the spy
128
+ broadcast.mockClear();
129
+
130
+ // send a message to all users except the sender
131
+ response.broadcastFromUser('hello_everyone', { message: 'hello' });
132
+ expect(broadcast).toHaveBeenCalledWith('sender', ChannelReceiver.ALL_EXCEPT_SENDER, ServerActions.BROADCAST, 'hello_everyone', { message: 'hello' });
133
+ });
134
+
135
+ it('should be able to track the presence of users', () => {
136
+ const { response, channelEngine } = createPondResponse();
137
+
138
+ // spy on the channelEngine to see if the trackPresence method was called
139
+ const trackPresence = jest.spyOn(channelEngine, 'trackPresence');
140
+
141
+ // add a second user to the channel
142
+ response.accept()
143
+ .trackPresence({
144
+ status: 'online',
145
+ });
146
+
147
+ // check if the trackPresence method was called
148
+ expect(trackPresence).toHaveBeenCalledWith('sender', { status: 'online' });
149
+ });
150
+
151
+ it('should throw an error if accept, reject / send is called more than once', () => {
152
+ const { response, channelEngine, socket } = createPondResponse();
153
+
154
+ jest.spyOn(channelEngine, 'addUser');
155
+ expect(channelEngine.addUser).not.toHaveBeenCalled();
156
+ response.accept();
157
+ expect(channelEngine.addUser).toHaveBeenCalledWith(socket.clientId, socket.assigns, expect.any(Function));
158
+ expect(() => response.accept()).toThrowError('Request to join channel test rejected: Request already executed');
159
+ expect(() => response.reject()).toThrowError('Request to join channel test rejected: Request already executed');
160
+ expect(() => response.send('event', { payload: 'payload' })).toThrowError('Request to join channel test rejected: Request already executed');
161
+ });
162
+ });
@@ -0,0 +1,32 @@
1
+ import { AbstractRequest } from '../abstracts/abstractRequest';
2
+ import { ChannelEngine } from '../channel/channel';
3
+ import { RequestCache } from '../endpoint/endpoint';
4
+ // eslint-disable-next-line import/no-unresolved
5
+ import { JoinParams, UserData, PondAssigns } from '../types';
6
+
7
+ export class JoinRequest<Path extends string> extends AbstractRequest<Path> {
8
+ readonly #params: JoinParams;
9
+
10
+ readonly #clientId: string;
11
+
12
+ readonly #assigns: PondAssigns;
13
+
14
+ constructor (event: RequestCache, params: JoinParams, engine: ChannelEngine) {
15
+ super(engine.name, engine, params);
16
+ this.#params = params;
17
+ this.#clientId = event.clientId;
18
+ this.#assigns = event.assigns;
19
+ }
20
+
21
+ public get joinParams (): JoinParams {
22
+ return this.#params;
23
+ }
24
+
25
+ public get user (): UserData {
26
+ return {
27
+ id: this.#clientId,
28
+ assigns: this.#assigns,
29
+ presence: {},
30
+ };
31
+ }
32
+ }
@@ -0,0 +1,146 @@
1
+ import { PondResponse } from '../abstracts/abstractResponse';
2
+ import { ChannelEngine } from '../channel/channel';
3
+ import { RequestCache } from '../endpoint/endpoint';
4
+ import { ErrorTypes, ServerActions, SystemSender, ChannelReceiver, Events } from '../enums';
5
+ import { ChannelError } from '../errors/pondError';
6
+ // eslint-disable-next-line import/no-unresolved
7
+ import { PondAssigns, ChannelEvent, PondMessage, PondPresence } from '../types';
8
+
9
+ export class JoinResponse extends PondResponse {
10
+ readonly #user: RequestCache;
11
+
12
+ readonly #engine: ChannelEngine;
13
+
14
+ #executed: boolean;
15
+
16
+ constructor (user: RequestCache, engine: ChannelEngine) {
17
+ super();
18
+ this.#user = user;
19
+ this.#engine = engine;
20
+ this.#executed = false;
21
+ }
22
+
23
+ /**
24
+ * @desc Accepts the request and optionally assigns data to the client
25
+ * @param assigns - the data to assign to the client
26
+ */
27
+ public accept (assigns?: PondAssigns): JoinResponse {
28
+ this.#performChecks();
29
+
30
+ const newAssigns = {
31
+ ...assigns || {},
32
+ ...this.#user.assigns,
33
+ };
34
+
35
+ const acknowledgement: ChannelEvent = {
36
+ action: ServerActions.SYSTEM,
37
+ channelName: this.#engine.name,
38
+ event: Events.ACKNOWLEDGE,
39
+ payload: {},
40
+ };
41
+
42
+ this.#user.socket.send(JSON.stringify(acknowledgement));
43
+ this.#engine.addUser(this.#user.clientId, newAssigns, (event) => {
44
+ this.#user.socket.send(JSON.stringify(event));
45
+ });
46
+
47
+ return this;
48
+ }
49
+
50
+ /**
51
+ * @desc Rejects the request and optionally assigns data to the client
52
+ * @param message - the error message
53
+ * @param errorCode - the error code
54
+ */
55
+ public reject (message?: string, errorCode?: number): JoinResponse {
56
+ this.#performChecks();
57
+
58
+ const text = `Request to join channel ${this.#engine.name} rejected: ${message || 'Unauthorized request'}`;
59
+
60
+ const errorMessage: ChannelEvent = {
61
+ event: ErrorTypes.UNAUTHORIZED_JOIN_REQUEST,
62
+ payload: {
63
+ message: text,
64
+ code: errorCode || 403,
65
+ },
66
+ channelName: this.#engine.name,
67
+ action: ServerActions.ERROR,
68
+ };
69
+
70
+ this.#user.socket.send(JSON.stringify(errorMessage));
71
+
72
+ return this;
73
+ }
74
+
75
+ /**
76
+ * @desc Emits a direct message to the client
77
+ * @param event - the event name
78
+ * @param payload - the payload to send
79
+ * @param assigns - the data to assign to the client
80
+ */
81
+ public send (event: string, payload: PondMessage, assigns?: PondAssigns) {
82
+ this.accept(assigns);
83
+ this.#engine.sendMessage(SystemSender.CHANNEL, [this.#user.clientId], ServerActions.SYSTEM, event, payload);
84
+
85
+ return this;
86
+ }
87
+
88
+ /**
89
+ * @desc Emits a message to all clients in the channel
90
+ * @param event - the event name
91
+ * @param payload - the payload to send
92
+ */
93
+ public broadcast (event: string, payload: PondMessage): JoinResponse {
94
+ this.#engine.sendMessage(this.#user.clientId, ChannelReceiver.ALL_USERS, ServerActions.BROADCAST, event, payload);
95
+
96
+ return this;
97
+ }
98
+
99
+ /**
100
+ * @desc Emits a message to all clients in the channel except the sender
101
+ * @param event - the event name
102
+ * @param payload - the payload to send
103
+ */
104
+ public broadcastFromUser (event: string, payload: PondMessage): JoinResponse {
105
+ this.#engine.sendMessage(this.#user.clientId, ChannelReceiver.ALL_EXCEPT_SENDER, ServerActions.BROADCAST, event, payload);
106
+
107
+ return this;
108
+ }
109
+
110
+ /**
111
+ * @desc Emits a message to a specific set of clients
112
+ * @param event - the event name
113
+ * @param payload - the payload to send
114
+ * @param userIds - the ids of the clients to send the message to
115
+ */
116
+ public sendToUsers (event: string, payload: PondMessage, userIds: string[]): JoinResponse {
117
+ this.#engine.sendMessage(this.#user.clientId, userIds, ServerActions.BROADCAST, event, payload);
118
+
119
+ return this;
120
+ }
121
+
122
+ /**
123
+ * @desc tracks the presence of a client
124
+ * @param presence - the presence data to track
125
+ */
126
+ public trackPresence (presence: PondPresence): JoinResponse {
127
+ this.#engine.trackPresence(this.#user.clientId, presence);
128
+
129
+ return this;
130
+ }
131
+
132
+ /**
133
+ * @desc Performs checks to ensure the response has not been executed
134
+ * @private
135
+ */
136
+ #performChecks (): void {
137
+ if (this.#executed) {
138
+ const message = `Request to join channel ${this.#engine.name} rejected: Request already executed`;
139
+ const code = 403;
140
+
141
+ throw new ChannelError(message, code, this.#engine.name);
142
+ }
143
+
144
+ this.#executed = true;
145
+ }
146
+ }
@@ -0,0 +1,182 @@
1
+ import { Middleware } from '../abstracts/middleware';
2
+ import { ChannelEngine, ParentEngine } from '../channel/channel';
3
+ import { EventRequest } from '../channel/eventRequest';
4
+ import { EventResponse } from '../channel/eventResponse';
5
+ import { ServerActions, ChannelReceiver, SystemSender } from '../enums';
6
+ // eslint-disable-next-line import/no-unresolved
7
+ import { PondPath, PondMessage } from '../types';
8
+
9
+ export class LobbyEngine {
10
+ readonly #channels: Set<ChannelEngine>;
11
+
12
+ readonly #middleware: Middleware<EventRequest<string>, EventResponse>;
13
+
14
+ constructor () {
15
+ this.#channels = new Set<ChannelEngine>();
16
+ this.#middleware = new Middleware();
17
+ }
18
+
19
+ /**
20
+ * @desc Handles an event request made by a user
21
+ * @param event - The event to listen for
22
+ * @param handler - The handler to execute when the event is received
23
+ * @example
24
+ * pond.onEvent('echo', (request, response) => {
25
+ * response.send('echo', {
26
+ * message: request.event.payload,
27
+ * });
28
+ * });
29
+ */
30
+ public onEvent<Event extends string> (event: PondPath<Event>, handler: (request: EventRequest<Event>, response: EventResponse) => void | Promise<void>) {
31
+ this.#middleware.use((request, response, next) => {
32
+ if (request._parseQueries(event)) {
33
+ return handler(request as EventRequest<Event>, response);
34
+ }
35
+
36
+ next();
37
+ });
38
+ }
39
+
40
+ /**
41
+ * @desc Broadcasts a message to all users in a channel
42
+ * @param event - The event to broadcast
43
+ * @param payload - The payload to send
44
+ * @param channelName - The channel to broadcast to (if not specified, broadcast to all channels)
45
+ * @example
46
+ * pond.broadcast('echo', {
47
+ * message: 'Hello World',
48
+ * timestamp: Date.now(),
49
+ * channel: 'my_channel',
50
+ *});
51
+ */
52
+ public broadcast (event: string, payload: PondMessage, channelName?: string) {
53
+ if (channelName) {
54
+ const channel = this.getChannel(channelName) || this.createChannel(channelName);
55
+
56
+ channel.sendMessage(SystemSender.CHANNEL, ChannelReceiver.ALL_USERS, ServerActions.SYSTEM, event, payload);
57
+ } else {
58
+ this.#channels.forEach((channel) => {
59
+ channel.sendMessage(SystemSender.CHANNEL, ChannelReceiver.ALL_USERS, ServerActions.SYSTEM, event, payload);
60
+ });
61
+ }
62
+ }
63
+
64
+ /**
65
+ * @desc Removes a user from all channels
66
+ * @param clientId - The client id of the user to remove
67
+ * @param graceful - Whether to gracefully remove the user or not
68
+ */
69
+ public removeUser (clientId: string, graceful = false) {
70
+ this.#channels.forEach((channel) => {
71
+ channel.removeUser(clientId, graceful);
72
+ });
73
+ }
74
+
75
+ /**
76
+ * @desc Executes a function on a channel
77
+ * @param channelName - The name of the channel to execute the function on
78
+ * @param handler - The function to execute
79
+ * @private
80
+ */
81
+ public execute<Return> (channelName: string, handler: ((channel: ChannelEngine) => Return)) {
82
+ const newChannel = this.getChannel(channelName);
83
+
84
+ if (newChannel) {
85
+ return handler(newChannel);
86
+ }
87
+
88
+ throw new Error(`GatewayEngine: Channel ${channelName} does not exist`);
89
+ }
90
+
91
+ /**
92
+ * @desc Gets a channel by name
93
+ * @param channelName - The name of the channel to get
94
+ * @private
95
+ */
96
+ public getChannel (channelName: string): ChannelEngine | undefined {
97
+ return Array.from(this.#channels)
98
+ .find((channel) => channel.name === channelName);
99
+ }
100
+
101
+ /**
102
+ * @desc Destroys a channel
103
+ * @param channel - The name of the channel to destroy
104
+ * @private
105
+ */
106
+ public destroyChannel (channel: string) {
107
+ const newChannel = this.getChannel(channel);
108
+
109
+ if (newChannel) {
110
+ this.#channels.delete(newChannel);
111
+ }
112
+ }
113
+
114
+ /**
115
+ * @desc Lists all channels
116
+ * @private
117
+ */
118
+ public listChannels () {
119
+ return Array.from(this.#channels)
120
+ .map((channel) => channel.name);
121
+ }
122
+
123
+ /**
124
+ * @desc Creates a new channel
125
+ * @param channelName - The name of the channel to create
126
+ * @private
127
+ */
128
+ public createChannel (channelName: string): ChannelEngine {
129
+ const destroyChannel = this.destroyChannel.bind(this, channelName);
130
+ const execute = this.#middleware.run.bind(this.#middleware);
131
+
132
+ const parentEngine: ParentEngine = {
133
+ execute,
134
+ destroyChannel,
135
+ };
136
+
137
+ const newChannel: ChannelEngine = new ChannelEngine(channelName, parentEngine);
138
+
139
+ this.#channels.add(newChannel);
140
+
141
+ return newChannel;
142
+ }
143
+ }
144
+
145
+ export class PondChannel {
146
+ readonly #lobby: LobbyEngine;
147
+
148
+ constructor (lobby: LobbyEngine) {
149
+ this.#lobby = lobby;
150
+ }
151
+
152
+ /**
153
+ * @desc Handles an event request made by a user
154
+ * @param event - The event to listen for
155
+ * @param handler - The handler to execute when the event is received
156
+ * @example
157
+ * pond.onEvent('echo', (request, response) => {
158
+ * response.send('echo', {
159
+ * message: request.event.payload,
160
+ * });
161
+ * });
162
+ */
163
+ public onEvent<Event extends string> (event: PondPath<Event>, handler: (request: EventRequest<Event>, response: EventResponse) => void | Promise<void>) {
164
+ this.#lobby.onEvent(event, handler);
165
+ }
166
+
167
+ /**
168
+ * @desc Broadcasts a message to all users in a channel
169
+ * @param event - The event to broadcast
170
+ * @param payload - The payload to send
171
+ * @param channelName - The channel to broadcast to (if not specified, broadcast to all channels)
172
+ * @example
173
+ * pond.broadcast('echo', {
174
+ * message: 'Hello World',
175
+ * timestamp: Date.now(),
176
+ * channel: 'my_channel',
177
+ *});
178
+ */
179
+ public broadcast (event: string, payload: PondMessage, channelName?: string) {
180
+ this.#lobby.broadcast(event, payload, channelName);
181
+ }
182
+ }
@@ -0,0 +1,103 @@
1
+ import { parseAddress } from './matcher';
2
+
3
+ describe('parseAddress', () => {
4
+ it('should return null if a string does not match a regex and {} if it does', () => {
5
+ const regex = new RegExp(/^test/);
6
+
7
+ expect(parseAddress(regex, 'test')).toStrictEqual({
8
+ params: {},
9
+ query: {},
10
+ });
11
+
12
+ const regex2 = new RegExp(/^test2/);
13
+
14
+ expect(parseAddress(regex2, 'test')).toBe(null);
15
+ });
16
+
17
+ it('should return the params of a string matching the pattern', () => {
18
+ const pattern = '/test/:id';
19
+ const secondPattern = '/test/:id/:id2';
20
+ const string = '/test/5';
21
+ const secondString = '/test/5/6';
22
+
23
+ expect(parseAddress(pattern, string))
24
+ .toStrictEqual({
25
+ params: {
26
+ id: '5',
27
+ },
28
+ query: {},
29
+ });
30
+
31
+ expect(parseAddress(secondPattern, secondString))
32
+ .toStrictEqual({
33
+ params: {
34
+ id: '5',
35
+ id2: '6',
36
+ },
37
+ query: {},
38
+ });
39
+
40
+ expect(parseAddress(pattern, secondString))
41
+ .toBe(null);
42
+
43
+ expect(parseAddress(secondPattern, string))
44
+ .toBe(null);
45
+ });
46
+
47
+ it('should not match colons without slashes', () => {
48
+ const pattern = '/test:id';
49
+ const string = '/test5';
50
+
51
+ expect(parseAddress(pattern, string))
52
+ .toBe(null);
53
+ });
54
+
55
+ it('should match when there is a *', () => {
56
+ const pattern = '/test/:id/*';
57
+ const string = '/test/5/6';
58
+
59
+ expect(parseAddress(pattern, string))
60
+ .toStrictEqual({
61
+ params: {
62
+ id: '5',
63
+ },
64
+ query: {},
65
+ });
66
+
67
+ const secondPattern = '*';
68
+ const secondString = '/test/5/6';
69
+
70
+ expect(parseAddress(secondPattern, secondString))
71
+ .toStrictEqual({
72
+ params: {},
73
+ query: {},
74
+ });
75
+ });
76
+
77
+ it('should return the query of string', () => {
78
+ const pattern = '/test/:id';
79
+ const string = '/test/5?test=5';
80
+ const secondString = '/test/5?test=5&test2=6';
81
+
82
+ expect(parseAddress(pattern, string))
83
+ .toStrictEqual({
84
+ params: {
85
+ id: '5',
86
+ },
87
+ query: {
88
+ test: '5',
89
+ },
90
+ });
91
+
92
+ expect(parseAddress(pattern, secondString))
93
+ .toStrictEqual({
94
+ params: {
95
+ id: '5',
96
+ },
97
+ query: {
98
+ test: '5',
99
+ test2: '6',
100
+ },
101
+ });
102
+ });
103
+ });