Sign up to get extra content & updates via email!

Thanks for signing up!
I appreciate it!

Karma, Mocha, End to End Testing or Unit Testing?

unit-testing2I was recently asked by a good friend of mine whether or not Unit Testing are a must, or should he just stick to End to End Testing.

End to End Testing has some solid Pros:

  • You can let Testers/QA define most of them, they might even be able to build them completely, thus developers spend less time on them
  • The more your website gets full of features and complex – the higher the chance your QA might miss a button/feature to test. E2E Testing prevents this from happening
  • It’s the closest thing to the actual user experience

So if they’re so perfect and easy on the developers, why should we add Unit Testing as well?

The answer lies in the complexity of the project.
The more your project gets complex, the harder it’s going to be to find out why the tests are failing.

Consider this example:
Say you’re using Facebook Connect to login your user, once the user is logged in – he’s redirected to his Inbox.

Within this test you check if the user already exists, you log them in (via Facebook Connect API) if so, otherwise you add the user to the database.
Finally, you refresh the page and show the user’s inbox (or something of sorts).

The End to End test might attempt to login, realize that it’s not seeing the inbox and output an error.

So Where’s the problem?
It could happen on any one of these stages:

  • Connecting to Facebook Connect API
  • Checking if the user exists or not
  • Writing a new user to the database
  • Redirecting to Inbox
  • Rendering the Inbox page

This is a lot of things to check, and we’re supposed to build tests to avoid such nightmares.

This is where Unit Testing comes into play.
With a unit test on every major function, you’ll be able to easily point to where the process went wrong, thus save a LOT of time.

Some words on Testing Libraries
The testing world is complex and confusing at times, here are some short descriptions for different testing tools:

  • Unit Testing Frameworks (JavaScript) – Mocha/Jasmine, I personally choose Mocha most of the time, but both are quite similar
  • Behavior Driven Development (BDD) – Cucumber, very popular with Ruby developers, I’ve yet to work with it on production level projects, but I can see the advantages of having human readable tests
  • Test Runners – Karma/Velocity, these help you run multiple tests on real browsers, Karma is widely used for NodeJS and Velocity is the official Meteor test runner
  • Browser Automation – Selenium, this is definitely more of the End to End kind of testing, the highest level there is – automating the browser to test your application. Ideally it should be used more by QAs than devs.

More information about Testing:

Tagged with: , , , , , ,
Posted in Technology

Double event calling problem in Meteor

Meteor_double_event_call
Recently, when working with Meteor methods, I’ve stumbled upon an odd problem.
While going into debug mode:

meteor debug

I’ve suddenly noticed some methods are being called twice. I wasn’t sure when exactly it happens but I’ve noticed it happens more often when the method has a bunch of async calls.

I started Googling to see if this is a known bug, and found this: Method called once but executed twice.

This answer in particular is what I found interesting:

…During the yield, the background observe thread notices that the user object is gone and disconnects the connection. The client sees this and reconnects; because the removeUser method was in flight and never got a response, it runs it again.

So while the reason for disconnecting was different on my end (I wasn’t deleting the user in my methods, but I was manipulating user data), I started to think that it’s related to the client call.

Another evidence for this was the dead end I reached when examining the call stack. Once compared, I realized the call stacks are identical, which probably points back to the client calling the function again.

How did I fix this?
The workaround may sound silly, but because the method was a multi-stages kind of thing, I decided to have a status, so we know “where we are” in the process.
The status should be written right before calling the method, and be overwritten as soon as the method starts.
Because Session is not available on server side, I used the database to store the status.

/* wherever you call your methods, e.g. where the template events are */
Meteor.call( 'setUserStatus', 'method1', 'execute' );
Meteor.call( 'method1' );

