can-fixture-socket
Simulate socket.io services.
Object
can-fixture-socket
intercepts socket.io messages and simulates socket.io server responses.
The can-fixture-socket
module exports an object with:
- Server, a constructor function which instance intercepts the socket.io connection;
- requestHandlerToListener, a helper to convert XHR request handler into SocketEventListener;
- storeToListeners, a helper to convert all Store request handlers into SocketEventListener.
With three simple steps you can test your real-time application that uses socket.io:
- create a mock server that intercepts socket.io;
- mock server behavior;
- test your application.
import fixtureSocket from "can-fixture-socket";
// Import socket-io client:
import io from "socket.io-client";
// Create a mock server that intercepts socket.io:
const mockServer = new fixtureSocket.Server( io );
// Mock server behavior
mockServer.on( "connection", function() {
mockServer.emit( "notifications", { test: "OK" } );
} );
// Client. Create socket.io connection:
const socket = io( "http://localhost:8080/api" );
// Test your application:
socket.on( "connect", function() {
assert.ok( true, "socket connected" );
} );
socket.on( "notifications", function( data ) {
assert.deepEqual( data, { test: "OK" }, "received notifications message" );
} );
Use basics
Lets say we wanted to test a simple app that connects to socket.io
, and
once connected, creates a message, and logs when the message is created.
That app could look like the following:
const socket = io();
socket.on( "connect", function() {
socket.emit( "messages create", { text: "A new message" } );
} );
socket.on( "message created", function( data ) {
// data.text === "A new message"
console.log( "Server sent out a new message we just created", data );
} );
To test this, we'll first use can-fixture-socket.Server to intercept the socket connection:
import io from "socket.io-client";
import fixtureSocket from "can-fixture-socket";
const mockServer = new fixtureSocket.Server( io );
Now we can mock the socket server by creating socket event listeners and emitting socket events:
mockServer.on( "messages create", function( data ) {
console.log( "New message received", data );
mockServer.emit( "message created", data );
} );
To see this in action:
Acknowledgement callbacks
We also can use socket.io acknowledgement callbacks:
mockServer.on( "users create", function( user, ackCb ) {
console.log( "Simulating saving a new user to DB and return the new user id", user );
ackCB( {
id: Math.random()
} );
} );
Client code:
const socket = io();
socket.on( "connect", function() {
socket.emit( "users create", { name: "Ilya", likes: "skiing" }, function( data ) {
// data is what server calls the acknowledgement callback
// with (e.g. data.id is the new user id).
console.log( data.id );
} );
} );
Use with can-fixture.Store
With can-fixture store we can create a store of items and emulate a fully working CRUD service. Optionally, we can use Algebra to power our store filtering, pagination, and sorting abilities.
// Import can-fixture that provides `store` method for creating a store:
import fixture from "can-fixture";
import canSet from "can-set";
// Create a fixture store:
const messagesStore = fixture.store( [
{ id: 1, title: "One" },
{ id: 2, title: "Two" },
{ id: 3, title: "Three" }
], new canSet.Algebra( {} ) );
We can mock the socket.io connection with the rich behavior of fixture stores using the requestHandlerToListener helper. requestHandlerToListener
converts a fixture store request handler to a socket.io event listener.
import fixtureSocket from "can-fixture-socket";
import io from "socket.io-client";
const mockServer = new fixtureSocket.Server( io );
mockServer.on( "messages get", fixtureSocket.requestHandlerToListener( messagesStore.getData ) );
Or we can use storeToListeners helper to convert all CRUD fixture store request handlers into socket.io event listeners:
const listeners = fixtureSocket.storeToListeners( messagesStore );
mockServer.on( {
"messages remove": listeners.destroyData,
"messages create": listeners.createData,
"messages update": listeners.updateData
} );
Use with FeathersJS
Feathers is a minimalist, service-oriented, real-time web framework for modern applications. It is a NodeJS framework built on top of Express. It allows you to build REST-ful services and works with three providers: standard HTTP communication, WebSockets and Primus.
The mocked server exposes [can-fixture-socket.Server.prototype.onFeathers] method to simulate FeathersJS CRUD services.
For example, given the following FeathersJS client app:
const socket = io( "http://api.my-feathers-server.com" );
const app = feathers()
.configure( hooks() )
.configure( feathersSocketio( socket ) );
// Create FeathersJS CRUD service for "messages" resource:
const messagesService = app.service( "messages" );
We can simulate it with a store as follows:
const messagesStore = fixture.store( [
{ id: 1, title: "One" },
{ id: 2, title: "Two" },
{ id: 3, title: "Three" }
], new canSet.Algebra( {} ) );
mockServer.onFeathersService( "messages", fixtureStore );
Now you can test your FeathersJS app:
messagesService.find( {} ).then( function( data ) {
assert.equal( data.total, 3, "find should receive 3 items" );
} );
messagesService.get( 1 ).then( function( data ) {
assert.deepEqual( data, { id: 1, title: "One" }, "get should receive an item" );
} );
messagesService.create( { title: "Four" } ).then( function( data ) {
assert.equal( data.title, "Four", "create should add an new item" );
} );