Merge branch 'main' into glitch-soc/merge-upstream

Conflicts:
- `.github/dependabot.yml`:
  Upstream made changes while we have dropped this file.
  Keep the file deleted.
- `.prettierignore`:
  Upstream made changes at the end of the file, where we
  had our extra lines.
  Just moved our extra lines back at the end.
- `app/serializers/initial_state_serializer.rb`:
  Upstream code style changes.
  Applied them.
- `app/services/backup_service.rb`:
  Upstream code style changes.
  Applied them.
This commit is contained in:
Claire
2023-02-19 10:42:55 +01:00
391 changed files with 6713 additions and 3145 deletions

View File

@@ -76,7 +76,7 @@ describe AccountSearchService, type: :service do
expect(results).to eq [partial]
end
it "does not return suspended remote accounts" do
it 'does not return suspended remote accounts' do
remote = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true)
results = subject.call('a@example.com', nil, limit: 2)

View File

@@ -42,8 +42,8 @@ describe AccountStatusesCleanupService, type: :service do
context 'when called repeatedly with a budget of 2' do
it 'reports 2 then 1 deleted statuses' do
expect(subject.call(account_policy, 2)).to eq 2
expect(subject.call(account_policy, 2)).to eq 1
expect(subject.call(account_policy, 2)).to eq 2
expect(subject.call(account_policy, 2)).to eq 1
end
it 'actually deletes the statuses in the expected order' do

View File

@@ -109,7 +109,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
type: 'CollectionPage',
partOf: actor.featured_collection_url,
items: items,
}
},
}.with_indifferent_access
end

View File

@@ -81,7 +81,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
type: 'CollectionPage',
partOf: collection_url,
items: items,
}
},
}.with_indifferent_access
end

View File

