Add remote browser pages and website sync
Enable managed remote browser custom pages with login autofill and add website sync workflows so external admin surfaces can be handled inside SmartUp. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy import create_engine, text
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from app import database as database_module
|
||||
from app.database import Base, get_db
|
||||
from app.main import app
|
||||
from app.models.custom_page import CustomPage
|
||||
from app.utils.auth import get_current_user
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def db_session():
|
||||
engine = create_engine(
|
||||
"sqlite://",
|
||||
connect_args={"check_same_thread": False},
|
||||
poolclass=StaticPool,
|
||||
)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
db = TestingSessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
Base.metadata.drop_all(bind=engine)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def client(db_session):
|
||||
def override_get_db():
|
||||
yield db_session
|
||||
|
||||
app.dependency_overrides[get_db] = override_get_db
|
||||
app.dependency_overrides[get_current_user] = lambda: object()
|
||||
try:
|
||||
yield TestClient(app)
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
def test_create_page_auto_enables_autofill_when_credentials_are_saved(client):
|
||||
response = client.post("/api/custom-pages", json={
|
||||
"name": "Login page",
|
||||
"url": "https://example.test/login",
|
||||
"access_mode": "remote_browser",
|
||||
"login_username": "alice",
|
||||
"login_password": "secret",
|
||||
})
|
||||
|
||||
assert response.status_code == 201
|
||||
assert response.json()["login_autofill_enabled"] is True
|
||||
assert response.json()["login_password_configured"] is True
|
||||
|
||||
|
||||
def test_create_page_respects_explicit_autofill_disable(client):
|
||||
response = client.post("/api/custom-pages", json={
|
||||
"name": "Login page",
|
||||
"url": "https://example.test/login",
|
||||
"access_mode": "remote_browser",
|
||||
"login_username": "alice",
|
||||
"login_password": "secret",
|
||||
"login_autofill_enabled": False,
|
||||
})
|
||||
|
||||
assert response.status_code == 201
|
||||
assert response.json()["login_autofill_enabled"] is False
|
||||
|
||||
|
||||
def test_update_page_auto_enables_autofill_when_new_password_is_saved(client, db_session):
|
||||
page = CustomPage(
|
||||
name="Login page",
|
||||
url="https://example.test/login",
|
||||
access_mode="remote_browser",
|
||||
login_username="alice",
|
||||
login_password="old-secret",
|
||||
login_autofill_enabled=False,
|
||||
)
|
||||
db_session.add(page)
|
||||
db_session.commit()
|
||||
db_session.refresh(page)
|
||||
|
||||
response = client.put(f"/api/custom-pages/{page.id}", json={
|
||||
"login_username": "alice@example.test",
|
||||
"login_password": "new-secret",
|
||||
})
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["login_autofill_enabled"] is True
|
||||
|
||||
|
||||
def test_update_page_keeps_autofill_disabled_when_existing_password_is_kept(client, db_session):
|
||||
page = CustomPage(
|
||||
name="Login page",
|
||||
url="https://example.test/login",
|
||||
access_mode="remote_browser",
|
||||
login_username="alice",
|
||||
login_password="secret",
|
||||
login_autofill_enabled=False,
|
||||
)
|
||||
db_session.add(page)
|
||||
db_session.commit()
|
||||
db_session.refresh(page)
|
||||
|
||||
response = client.put(f"/api/custom-pages/{page.id}", json={
|
||||
"login_username": "alice@example.test",
|
||||
})
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["login_autofill_enabled"] is False
|
||||
|
||||
|
||||
def test_update_page_respects_explicit_autofill_disable(client, db_session):
|
||||
page = CustomPage(
|
||||
name="Login page",
|
||||
url="https://example.test/login",
|
||||
access_mode="remote_browser",
|
||||
login_username="alice",
|
||||
login_password="secret",
|
||||
login_autofill_enabled=False,
|
||||
)
|
||||
db_session.add(page)
|
||||
db_session.commit()
|
||||
db_session.refresh(page)
|
||||
|
||||
response = client.put(f"/api/custom-pages/{page.id}", json={
|
||||
"login_username": "alice@example.test",
|
||||
"login_autofill_enabled": False,
|
||||
})
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["login_autofill_enabled"] is False
|
||||
|
||||
|
||||
def test_custom_page_migration_backfills_autofill_once(monkeypatch):
|
||||
engine = create_engine(
|
||||
"sqlite://",
|
||||
connect_args={"check_same_thread": False},
|
||||
poolclass=StaticPool,
|
||||
)
|
||||
monkeypatch.setattr(database_module, "engine", engine)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
with engine.begin() as conn:
|
||||
conn.execute(text("ALTER TABLE custom_pages DROP COLUMN login_autofill_backfilled_at"))
|
||||
conn.execute(text(
|
||||
"INSERT INTO custom_pages "
|
||||
"(name, url, icon, sort_order, enabled, use_proxy, access_mode, login_username, login_password, login_autofill_enabled, created_at, updated_at) "
|
||||
"VALUES ('Login page', 'https://example.test/login', 'Link', 0, 1, 0, 'remote_browser', 'alice', 'secret', 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
|
||||
))
|
||||
|
||||
database_module._migrate_custom_pages()
|
||||
with engine.begin() as conn:
|
||||
row = conn.execute(text(
|
||||
"SELECT login_autofill_enabled, login_autofill_backfilled_at FROM custom_pages WHERE name = 'Login page'"
|
||||
)).one()
|
||||
assert row.login_autofill_enabled == 1
|
||||
assert row.login_autofill_backfilled_at is not None
|
||||
conn.execute(text("UPDATE custom_pages SET login_autofill_enabled = 0"))
|
||||
|
||||
database_module._migrate_custom_pages()
|
||||
with engine.begin() as conn:
|
||||
row = conn.execute(text("SELECT login_autofill_enabled FROM custom_pages WHERE name = 'Login page'")).one()
|
||||
assert row.login_autofill_enabled == 0
|
||||
Reference in New Issue
Block a user