UNPKG

xrs

Version:

reactive server

171 lines (138 loc) 5.73 kB
const { test } = require('tap') , { str, emitterify, extend, delay, values } = require('utilise/pure') , { stringify } = JSON , nanosocket = require('nanosocket/fake') , xclient = require('./client') , { Blob, fakeTimeout } = require('global-mocks') , window = global.window = { Blob, setTimeout: fakeTimeout } , collect = (stream, count) => stream .reduce((acc = [], d) => (acc.push(d), acc)) .filter(d => d.length === count) test('should send request and unsubscribe', async ({ plan, same }) => { plan(8) const socket = nanosocket() , xrs = xclient({ socket }) , output = xrs.send({ name: 'trades', type: 'ACTIVE', top: 10 }) // request sent same(xrs.subscriptions.length, 1, 'subscription created') const { id, count } = await output.once('sent') same(id, 1, 'increment subscription number') same(count, 0, 'updates on that subscription') // await replies const replies = collect(output, 3) // send replies socket.emit('recv', stringify({ id: '10', data: { type: 'fail' }})) socket.emit('recv', stringify({ id, data: { type: 'update', value: {}}})) socket.emit('recv', stringify({ id, data: { type: 'update', value: { price: 10 }, key: 'foo' }})) socket.emit('recv', stringify({ id, data: { type: 'update', value: { price: 20 }, key: 'bar' }})) // unsubscribe const unsubscribe = output.source.emit('stop').pop() same(xrs.subscriptions.length, 1, 'subscription destroyed, waiting for unsubscribe response') socket.emit('recv', stringify({ id: '2', data: 'uack' })) same(await unsubscribe, 'uack', 'unsubscribe ack') same(xrs.subscriptions.length, 0, 'subscriptions all destroyed') same(await replies, [ { type: 'update', value: {} } , { type: 'update', value: { price: 10 }, key: 'foo' } , { type: 'update', value: { price: 20 }, key: 'bar' } ], 'replies') same(socket.sent, [ str({ id: '1', data: { name: 'trades', type: 'ACTIVE', top: 10 }}) , str({ id: '2', data: '1', type: 'UNSUBSCRIBE' }) ]) }) test('should send stream, change and unsubscribe', async ({ plan, same }) => { plan(6) const socket = nanosocket() , xrs = xclient({ socket }) , input = emitterify().on('change') , output = xrs.send(input) // request sent same(xrs.subscriptions.length, 1, 'subscription created') const sent = collect(output.on('sent'), 2) input.next({ name: 'trades', type: 'ACTIVE', top: 10 }) input.next({ name: 'trades', type: 'ACTIVE', top: 20 }) // unsubscribe const unsubscribe = output.source.emit('stop').pop() same(xrs.subscriptions.length, 1, 'subscription destroyed, waiting for unsubscribe response') socket.emit('recv', stringify({ id: '2', data: 'uack' })) same(await unsubscribe, 'uack', 'unsubscribe ack') same(xrs.subscriptions.length, 0, 'subscription destroyed') same(await sent, [ { id: 1, count: 0 } , { id: 1, count: 1 } ], 'messages sent') same(socket.sent, [ str({ id: '1', data: { name: 'trades', type: 'ACTIVE', top: 10 }}) , str({ id: '1', data: { name: 'trades', type: 'ACTIVE', top: 20 }}) , str({ id: '2', data: '1', type: 'UNSUBSCRIBE' }) ]) }) test('should evaluate exec responses', async ({ plan, same }) => { plan(1) const socket = nanosocket() , { send } = xclient({ socket }) , output = send({}) socket.emit('recv', '{"id":"1","data":{"exec":(o, v) => o.next(v*2),"value":2}}') same(await output, 4, 'reply') }) test('should send binaries', async ({ plan, same }) => { plan(4) const socket = nanosocket() , { send } = xclient({ socket }) , output = send(new Blob({ size: 2000 }), 'meta') await output.once('sent') socket.emit('recv', '{"id":"1","data":"back"}') output.once('progress', d => same(d, { received: 1024, total: 2000 }), 'progress 1') socket.emit('recv', '{"id":"1","data":{"exec":(o, v) => o.emit(\'progress\', v),"value":1024}}') output.once('progress', d => same(d, { received: 2000, total: 2000 }), 'progress 2') socket.emit('recv', '{"id":"1","data":{"exec":(o, v) => o.emit(\'progress\', v),"value":2000}}') same(socket.sent, [ str({ id: '1', data: { size: 2000, meta: 'meta' }, type: 'BINARY' }) , { start: 0, end: 1024 } , { start: 1024, end: 2000 } ]) same(await output, 'back' ) }) test('should continue subscriptions during reconnect', async ({ plan, same }) => { plan(2) const socket = nanosocket() , { send } = xclient({ socket }) , output = send('foo') const replies = collect(output, 2) // reply before reconnect socket.emit('recv', stringify({ id: '1', data: 'reply 1' })) socket.emit('disconnected') socket.emit('connected') // reply after reconnect socket.emit('recv', stringify({ id: '1', data: 'reply 2' })) same(await replies, [ 'reply 1' , 'reply 2' ]) same(socket.sent, [ str({ id: '1', data: 'foo' }) , str({ id: '1', data: 'foo' }) ]) }) test('should not duplicate resubscriptions during backoff', async ({ plan, same }) => { plan(1) const socket = nanosocket() , { send } = xclient({ socket }) , output = send('foo') socket.emit('disconnected') socket.emit('disconnected') socket.emit('disconnected') socket.emit('disconnected') socket.emit('connected') socket.emit('disconnected') socket.emit('disconnected') socket.emit('disconnected') socket.emit('disconnected') socket.emit('connected') same(socket.sent, [ str({ id: '1', data: 'foo' }) , str({ id: '1', data: 'foo' }) , str({ id: '1', data: 'foo' }) ]) })