* feat(tests): Add reusable workspace fixture Introduces a new `workspace` fixture in `conftest.py` to provide a consistent and reusable setup for tests that require a workspace. * feat(tests): Add tests for project creation (POST) This commit introduces a comprehensive test suite for the project creation API endpoint. The suite covers a wide range of scenarios, including: - Successful creation and verification of side-effects (default states, project members, user properties). - Validation for invalid or missing data (400 Bad Request). - Permission checks for different user roles (e.g., guests are forbidden). - Authentication requirements (401 Unauthorized). - Uniqueness constraints for project names and identifiers (409 Conflict). - Successful creation with all optional fields populated. It leverages the `workspace`, `session_client` and `create_user` fixtures for a consistent test setup. * refactor(tests): Centralize project URL helper into a base class To avoid code duplication in upcoming tests, this commit introduces a `TestProjectBase` class. The `get_project_url` helper method is moved into this shared base class, and the existing `TestProjectAPIPost` class is updated to inherit from it. This ensures the URL generation logic is defined in a single place and preparing the suite for the upcoming GET tests. * feat(tests): Add tests for project listing and retrieval (GET) This commit adds a suite for the GET method. It leverages the previously created `TestProjectBase` class for URL generation. The new test suite covers: - Listing projects: - Verifies that administrators see all projects. - Confirms guests only see projects they are members of. - Tests the separate detailed project list endpoint. - Retrieving a single project: - Checks for successful retrieval of a project by its ID. - Handles edge cases for non-existent and archived projects (404 Not Found). - Authentication: - Ensures authentication is required (401 Unauthorized). * feat(tests): Add tests for project update (PATCH) and deletion (DELETE) Key scenarios tested for PATCH: - Successful partial updates by project administrators. - Forbidden access for non-admin members (403). - Conflict errors for duplicate names or identifiers on update (409). - Validation errors for invalid data (400). Key scenarios tested for DELETE: - Successful deletion by both project admins and workspace admins. - Forbidden access for non-admin members (403). - Authentication checks for unauthenticated users (401). * Remove unnecessary print statement * refactor(tests): Update workspace fixture to use ORM Updates the `workspace` fixture to create the model instance directly via the ORM using the `Workspace` model instead of the API, as requested during code review. * Refactor: Remove some unused imports Removes imports that I added while working on the test suite for the Project API but were ultimately not used. Note that other unused imports still exist from the state of the codebase when this branch was created/forked.
140 lines
3.5 KiB
Python
140 lines
3.5 KiB
Python
import pytest
|
|
from django.conf import settings
|
|
from rest_framework.test import APIClient
|
|
from pytest_django.fixtures import django_db_setup
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
from plane.db.models import User, Workspace, WorkspaceMember
|
|
from plane.db.models.api import APIToken
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def django_db_setup(django_db_setup):
|
|
"""Set up the Django database for the test session"""
|
|
pass
|
|
|
|
|
|
@pytest.fixture
|
|
def api_client():
|
|
"""Return an unauthenticated API client"""
|
|
return APIClient()
|
|
|
|
|
|
@pytest.fixture
|
|
def user_data():
|
|
"""Return standard user data for tests"""
|
|
return {
|
|
"email": "test@plane.so",
|
|
"password": "test-password",
|
|
"first_name": "Test",
|
|
"last_name": "User",
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def create_user(db, user_data):
|
|
"""Create and return a user instance"""
|
|
user = User.objects.create(
|
|
email=user_data["email"],
|
|
first_name=user_data["first_name"],
|
|
last_name=user_data["last_name"],
|
|
)
|
|
user.set_password(user_data["password"])
|
|
user.save()
|
|
return user
|
|
|
|
|
|
@pytest.fixture
|
|
def api_token(db, create_user):
|
|
"""Create and return an API token for testing the external API"""
|
|
token = APIToken.objects.create(
|
|
user=create_user,
|
|
label="Test API Token",
|
|
token="test-api-token-12345",
|
|
)
|
|
return token
|
|
|
|
|
|
@pytest.fixture
|
|
def api_key_client(api_client, api_token):
|
|
"""Return an API key authenticated client for external API testing"""
|
|
api_client.credentials(HTTP_X_API_KEY=api_token.token)
|
|
return api_client
|
|
|
|
|
|
@pytest.fixture
|
|
def session_client(api_client, create_user):
|
|
"""Return a session authenticated API client for app API testing, which is what plane.app uses"""
|
|
api_client.force_authenticate(user=create_user)
|
|
return api_client
|
|
|
|
|
|
@pytest.fixture
|
|
def create_bot_user(db):
|
|
"""Create and return a bot user instance"""
|
|
from uuid import uuid4
|
|
|
|
unique_id = uuid4().hex[:8]
|
|
user = User.objects.create(
|
|
email=f"bot-{unique_id}@plane.so",
|
|
username=f"bot_user_{unique_id}",
|
|
first_name="Bot",
|
|
last_name="User",
|
|
is_bot=True,
|
|
)
|
|
user.set_password("bot@123")
|
|
user.save()
|
|
return user
|
|
|
|
|
|
@pytest.fixture
|
|
def api_token_data():
|
|
"""Return sample API token data for testing"""
|
|
from django.utils import timezone
|
|
from datetime import timedelta
|
|
|
|
return {
|
|
"label": "Test API Token",
|
|
"description": "Test description for API token",
|
|
"expired_at": (timezone.now() + timedelta(days=30)).isoformat(),
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def create_api_token_for_user(db, create_user):
|
|
"""Create and return an API token for a specific user"""
|
|
return APIToken.objects.create(
|
|
label="Test Token",
|
|
description="Test token description",
|
|
user=create_user,
|
|
user_type=0,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def plane_server(live_server):
|
|
"""
|
|
Renamed version of live_server fixture to avoid name clashes.
|
|
Returns a live Django server for testing HTTP requests.
|
|
"""
|
|
return live_server
|
|
|
|
|
|
@pytest.fixture
|
|
def workspace(create_user):
|
|
"""
|
|
Create a new workspace and return the
|
|
corresponding Workspace model instance.
|
|
"""
|
|
# Create the workspace using the model
|
|
created_workspace = Workspace.objects.create(
|
|
name="Test Workspace",
|
|
owner=create_user,
|
|
slug="test-workspace",
|
|
)
|
|
|
|
WorkspaceMember.objects.create(
|
|
workspace=created_workspace, member=create_user, role=20
|
|
)
|
|
|
|
return created_workspace
|