summaryrefslogtreecommitdiff
path: root/spec/support/shared_examples/notify_shared_examples.rb
blob: ca031df000e3d77d5f5a16248d504ec63d90aa19 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# frozen_string_literal: true

shared_context 'gitlab email notification' do
  set(:group) { create(:group) }
  set(:subgroup) { create(:group, parent: group) }
  set(:project) { create(:project, :repository, name: 'a-known-name', group: group) }
  set(:recipient) { create(:user, email: 'recipient@example.com') }

  let(:gitlab_sender_display_name) { Gitlab.config.gitlab.email_display_name }
  let(:gitlab_sender) { Gitlab.config.gitlab.email_from }
  let(:gitlab_sender_reply_to) { Gitlab.config.gitlab.email_reply_to }
  let(:new_user_address) { 'newguy@example.com' }

  before do
    email = recipient.emails.create(email: "notifications@example.com")
    recipient.update_attribute(:notification_email, email.email)
    stub_incoming_email_setting(enabled: true, address: "reply+%{key}@#{Gitlab.config.gitlab.host}")
  end
end

shared_context 'reply-by-email is enabled with incoming address without %{key}' do
  before do
    stub_incoming_email_setting(enabled: true, address: "reply@#{Gitlab.config.gitlab.host}")
  end
end

shared_examples 'a multiple recipients email' do
  it 'is sent to the given recipient' do
    is_expected.to deliver_to recipient.notification_email
  end
end

shared_examples 'an email sent from GitLab' do
  it 'has the characteristics of an email sent from GitLab' do
    sender = subject.header[:from].addrs[0]
    reply_to = subject.header[:reply_to].addresses

    aggregate_failures do
      expect(sender.display_name).to eq(gitlab_sender_display_name)
      expect(sender.address).to eq(gitlab_sender)
      expect(reply_to).to eq([gitlab_sender_reply_to])
    end
  end
end

shared_examples 'an email sent to a user' do
  it 'is sent to user\'s global notification email address' do
    expect(subject).to deliver_to(recipient.notification_email)
  end

  context 'with group notification email' do
    it 'is sent to user\'s group notification email' do
      group_notification_email = 'user+group@example.com'

      create(:notification_setting, user: recipient, source: group, notification_email: group_notification_email)

      expect(subject).to deliver_to(group_notification_email)
    end
  end
end

shared_examples 'an email that contains a header with author username' do
  it 'has X-GitLab-Author header containing author\'s username' do
    is_expected.to have_header 'X-GitLab-Author', user.username
  end
end

shared_examples 'an email with X-GitLab headers containing IDs' do
  it 'has X-GitLab-*-ID header' do
    is_expected.to have_header "X-GitLab-#{model.class.name}-ID", "#{model.id}"
  end

  it 'has X-GitLab-*-IID header if model has iid defined' do
    if model.respond_to?(:iid)
      is_expected.to have_header "X-GitLab-#{model.class.name}-IID", "#{model.iid}"
    else
      expect(subject.header["X-GitLab-#{model.class.name}-IID"]).to eq nil
    end
  end
end

