Files
gitea/tests/e2e/issue-project.test.ts
Myers Carpenter 2f5b5a9e9c Add project column picker to issue and pull request sidebar (#37037)
Why? You are working on a ticket, it's ready to be moved to the QA
column in your project. Currently you have to go to the project, find
the issue card, then move it. With this change you can move the issue's
column on the issue page.

When an issue or pull request belongs to a project board, a dropdown
appears in the sidebar to move it between columns without opening the
board view. Read-only users see the current column name instead.

* Fix #13520
* Replace #30617

This was written using Claude Code and Opus. 

Closed:

<img width="1346" height="507" alt="image"
src="https://github.com/user-attachments/assets/7c1ea7ee-b71c-40af-bb14-aeb1d2beff73"
/>

Open:
<img width="1315" height="577" alt="image"
src="https://github.com/user-attachments/assets/4d64b065-44c2-42c7-8d20-84b5caea589a"
/>

---------

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Cursor <cursor@cursor.com>
2026-04-19 12:53:02 +00:00

68 lines
2.8 KiB
TypeScript

import {env} from 'node:process';
import {test, expect} from '@playwright/test';
import {login, apiCreateRepo, apiCreateIssue, apiDeleteRepo, createProjectColumn, randomString, timeoutFactor} from './utils.ts';
test('assign issue to project and change column', async ({page}) => {
const repoName = `e2e-issue-project-${randomString(8)}`;
const user = env.GITEA_TEST_E2E_USER;
await Promise.all([login(page), apiCreateRepo(page.request, {name: repoName})]);
await page.goto(`/${user}/${repoName}/projects/new`);
await page.locator('input[name="title"]').fill('Kanban Board');
await page.getByRole('button', {name: 'Create Project'}).click();
const projectLink = page.locator('.milestone-list a', {hasText: 'Kanban Board'}).first();
await expect(projectLink).toBeVisible();
const href = await projectLink.getAttribute('href');
const projectID = href!.split('/').pop();
// columns created via POST because the web UI uses modals that are hard to drive
await Promise.all(['Backlog', 'In Progress', 'Done'].map((title) =>
createProjectColumn(page.request, user, repoName, projectID!, title),
));
await apiCreateIssue(page.request, user, repoName, {title: 'Column picker test'});
// Same ceiling as tests/e2e/events.test.ts; Playwright defaults are 5000*factor (see playwright.config.ts).
const slowTimeout = 15_000 * timeoutFactor;
await page.goto(`/${user}/${repoName}/issues/1`);
await page.locator('.sidebar-project-combo .ui.dropdown').click();
await Promise.all([
page.waitForResponse(
(resp) => resp.url().includes('/issues/projects') && resp.status() === 200,
{timeout: slowTimeout},
),
page.locator('.sidebar-project-combo .menu .item', {hasText: 'Kanban Board'}).click(),
]);
const columnCombo = page.locator('.sidebar-project-column-combo');
await expect(columnCombo).toBeVisible({timeout: slowTimeout});
await columnCombo.locator('.ui.dropdown').click();
await columnCombo.locator('.menu').waitFor({state: 'visible', timeout: slowTimeout});
const inProgressItem = columnCombo.locator('a.item', {hasText: 'In Progress'});
await expect(inProgressItem).toBeVisible({timeout: slowTimeout});
await inProgressItem.scrollIntoViewIfNeeded();
await Promise.all([
page.waitForResponse(
(resp) =>
resp.request().method() === 'POST' &&
resp.url().includes('/issues/projects/column') &&
resp.ok(),
{timeout: slowTimeout},
),
inProgressItem.click(),
]);
await expect(columnCombo.getByTestId('sidebar-project-column-text')).toContainText('In Progress', {
timeout: slowTimeout,
});
await expect(page.locator('.timeline-item', {hasText: 'moved this to In Progress'})).toBeVisible({
timeout: slowTimeout,
});
await apiDeleteRepo(page.request, user, repoName);
});