Files
akkounts/spec/features/services/rs_auths_spec.rb
T
raucao a669bf7c9b Add storage dashboard card and per-app details modal
- Rework RsAuthComponent into a card that shows the app, its device, an
  access summary and the permission status
- Group connected apps by app and device, so repeated authorizations for
  the same app and device (e.g. after a browser update) are shown together,
  each with its own revoke action
- Add RsAuthDetailsModalComponent with the full scope list, device,
  connected tokens and permission expiry, plus Launch and Revoke actions
  (built on the existing ModalComponent)
- Add RemoteStorageAuthorization#device_name (parsed from the user agent)
  and #expired?

Part of #254
2026-11-03 11:42:31 +04:00

102 lines
3.3 KiB
Ruby

require 'rails_helper'
RSpec.describe "Storage connected apps", type: :feature do
let(:user) { create :user }
let(:firefox_ua) do
"Mozilla/5.0 (X11; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0"
end
let(:chrome_ua) do
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 " \
"(KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
end
before do
allow_any_instance_of(AppCatalog::WebApp).to receive(:update_metadata).and_return(true)
allow_any_instance_of(RemoteStorageAuthorization).to receive(:remove_token_expiry_job).and_return(nil)
allow_any_instance_of(User).to receive(:ldap_entry).and_return(
uid: user.cn, ou: user.ou, mail: user.email, admin: nil,
services_enabled: ["remotestorage"]
)
login_as user, scope: :user
end
def create_auth(client:, device:, permissions: %w(documents:rw))
user.remote_storage_authorizations.create!(
permissions: permissions,
client_id: client,
redirect_uri: "https://#{client}",
expire_at: 1.month.from_now,
user_agent: device
)
end
context "with a connected app" do
before do
AppCatalog::WebApp.create!(url: "https://notes.example.com", name: "Notes", metadata: {})
end
let!(:auth) do
create_auth(client: "notes.example.com", device: firefox_ua,
permissions: %w(documents:rw photos:r))
end
after { auth.destroy }
it "shows the app, its device and permission status" do
visit apps_services_storage_path
expect(page).to have_content("Notes")
expect(page).to have_content("notes.example.com")
expect(page).to have_content("Firefox on Linux")
expect(page).to have_content("2 folders")
expect(page).to have_content("Expires")
end
it "renders a details modal with scopes and actions" do
visit apps_services_storage_path
expect(page).to have_selector("li", text: "documents (read/write)", visible: false)
expect(page).to have_selector("li", text: "photos (read only)", visible: false)
expect(page).to have_link("Launch app", visible: false)
expect(page).to have_selector("a", text: "Revoke access", visible: false, count: 1)
end
end
context "with duplicates" do
let!(:first) { create_auth(client: "notes.example.com", device: firefox_ua) }
let!(:second) { create_auth(client: "notes.example.com", device: firefox_ua) }
let!(:other) { create_auth(client: "notes.example.com", device: chrome_ua) }
after do
first.destroy
second.destroy
other.destroy
end
it "groups authorizations for the same app and device into one card" do
visit apps_services_storage_path
expect(page).to have_selector(".rs-auth-card", count: 2)
expect(page).to have_content("Firefox on Linux")
expect(page).to have_content("Chrome on macOS")
expect(page).to have_content("Tokens")
end
it "lists every authorization in the group with its own revoke action" do
visit apps_services_storage_path
expect(page).to have_selector("a", text: "Revoke access", visible: false, count: 3)
end
end
context "without connected apps" do
it "shows the empty state" do
visit apps_services_storage_path
expect(page).to have_content("No apps connected")
end
end
end