Skip to content

Commit 14b7a8c

Browse files
authored
feat: add additional data to received message, move debugger to decorator (#15)
* feat: add additional data to received message, move debugger to decorator * test: update subscribe test * test: update all tests * test: fix bug when transform data on mock server * refactor: move subscribe logic to folder
1 parent ddb284f commit 14b7a8c

File tree

12 files changed

+138
-105
lines changed

12 files changed

+138
-105
lines changed

src/helpers.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/** Envelopes the content in a string of a certain length */
2+
export function formatString(text: string, count: number): string {
3+
const spaceString = ' '.repeat(count)
4+
return text + spaceString.substring(text.length)
5+
}
6+
7+
/** Converts milliseconds into a conveniently readable unit */
8+
export function fromMsToUp(ms: number): { value: number; unit: 'ms' | 's' | 'm' | 'h' } {
9+
if (ms < 1000) return { value: ms, unit: 'ms' }
10+
if (ms < 60000) return { value: ms / 1000, unit: 's' }
11+
if (ms < 3600000) return { value: ms / 60000, unit: 'm' }
12+
13+
return { value: ms / 3600000, unit: 'h' }
14+
}

src/index.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { type WSGOEventName, type WSGOConfig, type WSGOSubscriptions } from './types'
22

3-
import { type WSGOSubscribeCallback } from './subscribe'
4-
53
import { send } from './send'
64
import { subscribe } from './subscribe'
5+
import type { WSGOSubscribeCallback } from './subscribe/types'
76
import { heartbeatStart, heartbeatStop, listenHeartbeat } from './heartbeat'
87

98
/** Method allows you create new WebSocket connection */
@@ -63,7 +62,7 @@ export default function create(
6362
send(...args, ws, _config)
6463
},
6564
subscribe: (...args) => {
66-
subscribe(subscriptions, ...args)
65+
subscribe(...args, subscriptions, _config)
6766
},
6867
}
6968
}
@@ -112,15 +111,6 @@ function _listen(ws: WebSocket, subscriptions: WSGOSubscriptions, _config: WSGOC
112111
return
113112
}
114113

115-
if (_config.debugging) {
116-
if (message.event === 'exception') {
117-
console.error(message.data)
118-
} else {
119-
const { event, data, time } = message
120-
console.log(`%c${new Date(time).toLocaleTimeString()}%c`, 'color: gray', '', event, data)
121-
}
122-
}
123-
124114
if (message.event in subscriptions) {
125115
subscriptions[message.event](message)
126116
}

src/subscribe.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/subscribe/index.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { formatString, fromMsToUp } from '../helpers'
2+
import type { WSGOSubscribeResponse, WSGOSubscribeCallback } from './types'
3+
import type { WSGOEventName, WSGOConfig, WSGOSubscriptions } from '../types'
4+
5+
/** Method allows you to subscribe to listen to a specific event */
6+
export function subscribe<T>(
7+
eventName: WSGOEventName,
8+
callback: WSGOSubscribeCallback<T>,
9+
subscriptions: WSGOSubscriptions,
10+
_config: WSGOConfig,
11+
): void {
12+
if (eventName in subscriptions) return
13+
14+
callback = _subscribeDecoratorTransform<T>(callback, _config)
15+
16+
Object.assign(subscriptions, { [eventName]: callback })
17+
}
18+
19+
/** Decorator adds aditional data to received events */
20+
function _subscribeDecoratorTransform<T>(callback: WSGOSubscribeCallback<T>, _config: WSGOConfig): any {
21+
return (message: Omit<WSGOSubscribeResponse<T>, 'timeReceived'>) => {
22+
const transformedMessage: WSGOSubscribeResponse<T> = {
23+
...message,
24+
timeReceived: Date.now(),
25+
}
26+
27+
_subscribeDebugger(transformedMessage, _config)
28+
callback(transformedMessage)
29+
}
30+
}
31+
32+
function _subscribeDebugger(message: WSGOSubscribeResponse<any>, _config: WSGOConfig): void {
33+
if (!_config.debugging) return
34+
35+
if (message.event === 'exception') {
36+
console.error(message.data)
37+
return
38+
}
39+
40+
const { event, data, timeSended, timeReceived } = message
41+
const timeDiff = fromMsToUp(timeReceived - timeSended)
42+
43+
// console.log(`%c${new Date(timeReceived).toLocaleTimeString()}%c`, 'color: gray', '', event, data)
44+
// console.log(`%c${new Date(timeReceived).toLocaleTimeString()} %c${timeDiff}ms`, 'color: gray', 'color: green', event, data)
45+
console.log(
46+
`%c${new Date(timeReceived).toLocaleTimeString()} %c${formatString(`${timeDiff.value + timeDiff.unit}`, 5)}%c ${formatString(event, 30)}`,
47+
'color: gray',
48+
'color: green',
49+
'',
50+
data,
51+
)
52+
}

src/subscribe/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export interface WSGOSubscribeResponse<T = any> {
2+
/** Event name */
3+
event: string
4+
/** Event data */
5+
data: T
6+
/** Time when the server sent the event */
7+
timeSended: number
8+
/** Time when the client received the event */
9+
timeReceived: number
10+
}
11+
12+
export type WSGOSubscribeCallback<T> = (message: WSGOSubscribeResponse<T>) => any

test/close.test.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
22
import WSGO from '../src/index'
33
import ws from 'ws'
4+
import { createMockWSServer } from './utils'
45

