Skip to content

Instantly share code, notes, and snippets.

@lorenzoplanas
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lorenzoplanas/9370203 to your computer and use it in GitHub Desktop.
Save lorenzoplanas/9370203 to your computer and use it in GitHub Desktop.
DOM Hooks for cleaner presenter specs (using Riot.js and Jasmine)
App.LoginPresenter = (function() {
var Login = function($el, options) {
this.$el = $el;
this.name = "login";
this.errorMessage = $.render(
App.templates.error, { text: "Wrong credentials" }
);
// Listen to relevant events
this.listen = function() {
$("form", this.$el).on("submit", this.logIn.bind(this));
return this;
};
// Unbind listeners before being removed from the DOM
this.unlisten = function() {
$("form", this.$el).off("submit", this.logIn.bind(this));
return this;
};
// Handle login form submit
this.logIn = function(e) {
e.preventDefault();
$(".error", this.$el).remove();
options.user.login({
email: $("input[name='email']", this.$el).val();
password: $("input[name='password']", this.$el).val();
})
.fail(this.loginError.bind(this))
.done(this.loginSuccess.bind(this));
return this;
};
// Prepend an error message if incorrect credentials
this.loginError = function() {
$("form", this.$el).prepend(this.errorMessage);
return this;
};
// Upon a "load dashboard" event, this presenter will unbind
// events, be removed from the DOM, and the dashboard presenter
// will render, bind, etc. Code for that is in the Presenter mixin.
this.loginSuccess = function() {
options.bus.trigger("load", "dashboard");
return this;
};
};
// Presenter is a mixin with common code for presenters,
// not shown in this sample
$.extend(Login.prototype, App.Presenter);
return Login;
})();
App.LoginPresenter = (function() {
var Login = function($el, options) {
this.$el = $el;
this.name = "login";
this.errorMessage = $.render(
App.templates.error, { text: "Wrong credentials" }
);
// DOM hooks
this.$form = finder("form");
this.$inputEmail = finder("input[name='email']");
this.$inputPassword = finder("input[name='password']");
this.$errorMessages = finder(".error");
// Listen to relevant events
this.listen = function() {
this.$form().on("submit", this.logIn.bind(this));
return this;
};
// Unbind listeners before being removed from the DOM
this.unlisten = function() {
this.$form().off("submit", this.logIn.bind(this));
return this;
};
// Handle login form submit
this.logIn = function(e) {
e.preventDefault();
this.$errorMessages().remove();
options.user.login({
email: this.$inputEmail().val(),
password: this.$inputPassword().val()
})
.fail(this.loginError.bind(this))
.done(this.loginSuccess.bind(this));
return this;
};
// Prepend an error message if incorrect credentials
this.loginError = function() {
this.$form().prepend(this.errorMessage);
return this;
};
// Upon a "load dashboard" event, this presenter will unbind
// events, be removed from the DOM, and the dashboard presenter
// will render, bind, etc. Code for that is in the Presenter mixin.
this.loginSuccess = function() {
options.bus.trigger("load", "dashboard");
return this;
};
// Search for a selector within $el
function finder(selector) {
return (function() {
return (selector, this.$el);
});
}
};
// Presenter is a mixin with common code for presenters,
// not shown in this sample
$.extend(Login.prototype, App.Presenter);
return Login;
})();
App.LoginPresenter = (function() {
var Login = function($el, options) {
this.$el = $el;
this.name = "login";
this.errorMessage = $.render(
App.templates.error, { text: "Wrong credentials" }
);
// DOM Hooks
this.$form = function() {
return $("form", this.$el);
};
this.$inputEmail = function() {
return $("input[name='email']", this.$el);
};
this.$inputPassword = function() {
return $("input[name='password']", this.$el);
};
this.$errorMessages = function() {
return $(".error", this.$el);
};
// Listen to relevant events
this.listen = function() {
this.$form().on("submit", this.logIn.bind(this));
return this;
};
// Unbind listeners before being removed from the DOM
this.unlisten = function() {
this.$form().off("submit", this.logIn.bind(this));
return this;
};
// Handle login form submit
this.logIn = function(e) {
e.preventDefault();
this.$errorMessages().remove();
options.user.login({
email: this.$inputEmail().val();
password: this.$inputPassword().val();
})
.fail(this.loginError.bind(this))
.done(this.loginSuccess.bind(this));
return this;
};
// Prepend an error message if incorrect credentials
this.loginError = function() {
this.$form().prepend(this.errorMessage);
return this;
};
// Upon a "load dashboard" event, this presenter will unbind
// events, be removed from the DOM, and the dashboard presenter
// will render, bind, etc. Code for that is in the Presenter mixin.
this.loginSuccess = function() {
options.bus.trigger("load", "dashboard");
return this;
};
};
// Presenter is a mixin with common code for presenters,
// not shown in this sample
$.extend(Login.prototype, App.Presenter);
return Login;
})();
describe("login presenter", function() {
var $target;
var bus;
var loginPresenter;
beforeEach(function() {
bus = $.observable({});
$target = $("<div class='page'></div>");
loginPresenter = new App.LoginPresenter($target, {
user: new User(),
bus: bus
});
});
it("renders a login form upon a load login event", function() {
expect(loginPresenter.$el.is(":empty")).toBe(true);
loginPresenter.render();
expect(loginPresenter.$el.is(":empty")).toBe(false);
});
it("renders an error message if credentials incorrect", function() {
loginPresenter.render();
loginPresenter.listen();
expect($(".error", loginPresenter.$el).length).toBe(0);
$("input[name='email']", loginPresenter.$el).val("wrong");
$("input[name='email']", loginPresenter.$el).val("wrong");
$("form", loginPresenter.$el).trigger("submit");
expect($(".error", loginPresenter.$el).length).toBe(1);
});
it("triggers a load dashboard event upon successful login", function() {
bus.on("load", function(pageToLoad) {
expect(pageToLoad).toBe("dashboard")
})
loginPresenter.render();
loginPresenter.listen();
$("input[name='email']", loginPresenter.$el).val("wrong");
$("input[name='email']", loginPresenter.$el).val("wrong");
$("form", loginPresenter.$el).trigger("submit");
$("form", $el).trigger("submit");
});
});
describe("login presenter", function() {
var $target;
var bus;
var loginPresenter;
beforeEach(function() {
bus = $.observable({});
$target = $("<div class='page'></div>");
loginPresenter = new App.LoginPresenter($target, {
user: new User(),
bus: bus
});
});
it("renders a login form upon a load login event", function() {
expect(loginPresenter.$element.is(":empty")).toBe(true);
loginPresenter.render();
expect(loginPresenter.$element.is(":empty")).toBe(false);
});
it("renders an error message if credentials incorrect", function() {
loginPresenter.render();
loginPresenter.bindDomEvents();
expect(loginPresenter.$errorMessages().length).toBe(0);
loginPresenter.$inputEmail().val("wrong");
loginPresenter.$inputPassword().val("wrong");
loginPresenter.$form().trigger("submit");
expect(loginPresenter.$errorMessages().length).toBe(1);
});
it("triggers a load dashboard event upon successful login", function() {
bus.on("load", function(pageToLoad) {
expect(pageToLoad).toBe("dashboard")
})
loginPresenter.render();
loginPresenter.bindDomEvents();
loginPresenter.$inputEmail().val("wrong");
loginPresenter.$inputPassword().val("wrong");
loginPresenter.$form().trigger("submit");
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment