fix the specs for the page model
This commit is contained in:
parent
73b559260e
commit
02e48f5c36
@ -9,6 +9,13 @@ module Locomotive
|
|||||||
include ::Mongoid::Tree
|
include ::Mongoid::Tree
|
||||||
include ::Mongoid::Tree::Ordering
|
include ::Mongoid::Tree::Ordering
|
||||||
|
|
||||||
|
## fields ##
|
||||||
|
field :depth, :type => Integer, :default => 0
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
before_save :persist_depth
|
||||||
|
before_destroy :delete_descendants
|
||||||
|
|
||||||
## indexes ##
|
## indexes ##
|
||||||
index :position
|
index :position
|
||||||
index [:depth.asc, :position.asc]
|
index [:depth.asc, :position.asc]
|
||||||
@ -88,6 +95,16 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def depth
|
||||||
|
self.parent_ids.count
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def persist_depth
|
||||||
|
self.attributes[:depth] = self.depth
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -42,7 +42,7 @@ module Locomotive
|
|||||||
validates_presence_of :site, :title, :slug
|
validates_presence_of :site, :title, :slug
|
||||||
validates_uniqueness_of :slug, :scope => [:site_id, :parent_id]
|
validates_uniqueness_of :slug, :scope => [:site_id, :parent_id]
|
||||||
validates_uniqueness_of :handle, :allow_blank => true
|
validates_uniqueness_of :handle, :allow_blank => true
|
||||||
validates_exclusion_of :slug, :in => Locomotive.config.reserved_slugs, :if => Proc.new { |p| p.depth == 0 }
|
validates_exclusion_of :slug, :in => Locomotive.config.reserved_slugs, :if => Proc.new { |p| p.depth <= 1 }
|
||||||
|
|
||||||
## named scopes ##
|
## named scopes ##
|
||||||
scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.ui.latest_entries_nb
|
scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.ui.latest_entries_nb
|
||||||
|
@ -67,8 +67,7 @@ module Locomotive
|
|||||||
:slug => slug,
|
:slug => slug,
|
||||||
:title => ::I18n.t("attributes.defaults.pages.#{slug}.title"),
|
:title => ::I18n.t("attributes.defaults.pages.#{slug}.title"),
|
||||||
:raw_template => ::I18n.t("attributes.defaults.pages.#{slug}.body"),
|
:raw_template => ::I18n.t("attributes.defaults.pages.#{slug}.body"),
|
||||||
:published => true,
|
:published => true
|
||||||
:depth => 0
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -6,7 +6,7 @@ module Locomotive
|
|||||||
:domain => 'example.com',
|
:domain => 'example.com',
|
||||||
:reserved_subdomains => %w{www admin email blog webmail mail support help site sites},
|
:reserved_subdomains => %w{www admin email blog webmail mail support help site sites},
|
||||||
# :forbidden_paths => %w{layouts snippets stylesheets javascripts assets admin system api},
|
# :forbidden_paths => %w{layouts snippets stylesheets javascripts assets admin system api},
|
||||||
:reserved_slugs => %w{stylesheets javascripts assets admin images api pages edit},
|
:reserved_slugs => %w{stylesheets javascripts assets admin locomotive images api pages edit},
|
||||||
:locales => %w{en de fr pt-BR it nl no es ru},
|
:locales => %w{en de fr pt-BR it nl no es ru},
|
||||||
:site_locales => %w{en de fr pt-BR it nl no es ru},
|
:site_locales => %w{en de fr pt-BR it nl no es ru},
|
||||||
:cookie_key => '_locomotive_session',
|
:cookie_key => '_locomotive_session',
|
||||||
|
@ -31,4 +31,45 @@ module Mongoid#:nodoc:
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# make the validators work with localized field
|
||||||
|
module Validations #:nodoc:
|
||||||
|
|
||||||
|
def read_attribute_for_validation_with_localization(attr)
|
||||||
|
if fields[attr.to_s] && fields[attr.to_s].localized?
|
||||||
|
send(attr.to_sym)
|
||||||
|
else
|
||||||
|
read_attribute_for_validation_without_localization(attr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
alias_method_chain :read_attribute_for_validation, :localization
|
||||||
|
|
||||||
|
class PresenceValidator < ActiveModel::EachValidator
|
||||||
|
|
||||||
|
def validate_each(document, attribute, value)
|
||||||
|
document.errors.add(attribute, :blank, options) if value.blank?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
#
|
||||||
|
# class UniquenessValidator < ActiveModel::EachValidator
|
||||||
|
#
|
||||||
|
# protected
|
||||||
|
#
|
||||||
|
# def criterion_with_localization(document, attribute, value)
|
||||||
|
# field = document.fields[attribute.to_s]
|
||||||
|
# if field && field.localized? && !value.blank?
|
||||||
|
# value = document.send(attribute.to_sym)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# criterion_without_localization(document, attribute, value)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# alias_method_chain :criterion, :localization
|
||||||
|
#
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# end
|
||||||
end
|
end
|
@ -15,7 +15,6 @@ describe Locomotive::GlobalActionsCell do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'has a link to edit my account' do
|
it 'has a link to edit my account' do
|
||||||
puts "last test"
|
|
||||||
menu.should have_link('Admin')
|
menu.should have_link('Admin')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -13,29 +13,30 @@ describe Locomotive::Page do
|
|||||||
FactoryGirl.build(:page).should be_valid
|
FactoryGirl.build(:page).should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
# Validations ##
|
describe 'validation' do
|
||||||
|
|
||||||
%w{site title}.each do |field|
|
%w{site title}.each do |field|
|
||||||
it "should validate presence of #{field}" do
|
it "requires the presence of the #{field}" do
|
||||||
page = FactoryGirl.build(:page, field.to_sym => nil)
|
page = FactoryGirl.build(:page, field.to_sym => nil)
|
||||||
page.should_not be_valid
|
page.should_not be_valid
|
||||||
page.errors[field.to_sym].should == ["can't be blank"]
|
page.errors[field.to_sym].should == ["can't be blank"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should validate presence of slug' do
|
it 'requires the presence of the slug' do
|
||||||
page = FactoryGirl.build(:page, :title => nil, :slug => nil)
|
page = FactoryGirl.build(:page, :title => nil, :slug => nil)
|
||||||
page.should_not be_valid
|
page.should_not be_valid
|
||||||
page.errors[:slug].should == ["can't be blank"]
|
page.errors[:slug].should == ["can't be blank"]
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should validate uniqueness of slug' do
|
it 'requires the uniqueness of the slug' do
|
||||||
page = FactoryGirl.create(:page)
|
page = FactoryGirl.create(:page)
|
||||||
(page = FactoryGirl.build(:page, :site => page.site)).should_not be_valid
|
another_page = FactoryGirl.build(:page, :site => page.site)
|
||||||
page.errors[:slug].should == ["is already taken"]
|
another_page.should_not be_valid
|
||||||
|
another_page.errors[:slug].should == ["is already taken"]
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should validate uniqueness of slug within a "folder"' do
|
it 'requires the uniqueness of the slug within a "folder"' do
|
||||||
site = FactoryGirl.create(:site)
|
site = FactoryGirl.create(:site)
|
||||||
root = FactoryGirl.create(:page, :slug => 'index', :site => site)
|
root = FactoryGirl.create(:page, :slug => 'index', :site => site)
|
||||||
child_1 = FactoryGirl.create(:page, :slug => 'first_child', :parent => root, :site => site)
|
child_1 = FactoryGirl.create(:page, :slug => 'first_child', :parent => root, :site => site)
|
||||||
@ -46,14 +47,37 @@ describe Locomotive::Page do
|
|||||||
page.valid?.should be_true
|
page.valid?.should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
%w{admin stylesheets images javascripts}.each do |slug|
|
%w{admin locomotive stylesheets images javascripts}.each do |slug|
|
||||||
it "should consider '#{slug}' as invalid" do
|
it "considers '#{slug}' as invalid" do
|
||||||
page = FactoryGirl.build(:page, :slug => slug)
|
page = FactoryGirl.build(:page, :slug => slug)
|
||||||
|
page.stubs(:depth).returns(1)
|
||||||
page.should_not be_valid
|
page.should_not be_valid
|
||||||
page.errors[:slug].should == ["is reserved"]
|
page.errors[:slug].should == ["is reserved"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context '#i18n' do
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
::Mongoid::Fields::I18n.locale = 'en'
|
||||||
|
@page = FactoryGirl.build(:page, :title => 'Hello world')
|
||||||
|
::Mongoid::Fields::I18n.locale = 'fr'
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:all) do
|
||||||
|
::Mongoid::Fields::I18n.locale = 'en'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'requires the presence of the title' do
|
||||||
|
@page.title = ''
|
||||||
|
@page.valid?.should be_false
|
||||||
|
@page.errors[:title].should == ["can't be blank"]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
# Named scopes ##
|
# Named scopes ##
|
||||||
|
|
||||||
# Associations ##
|
# Associations ##
|
||||||
@ -64,7 +88,9 @@ describe Locomotive::Page do
|
|||||||
|
|
||||||
it 'should tell if the page is the index one' do
|
it 'should tell if the page is the index one' do
|
||||||
FactoryGirl.build(:page, :slug => 'index', :site => nil).index?.should be_true
|
FactoryGirl.build(:page, :slug => 'index', :site => nil).index?.should be_true
|
||||||
FactoryGirl.build(:page, :slug => 'index', :depth => 1, :site => nil).index?.should be_false
|
page = FactoryGirl.build(:page, :slug => 'index', :site => nil)
|
||||||
|
page.stubs(:depth).returns(1)
|
||||||
|
page.index?.should be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should have normalized slug' do
|
it 'should have normalized slug' do
|
||||||
@ -108,44 +134,42 @@ describe Locomotive::Page do
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'acts as tree' do
|
describe 'tree organization' do
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@home = FactoryGirl.create(:page)
|
@home = FactoryGirl.create(:page)
|
||||||
@child_1 = FactoryGirl.create(:page, :title => 'Subpage 1', :slug => 'foo', :parent_id => @home._id, :site => @home.site)
|
@child_1 = FactoryGirl.create(:page, :title => 'Subpage 1', :slug => 'foo', :parent_id => @home._id, :site => @home.site)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should add root elements' do
|
it 'adds root elements' do
|
||||||
page_404 = FactoryGirl.create(:page, :title => 'Page not found', :slug => '404', :site => @home.site)
|
page_404 = FactoryGirl.create(:page, :title => 'Page not found', :slug => '404', :site => @home.site)
|
||||||
Locomotive::Page.roots.count.should == 2
|
Locomotive::Page.roots.count.should == 2
|
||||||
Locomotive::Page.roots.should == [@home, page_404]
|
Locomotive::Page.roots.should == [@home, page_404]
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should add sub pages' do
|
it 'adds sub pages' do
|
||||||
child_2 = FactoryGirl.create(:page, :title => 'Subpage 2', :slug => 'bar', :parent => @home, :site => @home.site)
|
child_2 = FactoryGirl.create(:page, :title => 'Subpage 2', :slug => 'bar', :parent => @home, :site => @home.site)
|
||||||
@home = Locomotive::Page.find(@home.id)
|
@home = Locomotive::Page.find(@home.id)
|
||||||
@home.children.count.should == 2
|
@home.children.count.should == 2
|
||||||
@home.children.should == [@child_1, child_2]
|
@home.children.should == [@child_1, child_2]
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should move its children accordingly' do
|
it 'moves its children accordingly' do
|
||||||
sub_child_1 = FactoryGirl.create(:page, :title => 'Sub Subpage 1', :slug => 'bar', :parent => @child_1, :site => @home.site)
|
sub_child_1 = FactoryGirl.create(:page, :title => 'Sub Subpage 1', :slug => 'bar', :parent => @child_1, :site => @home.site)
|
||||||
archives = FactoryGirl.create(:page, :title => 'archives', :slug => 'archives', :parent => @home, :site => @home.site)
|
archives = FactoryGirl.create(:page, :title => 'archives', :slug => 'archives', :parent => @home, :site => @home.site)
|
||||||
posts = FactoryGirl.create(:page, :title => 'posts', :slug => 'posts', :parent => archives, :site => @home.site)
|
posts = FactoryGirl.create(:page, :title => 'posts', :slug => 'posts', :parent => archives, :site => @home.site)
|
||||||
|
|
||||||
@child_1.parent_id = archives._id
|
@child_1.parent = archives
|
||||||
@child_1.save
|
@child_1.save
|
||||||
|
|
||||||
@child_1.position.should == 2
|
|
||||||
@home.reload.children.count.should == 1
|
@home.reload.children.count.should == 1
|
||||||
|
|
||||||
archives.reload.children.count.should == 2
|
archives.reload.children.count.should == 2
|
||||||
archives.children.last.depth.should == 2
|
archives.children.last.depth.should == 2
|
||||||
archives.children.last.position.should == 2
|
|
||||||
archives.children.last.children.first.depth.should == 3
|
archives.children.last.children.first.depth.should == 3
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should destroy descendants as well' do
|
it 'destroys descendants as well' do
|
||||||
FactoryGirl.create(:page, :title => 'Sub Subpage 1', :slug => 'bar', :parent_id => @child_1._id, :site => @home.site)
|
FactoryGirl.create(:page, :title => 'Sub Subpage 1', :slug => 'bar', :parent_id => @child_1._id, :site => @home.site)
|
||||||
@child_1.destroy
|
@child_1.destroy
|
||||||
Locomotive::Page.where(:slug => 'bar').first.should be_nil
|
Locomotive::Page.where(:slug => 'bar').first.should be_nil
|
||||||
@ -163,12 +187,12 @@ describe Locomotive::Page do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'should be at the bottom of the folder once created' do
|
it 'should be at the bottom of the folder once created' do
|
||||||
[@child_1, @child_2, @child_3].each_with_index { |c, i| c.position.should == i + 1 }
|
[@child_1, @child_2, @child_3].each_with_index { |c, i| c.position.should == i }
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should have its position updated if a sibling is removed' do
|
it 'should have its position updated if a sibling is removed' do
|
||||||
@child_2.destroy
|
@child_2.destroy
|
||||||
[@child_1, @child_3.reload].each_with_index { |c, i| c.position.should == i + 1 }
|
[@child_1, @child_3.reload].each_with_index { |c, i| c.position.should == i }
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -176,8 +200,9 @@ describe Locomotive::Page do
|
|||||||
describe 'templatized extension' do
|
describe 'templatized extension' do
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@page = FactoryGirl.build(:page, :site => nil, :templatized => true, :content_type_id => 42)
|
@page = FactoryGirl.build(:page, :templatized => true, :target_klass_name => 'Foo')
|
||||||
Locomotive::ContentType.stubs(:find).returns(FactoryGirl.build(:content_type, :site => nil))
|
# @page.stubs(:target_klass)
|
||||||
|
# Locomotive::ContentType.stubs(:find).returns(FactoryGirl.build(:content_type, :site => nil))
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is considered as a templatized page' do
|
it 'is considered as a templatized page' do
|
||||||
@ -189,8 +214,52 @@ describe Locomotive::Page do
|
|||||||
@page.slug.should == 'content_type_template'
|
@page.slug.should == 'content_type_template'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does forget to set the content type id' do
|
it 'returns the target klass' do
|
||||||
@page.content_type_id.should == 42
|
@page.target_klass.should == Foo
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'has a name for the target entry' do
|
||||||
|
@page.target_entry_name.should == 'foo'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'uses the find_by_permalink method when fetching the entry' do
|
||||||
|
Foo.expects(:find_by_permalink)
|
||||||
|
@page.fetch_target_entry('foo')
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'using a content type' do
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
@site = FactoryGirl.build(:site)
|
||||||
|
@content_type = FactoryGirl.build(:content_type, :slug => 'posts', :site => @site)
|
||||||
|
@page.site = @site
|
||||||
|
@page.target_klass_name = 'Locomotive::Entry42'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'has a name for the target entry' do
|
||||||
|
@site.stubs(:content_types).returns(mock(:find => @content_type))
|
||||||
|
@page.target_entry_name.should == 'post'
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#security' do
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
Locomotive::ContentType.stubs(:find).returns(@content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is valid if the content type belongs to the site' do
|
||||||
|
@page.send(:ensure_target_klass_name_security)
|
||||||
|
@page.errors.should be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not valid the page if the content type does not belong to the site' do
|
||||||
|
@content_type.site = FactoryGirl.build(:site)
|
||||||
|
@page.send(:ensure_target_klass_name_security)
|
||||||
|
@page.errors[:target_klass_name].should == ['presents a security problem']
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -198,12 +267,12 @@ describe Locomotive::Page do
|
|||||||
describe 'listed extension' do
|
describe 'listed extension' do
|
||||||
|
|
||||||
it 'is considered as a visible page' do
|
it 'is considered as a visible page' do
|
||||||
@page = FactoryGirl.build(:page, :site => nil, :content_type_id => 42)
|
@page = FactoryGirl.build(:page, :site => nil)
|
||||||
@page.listed?.should be_true
|
@page.listed?.should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is not considered as a visible page' do
|
it 'is not considered as a visible page' do
|
||||||
@page = FactoryGirl.build(:page, :site => nil, :listed => false, :content_type_id => 42)
|
@page = FactoryGirl.build(:page, :site => nil, :listed => false)
|
||||||
@page.listed?.should be_false
|
@page.listed?.should be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -231,4 +300,14 @@ describe Locomotive::Page do
|
|||||||
@page.errors[:redirect_url].should == ["is invalid"]
|
@page.errors[:redirect_url].should == ["is invalid"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Foo
|
||||||
|
end
|
||||||
|
|
||||||
|
class Locomotive::Entry42
|
||||||
|
end
|
||||||
|
|
||||||
|
def fake_bson_id(id)
|
||||||
|
BSON::ObjectId(id.to_s.rjust(24, '0'))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user