UNPKG

@boringnode/transmit

Version:

A framework agnostic Server-Sent-Event library

325 lines (324 loc) 12.1 kB
/* * @boringnode/transmit * * @license MIT * @copyright BoringNode */ import { randomUUID } from 'node:crypto'; import { test } from '@japa/runner'; import { Transmit } from '../src/transmit.js'; import { StreamManager } from '../src/stream_manager.js'; import { makeStream } from './fixtures/stream.js'; import { TransportMessageType } from '../src/transport_message_type.js'; import { makeTransmitWithTransport, makeTransport } from './fixtures/transmit.js'; test.group('Transmit', () => { test('should return the manager instance', async ({ assert }) => { const transmit = new Transmit({ transport: null, }); assert.instanceOf(transmit.getManager(), StreamManager); }); test('should call the authorization callback', async ({ assert }) => { const transmit = new Transmit({ transport: null, }); const uid = randomUUID(); let authorized = false; transmit.authorize('channel1', () => { authorized = true; return true; }); await transmit.subscribe({ channel: 'channel1', uid }); assert.isTrue(authorized); }); test('should call the authorization callback with the context', async ({ assert }) => { assert.plan(1); const transmit = new Transmit({ transport: null, }); const uid = randomUUID(); transmit.authorize('channel1', (context) => { assert.equal(context, 'foo'); return true; }); await transmit.subscribe({ channel: 'channel1', uid, context: 'foo' }); }); test('should authorize the subscription', async ({ assert }) => { const transmit = new Transmit({ transport: null, }); const stream = makeStream(transmit); transmit.authorize('channel1', () => { return true; }); const authorized = await transmit.subscribe({ channel: 'channel1', uid: stream.getUid() }); assert.isTrue(authorized); }); test('should not authorize the subscription', async ({ assert }) => { const transmit = new Transmit({ transport: null, }); const uid = randomUUID(); transmit.authorize('channel1', () => { return false; }); const authorized = await transmit.subscribe({ channel: 'channel1', uid }); assert.isFalse(authorized); }); test('should authorize with channel params', async ({ assert }) => { const transmit = new Transmit({ transport: null, }); const stream = makeStream(transmit); transmit.authorize('channel/:id', (_context, params) => { return params.id === '1'; }); const authorized = await transmit.subscribe({ channel: 'channel/1', uid: stream.getUid() }); const refused = await transmit.subscribe({ channel: 'channel/2', uid: stream.getUid() }); assert.isTrue(authorized); assert.isFalse(refused); }); test('should emit an connect event', async ({ assert }, done) => { assert.plan(2); const transmit = new Transmit({ transport: null, }); const uid = randomUUID(); let connected = false; transmit.on('connect', (params) => { connected = true; assert.equal(params.uid, uid); }); makeStream(transmit, uid); setTimeout(() => { assert.isTrue(connected); done(); }, 0); }).waitForDone(); test('should emit an subscribe event', async ({ assert }) => { assert.plan(3); const transmit = new Transmit({ transport: null, }); const stream = makeStream(transmit); let subscribed = false; transmit.on('subscribe', (params) => { subscribed = true; assert.equal(params.uid, stream.getUid()); assert.equal(params.channel, 'users/1'); }); await transmit.subscribe({ uid: stream.getUid(), channel: 'users/1', }); assert.isTrue(subscribed); }); test('should emit an unsubscribe event', async ({ assert }) => { assert.plan(3); const transmit = new Transmit({ transport: null, }); const uid = randomUUID(); let unsubscribed = false; transmit.on('unsubscribe', (params) => { unsubscribed = true; assert.equal(params.uid, uid); assert.equal(params.channel, 'users/1'); }); await transmit.unsubscribe({ uid, channel: 'users/1', }); assert.isTrue(unsubscribed); }); test('should emit a broadcast event when a message is broadcasted', async ({ assert }, done) => { assert.plan(3); const transmit = new Transmit({ transport: null, }); const payload = { foo: 'bar' }; let broadcasted = false; transmit.on('broadcast', (params) => { broadcasted = true; assert.equal(params.channel, 'users/1'); assert.equal(params.payload, payload); }); transmit.broadcast('users/1', payload); setTimeout(() => { assert.isTrue(broadcasted); done(); }, 0); }).waitForDone(); test('should ping all subscribers', async ({ assert, cleanup }, done) => { assert.plan(1); const transmit = new Transmit({ transport: null, pingInterval: 100, }); cleanup(() => transmit.shutdown()); const stream = makeStream(transmit, randomUUID()); stream.on('data', (message) => { //? Ignore the first message if (message === '\n') return; assert.include(message, '$$transmit/ping'); done(); }); }).waitForDone(); test('should broadcast a message to all listening clients', async ({ assert }) => { assert.plan(1); const transmit = new Transmit({ transport: null, }); const stream = makeStream(transmit); const stream2 = makeStream(transmit); await transmit.subscribe({ uid: stream.getUid(), channel: 'channel1', }); let dataReceived = false; stream.on('data', (message) => { //? Ignore the first message if (message === '\n') return; dataReceived = true; }); stream2.on('data', () => { assert.fail('Should not receive the broadcasted message'); }); transmit.broadcast('channel1', { message: 'hello' }); assert.isTrue(dataReceived); }); test('should broadcast a message to all listening clients except the sender', async ({ assert, }) => { assert.plan(1); const transmit = new Transmit({ transport: null, }); const stream = makeStream(transmit); const stream2 = makeStream(transmit); await transmit.subscribe({ uid: stream.getUid(), channel: 'channel1', }); await transmit.subscribe({ uid: stream2.getUid(), channel: 'channel1', }); let dataReceived = false; stream.on('data', (message) => { //? Ignore the first message if (message === '\n') return; dataReceived = true; }); stream2.on('data', () => { assert.fail('Should not receive the broadcasted message'); }); transmit.broadcastExcept('channel1', { message: 'hello' }, stream2.getUid()); assert.isTrue(dataReceived); }); test('should not broadcast to ourself when sending to the bus', async ({ assert }) => { const transport = makeTransport(); const transmit = makeTransmitWithTransport(transport); const stream = makeStream(transmit); await transmit.subscribe({ uid: stream.getUid(), channel: 'channel1', }); transmit.broadcast('channel1', { message: 'hello' }); assert.lengthOf(transport.transport.receivedMessages, 0); }); test('should broadcast to the bus when sending a message', async ({ assert }) => { const transport = makeTransport(); const transmit = makeTransmitWithTransport(transport); makeTransmitWithTransport(transport); const stream = makeStream(transmit); await transmit.subscribe({ uid: stream.getUid(), channel: 'channel1', }); transmit.broadcast('channel1', { message: 'hello' }); assert.lengthOf(transport.transport.receivedMessages, 1); assert.equal(transport.transport.receivedMessages[0].type, TransportMessageType.Broadcast); }); test('second instance should receive the broadcasted message', async ({ assert }) => { const transport = makeTransport(); const transmit = makeTransmitWithTransport(transport); const transmit2 = makeTransmitWithTransport(transport); const stream = makeStream(transmit); const stream2 = makeStream(transmit2); await transmit.subscribe({ uid: stream.getUid(), channel: 'channel1', }); await transmit2.subscribe({ uid: stream2.getUid(), channel: 'channel1', }); let dataReceived = false; stream.on('data', () => { dataReceived = true; }); transmit.broadcast('channel1', { message: 'hello' }); assert.isTrue(dataReceived); }); test('should broadcast falsy payloads without converting them to empty object', async ({ assert, }) => { const transmit = new Transmit({ transport: null, }); const stream = makeStream(transmit); await transmit.subscribe({ uid: stream.getUid(), channel: 'channel1', }); const receivedPayloads = []; stream.on('data', (message) => { if (message === '\n') return; const parsed = JSON.parse(message.replace('data: ', '')); receivedPayloads.push(parsed.payload); }); transmit.broadcast('channel1', 0); transmit.broadcast('channel1', false); transmit.broadcast('channel1', ''); assert.deepEqual(receivedPayloads, [0, false, '']); }); test('should return all subscribers for a channel', async ({ assert }) => { const transport = makeTransport(); const transmit = makeTransmitWithTransport(transport); const stream1 = makeStream(transmit); const stream2 = makeStream(transmit); const stream3 = makeStream(transmit); const stream4 = makeStream(transmit); const stream5 = makeStream(transmit); await transmit.subscribe({ uid: stream1.getUid(), channel: 'channel1', }); await transmit.subscribe({ uid: stream2.getUid(), channel: 'channel1', }); await transmit.subscribe({ uid: stream3.getUid(), channel: 'channel2', }); await transmit.subscribe({ uid: stream4.getUid(), channel: 'channel2', }); await transmit.subscribe({ uid: stream5.getUid(), channel: 'channel2', }); const uuidsChannel1 = transmit.getSubscribersFor('channel1'); const uuidsChannel2 = transmit.getSubscribersFor('channel2'); assert.lengthOf(uuidsChannel1, 2); assert.equal(uuidsChannel1[0], stream1.getUid()); assert.equal(uuidsChannel1[1], stream2.getUid()); assert.lengthOf(uuidsChannel2, 3); assert.equal(uuidsChannel2[0], stream3.getUid()); assert.equal(uuidsChannel2[1], stream4.getUid()); assert.equal(uuidsChannel2[2], stream5.getUid()); }); });