about summary refs log tree commit diff
path: root/spec/services/update_status_service_spec.rb
blob: d6923722ab01e0d13efba7f6d699034026decc41 (plain) (blame)
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
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe UpdateStatusService, type: :service do
  subject { described_class.new }

  context 'when nothing changes' do
    let!(:status) { Fabricate(:status, text: 'Foo', language: 'en') }

    before do
      allow(ActivityPub::DistributionWorker).to receive(:perform_async)
      subject.call(status, status.account_id, text: 'Foo')
    end

    it 'does not create an edit' do
      expect(status.reload.edits).to be_empty
    end

    it 'does not notify anyone' do
      expect(ActivityPub::DistributionWorker).to_not have_received(:perform_async)
    end
  end

  context 'when text changes' do
    let!(:status) { Fabricate(:status, text: 'Foo') }
    let(:preview_card) { Fabricate(:preview_card) }

    before do
      status.preview_cards << preview_card
      subject.call(status, status.account_id, text: 'Bar')
    end

    it 'updates text' do
      expect(status.reload.text).to eq 'Bar'
    end

    it 'resets preview card' do
      expect(status.reload.preview_card).to be_nil
    end

    it 'saves edit history' do
      expect(status.edits.pluck(:text)).to eq %w(Foo Bar)
    end
  end

  context 'when content warning changes' do
    let!(:status) { Fabricate(:status, text: 'Foo', spoiler_text: '') }
    let(:preview_card) { Fabricate(:preview_card) }

    before do
      status.preview_cards << preview_card
      subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar')
    end

    it 'updates content warning' do
      expect(status.reload.spoiler_text).to eq 'Bar'
    end

    it 'saves edit history' do
      expect(status.edits.pluck(:text, :spoiler_text)).to eq [['Foo', ''], ['Foo', 'Bar']]
    end
  end

  context 'when media attachments change' do
    let!(:status) { Fabricate(:status, text: 'Foo') }
    let!(:detached_media_attachment) { Fabricate(:media_attachment, account: status.account) }
    let!(:attached_media_attachment) { Fabricate(:media_attachment, account: status.account) }

    before do
      status.media_attachments << detached_media_attachment
      subject.call(status, status.account_id, text: 'Foo', media_ids: [attached_media_attachment.id])
    end

    it 'updates media attachments' do
      expect(status.ordered_media_attachments).to eq [attached_media_attachment]
    end

    it 'does not detach detached media attachments' do
      expect(detached_media_attachment.reload.status_id).to eq status.id
    end

    it 'attaches attached media attachments' do
      expect(attached_media_attachment.reload.status_id).to eq status.id
    end

    it 'saves edit history' do
      expect(status.edits.pluck(:ordered_media_attachment_ids)).to eq [[detached_media_attachment.id], [attached_media_attachment.id]]
    end
  end

  context 'when already-attached media changes' do
    let!(:status) { Fabricate(:status, text: 'Foo') }
    let!(:media_attachment) { Fabricate(:media_attachment, account: status.account, description: 'Old description') }

    before do
      status.media_attachments << media_attachment
      subject.call(status, status.account_id, text: 'Foo', media_ids: [media_attachment.id], media_attributes: [{ id: media_attachment.id, description: 'New description' }])
    end

    it 'does not detach media attachment' do
      expect(media_attachment.reload.status_id).to eq status.id
    end

    it 'updates the media attachment description' do
      expect(media_attachment.reload.description).to eq 'New description'
    end

    it 'saves edit history' do
      expect(status.edits.map { |edit| edit.ordered_media_attachments.map(&:description) }).to eq [['Old description'], ['New description']]
    end
  end

  context 'when poll changes' do
    let(:account) { Fabricate(:account) }
    let!(:status) { Fabricate(:status, text: 'Foo', account: account, poll_attributes: { options: %w(Foo Bar), account: account, multiple: false, hide_totals: false, expires_at: 7.days.from_now }) }
    let!(:poll)   { status.poll }
    let!(:voter) { Fabricate(:account) }

    before do
      status.update(poll: poll)
      VoteService.new.call(voter, poll, [0])
      Sidekiq::Testing.fake! do
        subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i })
      end
    end

    it 'updates poll' do
      poll = status.poll.reload
      expect(poll.options).to eq %w(Bar Baz Foo)
    end

    it 'resets votes' do
      poll = status.poll.reload
      expect(poll.votes_count).to eq 0
      expect(poll.votes.count).to eq 0
      expect(poll.cached_tallies).to eq [0, 0, 0]
    end

    it 'saves edit history' do
      expect(status.edits.pluck(:poll_options)).to eq [%w(Foo Bar), %w(Bar Baz Foo)]
    end

    it 'requeues expiration notification' do
      poll = status.poll.reload
      expect(PollExpirationNotifyWorker).to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes)
    end
  end

  context 'when mentions in text change' do
    let!(:account) { Fabricate(:account) }
    let!(:alice) { Fabricate(:account, username: 'alice') }
    let!(:bob) { Fabricate(:account, username: 'bob') }
    let!(:status) { PostStatusService.new.call(account, text: 'Hello @alice') }

    before do
      subject.call(status, status.account_id, text: 'Hello @bob')
    end

    it 'changes mentions' do
      expect(status.active_mentions.pluck(:account_id)).to eq [bob.id]
    end

    it 'keeps old mentions as silent mentions' do
      expect(status.mentions.pluck(:account_id)).to match_array([alice.id, bob.id])
    end
  end

  context 'when hashtags in text change' do
    let!(:account) { Fabricate(:account) }
    let!(:status) { PostStatusService.new.call(account, text: 'Hello #foo') }

    before do
      subject.call(status, status.account_id, text: 'Hello #bar')
    end

    it 'changes tags' do
      expect(status.tags.pluck(:name)).to eq %w(bar)
    end
  end

  it 'notifies ActivityPub about the update' do
    status = Fabricate(:status, text: 'Foo')
    allow(ActivityPub::DistributionWorker).to receive(:perform_async)
    subject.call(status, status.account_id, text: 'Bar')
    expect(ActivityPub::DistributionWorker).to have_received(:perform_async)
  end
end