@@ -11,7 +11,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
let(:note) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://foo.bar/@foo/1234",
id: 'https://foo.bar/@foo/1234',
type: 'Note',
content: 'Lorem ipsum',
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
@@ -46,7 +46,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
let(:object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://foo.bar/@foo/1234",
id: 'https://foo.bar/@foo/1234',
type: 'Video',
name: 'Nyan Cat 10 hours remix',
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
@@ -54,13 +54,13 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
{
type: 'Link',
mimeType: 'application/x-bittorrent',
href: "https://foo.bar/12345.torrent",
href: 'https://foo.bar/12345.torrent',
},
{
type: 'Link',
mimeType: 'text/html',
href: "https://foo.bar/watch?v=12345",
href: 'https://foo.bar/watch?v=12345',
},
],
}
@@ -70,8 +70,8 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
status = sender.statuses.first
expect(status).to_not be_nil
expect(status.url).to eq "https://foo.bar/watch?v=12345"
expect(strip_tags(status.text)).to eq "Nyan Cat 10 hours remixhttps://foo.bar/watch?v=12345"
expect(status.url).to eq 'https://foo.bar/watch?v=12345'
expect(strip_tags(status.text)).to eq 'Nyan Cat 10 hours remixhttps://foo.bar/watch?v=12345'
end
end
@@ -79,7 +79,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
let(:object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://foo.bar/@foo/1234",
id: 'https://foo.bar/@foo/1234',
type: 'Audio',
name: 'Nyan Cat 10 hours remix',
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
@@ -87,13 +87,13 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
{
type: 'Link',
mimeType: 'application/x-bittorrent',
href: "https://foo.bar/12345.torrent",
href: 'https://foo.bar/12345.torrent',
},
{
type: 'Link',
mimeType: 'text/html',
href: "https://foo.bar/watch?v=12345",
href: 'https://foo.bar/watch?v=12345',
},
],
}
@@ -103,8 +103,8 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
status = sender.statuses.first
expect(status).to_not be_nil
expect(status.url).to eq "https://foo.bar/watch?v=12345"
expect(strip_tags(status.text)).to eq "Nyan Cat 10 hours remixhttps://foo.bar/watch?v=12345"
expect(status.url).to eq 'https://foo.bar/watch?v=12345'
expect(strip_tags(status.text)).to eq 'Nyan Cat 10 hours remixhttps://foo.bar/watch?v=12345'
end
end
@@ -112,10 +112,10 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
let(:object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://foo.bar/@foo/1234",
id: 'https://foo.bar/@foo/1234',
type: 'Event',
name: "Let's change the world",
attributedTo: ActivityPub::TagManager.instance.uri_for(sender)
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
}
end
@@ -123,7 +123,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
status = sender.statuses.first
expect(status).to_not be_nil
expect(status.url).to eq "https://foo.bar/@foo/1234"
expect(status.url).to eq 'https://foo.bar/@foo/1234'
expect(strip_tags(status.text)).to eq "Let's change the worldhttps://foo.bar/@foo/1234"
end
end
@@ -132,7 +132,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
let(:note) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://real.address/@foo/1234",
id: 'https://real.address/@foo/1234',
type: 'Note',
content: 'Lorem ipsum',
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
@@ -154,7 +154,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
let(:object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://foo.bar/@foo/1234/create",
id: 'https://foo.bar/@foo/1234/create',
type: 'Create',
actor: ActivityPub::TagManager.instance.uri_for(sender),
object: note,
@@ -174,11 +174,11 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
let(:object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://foo.bar/@foo/1234/create",
id: 'https://foo.bar/@foo/1234/create',
type: 'Create',
actor: ActivityPub::TagManager.instance.uri_for(sender),
object: {
id: "https://real.address/@foo/1234",
id: 'https://real.address/@foo/1234',
type: 'Note',
content: 'Lorem ipsum',
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
@@ -208,7 +208,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
let(:object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://foo.bar/@foo/1234/create",
id: 'https://foo.bar/@foo/1234/create',
type: 'Create',
actor: ActivityPub::TagManager.instance.uri_for(sender),
object: note.merge(updated: '2021-09-08T22:39:25Z'),
@@ -233,7 +233,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
let(:object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://foo.bar/@foo/1",
id: 'https://foo.bar/@foo/1',
type: 'Note',
content: 'Lorem ipsum',
inReplyTo: 'https://foo.bar/@foo/2',
@@ -269,7 +269,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
let(:object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://foo.bar/@foo/1",
id: 'https://foo.bar/@foo/1',
type: 'Note',
content: 'Lorem ipsum',
replies: {
@@ -298,7 +298,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
first: {
type: 'CollectionPage',
partOf: "https://foo.bar/@foo/#{i}/replies",
items: ["https://foo.bar/@foo/#{i+1}"],
items: ["https://foo.bar/@foo/#{i + 1}"],
},
},
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),

View File

@@ -90,7 +90,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do
type: 'CollectionPage',
partOf: collection_uri,
items: items,
}
},
}.with_indifferent_access
end

View File

@@ -172,10 +172,10 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
{
type: 'Mention',
href: "https://foo.test/users/#{i + 1}",
name: "@user#{i + 1 }",
}
name: "@user#{i + 1}",
},
],
to: [ 'as:Public', "https://foo.test/users/#{i + 1}" ]
to: ['as:Public', "https://foo.test/users/#{i + 1}"],
}.with_indifferent_access
featured_json = {
'@context': ['https://www.w3.org/ns/activitystreams'],

View File

@@ -95,11 +95,11 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
context 'when receiving a fabricated status' do
let!(:actor) do
Fabricate(:account,
username: 'bob',
domain: 'example.com',
uri: 'https://example.com/users/bob',
public_key: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuuYyoyfsRkYnXRotMsId\nW3euBDDfiv9oVqOxUVC7bhel8KednIMrMCRWFAkgJhbrlzbIkjVr68o1MP9qLcn7\nCmH/BXHp7yhuFTr4byjdJKpwB+/i2jNEsvDH5jR8WTAeTCe0x/QHg21V3F7dSI5m\nCCZ/1dSIyOXLRTWVlfDlm3rE4ntlCo+US3/7oSWbg/4/4qEnt1HC32kvklgScxua\n4LR5ATdoXa5bFoopPWhul7MJ6NyWCyQyScUuGdlj8EN4kmKQJvphKHrI9fvhgOuG\nTvhTR1S5InA4azSSchY0tXEEw/VNxraeX0KPjbgr6DPcwhPd/m0nhVDq0zVyVBBD\nMwIDAQAB\n-----END PUBLIC KEY-----\n",
private_key: nil)
username: 'bob',
domain: 'example.com',
uri: 'https://example.com/users/bob',
public_key: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuuYyoyfsRkYnXRotMsId\nW3euBDDfiv9oVqOxUVC7bhel8KednIMrMCRWFAkgJhbrlzbIkjVr68o1MP9qLcn7\nCmH/BXHp7yhuFTr4byjdJKpwB+/i2jNEsvDH5jR8WTAeTCe0x/QHg21V3F7dSI5m\nCCZ/1dSIyOXLRTWVlfDlm3rE4ntlCo+US3/7oSWbg/4/4qEnt1HC32kvklgScxua\n4LR5ATdoXa5bFoopPWhul7MJ6NyWCyQyScUuGdlj8EN4kmKQJvphKHrI9fvhgOuG\nTvhTR1S5InA4azSSchY0tXEEw/VNxraeX0KPjbgr6DPcwhPd/m0nhVDq0zVyVBBD\nMwIDAQAB\n-----END PUBLIC KEY-----\n",
private_key: nil)
end
let(:payload) do
@@ -107,48 +107,48 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
'@context': [
'https://www.w3.org/ns/activitystreams',
nil,
{'object': 'https://www.w3.org/ns/activitystreams#object'}
{ object: 'https://www.w3.org/ns/activitystreams#object' },
],
'id': 'https://example.com/users/bob/fake-status/activity',
'type': 'Create',
'actor': 'https://example.com/users/bob',
'published': '2022-01-22T15:00:00Z',
'to': [
'https://www.w3.org/ns/activitystreams#Public'
id: 'https://example.com/users/bob/fake-status/activity',
type: 'Create',
actor: 'https://example.com/users/bob',
published: '2022-01-22T15:00:00Z',
to: [
'https://www.w3.org/ns/activitystreams#Public',
],
'cc': [
'https://example.com/users/bob/followers'
cc: [
'https://example.com/users/bob/followers',
],
'signature': {
'type': 'RsaSignature2017',
'creator': 'https://example.com/users/bob#main-key',
'created': '2022-03-09T21:57:25Z',
'signatureValue': 'WculK0LelTQ0MvGwU9TPoq5pFzFfGYRDCJqjZ232/Udj4CHqDTGOSw5UTDLShqBOyycCkbZGrQwXG+dpyDpQLSe1UVPZ5TPQtc/9XtI57WlS2nMNpdvRuxGnnb2btPdesXZ7n3pCxo0zjaXrJMe0mqQh5QJO22mahb4bDwwmfTHgbD3nmkD+fBfGi+UV2qWwqr+jlV4L4JqNkh0gWljF5KTePLRRZCuWiQ/FAt7c67636cdIPf7fR+usjuZltTQyLZKEGuK8VUn2Gkfsx5qns7Vcjvlz1JqlAjyO8HPBbzTTHzUG2nUOIgC3PojCSWv6mNTmRGoLZzOscCAYQA6cKw=='
signature: {
type: 'RsaSignature2017',
creator: 'https://example.com/users/bob#main-key',
created: '2022-03-09T21:57:25Z',
signatureValue: 'WculK0LelTQ0MvGwU9TPoq5pFzFfGYRDCJqjZ232/Udj4CHqDTGOSw5UTDLShqBOyycCkbZGrQwXG+dpyDpQLSe1UVPZ5TPQtc/9XtI57WlS2nMNpdvRuxGnnb2btPdesXZ7n3pCxo0zjaXrJMe0mqQh5QJO22mahb4bDwwmfTHgbD3nmkD+fBfGi+UV2qWwqr+jlV4L4JqNkh0gWljF5KTePLRRZCuWiQ/FAt7c67636cdIPf7fR+usjuZltTQyLZKEGuK8VUn2Gkfsx5qns7Vcjvlz1JqlAjyO8HPBbzTTHzUG2nUOIgC3PojCSWv6mNTmRGoLZzOscCAYQA6cKw==',
},
'@id': 'https://example.com/users/bob/statuses/107928807471117876/activity',
'@type': 'https://www.w3.org/ns/activitystreams#Create',
'https://www.w3.org/ns/activitystreams#actor': {
'@id': 'https://example.com/users/bob'
'@id': 'https://example.com/users/bob',
},
'https://www.w3.org/ns/activitystreams#cc': {
'@id': 'https://example.com/users/bob/followers'
'@id': 'https://example.com/users/bob/followers',
},
'object': {
'id': 'https://example.com/users/bob/fake-status',
'type': 'Note',
'published': '2022-01-22T15:00:00Z',
'url': 'https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=puck-was-here',
'attributedTo': 'https://example.com/users/bob',
'to': [
'https://www.w3.org/ns/activitystreams#Public'
object: {
id: 'https://example.com/users/bob/fake-status',
type: 'Note',
published: '2022-01-22T15:00:00Z',
url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=puck-was-here',
attributedTo: 'https://example.com/users/bob',
to: [
'https://www.w3.org/ns/activitystreams#Public',
],
'cc': [
'https://example.com/users/bob/followers'
cc: [
'https://example.com/users/bob/followers',
],
'sensitive': false,
'atomUri': 'https://example.com/users/bob/fake-status',
'conversation': 'tag:example.com,2022-03-09:objectId=15:objectType=Conversation',
'content': '<p>puck was here</p>',
sensitive: false,
atomUri: 'https://example.com/users/bob/fake-status',
conversation: 'tag:example.com,2022-03-09:objectId=15:objectType=Conversation',
content: '<p>puck was here</p>',
'@id': 'https://example.com/users/bob/statuses/107928807471117876',
'@type': 'https://www.w3.org/ns/activitystreams#Note',
@@ -156,21 +156,21 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
'http://ostatus.org#conversation': 'tag:example.com,2022-03-09:objectId=15:objectType=Conversation',
'https://www.w3.org/ns/activitystreams#attachment': [],
'https://www.w3.org/ns/activitystreams#attributedTo': {
'@id': 'https://example.com/users/bob'
'@id': 'https://example.com/users/bob',
},
'https://www.w3.org/ns/activitystreams#cc': {
'@id': 'https://example.com/users/bob/followers'
'@id': 'https://example.com/users/bob/followers',
},
'https://www.w3.org/ns/activitystreams#content': [
'<p>hello world</p>',
{
'@value': '<p>hello world</p>',
'@language': 'en'
}
'@language': 'en',
},
],
'https://www.w3.org/ns/activitystreams#published': {
'@type': 'http://www.w3.org/2001/XMLSchema#dateTime',
'@value': '2022-03-09T21:55:07Z'
'@value': '2022-03-09T21:55:07Z',
},
'https://www.w3.org/ns/activitystreams#replies': {
'@id': 'https://example.com/users/bob/statuses/107928807471117876/replies',
@@ -179,29 +179,29 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
'@type': 'https://www.w3.org/ns/activitystreams#CollectionPage',
'https://www.w3.org/ns/activitystreams#items': [],
'https://www.w3.org/ns/activitystreams#next': {
'@id': 'https://example.com/users/bob/statuses/107928807471117876/replies?only_other_accounts=true&page=true'
'@id': 'https://example.com/users/bob/statuses/107928807471117876/replies?only_other_accounts=true&page=true',
},
'https://www.w3.org/ns/activitystreams#partOf': {
'@id': 'https://example.com/users/bob/statuses/107928807471117876/replies'
}
}
'@id': 'https://example.com/users/bob/statuses/107928807471117876/replies',
},
},
},
'https://www.w3.org/ns/activitystreams#sensitive': false,
'https://www.w3.org/ns/activitystreams#tag': [],
'https://www.w3.org/ns/activitystreams#to': {
'@id': 'https://www.w3.org/ns/activitystreams#Public'
'@id': 'https://www.w3.org/ns/activitystreams#Public',
},
'https://www.w3.org/ns/activitystreams#url': {
'@id': 'https://example.com/@bob/107928807471117876'
}
'@id': 'https://example.com/@bob/107928807471117876',
},
},
'https://www.w3.org/ns/activitystreams#published': {
'@type': 'http://www.w3.org/2001/XMLSchema#dateTime',
'@value': '2022-03-09T21:55:07Z'
'@value': '2022-03-09T21:55:07Z',
},
'https://www.w3.org/ns/activitystreams#to': {
'@id': 'https://www.w3.org/ns/activitystreams#Public'
}
'@id': 'https://www.w3.org/ns/activitystreams#Public',
},
}
end
@@ -212,8 +212,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
'id' => 'https://example.com/users/bob/fake-status'
)
),
anything(),
anything()
anything,
anything
)
expect(ActivityPub::Activity).not_to receive(:factory).with(
@@ -222,8 +222,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
'content' => '<p>puck was here</p>'
)
),
anything(),
anything()
anything,
anything
)
subject.call(json, forwarder)

