PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/ee/spec/mailers/notify_spec.rb

https://gitlab.com/realsatomic/gitlab
Ruby | 383 lines | 295 code | 87 blank | 1 comment | 0 complexity | 77c6f4c3d552f37aa2773e4c755d4a36 MD5 | raw file
  1. # frozen_string_literal: true
  2. require 'spec_helper'
  3. require 'email_spec'
  4. RSpec.describe Notify do
  5. include EmailSpec::Helpers
  6. include EmailSpec::Matchers
  7. include EmailHelpers
  8. include RepoHelpers
  9. include_context 'gitlab email notification'
  10. RSpec.shared_examples 'epic notifications with reply' do
  11. it_behaves_like 'having group identification headers'
  12. it_behaves_like 'it should show Gmail Actions View Epic link'
  13. it_behaves_like 'an unsubscribeable thread'
  14. it 'has the characteristics of a threaded reply' do
  15. host = Gitlab.config.gitlab.host
  16. route_key = "#{epic.class.model_name.singular_route_key}_#{epic.id}"
  17. aggregate_failures do
  18. is_expected.to have_header('Message-ID', /\A<.*@#{host}>\Z/)
  19. is_expected.to have_header('In-Reply-To', "<#{route_key}@#{host}>")
  20. is_expected.to have_header('References', /\A<reply\-.*@#{host}> <#{route_key}@#{host}>\Z/ )
  21. is_expected.to have_subject(/^Re: /)
  22. end
  23. end
  24. it 'has a Reply-To header' do
  25. is_expected.to have_header 'Reply-To', /<reply+(.*)@#{Gitlab.config.gitlab.host}>\Z/
  26. end
  27. it 'has the correct subject and body' do
  28. email_subject = "Re: #{epic.group.name} | #{epic.title} (#{epic.to_reference})"
  29. aggregate_failures do
  30. is_expected.to have_subject(email_subject)
  31. is_expected.to have_body_text(email_body)
  32. end
  33. end
  34. end
  35. let_it_be(:user, reload: true) { create(:user) }
  36. let_it_be(:current_user) { create(:user, email: "current@email.com") }
  37. let_it_be(:assignee) { create(:user, email: 'assignee@example.com', name: 'John Doe') }
  38. let_it_be(:assignee2) { create(:user, email: 'assignee2@example.com', name: 'Jane Doe') }
  39. let_it_be(:merge_request, reload: true) do
  40. create(:merge_request, source_project: project,
  41. target_project: project,
  42. author: current_user,
  43. assignees: [assignee, assignee2],
  44. description: 'Awesome description')
  45. end
  46. let_it_be(:issue, reload: true) do
  47. create(:issue, author: current_user,
  48. assignees: [assignee],
  49. project: project,
  50. description: 'My awesome description!')
  51. end
  52. let_it_be(:project2, reload: true) { create(:project, :repository) }
  53. let_it_be(:merge_request_without_assignee, reload: true) do
  54. create(:merge_request, source_project: project2,
  55. author: current_user,
  56. description: 'Awesome description')
  57. end
  58. context 'for a project' do
  59. context 'for merge requests' do
  60. describe "that are new with approver" do
  61. before do
  62. create(:approver, target: merge_request)
  63. end
  64. subject do
  65. described_class.new_merge_request_email(assignee.id, merge_request.id)
  66. end
  67. it "contains the approvers list" do
  68. is_expected.to have_body_text %r[#{merge_request.approvers.first.user.name}]
  69. end
  70. end
  71. describe 'that are approved' do
  72. let(:last_approver) { create(:user) }
  73. subject { described_class.approved_merge_request_email(recipient.id, merge_request.id, last_approver.id) }
  74. before do
  75. merge_request.approvals.create!(user: assignee)
  76. merge_request.approvals.create!(user: last_approver)
  77. end
  78. it_behaves_like 'a multiple recipients email'
  79. it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
  80. let(:model) { merge_request }
  81. end
  82. it_behaves_like 'it should show Gmail Actions View Merge request link'
  83. it_behaves_like 'an unsubscribeable thread'
  84. it 'is sent as the last approver' do
  85. expect_sender(last_approver)
  86. end
  87. it 'has the correct subject' do
  88. is_expected.to have_attributes(
  89. subject: a_string_including("#{merge_request.title} (#{merge_request.to_reference})")
  90. )
  91. end
  92. it 'contains the new status' do
  93. is_expected.to have_body_text('approved')
  94. end
  95. it 'contains a link to the merge request' do
  96. is_expected.to have_body_text("#{project_merge_request_path project, merge_request}")
  97. end
  98. it 'contains the names of all of the approvers' do
  99. names = merge_request.approvals.map { |a| a.user.name }
  100. aggregate_failures do
  101. names.each { |name| is_expected.to have_body_text(name) }
  102. end
  103. end
  104. it 'contains the names of all assignees' do
  105. names = merge_request.assignees.map(&:name)
  106. aggregate_failures do
  107. names.each { |name| is_expected.to have_body_text(name) }
  108. end
  109. end
  110. context 'when merge request has no assignee' do
  111. before do
  112. merge_request.update!(assignees: [])
  113. end
  114. it 'does not show the assignee' do
  115. is_expected.not_to have_body_text 'Assignee'
  116. end
  117. end
  118. end
  119. describe 'that are unapproved' do
  120. let(:last_unapprover) { create(:user) }
  121. subject { described_class.unapproved_merge_request_email(recipient.id, merge_request.id, last_unapprover.id) }
  122. before do
  123. merge_request.approvals.create!(user: assignee)
  124. end
  125. it_behaves_like 'a multiple recipients email'
  126. it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
  127. let(:model) { merge_request }
  128. end
  129. it_behaves_like 'it should show Gmail Actions View Merge request link'
  130. it_behaves_like 'an unsubscribeable thread'
  131. it 'is sent as the last unapprover' do
  132. expect_sender(last_unapprover)
  133. end
  134. it 'has the correct subject' do
  135. is_expected.to have_attributes(
  136. subject: a_string_including("#{merge_request.title} (#{merge_request.to_reference})")
  137. )
  138. end
  139. it 'contains the new status' do
  140. is_expected.to have_body_text('unapproved')
  141. end
  142. it 'contains a link to the merge request' do
  143. is_expected.to have_body_text("#{project_merge_request_path project, merge_request}")
  144. end
  145. it 'contains the names of all of the approvers' do
  146. names = merge_request.approvals.map { |a| a.user.name }
  147. aggregate_failures do
  148. names.each { |name| is_expected.to have_body_text(name) }
  149. end
  150. end
  151. it 'contains the names of all assignees' do
  152. names = merge_request.assignees.map(&:name)
  153. aggregate_failures do
  154. names.each { |name| is_expected.to have_body_text(name) }
  155. end
  156. end
  157. end
  158. end
  159. context 'for merge requests without assignee' do
  160. describe 'that are unapproved' do
  161. let(:last_unapprover) { create(:user) }
  162. subject { described_class.unapproved_merge_request_email(recipient.id, merge_request_without_assignee.id, last_unapprover.id) }
  163. it 'contains the new status' do
  164. is_expected.to have_body_text('unapproved')
  165. end
  166. end
  167. end
  168. end
  169. context 'for a group' do
  170. describe 'for epics' do
  171. let_it_be(:group) { create(:group) }
  172. let_it_be(:epic) { create(:epic, group: group) }
  173. context 'that are new' do
  174. subject { described_class.new_epic_email(recipient.id, epic.id) }
  175. it_behaves_like 'an epic email starting a new thread with reply-by-email enabled' do
  176. let(:model) { epic }
  177. end
  178. it_behaves_like 'it should show Gmail Actions View Epic link'
  179. it_behaves_like 'an unsubscribeable thread'
  180. it_behaves_like 'having group identification headers'
  181. it 'has the correct subject and body' do
  182. prefix = "#{epic.group.name} | "
  183. suffix = "#{epic.title} (#{epic.to_reference})"
  184. aggregate_failures do
  185. is_expected.to have_subject [prefix, suffix].compact.join
  186. is_expected.to have_body_text(group_epic_path(group, epic))
  187. end
  188. end
  189. it 'contains a link to epic author' do
  190. is_expected.to have_body_text(epic.author_name)
  191. is_expected.to have_body_text 'created an epic:'
  192. is_expected.to have_link(epic.to_reference, href: group_epic_url(group, epic))
  193. end
  194. it 'contains a link to the epic' do
  195. is_expected.to have_body_text(epic.to_reference)
  196. end
  197. context 'got deleted before notification' do
  198. subject { described_class.new_epic_email(recipient.id, 0) }
  199. it 'does not send email' do
  200. expect(subject.message).to be_a_kind_of ActionMailer::Base::NullMail
  201. end
  202. end
  203. end
  204. context 'that changed status' do
  205. let(:status) { 'reopened' }
  206. subject { described_class.epic_status_changed_email(recipient.id, epic.id, status, current_user.id) }
  207. it_behaves_like 'epic notifications with reply' do
  208. let(:email_body) { "Epic was #{status} by #{current_user.name}" }
  209. end
  210. end
  211. context 'for epic notes' do
  212. let_it_be(:note) { create(:note, project: nil, noteable: epic) }
  213. let(:note_author) { note.author }
  214. subject { described_class.note_epic_email(recipient.id, note.id) }
  215. it_behaves_like 'epic notifications with reply' do
  216. let(:email_body) { group_epic_path(group, epic, anchor: "note_#{note.id}") }
  217. end
  218. it_behaves_like 'a note email'
  219. end
  220. end
  221. end
  222. describe 'mirror was hard failed' do
  223. let(:project) { create(:project, :mirror, :import_hard_failed) }
  224. subject { described_class.mirror_was_hard_failed_email(project.id, user.id) }
  225. it_behaves_like 'an email sent from GitLab'
  226. it_behaves_like 'it should not have Gmail Actions links'
  227. it_behaves_like "a user cannot unsubscribe through footer link"
  228. it 'has the correct subject and body' do
  229. is_expected.to have_subject("#{project.name} | Repository mirroring paused")
  230. is_expected.to have_body_text(project.full_path)
  231. is_expected.to have_body_text(project_settings_repository_url(project))
  232. end
  233. end
  234. describe 'mirror was disabled' do
  235. let(:project) { create(:project) }
  236. subject { described_class.mirror_was_disabled_email(project.id, user.id, 'deleted_user_name') }
  237. it_behaves_like 'an email sent from GitLab'
  238. it_behaves_like 'it should not have Gmail Actions links'
  239. it_behaves_like "a user cannot unsubscribe through footer link"
  240. it 'has the correct subject and body' do
  241. is_expected.to have_subject("#{project.name} | Repository mirroring disabled")
  242. is_expected.to have_body_text(project.full_path)
  243. is_expected.to have_body_text(project_settings_repository_url(project))
  244. is_expected.to have_body_text('deleted_user_name')
  245. end
  246. context 'user was deleted' do
  247. before do
  248. user.destroy!
  249. end
  250. it 'does not send email' do
  251. expect(subject.message).to be_a_kind_of ActionMailer::Base::NullMail
  252. end
  253. end
  254. end
  255. describe 'mirror user changed' do
  256. let(:mirror_user) { create(:user) }
  257. let(:project) { create(:project, :mirror, mirror_user_id: mirror_user.id) }
  258. let(:new_mirror_user) { project.team.owners.first }
  259. subject { described_class.project_mirror_user_changed_email(new_mirror_user.id, mirror_user.name, project.id) }
  260. it_behaves_like 'an email sent from GitLab'
  261. it_behaves_like 'it should not have Gmail Actions links'
  262. it_behaves_like "a user cannot unsubscribe through footer link"
  263. it 'has the correct subject and body' do
  264. is_expected.to have_subject("#{project.name} | Mirror user changed")
  265. is_expected.to have_body_text(project.full_path)
  266. end
  267. end
  268. describe 'new user was created via saml' do
  269. let(:group_member) { create(:group_member, user: create(:user, :unconfirmed)) }
  270. let(:group) { group_member.source }
  271. let(:recipient) { group_member.user }
  272. subject { described_class.provisioned_member_access_granted_email(group_member.id) }
  273. it_behaves_like 'an email sent from GitLab'
  274. it_behaves_like 'it should not have Gmail Actions links'
  275. it_behaves_like 'a user cannot unsubscribe through footer link'
  276. it_behaves_like 'appearance header and footer enabled'
  277. it_behaves_like 'appearance header and footer not enabled'
  278. it 'delivers mail to user email' do
  279. expect(subject).to deliver_to(recipient.email)
  280. end
  281. it 'contains all the useful information' do
  282. is_expected.to have_subject 'Welcome to GitLab'
  283. is_expected.to have_body_text group.name
  284. is_expected.to have_body_text group.web_url
  285. is_expected.to have_body_text recipient.username
  286. is_expected.to have_body_text recipient.email
  287. is_expected.to have_body_text 'To get started, click the link below to confirm your account'
  288. is_expected.to have_body_text recipient.confirmation_token
  289. end
  290. end
  291. def expect_sender(user)
  292. sender = subject.header[:from].addrs[0]
  293. expect(sender.display_name).to eq("#{user.name} (@#{user.username})")
  294. expect(sender.address).to eq(gitlab_sender)
  295. end
  296. end