Chris@909: # Redmine - project management software Chris@909: # Copyright (C) 2006-2011 Jean-Philippe Lang Chris@909: # Chris@909: # This program is free software; you can redistribute it and/or Chris@909: # modify it under the terms of the GNU General Public License Chris@909: # as published by the Free Software Foundation; either version 2 Chris@909: # of the License, or (at your option) any later version. Chris@909: # Chris@909: # This program is distributed in the hope that it will be useful, Chris@909: # but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@909: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@909: # GNU General Public License for more details. Chris@909: # Chris@909: # You should have received a copy of the GNU General Public License Chris@909: # along with this program; if not, write to the Free Software Chris@909: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Chris@909: Chris@909: require File.expand_path('../../test_helper', __FILE__) Chris@909: Chris@909: class MailerTest < ActiveSupport::TestCase Chris@909: include Redmine::I18n Chris@909: include ActionController::Assertions::SelectorAssertions Chris@909: fixtures :projects, :enabled_modules, :issues, :users, :members, Chris@909: :member_roles, :roles, :documents, :attachments, :news, Chris@909: :tokens, :journals, :journal_details, :changesets, :trackers, Chris@909: :issue_statuses, :enumerations, :messages, :boards, :repositories, Chris@909: :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, Chris@909: :versions, Chris@909: :comments Chris@909: Chris@909: def setup Chris@909: ActionMailer::Base.deliveries.clear Chris@909: Setting.host_name = 'mydomain.foo' Chris@909: Setting.protocol = 'http' Chris@909: Setting.plain_text_mail = '0' Chris@909: end Chris@909: Chris@909: def test_generated_links_in_emails Chris@909: Setting.host_name = 'mydomain.foo' Chris@909: Setting.protocol = 'https' Chris@909: Chris@909: journal = Journal.find(2) Chris@909: assert Mailer.deliver_issue_edit(journal) Chris@909: Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_kind_of TMail::Mail, mail Chris@909: Chris@909: assert_select_email do Chris@909: # link to the main ticket Chris@909: assert_select "a[href=?]", Chris@909: "https://mydomain.foo/issues/1#change-2", Chris@909: :text => "Bug #1: Can't print recipes" Chris@909: # link to a referenced ticket Chris@909: assert_select "a[href=?][title=?]", Chris@909: "https://mydomain.foo/issues/2", Chris@909: "Add ingredients categories (Assigned)", Chris@909: :text => "#2" Chris@909: # link to a changeset Chris@909: assert_select "a[href=?][title=?]", Chris@909: "https://mydomain.foo/projects/ecookbook/repository/revisions/2", Chris@909: "This commit fixes #1, #2 and references #1 & #3", Chris@909: :text => "r2" Chris@909: end Chris@909: end Chris@909: Chris@909: def test_generated_links_with_prefix Chris@909: relative_url_root = Redmine::Utils.relative_url_root Chris@909: Setting.host_name = 'mydomain.foo/rdm' Chris@909: Setting.protocol = 'http' Chris@909: Redmine::Utils.relative_url_root = '/rdm' Chris@909: Chris@909: journal = Journal.find(2) Chris@909: assert Mailer.deliver_issue_edit(journal) Chris@909: Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_kind_of TMail::Mail, mail Chris@909: Chris@909: assert_select_email do Chris@909: # link to the main ticket Chris@909: assert_select "a[href=?]", Chris@909: "http://mydomain.foo/rdm/issues/1#change-2", Chris@909: :text => "Bug #1: Can't print recipes" Chris@909: # link to a referenced ticket Chris@909: assert_select "a[href=?][title=?]", Chris@909: "http://mydomain.foo/rdm/issues/2", Chris@909: "Add ingredients categories (Assigned)", Chris@909: :text => "#2" Chris@909: # link to a changeset Chris@909: assert_select "a[href=?][title=?]", Chris@909: "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2", Chris@909: "This commit fixes #1, #2 and references #1 & #3", Chris@909: :text => "r2" Chris@909: end Chris@909: ensure Chris@909: # restore it Chris@909: Redmine::Utils.relative_url_root = relative_url_root Chris@909: end Chris@909: Chris@909: def test_generated_links_with_prefix_and_no_relative_url_root Chris@909: relative_url_root = Redmine::Utils.relative_url_root Chris@909: Setting.host_name = 'mydomain.foo/rdm' Chris@909: Setting.protocol = 'http' Chris@909: Redmine::Utils.relative_url_root = nil Chris@909: Chris@909: journal = Journal.find(2) Chris@909: assert Mailer.deliver_issue_edit(journal) Chris@909: Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_kind_of TMail::Mail, mail Chris@909: Chris@909: assert_select_email do Chris@909: # link to the main ticket Chris@909: assert_select "a[href=?]", Chris@909: "http://mydomain.foo/rdm/issues/1#change-2", Chris@909: :text => "Bug #1: Can't print recipes" Chris@909: # link to a referenced ticket Chris@909: assert_select "a[href=?][title=?]", Chris@909: "http://mydomain.foo/rdm/issues/2", Chris@909: "Add ingredients categories (Assigned)", Chris@909: :text => "#2" Chris@909: # link to a changeset Chris@909: assert_select "a[href=?][title=?]", Chris@909: "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2", Chris@909: "This commit fixes #1, #2 and references #1 & #3", Chris@909: :text => "r2" Chris@909: end Chris@909: ensure Chris@909: # restore it Chris@909: Redmine::Utils.relative_url_root = relative_url_root Chris@909: end Chris@909: Chris@909: def test_email_headers Chris@909: issue = Issue.find(1) Chris@909: Mailer.deliver_issue_add(issue) Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_not_nil mail Chris@909: assert_equal 'OOF', mail.header_string('X-Auto-Response-Suppress') Chris@909: assert_equal 'auto-generated', mail.header_string('Auto-Submitted') Chris@909: end Chris@909: Chris@909: def test_plain_text_mail Chris@909: Setting.plain_text_mail = 1 Chris@909: journal = Journal.find(2) Chris@909: Mailer.deliver_issue_edit(journal) Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_equal "text/plain", mail.content_type Chris@909: assert_equal 0, mail.parts.size Chris@909: assert !mail.encoded.include?('href') Chris@909: end Chris@909: Chris@909: def test_html_mail Chris@909: Setting.plain_text_mail = 0 Chris@909: journal = Journal.find(2) Chris@909: Mailer.deliver_issue_edit(journal) Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_equal 2, mail.parts.size Chris@909: assert mail.encoded.include?('href') Chris@909: end Chris@909: Chris@909: def test_from_header Chris@909: with_settings :mail_from => 'redmine@example.net' do Chris@909: Mailer.deliver_test(User.find(1)) Chris@909: end Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_not_nil mail Chris@909: assert_equal 'redmine@example.net', mail.from_addrs.first.address Chris@909: end Chris@909: Chris@909: def test_from_header_with_phrase Chris@909: with_settings :mail_from => 'Redmine app ' do Chris@909: Mailer.deliver_test(User.find(1)) Chris@909: end Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_not_nil mail Chris@909: assert_equal 'redmine@example.net', mail.from_addrs.first.address Chris@909: assert_equal 'Redmine app', mail.from_addrs.first.name Chris@909: end Chris@909: Chris@909: def test_should_not_send_email_without_recipient Chris@909: news = News.find(:first) Chris@909: user = news.author Chris@909: # Remove members except news author Chris@909: news.project.memberships.each {|m| m.destroy unless m.user == user} Chris@909: Chris@909: user.pref[:no_self_notified] = false Chris@909: user.pref.save Chris@909: User.current = user Chris@909: Mailer.deliver_news_added(news.reload) Chris@909: assert_equal 1, last_email.bcc.size Chris@909: Chris@909: # nobody to notify Chris@909: user.pref[:no_self_notified] = true Chris@909: user.pref.save Chris@909: User.current = user Chris@909: ActionMailer::Base.deliveries.clear Chris@909: Mailer.deliver_news_added(news.reload) Chris@909: assert ActionMailer::Base.deliveries.empty? Chris@909: end Chris@909: Chris@909: def test_issue_add_message_id Chris@909: issue = Issue.find(1) Chris@909: Mailer.deliver_issue_add(issue) Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_not_nil mail Chris@909: assert_equal Mailer.message_id_for(issue), mail.message_id Chris@909: assert_nil mail.references Chris@909: end Chris@909: Chris@909: def test_issue_edit_message_id Chris@909: journal = Journal.find(1) Chris@909: Mailer.deliver_issue_edit(journal) Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_not_nil mail Chris@909: assert_equal Mailer.message_id_for(journal), mail.message_id Chris@909: assert_equal Mailer.message_id_for(journal.issue), mail.references.first.to_s Chris@909: assert_select_email do Chris@909: # link to the update Chris@909: assert_select "a[href=?]", Chris@909: "http://mydomain.foo/issues/#{journal.journalized_id}#change-#{journal.id}" Chris@909: end Chris@909: end Chris@909: Chris@909: def test_message_posted_message_id Chris@909: message = Message.find(1) Chris@909: Mailer.deliver_message_posted(message) Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_not_nil mail Chris@909: assert_equal Mailer.message_id_for(message), mail.message_id Chris@909: assert_nil mail.references Chris@909: assert_select_email do Chris@909: # link to the message Chris@909: assert_select "a[href=?]", Chris@909: "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.id}", Chris@909: :text => message.subject Chris@909: end Chris@909: end Chris@909: Chris@909: def test_reply_posted_message_id Chris@909: message = Message.find(3) Chris@909: Mailer.deliver_message_posted(message) Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_not_nil mail Chris@909: assert_equal Mailer.message_id_for(message), mail.message_id Chris@909: assert_equal Mailer.message_id_for(message.parent), mail.references.first.to_s Chris@909: assert_select_email do Chris@909: # link to the reply Chris@909: assert_select "a[href=?]", Chris@909: "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.root.id}?r=#{message.id}#message-#{message.id}", Chris@909: :text => message.subject Chris@909: end Chris@909: end Chris@909: Chris@909: context("#issue_add") do Chris@909: setup do Chris@909: ActionMailer::Base.deliveries.clear Chris@909: Setting.bcc_recipients = '1' Chris@909: @issue = Issue.find(1) Chris@909: end Chris@909: Chris@909: should "notify project members" do Chris@909: assert Mailer.deliver_issue_add(@issue) Chris@909: assert last_email.bcc.include?('dlopper@somenet.foo') Chris@909: end Chris@909: Chris@909: should "not notify project members that are not allow to view the issue" do Chris@909: Role.find(2).remove_permission!(:view_issues) Chris@909: assert Mailer.deliver_issue_add(@issue) Chris@909: assert !last_email.bcc.include?('dlopper@somenet.foo') Chris@909: end Chris@909: Chris@909: should "notify issue watchers" do Chris@909: user = User.find(9) Chris@909: # minimal email notification options Chris@909: user.pref[:no_self_notified] = '1' Chris@909: user.pref.save Chris@909: user.mail_notification = false Chris@909: user.save Chris@909: Chris@909: Watcher.create!(:watchable => @issue, :user => user) Chris@909: assert Mailer.deliver_issue_add(@issue) Chris@909: assert last_email.bcc.include?(user.mail) Chris@909: end Chris@909: Chris@909: should "not notify watchers not allowed to view the issue" do Chris@909: user = User.find(9) Chris@909: Watcher.create!(:watchable => @issue, :user => user) Chris@909: Role.non_member.remove_permission!(:view_issues) Chris@909: assert Mailer.deliver_issue_add(@issue) Chris@909: assert !last_email.bcc.include?(user.mail) Chris@909: end Chris@909: end Chris@909: Chris@909: # test mailer methods for each language Chris@909: def test_issue_add Chris@909: issue = Issue.find(1) Chris@909: valid_languages.each do |lang| Chris@909: Setting.default_language = lang.to_s Chris@909: assert Mailer.deliver_issue_add(issue) Chris@909: end Chris@909: end Chris@909: Chris@909: def test_issue_edit Chris@909: journal = Journal.find(1) Chris@909: valid_languages.each do |lang| Chris@909: Setting.default_language = lang.to_s Chris@909: assert Mailer.deliver_issue_edit(journal) Chris@909: end Chris@909: end Chris@909: Chris@909: def test_document_added Chris@909: document = Document.find(1) Chris@909: valid_languages.each do |lang| Chris@909: Setting.default_language = lang.to_s Chris@909: assert Mailer.deliver_document_added(document) Chris@909: end Chris@909: end Chris@909: Chris@909: def test_attachments_added Chris@909: attachements = [ Attachment.find_by_container_type('Document') ] Chris@909: valid_languages.each do |lang| Chris@909: Setting.default_language = lang.to_s Chris@909: assert Mailer.deliver_attachments_added(attachements) Chris@909: end Chris@909: end Chris@909: Chris@909: def test_version_file_added Chris@909: attachements = [ Attachment.find_by_container_type('Version') ] Chris@909: assert Mailer.deliver_attachments_added(attachements) Chris@909: assert_not_nil last_email.bcc Chris@909: assert last_email.bcc.any? Chris@909: assert_select_email do Chris@909: assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files" Chris@909: end Chris@909: end Chris@909: Chris@909: def test_project_file_added Chris@909: attachements = [ Attachment.find_by_container_type('Project') ] Chris@909: assert Mailer.deliver_attachments_added(attachements) Chris@909: assert_not_nil last_email.bcc Chris@909: assert last_email.bcc.any? Chris@909: assert_select_email do Chris@909: assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files" Chris@909: end Chris@909: end Chris@909: Chris@909: def test_news_added Chris@909: news = News.find(:first) Chris@909: valid_languages.each do |lang| Chris@909: Setting.default_language = lang.to_s Chris@909: assert Mailer.deliver_news_added(news) Chris@909: end Chris@909: end Chris@909: Chris@909: def test_news_comment_added Chris@909: comment = Comment.find(2) Chris@909: valid_languages.each do |lang| Chris@909: Setting.default_language = lang.to_s Chris@909: assert Mailer.deliver_news_comment_added(comment) Chris@909: end Chris@909: end Chris@909: Chris@909: def test_message_posted Chris@909: message = Message.find(:first) Chris@909: recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author} Chris@909: recipients = recipients.compact.uniq Chris@909: valid_languages.each do |lang| Chris@909: Setting.default_language = lang.to_s Chris@909: assert Mailer.deliver_message_posted(message) Chris@909: end Chris@909: end Chris@909: Chris@909: def test_wiki_content_added Chris@909: content = WikiContent.find(:first) Chris@909: valid_languages.each do |lang| Chris@909: Setting.default_language = lang.to_s Chris@909: assert_difference 'ActionMailer::Base.deliveries.size' do Chris@909: assert Mailer.deliver_wiki_content_added(content) Chris@909: end Chris@909: end Chris@909: end Chris@909: Chris@909: def test_wiki_content_updated Chris@909: content = WikiContent.find(:first) Chris@909: valid_languages.each do |lang| Chris@909: Setting.default_language = lang.to_s Chris@909: assert_difference 'ActionMailer::Base.deliveries.size' do Chris@909: assert Mailer.deliver_wiki_content_updated(content) Chris@909: end Chris@909: end Chris@909: end Chris@909: Chris@909: def test_account_information Chris@909: user = User.find(2) Chris@909: valid_languages.each do |lang| Chris@909: user.update_attribute :language, lang.to_s Chris@909: user.reload Chris@909: assert Mailer.deliver_account_information(user, 'pAsswORd') Chris@909: end Chris@909: end Chris@909: Chris@909: def test_lost_password Chris@909: token = Token.find(2) Chris@909: valid_languages.each do |lang| Chris@909: token.user.update_attribute :language, lang.to_s Chris@909: token.reload Chris@909: assert Mailer.deliver_lost_password(token) Chris@909: end Chris@909: end Chris@909: Chris@909: def test_register Chris@909: token = Token.find(1) Chris@909: Setting.host_name = 'redmine.foo' Chris@909: Setting.protocol = 'https' Chris@909: Chris@909: valid_languages.each do |lang| Chris@909: token.user.update_attribute :language, lang.to_s Chris@909: token.reload Chris@909: ActionMailer::Base.deliveries.clear Chris@909: assert Mailer.deliver_register(token) Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert mail.body.include?("https://redmine.foo/account/activate?token=#{token.value}") Chris@909: end Chris@909: end Chris@909: Chris@909: def test_test Chris@909: user = User.find(1) Chris@909: valid_languages.each do |lang| Chris@909: user.update_attribute :language, lang.to_s Chris@909: assert Mailer.deliver_test(user) Chris@909: end Chris@909: end Chris@909: Chris@909: def test_reminders Chris@909: Mailer.reminders(:days => 42) Chris@909: assert_equal 1, ActionMailer::Base.deliveries.size Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert mail.bcc.include?('dlopper@somenet.foo') Chris@909: assert mail.body.include?('Bug #3: Error 281 when updating a recipe') Chris@909: assert_equal '1 issue(s) due in the next 42 days', mail.subject Chris@909: end Chris@909: Chris@909: def test_reminders_for_users Chris@909: Mailer.reminders(:days => 42, :users => ['5']) Chris@909: assert_equal 0, ActionMailer::Base.deliveries.size # No mail for dlopper Chris@909: Mailer.reminders(:days => 42, :users => ['3']) Chris@909: assert_equal 1, ActionMailer::Base.deliveries.size # No mail for dlopper Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert mail.bcc.include?('dlopper@somenet.foo') Chris@909: assert mail.body.include?('Bug #3: Error 281 when updating a recipe') Chris@909: end Chris@909: Chris@909: def last_email Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert_not_nil mail Chris@909: mail Chris@909: end Chris@909: Chris@909: def test_mailer_should_not_change_locale Chris@909: Setting.default_language = 'en' Chris@909: # Set current language to italian Chris@909: set_language_if_valid 'it' Chris@909: # Send an email to a french user Chris@909: user = User.find(1) Chris@909: user.language = 'fr' Chris@909: Mailer.deliver_account_activated(user) Chris@909: mail = ActionMailer::Base.deliveries.last Chris@909: assert mail.body.include?('Votre compte') Chris@909: Chris@909: assert_equal :it, current_language Chris@909: end Chris@909: Chris@909: def test_with_deliveries_off Chris@909: Mailer.with_deliveries false do Chris@909: Mailer.deliver_test(User.find(1)) Chris@909: end Chris@909: assert ActionMailer::Base.deliveries.empty? Chris@909: # should restore perform_deliveries Chris@909: assert ActionMailer::Base.perform_deliveries Chris@909: end Chris@909: Chris@909: def test_tmail_to_header_field_should_not_include_blank_lines Chris@909: mail = TMail::Mail.new Chris@909: mail.to = ["a.user@example.com", "v.user2@example.com", "e.smith@example.com", "info@example.com", "v.pupkin@example.com", Chris@909: "b.user@example.com", "w.user2@example.com", "f.smith@example.com", "info2@example.com", "w.pupkin@example.com"] Chris@909: Chris@909: assert !mail.encoded.strip.split("\r\n").detect(&:blank?), "#{mail.encoded} malformed" Chris@909: end Chris@909: Chris@909: context "layout" do Chris@909: should "include the emails_header" do Chris@909: with_settings(:emails_header => "*Header content*") do Chris@909: assert Mailer.deliver_test(User.find(1)) Chris@909: Chris@909: assert_select_email do Chris@909: assert_select ".header" do Chris@909: assert_select "strong", :text => "Header content" Chris@909: end Chris@909: end Chris@909: end Chris@909: end Chris@909: end Chris@909: end