adva_blog 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +2 -0
  7. data/adva_blog.gemspec +17 -0
  8. data/app/controllers/admin/blog/articles_controller.rb +5 -0
  9. data/app/controllers/admin/blog/categories_controller.rb +1 -0
  10. data/app/controllers/admin/blog/contents_controller.rb +5 -0
  11. data/app/controllers/admin/blogs_controller.rb +1 -0
  12. data/app/controllers/blog_articles_controller.rb +23 -0
  13. data/app/helpers/blog_helper.rb +49 -0
  14. data/app/models/blog.rb +34 -0
  15. data/app/views/admin/blog/articles/index.html.erb +40 -0
  16. data/app/views/admin/sections/settings/_blog.html.erb +11 -0
  17. data/app/views/blogs/articles/_article.html.erb +28 -0
  18. data/app/views/blogs/articles/_footer.html.erb +40 -0
  19. data/app/views/blogs/articles/index.atom.builder +21 -0
  20. data/app/views/blogs/articles/index.html.erb +4 -0
  21. data/app/views/blogs/articles/show.html.erb +14 -0
  22. data/config/initializers/base_controller.rb +3 -0
  23. data/config/routes.rb +49 -0
  24. data/lib/adva_blog.rb +10 -0
  25. data/lib/adva_blog/version.rb +3 -0
  26. data/test/contexts.rb +9 -0
  27. data/test/fixtures.rb +50 -0
  28. data/test/functional/blog_articles_controller_test.rb +139 -0
  29. data/test/functional/blog_articles_routes_test.rb +159 -0
  30. data/test/integration/admin/blog_article_test.rb +54 -0
  31. data/test/integration/admin/blog_ping_test.rb +68 -0
  32. data/test/integration/admin/blog_test.rb +43 -0
  33. data/test/integration/blog_article_test.rb +40 -0
  34. data/test/integration/blog_categories_test.rb +55 -0
  35. data/test/integration/blog_comment_test.rb +51 -0
  36. data/test/integration/blog_index_test.rb +104 -0
  37. data/test/test_helper.rb +2 -0
  38. data/test/unit/cells/blog_cell_test.rb +29 -0
  39. data/test/unit/helpers/blog_helper_test.rb +50 -0
  40. data/test/unit/helpers/content_helper_test.rb +19 -0
  41. data/test/unit/models/blog_test.rb +37 -0
  42. data/test/unit/models/counter_test.rb +44 -0
  43. metadata +101 -0