View File

@@ -104,20 +104,19 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
context 'when the status has not been explicitly edited and features a poll' do
let(:account) { Fabricate(:account, domain: 'example.com') }
let(:account) { Fabricate(:account, domain: 'example.com') }
let!(:expiration) { 10.days.from_now.utc }
let!(:status) do
Fabricate(:status,
text: 'Hello world',
account: account,
poll_attributes: {
options: %w(Foo Bar),
account: account,
multiple: false,
hide_totals: false,
expires_at: expiration
}
)
text: 'Hello world',
account: account,
poll_attributes: {
options: %w(Foo Bar),
account: account,
multiple: false,
hide_totals: false,
expires_at: expiration,
})
end
let(:payload) do
@@ -156,20 +155,19 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
context 'when the status changes a poll despite being not explicitly marked as updated' do
let(:account) { Fabricate(:account, domain: 'example.com') }
let(:account) { Fabricate(:account, domain: 'example.com') }
let!(:expiration) { 10.days.from_now.utc }
let!(:status) do
Fabricate(:status,
text: 'Hello world',
account: account,
poll_attributes: {
options: %w(Foo Bar),
account: account,
multiple: false,
hide_totals: false,
expires_at: expiration
}
)
text: 'Hello world',
account: account,
poll_attributes: {
options: %w(Foo Bar),
account: account,
multiple: false,
hide_totals: false,
expires_at: expiration,
})
end
let(:payload) do
@@ -344,7 +342,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
updated: '2021-09-08T22:39:25Z',
attachment: [
{ type: 'Image', mediaType: 'image/png', url: 'https://example.com/foo.png' },
]
],
}
end
@@ -376,7 +374,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
updated: '2021-09-08T22:39:25Z',
attachment: [
{ type: 'Image', mediaType: 'image/png', url: 'https://example.com/foo.png', name: 'A picture' },
]
],
}
end

