Merge remote-tracking branch 'parent/main' into upstream-20250403

This commit is contained in:
KMY 2025-04-03 08:36:36 +09:00
commit 32f5604499
265 changed files with 6227 additions and 3383 deletions

View file

@ -1,52 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Settings::PicturesController do
render_views
let!(:user) { Fabricate(:user) }
before do
sign_in user, scope: :user
end
describe 'DELETE #destroy' do
context 'with invalid picture id' do
it 'returns http bad request' do
delete :destroy, params: { id: 'invalid' }
expect(response).to have_http_status(400)
end
end
context 'with valid picture id' do
context 'when account updates correctly' do
let(:service) { instance_double(UpdateAccountService, call: true) }
before do
allow(UpdateAccountService).to receive(:new).and_return(service)
end
it 'updates the account' do
delete :destroy, params: { id: 'avatar' }
expect(response).to redirect_to(settings_profile_path)
expect(response).to have_http_status(303)
expect(service).to have_received(:call).with(user.account, { 'avatar' => nil, 'avatar_remote_url' => '' })
end
end
context 'when account cannot update' do
let(:service) { instance_double(UpdateAccountService, call: false) }
before do
allow(UpdateAccountService).to receive(:new).and_return(service)
end
it 'redirects to profile' do
delete :destroy, params: { id: 'avatar' }
expect(response).to redirect_to(settings_profile_path)
end
end
end
end
end

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
Fabricator(:fasp_debug_callback, from: 'Fasp::DebugCallback') do
fasp_provider
ip '127.0.0.234'
request_body 'MyText'
end

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
Fabricator(:fasp_provider, from: 'Fasp::Provider') do
name { Faker::App.name }
base_url { Faker::Internet.unique.url }
sign_in_url { Faker::Internet.url }
remote_identifier 'MyString'
provider_public_key_pem "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAh2ldXsaej2MXj0DHdCx7XibSo66uKlrLfJ5J6hte1Gk=\n-----END PUBLIC KEY-----\n"
server_private_key_pem "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEICDjlajhVb8XfzyTchQWKraMKwtQW+r4opoAg7V3kw1Q\n-----END PRIVATE KEY-----\n"
capabilities []
end
Fabricator(:confirmed_fasp, from: :fasp_provider) do
confirmed true
capabilities [
{ id: 'callback', version: '0.1' },
{ id: 'data_sharing', version: '0.1' },
]
end
Fabricator(:debug_fasp, from: :fasp_provider) do
confirmed true
capabilities [
{ id: 'callback', version: '0.1', enabled: true },
]
after_build do |fasp|
# Prevent fabrication from attempting an HTTP call to the provider
def fasp.update_remote_capabilities = true
end
end

View file

