vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Serve changes at /r/<repo>/changes
8fb7aabf534adf208cd795724b1e3d287dc62f5a · Keenan Nemetz · 3d ago · parent b492b557
Serve changes at /r/<repo>/changes The metadata tree and the interface say changes; the browser was the last place spelling the route requests. Rename every method on that subtree and the URLs the server builds: redirects, activity and search results, the number alias, code links, templates, and the CLI's page links. The old route is gone rather than aliased. Nothing has been publicly released, so there is no bookmark or client to keep working, and a redirect would leave two spellings of the same page in the code. Refs #204 (01M6S6685JFG8S64ZFF452217W).
server/issues_changes_test.go +76−76
| @@ -172,18 +172,18 @@ func TestIssueAndChangeDetailsCanBeEditedInTheBrowser(t *testing.T) { | |||
| 172 | 172 | } | |
| 173 | 173 | ||
| 174 | 174 | // A change: same controls, and the same writer. | |
| 175 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests", cookie, url.Values{ | ||
| 175 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes", cookie, url.Values{ | ||
| 176 | 176 | "csrf": {sess.CSRF}, "title": {"First change draft"}, "body": {"original change body\n"}, | |
| 177 | 177 | "base": {"main"}, "head": {"feature"}, | |
| 178 | 178 | }) | |
| 179 | 179 | if resp.StatusCode != http.StatusSeeOther { | |
| 180 | 180 | t.Fatalf("create change: %d\n%s", resp.StatusCode, body) | |
| 181 | 181 | } | |
| 182 | changeID := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/requests/") | ||
| 182 | changeID := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/changes/") | ||
| 183 | 183 | if changeID == "" { | |
| 184 | 184 | t.Fatalf("no change id in %q", resp.Header.Get("Location")) | |
| 185 | 185 | } | |
| 186 | _, page = f.browserGet(t, "/r/"+f.repo+"/requests/"+changeID, cookie) | ||
| 186 | _, page = f.browserGet(t, "/r/"+f.repo+"/changes/"+changeID, cookie) | ||
| 187 | 187 | if !strings.Contains(page, "data-title-edit") || !strings.Contains(page, "data-title-edit-form") || | |
| 188 | 188 | !strings.Contains(page, `data-comment-menu`) || !strings.Contains(page, "Copy text") || | |
| 189 | 189 | !strings.Contains(page, "data-comment-edit") || !strings.Contains(page, `name="field" value="title"`) || | |
| @@ -192,16 +192,16 @@ func TestIssueAndChangeDetailsCanBeEditedInTheBrowser(t *testing.T) { | |||
| 192 | 192 | } | |
| 193 | 193 | // The Files tab reuses the change head but has no description form there, so | |
| 194 | 194 | // its title pencil must keep the ordinary link to the standalone page. | |
| 195 | if _, files := f.browserGet(t, "/r/"+f.repo+"/requests/"+changeID+"/files", cookie); !strings.Contains(files, "/requests/"+changeID+"/edit") || | ||
| 195 | if _, files := f.browserGet(t, "/r/"+f.repo+"/changes/"+changeID+"/files", cookie); !strings.Contains(files, "/changes/"+changeID+"/edit") || | ||
| 196 | 196 | strings.Contains(files, "data-title-edit") { | |
| 197 | 197 | t.Fatalf("the Files tab does not link to the edit page:\n%s", files) | |
| 198 | 198 | } | |
| 199 | resp, form = f.browserGet(t, "/r/"+f.repo+"/requests/"+changeID+"/edit", cookie) | ||
| 200 | if resp.StatusCode != http.StatusOK || !strings.Contains(form, `action="/r/`+f.repo+`/requests/`+changeID+`/edit"`) || | ||
| 199 | resp, form = f.browserGet(t, "/r/"+f.repo+"/changes/"+changeID+"/edit", cookie) | ||
| 200 | if resp.StatusCode != http.StatusOK || !strings.Contains(form, `action="/r/`+f.repo+`/changes/`+changeID+`/edit"`) || | ||
| 201 | 201 | !strings.Contains(form, `value="First change draft"`) || !strings.Contains(form, "original change body") { | |
| 202 | 202 | t.Fatalf("change edit page = %d:\n%s", resp.StatusCode, form) | |
| 203 | 203 | } | |
| 204 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+changeID+"/edit", cookie, url.Values{ | ||
| 204 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+changeID+"/edit", cookie, url.Values{ | ||
| 205 | 205 | "csrf": {sess.CSRF}, "title": {"Corrected change"}, "body": {"corrected change body\n"}, | |
| 206 | 206 | }) | |
| 207 | 207 | if resp.StatusCode != http.StatusSeeOther { | |
| @@ -214,12 +214,12 @@ func TestIssueAndChangeDetailsCanBeEditedInTheBrowser(t *testing.T) { | |||
| 214 | 214 | if req.Title != "Corrected change" || strings.TrimSpace(req.Description) != "corrected change body" { | |
| 215 | 215 | t.Fatalf("edited change = %q / %q", req.Title, req.Description) | |
| 216 | 216 | } | |
| 217 | if _, page := f.browserGet(t, "/r/"+f.repo+"/requests/"+changeID, cookie); !strings.Contains(page, "Corrected change") || | ||
| 217 | if _, page := f.browserGet(t, "/r/"+f.repo+"/changes/"+changeID, cookie); !strings.Contains(page, "Corrected change") || | ||
| 218 | 218 | !strings.Contains(page, "corrected change body") { | |
| 219 | 219 | t.Fatalf("the change page does not show the edit:\n%s", page) | |
| 220 | 220 | } | |
| 221 | 221 | ||
| 222 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+changeID+"/edit", cookie, url.Values{ | ||
| 222 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/changes/"+changeID+"/edit", cookie, url.Values{ | ||
| 223 | 223 | "csrf": {sess.CSRF}, "field": {"title"}, "title": {"In-place change"}, | |
| 224 | 224 | }) | |
| 225 | 225 | if resp.StatusCode != http.StatusOK || strings.Contains(body, "<!doctype html>") || | |
| @@ -231,7 +231,7 @@ func TestIssueAndChangeDetailsCanBeEditedInTheBrowser(t *testing.T) { | |||
| 231 | 231 | req.Title != "In-place change" || strings.TrimSpace(req.Description) != "corrected change body" { | |
| 232 | 232 | t.Fatalf("inline change title edit = %+v, %v", req, err) | |
| 233 | 233 | } | |
| 234 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+changeID+"/edit", cookie, url.Values{ | ||
| 234 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/changes/"+changeID+"/edit", cookie, url.Values{ | ||
| 235 | 235 | "csrf": {sess.CSRF}, "field": {"body"}, "body": {"in-place change body\n"}, | |
| 236 | 236 | }) | |
| 237 | 237 | if resp.StatusCode != http.StatusOK || strings.Contains(body, "<!doctype html>") || | |
| @@ -243,7 +243,7 @@ func TestIssueAndChangeDetailsCanBeEditedInTheBrowser(t *testing.T) { | |||
| 243 | 243 | req.Title != "In-place change" || strings.TrimSpace(req.Description) != "in-place change body" { | |
| 244 | 244 | t.Fatalf("inline change description edit = %+v, %v", req, err) | |
| 245 | 245 | } | |
| 246 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+changeID+"/edit", cookie, url.Values{ | ||
| 246 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/changes/"+changeID+"/edit", cookie, url.Values{ | ||
| 247 | 247 | "csrf": {sess.CSRF}, "field": {"title"}, "title": {""}, | |
| 248 | 248 | }) | |
| 249 | 249 | if resp.StatusCode != http.StatusOK || strings.Contains(body, "<!doctype html>") || | |
| @@ -262,7 +262,7 @@ func TestIssueAndChangeDetailsCanBeEditedInTheBrowser(t *testing.T) { | |||
| 262 | 262 | strangerSess, strangerCookie := f.browserSession(t, stranger.Name) | |
| 263 | 263 | for _, path := range []string{ | |
| 264 | 264 | "/r/" + f.repo + "/issues/" + issueID + "/edit", | |
| 265 | "/r/" + f.repo + "/requests/" + changeID + "/edit", | ||
| 265 | "/r/" + f.repo + "/changes/" + changeID + "/edit", | ||
| 266 | 266 | } { | |
| 267 | 267 | if resp, _ := f.browserGet(t, path, strangerCookie); resp.StatusCode != http.StatusForbidden { | |
| 268 | 268 | t.Fatalf("stranger got %d from %s, want 403", resp.StatusCode, path) | |
| @@ -270,7 +270,7 @@ func TestIssueAndChangeDetailsCanBeEditedInTheBrowser(t *testing.T) { | |||
| 270 | 270 | } | |
| 271 | 271 | for _, path := range []string{ | |
| 272 | 272 | "/r/" + f.repo + "/issues/" + issueID + "/edit", | |
| 273 | "/r/" + f.repo + "/requests/" + changeID + "/edit", | ||
| 273 | "/r/" + f.repo + "/changes/" + changeID + "/edit", | ||
| 274 | 274 | } { | |
| 275 | 275 | resp, _ := f.browserPost(t, path, strangerCookie, url.Values{ | |
| 276 | 276 | "csrf": {strangerSess.CSRF}, "title": {"Not mine"}, "body": {"not mine\n"}, | |
| @@ -296,52 +296,52 @@ func TestChangeCanBeDiscussedAndClosedInTheBrowser(t *testing.T) { | |||
| 296 | 296 | } | |
| 297 | 297 | ||
| 298 | 298 | sess, cookie := f.browserSession(t, f.ownerID) | |
| 299 | resp, body := f.browserPost(t, "/r/"+f.repo+"/requests", cookie, url.Values{ | ||
| 299 | resp, body := f.browserPost(t, "/r/"+f.repo+"/changes", cookie, url.Values{ | ||
| 300 | 300 | "csrf": {sess.CSRF}, "title": {"Browser change"}, "body": {"please review\n"}, | |
| 301 | 301 | "base": {"main"}, "head": {"feature"}, | |
| 302 | 302 | }) | |
| 303 | 303 | if resp.StatusCode != http.StatusSeeOther { | |
| 304 | 304 | t.Fatalf("create change: %d\n%s", resp.StatusCode, body) | |
| 305 | 305 | } | |
| 306 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/requests/") | ||
| 306 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/changes/") | ||
| 307 | 307 | if id == "" { | |
| 308 | 308 | t.Fatalf("no change id in %q", resp.Header.Get("Location")) | |
| 309 | 309 | } | |
| 310 | 310 | ||
| 311 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+id+"/comments", cookie, url.Values{ | ||
| 311 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+id+"/comments", cookie, url.Values{ | ||
| 312 | 312 | "csrf": {sess.CSRF}, "body": {"Looks good from the browser.\n"}, | |
| 313 | 313 | }) | |
| 314 | 314 | if resp.StatusCode != http.StatusSeeOther { | |
| 315 | 315 | t.Fatalf("comment: %d\n%s", resp.StatusCode, body) | |
| 316 | 316 | } | |
| 317 | _, page := f.browserGet(t, "/r/"+f.repo+"/requests/"+id, cookie) | ||
| 317 | _, page := f.browserGet(t, "/r/"+f.repo+"/changes/"+id, cookie) | ||
| 318 | 318 | if !strings.Contains(page, "Looks good from the browser.") { | |
| 319 | 319 | t.Fatalf("the browser comment is not on the page:\n%s", page) | |
| 320 | 320 | } | |
| 321 | 321 | ||
| 322 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+id+"/state", cookie, url.Values{ | ||
| 322 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+id+"/state", cookie, url.Values{ | ||
| 323 | 323 | "csrf": {sess.CSRF}, "state": {"closed"}, | |
| 324 | 324 | }) | |
| 325 | 325 | if resp.StatusCode != http.StatusSeeOther { | |
| 326 | 326 | t.Fatalf("close change: %d\n%s", resp.StatusCode, body) | |
| 327 | 327 | } | |
| 328 | if _, list := f.browserGet(t, "/r/"+f.repo+"/requests", cookie); strings.Contains(list, "Browser change") { | ||
| 328 | if _, list := f.browserGet(t, "/r/"+f.repo+"/changes", cookie); strings.Contains(list, "Browser change") { | ||
| 329 | 329 | t.Fatalf("closed change is still in the open list:\n%s", list) | |
| 330 | 330 | } | |
| 331 | if _, list := f.browserGet(t, "/r/"+f.repo+"/requests?state=all", cookie); !strings.Contains(list, "Browser change") { | ||
| 331 | if _, list := f.browserGet(t, "/r/"+f.repo+"/changes?state=all", cookie); !strings.Contains(list, "Browser change") { | ||
| 332 | 332 | t.Fatalf("closed change is missing from the All list:\n%s", list) | |
| 333 | 333 | } | |
| 334 | if _, page := f.browserGet(t, "/r/"+f.repo+"/requests/"+id, cookie); !strings.Contains(page, "Reopen</button>") { | ||
| 334 | if _, page := f.browserGet(t, "/r/"+f.repo+"/changes/"+id, cookie); !strings.Contains(page, "Reopen</button>") { | ||
| 335 | 335 | t.Fatalf("closed change does not offer a reopen:\n%s", page) | |
| 336 | 336 | } | |
| 337 | 337 | ||
| 338 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+id+"/state", cookie, url.Values{ | ||
| 338 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+id+"/state", cookie, url.Values{ | ||
| 339 | 339 | "csrf": {sess.CSRF}, "state": {"open"}, | |
| 340 | 340 | }) | |
| 341 | 341 | if resp.StatusCode != http.StatusSeeOther { | |
| 342 | 342 | t.Fatalf("reopen change: %d\n%s", resp.StatusCode, body) | |
| 343 | 343 | } | |
| 344 | if _, page := f.browserGet(t, "/r/"+f.repo+"/requests/"+id, cookie); !strings.Contains(page, "Close</button>") || | ||
| 344 | if _, page := f.browserGet(t, "/r/"+f.repo+"/changes/"+id, cookie); !strings.Contains(page, "Close</button>") || | ||
| 345 | 345 | !strings.Contains(page, `class="danger"`) { | |
| 346 | 346 | t.Fatalf("reopened change does not offer a close:\n%s", page) | |
| 347 | 347 | } | |
| @@ -370,8 +370,8 @@ func TestNewIssueAndChangePages(t *testing.T) { | |||
| 370 | 370 | t.Fatal("new issue page has no CSRF token") | |
| 371 | 371 | } | |
| 372 | 372 | ||
| 373 | resp, body = f.browserGet(t, "/r/"+f.repo+"/requests/new", cookie) | ||
| 374 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, `action="/r/`+f.repo+`/requests"`) || | ||
| 373 | resp, body = f.browserGet(t, "/r/"+f.repo+"/changes/new", cookie) | ||
| 374 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, `action="/r/`+f.repo+`/changes"`) || | ||
| 375 | 375 | !strings.Contains(body, "feature") || !strings.Contains(body, "Open change") { | |
| 376 | 376 | t.Fatalf("new change page = %d:\n%s", resp.StatusCode, body) | |
| 377 | 377 | } | |
| @@ -380,7 +380,7 @@ func TestNewIssueAndChangePages(t *testing.T) { | |||
| 380 | 380 | if _, page := f.browserGet(t, "/r/"+f.repo+"/issues", cookie); !strings.Contains(page, "/issues/new") { | |
| 381 | 381 | t.Fatal("issues list does not link to the new issue page") | |
| 382 | 382 | } | |
| 383 | if _, page := f.browserGet(t, "/r/"+f.repo+"/requests", cookie); !strings.Contains(page, "/requests/new") { | ||
| 383 | if _, page := f.browserGet(t, "/r/"+f.repo+"/changes", cookie); !strings.Contains(page, "/changes/new") { | ||
| 384 | 384 | t.Fatal("changes list does not link to the new change page") | |
| 385 | 385 | } | |
| 386 | 386 | } | |
| @@ -538,25 +538,25 @@ func TestChangeLinksIssuesFromTheIssuesSection(t *testing.T) { | |||
| 538 | 538 | first := createIssue("First linked issue") | |
| 539 | 539 | second := createIssue("Second linked issue") | |
| 540 | 540 | ||
| 541 | resp, body := f.browserPost(t, "/r/"+f.repo+"/requests", cookie, url.Values{ | ||
| 541 | resp, body := f.browserPost(t, "/r/"+f.repo+"/changes", cookie, url.Values{ | ||
| 542 | 542 | "csrf": {sess.CSRF}, "title": {"Linked issues"}, "body": {"body\n"}, | |
| 543 | 543 | "base": {"main"}, "head": {"feature"}, "closes": {first}, | |
| 544 | 544 | }) | |
| 545 | 545 | if resp.StatusCode != http.StatusSeeOther { | |
| 546 | 546 | t.Fatalf("create change: %d\n%s", resp.StatusCode, body) | |
| 547 | 547 | } | |
| 548 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/requests/") | ||
| 548 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/changes/") | ||
| 549 | 549 | if id == "" { | |
| 550 | 550 | t.Fatalf("no change id in %q", resp.Header.Get("Location")) | |
| 551 | 551 | } | |
| 552 | 552 | ||
| 553 | 553 | // The Issues section uses the overview's issue rows and offers the link | |
| 554 | 554 | // controls instead of the old one-line "Closes ... when merged". | |
| 555 | _, page := f.browserGet(t, "/r/"+f.repo+"/requests/"+id, cookie) | ||
| 555 | _, page := f.browserGet(t, "/r/"+f.repo+"/changes/"+id, cookie) | ||
| 556 | 556 | for _, want := range []string{ | |
| 557 | 557 | `id="request-issues"`, "First linked issue", `value="` + first + `"`, | |
| 558 | 558 | `value="remove"`, `request-unlink`, `class="request-issue-search"`, | |
| 559 | `hx-get="/r/` + f.repo + `/requests/` + id + `/live"`, | ||
| 559 | `hx-get="/r/` + f.repo + `/changes/` + id + `/live"`, | ||
| 560 | 560 | `hx-trigger="every 20s [document.visibilityState === 'visible']"`, `hx-swap="none"`, | |
| 561 | 561 | } { | |
| 562 | 562 | if !strings.Contains(page, want) { | |
| @@ -582,7 +582,7 @@ func TestChangeLinksIssuesFromTheIssuesSection(t *testing.T) { | |||
| 582 | 582 | t.Fatalf("the second issue has no number") | |
| 583 | 583 | } | |
| 584 | 584 | for _, query := range []string{"Second", "#" + strconv.Itoa(number), second[:8]} { | |
| 585 | resp, results := f.htmxGet(t, "/r/"+f.repo+"/requests/"+id+"/issues/search?q="+url.QueryEscape(query), cookie) | ||
| 585 | resp, results := f.htmxGet(t, "/r/"+f.repo+"/changes/"+id+"/issues/search?q="+url.QueryEscape(query), cookie) | ||
| 586 | 586 | if resp.StatusCode != http.StatusOK || !strings.Contains(results, "Second linked issue") || | |
| 587 | 587 | !strings.Contains(results, `value="`+second+`"`) || !strings.Contains(results, `value="add"`) || | |
| 588 | 588 | !strings.Contains(results, `hx-target="#request-issues"`) || | |
| @@ -592,19 +592,19 @@ func TestChangeLinksIssuesFromTheIssuesSection(t *testing.T) { | |||
| 592 | 592 | } | |
| 593 | 593 | // An issue already linked is not offered, so a shared title cannot hide the | |
| 594 | 594 | // rows that are still available. | |
| 595 | resp, results := f.htmxGet(t, "/r/"+f.repo+"/requests/"+id+"/issues/search?q=First", cookie) | ||
| 595 | resp, results := f.htmxGet(t, "/r/"+f.repo+"/changes/"+id+"/issues/search?q=First", cookie) | ||
| 596 | 596 | if resp.StatusCode != http.StatusOK || strings.Contains(results, "First linked issue") || | |
| 597 | 597 | !strings.Contains(results, "No issues match") { | |
| 598 | 598 | t.Fatalf("a linked issue is still in the search results (%d):\n%s", resp.StatusCode, results) | |
| 599 | 599 | } | |
| 600 | 600 | // Clearing the field removes the popover rather than leaving a blank panel. | |
| 601 | resp, results = f.htmxGet(t, "/r/"+f.repo+"/requests/"+id+"/issues/search?q=", cookie) | ||
| 601 | resp, results = f.htmxGet(t, "/r/"+f.repo+"/changes/"+id+"/issues/search?q=", cookie) | ||
| 602 | 602 | if resp.StatusCode != http.StatusOK || strings.TrimSpace(results) != "" { | |
| 603 | 603 | t.Fatalf("an empty search left a panel (%d):\n%s", resp.StatusCode, results) | |
| 604 | 604 | } | |
| 605 | 605 | ||
| 606 | 606 | // Clicking a result posts its id, and the section comes back with both links. | |
| 607 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+id+"/issues", cookie, url.Values{ | ||
| 607 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/changes/"+id+"/issues", cookie, url.Values{ | ||
| 608 | 608 | "csrf": {sess.CSRF}, "action": {"add"}, "issue": {second}, | |
| 609 | 609 | }) | |
| 610 | 610 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, `id="request-issues"`) || | |
| @@ -616,7 +616,7 @@ func TestChangeLinksIssuesFromTheIssuesSection(t *testing.T) { | |||
| 616 | 616 | } | |
| 617 | 617 | ||
| 618 | 618 | // Removing a link is the same write, and the row disappears. | |
| 619 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+id+"/issues", cookie, url.Values{ | ||
| 619 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/changes/"+id+"/issues", cookie, url.Values{ | ||
| 620 | 620 | "csrf": {sess.CSRF}, "action": {"remove"}, "issue": {first}, | |
| 621 | 621 | }) | |
| 622 | 622 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, `id="request-issues"`) || | |
| @@ -629,7 +629,7 @@ func TestChangeLinksIssuesFromTheIssuesSection(t *testing.T) { | |||
| 629 | 629 | } | |
| 630 | 630 | ||
| 631 | 631 | // A duplicate says so beside the control instead of rewriting the list. | |
| 632 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+id+"/issues", cookie, url.Values{ | ||
| 632 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/changes/"+id+"/issues", cookie, url.Values{ | ||
| 633 | 633 | "csrf": {sess.CSRF}, "action": {"add"}, "issue": {second}, | |
| 634 | 634 | }) | |
| 635 | 635 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, "already linked") { | |
| @@ -638,18 +638,18 @@ func TestChangeLinksIssuesFromTheIssuesSection(t *testing.T) { | |||
| 638 | 638 | ||
| 639 | 639 | // A closed request keeps its record but offers no edits, and the writer | |
| 640 | 640 | // refuses one posted anyway. | |
| 641 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+id+"/state", cookie, url.Values{ | ||
| 641 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+id+"/state", cookie, url.Values{ | ||
| 642 | 642 | "csrf": {sess.CSRF}, "state": {"closed"}, | |
| 643 | 643 | }) | |
| 644 | 644 | if resp.StatusCode != http.StatusSeeOther { | |
| 645 | 645 | t.Fatalf("close change: %d\n%s", resp.StatusCode, body) | |
| 646 | 646 | } | |
| 647 | _, page = f.browserGet(t, "/r/"+f.repo+"/requests/"+id, cookie) | ||
| 647 | _, page = f.browserGet(t, "/r/"+f.repo+"/changes/"+id, cookie) | ||
| 648 | 648 | if !strings.Contains(page, "Second linked issue") || strings.Contains(page, `request-unlink`) || | |
| 649 | 649 | strings.Contains(page, `class="request-issue-search"`) { | |
| 650 | 650 | t.Fatalf("a closed request does not show the right Issues section:\n%s", page) | |
| 651 | 651 | } | |
| 652 | resp, _ = f.htmxPost(t, "/r/"+f.repo+"/requests/"+id+"/issues", cookie, url.Values{ | ||
| 652 | resp, _ = f.htmxPost(t, "/r/"+f.repo+"/changes/"+id+"/issues", cookie, url.Values{ | ||
| 653 | 653 | "csrf": {sess.CSRF}, "action": {"remove"}, "issue": {second}, | |
| 654 | 654 | }) | |
| 655 | 655 | if resp.StatusCode != http.StatusForbidden { | |
| @@ -682,7 +682,7 @@ func TestRepositoryCanRequireALinkedIssueForNewChanges(t *testing.T) { | |||
| 682 | 682 | } | |
| 683 | 683 | ||
| 684 | 684 | sess, cookie := f.browserSession(t, f.ownerID) | |
| 685 | resp, body := f.browserGet(t, "/r/"+f.repo+"/requests/new", cookie) | ||
| 685 | resp, body := f.browserGet(t, "/r/"+f.repo+"/changes/new", cookie) | ||
| 686 | 686 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, "requires a linked issue") || | |
| 687 | 687 | !strings.Contains(body, "required") { | |
| 688 | 688 | t.Fatalf("new change page does not explain the rule (%d):\n%s", resp.StatusCode, body) | |
| @@ -692,7 +692,7 @@ func TestRepositoryCanRequireALinkedIssueForNewChanges(t *testing.T) { | |||
| 692 | 692 | "csrf": {sess.CSRF}, "title": {"Unlinked change"}, "body": {"body\n"}, | |
| 693 | 693 | "base": {"main"}, "head": {"feature"}, | |
| 694 | 694 | } | |
| 695 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests", cookie, form) | ||
| 695 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes", cookie, form) | ||
| 696 | 696 | if resp.StatusCode != http.StatusBadRequest || !strings.Contains(body, "requires at least one linked issue") { | |
| 697 | 697 | t.Fatalf("an unlinked change was accepted (%d):\n%s", resp.StatusCode, body) | |
| 698 | 698 | } | |
| @@ -710,11 +710,11 @@ func TestRepositoryCanRequireALinkedIssueForNewChanges(t *testing.T) { | |||
| 710 | 710 | ||
| 711 | 711 | form.Set("title", "Linked change") | |
| 712 | 712 | form.Set("closes", issueID) | |
| 713 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests", cookie, form) | ||
| 713 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes", cookie, form) | ||
| 714 | 714 | if resp.StatusCode != http.StatusSeeOther { | |
| 715 | 715 | t.Fatalf("a linked change was rejected (%d):\n%s", resp.StatusCode, body) | |
| 716 | 716 | } | |
| 717 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/requests/") | ||
| 717 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/changes/") | ||
| 718 | 718 | got, err := metadata.GetRequest(m.Git(), id) | |
| 719 | 719 | if err != nil { | |
| 720 | 720 | t.Fatal(err) | |
| @@ -805,14 +805,14 @@ func TestRequestSidebarAndDiscussionUpdateWithHtmx(t *testing.T) { | |||
| 805 | 805 | } | |
| 806 | 806 | ||
| 807 | 807 | ownerSess, ownerCookie := f.browserSession(t, f.ownerID) | |
| 808 | resp, body := f.browserPost(t, "/r/"+f.repo+"/requests", ownerCookie, url.Values{ | ||
| 808 | resp, body := f.browserPost(t, "/r/"+f.repo+"/changes", ownerCookie, url.Values{ | ||
| 809 | 809 | "csrf": {ownerSess.CSRF}, "title": {"HTMX change"}, "body": {"body\n"}, | |
| 810 | 810 | "base": {"main"}, "head": {"feature"}, | |
| 811 | 811 | }) | |
| 812 | 812 | if resp.StatusCode != http.StatusSeeOther { | |
| 813 | 813 | t.Fatalf("create change: %d\n%s", resp.StatusCode, body) | |
| 814 | 814 | } | |
| 815 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/requests/") | ||
| 815 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/changes/") | ||
| 816 | 816 | ||
| 817 | 817 | // A maintainer approves; the data-only regions and the action buttons come | |
| 818 | 818 | // back as out-of-band updates, so the Issues section and any open search are | |
| @@ -822,7 +822,7 @@ func TestRequestSidebarAndDiscussionUpdateWithHtmx(t *testing.T) { | |||
| 822 | 822 | if err != nil { | |
| 823 | 823 | t.Fatal(err) | |
| 824 | 824 | } | |
| 825 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+id+"/approve", writerCookie, url.Values{ | ||
| 825 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/changes/"+id+"/approve", writerCookie, url.Values{ | ||
| 826 | 826 | "csrf": {writerSess.CSRF}, "base": {request.Base}, "head": {request.Head}, | |
| 827 | 827 | }) | |
| 828 | 828 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, `hx-swap-oob="outerHTML"`) || | |
| @@ -838,7 +838,7 @@ func TestRequestSidebarAndDiscussionUpdateWithHtmx(t *testing.T) { | |||
| 838 | 838 | ||
| 839 | 839 | // The page's poll returns only out-of-band data regions. It has no sidebar | |
| 840 | 840 | // wrapper and no form, so it cannot close a search or replace a picker. | |
| 841 | resp, body = f.htmxGet(t, "/r/"+f.repo+"/requests/"+id+"/live", writerCookie) | ||
| 841 | resp, body = f.htmxGet(t, "/r/"+f.repo+"/changes/"+id+"/live", writerCookie) | ||
| 842 | 842 | if resp.StatusCode != http.StatusOK || strings.Contains(body, "<!doctype html>") || | |
| 843 | 843 | strings.Contains(body, "<form") || strings.Contains(body, `id="request-aside"`) || | |
| 844 | 844 | strings.Contains(body, `id="request-sidebar"`) || strings.Contains(body, `request-issues`) { | |
| @@ -856,7 +856,7 @@ func TestRequestSidebarAndDiscussionUpdateWithHtmx(t *testing.T) { | |||
| 856 | 856 | } | |
| 857 | 857 | ||
| 858 | 858 | // Posting a comment replaces only the discussion fragment. | |
| 859 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+id+"/comments", ownerCookie, url.Values{ | ||
| 859 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/changes/"+id+"/comments", ownerCookie, url.Values{ | ||
| 860 | 860 | "csrf": {ownerSess.CSRF}, "body": {"Review note over HTMX.\n"}, | |
| 861 | 861 | }) | |
| 862 | 862 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, `id="request-discussion"`) || | |
| @@ -912,7 +912,7 @@ func TestIssueAndChangeListsReturnFragmentsForHtmx(t *testing.T) { | |||
| 912 | 912 | t.Fatal("issues fragment lost its HTMX target") | |
| 913 | 913 | } | |
| 914 | 914 | ||
| 915 | resp, body = f.htmxGet(t, "/r/"+f.repo+"/requests?state=all", "") | ||
| 915 | resp, body = f.htmxGet(t, "/r/"+f.repo+"/changes?state=all", "") | ||
| 916 | 916 | if resp.StatusCode != http.StatusOK || !strings.Contains(body, `id="change-list"`) || | |
| 917 | 917 | strings.Contains(body, "<!doctype html>") { | |
| 918 | 918 | t.Fatalf("changes fragment = %d:\n%s", resp.StatusCode, body) | |
| @@ -952,16 +952,16 @@ func TestRequestFilesListsEveryChangedFile(t *testing.T) { | |||
| 952 | 952 | t.Fatalf("feature push: %s", errs) | |
| 953 | 953 | } | |
| 954 | 954 | sess, cookie := f.browserSession(t, f.ownerID) | |
| 955 | resp, body := f.browserPost(t, "/r/"+f.repo+"/requests", cookie, url.Values{ | ||
| 955 | resp, body := f.browserPost(t, "/r/"+f.repo+"/changes", cookie, url.Values{ | ||
| 956 | 956 | "csrf": {sess.CSRF}, "title": {"Every file"}, "body": {"body\n"}, | |
| 957 | 957 | "base": {"main"}, "head": {"feature"}, | |
| 958 | 958 | }) | |
| 959 | 959 | if resp.StatusCode != http.StatusSeeOther { | |
| 960 | 960 | t.Fatalf("create change: %d\n%s", resp.StatusCode, body) | |
| 961 | 961 | } | |
| 962 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/requests/") | ||
| 962 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/changes/") | ||
| 963 | 963 | ||
| 964 | filesURL := "/r/" + f.repo + "/requests/" + id + "/files" | ||
| 964 | filesURL := "/r/" + f.repo + "/changes/" + id + "/files" | ||
| 965 | 965 | _, page := f.browserGet(t, filesURL, cookie) | |
| 966 | 966 | if !strings.Contains(page, "5 changed") { | |
| 967 | 967 | t.Errorf("the tree does not count every file:\n%.2000s", page) | |
| @@ -1000,17 +1000,17 @@ func TestLineAnchoredReviewCommentFromTheWeb(t *testing.T) { | |||
| 1000 | 1000 | t.Fatalf("feature push: %s", errs) | |
| 1001 | 1001 | } | |
| 1002 | 1002 | sess, cookie := f.browserSession(t, f.ownerID) | |
| 1003 | resp, body := f.browserPost(t, "/r/"+f.repo+"/requests", cookie, url.Values{ | ||
| 1003 | resp, body := f.browserPost(t, "/r/"+f.repo+"/changes", cookie, url.Values{ | ||
| 1004 | 1004 | "csrf": {sess.CSRF}, "title": {"Line comments"}, "body": {"body\n"}, | |
| 1005 | 1005 | "base": {"main"}, "head": {"feature"}, | |
| 1006 | 1006 | }) | |
| 1007 | 1007 | if resp.StatusCode != http.StatusSeeOther { | |
| 1008 | 1008 | t.Fatalf("create change: %d\n%s", resp.StatusCode, body) | |
| 1009 | 1009 | } | |
| 1010 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/requests/") | ||
| 1010 | id := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/changes/") | ||
| 1011 | 1011 | ||
| 1012 | 1012 | // The Files tab brings the changed file and its per-line comment button. | |
| 1013 | filesURL := "/r/" + f.repo + "/requests/" + id + "/files" | ||
| 1013 | filesURL := "/r/" + f.repo + "/changes/" + id + "/files" | ||
| 1014 | 1014 | _, page := f.browserGet(t, filesURL, cookie) | |
| 1015 | 1015 | if !strings.Contains(page, `id="review-tree"`) || !strings.Contains(page, `data-status="M"`) || | |
| 1016 | 1016 | !strings.Contains(page, filesURL+"/readme.md") { | |
| @@ -1029,7 +1029,7 @@ func TestLineAnchoredReviewCommentFromTheWeb(t *testing.T) { | |||
| 1029 | 1029 | } | |
| 1030 | 1030 | ||
| 1031 | 1031 | // HTMX inserts the composer under the line, with the anchor already filled in. | |
| 1032 | resp, form := f.htmxGet(t, "/r/"+f.repo+"/requests/"+id+"/comment-form?path=readme.md&line=2&side=new", cookie) | ||
| 1032 | resp, form := f.htmxGet(t, "/r/"+f.repo+"/changes/"+id+"/comment-form?path=readme.md&line=2&side=new", cookie) | ||
| 1033 | 1033 | if resp.StatusCode != http.StatusOK || strings.Contains(form, "<!doctype html>") || | |
| 1034 | 1034 | !strings.Contains(form, `class="inline-comment"`) || | |
| 1035 | 1035 | !strings.Contains(form, `name="path" value="readme.md"`) || | |
| @@ -1039,7 +1039,7 @@ func TestLineAnchoredReviewCommentFromTheWeb(t *testing.T) { | |||
| 1039 | 1039 | } | |
| 1040 | 1040 | ||
| 1041 | 1041 | // The old full-page fallback still opens the composer with the anchor filled in. | |
| 1042 | _, page = f.browserGet(t, "/r/"+f.repo+"/requests/"+id+"?path=readme.md&line=2&side=new", cookie) | ||
| 1042 | _, page = f.browserGet(t, "/r/"+f.repo+"/changes/"+id+"?path=readme.md&line=2&side=new", cookie) | ||
| 1043 | 1043 | if !strings.Contains(page, "Commenting on") || !strings.Contains(page, `name="path" value="readme.md"`) || | |
| 1044 | 1044 | !strings.Contains(page, `name="line" value="2"`) { | |
| 1045 | 1045 | t.Fatalf("anchored composer is not pre-filled:\n%s", page) | |
| @@ -1048,7 +1048,7 @@ func TestLineAnchoredReviewCommentFromTheWeb(t *testing.T) { | |||
| 1048 | 1048 | // A rejected anchored comment re-renders the discussion with the anchor still | |
| 1049 | 1049 | // chosen, so the reader keeps the line they picked instead of being sent back to | |
| 1050 | 1050 | // the Files tab to choose it again. | |
| 1051 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+id+"/comments", cookie, url.Values{ | ||
| 1051 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/changes/"+id+"/comments", cookie, url.Values{ | ||
| 1052 | 1052 | "csrf": {sess.CSRF}, "body": {""}, | |
| 1053 | 1053 | "path": {"readme.md"}, "line": {"2"}, "side": {"new"}, | |
| 1054 | 1054 | }) | |
| @@ -1059,7 +1059,7 @@ func TestLineAnchoredReviewCommentFromTheWeb(t *testing.T) { | |||
| 1059 | 1059 | } | |
| 1060 | 1060 | ||
| 1061 | 1061 | // Posting it through HTMX stores the anchor and returns the discussion. | |
| 1062 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+id+"/comments", cookie, url.Values{ | ||
| 1062 | resp, body = f.htmxPost(t, "/r/"+f.repo+"/changes/"+id+"/comments", cookie, url.Values{ | ||
| 1063 | 1063 | "csrf": {sess.CSRF}, "body": {"This line needs a second look."}, | |
| 1064 | 1064 | "path": {"readme.md"}, "line": {"2"}, "side": {"new"}, | |
| 1065 | 1065 | }) | |
| @@ -1087,7 +1087,7 @@ func TestLineAnchoredReviewCommentFromTheWeb(t *testing.T) { | |||
| 1087 | 1087 | } | |
| 1088 | 1088 | ||
| 1089 | 1089 | // A normal form post from the Files tab returns to that file's line note. | |
| 1090 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+id+"/comments", cookie, url.Values{ | ||
| 1090 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+id+"/comments", cookie, url.Values{ | ||
| 1091 | 1091 | "csrf": {sess.CSRF}, "body": {"Another line note."}, | |
| 1092 | 1092 | "path": {"readme.md"}, "line": {"2"}, "side": {"new"}, | |
| 1093 | 1093 | }) | |
| @@ -1171,29 +1171,29 @@ func TestIssueAndChangeCommentsThreadOneLevel(t *testing.T) { | |||
| 1171 | 1171 | if _, errs, err := f.git(feature, "push", f.sshURL(f.repo), "HEAD:refs/heads/feature"); err != nil { | |
| 1172 | 1172 | t.Fatalf("feature push: %s", errs) | |
| 1173 | 1173 | } | |
| 1174 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests", cookie, url.Values{ | ||
| 1174 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes", cookie, url.Values{ | ||
| 1175 | 1175 | "csrf": {sess.CSRF}, "title": {"Threaded change"}, "body": {"body\n"}, | |
| 1176 | 1176 | "base": {"main"}, "head": {"feature"}, | |
| 1177 | 1177 | }) | |
| 1178 | 1178 | if resp.StatusCode != http.StatusSeeOther { | |
| 1179 | 1179 | t.Fatalf("create change: %d\n%s", resp.StatusCode, body) | |
| 1180 | 1180 | } | |
| 1181 | requestID := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/requests/") | ||
| 1182 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+requestID+"/comments", cookie, url.Values{ | ||
| 1181 | requestID := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/changes/") | ||
| 1182 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+requestID+"/comments", cookie, url.Values{ | ||
| 1183 | 1183 | "csrf": {sess.CSRF}, "body": {"Change root."}, | |
| 1184 | 1184 | }) | |
| 1185 | 1185 | rootID = commentID(resp) | |
| 1186 | 1186 | if resp.StatusCode != http.StatusSeeOther || rootID == "" { | |
| 1187 | 1187 | t.Fatalf("change root comment: %d %q\n%s", resp.StatusCode, rootID, body) | |
| 1188 | 1188 | } | |
| 1189 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+requestID+"/comments", cookie, url.Values{ | ||
| 1189 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+requestID+"/comments", cookie, url.Values{ | ||
| 1190 | 1190 | "csrf": {sess.CSRF}, "body": {"Change reply."}, "reply_to": {rootID}, | |
| 1191 | 1191 | }) | |
| 1192 | 1192 | replyID = commentID(resp) | |
| 1193 | 1193 | if resp.StatusCode != http.StatusSeeOther || replyID == "" { | |
| 1194 | 1194 | t.Fatalf("change reply: %d %q\n%s", resp.StatusCode, replyID, body) | |
| 1195 | 1195 | } | |
| 1196 | _, page = f.browserGet(t, "/r/"+f.repo+"/requests/"+requestID, cookie) | ||
| 1196 | _, page = f.browserGet(t, "/r/"+f.repo+"/changes/"+requestID, cookie) | ||
| 1197 | 1197 | if !strings.Contains(page, `class="comment-replies"`) || !strings.Contains(page, `id="c-`+replyID+`"`) || | |
| 1198 | 1198 | !strings.Contains(page, "Change reply.") || !strings.Contains(page, `data-reply-to="`+replyID+`"`) || | |
| 1199 | 1199 | !strings.Contains(page, `class="reply-context"`) || !strings.Contains(page, `href="#c-`+rootID+`"`) || | |
| @@ -1283,41 +1283,41 @@ func TestCommentEditAndDeleteFromTheWeb(t *testing.T) { | |||
| 1283 | 1283 | if _, errs, err := f.git(feature, "push", f.sshURL(f.repo), "HEAD:refs/heads/feature"); err != nil { | |
| 1284 | 1284 | t.Fatalf("feature push: %s", errs) | |
| 1285 | 1285 | } | |
| 1286 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests", cookie, url.Values{ | ||
| 1286 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes", cookie, url.Values{ | ||
| 1287 | 1287 | "csrf": {sess.CSRF}, "title": {"Editable change"}, "body": {"body\n"}, | |
| 1288 | 1288 | "base": {"main"}, "head": {"feature"}, | |
| 1289 | 1289 | }) | |
| 1290 | 1290 | if resp.StatusCode != http.StatusSeeOther { | |
| 1291 | 1291 | t.Fatalf("create change: %d\n%s", resp.StatusCode, body) | |
| 1292 | 1292 | } | |
| 1293 | requestID := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/requests/") | ||
| 1294 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+requestID+"/comments", cookie, url.Values{ | ||
| 1293 | requestID := strings.TrimPrefix(resp.Header.Get("Location"), "/r/"+f.repo+"/changes/") | ||
| 1294 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+requestID+"/comments", cookie, url.Values{ | ||
| 1295 | 1295 | "csrf": {sess.CSRF}, "body": {"Original change root."}, | |
| 1296 | 1296 | }) | |
| 1297 | 1297 | rootID = commentID(resp) | |
| 1298 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+requestID+"/comments", cookie, url.Values{ | ||
| 1298 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+requestID+"/comments", cookie, url.Values{ | ||
| 1299 | 1299 | "csrf": {sess.CSRF}, "body": {"Change reply survives."}, "reply_to": {rootID}, | |
| 1300 | 1300 | }) | |
| 1301 | 1301 | if resp.StatusCode != http.StatusSeeOther { | |
| 1302 | 1302 | t.Fatalf("change reply: %d\n%s", resp.StatusCode, body) | |
| 1303 | 1303 | } | |
| 1304 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+requestID+"/comments/"+rootID+"/edit", cookie, url.Values{ | ||
| 1304 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+requestID+"/comments/"+rootID+"/edit", cookie, url.Values{ | ||
| 1305 | 1305 | "csrf": {sess.CSRF}, "body": {"Edited change root."}, | |
| 1306 | 1306 | }) | |
| 1307 | 1307 | if resp.StatusCode != http.StatusSeeOther { | |
| 1308 | 1308 | t.Fatalf("change edit: %d\n%s", resp.StatusCode, body) | |
| 1309 | 1309 | } | |
| 1310 | _, page = f.browserGet(t, "/r/"+f.repo+"/requests/"+requestID, cookie) | ||
| 1310 | _, page = f.browserGet(t, "/r/"+f.repo+"/changes/"+requestID, cookie) | ||
| 1311 | 1311 | if !strings.Contains(page, "Edited change root.") || strings.Contains(page, "Original change root.") { | |
| 1312 | 1312 | t.Fatalf("change edit did not replace the comment:\n%s", page) | |
| 1313 | 1313 | } | |
| 1314 | resp, body = f.browserPost(t, "/r/"+f.repo+"/requests/"+requestID+"/comments/"+rootID+"/delete", cookie, url.Values{ | ||
| 1314 | resp, body = f.browserPost(t, "/r/"+f.repo+"/changes/"+requestID+"/comments/"+rootID+"/delete", cookie, url.Values{ | ||
| 1315 | 1315 | "csrf": {sess.CSRF}, | |
| 1316 | 1316 | }) | |
| 1317 | 1317 | if resp.StatusCode != http.StatusSeeOther { | |
| 1318 | 1318 | t.Fatalf("change delete: %d\n%s", resp.StatusCode, body) | |
| 1319 | 1319 | } | |
| 1320 | _, page = f.browserGet(t, "/r/"+f.repo+"/requests/"+requestID, cookie) | ||
| 1320 | _, page = f.browserGet(t, "/r/"+f.repo+"/changes/"+requestID, cookie) | ||
| 1321 | 1321 | if !strings.Contains(page, "Comment deleted") || !strings.Contains(page, "Change reply survives.") { | |
| 1322 | 1322 | t.Fatalf("deleted change root did not become a tombstone:\n%s", page) | |
| 1323 | 1323 | } | |
| @@ -1346,12 +1346,12 @@ func TestLandingRedirectsToTheRequestPage(t *testing.T) { | |||
| 1346 | 1346 | } | |
| 1347 | 1347 | ||
| 1348 | 1348 | sess, cookie := f.browserSession(t, f.ownerID) | |
| 1349 | resp, body := f.browserPost(t, "/r/"+f.repo+"/requests/"+reqID+"/merge", cookie, | ||
| 1349 | resp, body := f.browserPost(t, "/r/"+f.repo+"/changes/"+reqID+"/merge", cookie, | ||
| 1350 | 1350 | url.Values{"csrf": {sess.CSRF}}) | |
| 1351 | 1351 | if resp.StatusCode != http.StatusSeeOther { | |
| 1352 | 1352 | t.Fatalf("merge = %d, want 303:\n%s", resp.StatusCode, body) | |
| 1353 | 1353 | } | |
| 1354 | want := "/r/" + f.repo + "/requests/" + reqID | ||
| 1354 | want := "/r/" + f.repo + "/changes/" + reqID | ||
| 1355 | 1355 | if got := resp.Header.Get("Location"); got != want { | |
| 1356 | 1356 | t.Fatalf("merge redirect = %q, want %q", got, want) | |
| 1357 | 1357 | } | |
| @@ -1535,7 +1535,7 @@ func TestChangeListShowsOneStatus(t *testing.T) { | |||
| 1535 | 1535 | t.Fatalf("changes push: %v", err) | |
| 1536 | 1536 | } | |
| 1537 | 1537 | ||
| 1538 | code, body := f.get("/r/" + f.repo + "/requests?state=all") | ||
| 1538 | code, body := f.get("/r/" + f.repo + "/changes?state=all") | ||
| 1539 | 1539 | if code != http.StatusOK { | |
| 1540 | 1540 | t.Fatalf("change list: %d\n%s", code, body) | |
| 1541 | 1541 | } | |