shared_examples 'an email with X-GitLab headers containing project details' do
  it 'has X-GitLab-Project headers' do
    aggregate_failures do
      full_path_as_domain = "#{project.name}.#{project.namespace.path}"
      is_expected.to have_header('X-GitLab-Project', /#{project.name}/)
      is_expected.to have_header('X-GitLab-Project-Id', /#{project.id}/)
      is_expected.to have_header('X-GitLab-Project-Path', /#{project.full_path}/)
      is_expected.to have_header('List-Id', "#{project.full_path} <#{project.id}.#{full_path_as_domain}.#{Gitlab.config.gitlab.host}>")
    end
  end
end

shared_examples 'a new thread email with reply-by-email enabled' do
  it 'has the characteristics of a threaded email' do
    host = Gitlab.config.gitlab.host
    route_key = "#{model.class.model_name.singular_route_key}_#{model.id}"

    aggregate_failures do
      is_expected.to have_header('Message-ID', "<#{route_key}@#{host}>")
      is_expected.to have_header('References', /\A<reply\-.*@#{host}>\Z/ )
    end
  end
end

shared_examples 'a thread answer email with reply-by-email enabled' do
  include_examples 'an email with X-GitLab headers containing project details'
  include_examples 'an email with X-GitLab headers containing IDs'

  it 'has the characteristics of a threaded reply' do
    host = Gitlab.config.gitlab.host
    route_key = "#{model.class.model_name.singular_route_key}_#{model.id}"

    aggregate_failures do
      is_expected.to have_header('Message-ID', /\A<.*@#{host}>\Z/)
      is_expected.to have_header('In-Reply-To', "<#{route_key}@#{host}>")
      is_expected.to have_header('References', /\A<reply\-.*@#{host}> <#{route_key}@#{host}>\Z/ )
      is_expected.to have_subject(/^Re: /)
    end
  end
end

shared_examples 'an email starting a new thread with reply-by-email enabled' do
  include_examples 'an email with X-GitLab headers containing project details'
  include_examples 'an email with X-GitLab headers containing IDs'
  include_examples 'a new thread email with reply-by-email enabled'

  it 'includes "Reply to this email directly or <View it on GitLab>"' do
    expect(subject.default_part.body).to include(%(Reply to this email directly or <a href="#{Gitlab::UrlBuilder.build(model)}">view it on GitLab</a>.))
  end

  context 'when reply-by-email is enabled with incoming address with %{key}' do
    it 'has a Reply-To header' do
      is_expected.to have_header 'Reply-To', /<reply+(.*)@#{Gitlab.config.gitlab.host}>\Z/
    end
  end

  context 'when reply-by-email is enabled with incoming address without %{key}' do
    include_context 'reply-by-email is enabled with incoming address without %{key}'
    include_examples 'a new thread email with reply-by-email enabled'

    it 'has a Reply-To header' do
      is_expected.to have_header 'Reply-To', /<reply@#{Gitlab.config.gitlab.host}>\Z/
    end
  end
end

shared_examples 'an answer to an existing thread with reply-by-email enabled' do
  include_examples 'an email with X-GitLab headers containing project details'
  include_examples 'an email with X-GitLab headers containing IDs'
  include_examples 'a thread answer email with reply-by-email enabled'

  context 'when reply-by-email is enabled with incoming address with %{key}' do
    it 'has a Reply-To header' do
      is_expected.to have_header 'Reply-To', /<reply+(.*)@#{Gitlab.config.gitlab.host}>\Z/
    end
  end

  context 'when reply-by-email is enabled with incoming address without %{key}' do
    include_context 'reply-by-email is enabled with incoming address without %{key}'
    include_examples 'a thread answer email with reply-by-email enabled'

    it 'has a Reply-To header' do
      is_expected.to have_header 'Reply-To', /<reply@#{Gitlab.config.gitlab.host}>\Z/
    end
  end
end

shared_examples 'it should have Gmail Actions links' do
  it do
    aggregate_failures do
      is_expected.to have_body_text('<script type="application/ld+json">')
      is_expected.to have_body_text('ViewAction')
    end
  end
end

shared_examples 'it should not have Gmail Actions links' do
  it do
    aggregate_failures do
      is_expected.not_to have_body_text('<script type="application/ld+json">')
      is_expected.not_to have_body_text('ViewAction')
    end
  end
end

shared_examples 'it should show Gmail Actions View Issue link' do
  it_behaves_like 'it should have Gmail Actions links'

  it { is_expected.to have_body_text('View Issue') }
end

shared_examples 'it should show Gmail Actions View Merge request link' do
  it_behaves_like 'it should have Gmail Actions links'

  it { is_expected.to have_body_text('View Merge request') }
end

shared_examples 'it should show Gmail Actions View Commit link' do
  it_behaves_like 'it should have Gmail Actions links'

  it { is_expected.to have_body_text('View Commit') }
end

shared_examples 'an unsubscribeable thread' do
  it_behaves_like 'an unsubscribeable thread with incoming address without %{key}'

  it 'has a List-Unsubscribe header in the correct format, and a body link' do
    aggregate_failures do
      is_expected.to have_header('List-Unsubscribe', /unsubscribe/)
      is_expected.to have_header('List-Unsubscribe', /mailto/)
      is_expected.to have_header('List-Unsubscribe', /^<.+,.+>$/)
      is_expected.to have_body_text('unsubscribe')
    end
  end
end

shared_examples 'an unsubscribeable thread with incoming address without %{key}' do
  include_context 'reply-by-email is enabled with incoming address without %{key}'

  it 'has a List-Unsubscribe header in the correct format, and a body link' do
    aggregate_failures do
      is_expected.to have_header('List-Unsubscribe', /unsubscribe/)
      is_expected.not_to have_header('List-Unsubscribe', /mailto/)
      is_expected.to have_header('List-Unsubscribe', /^<[^,]+>$/)
      is_expected.to have_body_text('unsubscribe')
    end
  end
end

shared_examples 'a user cannot unsubscribe through footer link' do
  it 'does not have a List-Unsubscribe header or a body link' do
    aggregate_failures do
      is_expected.not_to have_header('List-Unsubscribe', /unsubscribe/)
      is_expected.not_to have_body_text('unsubscribe')
    end
  end
end

shared_examples 'an email with a labels subscriptions link in its footer' do
  it { is_expected.to have_body_text('label subscriptions') }
end

shared_examples 'a note email' do
  it_behaves_like 'it should have Gmail Actions links'

  it 'is sent to the given recipient as the author' do
    sender = subject.header[:from].addrs[0]

    aggregate_failures do
      expect(sender.display_name).to eq(note_author.name)
      expect(sender.address).to eq(gitlab_sender)
      expect(subject).to deliver_to(recipient.notification_email)
    end
  end

  it 'contains the message from the note' do
    is_expected.to have_body_text note.note
  end

  it 'contains a link to note author' do
    is_expected.to have_body_text note.author_name
  end
end

shared_examples 'appearance header and footer enabled' do
  it "contains header and footer" do
    create :appearance, header_message: "Foo", footer_message: "Bar", email_header_and_footer_enabled: true

    aggregate_failures do
      expect(subject.html_part).to have_body_text("<div class=\"header-message\" style=\"\"><p>Foo</p></div>")
      expect(subject.html_part).to have_body_text("<div class=\"footer-message\" style=\"\"><p>Bar</p></div>")

      expect(subject.text_part).to have_body_text(/^Foo/)
      expect(subject.text_part).to have_body_text(/Bar$/)
    end
  end
end

shared_examples 'appearance header and footer not enabled' do
  it "does not contain header and footer" do
    create :appearance, header_message: "Foo", footer_message: "Bar", email_header_and_footer_enabled: false

    aggregate_failures do
      expect(subject.html_part).not_to have_body_text("<div class=\"header-message\" style=\"\"><p>Foo</p></div>")
      expect(subject.html_part).not_to have_body_text("<div class=\"footer-message\" style=\"\"><p>Bar</p></div>")

      expect(subject.text_part).not_to have_body_text(/^Foo/)
      expect(subject.text_part).not_to have_body_text(/Bar$/)
    end
  end
end