@ -28,6 +28,19 @@ RSpec.describe Admin::Trends::StatusesHelper do
end
end
context 'with a remote status that has excessive attributes' do
let(:attr_limit) { Nokogiri::Gumbo::DEFAULT_MAX_ATTRIBUTES * 2 }
let(:html) { "<html><body #{(1..attr_limit).map { |x| "attr-#{x}" }.join(' ')}><p>text</p></body></html>" }
let(:status) { Fabricate.build(:status, uri: 'https://host.example', text: html) }
it 'renders a correct preview text' do
result = helper.one_line_preview(status)
expect(result).to eq ''
end
end
context 'with a status that has empty text' do
let(:status) { Fabricate.build(:status, text: '') }

View file

@ -13,13 +13,28 @@ RSpec.describe AccountReachFinder do
let(:ap_mentioned_example_com) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-3', domain: 'example.com') }
let(:ap_mentioned_example_org) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.org/inbox-4', domain: 'example.org') }
let(:ap_followed_example_com) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-5', domain: 'example.com') }
let(:ap_followed_example_org) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-6', domain: 'example.org') }
let(:ap_requested_example_com) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-7', domain: 'example.com') }
let(:ap_requested_example_org) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-8', domain: 'example.org') }
let(:unrelated_account) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/unrelated-inbox', domain: 'example.com') }
let(:old_followed_account) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/old-followed-inbox', domain: 'example.com') }
before do
travel_to(2.months.ago) { account.follow!(old_followed_account) }
ap_follower_example_com.follow!(account)
ap_follower_example_org.follow!(account)
ap_follower_with_shared.follow!(account)
account.follow!(ap_followed_example_com)
account.follow!(ap_followed_example_org)
account.request_follow!(ap_requested_example_com)
account.request_follow!(ap_requested_example_org)
Fabricate(:status, account: account).tap do |status|
status.mentions << Mention.new(account: ap_follower_example_com)
status.mentions << Mention.new(account: ap_mentioned_with_shared)
@ -44,7 +59,10 @@ RSpec.describe AccountReachFinder do
expect(subject)
.to include(*follower_inbox_urls)
.and include(*mentioned_account_inbox_urls)
.and include(*recently_followed_inbox_urls)
.and include(*recently_requested_inbox_urls)
.and not_include(unrelated_account.preferred_inbox_url)
.and not_include(old_followed_account.preferred_inbox_url)
end
def follower_inbox_urls
@ -56,5 +74,15 @@ RSpec.describe AccountReachFinder do
[ap_mentioned_with_shared, ap_mentioned_example_com, ap_mentioned_example_org]
.map(&:preferred_inbox_url)
end
def recently_followed_inbox_urls
[ap_followed_example_com, ap_followed_example_org]
.map(&:preferred_inbox_url)
end
def recently_requested_inbox_urls
[ap_requested_example_com, ap_requested_example_org]
.map(&:preferred_inbox_url)
end
end
end

View file

@ -287,6 +287,23 @@ RSpec.describe ActivityPub::TagManager do
end
end
describe '#uris_to_local_accounts' do
it 'returns the expected local accounts' do
account = Fabricate(:account)
expect(subject.uris_to_local_accounts([subject.uri_for(account), instance_actor_url])).to contain_exactly(account, Account.representative)
end
it 'does not return remote accounts' do
account = Fabricate(:account, uri: 'https://example.com/123', domain: 'example.com')
expect(subject.uris_to_local_accounts([subject.uri_for(account)])).to be_empty
end
it 'does not return an account for a local post' do
status = Fabricate(:status)
expect(subject.uris_to_local_accounts([subject.uri_for(status)])).to be_empty
end
end
describe '#uri_to_resource' do
it 'returns the local account' do
account = Fabricate(:account)

View file

@ -0,0 +1,57 @@
# frozen_string_literal: true
require 'rails_helper'
require 'securerandom'
RSpec.describe Fasp::Request do
include ProviderRequestHelper
subject { described_class.new(provider) }
let(:provider) do
Fabricate(:fasp_provider, base_url: 'https://reqprov.example.com/fasp')
end
shared_examples 'a provider request' do |method|
context 'when the response is signed by the provider' do
before do
stub_provider_request(provider, method:, path: '/test_path')
end
it "performs a signed #{method.to_s.upcase} request relative to the base_path of the fasp" do
subject.send(method, '/test_path')
expect(WebMock).to have_requested(method, 'https://reqprov.example.com/fasp/test_path')
.with(headers: {
'Signature' => /.+/,
'Signature-Input' => /.+/,
})
end
end
context 'when the response is not signed' do
before do
stub_request(method, 'https://reqprov.example.com/fasp/test_path')
.to_return(status: 200)
end
it 'raises an error' do
expect do
subject.send(method, '/test_path')
end.to raise_error(Mastodon::SignatureVerificationError)
end
end
end
describe '#get' do
include_examples 'a provider request', :get
end
describe '#post' do
include_examples 'a provider request', :post
end
describe '#delete' do
include_examples 'a provider request', :delete
end
end

View file

@ -0,0 +1,209 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Fasp::Provider do
include ProviderRequestHelper
describe '#capabilities' do
subject { described_class.new(confirmed: true, capabilities:) }
let(:capabilities) do
[
{ 'id' => 'one', 'enabled' => false },
{ 'id' => 'two' },
]
end
it 'returns an array of `Fasp::Capability` objects' do
expect(subject.capabilities).to all(be_a(Fasp::Capability))
end
end
describe '#capabilities_attributes=' do
subject { described_class.new(confirmed: true) }
let(:capabilities_params) do
{
'0' => { 'id' => 'one', 'enabled' => '1' },
'1' => { 'id' => 'two', 'enabled' => '0' },
'2' => { 'id' => 'three' },
}
end
it 'sets capabilities from nested form style hash' do
subject.capabilities_attributes = capabilities_params
expect(subject).to be_capability('one')
expect(subject).to be_capability('two')
expect(subject).to be_capability('three')
expect(subject).to be_capability_enabled('one')
expect(subject).to_not be_capability_enabled('two')
expect(subject).to_not be_capability_enabled('three')
end
end
describe '#capability?' do
subject { described_class.new(confirmed:, capabilities:) }
let(:capabilities) do
[
{ 'id' => 'one', 'enabled' => false },
{ 'id' => 'two', 'enabled' => true },
]
end
context 'when the provider is not confirmed' do
let(:confirmed) { false }
it 'always returns false' do
expect(subject.capability?('one')).to be false
expect(subject.capability?('two')).to be false
end
end
context 'when the provider is confirmed' do
let(:confirmed) { true }
it 'returns true for available and false for missing capabilities' do
expect(subject.capability?('one')).to be true
expect(subject.capability?('two')).to be true
expect(subject.capability?('three')).to be false
end
end
end
describe '#capability_enabled?' do
subject { described_class.new(confirmed:, capabilities:) }
let(:capabilities) do
[
{ 'id' => 'one', 'enabled' => false },
{ 'id' => 'two', 'enabled' => true },
]
end
context 'when the provider is not confirmed' do
let(:confirmed) { false }
it 'always returns false' do
expect(subject).to_not be_capability_enabled('one')
expect(subject).to_not be_capability_enabled('two')
end
end
context 'when the provider is confirmed' do
let(:confirmed) { true }
it 'returns true for enabled and false for disabled or missing capabilities' do
expect(subject).to_not be_capability_enabled('one')
expect(subject).to be_capability_enabled('two')
expect(subject).to_not be_capability_enabled('three')
end
end
end
describe '#server_private_key' do
subject { Fabricate(:fasp_provider) }
it 'returns an OpenSSL::PKey::PKey' do
expect(subject.server_private_key).to be_a OpenSSL::PKey::PKey
end
end
describe '#server_public_key_base64' do
subject { Fabricate(:fasp_provider) }
it 'returns the server public key base64 encoded' do
expect(subject.server_public_key_base64).to eq 'T2RHkakkqAOWEMRYv9OY7LGsuIcAdmBlxuXOKax6sjw='
end
end
describe '#provider_public_key_base64=' do
subject { Fabricate(:fasp_provider) }
it 'allows setting the provider public key from a base64 encoded raw key' do
subject.provider_public_key_base64 = '9qgjOfWRhozWc9dwx5JmbshizZ7TyPBhYk9+b5tE3e4='
expect(subject.provider_public_key_pem).to eq "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA9qgjOfWRhozWc9dwx5JmbshizZ7TyPBhYk9+b5tE3e4=\n-----END PUBLIC KEY-----\n"
end
end
describe '#provider_public_key' do
subject { Fabricate(:fasp_provider) }
it 'returns an OpenSSL::PKey::PKey' do
expect(subject.provider_public_key).to be_a OpenSSL::PKey::PKey
end
end
describe '#provider_public_key_raw' do
subject { Fabricate(:fasp_provider) }
it 'returns a string comprised of raw bytes' do
expect(subject.provider_public_key_raw).to be_a String
expect(subject.provider_public_key_raw.encoding).to eq Encoding::BINARY
end
end
describe '#provider_public_key_fingerprint' do
subject { Fabricate(:fasp_provider) }
it 'returns a base64 encoded sha256 hash of the public key' do
expect(subject.provider_public_key_fingerprint).to eq '/AmW9EMlVq4o+Qcu9lNfTE8Ss/v9+evMPtyj2R437qE='
end
end
describe '#url' do
subject { Fabricate(:fasp_provider, base_url: 'https://myprovider.example.com/fasp_base/') }
it 'returns a full URL for a given path' do
url = subject.url('/test_path')
expect(url).to eq 'https://myprovider.example.com/fasp_base/test_path'
end
end
describe '#update_info!' do
subject { Fabricate(:fasp_provider, base_url: 'https://myprov.example.com/fasp/') }
before do
stub_provider_request(subject,
path: '/provider_info',
response_body: {
capabilities: [
{ id: 'debug', version: '0.1' },
],
contactEmail: 'newcontact@example.com',
fediverseAccount: '@newfedi@social.example.com',
privacyPolicy: 'https::///example.com/privacy',
signInUrl: 'https://myprov.example.com/sign_in',
})
end
context 'when setting confirm to `true`' do
it 'updates the provider and marks it as `confirmed`' do
subject.update_info!(confirm: true)
expect(subject.contact_email).to eq 'newcontact@example.com'
expect(subject.fediverse_account).to eq '@newfedi@social.example.com'
expect(subject.privacy_policy).to eq 'https::///example.com/privacy'
expect(subject.sign_in_url).to eq 'https://myprov.example.com/sign_in'
expect(subject).to be_confirmed
expect(subject).to be_persisted
end
end
context 'when setting confirm to `false`' do
it 'updates the provider but does not mark it as `confirmed`' do
subject.update_info!
expect(subject.contact_email).to eq 'newcontact@example.com'
expect(subject.fediverse_account).to eq '@newfedi@social.example.com'
expect(subject.privacy_policy).to eq 'https::///example.com/privacy'
expect(subject.sign_in_url).to eq 'https://myprov.example.com/sign_in'
expect(subject).to_not be_confirmed
expect(subject).to be_persisted
end
end
end
end

View file

@ -0,0 +1,34 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Admin::Fasp::ProviderPolicy, type: :policy do
subject { described_class }
let(:admin) { Fabricate(:admin_user).account }
let(:user) { Fabricate(:account) }
shared_examples 'admin only' do |target|
let(:provider) { target.is_a?(Symbol) ? Fabricate(target) : target }
context 'with an admin' do
it 'permits' do
expect(subject).to permit(admin, provider)
end
end
context 'with a non-admin' do
it 'denies' do
expect(subject).to_not permit(user, provider)
end
end
end
permissions :index?, :create? do
include_examples 'admin only', Fasp::Provider
end
permissions :show?, :create?, :update?, :destroy? do
include_examples 'admin only', :fasp_provider
end
end

View file

@ -0,0 +1,28 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Api::Fasp::Debug::V0::Callback::Responses', feature: :fasp do
include ProviderRequestHelper
describe 'POST /api/fasp/debug/v0/callback/responses' do
let(:provider) { Fabricate(:debug_fasp) }
it 'create a record of the callback' do
payload = { test: 'call' }
headers = request_authentication_headers(provider,
url: api_fasp_debug_v0_callback_responses_url,
method: :post,
body: payload)
expect do
post api_fasp_debug_v0_callback_responses_path, headers:, params: payload, as: :json
end.to change(Fasp::DebugCallback, :count).by(1)
expect(response).to have_http_status(201)
debug_callback = Fasp::DebugCallback.last
expect(debug_callback.fasp_provider).to eq provider
expect(debug_callback.request_body).to eq '{"test":"call"}'
end
end
end

View file

@ -0,0 +1,42 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Api::Fasp::Registrations', feature: :fasp do
describe 'POST /api/fasp/registration' do
subject do
post api_fasp_registration_path, params:
end
context 'when given valid data' do
let(:params) do
{
name: 'Test Provider',
baseUrl: 'https://newprovider.example.com/fasp',
serverId: '123',
publicKey: '9qgjOfWRhozWc9dwx5JmbshizZ7TyPBhYk9+b5tE3e4=',
}
end
it 'creates a new provider' do
expect { subject }.to change(Fasp::Provider, :count).by(1)
expect(response).to have_http_status 200
end
end
context 'when given invalid data' do
let(:params) do
{
name: 'incomplete',
}
end
it 'does not create a provider and returns an error code' do
expect { subject }.to_not change(Fasp::Provider, :count)
expect(response).to have_http_status 422
end
end
end
end

View file

@ -0,0 +1,55 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Settings Pictures' do
let!(:user) { Fabricate(:user) }
before { sign_in user }
describe 'DELETE /settings/profile/pictures/:id' do
context 'with invalid picture id' do
it 'returns http bad request' do
delete settings_profile_picture_path(id: 'invalid')
expect(response)
.to have_http_status(400)
end
end
context 'with valid picture id' do
before { stub_service }
context 'when account updates correctly' do
let(:service) { instance_double(UpdateAccountService, call: true) }
it 'updates the account' do
delete settings_profile_picture_path(id: 'avatar')
expect(response)
.to redirect_to(settings_profile_path)
.and have_http_status(303)
expect(service)
.to have_received(:call).with(user.account, { 'avatar' => nil, 'avatar_remote_url' => '' })
end
end
context 'when account cannot update' do
let(:service) { instance_double(UpdateAccountService, call: false) }
it 'redirects to profile' do
delete settings_profile_picture_path(id: 'avatar')
expect(response)
.to redirect_to(settings_profile_path)
end
end
def stub_service
allow(UpdateAccountService)
.to receive(:new)
.and_return(service)
end
end
end
end

View file

@ -0,0 +1,72 @@
# frozen_string_literal: true
module ProviderRequestHelper
private
def stub_provider_request(provider, path: '/', method: :get, response_status: 200, response_body: '')
response_body = encode_body(response_body)
response_headers = {
'content-type' => 'application/json',
}.merge(response_authentication_headers(provider, response_status, response_body))
stub_request(method, provider.url(path))
.to_return do |_request|
{
status: response_status,
body: response_body,
headers: response_headers,
}
end
end
def request_authentication_headers(provider, url: root_url, method: :get, body: '')
body = encode_body(body)
headers = {}
headers['content-digest'] = content_digest(body)
request = Linzer.new_request(method, url, {}, headers)
key = private_key_for(provider)
signature = sign(request, key, %w(@method @target-uri content-digest))
headers.merge(signature.to_h)
end
def response_authentication_headers(provider, status, body)
headers = {}
headers['content-digest'] = content_digest(body)
response = Linzer.new_response(body, status, headers)
key = private_key_for(provider)
signature = sign(response, key, %w(@status content-digest))
headers.merge(signature.to_h)
end
def private_key_for(provider)
@cached_provider_keys ||= {}
@cached_provider_keys[provider] ||=
begin
key = OpenSSL::PKey.generate_key('ed25519')
provider.update!(provider_public_key_pem: key.public_to_pem)
key
end
{
id: provider.id.to_s,
private_key: @cached_provider_keys[provider].private_to_pem,
}
end
def sign(request_or_response, key, components)
message = Linzer::Message.new(request_or_response)
linzer_key = Linzer.new_ed25519_key(key[:private_key], key[:id])
Linzer.sign(linzer_key, message, components)
end
def encode_body(body)
return body if body.nil? || body.is_a?(String)
encoder = ActionDispatch::RequestEncoder.encoder(:json)
encoder.encode_params(body)
end
def content_digest(content)
"sha-256=:#{OpenSSL::Digest.base64digest('sha256', content)}:"
end
end

View file

@ -24,11 +24,6 @@ RSpec.describe 'Account notes', :inline_jobs, :js, :streaming do
# The easiest way is to send ctrl+enter ourselves
find_field(class: 'account__header__account-note__content').send_keys [:control, :enter]
within('.account__header__account-note .inline-alert') do
expect(page)
.to have_content('SAVED')
end
expect(page)
.to have_css('.account__header__account-note__content', text: note_text)

View file

@ -0,0 +1,29 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Debug FASP Callback Management', feature: :fasp do
before { sign_in Fabricate(:admin_user) }
describe 'Viewing and deleting callbacks' do
let(:provider) { Fabricate(:fasp_provider, name: 'debug prov') }
before do
Fabricate(:fasp_debug_callback, fasp_provider: provider, request_body: 'called back')
end
it 'displays callbacks and allows to delete them' do
visit admin_fasp_debug_callbacks_path
expect(page).to have_css('h2', text: I18n.t('admin.fasp.debug.callbacks.title'))
expect(page).to have_css('td', text: 'debug prov')
expect(page).to have_css('code', text: 'called back')
expect do
click_on I18n.t('admin.fasp.debug.callbacks.delete')
expect(page).to have_css('h2', text: I18n.t('admin.fasp.debug.callbacks.title'))
end.to change(Fasp::DebugCallback, :count).by(-1)
end
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'FASP Debug Calls', feature: :fasp do
include ProviderRequestHelper
before { sign_in Fabricate(:admin_user) }
describe 'Triggering a FASP debug call' do
let!(:provider) { Fabricate(:debug_fasp) }
let!(:debug_call) do
stub_provider_request(provider,
method: :post,
path: '/debug/v0/callback/logs',
response_status: 201)
end
it 'makes a debug call to the provider' do
visit admin_fasp_providers_path
expect(page).to have_css('h2', text: I18n.t('admin.fasp.providers.title'))
expect(page).to have_css('td', text: provider.name)
within 'table#providers' do
click_on I18n.t('admin.fasp.providers.callback')
end
expect(page).to have_css('h2', text: I18n.t('admin.fasp.providers.title'))
expect(debug_call).to have_been_requested
end
end
end

View file

@ -0,0 +1,81 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'FASP Management', feature: :fasp do
include ProviderRequestHelper
before { sign_in Fabricate(:admin_user) }
describe 'Managing capabilities' do
let!(:provider) { Fabricate(:confirmed_fasp) }
let!(:enable_call) do
stub_provider_request(provider,
method: :post,
path: '/capabilities/callback/0/activation')
end
let!(:disable_call) do
stub_provider_request(provider,
method: :delete,
path: '/capabilities/callback/0/activation')
end
before do
# We currently err on the side of caution and prefer to send
# a "disable capability" call too often over risking to miss
# one. So the following call _can_ happen here, and if it does
# that is fine, but it has no bearing on the behavior that is
# being tested.
stub_provider_request(provider,
method: :delete,
path: '/capabilities/data_sharing/0/activation')
end
it 'allows enabling and disabling of capabilities' do
visit admin_fasp_providers_path
expect(page).to have_css('h2', text: I18n.t('admin.fasp.providers.title'))
expect(page).to have_css('td', text: provider.name)
click_on I18n.t('admin.fasp.providers.edit')
expect(page).to have_css('h2', text: I18n.t('admin.fasp.providers.edit'))
check 'callback'
click_on I18n.t('admin.fasp.providers.save')
expect(page).to have_css('h2', text: I18n.t('admin.fasp.providers.title'))
expect(provider.reload).to be_capability_enabled('callback')
expect(enable_call).to have_been_requested
click_on I18n.t('admin.fasp.providers.edit')
expect(page).to have_css('h2', text: I18n.t('admin.fasp.providers.edit'))
uncheck 'callback'
click_on I18n.t('admin.fasp.providers.save')
expect(page).to have_css('h2', text: I18n.t('admin.fasp.providers.title'))
expect(provider.reload).to_not be_capability_enabled('callback')
expect(disable_call).to have_been_requested
end
end
describe 'Removing a provider' do
let!(:provider) { Fabricate(:fasp_provider) }
it 'allows to completely remove a provider' do
visit admin_fasp_providers_path
expect(page).to have_css('h2', text: I18n.t('admin.fasp.providers.title'))
expect(page).to have_css('td', text: provider.name)
click_on I18n.t('admin.fasp.providers.delete')
expect(page).to have_css('h2', text: I18n.t('admin.fasp.providers.title'))
expect(page).to have_no_css('td', text: provider.name)
end
end
end

View file

@ -0,0 +1,39 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'FASP registration', feature: :fasp do
include ProviderRequestHelper
before { sign_in Fabricate(:admin_user) }
describe 'Confirming an unconfirmed FASP' do
let(:provider) { Fabricate(:fasp_provider, confirmed: false) }
before do
stub_provider_request(provider,
path: '/provider_info',
response_body: {
capabilities: [
{ id: 'debug', version: '0.1' },
],
contactEmail: 'newcontact@example.com',
fediverseAccount: '@newfedi@social.example.com',
privacyPolicy: 'https::///example.com/privacy',
signInUrl: 'https://myprov.example.com/sign_in',
})
end
it 'displays key fingerprint and updates the provider on confirmation' do
visit new_admin_fasp_provider_registration_path(provider)
expect(page).to have_css('code', text: provider.provider_public_key_fingerprint)
click_on I18n.t('admin.fasp.providers.registrations.confirm')
expect(page).to have_css('h2', text: I18n.t('admin.fasp.providers.edit'))
expect(provider.reload).to be_confirmed
end
end
end