From 26c8ed0328000153eff37a183bbc9c61bf8a638b Mon Sep 17 00:00:00 2001 From: Myers Carpenter Date: Mon, 30 Mar 2026 03:06:09 +0000 Subject: [PATCH] Add Go integration tests and improve E2E assertions for column picker Integration tests for UpdateIssueProjectColumn endpoint: - MoveToColumn: verify column change persists - InvalidColumn: reject column from wrong project (404) - NonexistentColumn: reject missing column (404) - IssueFromOtherRepo: reject cross-repo issue (404) E2E test improvements: - Assert dropdown closes after selection - Assert sidebar shows new column name - Assert timeline event appears for column move - Use specific selector for reload verification --- tests/e2e/project-column-picker.test.ts | 9 ++++- tests/integration/project_test.go | 50 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/tests/e2e/project-column-picker.test.ts b/tests/e2e/project-column-picker.test.ts index 9c616f32d5..e35ccbf9ee 100644 --- a/tests/e2e/project-column-picker.test.ts +++ b/tests/e2e/project-column-picker.test.ts @@ -32,9 +32,16 @@ test('project column picker', async ({page}) => { // Select a different column await columnItems.filter({hasText: 'In Progress'}).click(); + // Verify the dropdown closed and shows the new selection + await expect(page.locator('#sidebar-project-column .menu')).toBeHidden(); + await expect(page.locator('#sidebar-project-column .default.text')).toHaveText('In Progress'); + + // Verify a timeline event appeared for the column move + await expect(page.locator('.timeline-item').last()).toContainText('moved this to In Progress'); + // Reload and verify the column persisted await page.reload(); - await expect(page.locator('#sidebar-project-column')).toContainText('In Progress'); + await expect(page.locator('#sidebar-project-column .default.text')).toHaveText('In Progress'); await apiDeleteRepo(page.request, owner, repoName); }); diff --git a/tests/integration/project_test.go b/tests/integration/project_test.go index 1e38322dbf..bc97d7ef30 100644 --- a/tests/integration/project_test.go +++ b/tests/integration/project_test.go @@ -89,6 +89,56 @@ func TestMoveRepoProjectColumns(t *testing.T) { assert.NoError(t, project_model.DeleteProjectByID(t.Context(), project1.ID)) } +func TestUpdateIssueProjectColumn(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + // Issue 1 is in project 1, column 1 (To Do) — see fixtures + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) + sess := loginUser(t, "user2") + + t.Run("MoveToColumn", func(t *testing.T) { + // Move issue 1 from To Do (column 1) to In Progress (column 2) + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/issues/projects/column", repo.FullName()), map[string]string{ + "issue_id": strconv.FormatInt(issue.ID, 10), + "id": "2", + }) + sess.MakeRequest(t, req, http.StatusOK) + + // Verify the column changed + columnID, err := issue.ProjectColumnID(t.Context()) + require.NoError(t, err) + assert.EqualValues(t, 2, columnID) + }) + + t.Run("InvalidColumn", func(t *testing.T) { + // Column 4 belongs to project 4, not project 1 + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/issues/projects/column", repo.FullName()), map[string]string{ + "issue_id": strconv.FormatInt(issue.ID, 10), + "id": "4", + }) + sess.MakeRequest(t, req, http.StatusNotFound) + }) + + t.Run("NonexistentColumn", func(t *testing.T) { + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/issues/projects/column", repo.FullName()), map[string]string{ + "issue_id": strconv.FormatInt(issue.ID, 10), + "id": "99999", + }) + sess.MakeRequest(t, req, http.StatusNotFound) + }) + + t.Run("IssueFromOtherRepo", func(t *testing.T) { + // Issue 4 belongs to repo 2, not repo 1 + otherIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}) + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/issues/projects/column", repo.FullName()), map[string]string{ + "issue_id": strconv.FormatInt(otherIssue.ID, 10), + "id": "2", + }) + sess.MakeRequest(t, req, http.StatusNotFound) + }) +} + // getProjectIssueIDs returns the set of issue IDs rendered as cards on the project board page. func getProjectIssueIDs(t *testing.T, htmlDoc *HTMLDoc) map[int64]struct{} { t.Helper()