fix conflict

This commit is contained in:
Juanjo Bazán
2015-08-05 14:46:18 +02:00
28 changed files with 363 additions and 159 deletions

1
.coveralls.yml Normal file
View File

@@ -0,0 +1 @@
service_name: travis-ci

2
.gitignore vendored
View File

@@ -19,3 +19,5 @@
/spec/examples.txt /spec/examples.txt
/config/database.yml /config/database.yml
/config/secrets.yml /config/secrets.yml
/coverage

View File

@@ -56,5 +56,6 @@ end
group :test do group :test do
gem 'database_cleaner' gem 'database_cleaner'
gem 'poltergeist' gem 'poltergeist'
gem 'coveralls', require: false
end end

View File

@@ -75,6 +75,12 @@ GEM
execjs execjs
coffee-script-source (1.9.1.1) coffee-script-source (1.9.1.1)
columnize (0.9.0) columnize (0.9.0)
coveralls (0.8.2)
json (~> 1.8)
rest-client (>= 1.6.8, < 2)
simplecov (~> 0.10.0)
term-ansicolor (~> 1.3)
thor (~> 0.19.1)
database_cleaner (1.4.1) database_cleaner (1.4.1)
debug_inspector (0.0.2) debug_inspector (0.0.2)
devise (3.5.1) devise (3.5.1)
@@ -85,6 +91,9 @@ GEM
thread_safe (~> 0.1) thread_safe (~> 0.1)
warden (~> 1.2.3) warden (~> 1.2.3)
diff-lcs (1.2.5) diff-lcs (1.2.5)
docile (1.1.5)
domain_name (0.5.24)
unf (>= 0.0.5, < 1.0.0)
erubis (2.7.0) erubis (2.7.0)
execjs (2.5.2) execjs (2.5.2)
factory_girl (4.5.0) factory_girl (4.5.0)
@@ -97,6 +106,8 @@ GEM
sass (>= 3.3.0, < 3.5) sass (>= 3.3.0, < 3.5)
globalid (0.3.5) globalid (0.3.5)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
http-cookie (1.0.2)
domain_name (~> 0.5)
i18n (0.7.0) i18n (0.7.0)
jbuilder (2.3.1) jbuilder (2.3.1)
activesupport (>= 3.0.0, < 5) activesupport (>= 3.0.0, < 5)
@@ -121,6 +132,7 @@ GEM
mini_portile (0.6.2) mini_portile (0.6.2)
minitest (5.7.0) minitest (5.7.0)
multi_json (1.11.2) multi_json (1.11.2)
netrc (0.10.3)
nokogiri (1.6.6.2) nokogiri (1.6.6.2)
mini_portile (~> 0.6.0) mini_portile (~> 0.6.0)
orm_adapter (0.5.0) orm_adapter (0.5.0)
@@ -164,6 +176,10 @@ GEM
recaptcha (0.4.0) recaptcha (0.4.0)
responders (2.1.0) responders (2.1.0)
railties (>= 4.2.0, < 5) railties (>= 4.2.0, < 5)
rest-client (1.8.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rspec-core (3.3.1) rspec-core (3.3.1)
rspec-support (~> 3.3.0) rspec-support (~> 3.3.0)
rspec-expectations (3.3.0) rspec-expectations (3.3.0)
@@ -191,6 +207,11 @@ GEM
sdoc (0.4.1) sdoc (0.4.1)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0) rdoc (~> 4.0)
simplecov (0.10.0)
docile (~> 1.1.0)
json (~> 1.8)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
spring (1.3.6) spring (1.3.6)
sprockets (3.2.0) sprockets (3.2.0)
rack (~> 1.0) rack (~> 1.0)
@@ -198,9 +219,12 @@ GEM
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
term-ansicolor (1.3.2)
tins (~> 1.0)
thor (0.19.1) thor (0.19.1)
thread_safe (0.3.5) thread_safe (0.3.5)
tilt (1.4.1) tilt (1.4.1)
tins (1.5.4)
turbolinks (2.5.3) turbolinks (2.5.3)
coffee-rails coffee-rails
tzinfo (1.2.2) tzinfo (1.2.2)
@@ -208,6 +232,9 @@ GEM
uglifier (2.7.1) uglifier (2.7.1)
execjs (>= 0.3.0) execjs (>= 0.3.0)
json (>= 1.8.0) json (>= 1.8.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.1)
warden (1.2.3) warden (1.2.3)
rack (>= 1.0) rack (>= 1.0)
web-console (2.2.1) web-console (2.2.1)
@@ -232,6 +259,7 @@ DEPENDENCIES
capybara capybara
ckeditor ckeditor
coffee-rails (~> 4.1.0) coffee-rails (~> 4.1.0)
coveralls
database_cleaner database_cleaner
devise devise
factory_girl_rails factory_girl_rails

