Hacking Meteor DDP

5,708 reads

the meteor by ready2freeze

TD;DR, Track all messages going through the DPP connection of your Meteor application by monitoring the Meteor.connection._stream.

Creating functional tests on Meteor can be a pain. It’s reactivity is great for UX, but things can get complicated when we are talking about functional testing.

On this project i’ve been working on, we were using Nightwatch to write our functional tests. This tool runs browser testing in a Selenium server and allows us to write test specifications with Nodejs.

Some weeks ago i was trying to figure out how to wait for the result of a Meteor’s Method before triggering a click command on some button in one page of the project’s web site.

There wasn’t an easy way of waiting for this result. Also, we try to avoid using the pause command that Nightwatch provides.

A lot of bad things can happen when someone infers how much time is necessary to wait for a computation to be completed, e.g., waiting for some CSS class is added to a div after the form is submitted.

Since pause was not an option, i needed another way of waiting for the result of this Method. After some investigation, i’ve come up with the idea of listening to DDP messages.

Meteor’s DDP

DDP is Meteor’s built-in pub/sub and RPC protocol

There are already many articles on the internet which will give you a nice introduction to the DDP protocol. You can also read more about DDP on the Meteor’s documentation at this link.

In short, DDP is a JSON based protocol which Meteor had implemented on top of SockJS. It serves to create a full duplex communication between client and server where it can change data and react to its changes.

SockJS is a Javascript library that emulates WebSockets

When you use Meteor.method, Meteor.call, Meteor.publish and Meteor.subscribe, Meteor is using DDP underneath.

Listening to DDP messages

It is possible to find the DDP connection created by Meteor on the client-side by accessing a variable called _stream, on the Meteor global object:

Meteor.connection._stream

With this object we can send and listen to any message we want on the client side. The following gist shows an example of a very simple code to do that:

First we save the reference for the original send method.

Then we override the send method with the desired function. On the example, it just print the message after sending it to the server by the original send method.

Finally, we register a new listener for message events, which also will just print everything it receives from the server. All listeners previously registered will not be affected.

If you have a Meteor application, you can copy and paste this snippet on your browser’s console and it will start tracking everything going through the DDP.

The first thing you might notice is the ping/pong messages. Meteor keep sending these messages after some interval of time to check if the connection is still alive.

> {"msg":"pong"}

> {"msg":"ping"}

Waiting for a Method response

There are my types of messages you might find in the stream. You can check this out by navigating through your application and monitoring what is happening in the console.

I used the message with type method to remove the dependency of the pause command from my test. The test now waits until the result message arrives, searching for it in the browser console during some intervals.

Meteor.call('foo');

> {"msg":"method", "method":"foo", "params":[], "id":"42"}

> {"msg":"result", "id":"42", "result":[{"a":1}, {"b":2}]}

The result does not include the name of the method, but it can be found on the method message as value of the method property. They are linked by the id property.

The same applies to waiting for a subscription to be ready.

Meteor.subscribe('bar');

> {"msg":"sub", "id":"abc1def3", name:"bar", params:[]}

> {msg:"ready", subs:["abc1def3"]}

Conclusion

Besides functional testing, some other cool stuffs you can do with this Meteor Hack are:

Debugging

Find memory Leak

Analyse security issues

References

Tags