Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions crates/api/src/domain/milestones.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,9 @@ pub async fn repository_milestone_detail_for_actor_by_owner_name(
) -> Result<RepositoryMilestoneDetail, MilestonesError> {
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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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?;
Expand Down
2 changes: 1 addition & 1 deletion crates/api/tests/repository_milestones_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
29 changes: 20 additions & 9 deletions web/tests/e2e/repository-milestones.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ function seedSession(): SeededSession {
env: {
...process.env,
DASHBOARD_E2E_EMPTY: "1",
DASHBOARD_E2E_SKIP_MIGRATIONS: "1",
SESSION_COOKIE_NAME: "og_session",
},
},
Expand Down Expand Up @@ -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,
}) => {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -217,39 +223,42 @@ 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", {
has: page.getByRole("heading", { name: "Milestone" }),
})
.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", {
has: page.getByRole("heading", { name: "Milestone" }),
})
.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}`);
Expand All @@ -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({
Expand Down