View File

@@ -1,5 +1,10 @@
# Aplicación de Participación Ciudadana del Ayuntamiento de Madrid # Aplicación de Participación Ciudadana del Ayuntamiento de Madrid
[![Build Status](https://travis-ci.org/AyuntamientoMadrid/participacion.svg?branch=master)](https://travis-ci.org/AyuntamientoMadrid/participacion)
[![Code Climate](https://codeclimate.com/github/AyuntamientoMadrid/participacion/badges/gpa.svg)](https://codeclimate.com/github/AyuntamientoMadrid/participacion)
[![Dependency Status](https://gemnasium.com/AyuntamientoMadrid/participacion.svg)](https://gemnasium.com/AyuntamientoMadrid/participacion)
[![Coverage Status](https://coveralls.io/repos/AyuntamientoMadrid/participacion/badge.svg?branch=master&service=github)](https://coveralls.io/github/AyuntamientoMadrid/participacion?branch=master)
Este es el repositorio de código abierto de la Aplicación de Participación Ciudadana del Ayuntamiento de Madrid. Este es el repositorio de código abierto de la Aplicación de Participación Ciudadana del Ayuntamiento de Madrid.
## Estado del proyecto ## Estado del proyecto
@@ -22,8 +27,8 @@ cd participacion
bundle install bundle install
cp config/database.yml.example config/database.yml cp config/database.yml.example config/database.yml
cp config/secrets.yml.example config/secrets.yml cp config/secrets.yml.example config/secrets.yml
bundle exec bin/rake db:create db:schema_load bundle exec bin/rake db:create db:schema:load
RAILS_ENV=test bundle exec rake db:create db:schema_load RAILS_ENV=test bundle exec rake db:create db:schema:load
``` ```
Para ejecutar la aplicación en local: Para ejecutar la aplicación en local:

View File

@@ -7,4 +7,9 @@ class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception. # Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead. # For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception protect_from_forgery with: :exception
def verify_captcha?(resource)
return true unless recaptcha_keys?
verify_recaptcha(model: resource)
end
end end

View File

@@ -1,6 +1,6 @@
class CommentsController < ApplicationController class CommentsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action :set_debate, :set_parent before_action :set_debate, :set_parent, only: :create
respond_to :html, :js respond_to :html, :js
def create def create
@@ -10,6 +10,12 @@ class CommentsController < ApplicationController
respond_with @comment respond_with @comment
end end
def vote
@comment = Comment.find(params[:id])
@comment.vote_by(voter: current_user, vote: params[:value])
respond_with @comment
end
private private
def comment_params def comment_params
params.require(:comments).permit(:commentable_type, :commentable_id, :body) params.require(:comments).permit(:commentable_type, :commentable_id, :body)

View File

@@ -1,7 +1,7 @@
class DebatesController < ApplicationController class DebatesController < ApplicationController
include RecaptchaHelper include RecaptchaHelper
before_action :set_debate, only: [:show, :edit, :update] before_action :set_debate, only: [:show, :edit, :update, :vote]
before_action :authenticate_user!, except: [:show, :index] before_action :authenticate_user!, except: [:index, :show]
before_action :validate_ownership, only: [:edit, :update] before_action :validate_ownership, only: [:edit, :update]
def index def index
@@ -26,7 +26,7 @@ class DebatesController < ApplicationController
def create def create
@debate = Debate.new(debate_params) @debate = Debate.new(debate_params)
@debate.author = current_user @debate.author = current_user
if verify_captcha? and @debate.save if verify_captcha?(@debate) and @debate.save
redirect_to @debate, notice: t('flash.actions.create.notice', resource_name: 'Debate') redirect_to @debate, notice: t('flash.actions.create.notice', resource_name: 'Debate')
else else
render :new render :new
@@ -38,6 +38,10 @@ class DebatesController < ApplicationController
respond_with @debate respond_with @debate
end end
def vote
@debate.vote_by(voter: current_user, vote: params[:value])
end
private private
def set_debate def set_debate
@@ -51,10 +55,4 @@ class DebatesController < ApplicationController
def validate_ownership def validate_ownership
raise ActiveRecord::RecordNotFound unless @debate.editable_by?(current_user) raise ActiveRecord::RecordNotFound unless @debate.editable_by?(current_user)
end end
def verify_captcha?
return true unless recaptcha_keys?
verify_recaptcha(model: @debate)
end
end end

View File

@@ -1,7 +1,8 @@
class RegistrationsController < Devise::RegistrationsController class RegistrationsController < Devise::RegistrationsController
include RecaptchaHelper
def create def create
if verify_recaptcha if verify_captcha?(resource)
super super
else else
build_resource(sign_up_params) build_resource(sign_up_params)

View File

@@ -1,21 +0,0 @@
class VotesController < ApplicationController
before_action :set_debate
before_action :authenticate_user!
respond_to :html, :js
def create
register_vote
notice = @debate.vote_registered? ? I18n.t("votes.notice_thanks") : I18n.t("votes.notice_already_registered")
respond_with @debate
end
private
def set_debate
@debate = Debate.find(params[:debate_id])
end
def register_vote
@debate.vote_by voter: current_user, vote: params[:value]
end
end

View File

@@ -1,5 +1,6 @@
class Comment < ActiveRecord::Base class Comment < ActiveRecord::Base
acts_as_nested_set scope: [:commentable_id, :commentable_type] acts_as_nested_set scope: [:commentable_id, :commentable_type]
acts_as_votable
validates :body, presence: true validates :body, presence: true
validates :user, presence: true validates :user, presence: true

View File

@@ -35,6 +35,10 @@ class Debate < ActiveRecord::Base
editable? && author == user editable? && author == user
end end
def description
super.try :html_safe
end
protected protected
def sanitize_description def sanitize_description

View File

@@ -8,6 +8,11 @@
<%= comment.user.name %>&nbsp;&bullet;&nbsp;<%= time_ago_in_words(comment.created_at) %> <%= comment.user.name %>&nbsp;&bullet;&nbsp;<%= time_ago_in_words(comment.created_at) %>
</span> </span>
<p><%= comment.body %></p> <p><%= comment.body %></p>
<span id="<%= dom_id(comment) %>_votes">
<%= render 'comments/votes', comment: comment %>
</span>
<% if user_signed_in? %> <% if user_signed_in? %>
<p class="reply"><%= render 'comments/form', {parent: comment, toggeable: true} %></p> <p class="reply"><%= render 'comments/form', {parent: comment, toggeable: true} %></p>
<% end %> <% end %>

View File

@@ -0,0 +1,11 @@
<span class="in_favor">
<%= link_to "up", vote_comment_path(comment, value: 'yes'),
method: "post", remote: true %>
<%= comment.get_likes.size %>
</span>
<span class="against">
<%= link_to "down", vote_comment_path(comment, value: 'no'),
method: "post", remote: true %>
<%= comment.get_dislikes.size %>
</span>

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@comment) %>_votes").html('<%= j render("comments/votes", comment: @comment) %>');

View File

@@ -10,29 +10,15 @@
<p class="debate-info"> <p class="debate-info">
<i class="icon-chat-bubble-two"></i>&nbsp;<%= pluralize(debate.comment_threads.count, t("debates.debate.comment"), t("debates.debate.comments")) %> <i class="icon-chat-bubble-two"></i>&nbsp;<%= pluralize(debate.comment_threads.count, t("debates.debate.comment"), t("debates.debate.comments")) %>
</p> </p>
<p><%= sanitize(truncate(debate.description, length: 200).html_safe) %></p> <%= debate.description %>
<%= render "shared/tags", debate: debate %> <%= render "shared/tags", debate: debate %>
</div> </div>
</div> </div>
<div class="small-12 medium-3 column">
<div class="text-center votes">
<%= link_to debate_votes_path(debate, value: 'yes'), class: "like inline-block", title: t('votes.agree'), method: "post" do %>
<i class="icon-like"></i>
<span><%= percentage('likes', debate) %></span>
<% end %>
<span class="divider"></span> <div id="<%= dom_id(debate) %>_votes" class="small-12 medium-3 column">
<%= render 'debates/votes_min', debate: debate %>
</div>
<%= link_to debate_votes_path(debate, value: 'no'), class: "unlike inline-block", title: t('votes.disagree'), method: "post" do %>
<i class="icon-unlike"></i>
<span><%= percentage('dislikes', debate) %></span>
<% end %>
<br>
<span class="total-votes">
<%= pluralize(debate.total_votes, t("debates.debate.vote"), t("debates.debate.votes")) %>
</span>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -16,22 +16,8 @@
</div> </div>
<div class="row votes"> <div class="row votes">
<div class="small-12 column"> <div id="<%= dom_id(featured_debate) %>_votes" class="small-12 column">
<%= link_to debate_votes_path(featured_debate, value: "yes"), class: "like", title: t('votes.agree'), method: "post" do %> <%= render 'debates/featured_debate_votes', debate: featured_debate %>
<i class="icon-like"></i>
<span><%= percentage('likes', featured_debate) %></span>
<% end %>
<span class="divider"></span>
<%= link_to debate_votes_path(featured_debate, value: "no"), class: "unlike", title: t('votes.disagree'), method: "post" do %>
<i class="icon-unlike"></i>
<span><%= percentage('dislikes', featured_debate) %></span>
<% end %>
<span class="total-votes right">
<%= pluralize(featured_debate.total_votes, t("debates.debate.vote"), t("debates.debate.votes")) %>
</span>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,21 @@
<span id="in_favor">
<%= link_to vote_debate_path(debate, value: 'yes', partial: 'featured_debate_votes'),
class: "like", title: t('votes.agree'), method: "post", remote: true do %>
<i class="icon-like"></i>
<span><%= percentage('likes', debate) %></span>
<% end %>
</span>
<span class="divider"></span>
<span id="against">
<%= link_to vote_debate_path(debate, value: 'no', partial: 'featured_debate_votes'),
class: "unlike", title: t('votes.disagree'), method: "post", remote: true do %>
<i class="icon-unlike"></i>
<span><%= percentage('dislikes', debate) %></span>
<% end %>
</span>
<span class="total-votes right">
<%= pluralize(debate.total_votes, t("debates.debate.vote"), t("debates.debate.votes")) %>
</span>

View File

@@ -7,7 +7,8 @@
<div class="text-center"> <div class="text-center">
<div id="in_favor" class="inline-block"> <div id="in_favor" class="inline-block">
<%= link_to debate_votes_path(@debate, value: 'yes'), class: "like", title: t('votes.agree'), method: "post", remote: true do %> <%= link_to vote_debate_path(@debate, value: 'yes', partial: 'votes'),
class: "like", title: t('votes.agree'), method: "post", remote: true do %>
<i class="icon-like"></i> <i class="icon-like"></i>
<span><%= percentage('likes', @debate) %></span> <span><%= percentage('likes', @debate) %></span>
<% end %> <% end %>
@@ -16,7 +17,8 @@
<span class="divider"></span> <span class="divider"></span>
<div id="against" class="inline-block"> <div id="against" class="inline-block">
<%= link_to debate_votes_path(@debate, value: 'no'), class: "unlike", title: t('votes.disagree'), method: "post", remote: true do %> <%= link_to vote_debate_path(@debate, value: 'no', partial: 'votes'),
class: "unlike", title: t('votes.disagree'), method: "post", remote: true do %>
<i class="icon-unlike"></i> <i class="icon-unlike"></i>
<span><%= percentage('dislikes', @debate) %></span> <span><%= percentage('dislikes', @debate) %></span>
<% end %> <% end %>

View File

@@ -0,0 +1,22 @@
<div class="text-center votes">
<span id="in_favor">
<%= link_to vote_debate_path(debate, value: 'yes', partial: 'votes_min'),
class: "like inline-block", title: t('votes.agree'), method: "post", remote: true do %>
<i class="icon-like"></i>
<span><%= percentage('likes', debate) %></span>
<% end %>
</span>
<span class="divider"></span>
<span id="against">
<%= link_to vote_debate_path(debate, value: 'no', partial: 'votes_min'),
class: "unlike inline-block", title: t('votes.disagree'), method: "post", remote: true do %>
<i class="icon-unlike"></i>
<span><%= percentage('dislikes', debate) %></span>
<% end %>
</span>
<br>
<span class="total-votes">
<%= pluralize(debate.total_votes, t("debates.debate.vote"), t("debates.debate.votes")) %>
</span>
</div>

View File

@@ -7,11 +7,11 @@
<span class="author"><%= @debate.author.name %></span><span class="bullet">&nbsp;&bullet;&nbsp;</span> <%= l @debate.created_at.to_date %> <span class="bullet">&nbsp;&bullet;&nbsp;</span><i class="icon-chat-bubble-two"></i>&nbsp;<%= pluralize(@debate.comment_threads.count, t("debates.show.comment"), t("debates.show.comments")) %> <span class="author"><%= @debate.author.name %></span><span class="bullet">&nbsp;&bullet;&nbsp;</span> <%= l @debate.created_at.to_date %> <span class="bullet">&nbsp;&bullet;&nbsp;</span><i class="icon-chat-bubble-two"></i>&nbsp;<%= pluralize(@debate.comment_threads.count, t("debates.show.comment"), t("debates.show.comments")) %>
</div> </div>
<h1><%= @debate.title %></h1> <h1><%= @debate.title %></h1>
<p><%= @debate.description %></p> <%= @debate.description %>
<p><%= render 'shared/tags', debate: @debate %></p> <p><%= render 'shared/tags', debate: @debate %></p>
</div> </div>
<div id="votes" class="small-12 medium-3 column votes"> <div id="<%= dom_id(@debate) %>_votes" class="votes small-12 medium-3 column">
<%= render 'votes/votes' %> <%= render 'debates/votes' %>
<div class="text-center"> <div class="text-center">
<% if user_signed_in? %> <% if user_signed_in? %>
<%= link_to t("debates.show.leave_comment"), "#comments", class: "leave-comment" %> <%= link_to t("debates.show.leave_comment"), "#comments", class: "leave-comment" %>

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@debate) %>_votes").html('<%= j render("debates/#{params[:partial]}", debate: @debate) %>');

View File

@@ -1 +0,0 @@
$("#votes").html("<%= j render('votes') %>");

View File

@@ -6,9 +6,18 @@ Rails.application.routes.draw do
# You can have the root of your site routed with "root" # You can have the root of your site routed with "root"
root 'debates#index' root 'debates#index'
resources :debates do resources :debates do
resources :votes, only: :create member do
resources :comments, only: :create post :vote
end
resources :comments, only: :create, shallow: true do
member do
post :vote
end
end
end end
resource :account, controller: "account", only: [:show, :update] resource :account, controller: "account", only: [:show, :update]

View File

@@ -54,21 +54,22 @@ feature 'Debates' do
expect(page).to have_content I18n.l(Date.today) expect(page).to have_content I18n.l(Date.today)
end end
scenario 'JS injection is sanitized' do scenario 'JS injection is prevented but safe html is respected' do
author = create(:user) author = create(:user)
login_as(author) login_as(author)
visit new_debate_path visit new_debate_path
fill_in 'debate_title', with: 'A test' fill_in 'debate_title', with: 'A test'
fill_in 'debate_description', with: 'This is <script>alert("an attack");</script>' fill_in 'debate_description', with: '<p>This is <script>alert("an attack");</script></p>'
check 'debate_terms_of_service' check 'debate_terms_of_service'
click_button 'Create Debate' click_button 'Create Debate'
expect(page).to have_content 'Debate was successfully created.' expect(page).to have_content 'Debate was successfully created.'
expect(page).to have_content 'A test' expect(page).to have_content 'A test'
expect(page).to have_content 'This is alert("an attack");' expect(page.html).to include '<p>This is alert("an attack");</p>'
expect(page.html).to_not include '<script>alert("an attack");</script>' expect(page.html).to_not include '<script>alert("an attack");</script>'
expect(page.html).to_not include '&lt;p&gt;This is'
end end
scenario 'tagging using dangerous strings' do scenario 'tagging using dangerous strings' do

View File

@@ -2,6 +2,8 @@ require 'rails_helper'
feature 'Votes' do feature 'Votes' do
feature 'Debates' do
background do background do
@manuela = create(:user) @manuela = create(:user)
@pablo = create(:user) @pablo = create(:user)
@@ -28,7 +30,7 @@ feature 'Votes' do
end end
end end
scenario 'Create', :js do scenario 'Create from debate show', :js do
find('#in_favor a').click find('#in_favor a').click
within('#in_favor') do within('#in_favor') do
@@ -42,6 +44,47 @@ feature 'Votes' do
expect(page).to have_content "1 vote" expect(page).to have_content "1 vote"
end end
scenario 'Create from debate featured', :js do
visit debates_path
within("#featured-debates") do
find('#in_favor a').click
within('#in_favor') do
expect(page).to have_content "100%"
end
within('#against') do
expect(page).to have_content "0%"
end
expect(page).to have_content "1 vote"
end
expect(URI.parse(current_url).path).to eq(debates_path)
end
scenario 'Create from debate index', :js do
3.times { create(:debate) }
visit debates_path
within("#debates") do
expect(page).to have_css(".debate", count: 1)
find('#in_favor a').click
within('#in_favor') do
expect(page).to have_content "100%"
end
within('#against') do
expect(page).to have_content "0%"
end
expect(page).to have_content "1 vote"
end
expect(URI.parse(current_url).path).to eq(debates_path)
end
scenario 'Update', :js do scenario 'Update', :js do
find('#in_favor a').click find('#in_favor a').click
find('#against a').click find('#against a').click
@@ -73,3 +116,80 @@ feature 'Votes' do
end end
end end
feature 'Comments' do
background do
@manuela = create(:user)
@pablo = create(:user)
@debate = create(:debate)
@comment = create(:comment, commentable: @debate)
login_as(@manuela)
visit debate_path(@debate)
end
scenario 'Show' do
vote = create(:vote, voter: @manuela, votable: @comment, vote_flag: true)
vote = create(:vote, voter: @pablo, votable: @comment, vote_flag: false)
visit debate_path(@debate)
within("#comment_#{@comment.id}_votes") do
within(".in_favor") do
expect(page).to have_content "1"
end
within(".against") do
expect(page).to have_content "1"
end
end
end
scenario 'Create', :js do
within("#comment_#{@comment.id}_votes") do
find(".in_favor a").click
within(".in_favor") do
expect(page).to have_content "1"
end
within(".against") do
expect(page).to have_content "0"
end
end
end
scenario 'Update', :js do
within("#comment_#{@comment.id}_votes") do
find('.in_favor a').click
find('.against a').click
within('.in_favor') do
expect(page).to have_content "0"
end
within('.against') do
expect(page).to have_content "1"
end
end
end
scenario 'Trying to vote multiple times', :js do
within("#comment_#{@comment.id}_votes") do
find('.in_favor a').click
find('.in_favor a').click
within('.in_favor') do
expect(page).to have_content "1"
end
within('.against') do
expect(page).to have_content "0"
end
end
end
end
end

View File

@@ -20,17 +20,24 @@ describe Debate do
expect(@debate).to_not be_valid expect(@debate).to_not be_valid
end end
it "should not be valid without a description" do describe "#description" do
it "should be mandatory" do
@debate.description = nil @debate.description = nil
expect(@debate).to_not be_valid expect(@debate).to_not be_valid
end end
it "should sanitize the description" do it "should be sanitized" do
@debate.description = "<script>alert('danger');</script>" @debate.description = "<script>alert('danger');</script>"
@debate.valid? @debate.valid?
expect(@debate.description).to eq("alert('danger');") expect(@debate.description).to eq("alert('danger');")
end end
it "should be html_safe" do
@debate.description = "<script>alert('danger');</script>"
expect(@debate.description).to be_html_safe
end
end
it "should sanitize the tag list" do it "should sanitize the tag list" do
@debate.tag_list = "user_id=1" @debate.tag_list = "user_id=1"
@debate.valid? @debate.valid?

View File

@@ -1,3 +1,5 @@
require 'coveralls'
Coveralls.wear!('rails')
ENV['RAILS_ENV'] ||= 'test' ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__) require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production? abort("The Rails environment is running in production mode!") if Rails.env.production?