View File

@@ -91,7 +91,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
type: 'CollectionPage',
partOf: collection_uri,
items: items,
}
},
}.with_indifferent_access
end

View File

@@ -32,6 +32,5 @@ RSpec.describe BootstrapTimelineService, type: :service do
expect(service).to_not have_received(:call)
end
end
end
end

View File

@@ -59,8 +59,8 @@ RSpec.describe DeleteAccountService, type: :service do
describe '#call on local account' do
before do
stub_request(:post, "https://alice.com/inbox").to_return(status: 201)
stub_request(:post, "https://bob.com/inbox").to_return(status: 201)
stub_request(:post, 'https://alice.com/inbox').to_return(status: 201)
stub_request(:post, 'https://bob.com/inbox').to_return(status: 201)
end
let!(:remote_alice) { Fabricate(:account, inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }
@@ -72,16 +72,16 @@ RSpec.describe DeleteAccountService, type: :service do
it 'sends a delete actor activity to all known inboxes' do
subject
expect(a_request(:post, "https://alice.com/inbox")).to have_been_made.once
expect(a_request(:post, "https://bob.com/inbox")).to have_been_made.once
expect(a_request(:post, 'https://alice.com/inbox')).to have_been_made.once
expect(a_request(:post, 'https://bob.com/inbox')).to have_been_made.once
end
end
end
describe '#call on remote account' do
before do
stub_request(:post, "https://alice.com/inbox").to_return(status: 201)
stub_request(:post, "https://bob.com/inbox").to_return(status: 201)
stub_request(:post, 'https://alice.com/inbox').to_return(status: 201)
stub_request(:post, 'https://bob.com/inbox').to_return(status: 201)
end
include_examples 'common behavior' do

View File

@@ -23,7 +23,7 @@ RSpec.describe FavouriteService, type: :service do
let(:status) { Fabricate(:status, account: bob) }
before do
stub_request(:post, "http://example.com/inbox").to_return(status: 200, body: "", headers: {})
stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {})
subject.call(sender, status)
end
@@ -32,7 +32,7 @@ RSpec.describe FavouriteService, type: :service do
end
it 'sends a like activity' do
expect(a_request(:post, "http://example.com/inbox")).to have_been_made.once
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
end
end
end

View File

