Skip to content

Commit

Permalink
adding Jasmine tests for private_pub.js
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanb committed Apr 27, 2011
1 parent e194743 commit ef03ef3
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 56 deletions.
4 changes: 3 additions & 1 deletion Rakefile
@@ -1,10 +1,12 @@
require 'rubygems'
require 'rake'
require 'rspec/core/rake_task'
require 'jasmine'
load 'jasmine/tasks/jasmine.rake'

desc "Run RSpec"
RSpec::Core::RakeTask.new do |t|
t.verbose = false
end

task :default => :spec
task :default => [:spec, "jasmine:ci"]
119 changes: 64 additions & 55 deletions lib/generators/private_pub/templates/private_pub.js
@@ -1,63 +1,72 @@
PrivatePub = {
connecting: false,
faye_client: null,
faye_callbacks: [],
subscriptions: {},
subscription_callbacks: {},
function buildPrivatePub(doc) {
var self = {
connecting: false,
fayeClient: null,
fayeCallbacks: [],
subscriptions: {},
subscriptionCallbacks: {},

faye: function(callback) {
if (PrivatePub.faye_client) {
callback(PrivatePub.faye_client);
} else {
PrivatePub.faye_callbacks.push(callback);
if (PrivatePub.subscriptions.server && !PrivatePub.connecting) {
PrivatePub.connecting = true;
var script = document.createElement("script");
script.type = "text/javascript";
script.src = PrivatePub.subscriptions.server + ".js";
script.onload = function() {
PrivatePub.faye_client = new Faye.Client(PrivatePub.subscriptions.server);
PrivatePub.faye_client.addExtension(PrivatePub.faye_extension);
for (var i=0; i < PrivatePub.faye_callbacks.length; i++) {
PrivatePub.faye_callbacks[i](PrivatePub.faye_client);
};
faye: function(callback) {
if (self.fayeClient) {
callback(self.fayeClient);
} else {
self.fayeCallbacks.push(callback);
if (self.subscriptions.server && !self.connecting) {
self.connecting = true;
var script = doc.createElement("script");
script.type = "text/javascript";
script.src = self.subscriptions.server + ".js";
script.onload = self.connectToFaye;
doc.documentElement.appendChild(script);
}
document.documentElement.appendChild(script);
}
}
},
},

faye_extension: {
outgoing: function(message, callback) {
if (message.channel == "/meta/subscribe") {
// Attach the signature and timestamp to subscription messages
var subscription = PrivatePub.subscriptions[message.subscription];
if (!message.ext) message.ext = {};
message.ext.private_pub_signature = subscription.signature;
message.ext.private_pub_timestamp = subscription.timestamp;
}
callback(message);
}
},
connectToFaye: function() {
self.fayeClient = new Faye.Client(self.subscriptions.server);
self.fayeClient.addExtension(self.fayeExtension);
for (var i=0; i < self.fayeCallbacks.length; i++) {
self.fayeCallbacks[i](self.fayeClient);
};
},

sign: function(options) {
if (!PrivatePub.subscriptions.server) {
PrivatePub.subscriptions.server = options.server;
}
PrivatePub.subscriptions[options.channel] = options;
PrivatePub.faye(function(faye) {
faye.subscribe(options.channel, function(message) {
if (message.eval) {
eval(message.eval);
}
if (callback = PrivatePub.subscription_callbacks[options.channel]) {
callback(message.data, message.channel);
fayeExtension: {
outgoing: function(message, callback) {
if (message.channel == "/meta/subscribe") {
// Attach the signature and timestamp to subscription messages
var subscription = self.subscriptions[message.subscription];
if (!message.ext) message.ext = {};
message.ext.private_pub_signature = subscription.signature;
message.ext.private_pub_timestamp = subscription.timestamp;
}
callback(message);
}
},

sign: function(options) {
if (!self.subscriptions.server) {
self.subscriptions.server = options.server;
}
self.subscriptions[options.channel] = options;
self.faye(function(faye) {
faye.subscribe(options.channel, self.handleResponse);
});
});
},
},

handleResponse: function(message) {
if (message.eval) {
eval(message.eval);
}
if (callback = self.subscriptionCallbacks[message.channel]) {
callback(message.data, message.channel);
}
},

subscribe: function(channel, callback) {
self.subscriptionCallbacks[channel] = callback;
}
};
return self;
}

subscribe: function(channel, callback) {
PrivatePub.subscription_callbacks[channel] = callback;
}
};
var PrivatePub = buildPrivatePub(document);
1 change: 1 addition & 0 deletions private_pub.gemspec
Expand Up @@ -11,6 +11,7 @@ Gem::Specification.new do |s|
s.require_path = "lib"

s.add_development_dependency 'rspec', '~> 2.1.0'
s.add_development_dependency 'jasmine'

s.rubyforge_project = s.name
s.required_rubygems_version = ">= 1.3.4"
Expand Down
108 changes: 108 additions & 0 deletions spec/javascripts/private_pub_spec.js
@@ -0,0 +1,108 @@
describe("PrivatePub", function() {
var pub, doc;
beforeEach(function() {
Faye = {}; // To simulate global Faye object
doc = {};
pub = buildPrivatePub(doc);
});

it("adds a subscription callback", function() {
pub.subscribe("hello", "callback");
expect(pub.subscriptionCallbacks["hello"]).toEqual("callback");
});

it("has a fayeExtension which adds matching subscription signature and timestamp to outgoing message", function() {
var called = false;
var message = {channel: "/meta/subscribe", subscription: "hello"}
pub.subscriptions["hello"] = {signature: "abcd", timestamp: "1234"}
pub.fayeExtension.outgoing(message, function(message) {
expect(message.ext.private_pub_signature).toEqual("abcd");
expect(message.ext.private_pub_timestamp).toEqual("1234");
called = true;
});
expect(called).toBeTruthy();
});

it("evaluates javascript in message response", function() {
pub.handleResponse({eval: 'self.subscriptions.foo = "bar"'});
expect(pub.subscriptions.foo).toEqual("bar");
});

it("triggers callback matching message channel in response", function() {
var called = false;
pub.subscribe("test", function(data, channel) {
expect(data).toEqual("abcd");
expect(channel).toEqual("test");
called = true;
});
pub.handleResponse({channel: "test", data: "abcd"});
expect(called).toBeTruthy();
});

it("adds a faye subscription with response handler when signing", function() {
var faye = {subscribe: jasmine.createSpy()};
spyOn(pub, 'faye').andCallFake(function(callback) {
callback(faye);
});
var options = {server: "server", channel: "somechannel"};
pub.sign(options);
expect(faye.subscribe).toHaveBeenCalledWith("somechannel", pub.handleResponse);
expect(pub.subscriptions.server).toEqual("server");
expect(pub.subscriptions.somechannel).toEqual(options);
});

it("adds a faye subscription with response handler when signing", function() {
var faye = {subscribe: jasmine.createSpy()};
spyOn(pub, 'faye').andCallFake(function(callback) {
callback(faye);
});
var options = {server: "server", channel: "somechannel"};
pub.sign(options);
expect(faye.subscribe).toHaveBeenCalledWith("somechannel", pub.handleResponse);
expect(pub.subscriptions.server).toEqual("server");
expect(pub.subscriptions.somechannel).toEqual(options);
});

it("triggers faye callback function immediately when fayeClient is available", function() {
var called = false;
pub.fayeClient = "faye";
pub.faye(function(faye) {
expect(faye).toEqual("faye");
called = true;
});
expect(called).toBeTruthy();
});

it("adds fayeCallback when client and server aren't available", function() {
pub.faye("callback");
expect(pub.fayeCallbacks[0]).toEqual("callback");
});

it("adds a script tag loading faye js when the server is present", function() {
script = {};
doc.createElement = function() { return script; };
doc.documentElement = {appendChild: jasmine.createSpy()};
pub.subscriptions.server = "path/to/faye";
pub.faye("callback");
expect(pub.fayeCallbacks[0]).toEqual("callback");
expect(script.type).toEqual("text/javascript");
expect(script.src).toEqual("path/to/faye.js");
expect(script.onload).toEqual(pub.connectToFaye);
expect(doc.documentElement.appendChild).toHaveBeenCalledWith(script);
});

it("connects to faye server, adds extension, and executes callbacks", function() {
callback = jasmine.createSpy();
client = {addExtension: jasmine.createSpy()};
Faye.Client = function(server) {
expect(server).toEqual("server")
return client;
};
pub.subscriptions.server = "server";
pub.fayeCallbacks.push(callback);
pub.connectToFaye();
expect(pub.fayeClient).toEqual(client);
expect(client.addExtension).toHaveBeenCalledWith(pub.fayeExtension);
expect(callback).toHaveBeenCalledWith(client);
});
});
73 changes: 73 additions & 0 deletions spec/javascripts/support/jasmine.yml
@@ -0,0 +1,73 @@
# src_files
#
# Return an array of filepaths relative to src_dir to include before jasmine specs.
# Default: []
#
# EXAMPLE:
#
# src_files:
# - lib/source1.js
# - lib/source2.js
# - dist/**/*.js
#
src_files:
- lib/generators/private_pub/templates/private_pub.js

# stylesheets
#
# Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs.
# Default: []
#
# EXAMPLE:
#
# stylesheets:
# - css/style.css
# - stylesheets/*.css
#
stylesheets:

# helpers
#
# Return an array of filepaths relative to spec_dir to include before jasmine specs.
# Default: ["helpers/**/*.js"]
#
# EXAMPLE:
#
# helpers:
# - helpers/**/*.js
#
helpers:

# spec_files
#
# Return an array of filepaths relative to spec_dir to include.
# Default: ["**/*[sS]pec.js"]
#
# EXAMPLE:
#
# spec_files:
# - **/*[sS]pec.js
#
spec_files:

# src_dir
#
# Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
# Default: project root
#
# EXAMPLE:
#
# src_dir: public
#
src_dir:

# spec_dir
#
# Spec directory path. Your spec_files must be returned relative to this path.
# Default: spec/javascripts
#
# EXAMPLE:
#
# spec_dir: spec/javascripts
#
spec_dir:
23 changes: 23 additions & 0 deletions spec/javascripts/support/jasmine_config.rb
@@ -0,0 +1,23 @@
module Jasmine
class Config

# Add your overrides or custom config code here

end
end


# Note - this is necessary for rspec2, which has removed the backtrace
module Jasmine
class SpecBuilder
def declare_spec(parent, spec)
me = self
example_name = spec["name"]
@spec_ids << spec["id"]
backtrace = @example_locations[parent.description + " " + example_name]
parent.it example_name, {} do
me.report_spec(spec["id"])
end
end
end
end
32 changes: 32 additions & 0 deletions spec/javascripts/support/jasmine_runner.rb
@@ -0,0 +1,32 @@
$:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes

require 'rubygems'
require 'jasmine'
jasmine_config_overrides = File.expand_path(File.join(File.dirname(__FILE__), 'jasmine_config.rb'))
require jasmine_config_overrides if File.exist?(jasmine_config_overrides)
if Jasmine::rspec2?
require 'rspec'
else
require 'spec'
end

jasmine_config = Jasmine::Config.new
spec_builder = Jasmine::SpecBuilder.new(jasmine_config)

should_stop = false

if Jasmine::rspec2?
RSpec.configuration.after(:suite) do
spec_builder.stop if should_stop
end
else
Spec::Runner.configure do |config|
config.after(:suite) do
spec_builder.stop if should_stop
end
end
end

spec_builder.start
should_stop = true
spec_builder.declare_suites

0 comments on commit ef03ef3

Please sign in to comment.