Permalink
Browse files

Add feature and controller tests

  • Loading branch information...
1 parent 21fd558 commit 39c738a083bc89c9e10d6476526292e86534f622 @reyesyang committed Dec 23, 2013
View
11 Gemfile
@@ -56,9 +56,18 @@ gem 'rvm-capistrano'
group :development, :test do
gem 'quiet_assets'
- gem 'factory_girl_rails'
gem 'pry-rails'
gem 'rspec-rails'
+ gem 'factory_girl_rails'
+end
+
+group :test do
+ gem "fakeweb"
gem "shoulda-matchers"
+ gem "capybara"
+ gem "capybara-webkit"
+ gem "selenium-webdriver"
+ gem "launchy"
+ gem "database_cleaner"
end
View
36 Gemfile.lock
@@ -25,6 +25,7 @@ GEM
multi_json (~> 1.3)
thread_safe (~> 0.1)
tzinfo (~> 0.3.37)
+ addressable (2.3.5)
arel (4.0.0)
atomic (1.1.13)
builder (3.1.4)
@@ -34,6 +35,17 @@ GEM
net-sftp (>= 2.0.0)
net-ssh (>= 2.0.14)
net-ssh-gateway (>= 1.1.0)
+ capybara (2.2.0)
+ mime-types (>= 1.16)
+ nokogiri (>= 1.3.3)
+ rack (>= 1.0.0)
+ rack-test (>= 0.5.4)
+ xpath (~> 2.0)
+ capybara-webkit (1.1.0)
+ capybara (~> 2.0, >= 2.0.2)
+ json
+ childprocess (0.3.9)
+ ffi (~> 1.0, >= 1.0.11)
coderay (1.0.9)
coffee-rails (4.0.0)
coffee-script (>= 2.2.0)
@@ -43,6 +55,7 @@ GEM
execjs
coffee-script-source (1.6.3)
commonjs (0.2.7)
+ database_cleaner (1.2.0)
diff-lcs (1.2.5)
erubis (2.7.0)
execjs (2.0.1)
@@ -51,6 +64,8 @@ GEM
factory_girl_rails (4.2.1)
factory_girl (~> 4.2.0)
railties (>= 3.0.0)
+ fakeweb (1.3.0)
+ ffi (1.9.3)
haml (4.0.3)
tilt
highline (1.6.19)
@@ -62,6 +77,9 @@ GEM
jquery-rails (3.0.4)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
+ json (1.8.1)
+ launchy (2.4.2)
+ addressable (~> 2.3)
less (2.4.0)
commonjs (~> 0.2.7)
less-rails (2.4.2)
@@ -73,6 +91,7 @@ GEM
treetop (~> 1.4.8)
method_source (0.8.2)
mime-types (1.25)
+ mini_portile (0.5.2)
minitest (4.7.5)
multi_json (1.7.9)
mysql2 (0.3.13)
@@ -83,6 +102,8 @@ GEM
net-ssh (2.6.8)
net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5)
+ nokogiri (1.6.1)
+ mini_portile (~> 0.5.0)
polyglot (0.3.3)
pry (0.9.12.2)
coderay (~> 1.0.5)
@@ -125,13 +146,19 @@ GEM
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
+ rubyzip (1.1.0)
rvm-capistrano (1.5.0)
capistrano (>= 2.15.4)
sass (3.2.10)
sass-rails (4.0.0)
railties (>= 4.0.0.beta, < 5.0)
sass (>= 3.1.10)
sprockets-rails (~> 2.0.0)
+ selenium-webdriver (2.39.0)
+ childprocess (>= 0.2.5)
+ multi_json (~> 1.0)
+ rubyzip (~> 1.0)
+ websocket (~> 1.0.4)
shoulda-matchers (2.4.0)
activesupport (>= 3.0.0)
slop (3.4.6)
@@ -165,21 +192,29 @@ GEM
uglifier (2.2.1)
execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2)
+ websocket (1.0.7)
will_paginate (3.0.4)
wmd-rails (0.0.7)
rails (>= 3.1.1)
+ xpath (2.0.0)
+ nokogiri (~> 1.3)
PLATFORMS
ruby
DEPENDENCIES
capistrano
+ capybara
+ capybara-webkit
coffee-rails (~> 4.0.0)
+ database_cleaner
execjs
factory_girl_rails
+ fakeweb
haml
jbuilder (~> 1.5.1)
jquery-rails
+ launchy
less-rails
mysql2
pry-rails
@@ -190,6 +225,7 @@ DEPENDENCIES
rspec-rails
rvm-capistrano
sass-rails (~> 4.0.0)
+ selenium-webdriver
shoulda-matchers
therubyracer
turbolinks
View
71 app/controllers/articles_controller.rb
@@ -1,74 +1,57 @@
# -*- encoding : utf-8 -*-
class ArticlesController < ApplicationController
- before_filter :require_admin, only: [:new, :create, :edit, :update, :destroy]
- before_filter :load_article_with_tags, only: [:show, :edit]
+ before_action :require_admin, only: [:new, :create, :edit, :update, :destroy]
+ before_action :find_article, only: [:show, :edit, :update, :destroy]
def index
@articles = current_user && current_user.admin? ?
- Article.includes(:tags).order("articles.id DESC").paginate(:page => params[:page]) :
- Article.includes(:tags).where("tags.name != 'draft'").order("articles.id DESC").paginate(:page => params[:page])
+ Article.order("articles.id DESC").paginate(page: params[:page]) :
+ Article.published.order("articles.id DESC").paginate(page: params[:page])
@page_title = '首页'
-
- respond_to do |format|
- format.html
- end
- end
-
- def show
- @page_title = '文章 - ' + @article.title
- @page_description = @article.title
-
- respond_to do |format|
- format.html
- end
end
def new
@article = Article.new
@page_title = '发布文章'
- respond_to do |format|
- format.html { render layout: 'wide' }
- end
- end
-
- def edit
- @page_title = '编辑文章 - ' + @article.title
- render layout: 'wide'
+ render layout: "wide"
end
def create
@article = Article.new(article_params)
- respond_to do |format|
- if @article.save
- format.html { redirect_to(@article, :notice => 'Article was successfully created.') }
- else
- format.html { render :action => "new" }
- end
+ if @article.save
+ redirect_to @article
+ else
+ render :new
end
end
+ def show
+ @page_title = "文章 - #{@article.title}"
+ @page_description = @article.title
+ end
+
+ def edit
+ @page_title = "编辑文章 - #{@article.title}"
+
+ render layout: "wide"
+ end
+
def update
- @article = Article.find params[:id]
- respond_to do |format|
- if @article.update_attributes(article_params)
- format.html { redirect_to(@article, :notice => 'Article was successfully updated.') }
- else
- format.html { render :action => "edit" }
- end
+ if @article.update_attributes(article_params)
+ redirect_to @article
+ else
+ render :edit
end
end
def destroy
@article = Article.find params[:id]
@article.destroy
- respond_to do |format|
- format.html { redirect_to(articles_url) }
- format.xml { head :ok }
- end
+ redirect_to articles_path
end
def tagging
@@ -78,8 +61,8 @@ def tagging
end
private
- def load_article_with_tags
- @article = Article.includes(:tags).find(params[:id])
+ def find_article
+ @article = Article.find(params[:id])
end
def article_params
View
2 app/models/article.rb
@@ -9,6 +9,8 @@ class Article < ActiveRecord::Base
self.per_page = 10
+ scope :published, -> { joins(:tags).where("tags.name != ?", "draft").uniq }
+
def tag_list=(value)
tags = value.split(',').map { |tag| tag.strip.downcase }.reject { |t| t.blank? }
View
4 app/models/tag.rb
@@ -11,9 +11,9 @@ def to_param
def self.list(user)
if user && user.admin?
- Tag.all
+ Tag.all.load
else
- Tag.where("name != 'draft'").all
+ Tag.where("name != 'draft'").load
end
end
end
View
2 app/views/articles/show.html.haml
@@ -13,7 +13,7 @@
-if logged_in? && current_user.admin?
%span.operation
= link_to t('edit'), edit_article_path(@article)
- = link_to t('back'), articles_path
+ = link_to t('destroy'), @article, data: { confirm: 'Are you sure?' }, :method => :delete
.article_content
~ format_text @article.content
View
2 app/views/layouts/application.html.haml
@@ -8,7 +8,7 @@
= csrf_meta_tag
= stylesheet_link_tag 'application'
= javascript_include_tag 'application'
- = javascript_include_tag 'https://login.persona.org/include.js'
+ = javascript_include_tag Rails.env.test? ? 'stubbyid' : 'https://login.persona.org/include.js'
= javascript_include_tag 'persona'
= yield :head
/[if lt IE 9]
View
1 config/app_config.example.yml
@@ -14,6 +14,7 @@ development:
test:
<<: *default
+ origin: "http://www.example.com"
production:
<<: *default
View
206 lib/assets/javascripts/stubbyid.js
@@ -0,0 +1,206 @@
+// stubbyid.js v0.2.1
+// A simple client-side "simulator" for the Persona login service.
+// https://github.com/toolness/stubbyid
+
+(function() {
+ "use strict";
+
+ var LOGIN_STATE_KEY = "STUBBYID_LOGIN_STATE";
+ var widget = {
+ el: document.createElement('div'),
+ update: function() {
+ var state = getLoginState();
+ if (state) {
+ widget.el.innerHTML = 'Persona simulator thinks you want to ' +
+ 'be logged in as <strong>' + escapeHtml(state) +
+ '</strong>. <button>logout</button>';
+ } else {
+ widget.el.innerHTML = 'Persona simulator thinks you want to ' +
+ 'be logged out. <button>login</button>';
+ }
+ },
+ init: function() {
+ widget.el.style.position = "fixed";
+ widget.el.style.bottom = "0";
+ widget.el.style.right = "0";
+ widget.el.style.color = "white";
+ widget.el.style.fontFamily = "Helvetica, Arial, sans-serif";
+ widget.el.style.fontSize = "12px";
+ widget.el.style.backgroundColor = "rgba(0, 0, 0, 0.75)";
+ widget.el.style.padding = "4px";
+ widget.el.style.zIndex = "100000";
+ widget.el.className = "stubbyid";
+ attach(widget.el, "click", function(event) {
+ if (target(event).nodeName == "BUTTON") {
+ if (getLoginState())
+ setLoginState(null, false);
+ else
+ setLoginState(window.prompt("Enter email address") || null,
+ false);
+ }
+ });
+ document.body.appendChild(widget.el);
+ widget.update();
+ }
+ };
+ var escapeHtml = function(string) {
+ var entityMap = {
+ "&": "&amp;",
+ "<": "&lt;",
+ ">": "&gt;",
+ '"': '&quot;',
+ "'": '&#39;',
+ "/": '&#x2F;'
+ };
+
+ return String(string).replace(/[&<>"'\/]/g, function (s) {
+ return entityMap[s];
+ });
+ };
+ var target = function(event) {
+ return event.target || event.srcElement;
+ };
+ var attach = function(element, eventName, cb) {
+ if (element.addEventListener)
+ element.addEventListener(eventName, cb, false);
+ else
+ element.attachEvent('on' + eventName, cb);
+ };
+ var setLoginState = function(state, notifyWatcher) {
+ if (typeof(notifyWatcher) == "undefined") notifyWatcher = true;
+ state = state || null;
+ if (getLoginState() === state)
+ return;
+ if (state) {
+ window.localStorage.setItem(LOGIN_STATE_KEY, state);
+ widget.update();
+ if (notifyWatcher) watchOptions.onlogin(state);
+ } else {
+ window.localStorage.removeItem(LOGIN_STATE_KEY);
+ widget.update();
+ if (notifyWatcher) watchOptions.onlogout();
+ }
+ };
+ var getLoginState = function() {
+ return window.localStorage.getItem(LOGIN_STATE_KEY) || null;
+ };
+ var fail = function(msg) {
+ log(msg);
+ throw new Error(msg);
+ };
+ var log = function(msg) {
+ if (window.console && window.console.log)
+ window.console.log("STUBBYID: " + msg);
+ if (navigator.id.stubby.onlog)
+ navigator.id.stubby.onlog(msg);
+ };
+ var watchOptions = {
+ _onlogin: null,
+ _onlogout: null,
+ onlogin: function(assertion) {
+ if (watchOptions._onlogin) {
+ log("Calling onlogin().");
+ watchOptions._onlogin(assertion);
+ }
+ },
+ onlogout: function() {
+ if (watchOptions._onlogout) {
+ log("Calling onlogout().");
+ watchOptions._onlogout();
+ }
+ }
+ };
+
+ window.navigator.id = {
+ stubby: {
+ reset: function() {
+ watchOptions._onlogin = null;
+ watchOptions._onlogout = null;
+ setLoginState(null);
+ },
+ onlog: null,
+ setPersonaState: setLoginState,
+ getPersonaState: getLoginState,
+ widgetElement: widget.el
+ },
+ // https://developer.mozilla.org/en-US/docs/DOM/navigator.id.watch
+ watch: function navigator_id_watch(options) {
+ if (!(typeof(options.loggedInUser) == "undefined" ||
+ typeof(options.loggedInUser) == "string" ||
+ options.loggedInUser === null))
+ fail("loggedInUser must be null, undefined, or string");
+ if (typeof(options.onlogin) != "function")
+ fail("onlogin must be a function");
+ if (typeof(options.onlogout) != "function")
+ fail("onlogout must be a function");
+
+ var personaState = getLoginState();
+ var loggedInUser = options.loggedInUser;
+ var reasoning = "";
+
+ watchOptions._onlogin = options.onlogin;
+ watchOptions._onlogout = options.onlogout;
+
+ if (typeof(loggedInUser) == "undefined") {
+ reasoning = "Client doesn't know if user is logged in or not ";
+ if (personaState) {
+ log(reasoning + "and they want to be logged in as " +
+ personaState + ".");
+ watchOptions.onlogin(personaState);
+ } else {
+ log(reasoning + "and they want to be logged out. ");
+ watchOptions.onlogout();
+ }
+ } else if (typeof(loggedInUser) == "string") {
+ reasoning = "Client thinks the user is logged in as " +
+ loggedInUser + " ";
+
+ if (personaState) {
+ if (personaState == loggedInUser) {
+ log(reasoning + "and they want to be, so doing nothing.");
+ } else {
+ log(reasoning + "but they want to be logged in as " +
+ personaState + ".");
+ watchOptions.onlogin(personaState);
+ }
+ } else {
+ log(reasoning + "but they want to be logged out.");
+ watchOptions.onlogout();
+ }
+ } else if (loggedInUser === null) {
+ reasoning = "Client thinks the user is logged out ";
+ if (personaState) {
+ log(reasoning + "but they want to be logged in as " +
+ personaState + ".");
+ watchOptions.onlogin(personaState);
+ } else {
+ log(reasoning + "and they want to be, so doing nothing.");
+ }
+ }
+ },
+ request: function navigator_id_request(options) {
+ options = options || {};
+ var response = window.prompt("Enter email address");
+ if (!response) {
+ if (options.oncancel)
+ options.oncancel();
+ return;
+ }
+ setLoginState(response);
+ },
+ logout: function navigator_id_logout() {
+ setLoginState(null);
+ },
+ get: function navigator_id_get(gotAssertion) {
+ var email = window.prompt("Enter email address") || null;
+ window.setTimeout(function() { gotAssertion(email); }, 1);
+ }
+ };
+
+ window.navigator.id.getVerifiedEmail = window.navigator.id.get;
+
+ if (document.readyState == "complete")
+ widget.init();
+ else
+ attach(window, "load", widget.init);
+})();
View
328 spec/controllers/articles_controller_spec.rb
@@ -0,0 +1,328 @@
+require 'spec_helper'
+
+describe ArticlesController do
+ let(:normal_user_email) { "normal_user@example.com" }
+
+ shared_examples "permission control" do
+ it "requrie admin" do
+ expect(response).to redirect_to root_path
+ end
+ end
+
+ describe "GET #index" do
+ let!(:normal_article) { create :article }
+ let!(:draft_article) { create :article, tag_list: "draft" }
+
+ shared_examples "for all user" do
+ it "page title set to '首页'" do
+ expect(assigns[:page_title]).to eq "首页"
+ end
+
+ it "render index page" do
+ expect(response).to render_template :index
+ end
+ end
+
+ shared_examples "for no or normal user sign in" do
+ it "get @articles without draft tag" do
+ expect(assigns[:articles]).to eq [normal_article]
+ end
+ end
+
+ context "when no user sign in" do
+ before { get :index }
+
+ it_behaves_like "for all user"
+ it_behaves_like "for no or normal user sign in"
+ end
+
+ context "when sign in with normal user" do
+ before do
+ set_user_session normal_user_email
+ get :index
+ end
+
+ it_behaves_like "for all user"
+ it_behaves_like "for no or normal user sign in"
+ end
+
+ context "when sign in with admin" do
+ before do
+ set_user_session APP_CONFIG[:admin_email]
+ get :index
+ end
+
+ it_behaves_like "for all user"
+
+ it "get @articles with draft tag" do
+ expect(assigns[:articles]).to eq [draft_article, normal_article]
+ end
+ end
+ end
+
+ describe "GET #new" do
+ context "when no user sign in" do
+ before { get :new }
+
+ it_behaves_like "permission control"
+ end
+
+ context "when sign in with normal user" do
+ before do
+ set_user_session normal_user_email
+ get :new
+ end
+
+ it_behaves_like "permission control"
+ end
+
+ context "when sign in with admin" do
+ before do
+ set_user_session APP_CONFIG[:admin_email]
+ get :new
+ end
+
+ it "create new @article" do
+ expect(assigns[:article]).to be_a_new(Article)
+ end
+
+ it "set page title to '发布文章'" do
+ expect(assigns[:page_title]).to eq "发布文章"
+ end
+
+ it "render new page" do
+ expect(response).to render_template :new
+ end
+ end
+ end
+
+ describe "POST #create" do
+ let(:article_attributes) { attributes_for :article }
+
+ context "when no user sign in" do
+ before { post :create, article: article_attributes }
+
+ it_behaves_like "permission control"
+ end
+
+ context "when sign in with normal user" do
+ before do
+ set_user_session normal_user_email
+ post :create, article: article_attributes
+ end
+
+ it_behaves_like "permission control"
+ end
+
+ context "when sign in with admin" do
+ before do
+ set_user_session APP_CONFIG[:admin_email]
+ end
+
+ context "with valid attributes" do
+ it "save @article to database" do
+ expect do
+ post :create, article: article_attributes
+ end.to change(Article, :count).by(1)
+ end
+
+ it "redirect to article path" do
+ post :create, article: article_attributes
+ expect(response).to redirect_to article_path(assigns[:article])
+ end
+ end
+
+ context "with invalid attributes" do
+ let(:invalid_attributes) { { title: "", content: "", tag_list: "" } }
+ it "does not save article to database" do
+ expect do
+ post :create, article: invalid_attributes
+ end.to_not change(Article, :count)
+ end
+
+ it "re-render new page" do
+ post :create, article: invalid_attributes
+ expect(response).to render_template :new
+ end
+ end
+ end
+ end
+
+ describe "GET #show" do
+ shared_examples "for all user" do
+ it "get @article" do
+ expect(assigns[:article]).to eq article
+ end
+
+ it "set page title" do
+ expect(assigns[:page_title]).to eq "文章 - #{assigns[:article].title}"
+ end
+
+ it "render show page" do
+ expect(response).to render_template :show
+ end
+ end
+
+ let(:article) { create :article }
+
+ context "when no user sign in" do
+ before { get :show, id: article }
+
+ it_behaves_like "for all user"
+ end
+
+ context "when sign in with normal user" do
+ before do
+ set_user_session normal_user_email
+ get :show, id: article
+ end
+
+ it_behaves_like "for all user"
+ end
+
+ context "when sign in with admin" do
+ before do
+ set_user_session APP_CONFIG[:admin_email]
+ get :show, id: article
+ end
+
+ it_behaves_like "for all user"
+ end
+ end
+
+ describe "GET #edit" do
+ let(:article) { create :article }
+
+ context "when no user sign in" do
+ before { get :edit, id: article }
+
+ it_behaves_like "permission control"
+ end
+
+ context "when sign in with normal user" do
+ before do
+ set_user_session normal_user_email
+ get :edit, id: article
+ end
+
+ it_behaves_like "permission control"
+ end
+
+ context "when sign in with admin" do
+ before do
+ set_user_session APP_CONFIG[:admin_email]
+ get :edit, id: article
+ end
+
+ it "get @article" do
+ expect(assigns[:article]).to eq article
+ end
+
+ it "set page title" do
+ expect(assigns[:page_title]).to eq "编辑文章 - #{assigns[:article].title}"
+ end
+
+ it "render edit page" do
+ expect(response).to render_template :edit
+ end
+ end
+ end
+
+ describe "PATCH #update" do
+ let!(:article) { create :article }
+ let(:article_attributes) { {title: article.title,
+ content: article.content + "new added",
+ tag_list: article.tag_list} }
+
+ context "when no user sign in" do
+ before { patch :update, id: article, article: article_attributes }
+
+ it_behaves_like "permission control"
+ end
+
+ context "when sign in with normal user" do
+ before do
+ set_user_session normal_user_email
+ patch :update, id: article, article: article_attributes
+ end
+
+ it_behaves_like "permission control"
+ end
+
+ context "when sign in with admin" do
+ before do
+ set_user_session APP_CONFIG[:admin_email]
+ end
+
+ context "with valid attributes" do
+ it "update article" do
+ patch :update, id: article, article: article_attributes
+
+ updated_article = assigns[:article].reload
+ expect(updated_article.content).to eq article_attributes[:content]
+ end
+
+ it "redirect to article page" do
+ patch :update, id: article, article: article_attributes
+
+ expect(response).to redirect_to article_path(assigns[:article])
+ end
+ end
+
+ context "with invalid attributes" do
+ let(:article_attributes) { {title: "",
+ content: "",
+ tag_list: ""} }
+ it "dese not update article" do
+ patch :update, id: article, article: article_attributes
+
+ updated_article = assigns[:article].reload
+ expect(updated_article.content).to_not eq article_attributes[:content]
+ end
+
+ it "re-render edit page" do
+ patch :update, id: article, article: { title: '' }
+
+ expect(response).to render_template :edit
+ end
+ end
+ end
+ end
+
+ describe "DELETE #destroy" do
+ let!(:article) { create :article }
+
+ context "when no user sign in" do
+ before { delete :destroy, id: article }
+
+ it_behaves_like "permission control"
+ end
+
+ context "when sign in with normal user" do
+ before do
+ set_user_session normal_user_email
+ delete :destroy, id: article
+ end
+
+ it_behaves_like "permission control"
+ end
+
+ context "when sign in with admin" do
+ before do
+ set_user_session APP_CONFIG[:admin_email]
+ end
+
+ it "destroy @article" do
+ expect do
+ delete :destroy, id: article
+ end.to change(Article, :count).by(-1)
+ end
+
+ it "redirect to articles path" do
+ delete :destroy, id: article
+
+ expect(response).to redirect_to articles_path
+ end
+ end
+ end
+end
View
72 spec/features/articles_spec.rb
@@ -0,0 +1,72 @@
+require 'spec_helper'
+
+feature "Articles" do
+ scenario "Post a new article", js: true do
+ sign_in APP_CONFIG[:admin_email]
+ click_link "现在就发表一篇"
+ expect(current_path).to eq new_article_path
+
+ article = build :article
+ within(".new_article") do
+ fill_in "article[title]", with: article.title
+ fill_in "article[tag_list]", with: article.tag_list
+ fill_in "article[content]", with: article.content
+ end
+ click_button "发表文章"
+
+ article = Article.last
+ expect(current_path).to eq article_path(article)
+ expect(page).to have_content article.title
+ article.tags.pluck(:name).each do |tag_name|
+ expect(page).to have_content tag_name
+ end
+ expect(page).to have_content article.content
+
+ sign_out
+ end
+
+
+ scenario "Edit a exist article", js: true do
+ article = create :article
+
+ sign_in APP_CONFIG[:admin_email]
+ click_link article.title
+ expect(current_path).to eq article_path(article)
+
+ click_link "编辑"
+ expect(current_path).to eq edit_article_path(article)
+
+ within(".edit_article") do
+ fill_in "article[title]", with: article.title + "new"
+ fill_in "article[tag_list]", with: article.tag_list + ",tag3"
+ fill_in "article[content]", with: article.content + "new"
+ end
+ click_button "发表文章"
+
+ expect(current_path).to eq article_path(article.reload)
+ expect(page).to have_content article.title
+ article.tags.pluck(:name).each do |tag_name|
+ expect(page).to have_content tag_name
+ end
+ expect(page).to have_content article.content
+
+ sign_out
+ end
+
+ scenario "Delete a exist article", js: true do
+ article = create :article
+
+ sign_in APP_CONFIG[:admin_email]
+ click_link article.title
+ expect(current_path).to eq article_path(article)
+
+ click_link "删除"
+
+ confirm = page.driver.browser.switch_to.alert
+ confirm.accept
+
+ expect(current_path).to eq articles_path
+
+ sign_out
+ end
+end
View
12 spec/features/persona_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+feature "Psersona" do
+ scenario "sign in and sign out", js: true do
+ visit root_path
+ sign_in APP_CONFIG["admin_email"]
+ expect(page).to have_content "退出"
+
+ sign_out
+ expect(page).to have_content "登录"
+ end
+end
View
9 spec/models/article_spec.rb
@@ -116,4 +116,13 @@
it { should be_draft }
end
end
+
+ describe "published scope" do
+ it "return articles without tagged with 'draft'" do
+ normal_article = create :article
+ draft_article = create :article, tag_list: "draft"
+
+ expect(Article.published).to eq [normal_article]
+ end
+ end
end
View
15 spec/spec_helper.rb
@@ -3,6 +3,7 @@
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
+require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
@@ -12,6 +13,8 @@
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
+#Capybara.javascript_driver = :webkit
+
RSpec.configure do |config|
# ## Mock Framework
#
@@ -22,14 +25,24 @@
# config.mock_with :rr
config.include FactoryGirl::Syntax::Methods
+ config.include PersonaMacros
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
- config.use_transactional_fixtures = true
+ config.use_transactional_fixtures = false
+
+ config.before(:each) do
+ DatabaseCleaner.strategy = example.metadata[:js] ? :truncation : :transaction
+ DatabaseCleaner.start
+ end
+
+ config.after(:each) do
+ DatabaseCleaner.clean
+ end
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
View
30 spec/support/persona_macros.rb
@@ -0,0 +1,30 @@
+module PersonaMacros
+ def set_user_session(user_email)
+ session[:email] = user_email
+ end
+
+ def sign_in(email)
+ require 'fakeweb'
+
+ visit root_path
+ FakeWeb.register_uri(:post, "https://verifier.login.persona.org/verify",
+ body: { status: "okay", email: email }.to_json,
+ status: ["200", "OK"])
+
+ click_link '登录'
+
+ alert = page.driver.browser.switch_to.alert
+ alert.send_keys email
+ alert.accept
+ #page.driver.js_prompt_input = email
+ #page.driver.accept_js_prompts!
+ end
+
+ def sign_out
+ click_link "退出"
+
+ alert = page.driver.browser.switch_to.alert
+ alert.accept
+ # page.driver.accept_js_comfirms!
+ end
+end

0 comments on commit 39c738a

Please sign in to comment.