@@ -30,7 +30,7 @@ RSpec.describe FetchLinkCardService, type: :service do
it 'works with SJIS' do
expect(a_request(:get, 'http://example.com/sjis')).to have_been_made.at_least_once
expect(status.preview_cards.first.title).to eq("SJISのページ")
expect(status.preview_cards.first.title).to eq('SJISのページ')
end
end
@@ -39,7 +39,7 @@ RSpec.describe FetchLinkCardService, type: :service do
it 'works with SJIS even with wrong charset header' do
expect(a_request(:get, 'http://example.com/sjis_with_wrong_charset')).to have_been_made.at_least_once
expect(status.preview_cards.first.title).to eq("SJISのページ")
expect(status.preview_cards.first.title).to eq('SJISのページ')
end
end
@@ -48,7 +48,7 @@ RSpec.describe FetchLinkCardService, type: :service do
it 'works with koi8-r' do
expect(a_request(:get, 'http://example.com/koi8-r')).to have_been_made.at_least_once
expect(status.preview_cards.first.title).to eq("Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.")
expect(status.preview_cards.first.title).to eq('Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.')
end
end
@@ -66,7 +66,7 @@ RSpec.describe FetchLinkCardService, type: :service do
it 'works with Japanese path string' do
expect(a_request(:get, 'http://example.com/日本語')).to have_been_made.at_least_once
expect(status.preview_cards.first.title).to eq("SJISのページ")
expect(status.preview_cards.first.title).to eq('SJISのページ')
end
end

View File