/* methods.js */
Meteor.methods({
  setUserStatus: function( method, status ) {
    Meteor.users.update(
{ _id: this.userId },
{ $set: { method + '_status':  status } }
);
  },
method1: function() {
   var user = Meteor.user();
   if ( user.method1_status === 'execute' )
     Meteor.call( 'setUserStatus', 'method 1', 'running' )
   else
     return false; //second call
   
   //...Functions content...
})

Don’t forget to expose the fields on publications.js (or wherever your publications are), otherwise the user object won’t have them as attributes.

Bonus: Push to a sub-attribute in MongoDB

If you’re going with a single attribute (e.g. ‘status’) that will hold sub-arrays of the different statuses, pushing to those arrays will only work when using $push.
In this example, we have an array within status that’s called ‘method1’, and we’re pushing the status ‘running’ to it:

Meteor.users.update(
	{_id: this.userId},
	{$push: { 'status.method1': 'running' }}
);
Tagged with: , , , ,
Posted in Technology

Deploying Meteor on a Production Server

Meteor_deployment
It’s been a while since I last wrote here, hopefully I could get back to my weekly routine.

In the last month or so I’ve been working heavily with Meteor.

When it came to the stage of deploying to a test server, I decided to use a simple node server, without an extra layer of Nginx/Apache.
Normally, to build a Meteor application, you run:

meteor build

This generates a tar.gz file with your compiled (-ish) application, which you could later extract to your production server.

After extracting, you’ll have to run node main.js to start the application.
This approach has 2 problems:

  • Dependencies – Some npm packages will have to be installed via running npm install under programs/server, this adds yet another step that has to be done for deployment.
  • No Logs – If we just run the application with node main.js we get no feedback on logs, there’s also a problem of the server being shutdown if the parent shell is closed.

Seeing these potential problems, I’ve decided to build a script for deploying a Meteor application:

#!/bin/bash
PATH_TO_APP='../app'
echo "Building Meteor App to a directory..."
( cd ${PATH_TO_APP}; meteor build --directory . )
echo "Getting NPM packages for project"
( cd ${PATH_TO_APP}/bundle/programs/server; npm install )
echo "Copying start_server.sh and stop_server.sh scripts to app"
cp st*.sh ${PATH_TO_APP}/bundle/
echo "Creating tar.gz file (in the parent folder)"
( cd ${PATH_TO_APP}; tar -zcvf ../bundle_$(date +"%d_%m_%Y_T%H_%M_%S").tar.gz bundle )
echo "Removing Bundle Directory..."
rm -rf ${PATH_TO_APP}/bundle

As you can see, some commands are in parentheses, this spawns a sub-shell so we don’t actually change the folder globally (more info).
Let’s go over this line-by-line (excluding the echo messages):

  • PATH_TO_APP=’../app’ – Define path to application (where the .meteor folder is located)
  • ( cd ${PATH_TO_APP}; meteor build –directory . ) – Build meteor app to a directory instead of a file
  • ( cd ${PATH_TO_APP}/bundle/programs/server; npm install ) – Install dependencies
  • cp st*.sh ${PATH_TO_APP}/bundle/ – Copy the start_server.sh and stop_server.sh scripts (more on those later)
  • ( cd ${PATH_TO_APP}; tar -zcvf ../bundle_$(date +”%d_%m_%Y_T%H_%M_%S”).tar.gz bundle ) – Compress the file to a tar.gz, with the date & time added to the filename
  • rm -rf ${PATH_TO_APP}/bundle – Remove the bundle/ directory we generated earlier

This script works pretty well, and you end up having a more complete package.
I have a separate scripts folder parallel to the application folder (this is why the PATH_TO_APP is ../app), this folder also holds the 2 running scripts:
start_server.sh

#!/bin/bash
NODE_EXEC="nodejs"
if [ "$1" = "debug" ]; then
	NODE_EXEC="node-debug"
	echo 'Starting Server in Debug Mode...'
else
	echo 'Starting Server...'
fi

PORT=3000 \
MONGO_URL=mongodb://localhost:27017/meteor \
ROOT_URL=http://localhost:3000/ \
METEOR_SETTINGS="$(cat settings.json)" \
nohup $NODE_EXEC main.js >/var/log/nodejs.log 2>&1 &

echo $! > server_id.txt

Once again, line-by-line (excluding echo):

  • NODE_EXEC=”nodejs” – Define the node executable file (could be node/nodejs)
  • if [ “$1” = “debug” ]; then – If the the first argument is “debug” (i.e. sh start_server.sh debug), run node-debug instead
  • PORT=3000 \ – Define port of the application to be 3000
  • MONGO_URL=mongodb://localhost:27017/meteor \ – Define Mongo URL (for DB)
  • ROOT_URL=http://localhost:3000/ \ – Define Root URL
  • METEOR_SETTINGS=”$(cat settings.json)” \ – Define a settings file (if you’re not using a custom one, feel free to remove this)
  • nohup $NODE_EXEC main.js >/var/log/nodejs.log 2>&1 & – Run the server with nohup (thus not closing if parent shell closes), move all output to /var/log/nodejs.log (make sure you have writing access to the file, otherwise choose another one)
  • echo $! > server_id.txt – Get the Server’s Process ID (PID) and write it into server_id.txt (so stop_server.sh knows which PID to kill)

stop_server.sh

#!/bin/bash
echo 'Stopping Server...'
kill `cat server_id.txt`

Not much to explain here, we’re basically killing the PID that was written by start_server.sh.

Since this is a pretty complete deployment package, I decided to offer it on a git repository.

I’d love to get some improvements going on, feel free to fork/add issues!

Tagged with: , , , ,
Posted in Technology

Moved to Dublin

clover-445255_1280

For those of you who religiously follow my blog (and I know some of you do),
you might’ve noticed it’s been over a month (!) since my last update.

The reason is quite simple: We moved to Dublin!
Moving to a new country is quite time consuming. Luckily we’re quite well versed in that, but I still had to get quite a few things in order, which is why I didn’t have much time left for many things, my blog is one of them.

I can say that there are some major things planned in the near future,
so I’ll try to post about these as much as I possibly can.

Here are some stunning pictures of the nearby scenery:
AkhGOaaBMuYJ79tUGnZx0eSSN-6kZSrFfrdvj6x6dxy8IMG_20150601_105626

 

 

 

 

 

 

 

 

Until next time!

Posted in Brainstorming

Getting data from server to client on Meteor

client-341420_640Today I’ll be writing about the easiest way of getting data from server to client on Meteor, data that is not necessarily DB related.

First lets start with the DB related data.
Usually if you want to get data from the server side to the client side on Meteor (assuming autopublish was removed of course) you’d use Publish and Subscribe:


//Publication

Meteor.publish( 'pomodoros', function() {
  return Pomodoros.find({ userId: this.userId });
});

//Subscription
Meteor.subscribe( 'pomodoros' );


//Client side jibber-jabber
Pomodoros.findOne({ userId: Meteor.userId() });


This example was taken from my Meteoro app, and it shows a simple way of getting Collection data from the server on the client side.

In the following scenario however, I was trying to get Stocks Quotes from Yahoo Finance – none DB related.
I found a meteor package called ajbarry:yahoo-finance, which is a simple wrapper for the node-yahoo-finance NPM package.
The example seemed pretty simple (I only care about snapshot for this project):

yahooFinance.snapshot({
  symbols: ['AAPL','GOOG']
  fields: ['s', 'n', 'd1', 'l1', 'y', 'r'],
}, function (err, snapshot) {
  //..
});

But I had a problem, for some reason the yahooFinance object wasn’t defined on the client side.
Later I found out the object is only available on the server side, to expose it to the client, I had to use Methods:
server/methods.js

Meteor.methods({
  getQuote: function( stockname ) {
    return YahooFinance.snapshot({symbols: [stockname] });
  }
})

And now I was able to access it via the client:

Template.stocks.onRendered(function() {
  if ( _.isEmpty(Session.get('GOOG')) ) {
    Meteor.call('getQuote', 'GOOG', function(err, result) {
      Session.set('GOOG', result.GOOG);
    });
  }
})

Template.stocks.helpers({
  stock: function() {
    return Session.get('GOOG');
  }
})

Template:

<template name="stocks">
  <h2>{{stock.symbol}}</h2>
  <ul>
    <li><strong>Name</strong> {{stock.name}}</li>
    <li><strong>Ask</strong> {{stock.ask}}</li>
    <li><strong>Bid</strong> {{stock.bid}}</li>
  </ul>
</template>

Result:

google-stock

Done!

Side Note:
There’s a small problem with the package, the node-yahoo-finance version used (0.1.4) on the Meteor package is quite outdated, and lacks the single stock snapshot (which is why the single stock had to be wrapped with [] when calling the function).

I’m considering forking the package, will try to write about it here.

Tagged with: , , , ,
Posted in Technology

ImageDock – Image Gallery plugin for WordPress with a Dock effect

Since I’m on vacation, this will be a short article (I haven’t forgotten about the Meteor tutorials, they’re coming!).

For now, let me introduce to you ImageDock, an Image Gallery Plugin for WordPress, with a cool Dock effect (similar to OSX).
Check it out in action:

The settings panel is pretty simple, letting you choose some images, after which you can add the gallery using a shortcode

This is how the gallery looks like on the front end:
screenshot-1

Settings Page:
screenshot-2

The GitHub Repo

The Plugin Page on WordPress.org

Tagged with: , ,
Posted in Technology
Welcome to KidsIL
A blog for Web Development & Technology


Check out my new series about MeanJS: Take a look at StartCast.
A podcast with the sole purpose of interviewing co-founders of Startups in Europe & around the world.


You should try Berlin On Feier, an App I built for finding the best parties in Berlin.