56
describe('close', () => {
6-
let port = 0
7+
let port: number = 0
78
let server: ws.Server
89

910
beforeAll(() => {
10-
server = new ws.WebSocketServer({ port })
11+
const mockWSServer = createMockWSServer(port)
1112

12-
server.on('connection', (ws) => {
13-
ws.on('message', (data, isBinary) => {
14-
const message = isBinary ? data : data.toString()
15-
ws.send(message)
16-
})
17-
})
18-
19-
port = (server.address() as ws.AddressInfo).port
13+
server = mockWSServer.server
14+
port = mockWSServer.port
2015
})
2116

2217
afterAll(() => {

test/create.test.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
22
import WSGO from '../src/index'
33
import ws from 'ws'
4+
import { createMockWSServer } from './utils'
45

56
describe('create', () => {
6-
let port = 0
7+
let port: number = 0
78
let server: ws.Server
89

910
beforeAll(() => {
10-
server = new ws.WebSocketServer({ port })
11+
const mockWSServer = createMockWSServer(port)
1112

12-
server.on('connection', (ws) => {
13-
ws.on('message', (data, isBinary) => {
14-
const message = isBinary ? data : data.toString()
15-
ws.send(message)
16-
})
17-
})
18-
19-
port = (server.address() as ws.AddressInfo).port
13+
server = mockWSServer.server
14+
port = mockWSServer.port
2015
})
2116

2217
afterAll(() => {
@@ -52,4 +47,6 @@ describe('create', () => {
5247
// Assert
5348
expect(wsgo.ws).toBeUndefined()
5449
})
50+
51+
// TODO: write tests for options
5552
})

test/heartbeat.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import WSGO from '../src/index'
33
import ws from 'ws'
44
import { createMockWSServer } from './utils'
55

6-
describe('open', () => {
6+
describe('heartbeat', () => {
77
const date = new Date(2000, 1, 1)
88

99
let port: number = 0
@@ -50,7 +50,7 @@ describe('open', () => {
5050
)
5151

5252
// Assert
53-
expect(event).toStrictEqual({ event: eventName, timeSended: Date.now() })
53+
expect(event).toStrictEqual({ event: eventName, timeSended: Date.now(), timeReceived: Date.now() })
5454
})
5555

5656
it.todo('must close the connection if no response is received from the server')

test/open.test.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
22
import WSGO from '../src/index'
33
import ws from 'ws'
4+
import { createMockWSServer } from './utils'
45

56
describe('open', () => {
6-
let port = 0
7+
let port: number = 0
78
let server: ws.Server
89

910
beforeAll(() => {
10-
server = new ws.WebSocketServer({ port })
11+
const mockWSServer = createMockWSServer(port)
1112

12-
server.on('connection', (ws) => {
13-
ws.on('message', (data, isBinary) => {
14-
const message = isBinary ? data : data.toString()
15-
ws.send(message)
16-
})
17-
})
18-
19-
port = (server.address() as ws.AddressInfo).port
13+
server = mockWSServer.server
14+
port = mockWSServer.port
2015
})
2116

2217
afterAll(() => {
@@ -38,4 +33,6 @@ describe('open', () => {
3833
// check source data
3934
expect(wsgo.ws?.url).toBe(`ws://localhost:${port}/`)
4035
})
36+
37+
it.todo('should open new Websocket, after closing old', () => {})
4138
})

test/send.test.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,51 @@
1-
import { describe, it, expect, vitest, beforeAll, afterAll } from 'vitest'
1+
import { describe, it, expect, vi, beforeAll, afterAll } from 'vitest'
22
import WSGO from '../src/index'
33
import ws from 'ws'
4+
import { createMockWSServer } from './utils'
45

56
describe('send', () => {
6-
let port = 0
7+
const date = new Date(2000, 1, 1)
8+
9+
let port: number = 0
710
let server: ws.Server
811

912
beforeAll(() => {
10-
server = new ws.WebSocketServer({ port })
11-
12-
server.on('connection', (ws) => {
13-
ws.on('message', (data, isBinary) => {
14-
const message = isBinary ? data : data.toString()
15-
ws.send(message)
16-
})
17-
})
13+
const mockWSServer = createMockWSServer(port)
1814

19-
port = (server.address() as ws.AddressInfo).port
15+
server = mockWSServer.server
16+
port = mockWSServer.port
2017
})
2118

2219
afterAll(() => {
2320
server.close()
2421
})
2522

2623
it('should send an event to the server', async () => {
24+
const eventName = 'eventName'
25+
const eventData = { text: 'Hello World!' }
26+
2727
let event: any
2828

2929
// Arrange
3030
const wsgo = WSGO(`ws://localhost:${port}`)
31-
await vitest.waitFor(() => {
31+
await vi.waitFor(() => {
32+
vi.setSystemTime(date)
3233
if (wsgo.ws?.readyState !== window.WebSocket.OPEN) {
3334
throw new Error()
3435
}
3536
})
3637

3738
// Act
38-
wsgo.subscribe('eventName', (ev) => (event = ev))
39-
wsgo.send('eventName', { text: 'Hello World!' })
40-
await vitest.waitFor(() => {
39+
wsgo.subscribe(eventName, (ev) => (event = ev))
40+
wsgo.send(eventName, eventData)
41+
await vi.waitFor(() => {
42+
vi.setSystemTime(date)
4143
if (event === undefined) {
4244
throw new Error('Message not received back')
4345
}
4446
})
4547

4648
// Assert
47-
expect(wsgo.ws).toBeInstanceOf(window.WebSocket)
48-
expect(wsgo.ws?.readyState).toBe(window.WebSocket.OPEN)
49-
expect(event).toStrictEqual({ event: 'eventName', data: { text: 'Hello World!' } })
49+
expect(event).toStrictEqual({ event: eventName, data: eventData, timeSended: Date.now(), timeReceived: Date.now() })
5050
})
5151
})

0 commit comments

Comments
 (0)