@@ -6,9 +6,9 @@ describe FetchOEmbedService, type: :service do
subject { described_class.new }
before do
stub_request(:get, "https://host.test/provider.json").to_return(status: 404)
stub_request(:get, "https://host.test/provider.xml").to_return(status: 404)
stub_request(:get, "https://host.test/empty_provider.json").to_return(status: 200)
stub_request(:get, 'https://host.test/provider.json').to_return(status: 404)
stub_request(:get, 'https://host.test/provider.xml').to_return(status: 404)
stub_request(:get, 'https://host.test/empty_provider.json').to_return(status: 200)
end
describe 'discover_provider' do
@@ -18,7 +18,7 @@ describe FetchOEmbedService, type: :service do
stub_request(:get, 'https://www.youtube.com/watch?v=IPSbNdBmWKE').to_return(
status: 200,
headers: { 'Content-Type': 'text/html' },
body: request_fixture('oembed_youtube.html'),
body: request_fixture('oembed_youtube.html')
)
stub_request(:get, 'https://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DIPSbNdBmWKE').to_return(
status: 200,
@@ -151,7 +151,6 @@ describe FetchOEmbedService, type: :service do
expect(subject.format).to eq :json
end
end
end
context 'when endpoint is cached' do

View File

@@ -7,7 +7,7 @@ RSpec.describe FetchRemoteStatusService, type: :service do
let(:note) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: "https://example.org/@foo/1234",
id: 'https://example.org/@foo/1234',
type: 'Note',
content: 'Lorem ipsum',
attributedTo: ActivityPub::TagManager.instance.uri_for(account),

View File

@@ -8,6 +8,7 @@ RSpec.describe FetchResourceService, type: :service do
context 'with blank url' do
let(:url) { '' }
it { is_expected.to be_nil }
end
@@ -21,7 +22,7 @@ RSpec.describe FetchResourceService, type: :service do
context 'when OpenSSL::SSL::SSLError is raised' do
before do
request = double()
request = double
allow(Request).to receive(:new).and_return(request)
allow(request).to receive(:add_headers)
allow(request).to receive(:on_behalf_of)
@@ -33,7 +34,7 @@ RSpec.describe FetchResourceService, type: :service do
context 'when HTTP::ConnectionError is raised' do
before do
request = double()
request = double
allow(Request).to receive(:new).and_return(request)
allow(request).to receive(:add_headers)
allow(request).to receive(:on_behalf_of)
@@ -62,6 +63,7 @@ RSpec.describe FetchResourceService, type: :service do
before do
stub_request(:get, url).to_return(status: 200, body: body, headers: headers)
stub_request(:get, 'http://example.com/foo').to_return(status: 200, body: json, headers: { 'Content-Type' => 'application/activity+json' })
end
it 'signs request' do
@@ -89,13 +91,8 @@ RSpec.describe FetchResourceService, type: :service do
it { is_expected.to eq [1, { prefetched_body: body, id: true }] }
end
before do
stub_request(:get, url).to_return(status: 200, body: body, headers: headers)
stub_request(:get, 'http://example.com/foo').to_return(status: 200, body: json, headers: { 'Content-Type' => 'application/activity+json' })
end
context 'when link header is present' do
let(:headers) { { 'Link' => '<http://example.com/foo>; rel="alternate"; type="application/activity+json"', } }
let(:headers) { { 'Link' => '<http://example.com/foo>; rel="alternate"; type="application/activity+json"' } }
it { is_expected.to eq [1, { prefetched_body: json, id: true }] }
end

View File

@@ -140,7 +140,7 @@ RSpec.describe FollowService, type: :service do
let(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') }
before do
stub_request(:post, "http://example.com/inbox").to_return(status: 200, body: "", headers: {})
stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {})
subject.call(sender, bob)
end

View File

@@ -8,7 +8,7 @@ RSpec.describe ImportService, type: :service do
let!(:eve) { Fabricate(:account, username: 'eve', domain: 'example.com', locked: false, protocol: :activitypub, inbox_url: 'https://example.com/inbox') }
before do
stub_request(:post, "https://example.com/inbox").to_return(status: 200)
stub_request(:post, 'https://example.com/inbox').to_return(status: 200)
end
context 'import old-style list of muted users' do
@@ -18,6 +18,7 @@ RSpec.describe ImportService, type: :service do
describe 'when no accounts are muted' do
let(:import) { Import.create(account: account, type: 'muting', data: csv) }
it 'mutes the listed accounts, including notifications' do
subject.call(import)
expect(account.muting.count).to eq 2
@@ -55,6 +56,7 @@ RSpec.describe ImportService, type: :service do
describe 'when no accounts are muted' do
let(:import) { Import.create(account: account, type: 'muting', data: csv) }
it 'mutes the listed accounts, respecting notifications' do
subject.call(import)
expect(account.muting.count).to eq 2
@@ -95,6 +97,7 @@ RSpec.describe ImportService, type: :service do
describe 'when no accounts are followed' do
let(:import) { Import.create(account: account, type: 'following', data: csv) }
it 'follows the listed accounts, including boosts' do
subject.call(import)
@@ -136,6 +139,7 @@ RSpec.describe ImportService, type: :service do
describe 'when no accounts are followed' do
let(:import) { Import.create(account: account, type: 'following', data: csv) }
it 'follows the listed accounts, respecting boosts' do
subject.call(import)
expect(account.following.count).to eq 1
@@ -178,18 +182,18 @@ RSpec.describe ImportService, type: :service do
context 'utf-8 encoded domains' do
subject { ImportService.new }
let!(:nare) { Fabricate(:account, username: 'nare', domain: 'թութ.հայ', locked: false, protocol: :activitypub, inbox_url: 'https://թութ.հայ/inbox') }
let!(:nare) { Fabricate(:account, username: 'nare', domain: 'թութ.հայ', locked: false, protocol: :activitypub, inbox_url: 'https://թութ.հայ/inbox') }
# Make sure to not actually go to the remote server
before do
stub_request(:post, "https://թութ.հայ/inbox").to_return(status: 200)
stub_request(:post, 'https://թութ.հայ/inbox').to_return(status: 200)
end
let(:csv) { attachment_fixture('utf8-followers.txt') }
let(:import) { Import.create(account: account, type: 'following', data: csv) }
it 'follows the listed account' do
expect(account.follow_requests.count).to eq 0
expect(account.follow_requests.count).to eq 0
subject.call(import)
expect(account.follow_requests.count).to eq 1
end
@@ -224,6 +228,7 @@ RSpec.describe ImportService, type: :service do
describe 'when no bookmarks are set' do
let(:import) { Import.create(account: account, type: 'bookmarks', data: csv) }
it 'adds the toots the user has access to to bookmarks' do
local_status = Fabricate(:status, account: local_account, uri: 'https://local.com/users/foo/statuses/42', id: 42, local: true)
subject.call(import)

View File

@@ -5,7 +5,7 @@ RSpec.describe PostStatusService, type: :service do
it 'creates a new status' do
account = Fabricate(:account)
text = "test status update"
text = 'test status update'
status = subject.call(account, text: text)
@@ -16,7 +16,7 @@ RSpec.describe PostStatusService, type: :service do
it 'creates a new response status' do
in_reply_to_status = Fabricate(:status)
account = Fabricate(:account)
text = "test status update"
text = 'test status update'
status = subject.call(account, text: text, thread: in_reply_to_status)
@@ -58,7 +58,7 @@ RSpec.describe PostStatusService, type: :service do
boosted_status = Fabricate(:status)
in_reply_to_status = Fabricate(:status, reblog: boosted_status)
account = Fabricate(:account)
text = "test status update"
text = 'test status update'
status = subject.call(account, text: text, thread: in_reply_to_status)
@@ -75,7 +75,7 @@ RSpec.describe PostStatusService, type: :service do
end
it 'creates a status with spoiler text' do
spoiler_text = "spoiler text"
spoiler_text = 'spoiler text'
status = create_status_with_options(spoiler_text: spoiler_text)
@@ -101,14 +101,14 @@ RSpec.describe PostStatusService, type: :service do
status = create_status_with_options(visibility: :private)
expect(status).to be_persisted
expect(status.visibility).to eq "private"
expect(status.visibility).to eq 'private'
end
it 'creates a status with limited visibility for silenced users' do
status = subject.call(Fabricate(:account, silenced: true), text: 'test', visibility: :public)
expect(status).to be_persisted
expect(status.visibility).to eq "unlisted"
expect(status.visibility).to eq 'unlisted'
end
it 'creates a status for the given application' do
@@ -135,7 +135,7 @@ RSpec.describe PostStatusService, type: :service do
allow(ProcessMentionsService).to receive(:new).and_return(mention_service)
account = Fabricate(:account)
status = subject.call(account, text: "test status update")
status = subject.call(account, text: 'test status update')
expect(ProcessMentionsService).to have_received(:new)
expect(mention_service).to have_received(:call).with(status, save_records: false)
@@ -148,7 +148,7 @@ RSpec.describe PostStatusService, type: :service do
expect do
subject.call(account, text: '@alice hm, @bob is really annoying lately', allowed_mentions: [mentioned_account.id])
end.to raise_error(an_instance_of(PostStatusService::UnexpectedMentionsError).and having_attributes(accounts: [unexpected_mentioned_account]))
end.to raise_error(an_instance_of(PostStatusService::UnexpectedMentionsError).and(having_attributes(accounts: [unexpected_mentioned_account])))
end
it 'processes duplicate mentions correctly' do
@@ -166,7 +166,7 @@ RSpec.describe PostStatusService, type: :service do
allow(ProcessHashtagsService).to receive(:new).and_return(hashtags_service)
account = Fabricate(:account)
status = subject.call(account, text: "test status update")
status = subject.call(account, text: 'test status update')
expect(ProcessHashtagsService).to have_received(:new)
expect(hashtags_service).to have_received(:call).with(status)
@@ -178,7 +178,7 @@ RSpec.describe PostStatusService, type: :service do
account = Fabricate(:account)
status = subject.call(account, text: "test status update")
status = subject.call(account, text: 'test status update')
expect(DistributionWorker).to have_received(:perform_async).with(status.id)
expect(ActivityPub::DistributionWorker).to have_received(:perform_async).with(status.id)
@@ -188,7 +188,7 @@ RSpec.describe PostStatusService, type: :service do
allow(LinkCrawlWorker).to receive(:perform_async)
account = Fabricate(:account)
status = subject.call(account, text: "test status update")
status = subject.call(account, text: 'test status update')
expect(LinkCrawlWorker).to have_received(:perform_async).with(status.id)
end
@@ -199,8 +199,8 @@ RSpec.describe PostStatusService, type: :service do
status = subject.call(
account,
text: "test status update",
media_ids: [media.id],
text: 'test status update',
media_ids: [media.id]
)
expect(media.reload.status).to eq status
@@ -212,8 +212,8 @@ RSpec.describe PostStatusService, type: :service do
status = subject.call(
account,
text: "test status update",
media_ids: [media.id],
text: 'test status update',
media_ids: [media.id]
)
expect(media.reload.status).to eq nil
@@ -225,18 +225,18 @@ RSpec.describe PostStatusService, type: :service do
expect do
subject.call(
account,
text: "test status update",
text: 'test status update',
media_ids: [
Fabricate(:media_attachment, account: account),
Fabricate(:media_attachment, account: account),
Fabricate(:media_attachment, account: account),
Fabricate(:media_attachment, account: account),
Fabricate(:media_attachment, account: account),
].map(&:id),
].map(&:id)
)
end.to raise_error(
Mastodon::ValidationError,
I18n.t('media_attachments.validations.too_many'),
I18n.t('media_attachments.validations.too_many')
)
end
@@ -250,15 +250,15 @@ RSpec.describe PostStatusService, type: :service do
expect do
subject.call(
account,
text: "test status update",
text: 'test status update',
media_ids: [
video,
image,
].map(&:id),
].map(&:id)
)
end.to raise_error(
Mastodon::ValidationError,
I18n.t('media_attachments.validations.images_and_video'),
I18n.t('media_attachments.validations.images_and_video')
)
end

