Skip to content

Commit 545507f

Browse files
[WEB-4668] fix: LabelDetailAPIEndpoint from LabelListCreateAPIEndpoint (#7571)
1 parent d317755 commit 545507f

File tree

2 files changed

+233
-3
lines changed

2 files changed

+233
-3
lines changed

apps/api/plane/api/views/issue.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ def get(self, request, slug, project_id):
947947
)
948948

949949

950-
class LabelDetailAPIEndpoint(BaseAPIView):
950+
class LabelDetailAPIEndpoint(LabelListCreateAPIEndpoint):
951951
"""Label Detail Endpoint"""
952952

953953
serializer_class = LabelSerializer
@@ -1012,14 +1012,16 @@ def patch(self, request, slug, project_id, pk):
10121012
if (
10131013
str(request.data.get("external_id"))
10141014
and (label.external_id != str(request.data.get("external_id")))
1015-
and Issue.objects.filter(
1015+
and Label.objects.filter(
10161016
project_id=project_id,
10171017
workspace__slug=slug,
10181018
external_source=request.data.get(
10191019
"external_source", label.external_source
10201020
),
10211021
external_id=request.data.get("external_id"),
1022-
).exists()
1022+
)
1023+
.exclude(id=pk)
1024+
.exists()
10231025
):
10241026
return Response(
10251027
{
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
import pytest
2+
from rest_framework import status
3+
from django.db import IntegrityError
4+
from uuid import uuid4
5+
6+
from plane.db.models import Label, Project, ProjectMember
7+
8+
9+
@pytest.fixture
10+
def project(db, workspace, create_user):
11+
"""Create a test project with the user as a member"""
12+
project = Project.objects.create(
13+
name="Test Project",
14+
identifier="TP",
15+
workspace=workspace,
16+
created_by=create_user,
17+
)
18+
ProjectMember.objects.create(
19+
project=project,
20+
member=create_user,
21+
role=20, # Admin role
22+
is_active=True,
23+
)
24+
return project
25+
26+
27+
@pytest.fixture
28+
def label_data():
29+
"""Sample label data for tests"""
30+
return {
31+
"name": "Test Label",
32+
"color": "#FF5733",
33+
"description": "A test label for unit tests",
34+
}
35+
36+
37+
@pytest.fixture
38+
def create_label(db, project, create_user):
39+
"""Create a test label"""
40+
return Label.objects.create(
41+
name="Existing Label",
42+
color="#00FF00",
43+
description="An existing label",
44+
project=project,
45+
workspace=project.workspace,
46+
created_by=create_user,
47+
)
48+
49+
50+
@pytest.mark.contract
51+
class TestLabelListCreateAPIEndpoint:
52+
"""Test Label List and Create API Endpoint"""
53+
54+
def get_label_url(self, workspace_slug, project_id):
55+
"""Helper to get label endpoint URL"""
56+
return f"/api/v1/workspaces/{workspace_slug}/projects/{project_id}/labels/"
57+
58+
@pytest.mark.django_db
59+
def test_create_label_success(self, api_key_client, workspace, project, label_data):
60+
"""Test successful label creation"""
61+
url = self.get_label_url(workspace.slug, project.id)
62+
63+
response = api_key_client.post(url, label_data, format="json")
64+
65+
assert response.status_code == status.HTTP_201_CREATED
66+
assert Label.objects.count() == 1
67+
68+
created_label = Label.objects.first()
69+
assert created_label.name == label_data["name"]
70+
assert created_label.color == label_data["color"]
71+
assert created_label.description == label_data["description"]
72+
assert created_label.project == project
73+
74+
@pytest.mark.django_db
75+
def test_create_label_invalid_data(self, api_key_client, workspace, project):
76+
"""Test label creation with invalid data"""
77+
url = self.get_label_url(workspace.slug, project.id)
78+
79+
# Test with empty data
80+
response = api_key_client.post(url, {}, format="json")
81+
assert response.status_code == status.HTTP_400_BAD_REQUEST
82+
83+
# Test with missing name
84+
response = api_key_client.post(url, {"color": "#FF5733"}, format="json")
85+
assert response.status_code == status.HTTP_400_BAD_REQUEST
86+
87+
@pytest.mark.django_db
88+
def test_create_label_with_external_id(self, api_key_client, workspace, project):
89+
"""Test creating label with external ID"""
90+
url = self.get_label_url(workspace.slug, project.id)
91+
92+
label_data = {
93+
"name": "External Label",
94+
"color": "#FF5733",
95+
"external_id": "ext-123",
96+
"external_source": "github",
97+
}
98+
99+
response = api_key_client.post(url, label_data, format="json")
100+
101+
assert response.status_code == status.HTTP_201_CREATED
102+
created_label = Label.objects.first()
103+
assert created_label.external_id == "ext-123"
104+
assert created_label.external_source == "github"
105+
106+
@pytest.mark.django_db
107+
def test_create_label_duplicate_external_id(
108+
self, api_key_client, workspace, project
109+
):
110+
"""Test creating label with duplicate external ID"""
111+
url = self.get_label_url(workspace.slug, project.id)
112+
113+
# Create first label
114+
Label.objects.create(
115+
name="First Label",
116+
project=project,
117+
workspace=workspace,
118+
external_id="ext-123",
119+
external_source="github",
120+
)
121+
122+
# Try to create second label with same external ID
123+
label_data = {
124+
"name": "Second Label",
125+
"external_id": "ext-123",
126+
"external_source": "github",
127+
}
128+
129+
response = api_key_client.post(url, label_data, format="json")
130+
131+
assert response.status_code == status.HTTP_409_CONFLICT
132+
assert "same external id" in response.data["error"]
133+
134+
@pytest.mark.django_db
135+
def test_list_labels_success(
136+
self, api_key_client, workspace, project, create_label
137+
):
138+
"""Test successful label listing"""
139+
url = self.get_label_url(workspace.slug, project.id)
140+
141+
# Create additional labels
142+
Label.objects.create(
143+
name="Label 2", project=project, workspace=workspace, color="#00FF00"
144+
)
145+
Label.objects.create(
146+
name="Label 3", project=project, workspace=workspace, color="#0000FF"
147+
)
148+
149+
response = api_key_client.get(url)
150+
151+
assert response.status_code == status.HTTP_200_OK
152+
assert "results" in response.data
153+
assert len(response.data["results"]) == 3 # Including create_label fixture
154+
155+
156+
@pytest.mark.contract
157+
class TestLabelDetailAPIEndpoint:
158+
"""Test Label Detail API Endpoint"""
159+
160+
def get_label_detail_url(self, workspace_slug, project_id, label_id):
161+
"""Helper to get label detail endpoint URL"""
162+
return f"/api/v1/workspaces/{workspace_slug}/projects/{project_id}/labels/{label_id}/"
163+
164+
@pytest.mark.django_db
165+
def test_get_label_success(self, api_key_client, workspace, project, create_label):
166+
"""Test successful label retrieval"""
167+
url = self.get_label_detail_url(workspace.slug, project.id, create_label.id)
168+
169+
response = api_key_client.get(url)
170+
171+
assert response.status_code == status.HTTP_200_OK
172+
assert response.data["id"] == create_label.id
173+
assert response.data["name"] == create_label.name
174+
assert response.data["color"] == create_label.color
175+
176+
@pytest.mark.django_db
177+
def test_get_label_not_found(self, api_key_client, workspace, project):
178+
"""Test getting non-existent label"""
179+
from uuid import uuid4
180+
181+
fake_id = uuid4()
182+
url = self.get_label_detail_url(workspace.slug, project.id, fake_id)
183+
184+
response = api_key_client.get(url)
185+
assert response.status_code == status.HTTP_404_NOT_FOUND
186+
187+
@pytest.mark.django_db
188+
def test_update_label_success(
189+
self, api_key_client, workspace, project, create_label
190+
):
191+
"""Test successful label update"""
192+
url = self.get_label_detail_url(workspace.slug, project.id, create_label.id)
193+
194+
update_data = {
195+
"name": f"Updated Label {uuid4()}",
196+
}
197+
198+
response = api_key_client.patch(url, update_data, format="json")
199+
200+
assert response.status_code == status.HTTP_200_OK
201+
202+
create_label.refresh_from_db()
203+
assert create_label.name == update_data["name"]
204+
205+
@pytest.mark.django_db
206+
def test_update_label_invalid_data(
207+
self, api_key_client, workspace, project, create_label
208+
):
209+
"""Test label update with invalid data"""
210+
url = self.get_label_detail_url(workspace.slug, project.id, create_label.id)
211+
212+
update_data = {"name": ""}
213+
response = api_key_client.patch(url, update_data, format="json")
214+
215+
# This might be 400 if name is required, or 200 if empty names are allowed
216+
assert response.status_code in [status.HTTP_400_BAD_REQUEST, status.HTTP_200_OK]
217+
218+
@pytest.mark.django_db
219+
def test_delete_label_success(
220+
self, api_key_client, workspace, project, create_label
221+
):
222+
"""Test successful label deletion"""
223+
url = self.get_label_detail_url(workspace.slug, project.id, create_label.id)
224+
225+
response = api_key_client.delete(url)
226+
227+
assert response.status_code == status.HTTP_204_NO_CONTENT
228+
assert not Label.objects.filter(id=create_label.id).exists()

0 commit comments

Comments
 (0)