diff --git a/crates/api/src/domain/milestones.rs b/crates/api/src/domain/milestones.rs index 6948bc7b..b02d4373 100644 --- a/crates/api/src/domain/milestones.rs +++ b/crates/api/src/domain/milestones.rs @@ -252,7 +252,9 @@ pub async fn repository_milestone_detail_for_actor_by_owner_name( ) -> Result { let repository = repository_for_optional_actor(pool, owner, repo, actor_user_id).await?; let viewer = milestone_viewer(pool, &repository, actor_user_id).await?; - let row = sqlx::query(&milestone_select_sql("milestones.id = $2")) + let row = sqlx::query(&milestone_select_sql( + "milestones.repository_id = $1 AND milestones.id = $2", + )) .bind(repository.id) .bind(milestone_id) .fetch_optional(pool) @@ -817,8 +819,10 @@ async fn milestone_rows( MilestoneSort::IssuesAsc => "total_count ASC, milestones.updated_at DESC", }; let sql = format!( - "{} AND ($2::text IS NULL OR milestones.state = $2) ORDER BY {order_by} LIMIT $3 OFFSET $4", - milestone_select_sql("milestones.repository_id = $1") + "{} ORDER BY {order_by} LIMIT $3 OFFSET $4", + milestone_select_sql( + "milestones.repository_id = $1 AND ($2::text IS NULL OR milestones.state = $2)", + ) ); sqlx::query(&sql) .bind(repository_id) @@ -1041,7 +1045,7 @@ async fn insert_audit_event( .bind(actor_user_id) .bind(event_type) .bind(target_type) - .bind(target_id) + .bind(target_id.to_string()) .bind(metadata) .execute(pool) .await?; diff --git a/crates/api/tests/repository_milestones_contract.rs b/crates/api/tests/repository_milestones_contract.rs index 8e00f40c..0565fbc5 100644 --- a/crates/api/tests/repository_milestones_contract.rs +++ b/crates/api/tests/repository_milestones_contract.rs @@ -248,7 +248,7 @@ async fn repository_milestones_contract_lists_mutates_and_clears_associations() "SELECT COUNT(*)::bigint FROM audit_events WHERE actor_user_id = $1 AND target_id = $2", ) .bind(writer.id) - .bind(milestone.id) + .bind(milestone.id.to_string()) .fetch_one(&pool) .await .expect("audit count should load"); diff --git a/web/tests/e2e/repository-milestones.spec.ts b/web/tests/e2e/repository-milestones.spec.ts index d7eddce4..f80c1d75 100644 --- a/web/tests/e2e/repository-milestones.spec.ts +++ b/web/tests/e2e/repository-milestones.spec.ts @@ -43,6 +43,7 @@ function seedSession(): SeededSession { env: { ...process.env, DASHBOARD_E2E_EMPTY: "1", + DASHBOARD_E2E_SKIP_MIGRATIONS: "1", SESSION_COOKIE_NAME: "og_session", }, }, @@ -89,6 +90,8 @@ test.skip( "Repository milestones E2E needs TEST_DATABASE_URL or DATABASE_URL", ); +test.setTimeout(6 * 60 * 1000); + test("signed-in repository milestones manage lifecycle, assignment, reorder, and mobile layout", async ({ page, }) => { @@ -172,12 +175,15 @@ test("signed-in repository milestones manage lifecycle, assignment, reorder, and expect(pullNumber).toBeTruthy(); await page.goto(`/${ownerLogin}/${repoName}/milestones`); - await expect(page.getByRole("heading", { name: "Milestones" })).toBeVisible(); + await expect( + page.getByRole("heading", { exact: true, name: "Milestones" }), + ).toBeVisible(); await expect(page.getByText(`Launch readiness ${unique}`)).toBeVisible(); - await page.getByText("Sort").click(); + await page.getByRole("button", { name: "Sort" }).click(); await expect( page.getByRole("menuitemradio", { name: /Most issues/ }), ).toHaveAttribute("href", /sort=issues-desc/); + await page.getByRole("button", { name: "Sort" }).click(); await page.getByRole("button", { name: "New milestone" }).click(); await page.getByLabel("Milestone title").fill(`Docs cutover ${unique}`); await page @@ -217,15 +223,16 @@ test("signed-in repository milestones manage lifecycle, assignment, reorder, and await expect(page.getByText(`Polish release notes ${unique}`)).toBeVisible(); await page.getByRole("button", { name: "Close" }).click(); await page.reload(); - await expect(page.getByText("closed")).toBeVisible(); + await expect(page.getByText("closed", { exact: true })).toBeVisible(); await page.getByRole("button", { name: "Reopen" }).click(); await page.reload(); - await expect(page.getByText("open")).toBeVisible(); + await expect(page.getByText("open", { exact: true })).toBeVisible(); await page.getByRole("link", { name: "New issue" }).click(); await expect(page).toHaveURL( new RegExp(`/issues/new\\?milestone=${milestone}`), ); + await signIn(page, seeded); await page.goto(`/${ownerLogin}/${repoName}/issues/${issueOne.number}`); await page .locator("section", { @@ -233,11 +240,12 @@ test("signed-in repository milestones manage lifecycle, assignment, reorder, and }) .getByRole("button", { name: "Edit" }) .click(); - await page.getByLabel("Search milestones").fill("No milestone"); - await page.getByRole("button", { name: /Choose No milestone/ }).click(); + await page.getByPlaceholder("Search milestones").fill("No milestone"); + await page.getByRole("button", { name: "No milestone" }).click(); await expect(page.getByText("Issue metadata updated.")).toBeVisible(); await expect(page.getByText("No milestone")).toBeVisible(); + await signIn(page, seeded); await page.goto(`/${ownerLogin}/${repoName}/pull/${pullNumber}`); await page .locator("section", { @@ -245,11 +253,12 @@ test("signed-in repository milestones manage lifecycle, assignment, reorder, and }) .getByRole("button", { name: "Edit" }) .click(); - await page.getByLabel("Search milestones").fill("No milestone"); - await page.getByRole("button", { name: /Choose No milestone/ }).click(); + await page.getByPlaceholder("Search milestones").fill("No milestone"); + await page.getByRole("button", { name: "No milestone" }).click(); await expect(page.getByText("Pull request metadata updated.")).toBeVisible(); await expect(page.getByText("No milestone")).toBeVisible(); + await signIn(page, seeded); await page.goto(`/${ownerLogin}/${repoName}/issues/${issueTwo.number}`); await expect(page.getByText(`Launch readiness ${unique}`)).toBeVisible(); await page.goto(`/${ownerLogin}/${repoName}/milestones/${milestone}`); @@ -259,7 +268,9 @@ test("signed-in repository milestones manage lifecycle, assignment, reorder, and await page.setViewportSize({ width: 390, height: 844 }); await page.goto(`/${ownerLogin}/${repoName}/milestones`); - await expect(page.getByRole("heading", { name: "Milestones" })).toBeVisible(); + await expect( + page.getByRole("heading", { exact: true, name: "Milestones" }), + ).toBeVisible(); await expectNoHorizontalOverflow(page); await expectNoDeadControls(page); await page.screenshot({