View File

@@ -7,6 +7,7 @@ RSpec.describe PrecomputeFeedService, type: :service do
describe 'call' do
let(:account) { Fabricate(:account) }
it 'fills a user timeline with statuses' do
account = Fabricate(:account)
status = Fabricate(:status, account: account)

View File

@@ -62,7 +62,7 @@ RSpec.describe ProcessMentionsService, type: :service do
context 'with an IDN domain' do
let!(:remote_user) { Fabricate(:account, username: 'sneak', protocol: :activitypub, domain: 'xn--hresiar-mxa.ch', inbox_url: 'http://example.com/inbox') }
let!(:status) { Fabricate(:status, account: account, text: "Hello @sneak@hæresiar.ch") }
let!(:status) { Fabricate(:status, account: account, text: 'Hello @sneak@hæresiar.ch') }
before do
subject.call(status)
@@ -75,7 +75,7 @@ RSpec.describe ProcessMentionsService, type: :service do
context 'with an IDN TLD' do
let!(:remote_user) { Fabricate(:account, username: 'foo', protocol: :activitypub, domain: 'xn--y9a3aq.xn--y9a3aq', inbox_url: 'http://example.com/inbox') }
let!(:status) { Fabricate(:status, account: account, text: "Hello @foo@հայ.հայ") }
let!(:status) { Fabricate(:status, account: account, text: 'Hello @foo@հայ.հայ') }
before do
subject.call(status)
@@ -91,8 +91,8 @@ RSpec.describe ProcessMentionsService, type: :service do
let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox', last_webfingered_at: nil) }
before do
stub_request(:get, "https://example.com/.well-known/host-meta").to_return(status: 404)
stub_request(:get, "https://example.com/.well-known/webfinger?resource=acct:remote_user@example.com").to_return(status: 500)
stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(status: 404)
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:remote_user@example.com').to_return(status: 500)
subject.call(status)
end

View File

@@ -7,7 +7,7 @@ RSpec.describe RemoveFromFollowersService, type: :service do
describe 'local' do
let(:sender) { Fabricate(:account, username: 'alice') }
before do
Follow.create(account: sender, target_account: bob)
subject.call(bob, sender)

View File