@@ -0,0 +1,10 @@
1
+ # require "adva_blog/version"
2
+ require "rails"
3
+
4
+ module AdvaBlog
5
+ class Engine < Rails::Engine
6
+ initializer "adva_blog.init" do
7
+ Section.register_type 'Blog'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module AdvaBlog
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,9 @@
1
+ class Test::Unit::TestCase
2
+ share :a_blog do
3
+ before do
4
+ @section = Blog.find_by_permalink 'a-blog'
5
+ @site = @section.site
6
+ set_request_host!
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,50 @@
1
+ user = User.find_by_first_name('a user')
2
+ admin = User.find_by_first_name('an admin')
3
+ moderator = User.find_by_first_name('a moderator')
4
+
5
+ site = Site.create! :name => 'site with blog',
6
+ :title => 'site with blog title',
7
+ :host => 'site-with-blog.com'
8
+
9
+ blog = Blog.create! :site => site,
10
+ :title => 'a blog',
11
+ :permalink => 'a-blog',
12
+ :comment_age => 0,
13
+ :published_at => Time.parse('2008-01-01 12:00:00')
14
+
15
+ category = Category.create! :section => blog,
16
+ :title => 'a category'
17
+
18
+ Category.create! :section => blog,
19
+ :title => 'another category'
20
+
21
+ Category.create! :section => blog,
22
+ :title => 'öäü'
23
+
24
+ Category.create! :section => blog,
25
+ :title => '$%&'
26
+
27
+ article = Article.create! :site => site,
28
+ :section => blog,
29
+ :title => 'a blog article',
30
+ :body => 'a blog article body',
31
+ :categories => [category],
32
+ :tag_list => 'foo bar',
33
+ :author => user,
34
+ :published_at => Time.parse('2008-01-01 12:00:00')
35
+
36
+ Article.create! :site => site,
37
+ :section => blog,
38
+ :title => 'an unpublished blog article',
39
+ :body => 'an unpublished blog article body',
40
+ :categories => [category],
41
+ :tag_list => 'foo bar',
42
+ :author => user
43
+
44
+ attributes = { :site => site, :section => blog, :commentable => article, :author => user }
45
+ Comment.create! attributes.merge(:body => 'the approved comment body', :approved => 1)
46
+ Comment.create! attributes.merge(:body => 'the unapproved comment body', :approved => 0)
47
+
48
+ admin.roles.create!(:name => 'admin', :context => site)
49
+ moderator.roles.create!(:name => 'moderator', :context => blog)
50
+
@@ -0,0 +1,139 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+
3
+ class BlogArticlesControllerTest < ActionController::TestCase
4
+ tests BlogArticlesController
5
+ with_common :a_blog, :a_category, :an_article
6
+
7
+ test "is an BaseController" do
8
+ @controller.should be_kind_of(BaseController)
9
+ end
10
+
11
+ { :blog_paths => %w( /a-blog
12
+ /a-blog/2008
13
+ /a-blog/2008/1 ),
14
+ :blog_category_paths => %w( /a-blog/categories/a-category
15
+ /a-blog/categories/a-category/2008
16
+ /a-blog/categories/a-category/2008/1 ),
17
+ :blog_tag_paths => %w( /a-blog/tags/foo+bar ),
18
+ :blog_feed_paths => %w( /a-blog.atom
19
+ /a-blog/categories/a-category.atom
20
+ /a-blog/tags/foo+bar.atom ),
21
+ :blog_comment_feed_paths => %w( /a-blog/comments.atom
22
+ /a-blog/2008/1/1/a-blog-article.atom ) }.each do |type, paths|
23
+
24
+ paths.each { |path| With.share(type) { before { @params = params_from path } } }
25
+ end
26
+
27
+ describe "GET to :index" do
28
+ action { get :index, @params }
29
+
30
+ with [:blog_paths, :blog_category_paths, :blog_tag_paths] do
31
+ it_assigns :section, :articles
32
+ it_caches_the_page :track => ['@article', '@articles', '@category', {'@site' => :tag_counts, '@section' => :tag_counts}]
33
+
34
+ it_assigns :category, :in => :blog_category_paths
35
+ it_assigns :tags, %(foo bar), :in => :blog_tag_paths
36
+
37
+ it_renders :template, :index
38
+ end
39
+
40
+ with "a blog path" do
41
+ # splitting this off so we do not test all these combinations on any of the paths above
42
+ before { @params = params_from('/a-blog') }
43
+
44
+ it "displays the article" do
45
+ has_tag('div[class~=entry]') { has_permalink @article }
46
+ end
47
+
48
+ it "shows the excerpt", :with => :article_has_an_excerpt do
49
+ does_not_have_text 'article body'
50
+ has_text 'article excerpt'
51
+ has_tag 'a', /read the rest of this entry/i
52
+ end
53
+
54
+ it "shows the body", :with => :article_has_no_excerpt do
55
+ has_text 'article body'
56
+ does_not_have_text 'article excerpt'
57
+ has_tag 'a', :text => /read the rest of this entry/i, :count => 0
58
+ end
59
+
60
+ it "displays the number of comments and links to them", :with => :comments_or_commenting_allowed do
61
+ has_tag 'div.meta a', /\d comment[s]?/i
62
+ end
63
+
64
+ it "does not display the number of comments", :with => :no_comments_and_commenting_not_allowed do
65
+ has_tag 'div.meta a', :text => /\d comment[s]?/, :count => 0
66
+ end
67
+
68
+ has_tag 'div[id=footer]', :if => :default_theme do
69
+ has_tag 'ul[id=categories_list]'
70
+ has_tag 'ul[id=archives]'
71
+ # has_tag 'ul[id=tags-list]' # FIXME currently tags are not displayed
72
+ end
73
+ end
74
+
75
+ with :blog_feed_paths do
76
+ it_assigns :section, :articles
77
+ it_renders :template, :index, :format => :atom
78
+ end
79
+ end
80
+
81
+ describe "GET to :show" do
82
+ action { get :show, {:section_id => @section.id}.merge(@article.full_permalink) }
83
+
84
+ with :the_article_is_published do
85
+ it_assigns :section, :article
86
+ it_caches_the_page :track => ['@article', '@articles', '@category', {'@site' => :tag_counts, '@section' => :tag_counts}]
87
+
88
+ it_renders :template, :show do
89
+ has_tag 'div[class~=entry]' do
90
+ # displays the title and links it to the article
91
+ has_permalink @article
92
+
93
+ # displays excerpt and body
94
+ has_text @article.excerpt
95
+ has_text @article.body
96
+
97
+ # displays an edit link for authorized users
98
+ has_authorized_tag 'a[href=?]', edit_admin_article_path(@site, @section, @article), /edit/i
99
+
100
+ # does not display a 'read more' link
101
+ assert @response.body !~ /read the rest of this entry/i
102
+
103
+ # FIXME
104
+ # lists the article's categories
105
+ # lists the article's tags
106
+ end
107
+ end
108
+
109
+ # FIXME
110
+ # when article has an approved comment: shows the comment
111
+ # when article has an unapproved comment: does not show any comments
112
+ # when article does not have any comments: does not show any comments
113
+ #
114
+ # when article allows commenting: shows comment form
115
+ # when article does not allow commenting: does not show comment form
116
+ end
117
+
118
+ # FIXME
119
+ # with "the article is not published" do
120
+ # when the user does not have edit permissions: 404, raises ActiveRecord::RecordNotFound
121
+ # when the user has edit permissions: renders show template, does not cache the page
122
+ # end
123
+
124
+ # FIXME
125
+ # with a permalink that does not point to an article: raises ActiveRecord::RecordNotFound
126
+ end
127
+
128
+ describe "GET to :comments" do
129
+ action { get :comments, @params }
130
+
131
+ with :the_article_is_published do
132
+ with :blog_comment_feed_paths do
133
+ # FIXME it_caches_the_page ...
134
+ it_assigns :section, :comments
135
+ it_renders :template, 'comments/comments', :format => :atom
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,159 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+
3
+ class BlogArticlesRoutesTest < ActionController::TestCase
4
+ tests BlogArticlesController
5
+ with_common :default_routing_filters, :a_blog, :a_category, :an_article
6
+
7
+ # FIXME /blogs/1 is regenerated as /sections/1
8
+ paths = %W( /blogs/1/2007
9
+ /blogs/1/2007/1
10
+ /blogs/1/categories/a-category
11
+ /blogs/1/categories/a-category/2007
12
+ /blogs/1/categories/a-category/2007/1
13
+ /blogs/1/categories/a-category.atom
14
+ /blogs/1/tags/foo+bar
15
+ /blogs/1/tags/foo+bar/2007
16
+ /blogs/1/tags/foo+bar/2007/1
17
+ /blogs/1/tags/foo+bar.atom )
18
+
19
+ paths.each do |path|
20
+ test "regenerates the original path from the recognized params for #{path}" do
21
+ without_routing_filters do
22
+ params = ActionController::Routing::Routes.recognize_path(path, :method => :get)
23
+ assert_equal path, @controller.url_for(params.merge(:only_path => true))
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "routing" do
29
+ ['', '/a-blog', '/de', '/de/a-blog'].each do |path_prefix|
30
+ ['', '/pages/2'].each do |path_suffix|
31
+
32
+ common = { :section_id => Blog.first.id.to_s, :path_prefix => path_prefix, :path_suffix => path_suffix }
33
+ common.merge! :locale => 'de' if path_prefix =~ /de/
34
+ common.merge! :page => 2 if path_suffix =~ /pages/
35
+
36
+ with_options common do |r|
37
+ r.it_maps :get, '/', :action => 'index'
38
+ r.it_maps :get, '/2000', :action => 'index', :year => '2000'
39
+ r.it_maps :get, '/2000/1', :action => 'index', :year => '2000', :month => '1'
40
+
41
+ r.it_maps :get, '/categories/foo', :action => 'index', :category_id => 'foo'
42
+ r.it_maps :get, '/categories/foo/2000', :action => 'index', :category_id => 'foo', :year => '2000'
43
+ r.it_maps :get, '/categories/foo/2000/1', :action => 'index', :category_id => 'foo', :year => '2000', :month => '1'
44
+
45
+ r.it_maps :get, '/tags/foo+bar', :action => 'index', :tags => 'foo+bar'
46
+ r.it_maps :get, '/tags/foo+bar/2000', :action => 'index', :tags => 'foo+bar', :year => '2000'
47
+ r.it_maps :get, '/tags/foo+bar/2000/1', :action => 'index', :tags => 'foo+bar', :year => '2000', :month => '1'
48
+
49
+ unless path_suffix =~ /pages/
50
+ r.it_maps :get, '/2000/1/1/an-article', :action => 'show', :year => '2000', :month => '1', :day => '1',
51
+ :permalink => 'an-article'
52
+
53
+ # article feeds
54
+ r.it_maps :get, '.atom', :action => 'index', :format => 'atom'
55
+ r.it_maps :get, '/categories/foo.atom', :action => 'index', :category_id => 'foo', :format => 'atom'
56
+ r.it_maps :get, '/tags/foo+bar.atom', :action => 'index', :tags => 'foo+bar', :format => 'atom'
57
+
58
+ # comment feeds
59
+ r.it_maps :get, '/2000/1/1/an-article.atom', :action => 'comments', :year => '2000', :month => '1', :day => '1',
60
+ :permalink => 'an-article', :format => 'atom'
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ # these do not work with a root section path because there's a reguar Comments resource
67
+ with_options :action => 'comments', :format => 'atom', :section_id => Blog.first.id.to_s do |r|
68
+ r.it_maps :get, '/a-blog/comments.atom'
69
+ r.it_maps :get, '/de/a-blog/comments.atom', :locale => 'de'
70
+ end
71
+ end
72
+
73
+ describe "the url_helper blog_path" do
74
+ before do
75
+ other = @section.site.sections.create! :title => 'another section' # FIXME move to db/populate
76
+ other.move_to_left_of @section
77
+
78
+ url_rewriter = ActionController::UrlRewriter.new @request, :controller => 'blog', :section => @section.id
79
+ @controller.instance_variable_set :@url, url_rewriter
80
+ @controller.instance_variable_set :@site, @site
81
+
82
+ I18n.default_locale = :en
83
+ I18n.locale = :de
84
+ end
85
+
86
+ blog_path = lambda { blog_path(@section) }
87
+ archive_path = lambda { blog_path(@section, :year => '2008', :month => '1') }
88
+ tag_path = lambda { blog_tag_path(@section, 'foo+bar') }
89
+ category_path = lambda { blog_category_path(@section, @category) }
90
+
91
+ paged_blog_path = lambda { blog_path(@section, :page => 2) }
92
+ paged_archive_path = lambda { blog_path(@section, :year => '2008', :month => '1', :page => 2) }
93
+ paged_tag_path = lambda { blog_tag_path(@section, 'foo+bar', :page => 2) }
94
+ paged_category_path = lambda { blog_category_path(@section, @category, :page => 2) }
95
+
96
+ blog_feed_path = lambda { blog_feed_path(@section.id, :format => :rss) }
97
+ tag_feed_path = lambda { tag_feed_path(@section, 'foo+bar', :rss) }
98
+ category_feed_path = lambda { category_feed_path(@section, @category, :rss) }
99
+
100
+ article_path = lambda { blog_article_path(@section, @article.full_permalink) }
101
+ comments_feed_path = lambda { blog_comments_path(@section, :format => :rss) }
102
+ article_comments_feed_path = lambda { blog_article_comments_path(@section, @article.full_permalink.merge(:format => :rss)) }
103
+
104
+ it_rewrites blog_path, :to => '/', :with => [:is_default_locale, :is_root_section]
105
+ it_rewrites blog_path, :to => '/de', :with => [:is_root_section]
106
+ it_rewrites blog_path, :to => '/a-blog', :with => [:is_default_locale]
107
+ it_rewrites blog_path, :to => '/de/a-blog'
108
+
109
+ it_rewrites archive_path, :to => '/2008/1', :with => [:is_default_locale, :is_root_section]
110
+ it_rewrites archive_path, :to => '/de/2008/1', :with => [:is_root_section]
111
+ it_rewrites archive_path, :to => '/a-blog/2008/1', :with => [:is_default_locale]
112
+ it_rewrites archive_path, :to => '/de/a-blog/2008/1'
113
+
114
+ it_rewrites tag_path, :to => '/tags/foo+bar', :with => [:is_default_locale, :is_root_section]
115
+ it_rewrites tag_path, :to => '/de/tags/foo+bar', :with => [:is_root_section]
116
+ it_rewrites tag_path, :to => '/a-blog/tags/foo+bar', :with => [:is_default_locale]
117
+ it_rewrites tag_path, :to => '/de/a-blog/tags/foo+bar'
118
+
119
+ it_rewrites category_path, :to => '/categories/a-category', :with => [:is_default_locale, :is_root_section]
120
+ it_rewrites category_path, :to => '/de/categories/a-category', :with => [:is_root_section]
121
+ it_rewrites category_path, :to => '/a-blog/categories/a-category', :with => [:is_default_locale]
122
+ it_rewrites category_path, :to => '/de/a-blog/categories/a-category'
123
+
124
+ it_rewrites paged_blog_path, :to => '/de/a-blog/pages/2'
125
+ it_rewrites paged_archive_path, :to => '/de/a-blog/2008/1/pages/2'
126
+ it_rewrites paged_tag_path, :to => '/de/a-blog/tags/foo+bar/pages/2'
127
+ it_rewrites paged_category_path, :to => '/de/a-blog/categories/a-category/pages/2'
128
+
129
+ it_rewrites blog_feed_path, :to => '/a-blog.rss', :with => [:is_default_locale, :is_root_section]
130
+ it_rewrites blog_feed_path, :to => '/de/a-blog.rss', :with => [:is_root_section]
131
+ it_rewrites blog_feed_path, :to => '/a-blog.rss', :with => [:is_default_locale]
132
+ it_rewrites blog_feed_path, :to => '/de/a-blog.rss'
133
+
134
+ it_rewrites tag_feed_path, :to => '/tags/foo+bar.rss', :with => [:is_default_locale, :is_root_section]
135
+ it_rewrites tag_feed_path, :to => '/de/tags/foo+bar.rss', :with => [:is_root_section]
136
+ it_rewrites tag_feed_path, :to => '/a-blog/tags/foo+bar.rss', :with => [:is_default_locale]
137
+ it_rewrites tag_feed_path, :to => '/de/a-blog/tags/foo+bar.rss'
138
+
139
+ it_rewrites category_feed_path, :to => '/categories/a-category.rss', :with => [:is_default_locale, :is_root_section]
140
+ it_rewrites category_feed_path, :to => '/de/categories/a-category.rss', :with => [:is_root_section]
141
+ it_rewrites category_feed_path, :to => '/a-blog/categories/a-category.rss', :with => [:is_default_locale]
142
+ it_rewrites category_feed_path, :to => '/de/a-blog/categories/a-category.rss'
143
+
144
+ it_rewrites article_path, :to => '/2008/1/1/a-blog-article', :with => [:is_default_locale, :is_root_section]
145
+ it_rewrites article_path, :to => '/de/2008/1/1/a-blog-article', :with => [:is_root_section]
146
+ it_rewrites article_path, :to => '/a-blog/2008/1/1/a-blog-article', :with => [:is_default_locale]
147
+ it_rewrites article_path, :to => '/de/a-blog/2008/1/1/a-blog-article'
148
+
149
+ it_rewrites comments_feed_path, :to => '/comments.rss', :with => [:is_default_locale, :is_root_section]
150
+ it_rewrites comments_feed_path, :to => '/de/comments.rss', :with => [:is_root_section]
151
+ it_rewrites comments_feed_path, :to => '/a-blog/comments.rss', :with => [:is_default_locale]
152
+ it_rewrites comments_feed_path, :to => '/de/a-blog/comments.rss'
153
+
154
+ it_rewrites article_comments_feed_path, :to => '/2008/1/1/a-blog-article.rss', :with => [:is_default_locale, :is_root_section]
155
+ it_rewrites article_comments_feed_path, :to => '/de/2008/1/1/a-blog-article.rss', :with => [:is_root_section]
156
+ it_rewrites article_comments_feed_path, :to => '/a-blog/2008/1/1/a-blog-article.rss', :with => [:is_default_locale]
157
+ it_rewrites article_comments_feed_path, :to => '/de/a-blog/2008/1/1/a-blog-article.rss'
158
+ end
159
+ end
@@ -0,0 +1,54 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper' )
2
+
3
+ module IntegrationTests
4
+ class AdminBlogArticleTest < ActionController::IntegrationTest
5
+ def setup
6
+ super
7
+ @section = Blog.first
8
+ @site = @section.site
9
+ use_site! @site
10
+ stub(Time).now.returns Time.utc(2008, 1, 1)
11
+ end
12
+
13
+ test "Admin creates an article, previews, edits and deletes it" do
14
+ login_as_admin
15
+ visit_admin_articles_index_page
16
+ create_a_new_article
17
+ revise_the_article
18
+ preview_article
19
+ delete_article
20
+ end
21
+
22
+ def visit_admin_articles_index_page
23
+ visit "/admin/sites/#{@site.id}/sections/#{@section.id}/articles"
24
+ end
25
+
26
+ def create_a_new_article
27
+ click_link "New"
28
+ fill_in 'article[title]', :with => 'the article title'
29
+ fill_in 'article[body]', :with => 'the article body'
30
+ click_button 'Save'
31
+ request.url.should =~ %r(/admin/sites/\d+/sections/\d+/articles/\d+/edit)
32
+ end
33
+
34
+ def revise_the_article
35
+ fill_in 'article[title]', :with => 'the revised article title'
36
+ fill_in 'article[body]', :with => 'the revised article body'
37
+ click_button 'Save'
38
+ request.url.should =~ %r(/admin/sites/\d+/sections/\d+/articles/\d+/edit)
39
+ @back_url = request.url
40
+ end
41
+
42
+ def preview_article
43
+ click_link 'Show'
44
+ request.url.should == controller.show_url(Article.find_by_permalink('the-article-title'))
45
+ end
46
+
47
+ def delete_article
48
+ visit @back_url
49
+ click_link 'Delete'
50
+ request.url.should =~ %r(/admin/sites/\d+/sections/\d+/articles)
51
+ response.body.should_not =~ %r(the revised article title)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper' )
2
+
3
+ if Rails.plugin?(:adva_post_ping)
4
+ module IntegrationTests
5
+ class AdminBlogPingTest < ActionController::IntegrationTest
6
+ def setup
7
+ super
8
+ @section = Blog.first
9
+ @site = @section.site
10
+ use_site! @site
11
+ stub(Time).now.returns Time.utc(2008, 1, 2)
12
+
13
+ Article.old_add_observer(@observer = ArticlePingObserver.instance)
14
+
15
+ @ping_service = { :url => "http://rpc.pingomatic.com/", :type => :xmlrpc }
16
+ ArticlePingObserver::SERVICES.replace [@ping_service]
17
+ end
18
+
19
+ def teardown
20
+ super
21
+ Article.delete_observer(@observer)
22
+ end
23
+
24
+ test "The system pings FOO when a blog article is published" do
25
+ login_as_admin
26
+
27
+ visit "/admin/sites/#{@site.id}/sections/#{@section.id}/articles"
28
+ click_link "New"
29
+
30
+ expect_no_pings do
31
+ create_a_new_article
32
+ end
33
+
34
+ expect_ping_to(@ping_service) do
35
+ publish_article
36
+ end
37
+ end
38
+
39
+ def create_a_new_article
40
+ fill_in 'article[title]', :with => 'the article title'
41
+ fill_in 'article[body]', :with => 'the article body'
42
+ click_button 'Save'
43
+ request.url.should =~ %r(/admin/sites/\d+/sections/\d+/articles/\d+/edit)
44
+ end
45
+
46
+ def publish_article
47
+ uncheck 'article[draft]'
48
+ select_date "2008-1-1", :from => 'Publish on this date'
49
+ click_button 'Save'
50
+ request.url.should =~ %r(/admin/sites/\d+/sections/\d+/articles/\d+/edit)
51
+ end
52
+
53
+ def expect_no_pings
54
+ RR.dont_allow(ArticlePingObserver.instance).ping_service(anything, anything)
55
+ yield
56
+ RR.verify
57
+ RR.reset
58
+ end
59
+
60
+ def expect_ping_to(service)
61
+ RR.mock(ArticlePingObserver.instance).ping_service(service, anything)
62
+ yield
63
+ RR.verify
64
+ RR.reset
65
+ end
66
+ end
67
+ end
68
+ end