a10fe11136
Unit Tests / test (push) Successful in 11m24s
Email, calendar, and files no longer appear in the nav or as usable pages unless they are installed. The nav refreshes whenever a service is installed or removed via the new pic-services-changed CustomEvent. Changes: - routes/services.py: add GET /api/services/active endpoint - api.js: add servicesAPI.listActive() - App.jsx: replace hardcoded coreServiceChildren with dynamic state fetched from /api/services/active; SERVICE_META maps ids to nav entry shapes - ServiceNotInstalledBanner.jsx: new component — admin gets catalog link, peer gets "contact admin" message - EmailPage/CalendarPage/FilesPage: show banner when service not installed - ServicesIndex.jsx: remove CoreServiceCard + CORE_SERVICES "Built-in" section; rename Remove → Uninstall; dispatch pic-services-changed on install/uninstall success - MyServices.jsx: conditionally render service cards based on active list; placeholder card when absent; page-level notice when nothing is installed - tests/test_services_active_endpoint.py: 4 new endpoint tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
81 lines
2.1 KiB
Python
81 lines
2.1 KiB
Python
"""
|
|
Tests for GET /api/services/active endpoint.
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / 'api'))
|
|
|
|
from app import app
|
|
|
|
|
|
def _make_registry(active_services):
|
|
reg = MagicMock()
|
|
reg.list_active = MagicMock(return_value=active_services)
|
|
return reg
|
|
|
|
|
|
@pytest.fixture()
|
|
def client():
|
|
app.config['TESTING'] = True
|
|
with app.test_client() as c:
|
|
yield c
|
|
|
|
|
|
def test_active_returns_200(client):
|
|
import app as app_module
|
|
with patch.object(app_module, 'service_registry', _make_registry([])):
|
|
resp = client.get('/api/services/active')
|
|
assert resp.status_code == 200
|
|
|
|
|
|
def test_active_returns_empty_list_when_nothing_installed(client):
|
|
import app as app_module
|
|
with patch.object(app_module, 'service_registry', _make_registry([])):
|
|
resp = client.get('/api/services/active')
|
|
data = json.loads(resp.data)
|
|
assert data == []
|
|
|
|
|
|
def test_active_returns_installed_services(client):
|
|
email_svc = {
|
|
'id': 'email',
|
|
'name': 'Email',
|
|
'subdomain': 'mail',
|
|
'capabilities': {'has_accounts': True},
|
|
'config': {},
|
|
}
|
|
import app as app_module
|
|
with patch.object(app_module, 'service_registry', _make_registry([email_svc])):
|
|
resp = client.get('/api/services/active')
|
|
data = json.loads(resp.data)
|
|
assert isinstance(data, list)
|
|
assert len(data) == 1
|
|
assert data[0]['id'] == 'email'
|
|
assert data[0]['name'] == 'Email'
|
|
|
|
|
|
def test_active_response_shape(client):
|
|
"""Each entry must have id, name, subdomain, and capabilities keys."""
|
|
email_svc = {
|
|
'id': 'email',
|
|
'name': 'Email',
|
|
'subdomain': 'mail',
|
|
'capabilities': {'has_accounts': True},
|
|
'config': {},
|
|
}
|
|
import app as app_module
|
|
with patch.object(app_module, 'service_registry', _make_registry([email_svc])):
|
|
resp = client.get('/api/services/active')
|
|
data = json.loads(resp.data)
|
|
entry = data[0]
|
|
assert 'id' in entry
|
|
assert 'name' in entry
|
|
assert 'subdomain' in entry
|
|
assert 'capabilities' in entry
|