@@ -37,29 +37,29 @@ RSpec.describe RemoveStatusService, type: :service do
it 'sends Delete activity to followers' do
subject.call(@status)
expect(a_request(:post, 'http://example.com/inbox').with(
body: hash_including({
'type' => 'Delete',
'object' => {
'type' => 'Tombstone',
'id' => ActivityPub::TagManager.instance.uri_for(@status),
'atomUri' => OStatus::TagManager.instance.uri_for(@status),
},
})
)).to have_been_made.once
body: hash_including({
'type' => 'Delete',
'object' => {
'type' => 'Tombstone',
'id' => ActivityPub::TagManager.instance.uri_for(@status),
'atomUri' => OStatus::TagManager.instance.uri_for(@status),
},
})
)).to have_been_made.once
end
it 'sends Delete activity to rebloggers' do
subject.call(@status)
expect(a_request(:post, 'http://example2.com/inbox').with(
body: hash_including({
'type' => 'Delete',
'object' => {
'type' => 'Tombstone',
'id' => ActivityPub::TagManager.instance.uri_for(@status),
'atomUri' => OStatus::TagManager.instance.uri_for(@status),
},
})
)).to have_been_made.once
body: hash_including({
'type' => 'Delete',
'object' => {
'type' => 'Tombstone',
'id' => ActivityPub::TagManager.instance.uri_for(@status),
'atomUri' => OStatus::TagManager.instance.uri_for(@status),
},
})
)).to have_been_made.once
end
it 'remove status from notifications' do
@@ -78,14 +78,14 @@ RSpec.describe RemoveStatusService, type: :service do
it 'sends Undo activity to followers' do
subject.call(@status)
expect(a_request(:post, 'http://example.com/inbox').with(
body: hash_including({
'type' => 'Undo',
'object' => hash_including({
'type' => 'Announce',
'object' => ActivityPub::TagManager.instance.uri_for(@original_status),
}),
})
)).to have_been_made.once
body: hash_including({
'type' => 'Undo',
'object' => hash_including({
'type' => 'Announce',
'object' => ActivityPub::TagManager.instance.uri_for(@original_status),
}),
})
)).to have_been_made.once
end
end
@@ -98,14 +98,14 @@ RSpec.describe RemoveStatusService, type: :service do
it 'sends Undo activity to followers' do
subject.call(@status)
expect(a_request(:post, 'http://example.com/inbox').with(
body: hash_including({
'type' => 'Undo',
'object' => hash_including({
'type' => 'Announce',
'object' => ActivityPub::TagManager.instance.uri_for(@original_status),
}),
})
)).to have_been_made.once
body: hash_including({
'type' => 'Undo',
'object' => hash_including({
'type' => 'Announce',
'object' => ActivityPub::TagManager.instance.uri_for(@original_status),
}),
})
)).to have_been_made.once
end
end
end

View File

@@ -4,11 +4,11 @@ RSpec.describe ResolveAccountService, type: :service do
subject { described_class.new }
before do
stub_request(:get, "https://example.com/.well-known/host-meta").to_return(status: 404)
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
stub_request(:get, "https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com").to_return(request_fixture('activitypub-webfinger.txt'))
stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor.txt'))
stub_request(:get, "https://ap.example.com/users/foo.atom").to_return(request_fixture('activitypub-feed.txt'))
stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(status: 404)
stub_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png').to_return(request_fixture('avatar.txt'))
stub_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com').to_return(request_fixture('activitypub-webfinger.txt'))
stub_request(:get, 'https://ap.example.com/users/foo').to_return(request_fixture('activitypub-actor.txt'))
stub_request(:get, 'https://ap.example.com/users/foo.atom').to_return(request_fixture('activitypub-feed.txt'))
stub_request(:get, %r{https://ap.example.com/users/foo/\w+}).to_return(status: 404)
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:hoge@example.com').to_return(status: 410)
end
@@ -56,8 +56,8 @@ RSpec.describe ResolveAccountService, type: :service do
context 'when there is an LRDD endpoint but no resolvable account' do
before do
stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:catsrgr8@quitter.no").to_return(status: 404)
stub_request(:get, 'https://quitter.no/.well-known/host-meta').to_return(request_fixture('.host-meta.txt'))
stub_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:catsrgr8@quitter.no').to_return(status: 404)
end
it 'returns nil' do
@@ -67,7 +67,7 @@ RSpec.describe ResolveAccountService, type: :service do
context 'when there is no LRDD endpoint nor resolvable account' do
before do
stub_request(:get, "https://example.com/.well-known/webfinger?resource=acct:catsrgr8@example.com").to_return(status: 404)
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:catsrgr8@example.com').to_return(status: 404)
end
it 'returns nil' do
@@ -153,7 +153,7 @@ RSpec.describe ResolveAccountService, type: :service do
context 'with multiple types' do
before do
stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor-individual.txt'))
stub_request(:get, 'https://ap.example.com/users/foo').to_return(request_fixture('activitypub-actor-individual.txt'))
end
it 'returns new remote account' do
@@ -190,7 +190,7 @@ RSpec.describe ResolveAccountService, type: :service do
context 'with an already-known acct: URI changing ActivityPub id' do
let!(:old_account) { Fabricate(:account, username: 'foo', domain: 'ap.example.com', uri: 'https://old.example.com/users/foo', last_webfingered_at: nil) }
let!(:status) { Fabricate(:status, account: old_account, text: 'foo') }
let!(:status) { Fabricate(:status, account: old_account, text: 'foo') }
it 'returns new remote account' do
account = subject.call('foo@ap.example.com')

View File

@@ -133,7 +133,7 @@ describe ResolveURLService, type: :service do
let!(:status) { Fabricate(:status, account: poster, visibility: :public) }
let(:url) { 'https://link.to/foobar' }
let(:status_url) { ActivityPub::TagManager.instance.url_for(status) }
let(:uri) { ActivityPub::TagManager.instance.uri_for(status) }
let(:uri) { ActivityPub::TagManager.instance.uri_for(status) }
before do
stub_request(:get, url).to_return(status: 302, headers: { 'Location' => status_url })

View File

@@ -83,6 +83,7 @@ describe SearchService, type: :service do
expect(Tag).to have_received(:search_for).with('tag', 10, 0, exclude_unreviewed: nil)
expect(results).to eq empty_results.merge(hashtags: [tag])
end
it 'does not include tag when starts with @ character' do
query = '@username'
allow(Tag).to receive(:search_for)
@@ -91,6 +92,7 @@ describe SearchService, type: :service do
expect(Tag).not_to have_received(:search_for)
expect(results).to eq empty_results
end
it 'does not include account when starts with # character' do
query = '#tag'
allow(AccountSearchService).to receive(:new)

View File

@@ -111,7 +111,7 @@ RSpec.describe UpdateStatusService, type: :service do
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!(: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) }