test: add tests for folder browser APIs and system credentials toggle

Added tests for POST /api/dropbox/list-folders (7 tests) and
POST /api/onedrive/list-folders (7 tests) covering success, subfolder
navigation, empty directories, auth errors, API errors, path
normalization, and alphabetical sorting.

Added view tests for system credentials toggle visibility in Dropbox
setup wizard.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-20 13:40:51 +00:00
parent a8423064ec
commit 1e1e6e6280
6 changed files with 386 additions and 13 deletions
+1 -1
View File
@@ -270,7 +270,7 @@ async def list_onedrive_folders(
raw_parent = item["parentReference"]["path"]
prefix = "/drive/root:"
if raw_parent.startswith(prefix):
parent_path = raw_parent[len(prefix):]
parent_path = raw_parent[len(prefix) :]
elif raw_parent == "/drive/root":
parent_path = ""
+3 -9
View File
@@ -47,9 +47,7 @@ async def google_drive_setup_page(
folder_id = cfg.get("folder_id", "")
# Provide system-wide OAuth credentials when available so users can
# authorize without registering their own Google Cloud app.
has_system_credentials = bool(
settings.google_drive_client_id and settings.google_drive_client_secret
)
has_system_credentials = bool(settings.google_drive_client_id and settings.google_drive_client_secret)
return templates.TemplateResponse(
"google_drive.html",
{
@@ -65,9 +63,7 @@ async def google_drive_setup_page(
"sa_configured": False,
"has_system_credentials": has_system_credentials,
"client_id": bool(settings.google_drive_client_id) if has_system_credentials else False,
"client_id_value": (
settings.google_drive_client_id or "" if has_system_credentials else ""
),
"client_id_value": (settings.google_drive_client_id or "" if has_system_credentials else ""),
"client_secret": bool(settings.google_drive_client_secret) if has_system_credentials else False,
"client_secret_value": (
settings.google_drive_client_secret or "" if has_system_credentials else ""
@@ -100,9 +96,7 @@ async def google_drive_setup_page(
"use_oauth": use_oauth,
"oauth_configured": oauth_configured,
"sa_configured": sa_configured,
"has_system_credentials": bool(
settings.google_drive_client_id and settings.google_drive_client_secret
),
"has_system_credentials": bool(settings.google_drive_client_id and settings.google_drive_client_secret),
"client_id": bool(settings.google_drive_client_id),
"client_id_value": settings.google_drive_client_id or "",
"client_secret": bool(settings.google_drive_client_secret),
+1 -3
View File
@@ -61,9 +61,7 @@ async def onedrive_setup_page(
"client_id": bool(settings.onedrive_client_id) if has_system_credentials else False,
"client_id_value": settings.onedrive_client_id or "" if has_system_credentials else "",
"client_secret": bool(settings.onedrive_client_secret) if has_system_credentials else False,
"client_secret_value": (
settings.onedrive_client_secret or "" if has_system_credentials else ""
),
"client_secret_value": (settings.onedrive_client_secret or "" if has_system_credentials else ""),
"tenant_id": settings.onedrive_tenant_id or "common",
"refresh_token": False,
"refresh_token_value": "",
+144
View File
@@ -412,3 +412,147 @@ class TestSaveDropboxSettings:
# .env write is best-effort; endpoint should still succeed via DB write
assert response.status_code == 200
assert response.json()["status"] == "success"
@pytest.mark.unit
class TestListDropboxFolders:
"""Tests for list_dropbox_folders endpoint."""
@patch("app.api.dropbox.requests.post")
def test_list_folders_success(self, mock_post, client):
"""Test successful folder listing at root."""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"entries": [
{".tag": "folder", "name": "Documents", "path_display": "/Documents", "id": "id:1"},
{".tag": "folder", "name": "Photos", "path_display": "/Photos", "id": "id:2"},
{".tag": "file", "name": "readme.txt", "path_display": "/readme.txt", "id": "id:3"},
],
"has_more": False,
}
mock_post.return_value = mock_response
response = client.post(
"/api/dropbox/list-folders",
data={"access_token": "test-token", "path": ""},
)
assert response.status_code == 200
data = response.json()
assert len(data["folders"]) == 2
assert data["folders"][0]["name"] == "Documents"
assert data["folders"][1]["name"] == "Photos"
assert data["path"] == "/"
assert data["has_more"] is False
@patch("app.api.dropbox.requests.post")
def test_list_folders_subfolder(self, mock_post, client):
"""Test listing folders in a subfolder."""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"entries": [
{".tag": "folder", "name": "Invoices", "path_display": "/Documents/Invoices", "id": "id:4"},
],
"has_more": False,
}
mock_post.return_value = mock_response
response = client.post(
"/api/dropbox/list-folders",
data={"access_token": "test-token", "path": "/Documents"},
)
assert response.status_code == 200
data = response.json()
assert len(data["folders"]) == 1
assert data["folders"][0]["path"] == "/Documents/Invoices"
@patch("app.api.dropbox.requests.post")
def test_list_folders_empty(self, mock_post, client):
"""Test listing folders in an empty directory."""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"entries": [], "has_more": False}
mock_post.return_value = mock_response
response = client.post(
"/api/dropbox/list-folders",
data={"access_token": "test-token", "path": "/EmptyFolder"},
)
assert response.status_code == 200
assert len(response.json()["folders"]) == 0
@patch("app.api.dropbox.requests.post")
def test_list_folders_unauthorized(self, mock_post, client):
"""Test listing folders with invalid token returns 401."""
mock_response = Mock()
mock_response.status_code = 401
mock_response.text = "Invalid access token"
mock_post.return_value = mock_response
response = client.post(
"/api/dropbox/list-folders",
data={"access_token": "bad-token", "path": ""},
)
assert response.status_code == 401
@patch("app.api.dropbox.requests.post")
def test_list_folders_api_error(self, mock_post, client):
"""Test listing folders when Dropbox API returns an error."""
mock_response = Mock()
mock_response.status_code = 500
mock_response.text = "Internal server error"
mock_post.return_value = mock_response
response = client.post(
"/api/dropbox/list-folders",
data={"access_token": "test-token", "path": ""},
)
assert response.status_code == 502
@patch("app.api.dropbox.requests.post")
def test_list_folders_root_path_normalization(self, mock_post, client):
"""Test that '/' is normalized to empty string for Dropbox API."""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"entries": [], "has_more": False}
mock_post.return_value = mock_response
response = client.post(
"/api/dropbox/list-folders",
data={"access_token": "test-token", "path": "/"},
)
assert response.status_code == 200
# Check the actual API call used empty string for root
call_args = mock_post.call_args
assert call_args[1]["json"]["path"] == ""
@patch("app.api.dropbox.requests.post")
def test_list_folders_sorted_alphabetically(self, mock_post, client):
"""Test that folders are returned in alphabetical order."""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"entries": [
{".tag": "folder", "name": "Zebra", "path_display": "/Zebra", "id": "id:1"},
{".tag": "folder", "name": "Alpha", "path_display": "/Alpha", "id": "id:2"},
{".tag": "folder", "name": "middle", "path_display": "/middle", "id": "id:3"},
],
"has_more": False,
}
mock_post.return_value = mock_response
response = client.post(
"/api/dropbox/list-folders",
data={"access_token": "test-token", "path": ""},
)
assert response.status_code == 200
names = [f["name"] for f in response.json()["folders"]]
assert names == ["Alpha", "middle", "Zebra"]
+179
View File
@@ -695,3 +695,182 @@ class TestOneDriveIntegration:
# Verify env format is present (exact values may vary)
assert "env_format" in config_data
@pytest.mark.unit
class TestListOneDriveFolders:
"""Tests for list_onedrive_folders endpoint."""
@patch("app.api.onedrive.requests.get")
def test_list_folders_success(self, mock_get, client):
"""Test successful folder listing at root."""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"value": [
{
"name": "Documents",
"id": "id:1",
"folder": {"childCount": 3},
"parentReference": {"path": "/drive/root:"},
},
{
"name": "Pictures",
"id": "id:2",
"folder": {"childCount": 10},
"parentReference": {"path": "/drive/root:"},
},
],
}
mock_get.return_value = mock_response
response = client.post(
"/api/onedrive/list-folders",
data={"access_token": "test-token", "path": ""},
)
assert response.status_code == 200
data = response.json()
assert len(data["folders"]) == 2
assert data["folders"][0]["name"] == "Documents"
assert data["folders"][0]["path"] == "/Documents"
assert data["folders"][1]["name"] == "Pictures"
assert data["path"] == "/"
@patch("app.api.onedrive.requests.get")
def test_list_folders_subfolder(self, mock_get, client):
"""Test listing folders in a subfolder."""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"value": [
{
"name": "Invoices",
"id": "id:3",
"folder": {"childCount": 0},
"parentReference": {"path": "/drive/root:/Documents"},
},
],
}
mock_get.return_value = mock_response
response = client.post(
"/api/onedrive/list-folders",
data={"access_token": "test-token", "path": "Documents"},
)
assert response.status_code == 200
data = response.json()
assert len(data["folders"]) == 1
assert data["folders"][0]["path"] == "/Documents/Invoices"
assert data["path"] == "/Documents"
@patch("app.api.onedrive.requests.get")
def test_list_folders_empty(self, mock_get, client):
"""Test listing folders in an empty directory."""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"value": []}
mock_get.return_value = mock_response
response = client.post(
"/api/onedrive/list-folders",
data={"access_token": "test-token", "path": "EmptyFolder"},
)
assert response.status_code == 200
assert len(response.json()["folders"]) == 0
@patch("app.api.onedrive.requests.get")
def test_list_folders_unauthorized(self, mock_get, client):
"""Test listing folders with invalid token returns 401."""
mock_response = Mock()
mock_response.status_code = 401
mock_response.text = "Invalid access token"
mock_get.return_value = mock_response
response = client.post(
"/api/onedrive/list-folders",
data={"access_token": "bad-token", "path": ""},
)
assert response.status_code == 401
@patch("app.api.onedrive.requests.get")
def test_list_folders_api_error(self, mock_get, client):
"""Test listing folders when Graph API returns an error."""
mock_response = Mock()
mock_response.status_code = 500
mock_response.text = "Internal server error"
mock_get.return_value = mock_response
response = client.post(
"/api/onedrive/list-folders",
data={"access_token": "test-token", "path": ""},
)
assert response.status_code == 502
@patch("app.api.onedrive.requests.get")
def test_list_folders_sorted_alphabetically(self, mock_get, client):
"""Test that folders are returned in alphabetical order."""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"value": [
{
"name": "Zebra",
"id": "id:1",
"folder": {"childCount": 0},
"parentReference": {"path": "/drive/root:"},
},
{
"name": "Alpha",
"id": "id:2",
"folder": {"childCount": 0},
"parentReference": {"path": "/drive/root:"},
},
{
"name": "middle",
"id": "id:3",
"folder": {"childCount": 0},
"parentReference": {"path": "/drive/root:"},
},
],
}
mock_get.return_value = mock_response
response = client.post(
"/api/onedrive/list-folders",
data={"access_token": "test-token", "path": ""},
)
assert response.status_code == 200
names = [f["name"] for f in response.json()["folders"]]
assert names == ["Alpha", "middle", "Zebra"]
@patch("app.api.onedrive.requests.get")
def test_list_folders_root_drive_parent(self, mock_get, client):
"""Test folder path construction when parentReference.path is /drive/root."""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"value": [
{
"name": "TopLevel",
"id": "id:1",
"folder": {"childCount": 0},
"parentReference": {"path": "/drive/root"},
},
],
}
mock_get.return_value = mock_response
response = client.post(
"/api/onedrive/list-folders",
data={"access_token": "test-token", "path": ""},
)
assert response.status_code == 200
data = response.json()
assert data["folders"][0]["path"] == "/TopLevel"
+58
View File
@@ -144,3 +144,61 @@ class TestDropboxViews:
assert response.status_code == 200
assert b"/Documents/Uploads" in response.content
assert b"Back to Integrations" in response.content
def test_dropbox_setup_user_mode_system_credentials_shown(self, client, db_session):
"""Test that system credentials toggle appears when system creds are configured."""
owner_id = "user_sys_creds@example.com"
integration = UserIntegration(
owner_id=owner_id,
direction="DESTINATION",
integration_type="DROPBOX",
name="My Dropbox",
config=json.dumps({"folder": "/test"}),
is_active=True,
)
db_session.add(integration)
db_session.commit()
db_session.refresh(integration)
with (
patch("app.views.dropbox.get_current_owner_id", return_value=owner_id),
patch("app.views.dropbox.settings") as mock_settings,
):
mock_settings.dropbox_app_key = "system-key"
mock_settings.dropbox_app_secret = "system-secret"
mock_settings.dropbox_refresh_token = None
mock_settings.dropbox_folder = None
response = client.get(f"/dropbox-setup?integration_id={integration.id}")
assert response.status_code == 200
assert b"use-system-creds" in response.content
assert b"DocuElevate" in response.content
def test_dropbox_setup_user_mode_no_system_credentials(self, client, db_session):
"""Test that system credentials toggle is hidden when no system creds configured."""
owner_id = "user_no_sys@example.com"
integration = UserIntegration(
owner_id=owner_id,
direction="DESTINATION",
integration_type="DROPBOX",
name="My Dropbox",
config=json.dumps({"folder": "/test"}),
is_active=True,
)
db_session.add(integration)
db_session.commit()
db_session.refresh(integration)
with (
patch("app.views.dropbox.get_current_owner_id", return_value=owner_id),
patch("app.views.dropbox.settings") as mock_settings,
):
mock_settings.dropbox_app_key = None
mock_settings.dropbox_app_secret = None
mock_settings.dropbox_refresh_token = None
mock_settings.dropbox_folder = None
response = client.get(f"/dropbox-setup?integration_id={integration.id}")
assert response.status_code == 200
# When no system credentials, hasSystemCredentials JS var should be false
assert b"hasSystemCredentials = false" in response.content