Skip to content

Commit 14ace11

Browse files
author
Test User
committed
fix(e2e): make 422 validation error test independent of prior test state
The test was failing because it depended on project 2 being in 'planning' phase, but the previous test in the serial suite transitions it to 'active' phase after approval. The TaskReview component (with approve button) only renders when phase is 'planning'. Fix: Mock the project status and issues endpoints to return the expected state, making the test self-contained and deterministic regardless of database state from prior tests.
1 parent 01aee7f commit 14ace11

File tree

1 file changed

+50
-10
lines changed

1 file changed

+50
-10
lines changed

tests/e2e/test_task_approval.spec.ts

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,11 @@ test.describe('Task Approval API Contract', () => {
145145
* Test that 422 validation errors from task approval are properly handled.
146146
*
147147
* This test mocks a 422 response to verify the frontend handles it gracefully.
148+
* NOTE: Since earlier tests may have transitioned the project to 'active' phase,
149+
* we must mock the status endpoint to return 'planning' phase so TaskReview renders.
148150
*/
149151
test('should handle 422 validation error gracefully', async ({ page }) => {
150-
// Mock a 422 validation error response
152+
// Mock a 422 validation error response for the approval API
151153
await page.route('**/api/projects/*/tasks/approve', async (route: Route) => {
152154
await route.fulfill({
153155
status: 422,
@@ -164,6 +166,48 @@ test.describe('Task Approval API Contract', () => {
164166
});
165167
});
166168

169+
// Mock project status to return 'planning' phase so TaskReview component renders
170+
// (Earlier tests may have transitioned the project to 'active' phase)
171+
await page.route('**/api/projects/*/status', async (route: Route) => {
172+
await route.fulfill({
173+
status: 200,
174+
contentType: 'application/json',
175+
body: JSON.stringify({
176+
id: parseInt(PROJECT_ID),
177+
name: 'e2e-planning-project',
178+
description: 'Test project',
179+
status: 'planning',
180+
phase: 'planning', // Critical: Must be 'planning' for TaskReview to render
181+
workflow_step: 1,
182+
progress: { completed_tasks: 0, total_tasks: 6, percentage: 0 }
183+
})
184+
});
185+
});
186+
187+
// Mock issues endpoint to return test issues with tasks (required for TaskReview)
188+
await page.route('**/api/projects/*/issues*', async (route: Route) => {
189+
await route.fulfill({
190+
status: 200,
191+
contentType: 'application/json',
192+
body: JSON.stringify({
193+
issues: [
194+
{
195+
id: '1',
196+
issue_number: '1.1',
197+
title: 'Test Issue 1',
198+
status: 'pending',
199+
tasks: [
200+
{ id: '1', task_number: '1.1.1', title: 'Test Task 1', description: 'Description' },
201+
{ id: '2', task_number: '1.1.2', title: 'Test Task 2', description: 'Description' }
202+
]
203+
}
204+
],
205+
total_issues: 1,
206+
total_tasks: 2
207+
})
208+
});
209+
});
210+
167211
// Navigate to project
168212
await page.goto(`${FRONTEND_URL}/projects/${PROJECT_ID}`);
169213
await page.waitForLoadState('networkidle');
@@ -173,7 +217,7 @@ test.describe('Task Approval API Contract', () => {
173217
await expect(tasksTab).toBeVisible({ timeout: 10000 });
174218
await tasksTab.click();
175219

176-
// Look for approve button - MUST be visible
220+
// Look for approve button - MUST be visible (TaskReview renders because phase is mocked to 'planning')
177221
const approveButton = page.getByRole('button', { name: /approve/i });
178222
await expect(approveButton).toBeVisible({ timeout: 5000 });
179223

@@ -190,14 +234,10 @@ test.describe('Task Approval API Contract', () => {
190234
expect(response.status()).toBe(422);
191235

192236
// Verify UI shows error message (not a blank screen)
193-
// Use explicit assertion - FAIL if no error UI appears
194-
const errorIndicators = page.locator('[class*="destructive"], [class*="error"], [role="alert"]');
195-
const errorText = page.getByText(/failed|error|try again/i);
196-
197-
// At least one error indicator must be visible
198-
await expect(
199-
errorIndicators.first().or(errorText.first())
200-
).toBeVisible({ timeout: 5000 });
237+
// Look for the specific error message from TaskReview component
238+
// Note: Exclude Next.js route announcer which also has role="alert"
239+
const errorMessage = page.getByText('Failed to approve tasks');
240+
await expect(errorMessage).toBeVisible({ timeout: 5000 });
201241
});
202242

203243
});

0 commit comments

Comments
 (0)